You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Hardhat测试中监听外部库触发的事件?

监听未在被调用合约ABI中声明的库事件(Hardhat+Chai测试)

要监听这种由独立库触发、未被调用合约(A)声明的事件,核心思路是直接解析交易收据(receipt)中的日志,手动用事件所在库的ABI解码。具体步骤如下:

1. 定义Events库的事件ABI

首先抽取出Events库中DataChanged事件的ABI(支持人类可读格式或JSON格式):

const EVENTS_ABI = [
  "event DataChanged()"
];

2. 编写测试逻辑

在测试用例中,调用合约方法后获取交易收据,通过事件签名的哈希匹配日志,再解码验证:

const { expect } = require("chai");
const { ethers } = require("hardhat");

// 定义Events库的事件ABI
const EVENTS_ABI = [
  "event DataChanged()"
];

describe("Contract A Event Test", function () {
  let contractA;

  beforeEach(async function () {
    // 部署合约A
    const ContractA = await ethers.getContractFactory("A");
    contractA = await ContractA.deploy();
    await contractA.deployed();
  });

  it("should capture DataChanged event from Events library", async function () {
    // 调用合约A的callToB方法,获取交易响应
    const txResponse = await contractA.callToB();
    // 等待交易上链,获取完整收据
    const txReceipt = await txResponse.wait();

    // 创建Events库的Interface实例,用于解码事件
    const eventsInterface = new ethers.Interface(EVENTS_ABI);
    // 计算DataChanged事件的topic(事件签名的Keccak256哈希)
    const dataChangedTopic = ethers.id("DataChanged()");

    // 从收据日志中筛选出目标事件
    const targetLogs = txReceipt.logs.filter(log => log.topics[0] === dataChangedTopic);

    // 验证事件是否被触发
    expect(targetLogs.length).to.equal(1, "DataChanged event should be emitted once");

    // 解码事件(无参数时args为空数组)
    const decodedEvent = eventsInterface.parseLog(targetLogs[0]);
    expect(decodedEvent.name).to.equal("DataChanged");
  });
});

关键说明

  • 无法直接用contractA.on("DataChanged")监听:因为合约A的ABI中未包含该事件,合约实例无法识别这个事件的签名。
  • 事件topic的作用:每一个事件的签名(如DataChanged())都会被哈希成唯一的topic,作为日志的第一个元素,用来匹配对应事件。
  • 库事件的日志会被包含在交易收据中:不管触发事件的是库还是合约,只要交易执行了事件触发逻辑,日志就会被记录在交易收据里。

内容的提问来源于stack exchange,提问作者JuanXavier

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 10:07:46