18.Uniswap V3 手续费计算(一)
核心摘要 (Key Takeaways)
- V3手续费的复杂性根源:与V2的全范围流动性不同,Uniswap V3的集中流动性允许LP在自定义价格区间(
ticks)提供流动性,这使得手续费的计算和分配变得极其复杂。 - 全局手续费累加器
feeGrowthGlobal:Uniswap V3引入了一个全局状态变量feeGrowthGlobal,它代表每单位流动性可以获得的总手续费。这个值会随着每笔交易单调递增。 - 手续费按
token in收取:手续费只对交易中“进入”池子的代币收取。因此,系统需要为交易对中的两种代币(token0和token1)分别维护两个独立的feeGrowthGlobal变量,导致其增长呈现阶梯状。 - LP的核心关注点
feeGrowthInside:LP只关心在其提供的流动性区间内产生的手су费。因此,需要从全局feeGrowthGlobal中剥离掉区间外的部分,得到feeGrowthInside。 - 精巧的边界记录机制
feeGrowthOutside:V3通过在每个tick边界上记录一个名为feeGrowthOutside的值,来巧妙地计算任意区间的feeGrowthInside。当价格穿越一个tick时,该tick的feeGrowthOutside值会被更新,从而精确追踪内外手续费的累积情况。
1. Uniswap V2 vs. V3 手续费机制对比
1.1 Uniswap V2:简单直接
- 流动性模型:流动性平均分布在从
0到+∞的整个价格曲线上。 - 手续费收取:
- 对每笔交易收取固定的千分之三(0.3%)手续费。
- 手续费只对
token in(交易中流入池子的代币)收取。 - 案例:
- 用 X 换 Y:收取
0.003 * X,实际用于交易的是0.997 * X。 - 用 Y 换 X:收取
0.003 * Y,实际用于交易的是0.997 * Y。
- 用 X 换 Y:收取
- 手续费分配:收取的手续费会自动累积到流动性池中,为LP实现自动复投增值,无需任何额外操作。
1.2 Uniswap V3:挑战重重
- 核心挑战:集中流动性 (Concentrated Liquidity)。
- 不同的LP可以在不同的价格区间(由
tick lower和tick upper定义,视频中也称为PA和PB)提供流动性。 - 手续费档位:V3提供了多个手续费档位供流动性池选择,如
0.01%,0.05%,0.3%,1%。
- 不同的LP可以在不同的价格区间(由
- 需要解决的问题:
- 按比例分配:在同一个
tick区间内,手续费需按LP提供的流动性比例进行分配。 - 跨
tick计算:当交易价格跨越tick边界,导致总流动性发生变化时,如何精确计算每个LP在其活跃区间内应得的手续费。
- 按比例分配:在同一个
2. 手续费分配的基本原理与 feeGrowth 的引入
2.1 单次交易的分配逻辑
- 核心思想:LP在某个价格区间获得的手续费,等于该区间产生的总手续费乘以该LP提供的流动性占比。
- 案例:单次跨
tick交易- 背景:
- 一个LP在某个范围内提供了流动性,大小为
S。 - 一笔交易发生,使得价格从
tick_0移动到tick_1。 - 在区间的总流动性为,产生的总手续费为。
- 在
tick_1区间的总流动性为,产生的总手续费为。
- 一个LP在某个范围内提供了流动性,大小为
- 计算LP应得手续费:该LP获得的手续费 是其在每个
tick区间所获手续费的总和。
- 背景:
2.2 feeGrowthGlobal:全局手续费累加器
- 概念推导:将上述逻辑扩展到
N次交易,LP的总手续费可以表示为: - 定义:Uniswap V3将公式中求和的部分 定义为一个全局变量,称为
feeGrowthGlobal(视频中简称为FG)。- 物理含义:
feeGrowthGlobal代表从系统部署开始,每单位流动性 (S=1) 累计可以获得的总手续费。 - 简化公式:LP的总手续费 。
- 物理含义:
- 核心特性:
- 全局状态:
feeGrowthGlobal是一个存储在合约中的全局变量,随每次交易更新。 - 单调递增:只要有交易发生,
feeGrowthGlobal的值就会不断累积,永远不会减少。 - 按代币分离:由于手续费只对
token in收取,因此合约为交易对中的两个代币分别维护了两个feeGrowthGlobal变量:**feeGrowthGlobal0**(针对token0)**feeGrowthGlobal1**(针对token1)
- 阶梯式增长:
- 当价格上涨时(例如,用
token0换token1),feeGrowthGlobal0会增加,而feeGrowthGlobal1保持不变(呈水平线)。 - 当价格下跌时(例如,用
token1换token0),feeGrowthGlobal1会增加,而feeGrowthGlobal0保持不变。 - 这导致每个
feeGrowthGlobal变量的增长曲线都呈现出阶梯状。
- 当价格上涨时(例如,用
- 全局状态:
3. 从全局到局部:计算 feeGrowthInside
- LP的视角:一个在特定价格区间 (
tick lower,tick upper) 提供流动性的LP,只关心在这个区间内(inside)累积的手续费,区间外(outside)的与他无关。 - 核心概念:
- feeGrowthInside:在LP指定的 区间内累积的每单位流动性手续费。
- feeGrowthOutside:在该区间之外累积的手续费。
- 计算逻辑:
feeGrowthInside等于全局的feeGrowthGlobal减去所有在区间之外累积的部分。- 白皮书与视频中的公式 (变量名来自视频讲解):
- 公式解读:
- :我们想求的
feeGrowthInside(Range Fee)。 - :当前的全局
feeGrowthGlobal。 - :所有低于下边界 的手续费累积 (
Fee Below)。 - :所有高于上边界 的手续费累积 (
Fee Above)。
- :我们想求的
4. feeGrowthOutside:精巧的边界状态记录机制
为了高效计算任意区间的和,V3合约并不直接记录它们,而是采用了一个更巧妙的机制:在每个被激活的tick上记录一个状态变量 **feeGrowthOutside** (视频中简称为)。