20251124-DRLVaultV3安全事件:链上实时计算的滑点就等于没有滑点
背景介绍
DRLVaultV3 就是一个基于 USDC 的 Uniswap V3 [WETH, USDC] 流动性收益协议:用户只需要存 USDC 和取 USDC,项目方(operator)负责所有添加流动性、调仓、收手续费的复杂操作,最终收益和本金都以 USDC 形式归用户所有。
造成本次事件的原因是在 DRLVaultV3.swapToWETH() 中采用了 Quoter.quoteExactInputSingle() 在线计算滑点,这个途径计算得到的滑点并不会起作用。这导致了白帽可以对 swapToWETH() 函数进行三文治攻击挽救协议资产。
相关地址:
- DRLVaultV3: 0x6A06707ab339BEE00C6663db17DdB422301ff5e8
- Quoter: 0x61fFE014bA17989E743c5F6cB21bF9697530B21e
- WhiteHat: 0xC0ffeEBABE5D496B2DDE509f9fa189C25cF29671
攻击交易:
Trace 分析
白帽先从 Morpho 闪电贷了 USDC 来完成资金准备

重点是三文治攻击的手法
- 首先用 USDC → WETH 抬高 WETH 的价格
- 然后调用 DRLVaultV3.swapToWETH() 在被操纵的价格基础上,进行 USDC → WETH 进一步抬高 WETH 的价格
- 最后 WETH → USDC 兑换出超额的 USDC 完成获利
代码分析
在 DRLVaultV3.swapToWETH() 函数中,它通过 Quoter.quoteExactInputSingle() 计算与滑点相关的最少换出数量。最后调用 swapRouter.exactInputSingle() 将合约中的 USDC 兑换成 WETH。
注意它的滑点是通过计算得到的,而不是从传入参数得到的

而在 Quoter.quoteExactInputSingle() 中,则是通过执行一个 revert swap 的形式来获取 amountOut 的数量,并在返回值中返回。由于此时 USDC/WETH 的价格已经被 Sandwich1 操纵了,所以通过该函数计算得到的值也是失真的,是不正常的,是无效的。

因为这个 Quoter 合约不持有任何代币,所以它发起的 swap 是必然 revert 的。

最终 DRLVaultV3.swapToWETH() 兑换得到的 WETH 会小于实际的数量。白帽再利用 Sandwich2 将失衡的价格恢复到正常价格,从而完成获利。

浙公网安备 33010602011771号