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

Hardhat测试报错:VM异常因'deposit more'回退问题求助

Hardhat测试中withdrawDeposit触发deposit more报错的解决

报错详情

执行测试时触发以下异常:

Error: VM Exception while processing transaction: reverted with reason string 'deposit more'

该报错来自合约withdrawDeposit函数的校验逻辑:

require(tasks[taskId].deposit > 0, "deposit more");

核心问题是目标任务的deposit字段值为0,不满足提现前置条件。

测试代码

it("should be able to withdraw if no one apply", async function() {
    const salary = "10" + "000000000000000000";
    const jobDesc = "https://example.com";
    const startBalance = await addrs[0].getBalance();
    const duration = 30 * 86400;
    
    await tasksV1.connect(addrs[0])
    .createTask(duration, jobDesc, { value: salary });
    const taskId = 3;
    
    await tasksV1.connect(addrs[0]).cancelTask(taskId);
    await tasksV1.connect(addrs[0]).withdrawDeposit(taskId);
    const newBalance = await addrs[0].getBalance();
    
    expect(startBalance.sub(newBalance).div("1000000000000000000")).equal(0);
});

对应合约函数

function withdrawDeposit(uint256 taskId) external {
    require(tasks[taskId].creator == msg.sender, "Not creator");
    require(tasks[taskId].deposit > 0, "deposit more");
    require(
    tasks[taskId].status == TaskStatus.failed
    ||
    (tasks[taskId].status == TaskStatus.cancelled && applicants[taskId].length == 0)
    ||
    (tasks[taskId].status == TaskStatus.cancelled && block.timestamp > tasks[taskId].createdTime + unlockTime)
    , "Cannot withdraw");
    
    uint256 valueToWithdraw = tasks[taskId].deposit;
    tasks[taskId].deposit = 0;
    payable(msg.sender).transfer(valueToWithdraw);
    
    emit TaskUpdate(taskId, msg.sender, TaskActions.withdraw);
}

排查与解决步骤

1. 检查createTask的deposit赋值逻辑

报错本质是任务的deposit未被正确初始化。需要确认合约中createTask函数是否将调用时传入的msg.value赋值给tasks[taskId].deposit:

  • 如果createTask把msg.value存入了其他字段(比如salary)而非deposit,则deposit始终为0,触发校验失败。
  • 修正createTask逻辑,确保tasks[newTaskId].deposit = msg.value;(根据实际业务逻辑调整,比如是否是部分金额作为押金)。

2. 修正taskId的获取方式

测试中硬编码taskId = 3极易出错,因为任务ID的生成依赖于合约内的计数器,且其他测试用例会影响计数。正确做法是从合约事件或返回值获取真实ID:

// 调用createTask并等待交易回执
const tx = await tasksV1.connect(addrs[0]).createTask(duration, jobDesc, { value: salary });
const receipt = await tx.wait();
// 从TaskCreated事件中提取taskId(需确保合约触发该事件)
const taskId = receipt.events.find(evt => evt.event === "TaskCreated").args.taskId;

3. 检查cancelTask是否修改了deposit

确认cancelTask函数是否在执行时错误清空了tasks[taskId].deposit。如果cancelTask中有重置deposit的逻辑,会导致后续提现时deposit为0,触发报错。需移除该不合理逻辑,仅保留状态变更等必要操作。

4. 验证任务状态与申请列表

虽然当前测试场景是“无人申请”,但需确保:

  • cancelTask成功将任务状态改为TaskStatus.cancelled
  • applicants[taskId].length确实为0
    这两个条件满足才能通过withdrawDeposit的第二个校验分支,避免因状态不满足导致的其他异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 08:54:51