1

I'm using web3js and web3js-raw as follows to change state of my smart contract on ethereum,

let initiateAddLoyaltyTransaction = function (fromWallet, toWallet, companyName, amount, callback) {
let functionName = 'transferWithAddLoyalty';
amount = web3.utils.toWei(amount.toString(), 'ether');
let params = [fromWallet, toWallet, amount, companyName];
W3JSR.prepareSignSend(config.ethereum[ethereumNetwork].ABI_DEFINITION, config.ethereum[ethereumNetwork].CONTRACT_ADDRESS, functionName,
    config.ethereum[ethereumNetwork].WALLET_ADDRESS, privateKey, params, 10000000000).then((result, error) => {
    callback(result, error);
});

};

It works fine when I call this function and wait for the transaction to mined by miners. But the problem is when I send another transaction before first one completes( because my use case needs to do several transactions in a short period of time) it gives an error saying

message: Error: Returned error: known transaction: 5abe27f97e23fb660b514c87c4d7db150dbd23bcf54632eef09fad6ec64427fe

I can see that the nonce is same for both transactions. Could someone please explain me how to deal with nonce while using Infura. Do I need to maintain nonce localy? And how to retry if one transaction fails

1

Indeed, your issue is that all the transactions are sent with the same nonce.

Unfortunately the prepareSignSend function doesn't give you the possibility to overwrite the nonce.

Fortunately, you have options:

  • start using the underlying ethereumjs-tx directly - you'll have to rewrite some parts of your codebase, but you'll get full flexibility
  • make your local copy of web3js-raw, rewrite the prepareSignSend(...) to accept nonce as an optional last parameter and if set, use it instead of the auto-filled one. The new function could look like this:

    this.prepareSignSend = async function(abi,contractAddress,functionName,senderAddress,privateKey, params, gasLimit, customNonce){
        try{
            var txnData = this.encodeFunctionParams(abi, functionName,  params);
            var _gasLimit = await this.ContractInstance.methods[functionName](...params).estimateGas({'from': senderAddress, 'gas': gasLimit});
            var txnRawData = await this.getDefaultTxnAttributes('',senderAddress,contractAddress,'0',txnData,_gasLimit,'')
    
            if ( typeof customNonce !== 'undefined')
                txnRawData.nonce = customNonce;
    
        if (txnRawData) {
            var dataToSend = this.getSignedTransaction(txnRawData, privateKey);
            var txHash = await web3.eth.sendSignedTransaction(dataToSend);
            return Promise.resolve({"status":1,"functionName":functionName,"message":txHash});
        }
        else{
            return Promise.reject({"status":0,"functionName":functionName,"message":"Error in setting Default Txn Attributes"});
        }
    }
    catch (err){
        return Promise.reject({"status":0,"functionName":functionName,"message":err});
      }
    }
    
  • Thank you for the answer, let's say I go with the first option you mentioned. Then how can I make sure nonce that I generate doesn't collide with pending transactions that I have already submitted and not mined yet. – Channa Nov 13 '18 at 8:31
  • You get the nonce for the first transaction from the batch, then increment it by 1 for each subsequent transaction. The blockchain itself will only accept transactions one at a time consecutively, based on the nonce, so no need to worry for gaps in nonce numbers. If you have a transaction that doesn't goes through (too small gasPrice might be a reason), you simply rebuild it with the same nonce and a higher fee and resubmit it. – Tudor Constantin Nov 13 '18 at 8:37

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.