目 录CONTENT

文章目录

重入,溢出,mev

懿曲折扇情
2026-02-23 / 0 评论 / 1 点赞 / 7 阅读 / 2,619 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2026-02-23,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。
广告 广告

DeFi 常见风险速查(重入 / 溢出&精度 / MEV)

这份文档面向 DApp/DeFi 开发、测试、产品,目标是“一目了然 + 可落地执行”。每个风险按如下结构说明:

  • 定义:它是什么
  • 触发条件:通常怎么发生
  • 影响:会造成什么损失/故障
  • 典型场景:在 DeFi 里常见在哪些模块出现
  • 如何发现:测试/审计时怎么快速定位
  • 防护建议:工程上怎么做更安全

1) 重入(Reentrancy)

定义

重入是指合约在一次外部调用(call / transfer / 调用外部合约函数)过程中,被对方合约“回调”回来,再次进入当前合约的某个函数(通常是同一个或相关的资金函数),导致状态尚未更新或校验被绕过,从而产生 重复提款、重复记账、绕过额度 等问题。

触发条件(常见)

  • 你在函数中 先对外部地址/合约转账或调用,再更新内部状态(余额、份额、索引等)。
  • 外部调用使用了 call(或可执行任意逻辑的外部合约调用),对方合约在 fallback/receive 中回调你的合约函数。
  • 资金相关逻辑没有“重入锁”或逻辑上允许在未完成状态下重复进入。

影响

  • 重复提现/盗取资金:同一份余额被多次取出。
  • 状态错乱:份额、利息索引、会计账本被多次更新或未一致更新。
  • 绕过限制:如额度检查在第一次通过后,第二次重入时绕过。

典型场景(DeFi 高频)

  • Vault / Bankdeposit() / withdraw() / redeem()
  • Stakingunstake() / claimRewards()(奖励发放先转账后更新)。
  • AMM/Swap Router:某些回调式设计(尤其是多合约交互、flash swap)。
  • 借贷协议borrow() / repay() / liquidate() 中的外部调用、代币转账、回调。

如何发现(测试/审计抓手)

  • 代码扫描
    • 查找“外部调用”后才更新状态的模式:
      • token.transfer(...) / call{value:...},再 balances[msg.sender] -= amount
    • 查找可重入入口:任何 public/external 且会改变余额/份额的函数。
  • 单测/模糊测试
    • 用恶意合约(attacker)在 fallback 中重入目标函数,验证能否重复提款或破坏不变量。
  • 不变量检查(Invariants)
    • “合约资产总额 = 用户份额总和”;
    • “单用户余额不会负数/不会在一次操作内增加两次”;
    • “每次提款后余额必然减少”。

防护建议(工程可落地)

  • CEI 模式(Checks-Effects-Interactions)
    • 先做校验(Checks),再更新状态(Effects),最后外部交互(Interactions)。
  • 重入锁(Reentrancy Guard)
    • 对关键函数加 nonReentrant,并避免可重入的内部/外部调用链造成“锁绕开”。
  • 拉取式支付(Pull over Push)
    • 先记账,用户自己来 claim();避免在核心流程里直接对外部地址转账。
  • 最小外部调用
    • 尽量减少可执行任意逻辑的外部调用;必要时把外部调用集中在最后一步。

2) 溢出 / 下溢(Overflow/Underflow)与“精度/舍入”风险

说明:Solidity 0.8+ 已默认检查整型溢出并自动 revert,但现实中更常见的“溢出类事故”来自:

  • 使用旧版本/unchecked/自定义数学库
  • 精度处理错误、舍入误差、单位换算错误、顺序错误(这些会导致资产错算,效果与“溢出”一样严重)

定义

  • 溢出/下溢:数值超过类型上限/下限后回绕(或在 0.8+ 触发 revert)。
  • 精度/舍入风险:由于整数除法、decimals 差异、固定点计算误差导致:
    • 计算出的金额偏大/偏小;
    • 利息、份额、价格、兑换比率错误;
    • 长期累积后出现“系统性亏损/被套利”。

触发条件(常见)

  • unchecked {} 中做加减乘,或依赖外部库/老版本合约。
  • amount * price / 1e18 的计算顺序不当,先除导致大量精度损失。
  • 不同代币 decimals 不同(6/8/18),单位换算遗漏。
  • 份额(share)/价格(pricePerShare)/利息指数(index)更新时,舍入方向导致可被“反复存取套利”。

影响

  • 用户资产被错误铸造/销毁:多给或少给。
  • 可被套利:利用舍入误差反复操作赚取差额(常见于 share 计算、兑换比率)。
  • 系统性坏账:借贷协议利息/抵押计算错误导致清算阈值失效。

典型场景(DeFi 高频)

  • Vault / Share 模型
    • shares = amount * totalShares / totalAssets
    • amount = shares * totalAssets / totalShares
  • 借贷利息/指数
    • 利息指数累乘、累加带来精度问题。
  • AMM 报价/滑点
    • amountOutMin 计算错误,导致用户被过度滑点或交易失败。
  • 抵押品估值
    • 价格喂价单位(8 位/18 位)换算出错,直接影响清算。

如何发现(测试/审计抓手)

  • 边界值测试
    • 极小金额(1 wei / 1 最小单位);
    • 极大金额(接近 uint256 上限);
    • decimals 不同的组合(6↔18、8↔18)。
  • 舍入方向测试
    • 连续执行 deposit -> withdraw -> deposit -> withdraw,看是否能凭舍入赚钱。
  • 属性/不变量测试
    • “总资产变化 = 用户资产变化之和(含手续费/利息)”;
    • “shares 不能凭空增发”;
    • “同一价格下可赎回金额不应超过总资产”。

防护建议(工程可落地)

  • 统一精度(WAD/RAY)
    • 约定内部统一用 1e18(WAD)或 1e27(RAY),对外再换算。
  • 使用成熟数学库
    • mulDiv(512 位乘法再除法)减少溢出与精度损失(例如 OpenZeppelin/PRBMath 等思路)。
  • 明确舍入策略
    • 关键处选择向下取整(防止多发钱)或向上(防止少收手续费)并在文档中写清楚。
  • 避免 unchecked
    • 除非明确证明安全,并写测试覆盖边界。

3) MEV(Maximal/Maximum Extractable Value)

定义

MEV 是指出块者/排序者(或通过搜寻者 Searcher 与他们合作)利用“交易排序权”从用户交易中获取额外收益的行为。它不是传统意义的“合约漏洞”,但会让用户在链上交易时产生 更差成交价、被夹击、被抢跑、被清算抢占 等损失。

触发条件(常见)

  • 交易进入公共 mempool,可被观察。
  • 交易包含可预测的盈利机会:
    • 大额 swap(滑点设置过宽);
    • 套利路径明显;
    • 清算、预言机更新窗口;
    • 铸造/赎回比例变化等。

影响

  • 夹子攻击(Sandwich):用户成交价显著变差(被前置买入抬价,后置卖出砸回)。
  • 抢跑(Front-run):别人先一步执行同类交易,吃掉机会(如套利/清算)。
  • 后跑(Back-run):在你交易后立刻套利,间接提高你的成本(尤其是 AMM)。
  • 交易失败/被 DoS:你的交易因价格变化或 Gas 竞争失败,浪费时间和机会(有的链会消耗手续费)。

典型场景(DeFi 高频)

  • Swap/聚合器交易:大额 swap、滑点宽、路径公开。
  • 清算:谁先清算谁赚清算奖励。
  • 铸造/赎回窗口:价格更新、指数更新前后存在可套利的短窗口。
  • NFT/IDO:抢跑铸造、本质也是 MEV。

如何发现(测试/审计抓手)

  • 看交易参数
    • amountOutMin 是否设置过低(滑点过大);
    • deadline 是否过长;
    • 是否暴露可预测的套利路径。
  • 回放链上案例
    • 在区块浏览器/MEV 仪表盘上查看同区块内是否出现“前置/后置”两笔围住用户交易的模式。
  • 仿真测试
    • 在本地 fork 环境里模拟:攻击者在你交易前后插入 swap,比较用户实际损失。

防护建议(工程可落地)

  • 合理滑点与期限
    • 默认给出保守滑点;对大额交易提示用户风险;
    • deadline 设短,降低被长时间观察的窗口。
  • 使用私有交易通道(视链而定):
    • 例如通过私有 mempool / 交易包(bundle)提交,减少被公开观察和夹击的概率。
  • 抗 MEV 设计
    • 对易被夹的操作拆分、引入 TWAP/预言机、限制单笔交易价格影响;
    • 对清算采用拍卖/批量处理(减少抢跑空间)。
  • 用户侧提示
    • 交易确认前展示“预计滑点损失范围”“价格影响”;
    • 大额交易建议分批或走聚合器、私有通道。

一页测试/审计清单(建议直接用)

重入

  • 是否所有资金函数满足 CEI?
  • 是否对关键入口加了重入锁?
  • 是否有外部调用(尤其是 call)在状态更新之前?
  • 是否有 attacker 合约重入单测?

溢出/精度

  • 是否统一内部精度(WAD/RAY)并清晰换算 decimals?
  • 是否覆盖极小/极大金额、不同 decimals 的边界测试?
  • 是否明确舍入方向并验证“反复存取套利”不可行?

MEV

  • 默认滑点是否过宽?deadline 是否过长?
  • 大额交易是否给出价格影响提示?
  • 是否考虑私有通道或抗 MEV 机制(尤其是清算、重大 swap)?
1

评论区