यह लेख बताता है कि Uniswap V3 में ticks क्या हैं। Ticks concentrated liquidity की gas-efficient अकाउंटिंग को सक्षम करते हैं, इसलिए आइए पहले जल्दी से concentrated liquidity की समीक्षा करें।
Concentrated liquidity का मतलब है कि Uniswap V2 की तरह प्राइस कर्व (price curve) पर तरलता (liquidity) का स्थिर होना आवश्यक नहीं है। Liquidity providers अपनी liquidity को रखने के लिए प्राइस कर्व में सेगमेंट्स चुन सकते हैं। नीचे दिया गया एनिमेशन Uniswap V2 और Uniswap V3 के प्राइस कर्व्स के बीच के अंतर को दर्शाता है।
उदाहरण के लिए, एक ETH:USDC पूल में, यदि ETH की कीमत 2,000 USDC है, तो एक liquidity provider अपनी liquidity को 1,800 USDC और 2,200 USDC के बीच रखने का विकल्प चुन सकता है, ताकि वे उस प्राइस रेंज (price range) में अधिक फीस प्राप्त कर सकें जहाँ उन्हें एसेट्स के ट्रेड होने की उम्मीद है। नीचे दिए गए चित्र में, अन्य सेगमेंट्स की तुलना में 1800 USDC और 2200 USDC के बीच के सेगमेंट में अधिक liquidity है।

एक रेंज के भीतर अधिक liquidity होने का मतलब है कि उस रेंज में होने वाले स्वैप (swap) का price impact कम होगा। इसके विपरीत, कम liquidity होने से price impact अधिक हो जाता है।
ticks का परिचय और Uniswap V3 में उनकी आवश्यकता क्यों है
Concentrated liquidity को सपोर्ट करने के लिए, Uniswap V3 प्रोटोकॉल को यह मॉडल करने की आवश्यकता है कि प्राइस कर्व के साथ liquidity कैसे बदलती है।
कर्व के साथ liquidity बदल सकती है, लेकिन किन्हीं भी मनमाने पॉइंट्स (arbitrary points) पर नहीं। यदि Uniswap v3 कर्व पर मनमाने पॉइंट्स पर liquidity को मॉडिफाई करने की अनुमति देता, तो जटिलता (complexity) और गैस लागत (gas costs) काफी बढ़ जाती। जब भी कीमत थोड़ी सी भी बदलती, तो प्रोटोकॉल को यह जाँचना पड़ता कि क्या liquidity बदली है।
इसलिए, हमें कितनी बार यह जाँचना है कि liquidity बदली है या नहीं, इसकी संख्या को काफी कम करने के लिए, Uniswap V3 में liquidity को केवल पूर्व-निर्धारित (predefined) कीमतों पर ही एडजस्ट किया जा सकता है।
इन पूर्व-निर्धारित प्राइस पॉइंट्स को ticks कहा जाता है। नीचे दिया गया चित्र इस कॉन्सेप्ट को दर्शाता है, जिसमें कुछ ticks दिखाए गए हैं। ध्यान दें कि Uniswap V3 में नीचे दर्शाए गए ticks की तुलना में कहीं अधिक ticks होते हैं। प्राइस कर्व को ticks (मूल बिंदु से निकलने वाली लाल किरणें) द्वारा “काटा” (sliced) जाता है।

समीक्षा के तौर पर, Uniswap V2 और V3 में “प्राइस” (price) की व्याख्या मूल बिंदु (origin) से प्राइस कर्व तक एक किरण (ray) के कोण (angle) के रूप में की जा सकती है। x-axis से “कोण” जितना बड़ा होगा, एसेट Y के संदर्भ में एसेट X की कीमत उतनी ही अधिक होगी। इसलिए, बड़े कोण वाले ticks एसेट X की उच्च कीमतों से मेल खाते हैं।
नीचे दिए गए एनिमेशन में, स्यान (cyan) किरण का कोण एसेट X की कीमत को दर्शाता है, जबकि लाल किरणें ticks को दर्शाती हैं। हालाँकि एसेट X की कीमत बदल सकती है और कोई भी मूल्य ले सकती है, लेकिन ticks फिक्स (fixed) रहते हैं।
यह समझना महत्वपूर्ण है कि ticks कर्व पर उन पॉइंट्स को दर्शाते हैं जिनका उपयोग लेबल (labels) के रूप में किया जाएगा। आइए इसे माइलेज मार्कर वाली सड़क के उदाहरण से जोड़ें। जबकि एक कार सड़क पर कहीं भी हो सकती है, मील के मार्कर विशिष्ट बिंदुओं पर रखे जाते हैं, आमतौर पर कुछ अनुमानित अंतराल पर। इसी तरह, Uniswap v3 में, टोकन की कीमतों का कोई भी मूल्य हो सकता है, लेकिन ticks को प्रोटोकॉल द्वारा पूर्व-निर्धारित विशिष्ट स्थानों पर स्थिर रूप से (statically) रखा जाता है।
Ticks प्राइस कर्व में उन रेफरेंस पॉइंट्स के रूप में काम करते हैं जहाँ liquidity बदल सकती है।
हम नीचे इस कॉन्सेप्ट को दर्शाते हैं। Ticks को मूल बिंदु से लाल किरणों के रूप में दिखाया गया है। बाईं ओर, liquidity को ticks के बीच एडजस्ट किया गया है, जिसकी अनुमति Uniswap V3 देता है। दाईं ओर का परिदृश्य कर्व के उन पॉइंट्स के बीच liquidity को एडजस्ट करने के प्रयास को दर्शाता है जो ticks नहीं हैं, जिसकी अनुमति प्रोटोकॉल नहीं देता है।

हम जल्द ही दिखाएंगे कि Uniswap V3 यह कैसे निर्धारित करता है कि ticks को कहाँ रखना है, लेकिन पहले आइए जल्दी से समीक्षा करें कि कैसे “प्राइस” का अर्थ “Y के संदर्भ में टोकन X की कीमत” है।
Uniswap v3 में, हम टोकन X की कीमत का उपयोग करते हैं
Uniswap v3 में, कीमतें हमेशा टोकन Y के संदर्भ में टोकन X की कीमत को संदर्भित करती हैं। इस प्रकार, जब भी हम लिखते हैं, तो यह टोकन X की कीमत को संदर्भित करता है, जिसे द्वारा दर्शाया जाता है।
टोकन X के संदर्भ में टोकन Y की कीमत, जिसे द्वारा दिया जाता है, उसे से के रूप में कैलकुलेट किया जा सकता है। इस प्रकार, प्रोटोकॉल को केवल X () में कीमतों का ट्रैक रखने की आवश्यकता है। Y () में कीमतों को उसी के अनुसार कैलकुलेट किया जा सकता है।
उदाहरण के लिए, यदि टोकन X की कीमत है, तो टोकन Y की कीमत की गणना या के रूप में की जा सकती है। टोकन Y के बजाय टोकन X में कीमतों के साथ काम करना चुनना केवल एक परंपरा (convention) है।
tick से price का फॉर्मूला
हमने कहा था कि ticks पूर्व-निर्धारित कीमतें हैं, लेकिन इन कीमतों को कैसे परिभाषित किया गया है?
उन्हें निम्नलिखित फॉर्मूले द्वारा परिभाषित किया गया है:
जहाँ एक पूर्णांक (integer) है जिसे tick index कहा जाता है और वह कीमत है जो tick index दर्शाता है। हम इसे “tick price” कहेंगे। याद रखें, प्रत्येक tick केवल एक फिक्स्ड कीमत (fixed price) के लिए एक लेबल है।
ticks के कुछ उदाहरण हैं:
- Tick index 0 कीमत 1:1 को परिभाषित करता है, क्योंकि ।
- Tick index 1 कीमत 1:1.0001 को परिभाषित करता है, क्योंकि ।
- Tick index 2 कीमत 1:1.00020001 को परिभाषित करता है, क्योंकि ।
- Tick index -1 कीमत को लगभग 1:0.99990001 परिभाषित करता है, क्योंकि ।
अनुमति प्राप्त tick indexes की सीमा (range) -887,272 से 887,272 तक है, और इस सीमा का कारण अगले अध्याय में समझाया जाएगा।
इंडेक्स को tick के रूप में संदर्भित करना आम बात है और कोडबेस (codebase) ऐसा बहुत करता है। tick index या tick price का संदर्भ देना कॉन्टेक्स्ट (context) से स्पष्ट होना चाहिए। किसी भी स्थिति में, प्रत्येक tick index विशिष्ट रूप से एक tick price से जुड़ा होता है और इसके विपरीत।
ticks के संबंध में एसेट की कीमतों के उदाहरण
मान लीजिए कि हमारे पास एक USDC:USDT पूल है, जहाँ टोकन X USDC है और टोकन Y USDT है। यदि दोनों एसेट्स का मूल्य बिल्कुल समान है, तो कीमत ठीक tick index 0 पर होगी, क्योंकि USDT के संदर्भ में USDC की कीमत 1:1 है। इसे नीचे दर्शाया गया है (ticks स्केल के अनुसार नहीं हैं)। ticks को लाल किरणों से दर्शाया गया है, वह कीमत जिस पर USDC USDT के साथ ट्रेड करता है उसे एक पीली बिंदीदार किरण से दर्शाया गया है जो पीले बिंदु पर समाप्त होती है, और प्राइस कर्व स्यान (cyan) रंग का कर्व है:

अब मान लीजिए कि USDT के मुकाबले USDC के मूल्य में बहुत मामूली वृद्धि होती है। यानी किसी को एक USDC पाने के लिए 1.00005 USDT का ट्रेड करना पड़ता है। यह USDC की वर्तमान कीमत को tick 0 से थोड़ा ऊपर रखेगा, लेकिन पूरी तरह से tick 1 पर नहीं:

यह बिल्कुल ठीक है — प्रोटोकॉल को एसेट्स के उस मूल्य की आवश्यकता नहीं होती जो एक tick से मेल खाता हो।
यदि USDC का मूल्य तब तक बढ़ता रहा जब तक कि एक USDC के लिए 1.0001 USDT का ट्रेड करने की आवश्यकता नहीं हो जाती, तो प्राइस कर्व पर बिंदु ठीक tick 1 पर आ जाएगा। यह कीमत ठीक tick 1 पर आती है क्योंकि है।

Positive और negative ticks
- यदि tick index नेगेटिव है, तो यह 1 से कम कीमत के अनुरूप है, क्योंकि यदि नेगेटिव है तो 1 से कम होगा।
- यदि है तो कीमत 1 है (जिसका अर्थ है कि एसेट्स का मूल्य समान है) क्योंकि किसी भी मान की पावर 0 होने पर वह 1 होता है।
- यदि 1 से बड़ा या उसके बराबर है, तो कीमत एक से अधिक होगी।
नेगेटिव ticks, tick 0 और पॉजिटिव ticks के बीच संबंध देखने के लिए, नीचे दिए गए लेबल वाले ticks देखें। विशेष रूप से, नीचे दी गई इमेज निम्नलिखित उदाहरण कीमतों का उपयोग करती है।

टोकन की कीमत और ticks के बीच संबंध
टोकन की कीमत को ticks के साथ भ्रमित करना आम बात है। जैसा कि ऊपर उल्लेख किया गया है, ticks प्राइस कर्व पर रेफरेंस पॉइंट्स (reference points) हैं, जो सड़क पर माइलेज मार्करों के समान हैं। वे कीमतें भी हैं क्योंकि वे प्राइस कर्व पर बिंदु हैं और उन्हें फॉर्मूले द्वारा परिभाषित किया गया है।
किसी टोकन की कीमत उसकी वर्तमान कीमत होती है: यह प्राइस कर्व पर एक बिंदु है जो स्वैप (swaps) के दौरान बदलता है। उदाहरण के लिए, किसी टोकन की कीमत अभी 10 हो सकती है और भविष्य में किसी समय 33.2 हो सकती है। जैसे-जैसे कीमत बदलती है, यह कर्व के साथ आगे बढ़ती है और ticks को पार करती है, ठीक वैसे ही जैसे सड़क पर चलती हुई कार माइलेज मार्करों को पार करती है।
कभी-कभी, टोकन की कीमत किसी दिए गए tick की कीमत से बिल्कुल मेल खाएगी, लेकिन अक्सर, टोकन की कीमत किसी भी ticks से मेल नहीं खाएगी। यह एक सड़क पर एक कार के क्षण भर के लिए उस बिंदु पर रुकने के समान है जहाँ एक माइलेज मार्कर स्थित है।
स्वैप के माध्यम से किसी टोकन की कीमत कैसे निर्धारित की जाती है, इस पर इस पुस्तक के कई अध्यायों में चर्चा की जाएगी। जो स्पष्ट होना चाहिए वह यह है कि फॉर्मूला केवल उन ticks को परिभाषित करने का एक तरीका है जो प्राइस कर्व पर मार्कर के रूप में कार्य करते हैं। वे उन स्थानों के रूप में काम करते हैं जहाँ, और केवल वहीं, liquidity को एडजस्ट किया जा सकता है।
ticks को परिभाषित करने के लिए 1.0001 मान का उपयोग क्यों करें?
Uniswap V3 के व्हाइटपेपर के अनुसार, 1.0001 मान को इसलिए चुना गया क्योंकि
“इसमें यह वांछनीय गुण है कि प्रत्येक tick अपने प्रत्येक पड़ोसी ticks से .01% (1 basis point) कीमत के मूवमेंट की दूरी पर होता है।”
ticks के बीच basis points का उपयोग करने से कीमतों में पूर्ण (absolute) अंतर के बजाय सापेक्ष (relative) अंतर व्यक्त होता है।
एक absolute अंतर, जैसे कि 0.1 सेंट, का टोकन की कीमत के आधार पर बहुत अलग प्रभाव हो सकता है। $100,000 के टोकन के लिए, 0.1 सेंट नगण्य (negligible) है, जबकि 1 सेंट के टोकन के लिए, यह एक महत्वपूर्ण बदलाव का प्रतिनिधित्व करता है।
इसके विपरीत, basis points में अंतर समान सापेक्ष अनुपात (relative proportion) सुनिश्चित करता है। उदाहरण के लिए, $100,000 की कीमत वाले टोकन के लिए, 1 basis point का अंतर $10 के बराबर होता है, जबकि 1 सेंट वाले टोकन के लिए, 1 basis point 0.0001 सेंट के बराबर होता है। हालाँकि $10 और $0.000001 अलग-अलग absolute मान हैं, वे टोकन की कीमत के सापेक्ष समान relative परिवर्तन का प्रतिनिधित्व करते हैं।
इस प्रकार, हम चाहते हैं कि $100,000 मूल्य के टोकन के लिए पड़ोसी ticks के बीच का अंतर $10 हो, और 1 सेंट मूल्य के टोकन के लिए $0.000001 हो।
पड़ोसी ticks के बीच 1 basis point का परिवर्तन देखने के लिए आइए कुछ उदाहरण देखें:
उदाहरण 1: Tick 100000 और tick 100001
tick 100000 और 100001 के लिए हमारे पास निम्नलिखित कीमतें हैं:
(स्पष्टता के लिए पहले चार अंकों को हाईलाइट किया गया था)। हम देख सकते हैं कि लगभग 22015 टोकन Y मूल्य के टोकन के लिए अंतर 2.201545604853891 (लगभग 1 basis point या 22015 का 0.01%) है।
उदाहरण 2: Tick 10 और tick 11
अब लगभग 1 टोकन Y मूल्य के टोकन के लिए अंतर 0.000100100045012 (0.0001 या लगभग 1 basis point) है।
Tick range
जब हम लिखते हैं, यह मानते हुए कि और ticks हैं, तो हम सीमाओं (boundaries) को छोड़कर, और के बीच की प्राइस रेंज का उल्लेख कर रहे हैं। इस संदर्भ में, को lower tick कहा जाता है और को upper tick कहा जाता है।
जब हम tick range को के रूप में लिखते हैं, तो हम वास्तव में का संदर्भ दे रहे होते हैं, जहाँ -10 और 10 tick indexes हैं, और और संबंधित tick prices हैं।
नीचे दिए गए चित्र में, हम और के बीच एक tick range का उदाहरण देखते हैं।

एक रेखा (line) के रूप में दर्शाया गया प्राइस कर्व
प्राइस कर्व का एक और सामान्य प्रतिनिधित्व एक रेखा के रूप में है। प्राइस कर्व को x और y अक्षों (axes) पर प्लॉट किया जाता है, जबकि नंबर लाइन पर प्रत्येक बिंदु एक कीमत को दर्शाता है।
कर्व पर, बढ़ती हुई कीमत (टोकन X की) ऊपर और बाईं ओर बढ़ती है, जबकि लाइन पर, यह बाएँ से दाएँ बढ़ती है:
इस प्रकार, हम कभी-कभी नीचे दिए गए लाइन डायग्राम का उपयोग करके कर्व की कीमत और liquidity को दर्शाएंगे, जहाँ नीला क्षेत्र tick range में निहित liquidity को दर्शाता है।

हम संबंधित लाइन प्लॉट पर liquidity लेवल को इस प्रकार प्लॉट कर सकते हैं:
नीचे एक इंटरैक्टिव टूल है जो आगे यह स्पष्ट करता है कि ये दोनों प्रतिनिधित्व एक ही जानकारी कैसे दिखाते हैं। k स्लाइडर्स को घुमाकर एक प्राइस सेगमेंट की liquidity को बदलें, फिर “Sweep Price” पर क्लिक करें। Sweep Price पर क्लिक करने के बाद, दोनों चार्ट्स के लिए एक प्राइस इंडिकेटर (कार्तीय प्लॉट (cartesian plot) के लिए एक लाल किरण और लाइन प्लॉट के लिए एक लाल बिंदु) दिखाई देगा। ध्यान दें कि कार्तीय प्लॉट पर लाल किरण लाइन प्लॉट पर लाल बिंदु को कैसे ट्रैक करती है।
हम उम्मीद करते हैं कि पाठक प्राइस कर्व के दोनों प्रस्तुतियों (representations) को समझेंगे: एक कार्तीय तल (Cartesian plane) (x-y अक्ष) पर और दूसरा एक रेखा के रूप में। अध्यायों में कॉन्सेप्ट्स को समझाने के लिए दोनों डायग्राम्स का उपयोग किया जाएगा।
v3 में x-y अक्ष का अर्थ
Uniswap V2 में, x का मान पूल द्वारा रखे गए टोकन X की शाब्दिक मात्रा (रिज़र्व) है (y के लिए भी ऐसा ही है)। हालाँकि Uniswap V3 में, “रिज़र्व” (reserves) एक अधिक जटिल कॉन्सेप्ट है क्योंकि प्रत्येक कर्व सेगमेंट टोकन X और/या Y की अलग-अलग मात्रा रखता है।
x और y अक्षों को टोकन की “मात्रा” (amount) मापने के रूप में सोचना अभी भी मददगार है, लेकिन यह “मात्रा” क्या है, इसमें काफी बारीकियां हैं, इसलिए हम इस पर चर्चा बाद के अध्याय के लिए टाल देते हैं। हम इसका उल्लेख इसलिए कर रहे हैं ताकि अक्षों को गलती से टोकन की कीमत न समझ लिया जाए, क्योंकि स्पष्टीकरण के बिना किसी अक्ष को केवल “x” लेबल करना अस्पष्ट (ambiguous) हो सकता है।
current tick
Uniswap V3 “active tick” या “current tick” या कभी-कभी केवल “tick” का ट्रैक रखता है। “current tick” वर्तमान कीमत है जिसे निकटतम tick पर राउंड डाउन (rounded down) किया गया है। यदि कीमत बढ़ती है और किसी tick को पार करती है, तो वह tick जिसे अभी पार किया गया था, वह current tick बन जाता है। “पार” (Crossed) करने के लिए यह आवश्यक नहीं है कि कीमत tick के “ऊपर से गुजरी” (passed over) हो। यदि कीमत tick पर रुक जाती है, तो tick को पार किया हुआ माना जाता है।
यदि कीमत घटती है और किसी tick को पार करती है, तो उसने पहले वाले current tick को पार किया होगा, इसलिए उस tick के नीचे वाला tick नया current tick बन जाता है।
नीचे दिया गया इंटरैक्टिव टूल यह दर्शाता है कि प्रोटोकॉल किसी tick को current tick के रूप में कैसे चुनता है। यह देखने के लिए कि कीमत के tick को पार करते ही ticks (ग्रे) कैसे current tick (हरा) बन जाते हैं, टूल के शीर्ष पर स्लाइडर को घुमाएँ:
slot0 वेरिएबल current tick को होल्ड करता है
प्रोटोकॉल current tick को slot0 नामक एक struct में स्टोर करता है (कोड लिंक)। यह वेरिएबल पब्लिक है, इसलिए कोई भी slot0 को क्वेरी (query) करके सीधे Etherscan पर पूल के current tick को पढ़ सकता है।

नीचे हम Base पर ETH:DAI पूल के लिए परिणाम दिखाते हैं:

current tick 81143 है। पूल ETH:DAI है, इसलिए कीमत को DAI के संदर्भ में ईथर (Ether) के रूप में व्यक्त किया जाता है। दोनों टोकन में 18 दशमलव स्थान (decimal places) हैं। tick 81143 पर कीमत की गणना करने पर आता है। current tick वर्तमान कीमत है जिसे निकटतम tick पर राउंड डाउन किया गया है। इसलिए हम मान सकते हैं कि current tick मोटे तौर पर वर्तमान कीमत से मेल खाता है। तो इस पूल के लिए, 1 ETH का मूल्य लगभग 3340 DAI है।
दशमलव (decimals) कीमत को कैसे प्रभावित करते हैं
यह स्पष्ट करने के लिए एक और उदाहरण पर विचार करें कि दशमलव स्थान कीमत और tick को कैसे प्रभावित करते हैं। नीचे हम Base पर ETH:USDC पूल के लिए परिणाम दिखाते हैं:

tick अब नेगेटिव है जिसका मान -195186 है, और कीमत की गणना के रूप में की जा सकती है। यहाँ दशमलव स्थानों में अंतर के कारण tick नेगेटिव है, क्योंकि ETH में 18 दशमलव हैं जबकि USDC में केवल 6 दशमलव हैं।
यह मानते हुए कि ETH का मूल्य $1000 है, ETH की सबसे छोटी इकाई का मूल्य (या ) है, जबकि USDC की सबसे छोटी इकाई का मूल्य है। इसलिए, हालाँकि हम मानते हैं कि 1 ETH 1 USDC से अधिक “मूल्य” का है, इसकी सबसे छोटी इकाई पर विचार करते हुए, USDC की 1 सबसे छोटी इकाई का मूल्य ETH की 1 सबसे छोटी इकाई से अधिक है।
इस उदाहरण में, दशमलव स्थानों (ETH के लिए 18 बनाम USDC के लिए 6) में अंतर को ध्यान में रखने के लिए, हमें कीमत को से गुणा करना होगा। इस प्रकार, पूल की कीमत हो जाती है, जो कि लगभग ETH:DAI पूल के समान ही मूल्य है।
सारांश
- प्राइस कर्व को ticks नामक बिंदुओं से सीमांकित (demarcated) किया जाता है, जिन्हें फॉर्मूले द्वारा परिभाषित किया जाता है, जहाँ को tick index का नाम दिया गया है। Ticks एक सेट की गई कीमत (set price) को दर्शाते हैं।
- Ticks उन सीमाओं के रूप में काम करते हैं जहाँ liquidity provider liquidity प्रदान कर सकता है। मनमाने बिंदुओं को सीमाओं के रूप में रखकर liquidity प्रदान करना संभव नहीं है।
- Ticks पॉजिटिव या नेगेटिव हो सकते हैं। Tick zero उस परिदृश्य से मेल खाता है जहाँ टोकन का मूल्य समान होता है। पॉजिटिव ticks उन कीमतों से मेल खाते हैं जहाँ X की एक इकाई को Y की एक से अधिक इकाई के लिए स्वैप किया जा सकता है। नेगेटिव ticks उन कीमतों से मेल खाते हैं जहाँ Y की एक इकाई में स्वैप करने पर X की एक से अधिक इकाई वापस मिलेगी।
- current tick वर्तमान कीमत के निकटतम राउंड डाउन किया गया tick है।
- न्यूनतम और अधिकतम ticks -887,272 से 887,272 तक हैं। हम अगले अध्याय में चर्चा करेंगे कि ऐसा क्यों है।
अभ्यास के लिए प्रश्न (Practice Exercises)
एक कम लागत वाले L2 पर एक पूल चुनें और liquidity प्रदान करें। पूलों की सूची यहाँ दी गई है। ध्यान दें कि आप कहाँ liquidity प्रदान कर सकते हैं और कहाँ नहीं।