Uniswap v4 引入了新特性,但随之而来的复杂性引发了一系列的安全审计问题。本文详细讨论了三项重大漏洞,包括资金双重计数、价格不变条件违反和手续费收集的干扰,强调了在复杂 DeFi 系统中确保安全性的必要性。
Uniswap v4 是去中心化交易所的最新进化,引入了变革性功能,如 hooks 和统一的池结构,以重新定义自动化市场制造商 (AMMs)。随着创新而来的复杂性,需要进行严格的安全审计。
为了加强其设计,Uniswap Labs 聘请了四家顶尖安全公司:OpenZeppelin、Spearbit、Trail of Bits 和 Certora。这些团队发现的漏洞包括从可能危及用户资金的严重风险到可能降低性能的轻微低效问题。
在本文中,我们重点介绍 三个突出的发现,评估它们的影响,并总结为保障先进 DeFi 系统安全所需的重要教训。
下表总结了参与审计的团队、评估的时间线以及识别的问题数量。我们鼓励读者查看链接的报告以获取详细的发现。
让我们看看在上述审计中发现的三个主要漏洞,弄清楚它们发生的原因,并学习如何使协议更加可靠。
OpenZeppelin 在 CELO 区块链上发现了一个 关键漏洞,这可能允许攻击者利用 Uniswap 的记账机制。这个漏洞被认为是必要的,因为它允许攻击者提取比他们存入的更多的资金,从而有效地使协议遭受盗窃。
这样的缺陷威胁到平台的财务稳定性,如果大规模利用,可能导致流动性完全耗尽。这个漏洞源于 CELO 的原生代币与其 ERC-20 对应代币交互的独特方式,允许重复提款,并可能耗尽协议。
理解这个漏洞
Uniswap 的记账通过跟踪 余额增量 来运作。它包括三个关键功能:
sync
: 记录当前代币余额。settle
: 计算余额增量(代币余额的变化)并记入用户。take
: 允许用户提取其记入的代币。在 CELO 上,协议错误地将原生代币和其 ERC-20 表现的存款都记入,从而为攻击者创造了一个漏洞。
漏洞利用场景
sync
函数,使用 CELO 的 ERC-20 代币来记录余额。sync
函数,使用原生 CELO 代币来记录余额。settle
函数,使用 ERC-20 代币。系统错误地再记入了 X 个代币。take
进行双重提款take
函数,使用 CELO ERC-20 代币提取 X 个代币,使 ERC-20 代币的增量变为零。take
函数,使用原生 CELO 代币提取另一个 X 个代币,使原生代币的增量变为零。影响
攻击者在仅存入 X 的情况下提取了 2X 个代币,并重复该过程以耗尽 CELO 的 ERC20 代币池。
为什么会发生这种情况
这个漏洞源于 Uniswap 无法区分 CELO 的原生代币和其 ERC-20 表现。这一边缘情况特定于 CELO,而在处理标准原生代币的区块链上是不可行的。
结论
开发者必须考虑涉及非标准代币和区块链特性的边缘情况,特别是在设计多链协议时。
具体针对这种情况,保持用户流程尽可能简单可以防止意外后果。在这个漏洞的案例中,用户不应在没有及时结算的情况下再次同步,这是该漏洞的缓解措施。
Certora 在 Uniswap v4 中发现了一个 中等严重性的漏洞,使用形式验证 工具。该方法利用数学证明来验证协议逻辑在所有场景下是否按预期行为。
通过严格分析代码,形式验证特别有效于发现传统测试方法可能遗漏的微妙漏洞。形式验证是一种证明协议逻辑正确性的数学方法,使其在发现微妙漏洞方面十分有效。
理解这个漏洞
该问题出现在大量联系 tick 价格和池状态变量的一项重要不变条件遭到违反时,导致可能的资金错误配置。
在 Uniswap v4 中,每个池保持两个关键变量:
pool.tick
:表示池的当前 tick。pool.sqrtPrice
:表示池当前价格的平方根。该协议确保这些变量遵循以下不变条件:
tickAtSqrtRatio(pool.sqrtPrice) == pool.tick
该不变条件确保池的 tick 和价格之间的一致性,使系统在交换期间维持准确的计算。然而,在我们使用 Certora Prover 对这一不变条件进行形式验证的过程中,我们发现了一种违反该保证的场景。
漏洞利用场景
pool.tick
更新到下一个 tick,但未能正确调整 pool.sqrtPrice
。影响:
为什么会发生这种情况
问题源于在耗尽 tick 这样的边缘情况下,准确更新多个状态变量的复杂性。尽管 Uniswap 团队承认我们的不变量是正确的,但其违反揭示了实现中的微妙失误。
结论
在定义不变条件时,开发者必须利用协议的设计原则,揭示隐藏的边缘案例,并确保系统行为与预期一致。
Trail of Bits 识别了一个 低严重性的问题,在交换期间调用 collectFees
函数会干扰余额跟踪,从而可能减少用户的回报或导致交易失败。
理解这个漏洞
Uniswap v4 允许用户在交易期间调用各种函数,包括收集协议费用的函数。然而,当在 актив“交换”过程中调用 collectFees
时,余额增量在交易进行中暂时被修改,反映未结算的金额。这一冲突导致计算错误。
漏洞利用场景
collectFees
函数以获取他们的部分已收取费用。collectFees
函数更新了余额增量,而在交换过程中,余额增量暂时为负数。这实际上将用户应收的费用抵消在他们的未清余额上。settle
函数被调用以完成交换时,用户的调整余额增量导致:影响
虽然财务影响较小,但此漏洞通过以下方式降低了用户体验:
为什么会发生这种情况
余额增量在交换期间临时反映未结算的值。可以将其视为显示正在进行但尚未完成交易的账本。例如,如果你在平衡支票帐户,未结算的值代表你已经写的但尚未结清的支票。在此阶段调用 collectFees
会干扰系统的中间状态。
结论
为防止此类问题,用户应避免在交换期间调用如 collectFees
这样的函数,或协议应明确阻止此类调用。确保正确的操作顺序对于避免冲突并维护系统的完整性至关重要。
本文中提出的发现强调了在开发安全和稳健的 DeFi 协议时的重要教训。尽管作为最经过测试和成熟的协议之一,但在多次 审计和形式验证 中发现的漏洞演示了处理边缘案例、通过第一原则推理创建鲁棒不变量和确保复杂系统中准确功能执行的重要性。
Uniswap 聘请各种独立安全团队的决定突显了多样化审计视角在识别漏洞中的必要性。这种协作方法加强了协议,同时确保了在多样区块链环境中的安全性和无缝的用户体验。
- 原文链接: certora.com/blog/uniswap...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!