Transactions in EVM-based blockchain networks can be batched using the web3.js library. You need to create a batch object in order to perform this task. You can have a look at the example code from the web3.js documentation.
var contract =new web3.eth.Contract(abi, address);
var batch =new web3.BatchRequest();
batch.add(web3.eth.getBalance.request('0x0000000000000000000000000000000000000000', 'latest', callback));
batch.add(contract.methods.balance(address).call.request({from: '0x0000000000000000000000000000000000000000'}, callback2));
batch.execute();
batch.add()
accepts request objects and batch.execute()
executes the requests in the order in which they were added.
there are a few things that you need to keep in mind if you are planning to use the web3.batchRequest for batching transactions.
- but
batch.execute()
does not return a promise, hence the transaction execution will continue in the background. - you will get transactionHash as a return value from the callback provided by the request object.
- But the transaction hash will be sent to you before the receipt is even generated(receipt gets generated after transaction execution).
This can cause a problem if you are planning to use this transaction receipt to retrieve the receipt using web3.eth.getTransactionHash()
.
In order to resolve this,
If you need to wait until batch.execute()
wraps up with the transaction execution, you need to write a wrapper function that returns a promise and resolves it in the callback of the request object.
[Note]: In the example given below, we are making use of the waitForReceipt()
function. It is a recursive function that calls the web3.eth.getTransactionReciept()
. If the receipt is null, it recursively calls itself after a delay of 2000 milliseconds. If the receipt is not null, then a callback function is resolved.
const batchExecution = () => {
try {
return new Promise((resolve) => {
batch.add( contract.methods.SomeFunc2(params).call.request(...), callback));
batch.add( contract.methods.SomeFunc2(params)
.call.request({from: '0x0000000000000000000000000000000000000000'}, (err,tx) => {
waitForReceipt(tx, (reciept) => {
console.log(":::::::::::::::::waitForReceipt::::::::", tx);
console.log(":::::::::::::::::receipt::::::::", receipt);
const data = {
success: receipt?.status
};
resolve(data);
};
});
batch.execute();
});
} catch(e) {
console.log("error");
}
}
const waitForReceipt = (tx, cb) =>{
let reciept = web3.eth.getTransactionReciept(tx, function(err, reciept) {
if(reciept){
cb(reciept);
} else {
window.setTimeout(function () {
waitForReceipt(tx, cb);
}, 2000);
}
});
}
Thus, by utilizing promises, you can use the batch execution provided by the web3.js library in an async/await pattern. and can await until the batch is completely executed.