safeBatchTransferFrom 的全有全无:ERC-1155 批量转账中途失败会怎样
把五种材料加一张门票一次性转给队友,是 ERC-1155 批量转账的典型场景。有人担心:十种代币转到第七种时余额不够,前六种会不会已经转出去了?答案写在标准的回滚规则里。本文按规范讲清批量调用发生什么。
批量调用的输入形态
safeBatchTransferFrom 接收两个等长数组:_ids 列代币类型编号,_values 列对应数量,按位置一一对应。规范明确余额变化和事件必须按数组顺序发生,并且要求调用方对 _from 账户下所有被转代币持有相应授权——批量操作里授权检查覆盖整批,任何一项缺授权都不行。
哪些情况必须回滚
规范用强制回滚的措辞列出了失败条件:_to 是零地址;两个数组长度不一致;任何一个代币持有者的余额低于对应要转的数量;以及任何其他错误。这些条件不是警告,而是让整笔交易回滚的硬性规则。换句话说,ERC-1155 的批量语义是全有全无:不存在“转成功一半、失败一半”的中间状态,失败时所有余额变动和事件都撤销,gas 照付、状态如旧。
接收方也能让整单失败
如果 _to 是合约地址,代币合约在余额更新后必须调用接收钩子(批量对应 onERC1155BatchReceived)。接收合约可以接受(返回约定的魔术值)、可以主动拒绝(内部回滚)、返回任何其他值同样导致交易回滚。所以即使你这边余额、授权、数组全部正确,对面合约一句“不接”同样让整单归零。给合约地址批量转账前,先确认对方实现了接收钩子,是排查“参数正确却失败”的第一站。
单转与批转的选择
标准同时提供单项版 safeTransferFrom 与批量版,批量版即使数组只含一项也应走批转路径,但个别接收合约对两条路径的处理不一致。实操建议:多项资产一律用批转保持原子性;单项转账遇到批转路径失败时,换单项调用再试一次,并把两种路径的失败都记进排查清单。
事件账怎么对
批转要求发出的事件必须完整反映所有余额变化,通常是一条 TransferBatch。核对批量交易时,用事件里的 ids 与 values 数组和你提交的清单逐项对:交易成功但事件数组内容、顺序对不上,说明合约实现不规范。事件数组与提交数组的一致性是判断一次批量操作是否真正按你的意思执行的依据。
小结
批量转账的心智模型:把整批当成一笔不可分割的交易。参数层面查数组等长与授权,状态层面查每种代币的余额,环境层面查接收合约的钩子支持,三关都过才会成功;任何一关失败,结果是干净的整体回滚而不是部分成交,这反而是 ERC-1155 在工程上最可靠的性质。
排查顺序模板
遇到批转失败,按固定顺序过一遍最省时间:先确认数组长度与配对没错;再逐项查 _from 对每个 id 的余额;然后查对操作地址的授权是否覆盖全部 id;最后确认收款合约实现钩子。四步都不涉及猜测,全部可以用只读调用完成。若全部通过仍失败,读一下合约源码里的额外限制(黑名单、暂停开关等),异常往往藏在标准之外的自定义逻辑里。
补充一个成本视角:批量把多笔转账合并为一笔,省的是每笔交易的基础 gas 与逐个确认等待,但失败的整单回滚也意味着重试要整批重来,对含外部接收合约的批次,先与对方确认钩子实现再批量执行,比反复整单重试便宜得多。
风险提示:本文仅介绍代币标准机制,不构成任何投资建议。涉及批量授权操作时请注意控制授权范围。
发表评论
还没有评论,来说两句吧。
评论区为展示样式,提交不会被处理。