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

VestingWallet智能合约单元测试报‘header not found’错误求助

VestingWallet合约测试‘header not found’错误排查与解决

问题描述

基于OpenZeppelin实现自定义VestingContract合约,使用Truffle编写单元测试时,最后一个测试用例执行抛出header not found错误,需排查原因并解决。

合约代码

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

import "@openzeppelin/contracts/finance/VestingWallet.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract VestingContract is VestingWallet {
    constructor(
        address beneficiaryAddress,
        uint64 startTimestamp,
        uint64 durationSeconds
    )
        public
        VestingWallet(beneficiaryAddress, startTimestamp, durationSeconds)
    {}

    function getBalance() public view returns (uint256) {
        return address(this).balance;
    }

    function getBalanceFromToken(address _token) public view returns (uint256) {
        return IERC20(_token).balanceOf(address(this));
    }
}

测试代码

const VestingContract = artifacts.require("VestingContract");
const IoraContract = artifacts.require("Iora");

contract("VestingContract", function (accounts) {

  it("should assert true", async function () {
    await VestingContract.deployed();
    return assert.isTrue(true);
  });

  it("beneficiary and accounts[0] should be the same", async function () {

    const wallet = accounts[0];
    const vestingInstance = await VestingContract.deployed();
    const walletFromSmartContract = await vestingInstance.beneficiary();

    return assert.isTrue(wallet === walletFromSmartContract)
  });

  it("actual timestamp should be the high or the same when it was deployed", async function () {

    const vestingInstance = await VestingContract.deployed();
    const vestingStarted = await vestingInstance.start();
    const startTimestamp = Math.floor(Date.now() / 1000);

    return assert.isTrue(startTimestamp >= vestingStarted.toNumber())
  });

  it("balance from erc20 token should be the same on this contract balance", async function () {

    const vestingInstance = await VestingContract.deployed();
    const ioraInstance = await IoraContract.deployed();
    await ioraInstance.transfer(vestingInstance.address, 150);
    const ioraBalance = await ioraInstance.balanceOf(vestingInstance.address);
    const ioraTokenBalance = await vestingInstance.getBalanceFromToken(ioraInstance.address);

    return assert.isTrue(ioraBalance.toNumber() === ioraTokenBalance.toNumber())
  });

  it("total released should be the same as we transfered", async function () {

    const amount = 3000;
    const vestingInstance = await VestingContract.deployed();
    const ioraInstance = await IoraContract.deployed();
    await ioraInstance.transfer(vestingInstance.address, amount);

    await vestingInstance.release(ioraInstance.address);
    const releasedVesting = await vestingInstance.released(vestingInstance.address);

    return assert.isTrue(amount === releasedVesting.toNumber())

  });

});

报错信息

1) Contract: VestingContract
     total released should be the same as we transfered:
   Error: Returned error: header not found
    at Context.<anonymous> (test/vesting_contract.js:47:51)
    at processTicksAndRejections (internal/process/task_queues.js:95:5)

错误原因分析

  1. 函数参数错误:最后一个测试用例中,vestingInstance.released(vestingInstance.address)传入了错误参数。OpenZeppelin的VestingWallet合约中,released函数参数应为ERC20代币地址,而非vesting合约自身地址,参数错误会触发合约调用逻辑异常。
  2. 时间条件不满足:VestingWallet的释放逻辑依赖vesting周期,若测试时未快进时间至周期结束,release操作无法释放全部代币,不仅断言会失败,还可能引发连锁调用异常。
  3. 测试环境问题:Truffle与Ganache版本不兼容、Ganache服务未正常启动,或truffle-config.js网络配置错误,也会导致header not found这类通信错误。

解决方法

1. 修正函数参数

将released函数的参数改为代币实例地址:

const releasedVesting = await vestingInstance.released(ioraInstance.address);

2. 模拟vesting时间到期

使用Truffle时间工具快进时间至vesting周期结束,确保可全额释放代币:

const { time } = require("@openzeppelin/test-helpers");

it("total released should be the same as we transfered", async function () {
  const amount = 3000;
  const vestingInstance = await VestingContract.deployed();
  const ioraInstance = await IoraContract.deployed();
  
  // 获取vesting结束时间
  const start = await vestingInstance.start();
  const duration = await vestingInstance.duration();
  const endTime = start.add(duration);
  
  await ioraInstance.transfer(vestingInstance.address, amount);
  // 快进时间至vesting结束
  await time.increaseTo(endTime);
  
  await vestingInstance.release(ioraInstance.address);
  const releasedVesting = await vestingInstance.released(ioraInstance.address);

  return assert.isTrue(amount === releasedVesting.toNumber())
});

3. 确保测试环境正常

  • 检查Ganache是否正常运行,端口与truffle-config.js配置一致;
  • 升级Truffle和Ganache至兼容版本(推荐Truffle v5.x + Ganache v7.x);
  • 每个测试用例使用全新合约实例,避免状态污染:
const vestingInstance = await VestingContract.new(accounts[0], Math.floor(Date.now()/1000), 3600);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 00:43:27