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

为何通过delegateCall调用智能合约函数时触发的事件会消失?

delegatecall场景下Hardhat测试捕获不到事件的原因

核心原因来自Solidity中delegatecall的运行机制:delegatecall会在调用方合约的上下文中执行被调用方的代码,全程不会切换执行所属的合约地址。

具体到你的场景:

  • 直接调用DelegateCallee合约的getData()函数时,代码运行在DelegateCallee自身的上下文,EVM会将Received事件标记为从DelegateCallee地址发出,因此测试中在delagateCallee实例上监听事件可以正常匹配。
  • 通过DelegateCaller的delegateCallGetData()发起delegatecall时,DelegateCallee的getData()逻辑实际运行在DelegateCaller的上下文内,使用DelegateCaller的存储、DelegateCaller的地址作为执行主体:
    • 此时触发的Received事件,EVM会标记为从DelegateCaller地址发出,而非DelegateCallee地址
    • 你的测试代码是在delagateCallee实例上监听事件,Hardhat的chai匹配器会自动过滤掉地址不匹配的日志,自然无法捕获到从DelegateCaller发出的同名事件,最终抛出“事件未被触发”的断言错误。

修正方案

将测试中监听事件的合约实例替换为delegateCaller即可正常捕获事件,修正后的测试代码片段如下:

it('delegateCallGetData function on caller should emit the Received event on the callee', async () => {
  const value = ethers.utils.parseEther('1');
  const tx = await delegateCaller.delegateCallGetData({ value });
  await expect(tx)
    .to.emit(delegateCaller, 'Received')
    .withArgs(deployer.address, value);
});

补充说明:delegatecall模式下事件的发送方永远是发起delegatecall的合约地址,与逻辑来源的被调用合约无关,是delegatecall的常见易错点。另外你的代码中变量名delagateCallee存在拼写错误(正确拼写为delegateCallee),虽然不影响当前逻辑运行,建议修正避免后续排查问题时产生误导。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 22:33:22