Uniswap V3 中的 TickMath getSqrtRatioAtTick 函数是如何工作的

本文详细解释了 Uniswap V3 TickMath 库中 getSqrtRatioAtTick() 函数的工作原理。

Tickmath getSqrtRatioAtTick

本文解释了 Uniswap V3 TickMath 库中的 getSqrtRatioAtTick() 函数是如何工作的。getSqrtRatioAtTick() 函数接受一个 tick 索引,并返回该 tick 处的平方根价格,格式为 Q64.96 q-number。该函数计算:

$sqrtPriceX96= \sqrt {1.0001^i}⋅2^{96}$

其中 i 是 tick 索引。以下是该函数的截图:

getsqrtratioattick() 的截图

本教程假定读者已经理解了我们对平方和乘算法的处理,getSqrtRatioAtTick() 依赖于该算法。我们在此经常引用该教程中的概念,因此我们建议读者首先阅读该文章。

getSqrtPriceRatioAtTick 概述

该函数执行以下步骤:

  1. 使用代码 uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick)); 计算 tick 的绝对值。
  2. 检查 tick 是否在最小和最大 tick 的范围内,如果超出范围则恢复:require(absTick <= uint256(MAX_TICK), 'T');
  3. 使用平方和乘法计算 $ \sqrt {1.0001^{−|i|}} $ 作为 Q128.128 number。
  4. 如果原始 tick 为正,则计算 $ 1/ \sqrt {1.0001^{−|i|}} $
  5. 使用 >> 32 将 Q128.128 number 转换为 Q64.96 number

以下是代码中概述的步骤:

getsqrtratioattick 中的五个步骤

第 1/5 部分:为什么 Uniswap V3 计算绝对值 tick

为什么 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}$

观察到一般情况下:

image.png 因此,该函数首先计算: 然后,如果 tick 最初为正数,它会通过返回倒数来反转答案:

image.png

如果 tick 最初为负数,则代码不计算倒数。

第 2/5 部分:检查 tick 是否在范围内

函数中的第二行代码是不言自明的:

require(absTick <= uint256(MAX_TICK), 'T');

Max tick 是文件中的一个常量 887272,我们在关于 Tick 限制的文章中推导出了它。 我们不需要检查 tick 是否小于 MIN_TICK,因为我们计算了 tick 的绝对值,所以 absTick 不可能是负数。

第 3/5 部分:使用平方和乘法计算价格

在本节中,我们将展示该函数如何使用平方和乘算法并推导出函数中的大常量。

用于计算价格的变量是 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() 预计算

image.png

Uniswap V3 中的最小和最大 ticks 分别为 -887,272 和 887,272。但是,由于 getSqrtPriceRatioAtTick 仅直接计算负数部...

剩余50%的内容订阅专栏后可查看

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论