12.Uniswap V3 添加流动性案例
目录
核心摘要 (Key Takeaways)
- Uniswap V3 的核心是集中流动性:与 V2 的无限价格范围不同,V3 允许流动性提供者(LP)将资金集中在特定的价格区间
[Pa, Pb]内,其底层数学模型可以看作是对 V2 的x * y = k模型进行了平移和截断。 - 价格变动消耗特定 Token:在设定的价格区间内,当价格从当前价
P下降至Pa时,池子会消耗YToken;当价格从P上升至Pb时,池子会消耗XToken。理解这一点是计算所需流动性的关键。 - 流动性计算基于虚拟曲线:尽管 V3 的真实曲线是分段的,但其流动性数量 和 的计算可以基于 V2 的 和 这两个基础公式,应用在一条“虚拟”的、经过平移的曲线上进行推导。
- 工程实现中的核心逻辑:在实际添加流动性时,智能合约会根据用户提供的两种 Token ( 和 ) 分别计算出两个可能的流动性值
L,并最终选择较小的那个作为最终的流动性。这可能导致实际使用的某一种 Token 数量略少于用户最初提供的数量。
一、 Uniswap V3 核心公式与概念回顾
1. V3 流动性公式与曲线
Uniswap V3 引入了集中流动性的概念,允许将流动性提供在指定的价格区间 [Pa, Pb]。其公式可以理解为对 V2 公式的平移。
-
V2/V3 通用基础公式 (应用于虚拟曲线):
- 恒定乘积公式: (其中
L是流动性量) - 价格公式:
- 恒定乘积公式: (其中
-
V3 集中流动性公式 (体现真实与虚拟流动性的关系):
这个公式描述了真实流动性(橙色曲线)是如何通过虚拟流动性(绿色曲线)平移而来的。在进行计算时,我们通常会利用更简洁的虚拟曲线公式。

2. 真实流动性与虚拟流动性
- 真实流动性 (Real Liquidity): 用户在指定价格区间
[Pa, Pb]内实际存入的X和YToken 数量。 - 虚拟流动性 (Virtual Liquidity): 为了方便使用 公式进行计算,我们将真实流动性曲线向左和向下平移,补全成一条完整的双曲线。这部分被“补全”的流动性就是虚拟流动性。
- 计算的便利性:所有关于 和 的计算都是在这条包含了虚拟流动性的完整双曲线(视频中的黄色曲线)上进行的,这样可以简化数学模型。
二、 价格区间内的 Token 消耗机制
这是理解添加多少流动性的核心前提。站在资金池的角度:
-
价格下降,消耗 Y Token:
- 逻辑:当池内价格从
P点向A点移动(价格下降)时,意味着市场正在用XToken 换取池中的YToken。池中的YToken 数量减少,XToken 数量增加。 - 结论:从价格
P降到Pa的过程,消耗的是池子里的YToken。
- 逻辑:当池内价格从
-
价格上升,消耗 X Token:
- 逻辑:当池内价格从
P点向B点移动(价格上升)时,意味着市场正在用YToken 换取池中的XToken。池中的XToken 数量减少,YToken 数量增加。 - 结论:从价格
P升到Pb的过程,消耗的是池子里的XToken。
- 逻辑:当池内价格从
-
案例:
- 假设当前价格点为
P,对应的池内 Token 数量为 (, )。 - 当曲线上的点沿着曲线向左下方移动至
A点时,纵坐标Y的值减小,说明YToken 被消耗。 - 当曲线上的点沿着曲线向右上方移动至
B点时,横坐标X的值减小,说明XToken 被消耗。
- 假设当前价格点为
三、 流动性数量计算
三、 流动性数量 (\Delta X 和 \Delta Y) 计算
1. 基础公式推导
从两个基础公式 和 出发,可以推导出在任意价格 P 点,对应的 x 和 y 的数量(在虚拟曲线上)。
-
推导过程:
- 将 代入
- 得到
- 解得
- 再将
x代入 ,得到
-
结论:
2. 计算 \Delta X 和 \Delta Y
利用上述公式,我们可以计算出在特定价格范围内支持交易所需的 Token 数量。
-
计算 (支持价格从
P降到Pa):- 这是
YToken 的消耗量,等于P点的Y值减去Pa点的Y值。
- 这是
-
计算 (支持价格从
P升到Pb):- 这是
XToken 的消耗量,等于P点的X值减去Pb点的X值。(注意:因为P越大,X越小,所以是用低价对应的X减去高价对应的X)
- 这是
四、 案例分析:添加流动性实践
案例 1: 理论计算题回顾
- 问题: 用户有 = 2 ETH,当前价格
P = 2000,目标价格区间是[1500, 2500],求解需要多少 ? - 分析: 这是一个上述公式的直接应用。
- 已知 ,
P,Pa=1500,Pb=2500。 - 使用 的公式 先反解出流动性
L。 - 将求出的
L代入 的公式 即可计算出所需的 。
- 已知 ,
案例 2: 结合代码实现的完整流程
这是一个更贴近工程实践的案例,展示了从价格到最终流动性添加的完整步骤。
- 场景设定:
- 交易对: ETH/USDC
- 当前价格 (P): 5000
- 价格区间:
[4545 (Pa), 5500 (Pb)] - 计划投入: 1 ETH 和 5000 USDC
流程图:添加流动性的工程实现步骤
flowchart TD
A[用户提供Token和价格区间] --> B
B[步骤一 价格转换为Tick索引] --> C
C[步骤二 Tick索引转换为SqrtPriceX96格式] --> D
D[步骤三 根据ΔX计算流动性L_x] --> F
C --> E[步骤四 根据ΔY计算流动性L_y] --> F
F[步骤五 选择较小的L作为最终流动性] --> G
G[步骤六 使用最终L反推实际Token用量] --> H
H[步骤七 完成流动性添加]
flowchart TD
A[用户提供Token和价格区间] --> B
B[步骤一 价格转换为Tick索引] --> C
C[步骤二 Tick索引转换为SqrtPriceX96格式] --> D
D[步骤三 根据ΔX计算流动性L_x] --> F
C --> E[步骤四 根据ΔY计算流动性L_y] --> F
F[步骤五 选择较小的L作为最终流动性] --> G
G[步骤六 使用最终L反推实际Token用量] --> H
H[步骤七 完成流动性添加]
flowchart TD
A[用户提供Token和价格区间] --> B
B[步骤一 价格转换为Tick索引] --> C
C[步骤二 Tick索引转换为SqrtPriceX96格式] --> D
D[步骤三 根据ΔX计算流动性L_x] --> F
C --> E[步骤四 根据ΔY计算流动性L_y] --> F
F[步骤五 选择较小的L作为最终流动性] --> G
G[步骤六 使用最终L反推实际Token用量] --> H
H[步骤七 完成流动性添加]flowchart TD
A[用户提供Token和价格区间] --> B
B[步骤一 价格转换为Tick索引] --> C
C[步骤二 Tick索引转换为SqrtPriceX96格式] --> D
D[步骤三 根据ΔX计算流动性L_x] --> F
C --> E[步骤四 根据ΔY计算流动性L_y] --> F
F[步骤五 选择较小的L作为最终流动性] --> G
G[步骤六 使用最终L反推实际Token用量] --> H
H[步骤七 完成流动性添加]
流程解释
上述图表展示了在 Uniswap V3 中添加流动性的实际后台计算流程。它始于用户的输入(两种代币数量和价格区间),经过一系列的格式转换(价格到Tick,再到合约内部使用的SqrtPriceX96)。核心步骤是合约会并行计算两种代币分别能提供的流动性L_x和L_y,然后选择两者中较小的一个作为最终的有效流动性值。最后,根据这个最终的L值,反向计算出需要投入的精确代币数量,完成添加。
具体步骤详解:
-
从价格到 Tick
- 概念: 在 V3 中,价格不是连续的,而是离散的点,每个点由一个整数索引
tick表示。 - 公式:
- 案例结果:
P = 5000->tick = 85176Pa = 4545->tick = 84222Pb = 5500->tick = 86129
- 案例中的验证: 视频中提到,
1.0001的85176次方约等于4999.9,由于计算中向下取整,所以非常接近5000。
- 概念: 在 V3 中,价格不是连续的,而是离散的点,每个点由一个整数索引
-
从价格到 SqrtPriceX96
- 概念: 为了计算精度和效率,智能合约内部不直接存储价格
P,而是存储其平方根并乘以2^96的定点数格式。 - 公式:
- 概念: 为了计算精度和效率,智能合约内部不直接存储价格
-
计算流动性 L
- 逻辑转换: 前述理论公式计算的是从当前价
P到边界所需的和。在实际工程中,合约是根据用户提供的和,来计算它们能为整个价格区间[Pa, Pb]提供多少流动性L。 - 公式:
- 从 计算:
- 从 计算:
- 核心决策: 最终采用的流动性是两者中的最小值。
- 案例结果: 计算出的最终
L值为1517...。
- 逻辑转换: 前述理论公式计算的是从当前价
-
反推实际使用的 Token 数量
- 原因: 因为选择了最小的
L值,意味着其中一种 Token 并没有被完全使用,只会使用与那个较小的L值相匹配的数量。 - 过程: 使用最终确定的
L值,再通过公式反向计算出与这个L精确匹配的 和 。 - 案例结果:
- 初始提供: 1 ETH 和 5000 USDC。
- 最终实际使用: 0.998976 ETH 和 5000 USDC。
- 结论: 在这个价格区间和当前价格下,5000 USDC 是限制因素,它所能提供的流动性(
L_y)小于 1 ETH 所能提供的流动性(L_x)。因此,合约只使用了足以匹配 5000 USDC 的 ETH 数量。
- 原因: 因为选择了最小的