什么是 Multicall?钱包里一笔交易,为什么能连续做多件事

Multicall 把多个函数调用打包进同一笔交易,可组合原子操作,也可能隐藏授权与资产变化。本文讲清原理、失败模式与核查方法。

什么是 Multicall?钱包里一笔交易,为什么能连续做多件事

钱包里有时只显示“一笔交易”,结果却连续完成授权、兑换、存入和质押。它并不是把多笔交易藏起来,而是合约通过 Multicall 或其他批处理机制,把多个函数调用装进一次外部交易中按顺序执行。

批量调用能减少签名步骤并组合原子操作,但也让交易内容更长、更难读。看到 multicall 时,不能只看最外层函数名,必须检查里面每个子调用。

Multicall 是一个信封,真正的动作在信封里的每段 calldata。一次确认可能包含多个权限与资产变化。

Multicall 怎样工作

Multicall 将多段函数 calldata 打包,在同一笔交易中按顺序执行
Multicall 将多段函数 calldata 打包,在同一笔交易中按顺序执行

调用者先把 foo、bar 等函数及参数编码成 bytes 数组,再调用 multicall。合约逐个执行并收集返回结果。OpenZeppelin 的 Multicall 抽象合约允许外部账户把对同一合约的多个函数调用打包为一次外部调用。

“一笔交易”与“一次调用”不一样

一笔交易可以形成很深的调用树:钱包调用路由器,路由器 multicall 多个函数,子函数再调用代币、池子或其他协议。区块浏览器顶层只显示一个 to 地址,不代表只触碰一个合约。

层次例子
交易用户向路由器发送一次链上交易
顶层调用multicall(bytes[])
子调用approve、swap、deposit
外部调用路由器调用代币和流动性池

原子性有什么好处

同一交易中的状态变化通常一起成功或一起回滚。可以先兑换再存入,如果后一步失败,前一步也回滚,避免用户停在半完成状态。OpenZeppelin 文档也强调,后续调用失败可让先前调用一起撤销。

是不是所有批处理都整体回滚

不一定。具体实现可能在子调用失败时立即 revert,也可能捕获失败、返回 success 标志并继续。还有“允许部分失败”的批处理。必须阅读实现和交易模拟,不能仅凭函数名判断原子性。

Gas 与体验

批处理可减少多次交易的固定开销、钱包确认和区块等待,但每个子动作仍消耗 Gas,批次过大也可能超过区块或交易限制。某一步失败导致整体回滚时,已执行计算的 Gas 通常不会退回。

msg.value 如何分配

顶层交易只有一个 msg.value。若多个子调用都按同一个值判断,可能产生重复计算或资金分配错误。实现需要明确每个子调用可使用多少原生币、剩余如何退回,开发者不能假设每次子调用都有独立 value。

为什么安全审查更难

检查 Multicall 交易时要逐项解码批次中的授权、兑换、质押与资金动作
检查 Multicall 交易时要逐项解码批次中的授权、兑换、质押与资金动作

恶意页面可把看似正常动作与无限授权、资产转移或管理员调用打包在一起。中继服务若只过滤顶层函数选择器,也可能漏掉嵌套在 multicall 里的被禁止函数。OpenZeppelin 旧版 API 文档专门提醒,发送方若只验证顶层 calldata,假设可能被 multicall 破坏。

风险核查
隐藏子调用解码 bytes 数组中的每个 selector 和参数
无限授权确认 token、spender、amount
部分失败确认失败策略和返回值处理
重复 value检查原生币记账与退款
重入与状态交叉分析子调用顺序和共享状态

顺序为什么重要

后一个动作读到的是前一个动作更新后的状态。授权后兑换与兑换后授权不同;先领取再质押与先质押再领取也不同。攻击者可能利用顺序、重复调用或中间状态绕过只在单函数场景成立的限制。

开发者清单

  • 明确子调用目标范围、失败策略、返回值和最大批次长度。
  • 对每个嵌套 selector 做权限和参数校验,不只过滤顶层。
  • 正确处理 msg.value、退款、重复调用和幂等性。
  • 分析共享状态、重入、授权和子调用顺序。
  • 与元交易或 ERC-2771 组合时使用兼容版本并测试发送者上下文。
  • 用模糊测试覆盖任意排列、部分失败和恶意 calldata。

普通用户怎样看 Multicall

  1. 使用能展开内部调用的交易模拟器或钱包。
  2. 逐项核对资产、数量、接收方、授权对象和最小输出。
  3. 确认是否包含永久授权、NFT 操作或陌生合约。
  4. 顶层地址可信仍要检查它调用的下游地址。
  5. 内容无法解码或与页面描述不一致时停止签名。

Multicall 与智能账户批处理

智能账户也能一次执行多个目标和金额,但接口、权限和失败模式可能不同。不要把所有 batch 都当成 OpenZeppelin Multicall。核查具体账户标准、执行器、模块权限和签名范围。

三个误区

  • “一笔交易只做一件事”:调用树可包含多个合约和动作。
  • “子调用失败一定整体回滚”:取决于实现是否捕获失败。
  • “批量调用一定更省 Gas”:可能减少固定开销,但复杂批次和失败仍昂贵。

Multicall 的价值是把相关动作组合成一次原子体验。它的风险也来自同一点:复杂性集中在一次确认里。真正要读懂的不是外层 multicall,而是内部每个动作及其顺序。

风险提示:批量交易可能同时改变多项授权与资产状态。签名前请使用可信工具展开内部调用并核验全部参数。本文仅作技术科普,不构成任何投资建议。


本文为链上指南原创内容。技术依据参考 OpenZeppelin Multicall 官方文档。