去中心化交易协议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. 你先存入1个ETH,池子变成:x = 11 ETH。

  2. 为了保持 k = 400,000,USDC的数量必须变为:y = k / x = 400,000 / 11 ≈ 36,363.64。

  3. 这意味着你可以拿走的USDC是:40,000 - 36,363.64 = 3,636.36 USDC。

  4. 你得到的汇率是: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费中做权衡。

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐