本文详细介绍了Uniswap v3中的tick索引的最小值和最大值,以及它们与价格存储的关系。文章解释了如何计算与最大价格2128对应的tick值,并探讨了使用int24
来存储tick索引的原因,同时指出了在代码库中硬编码的最小和最大平方根比率值。
最小的 tick 在 Uniswap v3 中是 -887,272,最大的 tick 是 887,272。本章解释了这一范围背后的理由,它基于找到与协议中可以存储的最高价格相对应的 tick。
在上一章中,我们看到协议将代币价格的平方根存储为 Q64.96
类型的固定点数字。这种类型的变量的最大整数值为 264。因此,它可以存储的最高价格为 2128。
这意味着协议无法处理超过 2128 的价格。换句话说,在 Uniswap v3 中,代币永远无法达到超过 2128 的实际价格。如果不遵守此限制,代币可能会达到协议无法存储的价格值。
因此,最高 tick 必须是对应于价格 2128 的 tick,以与最高价格保持一致。
要计算对应于价格 2128 的 tick,让我们记住价格与 tick 之间的关系是由以下公式给出的:
$$p(i)=1.0001^i$$
通过对两边取以 1.0001 为底的对数,可以反转这个关系。
$$ \begin{align} \log{1.0001}(p(i)) &= \log{1.0001}(1.0001^i) \ \log_{1.0001}(p(i)) &= i \end{align} $$
因为对于任何底 b,有 $log_b(b^x)=x$。
上述公式允许我们根据价格 p(i) 计算 tick 索引 i。
现在,我们需要确定相对于最高可能代币价格 2128 的 tick 索引。
在上面的公式中使用 p(i)=2128,我们得到:
$i=log_{1.0001}(2^{128})=887272$
这个计算可以用 Python 进行如下操作:
from math import log
log(2**128,1.0001) # log_1.0001(2**128) = 887272
因此,tick 索引 887,272 是协议使用的最高索引,因为大于 887,272 的 ticks 对应于超过 sqrtPriceX96
变量可以存储的最大值的价格。
最低 tick 索引设置为 -887,272,这是最高可能 tick 的负数。
这种对称性是可取的,因为代币 X 相对于代币 Y 的价格是代币 Y 相对于代币 X 的价格的倒数。因此,限制代币价格的最小值为 2^-128 是可取的,这对应于 tick -887272。
最小和最大 ticks 索引在 Uniswap v3 TickMath 库中被硬编码为 MIN_TICK
和 MAX_TICK
。
sqrtPriceX96
变量可以假定的最小值和最大值也分别被硬编码为 MIN_SQRT_RATIO
和 MAX_SQRT_RATIO
。这是可以在下面的截图中看到的,这些值将在后面的章节中计算。
在章节 在 Uniswap v3 中介绍 ticks 中,我们看到 ticks 是由以下公式定义的,
$$ p(i)=1.0001^i $$
其中 i 是 tick 索引。
可以使用价格的平方根而不是价格本身,并为给定 tick 索引计算价格的平方根。
为此,只需对上面的公式取平方根:
$$ \sqrt{p}= \sqrt{1.0001^i} = 1.0001^{\frac{i}{2}} $$
例如,要计算 tick 100 的 p,我们有 $\sqrt{p}{100}= 1.0001^{\frac{100}{2}} = 1.0001^{50} = 1.0050122696230506$。从这个信息,如果我们想要获得 p100(tick 100 的价格),我们只需平方它:$p{100} = \left(\sqrt{p}_{100} \right)^2$。
请注意,我们忽略了负平方根,仅保留了正平方根,因为价格不能为负。因此,我们可以始终通过平方平方根价格明确获取价格。
MIN_SQRT_RATIO
和 MAX_SQRT_RATIO
的值可以通过以下公式计算:
最低 tick 索引为 -887,272,所以允许的最低平方根价格为 $\sqrt{p}_{−887272}$。这可以计算为:
$$ \sqrt{{p}}_{−887272} = 1.0001^{\frac{-887272}{2}} = 1.0001^{-443636} $$
要将此值转换为固定点 Q64.96
,需要将其乘以 296。因此,
$$ \text{MIN_SQRT_RATIO} = 1.0001^{-443636} \times 2^{96} \approx 4295128738.152353 $$
出现的一个问题是:我们应该向上舍入还是向下舍入这个值?假设我们向下舍入,这意味着变量 sqrtPriceX96
的最低可能值是 4295128738
。换句话说,sqrtPriceX96
有可能达到 4295128738
的值。
这个值 4295128738
稍微低于 tick -887272(请记住,与 tick -887272 相关的值是 4295128738.152353
)。因此,如果价格达到 4295128738
,当前的 tick 将是向下舍入的最近 tick。这意味着它将是 -887273。 however, tick -887273 是不允许的,因为我们将 tick -887272 设置为最小。
因此,我们得出结论,向上舍入是必要的。也就是说,sqrtPriceX96
变量可以假定的最小值是 4295128739
,因为它已被硬编码到代码库中。
这个计算可以用 Python 进行如下操作:
math.ceil(1.0001**(-887272/2)*(2**96)) # 4295128739
MAX_SQRT_RATIO
的计算是类似的,但这次我们使用最高可能的 tick 索引 887,272:
$$ \begin{align} \text{MAX_SQRT_RATIO} &=\sqrt{p(887272)} \cdot 2^{96} \ &= 1.0001^{\frac{887272}{2}} \cdot 2^{96} \ &=1461446703485210103287273052203988822378723970342 \end{align} $$
这个计算可以用 Python 执行,但会受到精度损失。在后面的章节中,我们将看到 Solidity 是如何精确执行这种计算,而没有精度损失的。
int24
作为 tick 索引存储 887,272 所需的位数为$\log_2(887,272)\approx20$。由于我们也有负 ticks,我们需要存储两倍的 ticks。为了保存正数和它们的负值,我们的 tick 变量需要支持 21 位。
由于 Solidity 只支持倍数为 8 的 int
尺寸,这样所需的最小 int
尺寸是 int24
。因此,Uniswap V3 使用 int24
以存储 tick 索引(代码链接),如下所示。
MIN_SQRT_RATIO
和 MAX_SQRT_RATIO
的值表示允许的最小和最大平方根价格,格式为 Q64.96,正如协议中所定义。这些值在代码库中是硬编码的。
- 原文链接: rareskills.io/post/unisw...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!