使用Hardhat+Chai测试Solidity众筹合约提款功能时余额断言失败
众筹Solidity合约测试用例问题
我编写了一个众筹Solidity合约,在最后一个测试用例中遇到问题:
it("should allow the owner of the campaign to withdraw funds if the campaign is successful", async () => { const target = ethers.utils.parseEther("1"); await contract .connect(aliceAccount) .createCampaign( "Test Campaign", "Test Description", target, "testimage.jpg" ); await contract .connect(bobAccount) .donateToCampaign(0, { value: ethers.utils.parseEther("1") }); const campaign = await contract.campaigns(0); const ownerInitialBalance = await aliceAccount.getBalance(); const tx = await contract.connect(aliceAccount).withdrawFunds(0); const receipt = await tx.wait() const ownerFinalBalance = await aliceAccount.getBalance(); const result = ownerInitialBalance.add(target).sub(receipt.gasUsed) expect(campaign.status).to.equal(2); expect(ownerFinalBalance).to.equal(result); });
控制台输出错误:
AssertionError: expected 10000997823969736606208 to equal 10000997858212031010378. The numerical values of the given "ethers.BigNumber" and "ethers.BigNumber" inputs were compared, and they differed. + expected - actual -10000997823969736606208 +10000997858212031010378
问题原因
你对gas消耗的计算逻辑错误:receipt.gasUsed只是交易消耗的gas数量,但账户实际被扣的是gas数量 × gas单价(即gasUsed × effectiveGasPrice),你只减去了gas数量,没有乘以单价,导致计算出的预期余额和实际余额出现差值。
另外还有个逻辑瑕疵:你在执行提现交易前就获取了campaign的状态,此时拿到的是交易前的旧状态,虽然这个测试里status的断言可能碰巧通过,但不符合测试逻辑,应该在交易完成后再获取最新状态。
修正方案
- 修正gas消耗的计算方式:
// 计算实际消耗的gas费用:gas数量 × 实际gas单价 const gasCost = receipt.gasUsed.mul(receipt.effectiveGasPrice); const result = ownerInitialBalance.add(target).sub(gasCost);
- 调整
campaign状态的获取时机:
// 先执行提现交易并等待确认 const tx = await contract.connect(aliceAccount).withdrawFunds(0); const receipt = await tx.wait() // 再获取最新的campaign状态 const campaign = await contract.campaigns(0);
修正后的完整测试代码:
it("should allow the owner of the campaign to withdraw funds if the campaign is successful", async () => { const target = ethers.utils.parseEther("1"); await contract .connect(aliceAccount) .createCampaign( "Test Campaign", "Test Description", target, "testimage.jpg" ); await contract .connect(bobAccount) .donateToCampaign(0, { value: ethers.utils.parseEther("1") }); const ownerInitialBalance = await aliceAccount.getBalance(); const tx = await contract.connect(aliceAccount).withdrawFunds(0); const receipt = await tx.wait() // 交易完成后再获取campaign状态 const campaign = await contract.campaigns(0); const ownerFinalBalance = await aliceAccount.getBalance(); // 计算实际gas费用 const gasCost = receipt.gasUsed.mul(receipt.effectiveGasPrice); const result = ownerInitialBalance.add(target).sub(gasCost) expect(campaign.status).to.equal(2); expect(ownerFinalBalance).to.equal(result); });
内容的提问来源于stack exchange,提问作者Fede
相关产品推荐
相关产品推荐

