本文详细解释了 Uniswap V3 TickMath 库中 getSqrtRatioAtTick()
函数的工作原理。
本文解释了 Uniswap V3 TickMath 库中的 getSqrtRatioAtTick()
函数是如何工作的。getSqrtRatioAtTick()
函数接受一个 tick 索引,并返回该 tick 处的平方根价格,格式为 Q64.96 q-number。该函数计算:
$sqrtPriceX96= \sqrt {1.0001^i}⋅2^{96}$
其中 i 是 tick 索引。以下是该函数的截图:
本教程假定读者已经理解了我们对平方和乘算法的处理,getSqrtRatioAtTick()
依赖于该算法。我们在此经常引用该教程中的概念,因此我们建议读者首先阅读该文章。
该函数执行以下步骤:
uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));
计算 tick 的绝对值。require(absTick <= uint256(MAX_TICK), 'T');
。>> 32
将 Q128.128 number 转换为 Q64.96 number以下是代码中概述的步骤:
为什么 Uniswap V3 计算绝对值 tick,,即 $ \sqrt {1.0001^{−|i|}} $, 函数中的第一行代码计算 tick 的绝对值:
uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));
Tick 索引可以是正数也可以是负数。为了避免分别处理这两种情况,getSqrtRatioAtTick()
的平方和乘法部分仅计算负数 tick。如果原始 tick 为正数,则平方和乘法算法的结果计算倒数。
例如,如果原始 tick 为正 5,则该算法计算 -5 的 tick:
$ratio=\sqrt {1.0001^{−5}}$
然后计算倒数:
$ {1 / ratio}$
观察到一般情况下:
因此,该函数首先计算:
然后,如果 tick 最初为正数,它会通过返回倒数来反转答案:
如果 tick 最初为负数,则代码不计算倒数。
函数中的第二行代码是不言自明的:
require(absTick <= uint256(MAX_TICK), 'T');
Max tick 是文件中的一个常量 887272
,我们在关于 Tick 限制的文章中推导出了它。 我们不需要检查 tick 是否小于 MIN_TICK
,因为我们计算了 tick 的绝对值,所以 absTick
不可能是负数。
在本节中,我们将展示该函数如何使用平方和乘算法并推导出函数中的大常量。
用于计算价格的变量是 ratio
,但返回的变量是 sqrtPriceX96
。
以下是使用平方和乘法的函数的相关部分:
uint256 ratio = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000;
if (absTick & 0x2 != 0) ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;
if (absTick & 0x4 != 0) ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;
if (absTick & 0x8 != 0) ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;
if (absTick & 0x10 != 0) ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128;
if (absTick & 0x20 != 0) ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128;
if (absTick & 0x40 != 0) ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128;
if (absTick & 0x80 != 0) ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;
if (absTick & 0x100 != 0) ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;
if (absTick & 0x200 != 0) ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128;
if (absTick & 0x400 != 0) ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;
if (absTick & 0x800 != 0) ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;
if (absTick & 0x1000 != 0) ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;
if (absTick & 0x2000 != 0) ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;
if (absTick & 0x4000 != 0) ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;
if (absTick & 0x8000 != 0) ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128;
if (absTick & 0x10000 != 0) ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;
if (absTick & 0x20000 != 0) ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128;
if (absTick & 0x40000 != 0) ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128;
if (absTick & 0x80000 != 0) ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128;
ratio
是 Q128.128,但 sqrtPriceX96
是 Q64.96为了最大限度地提高精度,getSqrtRatioAtTick()
在内部使用 Q128.128 numbers 执行平方和乘法算法,但以 Q64.96 的形式返回答案。价格的内部表示是 ratio
变量。
为了解释 Uniswap V3 如何推导出上面显示的大常量,我们必须首先回顾平方和乘法算法。
平方和乘法算法依赖于预计算底数的幂。我们现在表明,代码中的大常量是从重复平方 1.0001−1/2 派生的。
使用平方和乘法算法,getSqrtRatioAtTick()
预计算
Uniswap V3 中的最小和最大 ticks 分别为 -887,272 和 887,272。但是,由于 getSqrtPriceRatioAtTick
仅直接计算负数部...
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!