uniswap v3 copy 自 https://liaoph.com/ (因为自己没有怎么看懂,收藏以后常看)。
官方博客(https://uniswap.org/blog/uniswap-v3/)
v3白皮书(https://uniswap.org/whitepaper-v3.pdf)
设计原理
官方的白皮书已经比较详尽的描述了 v3 的设计原理,这里仅对白皮书中的内容做一些补充,包含本人对其中一些机制的理解和思考。
Uniswap v2 版本使用 x⋅y=k 这样一个简洁的公式实现了 AMM Dex,正是由于其简洁易用性,使其在短短的一年的时间内迅速成长为 DeFi 领域的龙头项目。但是随着 DeFi 生态走过了「从无到有」的阶段,因为 v2 无法满足某些特定需求,从而诞生了 Curve, Balancer 这些针对某些功能进行改进的 AMM。简单来说,官方认为 v2 版本最大的痛点是资金利用率(Capital Efficiency)太低,v3 版本在解决这个问题的同时,还带了了新的改进,总体总结如下:
1.可灵活选择价格区间提供流动性
2.更好用的预言机
3.order book 功能
4.灵活的费率
提升资金利用率
解决资金利用问题之前,我们可以观察到大部分的交易对的价格,在大部分时间内都只是在一个固定范围内波动。例如 ETH/DAI 交易对,在近一个月时间内都是在 1300 ~ 2200 DAI/ETH 这个范围内波动。更极端的例子是 DAI/USDC 这样的稳定币交易对,在大部分时间内都只是在 1.001 ~ 1.002 DAI/USDC 范围内波动。
v2 的问题
我们先来看一看 v2 版本的资金利用率是怎样的,假设 ETH/DAI 交易对的实时价格为 1500 DAI/ETH,交易对的流动性池中共有资金:4500 DAI 和 3 ETH,根据 x⋅y=k,可以算出池内的 k 值:
k=4500×3=13500
假设 x 表示 DAI,y 表示 ETH,即初始阶段 x1=4500,y1=3,当价格下降到 1300 DAI/ETH 时:
![](https://img.haomeiwen.com/i13781704/d29068ff497e9cf4.png)
得出 x2=4192.54,y2=3.22,资金利用率为:Δxx1=6.84%。同样的计算方式,当价格变为 2200 DAI/ETH 时,资金利用率约为 21.45%.
也就是说,在大部分的时间内池子中的资金利用与低于 25%. 这个问题对于稳定币池来说更加严重。
解决方案
v3 版本的解决方案是允许用户只在一段价格区间内提供流动性。如下图
![](https://img.haomeiwen.com/i13781704/e8316400c97a53b0.png)
此图展示了一个 x⋅y=k 的函数曲线图。为了满足让用户可以选择只在 [a,b] 价格区间内提供流动性。对于图中 [a,b] 区间的任意点,都有:
x=xvirtual+xreal
y=yvirtual+yreal
其中 xreal,yreal 分别表示用户提供的 x token, y token 数量,xvirtual,yvirtual 分别表示流动池虚拟出的 x token y token 数量。注意,虚拟出的 x token 和 y token 只是为了计算一致性,并不会参与真实交易,因此其数量是恒定不变的。
当流动池的价格来到用户设置的零界点时(例如图中的 a 点或者 b 点),用户实际提供的 x token 或者 y token 将为 0,x 或 y 将完全由虚拟 token 组成。为了保证虚拟 token 恒定不变,当价格进一步变动,移动到用户设定的价格区间之外时,流动池会移除这部分流动性,以保证虚拟的 x token 或 y token 数量不会减少,因此这部分虚拟的 token 只会在价格处于设定的区间内时参与价格的计算,而不会真的参与流动性提供(即虚拟 token 数为常数,并不会发生数量变化)。
例如,当价格到达 a 点时,用户的所有资金转换为 x,此时 yreal=0,y=yvirtual,当价格继续降低时,流动池将移除这部分流动性。用户的资金状态将停留在 a 点,直至价格再次回到 a 点并进入 [a,b] 价格区间。
通过这样的设计,用户的资金只会在 [a,b]价格区间内提供流动性,并且因为虚拟 token xvirtual,yvirtual 的参与,这部分流动性也满足 x⋅y=k 公式,计算价格的方式并没有产生变化。
![](https://img.haomeiwen.com/i13781704/9c3c61d45b98078a.png)
上图展示了用户选择在价格 [a,b] 之间提供流动性时,通过虚拟 token 的参与,将曲线 f(real) (橘红色)向右上方移动至 f(virtual)(绿色),实现了价格计算的一致性(即满足x⋅y=k)。
流动性聚合
上面我们说了,通过引入虚拟 token 的概念,让用户可以在某一个价格区间内提供流动性。而每一个用户提供的流动性都可能设置不同的价格区间,这样一来一个交易对的池子中就包含了多个不同的流动性。因此从单个交易池的视角来看,Uniswap v3 实际上扮演的角色是一个交易聚合器:当发生交易时,此交易会拆分成多个,通过池中多个不同的流动性来进行交易,最后将交易结果聚合,完成最终的交易过程。
从交易聚合器的角度看,在交易发生前,池中每一个流动性中的 token price 是一致的。那么我们需要让交易结束后,池中每一个流动性中的 token price 仍然是一致的(当然这里仅包含所有在区间内的流动性)。因此 v3 的交易过程会围绕价格来进行,这样可以保证所有流动性的价格一致。事实上这就和 AMM 交易聚合器的行为一致,因此我们可以把 Uniswap V3 理解成单个交易池中不同流动性的交易聚合器。
交易过程
![](https://img.haomeiwen.com/i13781704/6c6bbd1f944b7f25.png)
具体的实现,可以参考 v2 代码实现。
v3 版本
![](https://img.haomeiwen.com/i13781704/22238b72df9b089a.png)
如上图最右边所示,当价格变化时,流动池中的总流动性也会随之变化。因此 v3 版本流动池中资金的关系不能像 v2 版本一样用一个平滑的 bonding curve 曲线来表示。那么如何计算交易结果呢?
在前面我们说过,V3 的行为类似一个交易聚合器,它需要保证池中所有流动性的价格在交易前后一致。因此 V3 会围绕池中的代币价格来进行。
对于一个流动性来说,流动性大小可以用 k 表示,即 k=x⋅y,用 P 表示 x 的价格,即 P=yx
对于一个流动性来说,当使用 x token 交换 y token 时,我们需要进行如下计算:
交易至指定价格(不可以超出此流动性的边界价格)P,需要的 x token 数 Δx,可以获得的 y token 数 Δy
给定 x token 数 Δx(假设不会引发价格超出此流动性的边界价格),可以获得的 y token 数 Δy,以及最终的价格 P
当 k 值不变时,根据定义:
![](https://img.haomeiwen.com/i13781704/66078640bb08c785.png)
这样一来计算过程并不需要关注流动性中的 x token 和 y token 余额,通过 k 值和价格 P 就可以完成交易过程的计算。
![](https://img.haomeiwen.com/i13781704/7e03fcfb2bb710c3.png)
价格精度问题
![](https://img.haomeiwen.com/i13781704/474d428ee07063c3.png)
tick 管理
![](https://img.haomeiwen.com/i13781704/8bf56785219c3a45.png)
灵活的手续费选择
v3 版本内置了三种梯度的手续费率(0.05%, 0.30%, and 1.00%),同时可以在未来增加更多的费率值。关于手续费的计算过程,这部分放在后文来详解(链接:交易手续费)。需要注意的是,由于需要支持多种费率,同一个代币对 v3 版本会有多个不同的流动池。例如 ETH/DAI 代币对,会分成三个池,分别对应 0.05%, 0.30%, 1.00% 的手续费。
更多的费率选择性,这样做会更加灵活,但是同时也会带来一定的流动性分裂,uni 官方表示后续可以通过治理添加更多的费率可选值,这也势必会让流动性更加分裂。那么可能会出现一种情况是,即使是只使用 uniswap v3 这单个 AMM 来完成一笔交易,但是因为代币对的流通性分散在多个池子中。那么最优的交易策略是使用交易聚合器(例如 1inch)来进行交易,即将单笔交易拆散,同时使用多个流动性池来完成交易。就目前 uniswap v3 前端代码情况来看,官方的界面是不支持这种聚合交易的,其 sdk 代码中的注释也说明了这个问题:SDK 代码。
手续费与 tick 的关系
![](https://img.haomeiwen.com/i13781704/543ca1d3994300e9.png)
代码架构
Uniswap v3 在代码层面的架构和 v2 基本保持一致,将合约分成了两个仓库:
core 仓库的功能主要包含在以下 2 个合约中:
- UniswapV3Factory: 提供创建 pool 的接口,并且追踪所有的 pool
- UniswapV3Pool: 实现代币交易,流动性管理,交易手续费的收取,oracle 数据管理。接口的实现粒度比较低,不适合普通用户使用,错误的调用其中的接口可能会造成经济上的损失。
peirphery 仓库的功能主要包含在以下 2 个合约:
- SwapRouter: 提供代币交易的接口,它是对 UniswapV3Pool 合约中交易相关接口的进一步封装,前端界面主要与这个合约来进行对接。
- NonfungiblePositionManager: 用来增加/移除/修改 Pool 的流动性,并且通过 NFT token 将流动性代币化。使用 ERC721 token(v2 使用的是 ERC20)的原因是同一个池的多个流动性并不能等价替换(v3 的集中流性动功能)。
这些合约间的关系大致如下图:
![](https://img.haomeiwen.com/i13781704/ecb90f598170b9ae.png)
本系列后续会从常用的 Uniswap v3 操作入手,讲解代码调用流程。一般来说,用户的操作都是与 uniswap-v3-periphery 开始。
网友评论