Search code examples
node.jsethereumsolidityweb3js

Error when calling contract method and signing it manually. SendTransaction works SendRawTransaction doesn't


I'm writing a node API to expose methods on my blockchain (deployed and tested with truffle). I'm using web3.js, ethereumjs-tx, ethereum, truffle and solidity as my tech stack.

var txMethodData = masterKeyContract.myMethod.getData(myParams);

The transaction params are:

 const txParams = {
    nonce: web3.toHex(web3.eth.getTransactionCount(web3.eth.coinbase)),
    gasPrice: web3.toHex(web3.eth.gasPrice),
    gasLimit: web3.toHex(2000000),
    from: mainAccount,
    value: '0x00',
    to: targetContract.address,
    data: txMethodData,
    chainId: 3
};

im using ethereumjs-tx

const EthereumTx = require('ethereumjs-tx');

Signing the transaction with the private key linked to my mainAccount

const tx = new EthereumTx(txParams);
tx.sign(privateKey);
const serializedTx = tx.serialize();
web3.eth.sendRawTransaction("0x" + serializedTx.toString('hex'), function (err1, resp1) {
    if (err1) {
        console.log(err1);
    } else {
        console.log(resp1);
    }
});

And i get the error insufficient funds for gas * price + value. Im sending this transaction from the mainAccount (the from: field from txParams). So i logged the balance on my mainAccount

    web3.eth.getBalance(mainAccount, function (error, result) {
    if (!error) {
        console.log(web3.fromWei(result.toNumber(), "ether"));
    } else {
        console.error(error);
    }
});

And the result was 252.12609391539726. So it cant be without funds. I even estimated the web3.eth.estimateGas(txParams) transaction and it gave me 97899. The gas limit on the current ropstein block is 4,707,806. So i should have enough. So the question remains why im getting insufficient funds.

The only reason i suspect is that the from: field, which is my mainAccount is not actually the payer of the transaction.

UPDATE: The problem might be with the signing because I just tested with

    web3.eth.sendTransaction(txParams, function (err1, resp1) {
    if (err1) {
        console.log(err1);
    } else {
        console.log(resp1);
    }
});

And it worked so the question is actually why sendRawTransaction doesn't work. Might it be related to the way I sign the transaction?

I checked that the

const privateKey = Buffer.from('[private_key_inserted_here]', 'hex');

Is actually related to my mainAccount. The private_key_inserted_here is taken from the keystore related to my main account from the "ciphertext" field. And I checked that is related to my mainAccount by matching the "address" field of the keystore.


Solution

  • Some things I can see

    • It's gas and not gasLimit
    • chainId is not needed
    • You should really manage the nonce on your own instead of relying the node to send you the correct nonce. In other words, don't query it from the node but keep a variable around

    If you want you can look at a minimalist wallet signer class I wrote https://gist.github.com/gaiazov/e65a3e36c67eaf46fe81982cd193316d