這篇文章的第一部分討論了StableSwap不變數。
StableSwap
放大不變數是一個數學概念,旨在透過減少交易中的滑點來提高流動性池的效率,同時仍然允許價格失衡的靈活性。它結合了恆定和恆定乘積不變數的特點,創造了一個在低滑點(接近平衡)和任何價格下的可追溯性之間取得平衡的公式。
感謝您閱讀Verichains!免費訂閱以接收新帖並支援我的工作。
恆定乘積不變數(∏x_i=k):用於Uniswap型別的池。它非常靈活,支援任何價格的交易,但大交易的滑點會顯著增加。
恆定和不變數(∑x_i=k):用於穩定幣。它對平衡交易沒有滑點,但無法處理大的價格失衡。
放大不變數結合了兩者的優點:接近平衡時的低滑點和失衡交易的靈活性。StableSwap中放大係數引數的特點是,係數越低,不變數就越接近恆定乘積。
引入了一個槓桿因子χ來減少滑點。這個因子調整了不變數的形狀,使其能夠融合恆定乘積和恆定和不變數的特性,提高其在不同交易場景下的效率。
一般公式為:
其中:
χ:控制不變數曲率的槓桿因子。
D:平衡時代幣價值之和的常數。
n:池中代幣的數量。
∑x_i:代幣數量之和。
∏x_i:代幣數量之積。
如果這個方程式一直成立,使用者將獲得槓桿χ的交易。但是,它不會支援價格遠離理想價格1.0的情況。不變數應該支援任何價格(以確保在任何時候都有一些流動性)。所以Stable Swap使χ動態化。當投資組合完全平衡時,它等於一個常數A,但當失衡時會降至0:
StableSwap不變數將χ加入到一般公式(1)中:
有兩個常見的數學運算需要計算:
給定固定的A值和儲備x_1,x_2,...x_n(其中n是池支援的代幣數量,在部署池時就固定了),計算D。
給定D,使用者希望增加一個儲備xi的值到x'_i,計算另一個儲備x_j需要減少多少,以保持方程平衡。
在Curve V1(StableSwap)中,D的行為類似於Uniswap V2中的k - D越大,儲備越多,價格曲線就越"遠離"。在新增或移除流動性,或費用變化導致池平衡發生變化後,D都需要重新計算。
定義S=∑x_i和P=∏x_i,方程(3)現在變為:
例如,如果池中只有兩種代幣,不變數將變為:
在StableSwap原始碼中,它透過計算D_next來計算D:
這段程式碼中的方程可以寫為:
例如,我們有100,000 USDC和1,000,000 USDT在池中。使用(3)或(4),我們可以計算出D約為1,094,540.84。這是一個使用(5)(因為它是(4)的示例)計算D的簡單Python指令碼:
我們可以再次使用該常量D來計算USDT或USDC的數量,使用(6)。
StableSwap使用牛頓法數值求解方程,因為它無法代數求解。StableSwap建立f(D),當方程(4)平衡時等於0。此外,它還計算導數f′(D)。
StableSwap使用牛頓法求解D,其中D可以理解為當前的D值:
首先,我們可以透過將所有元素合併成一個分數,並將分數的分子和分母都乘以D來重寫(8):
透過使分母等於f'(D)來重寫牛頓法,然後用(10)代替:
將所有項分配到分子中的括號中:
在(11)中消除所有項後,我們可以定義一個元素D_p為:
方程變為:
這個方程等同於(6)中定義的方程。
此外,在Viper程式碼中,D_p的計算方式為:
D_P: uint256 = D # D_P = Sfor _x in xp:D_P = D_P * D / (_x * N_COINS)xp是代幣數量,所以迴圈將執行n次。因此,我們在分母中有D乘以自身n次。
然後我們可以計算y或x'_j(即x_j的新值)當用戶增加一個儲備x_i的值到x'_i時。
使用S=∑x_i和P=∏x_i.假設要計算代幣y的值,給定D, A, n;讓我們稍微調整一下S和P的公式:
S′和P′是除了我們要計算的代幣y之外的所有代幣的餘額之和和乘積。
公式從(4)變為:
同樣,StableSwap使用牛頓法數值求解方程。這次它建立了f(y)和導數f′(y)。
StableSwap的牛頓法求解y為:
將(13)和(14)組合成該方程,可以轉換為:
再次重寫(16)方法,使分母等於(14):
另一方面,(12)可以重寫為f(ADn^n):
將其代入(17),然後消除所有項:
我們將分子和分母都乘以y/(A*n^n):
再次重寫不變數(12),並將其代入(20):
公式(23)可以執行為:
在Viper原始碼中,定義了兩個變數:
將其代入公式(24),我們得到:
Curve原始碼中有兩個計算y的函式,get_y和get_Y_D。`get_Y_D`函式根據D計算y,與上述方法相同。此外,`get_y`函式在一個代幣x的數量從x變為x'時計算新的y。回到上面的例子,如果我們想將10,000 USDT兌換成USDC,使用get_y函式,使用者可以獲得9,253.70 USDC。這是因為,在該示例中,USDT的數量是USDC的10倍。因此,當用戶將USDT兌換為USDC時,會產生滑點。
需要注意的一點是,Curve的白皮書使用的不變數是An^n (A * n ** n),但在Viper原始碼中,不變數是Ann (A * n * n)。
程式碼庫反而計算A_ * n。這種差異是因為程式碼庫將A_儲存為:









