Hardhat测试Solidity转账时余额差额过大,手续费计算疑问
问题:Solidity转账测试中账户余额差额远大于转账金额的原因
我编写了如下Solidity转账方法:
function testTransfer() public payable { payable(owner()).transfer(msg.value); }
使用Hardhat对该方法进行单元测试,测试代码如下:
const balanceBefore = await ethers.provider.getBalance(address); console.log('balanceBefore', balanceBefore.toString()); await contract.testTransfer({value: 100}); const balanceAfter = await ethers.provider.getBalance(address); console.log('balanceAfter', balanceAfter.toString()); console.log('different:', parseFloat(balanceBefore.toString()) - parseFloat(balanceAfter.toString()));
测试输出为:
balanceBefore 10000000000000000000000 balanceAfter 9999999941570704178388 different: 58429295034368
可见,Solidity中的testTransfer仅向合约所有者转账100 wei,但执行该方法前后的账户余额差额为58429295034368 wei,远大于100 wei。请问这是Hardhat存在问题吗?
解答
这不是Hardhat的问题,余额差额偏大的核心原因是你计算的是发起交易账户的总支出,包含了转账金额+交易Gas费:
- 调用
contract.testTransfer({value: 100})时,发起交易的账户(即代码中address对应的账户)会先把100wei转入合约,随后合约再将这100wei转给owner。但发起交易的账户还要为这笔交易支付Gas费——Gas费是以太坊网络(包括Hardhat本地模拟链)中执行交易的手续费,由交易发起方承担,直接从发起账户余额中扣除。 - 你当前计算的
balanceBefore - balanceAfter,是发起账户的总支出:转给合约的100wei + 交易消耗的Gas费,所以数值远大于100wei。
验证方式
你可以修改测试代码,获取交易的Gas消耗详情,核对总支出:
const balanceBefore = await ethers.provider.getBalance(address); console.log('balanceBefore', balanceBefore.toString()); // 发起交易并获取回执 const tx = await contract.testTransfer({value: 100}); const receipt = await tx.wait(); // 计算实际Gas费 const gasCost = receipt.gasUsed.mul(receipt.effectiveGasPrice); console.log('Gas费:', gasCost.toString()); console.log('转账金额+Gas费:', gasCost.add(100).toString()); const balanceAfter = await ethers.provider.getBalance(address); console.log('balanceAfter', balanceAfter.toString()); console.log('different:', balanceBefore.sub(balanceAfter).toString());
运行后会发现,gasCost.add(100)的结果和余额差额完全一致。
内容的提问来源于stack exchange,提问作者Joey Yi Zhao
相关产品推荐
相关产品推荐

