7

I am new to web3. I am trying to connect UI with web3. Metamask version is 6.0.1 and web3 version injected by (don't know who), but it is 0.20.3. Following is my code to send ethers to a function of my contract which is inside using Oracalize as well,

var option = {from: accounts[0], to: contractAddress, value:4000000000000000};
        mycontract.update.sendTransaction(option, function(error,result){});

I want to run some other code on basis of confirmation of this transaction. What is the best way to wait until transaction is confirmed and then I can run some more code? Make sure, I am stuck with this version of web3 and I cannot use 1.0.0 version and so does the "send" function.

2
  • Here is a coding example from the official documentation. Check the one under using the event emitter. It allows you to wait for the hash, then for the receipt, then for each one of 24 confirmation events. Please note that this is relevant for web3.js v1.x, but it should be pretty similar to that of web3.js v0.x. Commented Feb 18, 2019 at 10:42
  • @goodvibration I would prefer using this approach but im stuck with web3.js v0.x. because I have no idea who is injecting this version, do u know how can I use web3.js v1.x, so I can straightaway use the above mentioned method. Thank you Commented Feb 18, 2019 at 13:00

5 Answers 5

7

sendTransaction returns transactionHash in callback. If the transaction was a contract creation use web3.eth.getTransactionReceipt() to get the contract address, after the transaction was mined.

web3.eth.sendTransaction({data: code}, function(err, transactionHash) {
  if (!err)
    console.log(transactionHash);

  var receipt = web3.eth.getTransactionReceipt(transactionHash);
});

In order to wait until transaction is mined, you can use this module:

module.exports = function getTransactionReceiptMined(txHash, interval) {
    const self = this;
    const transactionReceiptAsync = function(resolve, reject) {
        self.getTransactionReceipt(txHash, (error, receipt) => {
            if (error) {
                reject(error);
            } else if (receipt == null) {
                setTimeout(
                    () => transactionReceiptAsync(resolve, reject),
                    interval ? interval : 500);
            } else {
                resolve(receipt);
            }
        });
    };

    if (Array.isArray(txHash)) {
        return Promise.all(txHash.map(
            oneTxHash => self.getTransactionReceiptMined(oneTxHash, interval)));
    } else if (typeof txHash === "string") {
        return new Promise(transactionReceiptAsync);
    } else {
        throw new Error("Invalid Type: " + txHash);
    }
};
2

Here is refined TypeScript code that also

  • Allows you to wait for N confirmations for the transaction to be mined

  • Checks if the transaction, after mined, was successful or not

The code is based on the example and Github MIT sources.

/**
 * Wait transactions to be mined.
 *
 * Based on https://raw.githubusercontent.com/Kaisle/await-transaction-mined/master/index.js
 */

import Web3 from 'web3';

const DEFAULT_INTERVAL = 500;

const DEFAULT_BLOCKS_TO_WAIT = 0;

interface Options {
  interval: number;
  blocksToWait: number;
}

/**
 * Wait for one or multiple transactions to confirm.
 *
 * @param web3
 * @param txnHash A transaction hash or list of those
 * @param options Wait timers
 * @return Transaction receipt
 */
export function waitTransaction(web3: Web3, txnHash: string|string[], options: Options = null): Promise<any> {
    const interval = options && options.interval ? options.interval : DEFAULT_INTERVAL;
    const blocksToWait = options && options.blocksToWait ? options.blocksToWait : DEFAULT_BLOCKS_TO_WAIT;
    var transactionReceiptAsync = async function(txnHash, resolve, reject) {
        try {
            var receipt = web3.eth.getTransactionReceipt(txnHash);
            if (!receipt) {
                setTimeout(function () {
                    transactionReceiptAsync(txnHash, resolve, reject);
                }, interval);
            } else {
              if (blocksToWait > 0) {
                var resolvedReceipt = await receipt;
                if (!resolvedReceipt || !resolvedReceipt.blockNumber) setTimeout(function () { transactionReceiptAsync(txnHash, resolve, reject);
                }, interval);
                else {
                  try {
                  var block = await web3.eth.getBlock(resolvedReceipt.blockNumber)
                  var current = await web3.eth.getBlock('latest');
                  if (current.number - block.number >= blocksToWait) {
                    var txn = await web3.eth.getTransaction(txnHash)
                    if (txn.blockNumber != null) resolve(resolvedReceipt);
                    else reject(new Error('Transaction with hash: ' + txnHash + ' ended up in an uncle block.'));
                  }
                  else setTimeout(function () {
                      transactionReceiptAsync(txnHash, resolve, reject);
                  }, interval);
                  }
                  catch (e) {
                    setTimeout(function () {
                        transactionReceiptAsync(txnHash, resolve, reject);
                    }, interval);
                  }
                }
              }
              else resolve(receipt);
            }
        } catch(e) {
            reject(e);
        }
    };

    // Resolve multiple transactions once
    if (Array.isArray(txnHash)) {
        var promises = [];
        txnHash.forEach(function (oneTxHash) {
            promises.push(waitTransaction(web3, oneTxHash, options));
        });
        return Promise.all(promises);
    } else {
        return new Promise(function (resolve, reject) {
                transactionReceiptAsync(txnHash, resolve, reject);
            });
    }
};


/**
 * Check if the transaction was success based on the receipt.
 *
 * https://ethereum.stackexchange.com/a/45967/620
 *
 * @param receipt Transaction receipt
 */
export function isSuccessfulTransaction(receipt: any): boolean {
  if(receipt.status == '0x1' || receipt.status == 1) {
    return true;
  } else {
    return false;
  }
}
2

If you are waiting for many transaction receipts, then it is more efficient to listen for newBlockHeaders event and search for pending transactions, e.g.

web3.eth.subscribe('newBlockHeaders', async (error, event) => {
  const blockTxHashes = (await web3.eth.getBlock(event.hash)).transactions;

  for (const pendingTxHash of pendingTxHashes) {
    if (blockTxHashes.includes(pendingTxHash)) {
      console.log(await web3.eth.getTransactionReceipt(pendingTxHash));
    }
  }
});
1
  • it doesn't solve problem because i need to wait until pending transaction get mined, but how to wait? whats the best solution? is there any event? Commented Oct 29, 2021 at 22:05
2

Here is an simple way to wait for a tx mined

source: https://docs.alchemy.com/alchemy/guides/eip-1559/send-tx-eip-1559#lets-send-a-transaction

async function sendTx(web3, fields = {}) {
  const signedTx = await signTx(web3, fields);

  web3.eth.sendSignedTransaction(signedTx.rawTransaction, function(error, hash) {
    if (!error) {
      console.log("Transaction sent!", hash);
      const interval = setInterval(function() {
        console.log("Attempting to get transaction receipt...");
        web3.eth.getTransactionReceipt(hash, function(err, rec) {
          if (rec) {
            console.log(rec);
            clearInterval(interval);
          }
        });
      }, 1000);
    } else {
      console.log("Something went wrong while submitting your transaction:", error);
    }
  });
}

0
0

You can also do it like this, by specifying number of block confirmations you'd like to wait for before proceeding. Note: You'll have to first instantiate account and target contract with web3. (https://web3js.readthedocs.io/en/v1.2.11/callbacks-promises-events.html):

    const encoded = await tokenContract.methods.approve(routerAddr, amountToSend).encodeABI()
    const tx = {
      gas: 100000,
      to: tokenAddr,
      data: encoded
    }
     const signedTx = await account.signTransaction(tx);
    console.log("Sending transaction...");

    const targetConfirmations = 3;

    await new Promise((resolve, reject) => {
      const promiEvent = web3.eth.sendSignedTransaction(signedTx.rawTransaction);

      promiEvent
        .on('confirmation', (confNumber, receipt) => {
          console.log("Confirmation number:", confNumber);
          if (confNumber >= targetConfirmations) {
            console.log(`Received ${targetConfirmations} confirmations. Transaction is confirmed.`);
            promiEvent.off('confirmation'); // Remove all confirmation handlers
            resolve(receipt); // Resolve the promise after the desired confirmations
          }
        })
        .on('error', error => {
          console.error("Error:", error);
          reject(error); // Reject the promise if there's an error
        });
    });

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.