我最近在重新学 solidity,巩固一下细节,也写一个「Solidity 极简入门」,供小白们使用(编程大佬可以另找教程),每周更新 1-3 讲。
所有代码开源在 github: github.com/AmazingAng/WTFSolidity
这一讲,我们用转账 ERC20 Token为例来介绍 solidity 中的事件(event)。
事件
Solidity 中的事件(event)是 EVM 上日志的抽象,它具有两个特点:
响应:应用程序(ether.js)可以通过 RPC 接口订阅和监听这些事件,并在前端做响应。
经济:事件是 EVM 上比较经济的存储数据的方式,每个大概消耗 2,000-5,000gas 不等。相比之下,存储一个新的变量至少需要 20,000gas。
规则
事件的声明由 event 关键字开头,然后跟事件名称,括号里面写好事件需要记录的变量类型和变量名。以 ERC20 Token合约的 Transfer 事件为例:
我们可以看到,Transfer 事件共记录了 3 个变量 from,to 和 value,分别对应Token的转账地址,接收地址和转账数量。同时 from 和 to 前面带着 indexed 关键字,表示很重要,程序可以轻松的筛选出特定转账地址和接收地址的转账事件。每个事件最多有 3 个带 indexed 的变量。
我们可以在函数里释放事件。在下面的例子中,每次用_transfer() 函数进行转账操作的时候,都会释放 Transfer 事件,并记录相应的变量。
在 etherscan 上查询事件
我们尝试用_transfer() 函数在 Rinkeby 测试网络上转账 100 Token,可以在 etherscan 上查询到相应的 tx:https://rinkeby.etherscan.io/tx/0x8cf87215b23055896d93004112bbd8ab754f081b4491cb48c37592ca8f8a36c7
点击 Logs 按钮,就能看到事件明细:
Event 明细
Topics 里面有三个元素,[0] 是这个事件的哈希,[1] 和 [2] 是我们定义的两个 indexed 变量的信息,即转账的转出地址和接收地址。Data 里面是剩下的不带 indexed 的变量,也就是转账数量。
总结
这一讲,我们介绍了如何使用和查询 solidity 中的事件。很多链上分析工具包括 Nansen 和 Dune Analysis 都是基于事件工作的。