#3 Balancer V2 事件:舍入不一致破坏了不变式并跨链传播
2025 年 11 月 3 日,Balancer V2 的可组合稳定池以及多个链上的多个分叉项目遭受了协调性攻击,导致总损失超过 1.25 亿美元,据报道约有 4500 万美元被追回。根本原因是由于在放大和缩小操作之间的舍入不一致,导致不变式计算中的精度损失,从而使 BPT(Balancer 池代币)定价逻辑扭曲。
此次事件之所以成为 2025 年十大安全事件之一,不仅因为损失的规模,还因为底层 bug 的微妙性。此外,此次攻击迅速蔓延到多个链,并影响了 Balancer 及其分叉,凸显了共享代码库和可组合 DeFi 基础设施如何显著放大系统性风险。
我们已发布一份题为“深入分析:Balancer V2 攻击” [1] 的详细报告,其中提供了详细的技术 breakdown。下面,我们对此次事件进行简要说明。
背景
Balancer V2 的可组合稳定池
此次攻击中受影响的组件是 Balancer V2 协议的可组合稳定池 [2]。这些池专为预期保持近 1:1 比例(或以已知汇率交易)的资产而设计,并允许进行大额掉期,价格影响极小,从而显著提高了同类或相关资产之间的资本效率。每个池都有自己的 Balancer 池代币(BPT),代表流动性提供者在池中的份额,以及相应的底层资产。
-
此池采用稳定币数学(基于 Curve 的 StableSwap 模型),其中不变式 D 代表池的虚拟总价值。
-
BPT 价格可近似为:
从上述公式可以看出,如果 D 在纸面上可以减小(即使没有实际的资金损失),BPT 的价格就会显得更便宜。
batchSwap() 和 onSwap()
Balancer V2 提供了 batchSwap() 函数,该函数支持 Vault [3] 内的多跳掉期。根据传递给该函数的参数,有两种掉期类型:
GIVEN_IN(“给定输入”):调用者指定输入的精确数量,池计算相应的输出数量。GIVEN_OUT(“给定输出”):调用者指定所需的输出数量,池计算所需的输入数量。
通常,batchSwap() 由通过 onSwap() 函数执行的多个代币到代币掉期组成。此过程不可避免地涉及与不变式 D [1] 相关的金额计算。
缩放和舍入
为了标准化不同代币余额之间的计算,Balancer 执行以下两个操作:
- 放大:在执行计算之前,将余额和金额放大到统一的内部精度。
- 缩小:将结果转换回其原始精度,并应用定向舍入(例如,输入金额通常向上舍入以确保池不会少收费用,而输出金额通常向下舍入)。
放大和缩小在理论上是成对的操作:分别对应乘法和除法。然而,在这些操作的实现中存在不一致性。 具体来说,缩小操作有两种变体或方向:“divUp”和“divDown”。相比之下,放大操作只有一个方向,即“mulDown”。
漏洞分析
根本问题源于 BaseGeneralPool._swapGivenOut() 函数中放大期间执行的向下舍入操作。特别地,_swapGivenOut() 通过 _upscale() 函数错误地向下舍除了 swapRequest.amount。由此产生的舍入值随后在通过 _onSwapGivenOut() 计算 amountIn 时用作 amountOut。此行为与协议有利的舍入标准做法相悖。
因此,对于给定的池(wstETH/rETH/cbETH),计算出的 amountIn 低估了实际所需的输入。这使得用户可以用较少数量的一种底层资产(例如 wstETH)换取另一种资产(例如 cbETH),从而由于有效流动性降低而导致不变式 D 降低。因此,相应 BPT(wstETH/rETH/cbETH)的价格被人为压低,因为 BPT 价格 = D / totalSupply。
攻击分析
攻击者执行了分两个阶段的攻击,可能是为了最大限度地降低被发现的风险:
- 在第一阶段,核心攻击在单个交易内完成,没有立即获利。
- 在第二阶段,攻击者在单独的交易中提取资产以实现利润。
第一阶段可进一步细分为两个阶段:参数计算和批量掉期。下面,我们将使用 Arbitrum 上的示例攻击交易(TX)来说明这些阶段。
参数计算阶段
在此阶段,攻击者结合了链下计算和链上模拟,根据可组合稳定池的当前状态(包括缩放因子、放大系数、BPT 费率、交易费用和其他参数),精确调整下一个(批量掉期)阶段的每个跳跃参数。攻击者还部署了一个辅助合约来协助这些计算,这可能旨在减少被抢跑的风险。有关更多详细信息,请参阅 [1]。
批量掉期阶段
然后,batchSwap() 操作可分解为三个步骤:
步骤 1:攻击者将 BPT(wstETH/rETH/cbETH)兑换成底层资产,以精确地将一种代币(cbETH)的余额调整到舍入边界的边缘(金额 = 9)。这为下一步的精度损失创造了条件。
步骤 2:攻击者随后使用一个精心设计的金额(= 8)在另一种底层资产(wstETH)和 cbETH 之间进行掉期。由于在缩放代币金额时向下舍入,计算出的 Δx 变得稍小(从 8.918 变为 8),导致 Δy 被低估,从而导致不变式(Curve 的 StableSwap 模型中的 D)减小。由于 BPT 价格 = D / totalSupply,BPT 价格被人为压低。
步骤 3:攻击者将底层资产反向兑换回 BPT,恢复了平衡,同时从被压低的 BPT 价格中获利。
总结
此次事件涉及一系列协调攻击交易,目标是 Balancer V2 的可组合稳定池以及跨不同链的多个分叉部署,造成了巨额损失。在第一次攻击后,模仿攻击交易迅速涌现,表明一旦攻击模式暴露,其传播速度有多快。
关键经验教训:
- 舍入和精度处理:所有代币金额的缩放和精度操作都应朝着有利于协议的方向舍入。
_upscale()(仅向下舍入)和缩小操作(定向舍入)之间的单一不一致足以造成可利用的定价扭曲。 - 安全军备竞赛:攻击者将操纵和利润提取分拆到单独的交易中以逃避检测。检测系统应关联相关交易,而不仅仅是标记单个交易。
- 运营安全:一旦攻击模式公开,模仿者在几分钟内就跨链复制了它。共享代码库的协议需要协调的监控和快速的跨链暂停功能。
参考
-
https://blocksec.com/blog/in-depth-analysis-the-balancer-v2-exploit
-
https://docs-v2.balancer.fi/concepts/pools/composable-stable.html
-
https://docs-v2.balancer.fi/reference/swaps/batch-swaps.html
关于 BlockSec
BlockSec 是一家全栈式区块链安全和加密合规提供商。我们构建产品和服务,帮助客户在协议和平台的整个生命周期中进行代码审计(包括智能合约、区块链和钱包)、实时拦截攻击、分析事件、追踪非法资金,并满足 AML/CFT 义务。
BlockSec 在知名会议上发表了多篇区块链安全论文,报告了多个 DeFi 应用的零日攻击,阻止了多次黑客攻击,挽救了超过 2000 万美元,并确保了数十亿美元的加密货币安全。
-
官方 Twitter 账号:https://twitter.com/BlockSecTeam



