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

使用evm_increaseTime后Hardhat测试交易回滚问题排查

问题诊断与修复方案

核心问题:合约ETH余额不足导致转账失败

你的claim()函数最后执行payable(msg.sender).transfer(policy.payout)时,合约ETH余额不足以支付0.1ETH的赔付金额,这是交易回滚的直接原因:

  • 用户购买保单仅支付了0.01ETH,合约初始部署后无额外资金,无法覆盖0.1ETH的赔付额度
  • Solidity的transfer()函数在余额不足时会直接触发交易回滚,这就是报错的根源

时间操作的正确性验证

你使用evm_increaseTime(10)+evm_mine()的方式是正确的,从日志输出的时间来看,区块时间确实已推进至保单到期之后,block.timestamp >= policy.expiresAt、!policy.claimed、currentPrice <= policy.triggerPrice这三个前置检查均已通过,问题出在最后一步转账环节。

修复步骤

1. 给合约注入足够赔付准备金

在测试脚本的合约部署完成后,添加代码让合约所有者向合约转入足够ETH:

// 部署合约后新增此段代码
await owner.sendTransaction({
  to: crash.address,
  value: hre.ethers.parseEther("1.0") // 转入1ETH作为赔付准备金
});

2. 可选:优化合约资金安全检查

为提前暴露余额不足问题,可在claim()函数中增加余额校验:

function claim(uint256 currentPrice) external {
    Policy storage policy = policies[msg.sender];
    require(block.timestamp >= policy.expiresAt, "Policy still active");
    require(!policy.claimed, "Already claimed");
    require(currentPrice <= policy.triggerPrice, "Trigger not met");
    // 新增:提前检查合约余额是否足够支付赔付
    require(address(this).balance >= policy.payout, "Insufficient contract balance");

    policy.claimed = true;
    payable(msg.sender).transfer(policy.payout);
}

3. 验证修复效果

修改后重新执行测试脚本,合约有足够余额完成赔付,claim()交易即可成功执行。

额外提示

  • 测试时间依赖合约时,evm_increaseTime仅修改节点时间偏移,必须配合evm_mine生成新区块,新区块的timestamp才会更新,你的时间操作用法是正确的
  • 涉及ETH转账的合约,建议采用pull模式(让用户主动提取资金)替代合约主动转账,避免因gas限制或余额不足导致的交易失败

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 23:39:52