Uniswap V3 第3章 数学:集中流动性的核心方程

推导 Uniswap V3 集中流动性的核心方程:流动性 L 与 token 数量和价格的关系、虚拟储备、以及区间内 x 和 y 的计算。

6 分钟阅读
Uniswap V3 第3章 数学:集中流动性的核心方程

Uniswap V3 第 3 章:数学——集中流动性方程

这一章是 V3 的数学心脏。我们推导三个关键公式:流动性 L 与价格、token 数量的关系虚拟储备(V3 怎么”假装”自己是 V2)、以及给定区间 [Pa,Pb] 需要多少 x 和 y。掌握它们,后面的 swap 和 liquidity 章节就是水到渠成。


目录


1. 从 V2 到 V3:虚拟储备的思想

V2 的池子真实持有 x 和 y,满足 x·y=k。V3 的 LP 只在区间 [Pa,Pb] 提供流动性,但在这个区间内部,池子的行为和一个 V2 池子一模一样——只是这个”等效 V2 池”的储备是虚拟的(virtual reserves)。

核心思想:

  • V3 在区间内表现得像一个 x_v · y_v = L² 的恒定乘积池(x_v, y_v 是虚拟储备)。
  • 但 LP 实际只需投入”真实储备”——也就是把虚拟双曲线平移,只保留 [Pa,Pb] 这一段所需的资产。
  • 区间外的虚拟储备不需要真的存在,因为价格永远不会走到那里(走到区间边界,头寸就全变成单一资产了)。

2. 流动性 L 的定义

虚拟储备满足 x_v · y_v = L²,且:

x_v = L / √P        y_v = L · √P

验证:x_v · y_v = (L/√P)·(L·√P) = L² ✓。

L 就是这个等效恒定乘积池的”流动性深度”(类比 V2 的 √k)。在一个不跨 tick 的 swap 过程中,L 保持不变,价格 √P 沿着曲线移动。跨越 tick 时 L 才会改变(下一章)。

x_v = L/√Py_v = L·√P 也可反解:

L = x_v · √P  (由 x 一侧)
L = y_v / √P  (由 y 一侧)

3. 核心公式:x 和 y 关于 L 和 √P

把上面两式记牢,这是 V3 一切计算的基础:

x = L / √P          (token0 数量与 √P 成反比)
y = L · √P          (token1 数量与 √P 成正比)

直觉:

  • 价格 P 上涨(√P 变大)→ x 变少、y 变多。符合”token0 涨价了,池子里 token0 被买走、token1 增多”。
  • swap 的本质就是沿这条曲线移动 √P,同时按这两个公式调整 x、y。

由此还能推出 swap 的增量公式(第 4 章会用):

Δy = L · Δ(√P)           (卖出 y / 买入 y 改变 √P)
Δx = L · Δ(1/√P)         (改变 1/√P)

4. 真实储备曲线:被”平移”的双曲线

V2 的曲线 x·y=k 过原点附近无限延伸(两端贴近坐标轴)。V3 的真实储备曲线是把这条虚拟双曲线向内平移,使它在区间端点处正好碰到坐标轴:

  • 在价格 = Pb(上边界)时,头寸全是 token0(x),y = 0。
  • 在价格 = Pa(下边界)时,头寸全是 token1(y),x = 0。
  • 在 Pa 和 Pb 之间,头寸是 x 和 y 的混合。

平移量正好是”区间外那部分虚拟储备”。所以 LP 只需投入”真实储备”(区间内那段),却能获得等同于一个大得多的虚拟池的深度——这就是资本效率提升的数学来源。

图像上:V3 真实储备曲线是 V2 双曲线的一小段,被平移后两端真的碰到了坐标轴(V2 永远碰不到)。碰到坐标轴 = 头寸变单一资产 = 价格走出区间。


5. 区间内需要多少 x 和 y

设当前价格 Pc,区间 [Pa, Pb](Pa < Pb),流动性 L。需要投入的真实数量:

若 Pc ≤ Pa(价格在区间下方):全是 token0
    x = L · (1/√Pa − 1/√Pb),   y = 0

若 Pc ≥ Pb(价格在区间上方):全是 token1
    x = 0,   y = L · (√Pb − √Pa)

若 Pa < Pc < Pb(价格在区间内):两种都要
    x = L · (1/√Pc − 1/√Pb)
    y = L · (√Pc − √Pa)

这三组公式就是 NonfungiblePositionManager.mint 背后算”你要存多少 x 和 y”的依据。记忆方法:

  • x(token0)的量和”上半区间 [Pc, Pb]“有关,用 1/√ 的差。
  • y(token1)的量和”下半区间 [Pa, Pc]“有关,用 的差。

6. 案例:在 [2700, 3300] 提供流动性

设 ETH/USDC,当前 Pc = 3000,区间 [Pa=2700, Pb=3300],想提供 L = 1,000,000(示意值)。先算平方根:

√Pa = √2700 ≈ 51.96
√Pc = √3000 ≈ 54.77
√Pb = √3300 ≈ 57.45

价格在区间内(2700 < 3000 < 3300),两种币都要:

x = L · (1/√Pc − 1/√Pb) = 1,000,000 · (1/54.77 − 1/57.45)
  = 1,000,000 · (0.018258 − 0.017407) = 1,000,000 · 0.000851 ≈ 851  (token0 单位)

y = L · (√Pc − √Pa) = 1,000,000 · (54.77 − 51.96)
  = 1,000,000 · 2.81 ≈ 2,810,000  (token1 单位)

所以提供这个头寸,你大约需要按比例投入 851 单位的 token0 和 2,810,000 单位的 token1(具体单位/精度按池子代币定)。如果价格涨到 3300,x 会被换光(全变 token1);跌到 2700,y 会被换光(全变 token0)。


7. 三种价格位置的资产形态

当前价 Pc 相对区间头寸资产形态是否赚手续费
Pc ≤ Pa(跌破下界)全是 token1(Y)❌ 不赚(价格不在区间内)
Pa < Pc < Pb(区间内)token0 + token1 混合✅ 赚手续费
Pc ≥ Pb(涨破上界)全是 token0(X)❌ 不赚

关键认知:只有当前价格落在你的区间内时,你的流动性才被使用、才赚手续费。 价格走出区间,你的头寸”睡着了”,变成单一资产静静躺着,直到价格回来。这就是 V3 LP 要主动管理区间(甚至用机器人再平衡)的原因。


8. 本章小结

  1. V3 在区间内表现得像 V2 恒定乘积池,但储备是虚拟的x_v·y_v = L²
  2. 核心公式:x = L/√Py = L·√P;增量 Δy = L·Δ√PΔx = L·Δ(1/√P)
  3. 真实储备曲线 = 虚拟双曲线被平移,使两端碰到坐标轴(= 头寸变单一资产 = 价格出区间)。
  4. 区间内所需 x、y:x = L(1/√Pc − 1/√Pb)y = L(√Pc − √Pa)(价格在区间内时)。
  5. 三种位置:跌破下界全是 token1、区间内混合、涨破上界全是 token0;只有区间内才赚手续费

9. 动手练习

目标:把第 5 节的公式用代码实现,亲手算一个头寸需要的 x 和 y。

练习:计算区间所需 token 数量

写一个脚本/测试(纯数学,可不连链):

  1. 输入:L、当前价 Pc、区间 [Pa, Pb]
  2. 先算 √Pa, √Pc, √Pb
  3. 按第 5 节三种情况,分别实现并返回 (x, y)
  4. 用第 6 节的数字验证:[2700,3300]、Pc=3000、L=1e6,应得到 x≈851、y≈2.81e6。
  5. 测试边界:令 Pc=2700(=Pa),应得到 y=0(全是 token0);令 Pc=3300(=Pb),应得到 x=0(全是 token1)。

进阶(链上)

  • 用 V3 的 LiquidityAmounts 库(periphery)里的 getAmountsForLiquidity 验证你的手算结果。
  • 反过来用 getLiquidityForAmounts:给定你愿意投入的 x、y 和区间,算出能得到的 L。

运行

forge test --evm-version cancun --fork-url $FORK_URL \
  --match-path test/UniswapV3Math.t.sol -vvv

下一章(第 4 章 Swap)讲 V3 的兑换算法:单区间内怎么算、跨 tick 时 liquidity net 怎么切换流动性、swap 手续费,以及 SwapRouter 的定输入/定输出。

💬 评论