简介

背景

随着稳定币的发展,TRON公链上除主流的USDT以外,同时还存在其他稳定币,如USDJ、TUSD、USDC、USDD等。 稳定币市场份额的扩大和种类的增加,催生了稳定币之间兑换的复杂的需求,SUN.io的StableSwap协议定位在稳定币或者等价币之间的交换, 并通过以下两个两种途径,相较于竞品有更低的费率和滑点。

  • 在流动性池中的代币充足的情况下,StableSwap滑点尽可能的小甚至没有;

  • 避免流动性池中某一种代币被全部兑换,StableSwap在某一种代币数量很少的时候会提升兑换价格;

原理简介

如果让交易价格稳定为1,最简单直接的恒等式就是采用一个斜率为-1的直线,即恒定求和公式 x + y = k; 为防止流动性枯竭的问题,需要一个价格自调整的能力,即恒定乘积公式 x * y = k。 为了达到以上途径,StableSwap协议融合了恒定求和与恒定乘积两种方式。可以先简单将其看做恒定求和以及恒定乘积加权求和,即为SUN白皮书中所阐述的做市公式:

Anni=0nxi+D=ADnn+Dn+1nni=1nxiA n^n \sum_{i=0}^{n} x_i + D = A D n^n + \frac { D^{n + 1} } { n^n \prod_{i=1}^{n} x_i }

​根据以上作市公式,代币的兑换会影响 xix_i 的值, 以2pool(USDD, USDT)为例,假设交易前数量为 (x1,x2)(x_1, x_2) , 当投入 x1x1x_{1}^{'} - x_1个USDD换取USDT时, x1x_1 的值会变成 x1x_{1}^{'}, 将 x1x_{1}^{'} 代入以上公式可以计算出新的 x2x_{2}^{'}, x2x2x_2 - x_{2}^{'} 即为换取到的USDT的个数,在这个过程中, AADD 都是不变的, AA 值是常量,在给定 xix_i 的情况下,采用牛顿迭代法求解 DD

D1=D0f(D0)f(D0)=D0D0n+1nni=1nxi+D0(Ann1)Anni=1nxi(n+1)D0nnni=1nxi+Ann1=nD0n+1nni=1nxi+Anni=1nxi(n+1)D0nnni=1nxi+Ann1\begin{align*} D_1 &= D_0 - \frac{f(D_0)}{f'(D_0)} \\ &= D_0 - \frac{\frac{D_0^{n + 1}}{n^n \prod_{i=1}^{n} x_i} + D_0 (A n^n - 1) - A n^n \sum_{i=1}^{n} x_i } {\frac{(n + 1) D_0^n}{n^n \prod_{i=1}^{n} x_i} + A n^n - 1} \\ &= \frac{ \frac{n D_0^{n + 1}}{n^n \prod_{i=1}^{n} x_i} + A n^n \sum_{i=1}^{n} x_i} {\frac{(n + 1) D_0^n}{n^n \prod_{i=1}^{n} x_i} + A n^n - 1} \end{align*}
S=i=1nxi,Dp=D0D0nnni=1nxi,代入上式得:令 S = \sum_{i=1}^{n} x_i , D_p = \frac{D_0 D_0^n}{ n^n \prod_{i=1}^{n} x_i} , 代入上式得:
D1=(nDp+AnnS)D0(n+1)Dp+(Ann1)D0D_1 =\frac{(n D_p + A n^n S) D_0}{ (n + 1) D_p + (A n^n - 1) D_0}

​对应的合约代码如下:

牛顿迭代法求解D值
def get_D(xp: uint256[N_COINS], amp: uint256) -> uint256:
    S: uint256 = 0
    for _x in xp:
        S += _x
    if S == 0:
        return 0

    Dprev: uint256 = 0
    D: uint256 = S
    Ann: uint256 = amp * N_COINS
    for _i in range(255):
        D_P: uint256 = D
        for _x in xp:
            D_P = D_P * D / (_x * N_COINS) 
        Dprev = D
        D = (Ann * S + D_P * N_COINS) * D / ((Ann - 1) * D + (N_COINS + 1) * D_P)
        if D > Dprev:
            if D - Dprev <= 1:
                break
        else:
            if Dprev - D <= 1:
                break
    return D

Last updated