什么是 ABI 和函数选择器?钱包为什么能把十六进制翻成合约操作
ABI 是钱包与智能合约之间的编码说明书,函数选择器决定调用入口。本文讲清 calldata、参数解码、代理、碰撞与核查方法。
钱包让你签一笔交易,详情里却是一长串 0x 开头的十六进制。区块浏览器有时能把它翻译成 transfer、approve 和具体参数,有时只显示 Method ID。完成这层翻译的关键说明书,就是合约 ABI。
ABI 全称 Application Binary Interface,它规定外部世界怎样编码函数调用、参数、返回值、事件和错误。字节本身不自带字段名称,必须配合正确 ABI 才能解码。
ABI 像合约的插头规格与说明书;函数选择器告诉合约要进哪扇门,后面的 calldata 则携带按类型打包的参数。
一次函数调用由什么组成

Solidity ABI 规范定义,函数调用的前四字节是函数选择器:函数规范签名的 Keccak-256 哈希前四字节。规范签名包含函数名和规范化参数类型,例如 transfer(address,uint256),不包含参数名称和返回类型。
选择器后面是参数编码。常见静态值按 32 字节槽排列;string、bytes、动态数组等使用偏移指向后部数据区。人看到的是金额和地址,EVM 接收的是严格排列的字节。
| 部分 | 作用 |
|---|---|
| 函数选择器 | 选择要执行的外部函数 |
| 参数头部 | 静态值或动态数据偏移 |
| 动态数据区 | 长度与实际 bytes、数组内容 |
| Return data | 按 ABI 编码函数返回值 |
JSON ABI 又是什么
开发工具常见的 JSON ABI 列出 functions、events、errors、inputs、outputs 和 stateMutability。前端根据它生成调用界面、编码参数和解码结果。JSON 里的参数名方便人阅读,但链上选择器主要由函数名与类型决定。

为什么有时浏览器解码失败
- 合约源码和 ABI 未公开验证。
- 地址是代理,浏览器没有匹配当前实现 ABI。
- 调用走 fallback、自定义路由或动态字节。
- 交易数据被 Multicall 再次嵌套。
- 实现升级后,使用了旧 ABI。
- 四字节选择器数据库只猜到候选,无法确认真实接口。
四字节会不会碰撞
选择器只有四字节,不同函数签名理论上可能得到相同结果。Solidity 编译器会避免同一合约外部接口中无法区分的冲突,但只靠公共选择器数据库猜函数名仍可能出现多个候选。正确 ABI 和目标合约代码比猜测更可靠。
参数类型为什么必须精确
transfer(address,uint256) 与 transfer(address,uint) 在规范化后都使用 uint256,但 transfer(address,uint128) 会得到不同选择器。tuple、数组和嵌套动态类型的编码也必须完全匹配。类型错了可能调用不到函数,或让参数被错误解释。
payable 不在函数选择器里
可变性、返回类型和参数名不会进入选择器签名。两个接口不能只靠返回值区分重载。交易是否附带原生币还要看 msg.value 和函数 payable 属性,不能从四字节单独判断。
ABI 与代理合约
代理地址接收 calldata,再通过 delegatecall 交给实现。用户交互地址是代理,解码通常要使用实现 ABI。升级会改变可用函数和错误,因此必须同时检查代理类型、当前实现和历史版本。
ABI 与 Event、Custom Error
事件参数按 ABI 分到 topics 与 data;自定义错误也像函数调用一样,以四字节错误选择器加编码参数返回。一个完整 ABI 不只让前端“会调用”,也让它理解成功输出与失败原因。
为什么 ABI 不是安全证明
任何人都可以给一份看似合理的 ABI。它能把字节解释成字段,却不证明目标地址使用这份代码,也不证明函数行为与名称一致。恶意函数可以叫 claimReward,实际执行资产转移。应结合地址、已验证源码、实现和交易模拟。
| 你看到的内容 | 仍需确认 |
|---|---|
| 函数名 approve | token、spender、amount 与真实合约 |
| 函数名 swap | 输入输出、最小值、接收方和路由 |
| 已成功解码 | ABI 是否匹配当前实现 |
| 熟悉的 selector | 是否存在碰撞或自定义 fallback |
开发者怎样更安全地编码
- 优先使用类型检查的接口调用或 abi.encodeCall。
- 低级 call 后检查 success,并正确处理 returndata。
- 避免随意使用容易产生歧义的 abi.encodePacked 进行认证哈希。
- 发布并验证与部署字节码匹配的源码和 ABI。
- 代理升级同步版本、前端、索引器与监控。
- 测试动态类型、空值、边界长度和恶意 calldata。
普通用户怎样看 calldata
- 先确认网络、to 地址和 value。
- 使用可信钱包或模拟器展开函数与参数。
- 重点核对资产、数量、spender、recipient 和 deadline。
- 若是 Multicall,展开每个内部调用。
- 无法解码或 ABI 来源不明时,不要只信网页按钮文字。
三个误区
- “ABI 是合约源码”:它只描述外部接口,不包含完整实现。
- “能解码就安全”:名称和数据可读,不代表行为可信。
- “Method ID 唯一对应一个函数名”:四字节空间有限,可能有碰撞候选。
ABI 是人类工具与 EVM 字节之间的翻译协议。读懂一笔合约调用,需要同时确认选择器、参数、目标地址和真实实现。翻译正确只是起点,理解它会造成什么状态变化才是终点。
风险提示:前端和第三方解码结果可能使用错误 ABI。签名前请核验合约地址、实现、全部参数和资产变化。本文仅作技术科普,不构成任何投资建议。
本文为链上指南原创内容。技术依据参考 Solidity Contract ABI 官方规范。