Pre:
查了一些有关uniswap源码解析的文章,找到这篇Uniswap 解析:恆定乘積做市商模型 Constant Product Market Maker Model 的 Vyper 實作里面讲得非常清楚,涉及到一些数学公式的推导,自己推导一遍,之后再去看uniswap的代码会清晰很多。
恒定乘积公式
无手续费:
1 | x * y = k |
-
令交易的两虚拟货币为 X 和 Y,各自数量为 x 和 y
-
两货币数量的乘积 x * y 恆等于 k
-
k 值是由第一笔注入的流动性所决定
因此,用∆x
数量的X
币来购买Y
币所能得到的数量∆y
、或是为了购买∆y
需要付出的∆x
数量
依照此公式进行计算:(x+∆x)(y-∆y) = k
,而交易的价格就是两币量 ∆x
和 ∆y
的比。
以下公式用 α = ∆x / x
和 β = ∆y / y
来表示 ∆x
和 ∆y
及 X
Y
两币在交易发生后的新均衡数量:
公式推导:
这样可以推导出前2行
接着推导∆x
推导∆y
第一个图里的公式,都推导完了。
计入手续费:
在 Uniswap 进行的每一笔交易都会被收取 ρ = 0.003 / 0.3%
的手续费回馈给流动性提供者liquidity provider,因此要将手续费纳入公式的考量:
文里作者推荐从 ∆x
和 ∆y
两值开始去推导
手续费 ρ = 0.3% 的意思是会从付款中扣掉 0.3 %,也就是从∆x
扣。
在有手续费的情况下 ∆x
就变成了 (1-ρ)∆x
,若令 γ = 1-ρ
则为 γ∆x
。因此,将图一中的 ∆x
换成 γ∆x
,就会得到以下式子:
将等号左方的 γ
移到右方后就得到了图二中的 ∆x
接着推导∆y
而 x’
还有 y’
就可以由 ∆x
和 ∆y
推出来
推导x’
:
推导y’
:
将图二中得到的 x’ 和 y’ 相乘,会得到:
当有手续费使得γ != 1
或ρ != 0
,x’ρ * y’ρ
的值其实会稍微和 xy = k
不同
实际上 γ = 0.997
或 ρ = 0.003
,因此 1除以0.997-1 => 1/γ-1 ≒ 0.003
。
β = ∆y / y
代表的是换得的 Y 币佔总量的比例,即使最大值为1(全部兑换出来),误差也只有 1 * 0.003,故可知手续费 = 0.3% 对于 k 值的影响极小。
相关代码:
给定∆x
能购买多少∆y
1 | // @dev 获取的单个输出数额 |
上面已知
代码和公式表达方式不同,因此先将 α = ∆x / x
和 β = ∆y / y
代换回来并将上下同乘 x
:
由于 γ = 0.997
,可以将上下同乘 1000 后得到:
将代码和公式结合起来:
getAmountOut函数,通过入参:
-
amountIn —— ∆x —— ∆x数量的x币
-
reserveIn —— x —— x币的储备量/池子原有的x币数量
-
reserveOut —— y —— y币的储备量
计算出参:
-
amountOut —— ∆y —— ∆y数量的y币
指定的∆y
需要多少∆x
1 | // @dev 获取的单个输入数额 |
一样先将 α = ∆x / x
、β = ∆y / y
和 γ = 0.997
代换并上下同乘 1000y
得到:
将代码和公式结合起来:
getAmountIn函数,通过入参:
-
amountOut —— ∆y —— ∆y数量的y币
-
reserveIn —— x —— x币的储备量/池子原有的x币数量
-
reserveOut —— y —— y币的储备量
计算出参:
-
amountIn —— ∆x —— ∆x数量的x币
最后有个+1,因为solidity
在进行整数除法的时候,余数部分是会被抛弃掉的,相当于向下取整。
+1之后,交易者需要付出多一点点