Cover photo

DeFi 的灵魂 -- AMM 自动做市商模型

这篇文章带大家过一遍DeFi里常见的自动做市商模型。

视频版本可以看这里。ppt内容可以看这里。Mirror上会持续分享一下crypto scientist & analyst 相关的内容,我的mirror主页,我的twitter链接BuidlerDAO链接,欢迎大家关注。

下面是全文内容。


此文从无常损失和滑点两个方面,分析 Uniswap 和 Curve (主流自动做市商) 稳定币做市曲线。

定义

滑点有2种定义。本文采用第一种定义方法,反映交易者成交的真实平均损失。(!!视频里用的第二种定义方式,因为觉得成交后的当时的价格作为市场价格会更有参考意义吧!!)

  1. (成交平均价格-初始价格)/ 初始价格

  2. (成交后价格-初始价格)/ 初始价格

无常损失定义:

  1. 有两种选项

    1. 参加流动性挖矿 ==> w10(参与挖矿的资产市值)

    2. 持有资产,不参加流动性挖矿 ==> W11(不参与挖矿的资产市值)

  2. 无常损失 = (w10 - w11) / w11

结论 -- 稳定币对交易

选择什么样的做市曲线,这是一个滑点(交易者)和无常损失(流动性提供者)的权衡利弊。就稳定币而言,我们追求更低的滑点,且绝大多数情况下价格会在1附近波动。Uniswap v3 和 Curve 曲线会是更好的选择,因为他们相当于加个杠杆的uniswap v1/v2 曲线,同样的成交量可以带来更低的滑点。而Uniswap v3 和 Curve 曲线可以通过调整参数(价格区间和A值)达到相似的效果。就现在市场而言(P=[0.9986, 1.0014], A=5000),Curve 能够在价格在1附近提供更好的滑点,而无常损失和Uniswap v3 基本一致。假设稳定币价格不会脱钩,Curve 会是更好的选择。

滑点

假设我们从价格为1的点开始做交易

  1. 相同的成交量,Curve上的滑点低于Uniswap v1/v2。如果我们单次交易池子里一个币对的99.9999%存量,Curve上的滑点也低于Uniswap v1/v2。对交易者来说,Curve 确实会带来更好的用户体验。

  2. Uniswap v3 采用了设置区间的方式来放大流动性。在区间范围内,Uniswap v3上的滑点始终低于Uniswap v1/v2。但只要超出区间,Uniswap v3交易对就失去了流动性,无法交易。

  3. Uniswap v3的价格区间的宽窄就类似于Curve曲线中A值带来的杠杆。Uniswap v3所对应的滑点和我们想要的成交数量和资产效率乘数是线性相关的。Curve曲线会随着A值的变大,滑点由线性变得更弯曲。不同的价格区间和不同的A值会带来不同的滑点:

    1. Uniswap v3: [0.8, 1.25]; Curve A =2 (图1)==> Uniswap v3 滑点低

    2. Uniswap v3: [0.8, 1.25]; Curve A =8 (图2)==> 成交量比较小,Curve 滑点低;成交量比较大,Uniswap v3 滑点低

    3. Uniswap v3: [0.8, 1.25]; Curve A =50 (图3)==> 成交量比较小,Curve 滑点低;成交量比较大,Uniswap v3 滑点低

    4. Uniswap v3: [0.9986, 1.0014]; Curve A = 5000【现在市场情况】 (图4)==> 成交量比较小,Curve 滑点低;成交量比较大,Uniswap v3 滑点低。绝大多数情况,同样成交量,Curve 滑点更低。

  4. 就现在市场而言 (图4),成交量较小时,Curve 滑点 < Uniswap v3 < Uniswap v1/v2。如果出现出现巨额成交量(超90%)或者池子内一个币的数量偏移90%以上或者严重脱钩(稳定币价格远离1),Uniswap v3 滑点 < Curve < Uniswap v1/v2

图1: Uniswap v3:
图1: Uniswap v3:
图2: Uniswap v3:
图2: Uniswap v3:
图3: Uniswap v3:
图3: Uniswap v3:
图4:Uniswap v3:
图4:Uniswap v3:

无常损失

此处做了两个重要假设:

  1. 池子里只有两个币对(A, B)

  2. A和B的初始数量为1:1

结论

  1. 同样成交量下,Curve滑点比uniswap v1/v2更低,但是在同样价格变化下,Curve无常损失更大。随着A值增大,Curve滑点越来越低,无常损失也越来越大(图5)。

  2. 为达到和uniswap一样的价格,Curve池需要更多的成交量。假设P0=1

    1. A = 1时,一次性交易池内99%的一个币,价格变化99.3%

    2. A = 100时,一次性交易池内99%的一个币,价格变化84.8%

    3. A = 1000时,一次性交易池内99%的一个币,价格变化38%

    4. ==> 因为需要更多的成交量,Curve 很难出现和Uniswap同样的价格。但是假设没有无风险套利机会,Curve 和Uniswap V1/v2 上 是同样的价格,Curve 无常损失更大。

  3. 同样成交量下,Uniswap v3滑点比uniswap v1/v2更低,但是同样价格变化下,Uniswap v3无常损失更大。随着价格区间变小,Uniswap v3滑点越来越低,无常损失也越来越大(图6)。

  4. 同样是加了杠杆的Uniswap v1/v2仓位, Uniswap v3和Curve 有什么区别呢?

    1. 固定Uniswap v3价格区间为[0.8, 1.25], 我们变化 Curve 的A值,我们可以看到,Uniswap v3 的无常损失曲线是在Curve[A =10] 和Curve[A =100] 之间的。也就是说,通过变化A值,Uniswap v3 和 Curve 的无常损失可以达到类似效果。(图7)

    2. Uniswap v3: [0.9986, 1.0014]; Curve A = 5000【现在市场情况】。就现在市场而言,同样价格变化,Curve 和 Uniswap v3 的无常损失基本一致。(图8)

图5
图5
图6
图6
图7
图7
图8
图8

详细python实现见此:python

详细excel实现见此:excel


以下是公式推导

Uniswap v1/v2

做市曲线 -- 恒定乘积做市

x * y = k = L^2

其中x,y分别代表代币x和y的数量。因为k>0,可以把它定义为L^2

价格 (以y为基本单位,x的价格)

y = L^2 / x ==> dy = - L^2 / x^2 dx ==>  
P = - dy / dx = - (- L^2 / x^2 dx) / dx = L^2 / x^2 = y / x
 
x = L / sqrt(P)
y = L * sqrt(P)
价格为边际数量变化之商
价格为边际数量变化之商

成交价格

假设流动池里的币对从(x1,y1) 变化到(x2,y2),而价格从p1变化到p2

post image

滑点

post image

无常损失

w10: wealth at time t1 if participate as UNISWAP LP at time t0 
w11: wealth at time t1 if hold half asset x and half asset y at time t0
p(t1): price for x at time t1 
p(t0): price for x at time t0

Assume r = p(t1) / p(t0)

!!! all the wealth are denominated in y. 

w10 = p(t1) * x1 + y1 
    = p(t1) * L / sqrt(p(t1)) + y1
    = L * sqrt(p(t1)) + y1
    = 2 * L * sqrt(p(t1))

w11 = p(t1) * x0 + y0 【the quantities remain the same】
    = p(t1) * L / sqrt(p(t0)) + y0
    = r * P(t0) * L / sqrt(p(t0)) + y0 
    = r * sqrt(p(t0)) * L + sqrt(p(t0)) * L
    = (1 + r) * sqrt(p(t0)) * L
 
IL = w10 / w11 - 1   
   = 2 * L * sqrt(p(t1)) / ((1 + r) * sqrt(p(t0)) * L) - 1
   = 2 * sqrt(p(t1)) / ((1 + r) * sqrt(p(t0))) - 1 
   = 2 * sqrt(r) / (1 + r) - 1 

做市曲线 -- 恒定乘积做市

post image
what's new:
Pa: low range for x
Pb: up range for x
Pc: current price for x 
Pa < Pc < Pb 

x_v: virtual reserve for x 
y_v: virtual reserve for y 
L: virtual liquidity 

(x + L / sqrt(Pb)) * (y + L * sqrt(Pa)) = L^2 

x_v * y_v =  L^2 
x_v = x + L / sqrt(Pb)
y_v = y + L * sqrt(Pa)

Pc = - dy / dx = y_v / x_v     
x_v = L / sqrt(Pc)
y_v = L * sqrt(Pc)

x = x_v -  L / sqrt(Pb)
  = L / sqrt(Pc) - L / sqrt(Pb)

y = y_v - L * sqrt(Pa)
  = L * sqrt(Pc) - L * sqrt(Pa)

无常损失

w10: wealth at time t1 if participate as UNISWAP LP at time t0 
w11: wealth at time t1 if hold half asset x and half asset y at time t0

Assume r = p(x1) / p(x0)
post image
post image
post image

资本效率乘数

w_v2 = w_v3
w_v2 = w_v3
post image

单区间滑点

假设V3只有一个流动区间

  1. V2滑点 = 资本效率乘数 * V3滑点

  2. 区间越小, V3滑点越小

post image

实际上,Uniswap v3 是无数个流动性区间累加起来的。每个tick之间对应其单独的流动性,只有这个tick对应的流动性被耗尽,才会进入下一个区间继续寻找流动性。

Curve v1

Curve 是 恒定乘积做市 和 恒定和做市的结合。当 A 取值接近于0时,Curve 曲线 = Uniswap v1/v2 曲线;当 A 取值接近于无穷时,Curve 曲线 = 恒定和做市曲线。A 越大,Curve 曲线越向恒定和做市曲线倾斜。

做市曲线 -- 恒定乘积和恒定和结合做市

post image

A ==> 扩增参数(amplification parameter)

D ==> 不变量参数 (StableSwap invariant)

post image

其中,Ann = An^n

如何计算置换的量

假设我们手上有 xi,想去池子换成 xj (=y)。

post image

通过上图的变化,再加上一些简化,我们就可以得到

post image

这个问题就变为,在满足f(y)=0的情况下,求解y。这是一元二次方程,可以直接用求根公式,但Curve.fi 用的牛顿迭代法(可能是Solidity没有根号?)。

牛顿迭代法 (Newton Raphson Method)
牛顿迭代法 (Newton Raphson Method)

由于f’(y) = 2y + (b-D),我们就可以得出下图的迭代公式了

Curve Stable Swap - 牛顿迭代法
Curve Stable Swap - 牛顿迭代法

如何计算D

和计算置换量类似的方法,我们假设x,y不变,对做市曲线求解D。

post image

这里的S = sum(xi)。

求导
求导

其中 Dp 如下图

Dp
Dp

同样用牛顿迭代法,求解D「注:当n=2,此方程有闭式解;当n>2,使用牛顿迭代法」

Curve Stable Swap - 牛顿迭代法
Curve Stable Swap - 牛顿迭代法

现在假设n=2(池子里只有两个币对),x和y

做市曲线 (n = 2, x1 = x, x2 = y)

n = 2, x1 = x, x2 = y
n = 2, x1 = x, x2 = y

如何计算D

已知x,y求D,这是一个三元方程, 可以通过卡尔达诺公式(Cardano Formula)求解

post image

其中

post image

值得注意的是,假设不添加或删除流动性,D是恒定的。x的变化只会带来y的变化。

如何计算置换的量

已知n=2,n^n =4, 带入之前的置换公式,可以得到

post image

同理,对于y来说,这是一个一元二次方程,可以用求根公式求解。

post image

其中a, b, c 分别为:

post image

置换后价格

我们知道

post image

对等式两边求导得到

post image

即可得到y’的公式

post image

我们知道价格等于边际变化量之比,即p_x = -y’ = -dy / dx。通过上述公式,我们就可以得到置换后价格。

滑点

已知 p_x = - y’ = g(x,y),对任意(x,y),我们都可以求到其对应的价格。也可以求到平均价格。再利用滑点定义【(成交平均价格-初始价格)/ 初始价格】,即可以求出滑点。

无常损失

已知做市曲线f(x,y) = 0 和 p_x = - y’ = g(x,y),两个方程求解两个未知数(x,y),我们就可以求到 x,y 分别关于 D和 p_x 的函数。然后再通过无常损失定义【(w10 - w11) / w11】,即可以求出无常损失。

首先找到 y = f(p,x),如下图。

post image

然后我们还知道 y = f(x),所以通过y = f(x) = f(p,x),我们就可以求解 x = f(p) 。这是一个一元四次方程,不太容易解出来,就没继续了。


**此处考虑另外一种方法画出无常损失曲线。**首先我们假设池子里的初始币对(x,y)数量为1:1,那么对于每个给定的y的数量变化,我都可以得到对应x的数量变化,从而计算得到变化后的价格。已知了初始价格,初始数量,新价格和新数量,我们就可以通过无常损失定义,计算出其无常损失了。为了画出,我们就需要一个y的数量变化的列表【dy= [-99, -98, -97, ……, 99]】,然后计算出当前价格,再计算出无常损失。我们就可以得到一个当前价格和无常损失的一一对应关系列表。即可以画出价格对应的无常损失的曲线。

详细python实现见此:python

详细excel实现见此:excel

!!!在推导Uniswap无常损失时,我们是没有限制初始币对数量的。它的机制,在任何时刻,两个币对的价值都是1:1。所以不管当前池子里数量是什么,我们都可以通过公式直接得出无常损失。而在推导Curve无常损失时,我们假设了初始币对数量为1:1。我们通过初始币对数量求到D=x+y=2x=2y(如果不添加或删除流动性,D不变),再通过成交量就可以求到无常损失。 如果初始币对数量不是1:1,那么同样的价格变化(与1:1的初始状态相比),对应的无常损失会不一样。

公式

https://www.overleaf.com/read/zgcffvfngxcp

参考目录

https://dev.balancer.fi/resources/pool-math/stable-math

https://atulagarwal.dev/posts/curveamm/stableswap/#mjx-eqn%3Aeqn%3Astableswap

https://alvarofeito.com/articles/curve

https://pandichef.medium.com/the-slippage-ratio-a-new-metric-to-understand-curve-fis-amm-protocol-fddf0ba4d6c8

https://github.com/curvefi/curve-contract/blob/master/contracts/pools/usdt/StableSwapUSDT.vy

https://medium.com/auditless/impermanent-loss-in-uniswap-v3-6c7161d3b445

Uniswap v1 example: https://hackmd.io/@HaydenAdams/HJ9jLsfTz?type=view#🦄-Uniswap-Whitepaper

Uniswap V2 白皮书:https://uniswap.org/whitepaper.pdf

Uniswap V3 白皮书:https://uniswap.org/whitepaper-v3.pdf

Curve v1 白皮书:https://curve.fi/files/stableswap-paper.pdf

Curve v1 详解:https://alvarofeito.com/articles/curve/