加粗为自己添加的内容
配套课程视频:【01 区块链金融课程简介】- B站
课程实验以及讲义:liangpeili/defi-practices - Github
完成的实验代码:
github.com/DestinyWei/…
github.com/DestinyWei/…
若有任何问题或错误,可在Notion评论或直接评论
完整笔记请查看 Notion 链接:dune-marten-78b.notion.site/85b1d29c863…
个人博客:Howe的个人博客
Uniswap V2
手续费的计算机制
- 手续费全给项目方
因为项目方在池子中并没有 share,所以需要进行增发即 Sm 部分
S1:LP 提供流动性得到的 share 数量 Sm:系统按手续费比例增发的 share 数量
k1:添加流动性对应的 k 值 k2:添加流动性加上增发的 share 所对应的 k 值

由上面可得,
S1+SmSmSm∗k2Sm=k2k2−k1=S1∗k2+Sm∗k2−S1∗k1−Sm∗k1(化简)=k1k2−k1∗S1
- 手续费全给 Liquidity Provider
LP 的手续费并不是给 LP 增发新的 share 即 Sm=0,而是仍然是 S1 的数量,但随着手续费的累积,k 值会变大(此时可以理解为,LP 的 share 数量没有变化,在没有手续费收入的时候只共享 S1 价值,在有手续费收入的时候则共享 S1+手续费 价值 )
所以,LP 为 0,项目方为 0
例子:最开始有100 DAI:1 ETH (k 值为 100),经过一系列的交换,此时池子中有 96 DAI:1.5 ETH (k 值为 144)
- 项目方拿取一定比例(用 ϕ 表示,为 Sm 占整个增发部分的比例)的手续费

由上面可得,
Sm+S1Sm=k2k2−k1∗ϕ
Sm+S1Sm 表示的是项目方增发的比例,k1k2−k1 表示的是 LP 增加的比例
由此可以推导出
Sm∗k2Sm=Sm∗k2∗ϕ+S1∗k2∗ϕ−Sm∗k1∗ϕ−S1∗k1∗ϕ=(ϕ1−1)k2+k1(k2−k1)∗S1
当 ϕ=1 时,则为手续费全给项目方时所得到的公式
Spot Price
在使用 x 交换成 y 的时候,显示的价格为 P0=xy,但实际成交价格为 P1=ΔxΔy,P0 和 P1 之间的差值就是所谓的滑点

x∗yΔxΔy=(x+Δx)∗(y−Δy)=x+Δxy
当 Δx 较小时,我们可以理解为是在计算 limΔx→0x+Δxy
Price Oracle
TWAP (Time Weighted Average Price) 时间权重的平均价格
Pn 是在 tn 时间点的价格

由上面可得,
i=0∑n−1Pi∗(Ti+1−Ti)
假如我们想要从 tk 计算,而不是从 0 计算

由上面可得,
P=Tn−Tk∑i=kn−1Pi∗(Ti+1−Ti)=Tn−Tk∑i=0n−1Pi∗(Ti+1−Ti)−∑i=0k−1Pi∗(Ti+1−Ti)
通过这个公式,我们可以计算比如一个代币在一小时里的平均价格
如何计算 Uniswap V2 的无常损失
无常损失是出现在添加/移除流动性的情况下,而滑点是出现在两个代币交换的情况下
假设我们有一个初始 LP 为:100DAI:1ETH,此时 K = 100,PE=1100=100,两个代币总价值为 100 + 100 = $200
- 当 ETH 涨价时,LP 为:120DAI:0.83ETH,此时 K 不变,PE=0.83120=144.58,两个代币总价值为 120 + 120 = 240,但如果我们并没有添加流动性而是拿住最开始的100DAI和1ETH,两个代币总价值为100+1∗144.58=244.58,那么 244.58 与 240 的差值就是无常损失的值
- 当 ETH 降价时,LP 为:80DAI:1.25ETH,此时 K 不变,PE=1.2580=64,两个代币总价值为 80 + 80 =160,但如果我们并没有添加流动性而是拿住最开始的100DAI和1ETH,两个代币总价值为100+1∗64=164,那么 164 与 160 的差值就是无常损失的值
即在添加流动性所产生的无常损失会导致 ETH 涨价时相比拿住赚得更少,ETH 降价时相比拿住亏得更多
通过上面的例子我们可以抽象出更通用的模型,我们可以列出下面这三个公式,Pi 表示在 i 时刻某个代币的价格,d 表示价格变化的因素 (当 0<d<1 时表示降价,d=1 时表示价格不变,d>1 时表示涨价)
P1x∗yP=P0∗d=k=xy
由 (2) (3) 可以计算得到 x 和 y 用价格P 和流动性k 的表达式
x=yk⇒yk=Py⇒y2x=k∗P⇒y=k∗P=Py=Pk∗P=Pk
假设一开始为 t0、x0、y0、P0=x0y0
添加流动性(无手续费)之后为 t1、x1、y1、P1=x1y1
拿住为 thodl、x0、y0、P1=x1y1
将无常损失与价格变化之间的关系函数设为 f(d),V 表示为代币的 value,则
f(d)=拿住之后的价值做LP的损失=VhodlV1−Vhodl=VhodlV1−1
由 (4) (5) 可以计算出 V1,Vhodl
V1=y1+x1∗P1=k1∗P1+P1k1∗P1Vhodl=y0+x0∗P1=k0∗P0+P0k0∗P0∗d=2∗k1∗P1=(1+d)∗k0∗P0
所以
f(d)=(1+d)∗k0∗P02∗k1∗P1−1=(1+d)∗k0∗P02∗k1∗P0∗d−1(因为无手续费,所以k1和k0相同)=1+d2∗d−1
Uniswap 官方文档中给出的无常损失与价格变化的关系曲线

Flash Swap

传统的借贷需要用户先超额抵押才能借出代币
闪电交换是指用户无需质押一分钱即可借出一定数量的代币,例如当你发现有一个套利机会但没有足够的资金去进行超额抵押借贷时,我们可以通过闪电借贷借出 100 个 DAI,然后将这些 DAI 进行一系列的投资等去获取收益如变为 110 个 DAI,此时我们在把借出的 100 个 DAI 及其利息归还,剩下的收益就是自己的也就是 7 个 DAI
使用 Flash Swap 加杠杆
用户持有 3 个 ETH,每个 ETH 的价格为 200 DAI,抵押率为 150%。用户想要 2 倍杠杆
传统借贷
- 添加 3 ETH 到 Maker Vault
- 借出 400 DAI 出来
- 在 Uniswap 把 DAI 换成 ETH
- 重复 1-3 步
闪电借贷
- 跟 Uniswap 借 3 个 ETH
- 把用户的 3 个 ETH 和借的 3 个 ETH 抵押到 Maker Vault
- 借出 800 个 DAI 出来
- 还给 Uniswap 600 DAI
Uniswap V2 代码结构

Uniswap V2 的核心合约就只有三个,分别是 Router、Factory 和 Pair 合约
图中的三个操作分别为 ① add liquidity ② swap ③ remove liquidity
用户通过前端页面即页面右边的长方块进行上述的三种操作时,会通过 Router 合约来判断执行的操作并调用相关合约的函数,在路由时合约会判断当前用户执行操作所对应的 Pair 是否已创建,若没有则会先创建一个 Factory 合约来创建相关的 Pair 合约,若有则直接调用对应 Pair 合约的函数
Uniswap V2 总结
一个核心:CPAMM
三个操作:添加流动性 / 加密资产交易 / 移除流动性
几个概念:手续费 / Price Oracle / TWAP / Falsh Swap / 无常损失 / 滑点等
后续笔记会在之后发布,让我们尽情期待,您也可以关注我的推特账号(@weihaoming)以获取更多笔记资源……