UniV3 Share

  • bixia1994
  • 更新于 2023-10-07 11:14
  • 阅读 1330

UniV3Share

UniV3 Share

核心公式:

$$ (x + \frac{L}{\sqrt{P_a}}) (y + L\sqrt{Pb}) = L^2 $$ 核心公式可以看作是$x*y=K$曲线的平移。偏移量$x{offset}=\frac{L}{\sqrt{Pa}}$,$y{offset}=L\cdot \sqrt{P_b}$。 偏移量事实上反映了这个仓位的杠杆大小。偏移量越大,说明加的杠杆越大。

衍生公式:

tick的定义: $$ ic=\lfloor log{\sqrt{1.0001}}\sqrt{P} \rfloor, 向下取整 $$ Price可以为任何值,但是tick只能是离散的值。 $$ L = \sqrt{xy} $$ x,y为包含虚拟流动性的部分,总的x,y $$ \sqrt{P} = \sqrt{\frac{y}{x}} $$ 已知$L,\sqrt{P_1},\sqrt{P_2}$,求$\delta x, \delta y$ $$ \delta x=\frac{L}{\sqrt{P_1}} - \frac{L}{\sqrt{P_2}} $$ $$ \delta y = L \cdot \sqrt{P_1} - L\cdot \sqrt{P_2} $$ 已知$\delta x, L,\sqrt{P_1}$, 求$\sqrt{P_2}$: $$ \sqrt{P_2} = \frac{L \cdot \sqrt{P_1}}{L + \delta x \cdot \sqrt{P_1}} $$ 已知$\delta y, L, \sqrt{P_1}$, 求$\sqrt{P_2}$: $$ \sqrt{P_2} = \sqrt{P_1} - \frac{\delta y}{L} $$ 再一次SWAP过程中,L保持不变,手续费的积累不会影响到L的值。

已知$\delta x, \sqrt{P_1},\sqrt{P_2}$, 求$L$: $$ L = \frac{\delta x}{\frac{1}{\sqrt{P_1}} - \frac{1}{\sqrt{P_2}}} $$ 已知$\delta y, \sqrt{P_1},\sqrt{P_2}$,求$L$: $$ L = \frac{\delta y}{\sqrt{P_1}-\sqrt{P_2}} $$

公式推导

L的含义: L反应的是价格变化的阻力,也就是流动性深度。L越大,价格变化的阻力也就越大。 $$ L=\frac{dy}{d\sqrt{P}} $$ 推导过程: 第一步:在一次swap过程中,L保持不变,公式可以写为如下 $$ (x + x{offset}) \cdot (y + y{offset}) = L^2 $$ 则: $$ x = \frac{L^2}{y + y{offset}} - x{offset} $$ $$ y = \frac{L^2}{x + x{offset}} - y{offset} $$ 价格P的定义为: $$ P = -\frac{dy}{dx}, dy < 0 $$ 则: $$ P = \frac{L^2}{(x+x{offset})^2} $$ 则: $$ \sqrt{P} = \frac{L}{(x+x{offset})} $$ 同理,带入$x+x{offset} = \frac{L^2}{y+y{offset}}$得到: $$ \sqrt {P} = \frac{y + y{offset}}{L} $$ 则y等于: $$ y = L*\sqrt{P} - y{offset} $$ 当实际流动性y=0时,价格达到$PA$,此时$y{offset}=L*\sqrt{P_A}$ 当实际流动性x=0时,价格达到$PB$,此时$x{offset}=L/\sqrt{P_B}$

则同时求导数可得: $$ \frac{dy}{d\sqrt{P}} = L $$

Tick的定义与模型

整个UniV3的核心逻辑都是围绕着价格展开,即Price。用户提供流动性时,需要指定价格区间;用户swap时,要么指定价格,要么指定数量。具体的swap过程中也是一个tick,一个tick的去swap。 tick可以看成是一条坐标轴,坐标轴上的每一个刻度都是一个tick。坐标轴的刻度是有限的。 tick的定义如下: $$ ic=\lfloor log{\sqrt{1.0001}}\sqrt{P} \rfloor, 向下取整 $$ tick的取值范围为: $$ (-887272,887271) $$ 相对应的$\sqrt{P}$的取值范围: $$ (4295128739, 1461446703485210103287273052203988822378723970342), 10^{18}精度 $$ 在tick的模型设计里,其与流动性深度相关。在每一个已被初始化的tick上,都维护了如下的变量: Type Variable Name Notation
int128 liquidityNet $\Delta L$
uint128 liquidityGross $L_g$
uint256 feeGrowthOutside0X128 $f_o0$
uint256 feeGrowthOutside1X128 $f_o1$
uint256 secondsOutside $s_o$
uint256 tickCumulativeOutside $i_o$
uint256 secondsPerLiquidityOutsideX128 $s_{lo}$
  1. liqudityNet与Liquidity Gross 这个值记录的是当cross 过一个tick时,流动性应该增减的部分。因为用户添加流动性时,指定了price range,也即是两个tick。 如下图所示,alice和bob分别在a-c和b-d的范围内添加了流动性L1=500,L2=700. 则 UniV3更新tickA时,其$\Delta L$ = +500, $L_g$ = 500; 针对tickC,其$\Delta L$ = -500, $L_g$ = 500; 针对tickB,其$\Delta L$ = +700, $L_g$ = 700; 针对tickD,其$\Delta L$ = -700, $L_g$ = 700; 左右皆为闭区间。即左右的tick都会被初始化。 每一个tick都对应于一个全局变量liquidity,该全局变量liquidity是当前tick的总流动性。用于swap的计算 比如: 当tick < a时,liquidity = 0; 当tick > a, tick < b时,liquidity = 0+500;即cross tickA 当tick > b, tick < c时,liquidity = 500+700; 即cross tickB 当tick > c, tick < d时,liquidity = 1200+(-500);即cross tickC 当tick > d时,liquidity = 700+(-700), 即cross tickD 如果price反方向移动,即从右到左移动,则将加 liquidityDelta变为 减 liquidityDelta即可;

liquidity Gross的作用主要是用来判断当一个用户移除流动性之后,该tick上对应的流动性是不是已经为0;如果该tick上对应的流动为0,则需要删除该tick。

  1. feeGrowthOutside0x128和feeGrowthOutside1X128 这两个量主要是用于帮助收取手续费的。 UniV3里面的手续费与如下几个因素有关:1. 提供的price range;2. 提供的流动性;3. swap过程中是否经过了所提供的price range;4. 做LP的时间长度; 可以看到UniV3的手续费收取,跟UniV2的手续费收取的模式完全不一样。事实上,UniV3使用的是类似于MasterChef的模式来收取手续费。 $$ R\cdot l \cdot \sum_{t=t_1}^{t2} \left{ \begin{aligned} \frac{1}{L(t)} ,& & i{lower} < ic < i{upper} \ 0,& & ic < i{lower}\ 0,& & ic > i{uppper}\ \end{aligned} \right} $$ 上面的式子可以转换为: $$ R \cdot l \cdot ( \sum_{t=t_1}^{t_2} \frac{1}{L(t)}
    • \sum_{t=t_1}^{t_2}\left{ \begin{aligned} \frac{1}{L(t)}, & & ic < i{lower} \ 0, & & ic >= i{lower} \end{aligned} \right}
    • \sum_{t=t_1}^{t_2}\left{ \begin{aligned} \frac{1}{L(t)}, & & ic >= i{lower} \ 0, & & ic < i{lower} \end{aligned} \right}) $$ 即: $$ secondsPerLiquidityInside = secondsPerLiquidity - secondsPerLiquidityBelow(lowerTick) - secondsPerLiquidityAbove(upperTick) $$ 其中,secondsPerLiquidity作为全局变量在oracle中存储,每一次操作,如swap,mint,burn都会更新该值。 对于secondsPerLiquidityBelow(lowerTick),UniV3的解决思路是,在tick中保存一个名为secondsPerLiquidityOutsideX128的变量。其具体的outside含义如下: tick中保存的值,如secondsPerLiquidityOutsideX128,feeGrowthOutside0x128和feeGrowthOutside1X128等都是保存的outside的值。“outside”的含义是,当前价格的另一侧。 上图中,currentTick < tickI, 所以outside保存的是右侧的所有手续费与流动性之比之和fee 即: $$ fo(i) = \sum{i=i0}^{i{max}}\frac{fee}{L} $$ 上图中,currentTick > tickI, 所以outside保存的是左侧的所有手续费之和fee 即: $$ fo(i) = \sum{i=i_{min}}^{i_0}\frac{fee}{L} $$ 即: $$ f_r = f_g-f_b(i_l)-f_a(i_u) \ fg = \sum{i=i{min}}^{i{max}}\frac{fee}{L} $$ *针对每一个tick,其L都是定值,可以认为是常量。

对于计算(lowerTick - upperTick)之间的所有手续费fee,此时currentTick在lowerTick和upperTick之间。则可以通过: 全局的fee - feeGrowthOutside0x128(lowerTick) - feeGrowthOutside1X128(upperTick)

那么,应该如何计算feeOutside呢?在整个UniV3的设计中,当且仅当currentTick穿过某一个tick时,才会导致该tick上记录的feeOutside翻转。 其公式为: $$ f_o(i) := f_g-f_o(i) $$ 即: 全局的手续费/L-左侧的所有手续费/L=右侧的所有手续费/L

Position的定义与模型

当一个用户像UniV3中添加流动性时,都会生成一个唯一的POSITION KEY:

key = keccak256(address(user),int24(leftTick),int24(rightTick))
每一个POSITION上,都会track如下变量: Type Variable Name Notation
uint128 liquidity $l$
uint256 feeGrowthInside0LastX128 $f_{r,0}(t_0)$
uint256 feeGrowthInside1LastX128 $f_{r,1}(t_0)$
uint256 tokensOwed0 $t_0$
uint256 tokensOwed1 $t_1$

其中,liquidity可以看作是用户mint时得到的lp token数量,也可以认为是$\sqrt{x \cdot y}$, 即L

POSITION的一大作用是,用于记录用户提供的流动性所应该收取的手续费数量。具体的手续费token数值会存储在tokensOwned中。

其中,feeGrowthInside0LastX128即为$f_r$, 其计算过程如下: $$ f_r = f_g-f_b(i_l)-f_a(i_u) \ f_b(i_l) = \left{ \begin{aligned} f_g-f_b(i_l), & & ic < i{lower} \ f_b(i_l), & & ic >= i{lower} \end{aligned} \right}\ f_a(i_u) = \left{ \begin{aligned} f_b(i_l), & & ic < i{upper} \ f_g-f_b(i_l), & & ic >= i{upper} \end{aligned} \right}\

$$ 具体的tokenOwned则为: $$ tokensOwned = (f_r - f_r`) \cdot l $$

Swap 过程

当在同一个tick里面进行swap时,会进行如下计算:

  1. 找到下一个tick(initialized) $tick_{next}$
  2. 根据当前tick $tick{curr}$, $tick{next}$及L,使用公式计算出$\delta x, \delta y$ 即:已知$L,\sqrt{P_1},\sqrt{P_2}$,求$\delta x, \delta y$ $$ \delta x=\frac{L}{\sqrt{P_1}} - \frac{L}{\sqrt{P_2}} $$ $$ \delta y = L \cdot \sqrt{P_1} - L\cdot \sqrt{P_2} $$
  3. 判断token remaining是否大于$\delta x$,
    • 如果大于,则 $$ token{remaining}=token{remaining} - \delta x $$ 在进入下一个循环。
    • 如果小于,则: 已知$\delta x = token_{remaining}, L,\sqrt{P_1}$, 求$\sqrt{P_2}$: $$ \sqrt{P_2} = \frac{L \cdot \sqrt{P_1}}{L + \delta x \cdot \sqrt{P_1}} $$
    • 然后根据求出的$\sqrt{P_2}$, 再次利用上述公式,求的$\delta x, \delta y$ 即:已知$L,\sqrt{P_1},\sqrt{P_2}$,求$\delta x, \delta y$ $$ \delta x=\frac{L}{\sqrt{P_1}} - \frac{L}{\sqrt{P_2}} $$ $$ \delta y = L \cdot \sqrt{P_1} - L\cdot \sqrt{P_2} $$
  4. 手续费扣除: UniV3里面扣除手续费也是在tokenIn中,直接减去相应的手续费部分,然后剩余的参与计算。
  5. 全局变量更新:
    • $f_g$更新:
      state.feeGrowthGlobalX128 += FullMath.mulDiv(step.feeAmount, FixedPoint128.Q128, state.liquidity);
    • tick更新: 如果不需要cross tick: 则: $$ ic=\lfloor log{\sqrt{1.0001}}\sqrt{P2} \rfloor, 向下取整 $$ 如果需要cross tick: 则: $$ L = L + \delta L $$ $$ tick = tick{next} -1 $$
  • 学分: 7
  • 分类: DeFi
  • 标签:
点赞 1
收藏 1
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
bixia1994
bixia1994
0x92Fb...C666
learn to code