本文详细介绍了 Uniswap V3 如何存储和计算代币价格的平方根,主要通过一种固定点数格式 (Q64.96) 处理,以提高计算的 gas 效率。同时探讨了代币价格的上下限及其处理方式,深入分析了 Solidity 中不支持浮动小数的原因。
在 Uniswap V2 中,协议跟踪代币储备并推导现货价格 $p_x=y/x$ 和总流动性 $L=xy$, ,其中 $x$ 和 $y$ 是代币 X 和 Y 的储备。
而 Uniswap V3 则跟踪当前价格和流动性,并推导储备。这一计算较为复杂,后面的章节将对其进行详细说明。
Uniswap V3 实际上存储的是价格的平方根 $\sqrt{p}$,而不是价格本身。这样的方法提高了 gas 效率,具体内容将在后面的章节中详细探讨。通过这种方式,我们不会失去准确性,因为价格总是可以从其平方根推导出来。
本章的目标是讨论 Uniswap V3 存储价格平方根 $\sqrt{p}$ 的位置和方式,以及如何处理代币价格可能为小数值,而 Solidity 并没有浮点或小数类型的问题。
价格的平方根存储在 池合约 中的结构体 slot0
的字段变量 sqrtPriceX96
中,如下图所示。
结构体 slot0
还存储其他变量,如 tick
,表示当前刻度,如我们在 刻度章节 中看到的。slot0
中的其他变量与预言机、费用或合约安全性相关,后续将进行检查。
变量名 sqrtPriceX96
已经表明存储值是价格的平方根 (sqrtPrice
),以 Q96 数字格式 (X96
) 存储,特别是 Q64.96 格式。
Q 数字格式 的详细说明在前一章中提供。我们将在接下来的部分简要回顾其在 Uniswap V3 中的使用。
Uniswap V3 将价格的平方根存储为定点数。
定点数允许我们以高效的 gas 使用来表示分数。例如,假设我们需要存储 1.0050122696230506
,但只能存储整数。一个方法是将该值乘以一个大数,比如 $2^{96}$,结果为:
$$ 1.0050122696230506 \times 2^{96}=79625275426524700982079509374.66678 $$
然后我们丢弃小数部分,存储 79625275426524700982079509374
。
因此,定点表示 Q64.96 和(原始)数字之间的关系为:
$$ \text{value_in_Q64.96} = \text{floor}( \text{original_value} \times 2^{96}) $$
要恢复原始值,我们只需将定点表示除以 $2^{96}$,公式为:
$$ \text{original_value} \approx \frac{\text{value_in_Q64.96}}{2^{96} } $$
在我们的例子中,值 1.0050122696230506
表示为定点数:79625275426524700982079509374
。要恢复原始值,我们将该值除以 $2^96$,得到大约 1.0050122696230507
,这非常接近原始数字。
这正是 Uniswap V3 处理 Solidity 没有浮点或小数类型方法。存储代币价格平方根的变量 sqrtPriceX96
是通过将实际的、可能为分数的价格 p 的平方根乘以 $2^96$ 得到的定点数。
sqrtPriceX96
之间的关系$\sqrt{p}$ 和 sqrtPriceX96
之间的关系是,$\sqrt{p}$ 是价格的实际平方根,而 sqrtPriceX96
表示代币价格在 Q64.96 格式中的平方根。
这种关系可以用一个简单的公式表示。要将 $\sqrt{p}$ 转换为 sqrtPriceX96
,我们使用:
$$ \text{sqrtPriceX96} = \text{floor}(\sqrt{p} \times 2^{96}) $$
要将 sqrtPriceX96
转回 $\sqrt{p}$ ,我们使用:
$$ \text{sqrtPriceX96} = \text{floor}(\sqrt{p} \times 2^{96}) $$
sqrtPriceX96
下面是将价格转换为 sqrtPriceX96
并随后检索原始价格的 Python 代码:
from decimal import Decimal, getcontext
getcontext().prec = 100
price = Decimal('1.0050122696230506')
sqrtPriceX96 = price * Decimal(2) ** 96 # Decimal('79625275426524700982079509374.6667867672150016')
original_price = sqrtPriceX96 / 2...
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!