Solidity自定义错误怎么解码? 图 1
Solidity自定义错误怎么解码? · 图 1

交易失败时,RPC常返回一串0x开头的data。前4字节决定错误类型,后续字节按ABI编码参数。自定义错误与函数调用使用同一种“选择器加参数”结构,因此只要有可信ABI就能还原名称和参数;没有ABI时只能做候选匹配,不能把猜测当成来源证明。

先拆开三种revert数据

  1. 自定义错误数据按同名同参数函数调用的方式ABI编码:前4字节是错误签名选择器,后面是参数编码。
  2. 无参数自定义错误只需4字节返回数据,通常比携带长字符串的Error(string)更节省Gas。
  3. revert data会沿外部调用链冒泡,任何合约都能构造匹配某错误签名的数据,因此不能把解码名称当成来源认证。

选择器怎样得到

例如error InsufficientBalance(uint256 available,uint256 required),规范签名不含参数名和空格。对签名做keccak256并取前4字节,再按两个uint256解码后64字节。错误不能靠显示名称唯一识别,4字节空间存在碰撞,必须结合目标ABI与调用上下文。

错误类型常见前4字节后续数据
Error(string)0x08c379a0动态字符串ABI编码
Panic(uint256)0x4e487b7132字节panic code
CustomError(…)keccak签名前4字节按声明类型ABI编码
空revert无可解码原因

先区分低级调用的返回

高级外部调用通常自动冒泡revert;call、delegatecall和staticcall则返回success=false与原始bytes。调试器若只展示外层包装错误,内层data可能被再编码。应沿调用trace找到最早失败帧,再用该帧可能的ABI集合解码。

拿到十六进制错误后怎么做

  1. 保存完整revert data和失败调用calldata
  2. 先匹配Error、Panic和空数据
  3. 从已验证合约ABI计算custom error selector
  4. 按参数类型和动态偏移解码
  5. 用trace确认错误最初出现的调用帧

错误数据可以被伪造

任何合约都能返回与某个自定义错误相同的字节,内层错误也可向外冒泡。看到OwnableUnauthorizedAccount不证明错误一定来自OpenZeppelin Ownable。错误用于解释失败,不适合充当授权或控制流依据;业务安全判断必须读取状态和验证调用者。

事件ABI可结合topics和data解码比较;执行结果先读交易回执,合约地址与源码来源按合约地址核验确认。

错误名称不能证明来源

自定义错误更省Gas不等于永远只占4字节;带多个参数仍会增加返回数据。Panic也不等于合约被黑,它可能来自数组越界、除零或算术检查。最可靠的报告会同时写出选择器、原始data、ABI来源和区块上下文。