Multicall3 is a powerful smart contract that allows batching multiple contract calls into a single transaction, reducing gas costs and improving efficiency. This guide demonstrates how to use Multicall3 to:
- Batch ERC20 Token Transfers
- Batch Native Token (5ire) Transfers
Before using Multicall3, ensure that you have:
- Node.js and npm installed.
- Clone the repository (
git clone https://github.com/imshvishal/multicall3-web3
). - Install Packages (
npm install
). - Set Environment Variables for private keys only in
.env
file. Checkout env example file. - Multicall3 contract deployed (or use an existing deployment).
npx hardhat run scripts/deploy_multicall_contract.ts --network thunder
or use existing deployment at testnet (thunder) at address0x1b25Ce9eE090f6d74A8b0C08211b7A6163a9c9c5
if you wish to use testnet. - Set Environment Variables for multicall contract address
.env
file. - ERC20 token contract deployed (for ERC20 batch transactions).
npx hardhat run scripts/deploy_erc20.ts --network thunder
1️⃣ Batch ERC20 Token Transfers [Script]
-
This function takes array of Calls and the call data consists of following parameters:
param
dtype
use
target
address Recepeint contract address where the function is to be called. callData
bytes Function call data encoded in the form of bytes. allowFailure
bool If true, call will be skipped if the call fails.
npx hardhat run scripts/multicall_contract_interaction.ts --network thunder
Before transferring tokens using Multicall3, the sender must approve the contract to spend tokens on their behalf.
const Token = await ethers.getContractAt("ERC20Token", TokenAddr);
await Token.approve(MulticallCtrAddr, ethers.parseEther("600"));
const Multicall = await ethers.getContractAt("Multicall3", MulticallCtrAddr);
let result = await Multicall.aggregate3([
{
target: TokenAddr,
callData: Token.interface.encodeFunctionData("transferFrom", [Owner, user1.address, ethers.parseEther("100")]),
allowFailure: false,
},
{
target: TokenAddr,
callData: Token.interface.encodeFunctionData("transferFrom", [Owner, user2.address, ethers.parseEther("200")]),
allowFailure: false,
},
{
target: TokenAddr,
callData: Token.interface.encodeFunctionData("transferFrom", [Owner, user3.address, ethers.parseEther("300")]),
allowFailure: false,
},
]);
await result.wait();
After execution, check token balances to confirm successful transfers.
console.log("USER1 BALANCE:", await Token.balanceOf(user1.address));
console.log("USER2 BALANCE:", await Token.balanceOf(user2.address));
console.log("USER3 BALANCE:", await Token.balanceOf(user3.address));
2️⃣ Batch Native Token (5ire) Transfers [Script]
-
This function takes array of Calls and the call data consists of following parameters:
param
dtype
use
target
address Recepeint contract address where the function is to be called. value
uint256 Amount of native token to be sent to the target. allowFailure
bool If true, call will be skipped if the call fails. callData
bytes Function call data encoded in the form of bytes. Here it will be empty bytes as we are not calling any function.
npx hardhat run scripts/multicall_native_transfer.ts --network thunder
let result = await Multicall.aggregate3Value(
[
{
target: user1.address,
value: ethers.parseEther("1"),
allowFailure: false,
callData: "0x",
},
{
target: user2.address,
value: ethers.parseEther("2"),
allowFailure: false,
callData: "0x",
},
{
target: user3.address,
value: ethers.parseEther("3"),
allowFailure: false,
callData: "0x",
},
],
{ value: ethers.parseEther("6") }
);
await result.wait();
After execution, check the new balances.
console.log("USER1 BALANCE:", await ethers.provider.getBalance(user1.address));
console.log("USER2 BALANCE:", await ethers.provider.getBalance(user2.address));
console.log("USER3 BALANCE:", await ethers.provider.getBalance(user3.address));
After the deployment, deployed contracts can be verified over the network!
npx hardhat verify 0x1b25Ce9eE090f6d74A8b0C08211b7A6163a9c9c5 --network thunder
Using Multicall3, you can significantly reduce gas fees and optimize smart contract interactions by batching multiple requests into a single transaction. Whether handling ERC20 token transfers or Native token transfers, this method ensures faster and more cost-efficient blockchain operations.
- Reduces Gas Fees: Executes multiple operations in a single transaction.
- Improves Efficiency: Allows batching various function calls at once.
📌 Next Steps: Experiment with adding more transactions in a single batch or integrate batch calls into your dApps for better performance!