1

I have a simple contract transaction that creates another contract. This transaction when called from Node.js using Web3 and truffle-contract throws a revert.

ContractFactory.deployed().then(function(instance) {
    return instance.createStore({from: accounts[0]}); 
});

Result:

2018-05-14T07:34:58.260Z develop:testrpc   Transaction: 0xc93859052bea36bd76c80ab21d30c90a3002303ec7eb1e3ea6d08cd002990d74
2018-05-14T07:34:58.261Z develop:testrpc   Gas usage: 89462
2018-05-14T07:34:58.261Z develop:testrpc   Block Number: 39
2018-05-14T07:34:58.261Z develop:testrpc   Block Time: Mon May 14 2018 13:04:58 GMT+0530 (India Standard Time)
2018-05-14T07:34:58.261Z develop:testrpc   Runtime Error: revert

When I call the same transaction from truffle console or truffle develop the transaction succeeds.

truffle (develop) > ContractFactory.deployed().then(function (instance) { return instance.createStore() });

Result:

2018-05-14T07:30:33.789Z develop:testrpc   Transaction: 0xbdc51bb74de2b59e98ad1b8f38ed4367c2d975a77340d778e44ee2ced969e5b9
2018-05-14T07:30:33.789Z develop:testrpc   Gas usage: 135843
2018-05-14T07:30:33.789Z develop:testrpc   Block Number: 38
2018-05-14T07:30:33.789Z develop:testrpc   Block Time: Mon May 14 2018 13:00:33 GMT+0530 (India Standard Time)
2018-05-14T07:30:33.789Z develop:testrpc
2018-05-14T07:30:33.791Z develop:testrpc eth_getTransactionReceipt

I've been trying to get truffle debug to work but it fails to debug transactions that create another contract.

My initial guess was that my Web3 transaction is running out of set gas limit, but would that throw a revert? I've tried setting gas limit to a very high value but with no better results.

ContractFactory.defaults({
  gasLimit: "100000000000000000"
});

Contract Code:

pragma solidity ^0.4.16;

contract SimpleStore {
    uint public value;
    function SimpleStore (uint num) public {
        value = num;
    }

    function setValue (uint num) public {
        value = num;
    }
}

contract ContractFactory {

    address public store;

    function ContractFactory () public {

    }

    function createStore () public {
        store = new SimpleStore(12);
    }
}

Note: Other transactions and calls work very well with the Web3 setup. This problem is common for all transactions that create a contract.

3
  • Did you try it in any other network that testrpc? try rinkeby and then post txhash for people to check.
    – Rajesh
    Commented May 18, 2018 at 13:06
  • can you post your NodeJS file?
    – qbsp
    Commented May 18, 2018 at 15:06
  • I'll to make this transaction on a testnet and provide a hash today, I'll also post the Contract JSON. Commented May 20, 2018 at 9:58

3 Answers 3

1

I am able to reproduce issue that you were facing. I did following to solve this issue. Created two separate contract files inside contracts folder for SimpleStore and ContrctFactory as following :- SimpleStore.sol file -

pragma solidity ^0.4.16;

contract SimpleStore {
    uint public value;
    function SimpleStore (uint num) public {
        value = num;
    }

    function setValue (uint num) public {
        value = num;
    }
}

ContractFactory.sol file -

pragma solidity ^0.4.16;

contract SimpleStore {
    uint public value;
    function SimpleStore (uint num) public {
        value = num;
    }

    function setValue (uint num) public {
        value = num;
    }
}
contract ContractFactory {

    address public store;

    function ContractFactory () public {

    }

    function createStore () public {
        store = new SimpleStore(12);
    }
}

2_deploy_contracts.js file -

var SimpleStore = artifacts.require("./SimpleStore.sol");
var ContractFactory = artifacts.require("./ContractFactory.sol");
module.exports = function(deployer) {
  deployer.deploy(SimpleStore,10, {gas: 6700000});
  deployer.deploy(ContractFactory,{gas: 6700000});
};

app.js file -

import { default as Web3} from 'web3';
import { default as contract } from 'truffle-contract'
import SimpleStore_artifacts from '../../build/contracts/SimpleStore.json'
import ContractFactory_artifacts from '../../build/contracts/ContractFactory.json'

var SimpleStore = contract(SimpleStore_artifacts);
var ContractFactory = contract(ContractFactory_artifacts);
$( document ).ready(function() {
  if (typeof web3 !== 'undefined') {
    console.warn("Using web3 detected from external source like Metamask")
    // Use Mist/MetaMask's provider
    window.web3 = new Web3(web3.currentProvider);
  } else {
    console.warn("No web3 detected. Falling back to http://localhost:8545. You should remove this fallback when you deploy live, as it's inherently insecure. Consider switching to Metamask for development. More info here: http://truffleframework.com/tutorials/truffle-and-metamask");
    // fallback - use your fallback strategy (local node / hosted node + in-dapp id mgmt / fail)
    window.web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));

  }
  SimpleStore.setProvider(web3.currentProvider);
  ContractFactory.setProvider(web3.currentProvider);
  ContractFactory.deployed().then(function(instance) {
    return instance.createStore({from: web3.eth.accounts[0],gas: 6700000}); 
    console.log("******");
  });
});

Adding gas cost as an argument has resolved problem of VM exception.

instance.createStore({from: web3.eth.accounts[0],gas: 6700000});

I am also able to execute transaction from truffle console -

truffle(development)> ContractFactory.deployed().then(function (instance) { return instance.createStore({from: web3.eth.accounts[0],gas: 6700000});})
{ tx: '0x4d34e45cddbfa6f087f5dcb02bb5e7dc0fa18a0f7d24e87f8fff8702dd3e53bc',
  receipt: 
   { transactionHash: '0x4d34e45cddbfa6f087f5dcb02bb5e7dc0fa18a0f7d24e87f8fff8702dd3e53bc',
     transactionIndex: 0,
     blockHash: '0xf77b2baa3cacc941a8376376425c642c6db580e4a26918a0905ed589a618bfe7',
     blockNumber: 26,
     gasUsed: 123078,
     cumulativeGasUsed: 123078,
     contractAddress: null,
2
+50

The answer might be a really simple one: The gas amount truffle sends per default on a function call is 90000. You can see your transaction aborting at a consumption aborting close to that value. The transaction succeeds with a higher value though from the truffle console, which uses gas estimation, i think. What you raised was the gasLimit, which != gas.

So it's actually really simple (mirg's solution already has it, it's just not really terse)

ContractFactory.deployed().then(function(instance) {
    return instance.createStore({from: accounts[0], gas:150000}); 
});
2
  • This is it. I worked it out over the last weekend and failed to update here as I have been travelling. I really appreciate your help :) Commented May 25, 2018 at 10:59
  • Another answer came in before yours, but I had already awarded you the bounty, so I'm the other one as a valid answer to be fair. <grin> Commented May 25, 2018 at 11:01
1

Don't know why will is not working with truffle-contract since there's not the entire code, but you can avoid using it and just create your instance using web3.

var Web3 = require('web3');
var web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));

web3.eth.getAccounts(function(error, accounts) {
    var myContract = new web3.eth.Contract([
        {
          "constant": true,
          "inputs": [],
          "name": "store",
          "outputs": [
            {
              "name": "",
              "type": "address"
            }
          ],
          "payable": false,
          "stateMutability": "view",
          "type": "function"
        },
        {
          "inputs": [],
          "payable": false,
          "stateMutability": "nonpayable",
          "type": "constructor"
        },
        {
          "constant": false,
          "inputs": [],
          "name": "createStore",
          "outputs": [],
          "payable": false,
          "stateMutability": "nonpayable",
          "type": "function"
        }
      ]);
    myContract.deploy({
        data: '[bytecode]',
    })
    .send({
        from: accounts[0],
        gas: 1500000,
        gasPrice: '30000000000000'
    }, function(error, transactionHash){ console.log(error, transactionHash); })
    .on('error', console.log)
    .then(function(newContractInstance){
        console.log(newContractInstance.options.address);
        newContractInstance.methods.createStore().send({from: accounts[0], gas: "1500000"}).then(console.log).catch(console.log);
    });
});

just change this line data: '[bytecode]' with the bytecode and it will work.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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