在 Solidity 中,abi是啥
在 Solidity 中,abi
既指「应用二进制接口(Application Binary Interface)」这一整套规范,也指语言里的全局单例变量 abi
,它提供了一组编解码函数,让合约与外界(EOA、其他合约、前端库)能够相互“说同一种语言”。
✅ 一句话记住
abi
= 合约的 JSON 描述 + 全局编解码工具箱
没有它,外部世界无法知道你的函数长什么样、参数如何排列。
📌 两个层面理解
层面 | 说明 | 例子 |
---|---|---|
规范层 | 定义函数选择器、参数编码、事件日志格式 | ERC-20 Transfer 事件日志就是按 ABI 规范编码 |
语言层 | Solidity 提供的 abi.encode* 系列工具函数 | abi.encodeWithSignature("transfer(address,uint256)", to, amt) |
🔧 常用 abi.*
工具函数速查
函数 | 用途 | 返回类型 |
---|---|---|
abi.encode(...) | 按 ABI 规范编码参数 | bytes memory |
abi.encodePacked(...) | 紧凑打包(不按 ABI 规范,节省空间) | bytes memory |
abi.encodeWithSelector(bytes4 selector, ...) | 编码参数并前置选择器 | bytes memory |
abi.encodeWithSignature(string sig, ...) | 同上,但直接用字符串签名 | bytes memory |
abi.decode(bytes memory, (types...)) | 解码已编码数据 | 返回对应类型的元组 |
type(C).creationCode / runtimeCode | 读取合约字节码 | bytes memory |
type(C).interfaceId | 计算 ERC-165 bytes4 接口 ID | bytes4 |
✅ 代码示例
1. 计算函数选择器
bytes4 sel = bytes4(keccak256("transfer(address,uint256)"));
// 等价于
bytes4 sel2 = IERC20.transfer.selector;
2. 编码外部调用
address to = 0xAbC...;
uint256 amount = 100 * 10**18;// 方法 A:encodeWithSignature
bytes memory data = abi.encodeWithSignature("transfer(address,uint256)",to,amount
);// 方法 B:encodeWithSelector
bytes4 sel = IERC20.transfer.selector;
data = abi.encodeWithSelector(sel, to, amount);
3. 解码返回值
bytes memory encoded = abi.encode(uint256(123), true);
(uint256 num, bool flag) = abi.decode(encoded, (uint256, bool));
4. 生成紧凑哈希(节省存储)
bytes32 hash = keccak256(abi.encodePacked(a, b, c));
🌉 与外部交互
场景 | ABI 作用 |
---|---|
前端调用合约 | Ethers.js / Web3.js 需要合约的 ABI JSON 才能构造交易 |
合约间低层调用 | address(target).call(data) 需要 abi.encodeWithSelector |
代理升级 | 代理合约通过 abi.encodeWithSelector 转发调用到实现合约 |
事件监听 | ABI 中的 anonymous 字段决定事件日志格式 |
✅ 一句话总结
对外:ABI 是合约的「API 说明书」;
对内:Solidity 的abi.*
工具箱让你编码、解码、计算选择器一气呵成。