本文深入探讨了Uniswap中Q64.96数字的概念及其在智能合约中的应用,强调了其在流动性管理与安全编码中的重要性。作者详细阐述了Q64.96数字的定义、工作原理、常见陷阱和安全隐患,并提供了最佳实践与测试策略以确保安全性,有助于开发者更好地理解和使用这一高级技术。
嘿,DeFi爱好者们!如果你在探索Uniswap的世界,你可能听说过ticks、流动性池,甚至可能还有一些叫做Q64.96的数字。别担心,如果最后一个听起来像是秘密代码——我们马上就要揭开它的神秘面纱!
你可能在想:“哦,太好了,又一次深入Uniswap的ticks?”但等等!虽然我们会提到ticks(因为,坦率地说,它们非常重要),但我们在这里谈论的是另一件同样重要但常常被忽视的事情:Q64.96数字。
“我为什么要关心这些Q什么的数字?”我听到你问。
好吧,如果你在Uniswap上构建或创建hooks,理解Q64.96数字可能是让一个安全、高效的合约与……嗯,反正你不想站在那个方程的另一边之间的区别。
所以,系好安全带!我们即将踏上探索Q64.96数字的旅程,看看如何安全地使用它们,并在途中避免一些棘手的陷阱。
好的,我们先来个快速回顾。你知道Uniswap v3中的ticks吗?不知道?好的,这里是重点总结:
Ticks就像Uniswap的流动性曲线上的价格点。每个tick代表0.01%的价格变化。这是Uniswap如何允许流动性提供者将资金集中在特定价格区间的方式。挺不错的,对吧?
但这里才有趣。你认为Uniswap是如何在内部表示这些价格的?常规小数?整数?不!有了Q64.96数字。
“Q64.96?听起来像个星际大战中的机器人!”你可能开玩笑道。
接近,但还不完全。Q64.96数字是一种使用整数表示小数的特殊方法。为什么?因为用于以太坊智能合约的语言Solidity与小数不太兼容。
喜欢吗?很好!因为我们即将深入这些神秘的数字。
好的,让我们深入研究Q64.96数字。但等一下,它们究竟是什么,我们为什么需要它们?
Q64.96数字是一种特定类型的定点数表示。把它们想象成一种在仅理解整数的系统中表示小数的方法。
但为什么是64和96呢?好问题!
“64”表示用于整数部分的位数,而“96”是用于小数部分的位数。总共有160位。你可能在想:“这不是过分了么?我们为什么需要这么多位?”好吧,在Uniswap中,我们处理的是广泛的价格和流动性金额。我们需要足够的精度来处理几美分的微小分数,但也需要足够的范围来表示数十亿美元。这就是Q64.96发挥作用的地方。
让我们通过一个例子来分解一下。我们如何将数字1.5表示为Q64.96数字?
操作步骤如下:
在代码中,它看起来像这样:
uint256 onePointFive = 1.5 * 2**96;
// 这相当于 118842243771396506390315925504
现在你可能在想:“为了表示1.5,这个数字也太大了!”你说得对,确实大。然而,这可以让我们在不因舍入误差而损失精度的情况下进行精确计算。
但关键是——我们怎么在计算中实际使用这些数字?别担心,我们将在下一节中讨论这个问题。
既然我们了解了Q64.96数字是什么,那就来谈谈使用它们时可能出现的问题。毕竟,高精度意味着高责任,对吧?
你可能熟悉常规整数数学中的这些情况,但在Q64.96中,风险更大。为什么?因为我们默认处理的是更大的数字。
假设你试图将两个Q64.96数字相乘。你可能会想:“没问题,我会像普通整数那样相乘。”但等等!记住这些数字有多大吗?直接相乘几乎肯定会导致溢出。
以下是一个不该这样做的示例:
uint256 a = 1.5 * 2**96; // 1.5的Q64.96表示
uint256 b = 2.0 * 2**96; // 2.0的Q64.96表示
uint256 result = a * b; // 别这么做!
你可能会在想:“好吧,那我们怎么安全地相乘呢?”
好问题!我们需要使用特殊函数来正确处理数学运算。我们将在最佳实践部分中讨论这个问题。
你可能在想:“我只需在最后除以2⁹⁶就可以回到普通数字。”但这没那么简单。在Solidity中,除法会截断结果,这意味着你可能失去重要的精度。
例如:
uint256 x = (1 * 2**96) / 3; // 尝试表示1/3
uint256 y = x * 3; // 你可能期望这个等于1 * 2**96,但实际上并不是!
很容易忘记你在处理Q64.96数字,把它们当作普通整数。这可能会导致一些非常奇怪的结果。
例如:
uint256 price = 1500 * 2**96; // 1500的Q64.96表示
require(price > 1000, "价格太低"); // 这将始终为真!
你可能会在想:“但1500明显大于1000,那么问题出在哪里?”
问题在于我们在将Q64.96数字与常规整数进行比较。由于乘以2⁹⁶,Q64.96数字要大得多。
那么,我们如何避免这些陷阱呢?别担心,在下一节的最佳实践中有应对策略。
好了,现在我们已经让你对可能出错的事情感到害怕,让我们谈谈如何正确处理。别担心,不全是悲观绝望!
首先,你可能会想:“我不能像处理常规整数那样使用SafeMath吗?”好的直觉!但不幸的是,SafeMath并不适用于Q64.96数字。那么我们该用什么呢?
欢迎使用FullMath和FixedPoint96库!这些将是你在处理Q64.96数字时的新好朋友。让我们看一个示例:
import '@uniswap/v3-core/contracts/libraries/FullMath.sol';
import '@uniswap/v3-core/contracts/libraries/FixedPoint96.sol';
function multiplyQ64x96(uint256 a, uint256 b) internal pure returns (uint256) {
return FullMath.mulDiv(a, b, FixedPoint96.Q96);
}
“但等一下,”你可能会说,“这个mulDiv函数是什么?为什么不直接相乘和除法?”
好问题!mulDiv是一个特殊函数,它以避免溢出并保留精度的方式执行乘法和除法。
那么,除法呢?还记得之前提到的精度损失问题吗?我们是这样处理的:
function divideQ64x96(uint256 a, uint256 b) internal pure returns (uint256) {
return FullMath.mulDiv(a, FixedPoint96.Q96, b);
}
看到我们怎么做了吗?在除法之前乘以Q96。这有助于保留精度。
最后,让我们谈谈比较。还记得我们的类型混淆问题吗?以下是正确比较Q64.96数字的方法:
function isGreaterThan(uint256 a, uint256 b) internal pure returns (bool) {
return a > b; // 假设a和b都是Q64.96数字
}
简单,对吧?关键是确保在比较之前,两个数字都必须处于Q64.96格式。
此时,你可能会在想:“我如何确保我的Q64.96实现真的安全?”
好问题!虽然单元测试很重要,但在DeFi安全中,我们需要使用更强大的工具:模糊测试和形式化验证。
模糊测试就像向你的代码投掷上千只猴子,看看能破坏什么。 好吧,不是字面意义上,而是差不多!它涉及生成大量随机(或半随机)输入来测试你的函数。这对于Q64.96操作尤其重要,因为边缘情况可能会非常尖锐。
例如,模糊测试工具可能会用极端值测试你的multiplyQ64x96
函数:
function testFuzzMultiplyQ64x96(uint256 a, uint256 b) public {
vm.assume(a <= type(uint256).max / 2**96);
vm.assume(b <= type(uint256).max / 2**96);
uint256 result = multiplyQ64x96(a, b);
assert(result <= type(uint256).max);
}
像Echidna或Foundry内置模糊测试工具这样的工具可以运行成千上万的这些测试,可能会发现你之前未曾考虑的漏洞。
现在,如果模糊测试像是投掷猴子在你的代码上,那么形式化验证就像是一群数学家来证明你的代码是正确的。它使用数学方法来证明或反驳你的算法的正确性。
对于Q64.96数字,形式化验证尤其强大。它可以证明你的操作永远不会溢出、损失精度或违反你指定的任何其他属性,涵盖所有可能的输入。
这就是为什么事情变得更有趣的地方:Zealynx Security专门应用这些先进技术于DeFi协议。我们利用模糊测试和形式化验证揭示了其他方法未能发现的微妙错误。看看这个 高级安全测试套件 是如何为这个DeFi协议实现的。
https://github.com/ZealynxSecurity/Possum-Labs/tree/main/test/V2MultiAsset
当然,最佳策略是结合多种方法:
记住,在DeFi安全方面,你决不能太谨慎。风险高,甚至极小的Q64.96计算错误也可能导致重大损失。
通过结合这些先进的测试策略,你不仅仅是在编写安全代码——你是在为一个更强大、更可信的DeFi生态系统奠定基础。
呼!我们已经覆盖了很多内容,对吧?让我们快速回顾一下:
记住,在DeFi中,精确和安全是密不可分的。通过掌握Q64.96数字,你不仅是在编写更好的代码——你还在为一个更安全、更可靠的DeFi生态系统做出贡献。
https://www.linkedin.com/in/carlos-vendrell-felici/
https://github.com/ZealynxSecurity
- 原文链接: medium.com/@bloqarl/unis...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!