Smart Contract Cost – How to estimate the cost to call a Smart Contract method

abiblockchaincontract-developmentcontract-invocationgas-estimate

After succesfully deployed this Smart Contract on Ethereum testnet

https://testnet.etherscan.io/address/0x27c042342C9ba937214117e11A4970A6145034cB

is it possible to calculate how much gas is going to take to invoke a given method of the Smart Contract?

Reading How to estimate gas for a function without any input parameter? and How much does it cost to use a contract? and What are the limitations to estimateGas and when would its estimate be considerably wrong? didn't help me as expected…

This is how to instantiate the Smart Contract on geth console command line:

// creation of contract object
var aContract = web3.eth.contract([ { "constant": true, "inputs": [], "name": "queryNumEscrows", "outputs": [ { "name": "", "type": "uint256", "value": "0" } ], "type": "function" }, { "constant": true, "inputs": [ { "name": "escrowId", "type": "uint256" } ], "name": "queryStatus", "outputs": [ { "name": "status", "type": "uint256", "value": "0" } ], "type": "function" }, { "constant": false, "inputs": [ { "name": "seller", "type": "address" }, { "name": "thirdParty", "type": "address" } ], "name": "start1", "outputs": [ { "name": "escrowId", "type": "uint256" } ], "type": "function" }, { "constant": false, "inputs": [ { "name": "escrowId", "type": "uint256" } ], "name": "revoke", "outputs": [ { "name": "amount", "type": "uint256" } ], "type": "function" }, { "constant": false, "inputs": [ { "name": "escrowId", "type": "uint256" } ], "name": "release", "outputs": [ { "name": "amount", "type": "uint256" } ], "type": "function" }, { "constant": false, "inputs": [ { "name": "seller", "type": "address" }, { "name": "thirdParty", "type": "address" } ], "name": "start", "outputs": [ { "name": "", "type": "uint256" } ], "type": "function" }, { "constant": false, "inputs": [], "name": "kill", "outputs": [], "type": "function" } ]);

// initiate contract for an address
var sc = aContract.at('0x27c042342C9ba937214117e11A4970A6145034cB');

// view code
eth.getCode(sc.address);

Now, I want to send this transaction to the Smart Contract, but I would like to previously know how much gas is it going to take:

sc.start.sendTransaction("0x90e8682b63d7922a3e942d4bbd4c88095634a17b", "0x47978a69f410d0f61850c92acdb0d4c464d70937", {from:"0x3b877e80b5c0b29d88f3768ed4292b35fdd93a9d", value:"0x3b9aca00"});

to avoid this message:

"Warning! Error encountered during contract execution [Out of gas]".

I guess the following json-rpc method should be used:

https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_estimategas

I have read at docs that:

When calling SCs => data: DATA - (optional) Hash of the method signature and encoded parameters.

But don't get how to encode method name, parameters and ABI in data field. Any idea?

Or is there any other way round to tackle this issue?

Thx.

Best Answer

The documentation is skimpy on details and it took me forever to figure out the correct way with the help of your links, anyways, here is what works for me:

Tested on Geth : 1.6.7 -stable , web3.js :0.20.2 Parity/v1.7.2 & Kovan testnet.

I'll be using the minimal token as example :

pragma solidity ^0.4.0;

contract minimalToken {

     mapping (address => uint256) public balanceOf;

    function minimalToken(uint256 initialSupply) {
        balanceOf[msg.sender] = initialSupply;
    }

    function transfer(address _to, uint256 _value) {
        require(balanceOf[msg.sender] >= _value);
        require(balanceOf[_to] + _value >= balanceOf[_to]);
        balanceOf[msg.sender] -= _value;
        balanceOf[_to] += _value;
    }
}

I'll be focusing on the transfer method which takes 2 arguments,( address, amount) to transfer:

    var contract = web3.eth.contract(contractABI).at("0x8caaa1f263ff14d0276ff1a1a6ed15c51159d6e0");
    var receiverAddress = '0x00Ce6C92856A657979E7728005DBc9acD002Eb09';
    var callData = contract.transfer.getData(receiverAddress, 2000);

    var gasEstimate = web3.eth.estimateGas({
        from: web3.eth.coinbase,
        to: "0x8caaa1f263ff14d0276ff1a1a6ed15c51159d6e0",
        data: callData
    });

    var gasPrice = web3.eth.gasPrice;

    console.log('gas Price: ' + gasPrice);
    console.log('Estimated Transaction gas: ' + gasEstimate);

// gas Price: 21000000000
// Estimated Transaction gas: 34207

One thing that Threw me off, was that I kept on getting transaction errors due to me not including the from: field on the transaction.

Hope this helps.