9

I have a function that iterate through an array, which could cost a lot of gas. But I still want to test out the estimate gas cost, then decide if I should maintain the design or not.

function giveAwayDividend(uint amount) onlyOwner payable {
for(uint i=0;i<size();i++){
    customerAddress[i].call.value((balances[customerAddress[i]] * amount * 100) / totalSupply)();
}}

If I test out on testnet, I have to manually create over 1 thousand user account and send each of them some token, which seems stupid. Is there a better way to calculate the gas cost? For example, if the cost is linear, I could calculate the cost for one customer then multiple by the number of customers. Question is, I dont think its linear, can someone shed some light on this?

19

Using Truffle and testrpc. It's actually pretty easy to build a development environment and test different use cases.

For the gas estimation, it's mostly based on Web3 native functions:

  1. You can retrieve the gas price (in wei) using web3.eth.getGasPrice

  2. The function estimateGas will give the gas estimation for a function (with the parameters passed)

  3. Multiply number of gas by gas price to get the gas cost estimation.

For example

var TestContract = artifacts.require("./Test.sol");

// Run unit tests to populate my contract
// ...
// ...

// getGasPrice returns the gas price on the current network
TestContract.web3.eth.getGasPrice(function(error, result){ 
    var gasPrice = Number(result);
    console.log("Gas Price is " + gasPrice + " wei"); // "10000000000000"

    // Get Contract instance
    TestContract.deployed().then(function(instance) {

        // Use the keyword 'estimateGas' after the function name to get the gas estimation for this particular function 
        return instance.giveAwayDividend.estimateGas(1);

    }).then(function(result) {
        var gas = Number(result);

        console.log("gas estimation = " + gas + " units");
        console.log("gas cost estimation = " + (gas * gasPrice) + " wei");
        console.log("gas cost estimation = " + TestContract.web3.fromWei((gas * gasPrice), 'ether') + " ether");
    });
});

Result in my case (private network):

> truffle test
Using network 'test'.

Compiling .\contracts\Migrations.sol...
Compiling .\contracts\Test.sol...

Gas Price is 20000000000 wei
gas estimation = 26794 units
gas cost estimation = 535880000000000 wei
gas cost estimation = 0.00053588 ether
  • Or web3.eth.gasPrice instead of web3.eth.getGasPrice – Jose Alban Oct 29 '17 at 19:10
  • How do we do an actual transaction with the gas? – Shamoon Jun 29 '18 at 2:22
7

The answer provided by Greg Jeanmart perfectly explained how to estimate the gas cost for a function. Here I want to point out that the design of your function giveAwayDividend() might be vulnerable to attack.

Since each of the for loop is paying ether to a user, and it only executes the next loop after this payment is successfully sent, it could be the case where the user at customerAddress[0] refuse the payment (they can do it by having a contract whose fallback function deliberately fails), then your function giveAwayDividend() would then also fail each time, and thus become uncallable.

A better approach could be having users to call a withdraw() function, so the fund only goes to their address when the users request it. This way attackers can only make the function invalid for their account and won't affect anyone else.

  • I have also thought about your solution, it is an technically ideal solution but the situation is: I want to give away dividend automatically so that my users won't have to call withdraw() themselves since most of them are investors that don't even know anything about smart contract. – Zixuan Zhang Feb 5 '18 at 14:22

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.