4

I am trying to figure out how to send a transaction to a contract method, retrieve the transaction hash automatically, and then get a receipt callback after the transaction is mined.

I am able to do one or the other but seemingly not both. Any suggestions?

Contract.deployed().then(function(instance) {
    instance.methodName(parameter, {from: this.account, value: price})
        .then(function(receipt) {
          //THIS FIRES AFTER THE TRANSACTION IS MINED, 
          //BUT I CANT GET THE TX HASH ANY SOONER
        });
});


Contract.deployed().then(function(instance) {
    instance.methodName.sendTransaction(parameter, {from: this.account, value: price})
        .then(function(hash) {
            //THIS FIRES BEFORE THE TRANSACTION IS MINED, 
            //BUT I NOW DON'T HAVE A WAY TO GET A MINED RECEIPT
        });
});
  • What version of web3.js? And is this actually truffle? – smarx Jan 19 '18 at 4:46
  • This is version 0.16.0 of web3.js and yes, this is a truffle project. – skajake Jan 19 '18 at 4:52
  • To my knowledge, instance.methodName() and instance.methodName.sendTransaction() should perform identically in web3.js 0.2x.x, but I'm not sure about older versions, and I believe that pre-1.0.0 versions of web3.js don't support promises, so I believe you're dealing with some truffle magic instead. (Sorry, but I'm unfamiliar with truffle.) – smarx Jan 19 '18 at 4:53
8

I'm unfamiliar with truffle, so I can't comment on whether there's a better way, but once you have a transaction receipt, you can poll using a transaction receipt like so (code taken from https://programtheblockchain.com/posts/2017/12/13/building-decentralized-apps-with-ethereum-and-javascript/):

function waitForReceipt(hash, cb) {
  web3.eth.getTransactionReceipt(hash, function (err, receipt) {
    if (err) {
      error(err);
    }

    if (receipt !== null) {
      // Transaction went through
      if (cb) {
        cb(receipt);
      }
    } else {
      // Try again in 1 second
      window.setTimeout(function () {
        waitForReceipt(hash, cb);
      }, 1000);
    }
  });
}

In your case, this would be:

instance.methodName.sendTransaction(parameter, {from: this.account, value: price}).then(function(hash) {
  waitForRecepit(hash, function (receipt) {
    ...
  });
});
  • Noob question - but what is 'cb' - is this the coinbase transaction? and if so, is their documentation on how to use it - because i see it used in a lot of different ways – Robert Tomas G IV May 17 '18 at 6:55
  • 2
    It's a "callback": in this case, the function that's called when the transaction is mined. – smarx May 17 '18 at 12:00
2

I see this is the version of web3 that does not use async await but I think timeouts are not the recommended way anymore, because as shown above you need to set timeouts and nest the callbacks, which may lead to 'callback hell'.

If you're using web3 1.0 and above, I think using async await will help to simplify the code. Here's an example from a submit form in React (this.setState is for storing values, you can save them to an object if not using React):

onSubmit = async (event) => {
  event.preventDefault();
  try {
    // start mining the transaction
    await instance.methodName.sendTransaction(parameter, 
      {from: this.account, value: price}, 
      (err, txHash) => this.setState({isMining: true, txHash}
    );

    // mining is finished, display the gas used for the transaction
    await web3.eth.getTransactionReceipt(this.state.txHash, 
      (err, txReceipt) => this.setState({ 
         blockNumber: txReceipt.blockNumber,
         gasUsed: txReceipt.gasUsed, 
         isMining: false
      })
    );
  } catch(err) {
    console.log(err)
  }
}

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.