Uniswap V3中的平方根价格

  • RareSkills
  • 发布于 2025-03-21 09:00
  • 阅读 2170

本文详细介绍了 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 并没有浮点或小数类型的问题。

变量 sqrtPriceX96

价格的平方根存储在 池合约 中的结构体 slot0 的字段变量 sqrtPriceX96 中,如下图所示。

slot0 代码截图

结构体 slot0 还存储其他变量,如 tick,表示当前刻度,如我们在 刻度章节 中看到的。slot0 中的其他变量与预言机、费用或合约安全性相关,后续将进行检查。

变量名 sqrtPriceX96 已经表明存储值是价格的平方根 (sqrtPrice),以 Q96 数字格式 (X96) 存储,特别是 Q64.96 格式。

Q 数字格式 的详细说明在前一章中提供。我们将在接下来的部分简要回顾其在 Uniswap V3 中的使用。

价格的平方根$\sqrt{p}$ 作为定点值

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$ 得到的定点数。

$\sqrt{p}$ 和 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}) $$

使用 Python 计算 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...

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

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

0 条评论

请先 登录 后评论