没有ABI怎么解码Calldata:函数选择器与参数步骤

 / 
2

没有 ABI 也能解码 Call dat a——靠函数选择器(4 字节)在公开数据库里查"函数名",然后按规则手拆参数。 查不到名字也照样能拆出参数值,只是看不到参数名而已。

欧易OKX交易所
全球领先的加密货币平台,适合新手与进阶交易者
新手福利:注册即享20% 交易手续费减免!

1. 先搞懂 Calldata 的结构:三块

一笔交易的 Input Data(Calldata)长这样:0xa9059cbb0000000000000000000000003f5047bdb647dc39c88625e17bdbffee905a9f440000000000000000000000000000000000000000000011c9a62d04ed0c80000

拆成两块:

  • 函数选择器(Function Selector):前 4 个字节(a9059cbb)。它是函数签名(如 transfer(address,uint256))的 Keccak-256 哈希的前 4 字节,用来告诉合约"你要调用哪个函数"。

  • 参数数据:4 字节之后的所有内容。每 32 字节(64 个十六进制字符)编码一个参数,按顺序排列。

前置条件:你手里有一笔交易的 TxHash,或者直接拿到了 Calldata 字符串。

2. 第一步:查函数选择器对应哪个函数名

步骤1:用 4byte.directory 查函数选择器

  • 做什么:把前 4 字节输入 4byte.directory 数据库,查对应的函数签名。

  • 怎么做

    • 情况A(网页访问):打开 4byte.directory,在搜索框输入 4 字节选择器(如 0xa9059cbb)。数据库会返回所有匹配的函数签名列表。

    • 情况B(API 调用):GET https://www.4byte.directory/api/v1/signatures/?hex_signature=0xa9059cbb,返回 JSON 结果。

  • 做到什么程度算完成:你拿到了一个或多个可能的函数签名(如 transfer(address,uint256))。如果有多个匹配项,说明不同的函数签名可能撞上了同一个选择器,需要根据参数数量来筛选。

4byte.directory 是目前最大的函数选择器公开数据库,收录了海量签名映射。

步骤2:如果 4byte.directory 查不到,用 Etherscan 的已验证合约兜底

  • 做什么:如果数据库里没有记录,试试通过 Eth erscan 的 API 获取该合约的完整 ABI。

  • 怎么做:调用 https://api.etherscan.io/api?module=contract&action=getabi&address=目标合约地址。如果该合约已开源验证,会返回完整 ABI。有了完整 ABI,用 Web3.py 或 ethers.js 即可精确解码。

  • 做到什么程度算完成:你拿到了完整 ABI 或至少确认了函数名。

欧易OKX交易所
全球领先的加密货币平台,适合新手与进阶交易者
新手福利:注册即享20% 交易手续费减免!

3. 第二步:手拆参数(没有 ABI 也能拆)

即使查不到函数名,你照样能把参数值拆出来。

步骤3:按 32 字节分块提取参数

  • 做什么:去掉函数选择器之后,把剩余数据按每 64 个字符(32 字节)切分。

  • 怎么做:以 0xa9059cbb0000000000000000000000003f5047bdb647dc39c88625e17bdbffee905a9f440000000000000000000000000000000000000000000011c9a62d04ed0c80000 为例:

    • 选择器:a9059cbb

    • 第 1 个参数(address):0000000000000000000000003f5047bdb647dc39c88625e17bdbffee905a9f44 → 去掉 12 字节填充后得到 0x3f5047bdb647dc39c88625e17bdbffee905a9f44

    • 第 2 个参数(uint256):00000000000000000000000000000000000000000000011c9a62d04ed0c80000 → 十进制 5250000000000000000000(18 位小数后为 5250)

  • 做到什么程度算完成:你得到了参数值的列表。

常见失败原因多个函数签名使用了相同的选择器。例如 transfer(address,uint256)transfer(address,address) 不可能撞,但不同参数类型确实可能产生相同选择器,这就是"选择器碰撞"。Nethereum 文档也明确指出,同一个选择器可能匹配多个函数签名。这种情况下,需要结合实际参数长度来推断调用的具体是哪个函数。

风险提醒:4byte.directory 是用户提交的数据库,未经审计,里面可能包含错误或误导性条目。不要仅凭查到的函数名就认为调用内容绝对安全。

做完以上操作,怎么确认自己解码对了?

用已经验证过的 ERC-20 转账交易做一次测试:抄一个 transfer 的 Calldata,按上述步骤拆出地址和金额——如果地址和你看到的接收方一致、金额对得上,说明方法正确。之后遇到陌生合约,如果 4byte.directory 查到多个匹配,用参数长度来排除不可能的那几个。