UniV3Share
$$ (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 $$
整个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}$ |
liquidity Gross的作用主要是用来判断当一个用户移除流动性之后,该tick上对应的流动性是不是已经为0;如果该tick上对应的流动为0,则需要删除该tick。
对于计算(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
当一个用户像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 $$
当在同一个tick里面进行swap时,会进行如下计算:
state.feeGrowthGlobalX128 += FullMath.mulDiv(step.feeAmount, FixedPoint128.Q128, state.liquidity);
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!