I'm writing a Smart Contract that individuals can donate to, and a specific address can withdraw all ether from the contract. I'm trying to write a test that validates that the withdrawer receives all money stored in the contract, but my asserts are failing when checking the expected final balance. I'm trying to adjust for gas used on all transactions. The actual is always slight less than the expected so I'm assuming I'm missing some gas cost somewhere. I'm using hardhat for testing.
contract:
pragma solidity ^0.8.0;
// A donation campaign being run
contract Campaign {
// the owner of the contract
address payable public immutable owner;
// the person running the donation campaign
// this person may also be the beneficiary
address payable public immutable runner;
// the beneficiary of the campaign
// this person may also be the campaign runner
address payable public immutable beneficiary;
// initializes owner, the runner of the campaign, and the contract beneficiary.
// beneficiary and runner may have the same value
constructor(address payable _runner, address payable _beneficiary) {
owner = payable(msg.sender);
runner = _runner;
beneficiary = _beneficiary;
}
// accepts donation payment
function donate() public payable {
// nothing to do here... yet...
}
// allows either the owner or the beneficiary to withdraw the donations
function withdraw() public {
require(msg.sender == beneficiary || msg.sender == owner, "only beneficiary or owner can withdraw");
payable(msg.sender).transfer(address(this).balance);
}
}
test function:
async function assertWithdrawSucceeds(donator, withdrawer) {
amount = ethers.utils.parseEther("2");
// load contract with money
txResp = await deployedCampaign.connect(donator).donate({value: amount});
txReceipt = await txResp.wait();
actuallyDonated = amount.sub(txReceipt.gasUsed);
// store original balance
originalWithdrawerBalance = await ethers.provider.getBalance(withdrawer.address);
// withdraw
txResp = await deployedCampaign.connect(withdrawer).withdraw();
txReceipt = await txResp.wait();
withdrawGas = ethers.BigNumber.from(txReceipt.gasUsed);
// balances to check
contractBalance = await ethers.provider.getBalance(deployedCampaign.address);
withdrawerFinalBalance = await ethers.provider.getBalance(withdrawer.address);
// asserts
expect(contractBalance).to.equal(0);
console.log("original withdraw balance: " + originalWithdrawerBalance);
console.log("final withdraw balance: " + withdrawerFinalBalance);
console.log("calculated final withdraw balance: " + originalWithdrawerBalance.add(actuallyDonated).sub(withdrawGas));
expect(
originalWithdrawerBalance.add(actuallyDonated).sub(withdrawGas)
.eq(withdrawerFinalBalance)
).is.true();
}
hardhat.config.js
require("@nomiclabs/hardhat-waffle");
/**
* @type import('hardhat/config').HardhatUserConfig
*/
module.exports = {
solidity: "0.8.0",
networks: {
hardhat: {
accounts: {
accountsBalance: '10500000000000000000' // 10.5 ether
}
}
}
};
Best Answer
receipt.gasUsed
returns, as the name says, the used gas, not the Ether spent to consume that gas. If you think about it, what you are doing is wrong from a dimensional point of view: you are subtractingoriginalWithdrawerBalance
(Ether) andgasUsed
(a pure number).To get the spent Ether you must multiply the
gasUsed
by the gas price of your transaction.