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.cancelledapplicants[taskId].length确实为0
这两个条件满足才能通过withdrawDeposit的第二个校验分支,避免因状态不满足导致的其他异常。
内容的提问来源于stack exchange,提问作者Akash Panda
相关产品推荐
相关产品推荐

