ABI 编码器把 Solidity 函数签名和一组参数值变成可以直接粘进交易的 0x 开头 calldata, 而且全部在浏览器内完成. 没有后端: 页面内置 js-sha3 做 keccak256, 用原生 BigInt 拼 32 字节字, 用浏览器自带的 UTF-8 编码器给字符串定长. 两个标签页覆盖整个流程: 编码模式吃签名加参数值, 输出选择器加每个参数一个 32 字节字; 解码模式吃原始 calldata, 打印它能还原的内容. 签名输入框下方有实时选择器预览, 结果下方有 hex 字符数计数, 复制前就能看到大小. 先用 ABI 编码器工具 试一下, 输入规范的 transfer(address,uint256).
4 字节选择器是怎么算出来的
选择器是签名串原样跑 keccak256 得到的哈希的前 4 字节. keccak256 是 256 位哈希, 工具算出完整的 64 位 hex 摘要, 取前 8 个 hex 字符, 也就是 EIP-196 定义的合约方法分发前缀. 所以格式很重要: transfer(address,uint256) 哈希出大家熟悉的 0xa9059cbb, 但逗号后多一个空格的同一签名会哈希出完全不同的摘要, 前缀也跟着变, 调用就会打错函数或者直接 revert. 签名输入框下方的预览每敲一个键就重算一次, 拼写错误立刻可见. 想看完整摘要, Keccak 哈希工具 对同一输入会给出完整 64 hex 输出, 前 4 字节作为函数选择器, 前 20 字节作为地址形式.
静态值怎么变成 32 字节字
每个静态参数都写成一个 32 字节字, 右对齐前面补零. 地址必须正好 40 个 hex 字符, 可带可不带 0x 前缀, 补齐到 64. 布尔值接受 true, false, 1 或 0. bytes32 接受 1 到 64 个 hex 字符. 整数覆盖从 8 位类型到 uint256 的整个无符号家族, 以及对应的 128 位和 256 位有符号类型, 每个值在编码前先做范围检查: int128 必须落在负 2^127 到 2^127 减 1 之间, int256 落在负 2^255 到 2^255 减 1 之间. 超范围的输入会被拒绝, 不会静默回绕. 负整数用补码形式存储, 也就是值加 2^bits: stake(int256) 传 -1, 编码结果是选择器 0x77b71df0 后接一个由 64 个 f 组成的字, 这正是 32 字节里 -1 的样子.
动态值怎么拿到偏移量
string, bytes 和数组参数是动态的, 头槽位放的是偏移量而不是数据. 偏移量按字节从第一个头字量起, 就是紧跟 4 字节选择器后面的那个 32 字节字, 不是从选择器本身量起. 只有一个动态参数时, 数据从第一个尾字开始, 比头槽起点晚 32 字节, 所以偏移量字就是 32. 尾部先是长度字, 然后是实际数据, 补齐到 32 字节的整数倍. 长度按 UTF-8 字节数算, 不是字符数, 一个 emoji 占 4 字节. greet(string) 传 hi, 得到选择器 0xead710c4, 偏移量字 32, 长度字 2, 数据字以 0x6869 开头, 即 h 和 i 的 hex, 后面补零.
一次完整编码, 逐字拆解
用 transfer(address,uint256) 拼一次, 接收方 0x1234567890123456789012345678901234567890, 金额 100. 结果是 0xa9059cbb00000000000000000000000012345678901234567890123456789012345678900000000000000000000000000000000000000000000000000000000000000000064, 计数显示 136 个 hex 字符, 正好是选择器 8 加地址字 64 加金额字 64. 金额 100 右对齐在最后那个字里, 100 的 hex 是 64, 地址的 48 个 hex 字符坐在自己那个字的末尾, 前面 24 个零.
解码标签页能做什么, 不能做什么
解码标签页去掉 0x 前缀, 取前 8 个 hex 字符作为选择器, 之后每 64 个 hex 字符按无符号 256 位整数读成一个十进制数. 喂进 stake(uint256,uint256) 的 calldata, 它报告选择器 0x7b0472f0 加两个参数 100 和 2026, 干净地往返. 解码器是类型盲的: 没有 ABI, 没有类型表, 所以 transfer 的 calldata 会把接收方打印成 48 位十进制 103929005307130220006098923584552504982110632080, 而不是地址; string 参数回来的是原始的偏移量, 长度和数据字, 不是文本. 需要看某个字背后的字节时, 把 hex 部分粘进 Hex 转换工具 就能读回 UTF-8 文本.
这个工具不是什么
ABI 编码器不是带类型的合约浏览器: 它只编解码原始字, 想上链查交易, 地址或代币, 用 区块浏览器工具 直连 Etherscan, BscScan, PolygonScan 和主流 L2 浏览器. 它也不是地址校验器: 接收方那个字是 32 字节, 地址是那个字末尾的 40 个 hex 字符, 而 ETH 地址检查工具 会把地址重排成 EIP-55 混合大小写并标出校验和不符. 它也不是手续费计算器: calldata 长度会影响 gas 消耗, Gas 费用估算器 把 gas 上限加基础费和优先费换算成 ETH 和美元成本. 它也不是数值的进制转换器: 小数值用 进制转换工具 就能验证十进制转 hex, 比如 100 变 64, 但它只支持 32 位范围. 它还不是字节级文本工具: 长度字按 UTF-8 字节算, 想看文本逐字符怎么展开, 文本转二进制指南 讲了 ASCII 输入的 8 位展开.