3

Below is from a truffle test cases in javascript, where I was trying to add the gas cost to an account balance to confirm the sum of transaction, where the sum should be equal to the previous balance.

But I couldn't get it to work!

The rcpt.cumulativeGasUsed, web3.eth.gasPrice, getBalance(accounts[1]) are all correct, but the arithmetic is not, some fromWei, toWei kung-fu needed?

What am I doing wrong here?

            return instance.bailOut({ from: accounts[1] }).then(function (resp) {
            var rcpt = web3.eth.getTransactionReceipt(resp.tx);
            console.log("Sum: " + ((rcpt.cumulativeGasUsed * web3.eth.gasPrice) + web3.eth.getBalance(accounts[1]).toString(10)));

});

After a lot of experiments, it looks like the below method works fine, but couldn't explain the logic of transaction cost! Any idea is most welcome.

Anyways unit test is passing now!!!

return contractInstance.withdraw({ value: web3.toWei(1, "ether"), gas: 1000000 }).then(function () {
          var contractAddressBalance = web3.fromWei(web3.eth.getBalance(contractAddress).toString(10));
          console.log("contractAddress balance after withdraw: " + contractAddressBalance);
          return contractInstance.bailOut({ from: accounts[1] }).then(function (resp) {
            var rcpt = web3.eth.getTransactionReceipt(resp.tx);

            console.log("cumulativeGasUsed: " + rcpt.cumulativeGasUsed);
            console.log("gasPrice: " + web3.eth.gasPrice);

            var transactionCost = (rcpt.cumulativeGasUsed / 10000000); // How come this works???

            console.log("transactionCost: " + transactionCost);
            console.log("Account[1] balance after withdraw: " + web3.eth.getBalance(accounts[1]));

            contractWalletAfter = web3.fromWei(web3.eth.getBalance(accounts[1]).add(web3.fromWei(rcpt.cumulativeGasUsed)));
            assert.equal(((contractWalletAfter.minus(contractWalletBefore)).add(transactionCost)).valueOf(), 6, "6 wasn't in the contract wallet");
          });
        });
  • The correct formula for the ether paid by a transaction should be gasUsed * gasPrice + value. If the contracts make a transfer to the sender that will change the final balance. – Ismael Mar 7 '18 at 6:20
  • yup, that is what my understanding also. You can see that in my original question, where I did rcpt.cumulativeGasUsed * web3.eth.gasPrice to get the transaction cost. But it didn't work! If you have a console open, you can quickly verify the same with the Metacoin in a truffle test case. Looks like some truffle test magic??? – Jimson Kannanthara James Mar 8 '18 at 22:08
2

Note: This answer is only valid for Truffle v4.


I've tried this test with the MetaCoin example from truffle (ie run truffle unbox metacoin in an empty directory)

var MetaCoin = artifacts.require("./MetaCoin.sol");

contract('MetaCoin', function(accounts) {
  it("Test gas", async () => {
    const meta = await MetaCoin.deployed();

    // Initial balance of the second account
    const initial = await web3.eth.getBalance(accounts[1]);
    console.log(`Initial: ${initial.toString()}`);

    // Obtain gas used from the receipt
    const receipt = await meta.sendCoin(accounts[2], 1, { from: accounts[1] });
    const gasUsed = receipt.receipt.gasUsed;
    console.log(`GasUsed: ${receipt.receipt.gasUsed}`);

    // Obtain gasPrice from the transaction
    const tx = await web3.eth.getTransaction(receipt.tx);
    const gasPrice = tx.gasPrice;
    console.log(`GasPrice: ${tx.gasPrice}`);

    // Final balance
    const final = await web3.eth.getBalance(accounts[1]);
    console.log(`Final: ${final.toString()}`);
    assert.equal(final.add(gasPrice.mul(gasUsed)).toString(), initial.toString(), "Must be equal");
  });
});

The correspoding output is:

  Contract: MetaCoin
Initial: 99971803600000000000
GasUsed: 23497
GasPrice: 100000000000
Final: 99969453900000000000
    ✓ Test gas (199ms)

  1 passing (217ms)

One difference is that I'm reading the gasPrice from the transaction (getTransaction(hash).gasPrice) instead of the network eth.gasPrice().

  • ok, that explains, getTransaction(hash).gasPrice is 100000000000 and eth.gasPrice() is 20000000000 in my tests. – Jimson Kannanthara James Mar 9 '18 at 5:31
  • For me tx.gasPrice is not BN (string), tx.gasPrice is int -- both require: new BN( n ); – The Burger King Jul 8 at 11:31
  • @TheBurgerKing The answer from last year was for Truffle v4, that uses web3 v0.20 which uses a fork of BigNumber.js. Likely you are using the new Truffle v5, which uses web3 v1.0 which uses BN.js in turn. I'd suggest to create a new answer with the solution for Truffle v5. I'd edit my answer to indicate it was tested with Truffle v4. – Ismael Jul 8 at 15:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.