去中心化交易协议uniswap 和 aave
去中心化交易协议uniswap 和 aave
uniswap
uniswap是去中心化交易所的标杆项目,v1、v2、v3
概念说明:
-
AMM 自动做市商,做市商是指对于一种资产双向报价概念
-
gas费,由于链的出块需要支付矿工打包的费用,所以用户的交易需要支付gas费,矿工打包区块需要花费计算资源维护区块链的一致性。
-
恒定乘积公式,x*y=k公式
-
流动性池,两种代币做交换的庄家
-
流动性,反映流动性池的深度(庄家的资产多少)
-
滑点,原本可以买到100个娃娃,实际到手91个,9个就是此次交易的滑点
在出现uniswap之前,区块链使用的是传统的订单薄模式,只是在去中心化约束下实现的。交易过程中,需要撮合开市商者和交易者交易,属于链下磋商,链上交易。由于底层公链性能限制,交易后订单薄存储在链下,存在中心化问题。为什么不支持订单薄上链,因为以太网链低吞吐量,每秒只能处理15-30笔交易,出块时间最少12秒,因为订单薄是一个高频操作,高延时不说, gas费更是天价。为了解决这种不完全去中心化的需求,uniswap孕育而生。
v1
使用合约,把交易的撮合过程上链,开创了AMM模式,引入恒定式乘积公式,也就是x*y=k公式。在这个模型中,流动性池包括两种代币,比如ETH和USDT。流动性提供者将两种代币按照当前的加个比例存入池子,获取LP代币作为凭证。交易者可以用一种代币兑换另一种代币,每次交易都会改变池子中两种代币的数量,但是保持k不变。
举例:初始池:10 ETH, 40,000 USDC。k = 10 * 40,000 = 400,000。
你想用1个ETH买USDC。
-
你先存入1个ETH,池子变成:
x = 11 ETH。 -
为了保持
k = 400,000,USDC的数量必须变为:y = k / x = 400,000 / 11 ≈ 36,363.64。 -
这意味着你可以拿走的USDC是:
40,000 - 36,363.64 = 3,636.36USDC。 -
你得到的汇率是:1 ETH = 3,636.36 USDC,低于初始的4000 USDC,这是因为你的交易对池子产生了影响(滑点)。
但是只支持ETH、ERC20之间的交易,ERC20之间的交易需要以ETH作为媒介进行两次交易。
这导致交易高滑点,高gas。
v2
v2解决了强制通过ETH交易的限制。
v2的特点是流动性在整个价格区间均匀分布,无论价格在哪里,所有的流动性都在工作,这种设计简单直观,但是资金利用率不高,比如ETH价格在2000U附近,但池子中大部分资金分布在1000U或3000U的价格区间,实际上这些资金很少被使用。
v2的手续费固定为0.3%,对所有交易对相同,没有差异。
用一个ETH买USDC,那就是(1 * 0.997 + x )* (y1)= k,和上面一样,将原本池子中usdc的数量减去算出的y1就是你买到的u的数量。
v3
v3的突破是引入了虚拟流动性,底层还是恒定乘积公式,只是做了离散化的处理。
设想,如果我认为ETH在1900 - 2100 之间波动,我可以只在这个区间提供流动性,这样,我的资金在这个区间利用率得到提升,可以获取更多的手续费,
把连续的价格区间离散化为一系列的Tick点,每个Tick对应一个特定的价格,价格只能在Tick之间跳跃,价格公式:P(i) = 2000 × (1.0001)^i,其中 i 为 Tick 索引,当前价格对应 i = 0(即 P=2000 USDC/ETH)。
Tick
struct Tick {
uint128 liquidityGross; // 经过该tick的总流动性
int128 liquidityNet; // 穿过该tick时,活跃流动性的净变化
// 其他字段:手续费增长值等
}
假设有两个流动性仓位:
-
仓位A:区间
[1000, 2000],流动性L = 500 -
仓位B:区间
[2000, 3000],流动性L = 300
Tick 2000 的状态为:
liquidityGross = 500 + 300 = 800 liquidityNet = -500 + 300 = -200
(负值表示当价格从左向右穿过 Tick 2000 时,活跃流动性减少 200)
L = sqrt(x * y),x,y是虚拟代币的数量,每次交易x,y的数量都会变化,但是L的大小不变。
流动性池在价格区间[Plower, Pupper]中x,y实际的数量可以推出:
P是当前价格,Pupper是流动性池中的最高价格、Plower是最低价格
有k为何还需要L,因为L可以线性反映池子的滑点。
举例说明
我们考虑一个 ETH/USDC 交易对,并做以下简化:
-
Tick 间距:每个 Tick 对应价格变化 10%(实际中约为 0.01%,这里为简化计算)。
-
价格公式:
P(i) = 2000 × (1.1)^i,其中i为 Tick 索引,当前价格对应i = 0(即P=2000 USDC/ETH)。 -
三个流动性提供者(LP) 及其仓位:
-
LP1:价格区间
[-2, 2](约1653 ~ 2420 USDC),提供流动性L₁ = 1000
-
LP2:价格区间
[0, 4](约2000 ~ 2928 USDC),提供流动性L₂ = 2000 -
LP3:价格区间
[2, 6](约2420 ~ 3546 USDC),提供流动性L₃ = 1500
-
初始状态
-
当前价格
P = 2000,对应 Tick 0。 -
活跃流动性:覆盖当前 Tick 的仓位有 LP1 和 LP2,因此: Lactive=L1+L2=1000+2000=3000
交易过程
假设一名交易者想用 USDC 购买 ETH,且交易量足够大,将推动价格从 Tick 0 上升至 Tick 3 以上。交易将按以下步骤分段进行:
第一步:价格从 Tick 0 (P0=2000) 移动到 Tick 1 (P1=2200)
流动性L:1000 + 2000 = 3000
计算所需USDC 和 ETH:
在此tick的区间的流动性池中可以交换一下数量的代币:
Tick 1 处流动性变化:检查 Tick 1 是否为任何仓位的边界。此处 LP1 区间为 [-2,2],Tick 1 在其内部;LP2 区间为 [0,4],Tick 1 也在内部;LP3 区间为 [2,6],Tick 1 低于其下限。因此 没有仓位在 Tick 1 边界生效,活跃流动性保持不变,仍为 3000。
第二步:价格从 Tick 1 (P=2200) 移动到 Tick 2 (P=2420)
当前活跃流动性:L = 3000
计算:
累计:Δx = 3.12 + 2.976 = 6.096 ETH,Δy = 6548.4 + 6868.02 = 13416.42 USDC
Tick 2 处流动性变化:
-
Tick 2 是 LP1 的上限(区间
[-2,2]):当价格从左侧穿过 Tick 2(价格上涨),LP1 的流动性 不再活跃,应移除1000。 -
Tick 2 是 LP3 的下限(区间
[2,6]):当价格从左侧穿过 Tick 2(价格上涨),LP3 的流动性 开始活跃,应添加1500。 -
LP2 的区间
[0,4]包含 Tick 2,继续有效。 -
因此,穿过 Tick 2 后,新的活跃流动性为: Lactive=L2+L3=2000+1500=3500
第三步:价格从 Tick 2 (P=2420) 移动到 Tick 3 (P=2662)
当前活跃流动性:L = 3500
计算:
累计:Δx = 6.096 + 3.3145 = 9.4105 ETH,Δy = 13416.42 + 8403.745 = 21820.165 USDC
Tick 3 处流动性变化:Tick 3 不是任何仓位的边界(LP2 上限为 Tick 4,LP3 上限为 Tick 6),因此 活跃流动性保持不变,仍为 3500。
交易结果
-
交易者总共支付 约 21820.165 USDC,获得 约 9.4105 ETH,平均价格约为 2318.5 USDC/ETH。
-
价格从 2000 USDC/ETH 上升至 2662 USDC/ETH,穿过了 3 个 Tick。
-
流动性随着价格跨越 Tick 边界而动态调整:在 Tick 2 处,LP1 退出,LP3 加入,活跃流动性从
3000变为3500
手续费
v3的手续费和v2类似,但是有多档,对于稳定币这种交易量多一点写的手续费会低一些:0.05%,对于高风险币手续费会高一些:1%。并且只有在你的价格区间内,你才能赚取手续费。超过你设定的区间,流动性就停止工作,不再赚取手续费,而且当价格重新回到区间时,你的资产比例已经改变,可能造成更大的无常损失,因此,v3需要流动性提供者更加主动的管理仓位,定期调整自己的价格区间。
v3实际上是v2的推广,我们把v3的价格区间设置为0-无穷大,v3就退化为v2了,我们可以把v2看作v3的特例,v2流动性在整个价格区间均匀分布,v3允许流动性在不同区间有不同的密度,这是最关键的区别。
他们底层都是恒定乘积公式,只是v3通过离散分段的算法,实现了虚拟流动性(也叫集中流动性),通过坐标变换,实现了滑点和流动性的线性变化。
凭证
v3使用的凭证是非同质化代币,v2中使用的同质化代币,因为v2流动性提供者提供的仓位都是相同的,v3中每个提供者提供的价格区间不同,仓位是独特的,所以转为用同质化代币(NFT)作为凭证。
熟悉这些算法对我们有什么好处呢?
1、价格预测
在交易之前,我们需要预估能够获取的输出数量。对于v2,直接套公式即可,对于v3,需要模拟跨越多个Tick,计算每个tick贡献的输出数量。
2、滑点控制
大额交易容易导致较大的滑点,v3的流动性集中,产生的滑点通常比v2小。
3、路径优化
有时通过多跳路径可以获得更好的价格,我们可以根据最短路径算法,维护我们常用代币的交易图,选择最优路径。
4、Gas优化
v3算法复杂,gas消耗高。对于小额交易,最好选择v2,开发的过程中需要在价格优势和gas费中做权衡。
更多推荐


所有评论(0)