यह लेख बीजगणितीय (algebraically) रूप से चरण-दर-चरण दिखाता है कि get_D() और get_y() का कोड StableSwap invariant से कैसे प्राप्त किया जाता है।
दिए गए StableSwap Invariant के अनुसार:
इसके साथ हम दो सामान्य गणितीय ऑपरेशन (math operations) करना चाहते हैं:
- और reserves के निश्चित मान (fixed values) दिए होने पर की गणना करना। ध्यान दें कि , यानी उन कॉइन्स की संख्या जिन्हें पूल सपोर्ट करता है, पूल के डिप्लॉय होने के समय ही निश्चित (fixed) हो जाती है। function
get_D()यही काम करता है। - दिए होने पर, हम किसी एक reserve का मान बढ़ाकर एक नए मान तक ले जाना चाहते हैं और यह पता लगाना चाहते हैं कि समीकरण (equation) को संतुलित (balanced) रखने के लिए किसी अन्य reserve को कितना कम करने की आवश्यकता है। function
get_y()यही काम करता है। यहाँ “y” का अर्थ है।
Curve StableSwap में इन ऑपरेशन्स को क्रमशः get_D() और get_y() कहा जाता है।
get_D() का उद्देश्य
Curve V1 (StableSwap) में, D बिल्कुल Uniswap V2 के k के समान व्यवहार करता है — D जितना बड़ा होगा, reserves उतने ही अधिक होंगे, और मूल्य वक्र (price curve) उतना ही “आगे की ओर (further out)” होगा। liquidity जोड़ने या हटाने के बाद, या जब कोई फीस पूल बैलेंस को बदल देती है, तो D बदल जाता है — और इसकी दोबारा गणना (recompute) करने की आवश्यकता होती है। function get_D() का उद्देश्य यही है। पूल के वर्तमान reserves के आधार पर, यह D की गणना करता है।
यदि एक curve पूल में दो टोकन, x और y हैं, तो StableSwap invariant है
हमारे उद्देश्यों के लिए, “amplification factor” A को एक स्थिरांक (constant) के रूप में माना जा सकता है।
get_y() का उद्देश्य
function get_y() का उपयोग स्वैप (swap) के दौरान किया जाता है। Uniswap V2 में k के समान, स्वैप के दौरान (फीस को छोड़कर) D को स्थिर (constant) रखा जाना चाहिए। विशेष रूप से, x का नया मान दिए जाने पर, यह y के उस मान की गणना करता है जो समीकरण को संतुलित रखता है। इस प्रकार, यह पता लगाने के लिए एक महत्वपूर्ण सबरूटीन (subroutine) है कि “यदि मैं पूल में इतना टोकन x डालता हूँ, तो कितना टोकन y निकाला जा सकता है?”
Curve पूल में 2 से अधिक टोकन रख सकता है (उदा. 3pool में USDT, USDC और DAI होते हैं)। Curve एक array में index द्वारा कॉइन्स की पहचान करता है। तो, इस मामले में, x और y उस array में विशिष्ट कॉइन्स को संदर्भित करते हैं। इस संदर्भ में, get_y() का अर्थ है किसी विशिष्ट टोकन x का बैलेंस बदलना, जबकि अन्य बैलेंस को स्थिर रखना, लेकिन किसी अन्य टोकन y के मान को बदलने की अनुमति देना। फिर, x में एक विशेष बदलाव दिए जाने पर, यह गणना करना कि invariant को संतुलित रखने के लिए y कैसे बदलता है।
n टोकन्स के लिए invariant है:
सरलता के लिए, हम बाकी लेख में summation के बजाय और product के बजाय का उपयोग करेंगे, इसलिए invariant बन जाता है:
जहाँ टोकन्स के बैलेंस का योग (sum) है (), बैलेंस का गुणनफल (product) है (, और टोकन i का बैलेंस है।
whitepaper में, को के रूप में और को के रूप में लिखा गया है। whitepaper का समीकरण (equation) नीचे दोहराया गया है:
हम sum और product नोटेशन के बजाय और का उपयोग करेंगे।
हम मान लेते हैं कि पूल में मनमाने ढंग से कितने भी टोकन हो सकते हैं, इसलिए सूत्र (formulas) उसी को दर्शाएंगे। हालांकि, व्यवहार में, छोटा होना चाहिए, अन्यथा पद (term) के overflow होने की संभावना रहती है।
get_D() के साथ की गणना करना
get_D() में, हमें बैलेंस का एक सेट x_0, x_1, ..., x_n दिया जाता है और हमें D की गणना करनी होती है।
बीजगणितीय (algebraically) रूप से इसे हल करना संभव नहीं है
के लिए। इसके बजाय, हमें इसे संख्यात्मक रूप से (numerically) हल करने के लिए Newton’s method लागू करने की आवश्यकता है। ऐसा करने के लिए, हम एक फ़ंक्शन बनाते हैं, जो समीकरण के संतुलित होने पर 0 होता है।
और हम के संदर्भ में व्युत्पन्न (derivative) की गणना इस प्रकार करते हैं:
Newton’s Method का फॉर्मूला
हम पुनरावृत्ति (iteratively) द्वारा को इसका उपयोग करके हल कर सकते हैं:
को हर (denominator) में के साथ व्यक्त करना उपयोगी होगा। सबसे पहले हम को परिभाषित करने वाले बाएँ भिन्न (fraction) के अंश (top) और हर (bottom) को से गुणा करते हैं।
और फिर को एक एकल भिन्न (single fraction) में मिलाएँ:
हम Newton’s method को एक समान हर (common denominator) के साथ फिर से लिख सकते हैं:
पहले वाले और को फिर से लिखे गए Newton’s method फॉर्मूले में प्रतिस्थापित (substitute) करने पर हमें मिलता है:
चूंकि हमने हर (denominator) में रखने के लिए को पुनर्व्यवस्थित (re-arrange) किया है, इसलिए पद (term) आसानी से कट (cancel) जाएगा:
अंश (numerator) में कोष्ठक (parenthesis) हटाने के लिए सभी पदों (terms) को वितरित (distribute) करें:
इससे बहुत सारे पद कट (cancellations) जाते हैं
हम अंश (numerator) और हर (denominator) को से गुणा करते हैं
यदि हम को इस प्रकार परिभाषित करते हैं:
और को प्रतिस्थापित (substitute) करने पर हमें मिलता है
मूल सोर्स कोड (original source code) से तुलना
यह बिल्कुल Vyper code से मेल खाता है:

वेरिएबल को इस प्रकार परिभाषित किया गया था:
D_P: uint256 = D # D_P = S
for _x in xp:
D_P = D_P * D / (_x * N_COINS)
xp टोकन्स की संख्या है, इसलिए लूप n बार चलेगा। इसलिए, हमारे पास हर (denominator) में को स्वयं से n बार गुणा किया गया है
get_y() के साथ y की गणना करना
विचार यह है कि हम में से किसी एक को एक नया मान लेने के लिए बाध्य करते हैं (कोड इसे x कहता है) और किसी अन्य (जहाँ के लिए सही मान की गणना करते हैं ताकि समीकरण संतुलित रहे। अन्य टोकन्स का बैलेंस अपरिवर्तित (unchanged) रहता है। को के रूप में संदर्भित किया जाता है।
हालाँकि एक StableSwap पूल में कई टोकन हो सकते हैं, लेकिन get_y() का उपयोग करके एक समय में उनमें से केवल दो टोकन का आदान-प्रदान (exchange) करना ही संभव है।
फिर से, हमारे पास वही invariant है
, , और निश्चित (fixed) हैं, लेकिन हम और में दो मानों को बदलेंगे
इसलिए, हमें सूत्र (formula) को थोड़ा समायोजित (adjust) करने की आवश्यकता है, क्योंकि और में वे मान शामिल हैं जिनकी हम गणना कर रहे हैं।
- उन सभी बैलेंस का योग (sum) होगा, सिवाय टोकन के उस नए बैलेंस के, जिसे हम हल करने का प्रयास कर रहे हैं
- उन सभी टोकन के बैलेंस का गुणनफल (product) होगा, सिवाय उसके जिसे हम हल करने का प्रयास कर रहे हैं।
दूसरे शब्दों में,
कोड के साथ एकरूपता (consistency) बनाए रखने के लिए, हम उस टोकन को कहेंगे जिसके नए बैलेंस की हम गणना करने का प्रयास कर रहे हैं।
तब सूत्र यह बन जाता है:
फिर से, हम एक प्राप्त करते हैं जो समीकरण के संतुलित होने पर 0 होता है, और y के संदर्भ में इसका व्युत्पन्न (derivative) निकालते हैं:
यहाँ फिर से Newton’s method का फॉर्मूला है:
Newton’s method में और को प्रतिस्थापित (substitute) करने के बाद हमें मिलता है:
हर (denominator) से को बाहर निकालें
समान हर (common denominator) प्राप्त करने के लिए (नीचे दिए गए बॉक्स में) को गुणा करें:
बाएँ पद (term) में को वितरित (distribute) करें
समान हर (common denominator) के साथ योग (sums) को मिलाएँ
मूल invariant से प्रतिस्थापन (substitution) बनाना
ऐसा लग सकता है कि समीकरण को आगे सरल नहीं किया जा सकता है, लेकिन यदि हम अपने मूल invariant पर वापस लौटें
हम के लिए इसे हल कर सकते हैं, हमें मिलता है:
और फिर यदि हम के अपने नवीनतम (latest) सूत्र में अंश (numerator) में को प्रतिस्थापित (substitute) करते हैं, तो हमें मिलता है:
बहुत सारे पद कट (cancellation) जाते हैं
और हमारे पास एक बहुत छोटा समीकरण बचता है
हम ऊपर और नीचे (अंश और हर) को से गुणा करते हैं
अपने invariant पर वापस जाते हुए, हम हर (denominator) में भिन्नात्मक पद (fractional term) के लिए हल कर सकते हैं:
फिर हम उसे ynext के समीकरण में प्रतिस्थापित (substitute) कर सकते हैं:
फिर हम को वितरित (distribute) कर सकते हैं और हर (denominator) को सरल कर सकते हैं
कोष्ठक (parenthesis) हटाकर और दोनों को एक साथ जोड़कर हर (denominator) को सरल करें
मूल कोड में, Curve अतिरिक्त वेरिएबल परिभाषित करता है:
के सूत्र में प्रतिस्थापन (substitution) के बाद, हमें मिलता है:
मूल सोर्स कोड (original source code) से तुलना
यह बिल्कुल Curve कोड से मेल खाता है, नीचे दिए गए बैंगनी बॉक्स को देखें:

Ann और An**ⁿ के बीच बेमेल (Mismatch)
थोड़ा भ्रामक (confusing) रूप से, Curve whitepaper invariant का उपयोग करता है लेकिन कोडबेस Ann का उपयोग करता है। अर्थात्, कोडबेस A * n ** n के बजाय A * n * n की गणना करता हुआ प्रतीत होता है। इस विसंगति (discrepancy) का कारण यह है कि कोडबेस को के रूप में स्टोर करता है। चूँकि डिप्लॉयमेंट के समय निश्चित (fixed) होता है, की पहले से गणना (precomputing) करने से कोड को ऑन-चेन घातांक (exponent) की गणना करने से बचने में मदद मिलती है, जो एक अधिक महँगा ऑपरेशन (costly operation) है।
सारांश (Summary)
Curve का मूल invariant वेरिएबल्स या को प्रतीकात्मक रूप से (symbolically) हल करने की अनुमति नहीं देता है। इसके बजाय, पदों (terms) को संख्यात्मक रूप से (numerically) हल किया जाना चाहिए।
इस अभ्यास से एक निष्कर्ष (takeaway) यह निकलता है कि अच्छा बीजगणितीय हेरफेर (algebraic manipulation) एक बहुत प्रभावी gas optimization तकनीक है। Curve डेवलपर्स Newton’s method का एक ऐसा फॉर्मूला निकालने में सक्षम थे जो और इसके व्युत्पन्न (derivative) को सीधे तौर पर प्लग इन करने और उसे वैसे ही छोड़ देने की तुलना में बहुत छोटा है।
संदर्भ और आभार (Citations and Acknowledgements)
इस लेख को लिखने में निम्नलिखित संसाधनों (resources) से परामर्श लिया गया था:
StableSwap - efficient mechanism for Stablecoin liquidity, Michael Egorov, https://resources.curve.fi/pdf/curve-stableswap.pdf
Understanding the Curve AMM, Part -1: StableSwap Invariant, Atul Agarwal https://atulagarwal.dev/posts/curveamm/stableswap/
Curve Finance Discord, “chanho”
https://discord.com/channels/729808684359876718/729812922649542758/1126630568004698132
Curve - Code Explaind - get_y() | DeFi, Smart Contract Programmer https://www.youtube.com/watch?v=jAhKbxoeskQ