以太坊事件日志解码器

将原始日志条目(address、topics、data)转换为具名事件和参数。四十余种常见事件可自动识别;其他事件请粘贴合约 ABI。收据中的所有日志会一次性解码。

区块浏览器的“Logs”标签页、viem、ethers 以及 JSON-RPC 响应均可识别;收据中的每条日志都会被解码。
示例:

由浏览器中的 JavaScript 计算。地址不会被上传或存储。

什么是事件日志?

事件日志是 EVM 合约执行 LOG0–LOG4 操作码(Solidity 中的 emit)时写入的记录。每条日志包含发出事件的合约地址、最多四个 32 字节的 topics,以及一个任意长度的 data 字段。解码日志就是把 topics[0] 与某个事件签名匹配,从其余 topics 中读取 indexed 参数,再从 data 中按 ABI 解码非索引参数。区块浏览器借助已验证的源码完成这一步;本页仅凭签名即可解码四十余种常见事件,也可使用你粘贴的任意 ABI。

日志的编码方式

字段内容示例(ERC-20 Transfer)
address发出事件的合约0xdAC17F958D2ee523a2206206994597C13D831ec7(USDT)
topics[0]规范签名的 keccak2560xddf252ad… = keccak256("Transfer(address,address,uint256)")
topics[1]第一个索引参数,左侧补零至 32 字节from 地址
topics[2]第二个索引参数to 地址
data所有非索引参数的 ABI 编码32 字节的 value

静态类型(address、整数、bool、bytes1–32)的索引参数直接存放在 topic 中。动态类型(string、bytes、数组、结构体)的索引参数则按 Solidity ABI 规范事件章节的描述,替换为其编码的 Keccak-256 哈希;解码器会将这类参数标记为已哈希。

实例演示:一笔 USDT 转账

点击上方的“ERC-20 Transfer”。topics[0] 与 Transfer 签名匹配,并且由于恰好有三个 topics,解码器选择 ERC-20 布局(两个索引地址)而非 ERC-721 布局(三个索引参数)。topics[1] 解码为 from = 0xd8dA6BF2…96045,topics[2] 解码为 to = 0x1111…1111,data 中唯一的字 0x17d7840 即 value = 25000000,按 USDT 的 6 位小数计算就是 25 USDT。同样的机制也能解码 Uniswap V2 Swap(两个索引地址,data 中四个金额)或 ERC-1155 TransferBatch(其 data 字段包含两个带偏移量和长度的动态数组)。

无需 ABI 即可识别的事件

下表由页面根据解码器使用的同一份签名列表实时生成,因此每个 topics[0] 值都是对 Keccak 实现的一次自检。它涵盖 ERC-20 和 ERC-721 的 Transfer 与 Approval、ApprovalForAll,ERC-1155 的 TransferSingle、TransferBatch 与 URI,WETH 的 Deposit 与 Withdrawal,Uniswap V2 的 Swap、Sync、Mint、Burn 与 PairCreated,Uniswap V3 的 Swap、Mint、Burn、Collect 与 PoolCreated,OwnershipTransferred,EIP-1967 的 Upgraded、AdminChanged 与 BeaconUpgraded,Initializable、Pausable 与 AccessControl 事件,Permit2 的 Approval、Permit、NonceInvalidation 与 Lockdown,ERC-4626 的 Deposit 与 Withdraw,以及 Safe 的 ExecutionSuccess、ExecutionFailure、SafeMultiSigTransaction、所有者与阈值变更、SafeSetup 与 ProxyCreation。

接受的输入

相关工具:用选择器与 topic 计算器根据任意签名计算 topic 哈希,用 ABI 解码器解码交易的 calldata,或用以太坊交易解码器检查原始交易。

常见问题

以太坊日志中的 topics 和 data 是什么?

一条日志最多有四个 32 字节的 topics 和一个变长的 data 字段。topics[0] 是事件签名的 Keccak-256 哈希(匿名事件除外);topics[1..3] 存放 indexed 参数,每个 topic 一个;所有非索引参数按声明顺序 ABI 编码到 data 中,与函数参数的编码方式完全相同。

为什么索引的 string 或 bytes 显示为哈希?

EVM 无法将动态值放进 32 字节的 topic,因此 Solidity 改为存储该值的 keccak256。原始字符串无法从日志中恢复,只能通过对候选值哈希后进行比对。地址、整数、bool 和 bytesN 会完整存储并正常解码。

ERC-20 和 ERC-721 的 Transfer 拥有相同的 topics[0],如何区分?

两者的签名都是 Transfer(address,address,uint256),所以 topics[0] 完全相同。ERC-721 将 tokenId 设为索引参数,因此有四个 topics 且 data 为空;ERC-20 只索引 from 和 to,因此有三个 topics 和一个 32 字节的 data 字段。解码器会选择索引参数数量与日志相符的布局。

如果事件无法识别怎么办?

日志会以原始形式显示并高亮 topics[0]。将合约的 ABI(只含事件即可)或类似 event Bid(address indexed bidder, uint256 amount) 的单行定义粘贴到 ABI 框中,然后重新解码。4byte.directory 和 openchain.xyz 等签名数据库可以帮助识别未知的 topic 哈希。

匿名事件是如何工作的?

声明为 anonymous 的事件没有签名 topic,因此它的所有 topics 都是索引参数,链上没有任何信息能标识它。解码器只能按 topic 数量将其与你提供的 ABI 中的匿名事件匹配,并会在附注中说明。

金额会换算成代币单位吗?

整数以精确的十进制显示。对于 uint256 值,会附带提示该值除以 1018 和 106 的结果,覆盖 ETH、大多数 ERC-20、USDC 和 USDT。其他小数位请使用代币小数位转换器;解码器并不知道每个代币的小数位数。

会上传任何内容吗?

不会。内置表的 topic 哈希在页面加载时由浏览器用 Keccak-256 计算,解码也在本地运行。页面加载完成后不会发出任何网络请求。