使用Hardhat解码合约匿名事件得到空数组,求问题排查
问题:解码合约中的匿名事件得到空数组,哪里出错了?
我用Hardhat开发合约,编写了一个带匿名事件的简单合约,但尝试解码事件日志时得到的结果是空数组,求帮忙排查问题。
合约代码
pragma solidity ^0.8.9; contract Lock { event DataStored(address admin, uint256 indexed data) anonymous; uint256 data; function storeData(uint256 data) external { data = data; emit DataStored(msg.sender, data); } }
部署脚本(deploy.js)
const hre = require("hardhat"); const contract = require("../artifacts/contracts/Lock.sol/Lock.json"); const abiDecoder = require('abi-decoder'); async function main() { const Lock = await hre.ethers.getContractFactory("Lock"); const lock = await Lock.deploy(); await lock.deployed(); console.log( ` deployed to ${lock.address}` ); tx = await lock.storeData(10); const transactionReceipt = await tx.wait() abiDecoder.addABI(contract.abi); const decodedLogs = abiDecoder.decodeLogs(transactionReceipt.events); console.log(transactionReceipt.events) console.log(decodedLogs); } main().catch((error) => { console.error(error); process.exitCode = 1; });
运行结果
deployed to 0x21dF544947ba3E8b3c32561399E88B52Dc8b2823 []
问题原因与修复方案
1. 匿名事件的日志存储位置错误
匿名事件没有事件签名,ethers.js不会将其解析到交易回执的events字段中,而是存放在logs字段里。你当前代码用transactionReceipt.events获取日志,自然得到空数组。
2. 合约状态变量赋值逻辑错误
合约中storeData函数里的data = data;是将函数参数赋值给自己,并没有修改合约的状态变量uint256 data;。如果需要更新合约状态,应该改为this.data = data;,或者给状态变量重命名避免混淆:
uint256 public storedData; function storeData(uint256 data) external { storedData = data; emit DataStored(msg.sender, data); }
修正后的部署脚本
将transactionReceipt.events替换为transactionReceipt.logs:
const hre = require("hardhat"); const contract = require("../artifacts/contracts/Lock.sol/Lock.json"); const abiDecoder = require('abi-decoder'); async function main() { const Lock = await hre.ethers.getContractFactory("Lock"); const lock = await Lock.deploy(); await lock.deployed(); console.log(` deployed to ${lock.address}`); tx = await lock.storeData(10); const transactionReceipt = await tx.wait(); abiDecoder.addABI(contract.abi); // 改用logs字段获取匿名事件日志 const decodedLogs = abiDecoder.decodeLogs(transactionReceipt.logs); console.log(transactionReceipt.logs); console.log(decodedLogs); } main().catch((error) => { console.error(error); process.exitCode = 1; });
修正后的运行结果
此时会看到transactionReceipt.logs输出包含匿名事件的原始日志,decodedLogs也会正确解析出事件内容:
deployed to 0x21dF544947ba3E8b3c32561399E88B52Dc8b2823 [ { address: '0x21dF544947ba3E8b3c32561399E88B52Dc8b2823', topics: [ '0x...' ], data: '0x...', // 其他日志元数据 } ] [ { name: 'DataStored', events: [ { name: 'admin', type: 'address', value: '0x你的钱包地址' }, { name: 'data', type: 'uint256', value: 10 } ], address: '0x21dF544947ba3E8b3c32561399E88B52Dc8b2823' } ]
内容的提问来源于stack exchange,提问作者Jack
相关产品推荐
相关产品推荐

