title | tags | ||||||
---|---|---|---|---|---|---|---|
7. 检索事件 |
|
我最近在重新学ethers.js
,巩固一下细节,也写一个WTF Ethers极简入门
,供小白们使用。
WTF Academy社群: 官网 wtf.academy | WTF Solidity教程 | discord | 微信群申请
所有代码和教程开源在github: github.com/WTFAcademy/WTFEthers
提示:本教程基于ethers.js 6.3.0 ,如果你使用的是v5,可以参考ethers.js v5文档。
这一讲,我们将介绍如何使用ethers.js
读取智能合约释放的事件。如果你不了解Solidity
的事件,可以阅读WTF Solidity极简教程中第12讲:事件。
具体可参考ethers.js文档。
智能合约释放出的事件存储于以太坊虚拟机的日志中。日志分为两个主题topics
和数据data
部分,其中事件哈希和indexed
变量存储在topics
中,作为索引方便以后搜索;没有indexed
变量存储在data
中,不能被直接检索,但可以存储更复杂的数据结构。
以ERC20代币中的Transfer
转账事件为例,在合约中它是这样声明的:
event Transfer(address indexed from, address indexed to, uint256 amount);
它共记录了3个变量from
,to
和amount
,分别对应代币的发出地址,接收地址和转账数量,其中from
和to
前面带有indexed
关键字。转账时,Transfer
事件会被记录,可以在etherscan
中查到。
从上图中可以看到,Transfer
事件被记录到了EVM的日志中,其中Topics
包含3个数据,分别对应事件哈希,发出地址from
,和接收地址to
;而Data
中包含一个数据,对应转账数额amount
。
我们可以利用Ethers
中合约类型的queryFilter()
函数读取合约释放的事件。
const transferEvents = await contract.queryFilter('事件名', 起始区块, 结束区块)
queryFilter()
包含3个参数,分别是事件名(必填),起始区块(选填),和结束区块(选填)。检索结果会以数组的方式返回。
注意:要检索的事件必须包含在合约的abi
中。
-
创建
provider
。import { ethers } from "ethers"; // 利用Alchemy的rpc节点连接以太坊网络 // 准备 alchemy API 可以参考https://github.com/AmazingAng/WTFSolidity/blob/main/Topics/Tools/TOOL04_Alchemy/readme.md const ALCHEMY_GOERLI_URL = 'https://eth-goerli.alchemyapi.io/v2/GlaeWuylnNM3uuOo-SAwJxuwTdqHaY5l'; const provider = new ethers.JsonRpcProvider(ALCHEMY_GOERLI_URL);
-
创建包含检索事件的
abi
。// WETH ABI,只包含我们关心的Transfer事件 const abiWETH = [ "event Transfer(address indexed from, address indexed to, uint amount)" ];
-
声明
WETH
合约实例。// 测试网WETH地址 const addressWETH = '0xb4fbf271143f4fbf7b91a5ded31805e42b2208d6' // 声明合约实例 const contract = new ethers.Contract(addressWETH, abiWETH, provider)
-
获取过去10个区块内的
Transfer
事件,并打印出1个。我们可以看到,topics
中有3个数据,对应事件哈希,from
,和to
;而data
中只有一个数据amount
。另外,ethers
还会根据ABI
自动解析事件,结果显示在args
成员中。// 得到当前block const block = await provider.getBlockNumber() console.log(`当前区块高度: ${block}`); console.log(`打印事件详情:`); const transferEvents = await contract.queryFilter('Transfer', block - 10, block) // 打印第1个Transfer事件 console.log(transferEvents[0])
-
读取事件的解析结果。
// 解析Transfer事件的数据(变量在args中) console.log("\n2. 解析事件:") const amount = ethers.formatUnits(ethers.getBigInt(transferEvents[0].args["amount"]), "ether"); console.log(`地址 ${transferEvents[0].args["from"]} 转账${amount} WETH 到地址 ${transferEvents[0].args["to"]}`)
这一讲,我们回顾了Solidity
中的事件,并介绍如何用ethers
检索智能合约释放的事件。要注意的一点:要检索的事件必须包含在合约abi
中。