Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

EVMlord/multicall-sdk

Repository files navigation

@evmlord/multicall-sdk – Batch smart-contract calls on Ethereum & EVM networks

A lightweight TypeScript/JavaScript library built on ethers v6 for DeFi dashboards, on-chain analytics and gas-optimised dApps.

npm @evmlord/multicall-sdk latest version CI Build Status MIT license for @evmlord/multicall-sdk Weekly npm downloads for @evmlord/multicall-sdk TypeScript types included Minified bundle size


πŸš€ Why @evmlord/multicall-sdk?

  • Gas & RPC Optimized
    Combine dozens of eth_call into one multicall, slashing HTTP/WebSocket overhead and minimizing latency.

  • Fully Typed
    Written in TypeScript with built-in declarationsβ€”autocomplete your batch calls, interfaces, and return values.

  • Failure-Tolerant
    Gracefully handle individual call failures (allowFailure) without aborting the entire batch.

  • Rich Decoding
    Automatically unpack tuples, structs, arrays and custom errors into plain JS objects & arraysβ€”no manual unpacking.

  • EVM & DeFi Focused
    Supports Multicall3, Multicall2 and on-chain block helpers (getBlockNumber, getEthBalance, etc.) across 280+ networks.


πŸ”§ Installation (Node .js / TypeScript)

# via yarn
yarn add @evmlord/multicall-sdk
# or npm
npm install @evmlord/multicall-sdk

πŸ“– Quick-Start Example with ethers v6

285 EVM-compatible networks are supported by default, and custom networks can be supported by providing a deployed Multicall contract address.

πŸ‘‰ See the complete list in SUPPORTED_NETWORKS.md.

1. Create your Multicall client

import { JsonRpcProvider, WebSocketProvider } from "ethers";
import { Multicall } from "@evmlord/multicall-sdk";
// 1) HTTP RPC URL
const mc1 = new Multicall({
 provider: "https://mainnet.infura.io/v3/...",
 chainId: 1,
});
// 2) Browser/EIP-1193 (e.g. MetaMask)
const mc2 = new Multicall({
 provider: window.ethereum, // auto-wrapped
 multicallAddress: "0x...", // override default if deployed elsewhere
});
// 3) Already-constructed ethers Provider
const ws = new WebSocketProvider("wss://...");
const mc3 = new Multicall({ provider: ws, chainId: 5 });
// 4) Custom signer for writing txs
const signer = wallet.connect(provider);
const mc4 = new Multicall({
 provider: provider,
 signer: signer,
 chainId: 56,
});

2. Batch simple eth_calls

import erc20Abi from "./abi/ERC20.json";
import { Call } from "@evmlord/multicall-abi";
const token = new ethers.Contract("0x...ERC20", erc20Abi, provider);
// Prepare calls
const calls: Call[] = [
 { contract: token, functionFragment: "balanceOf", args: ["0xYourAddress1"] },
 { contract: token, functionFragment: "balanceOf", args: ["0xYourAddress2"] },
 { contract: token, functionFragment: "balanceOf", args: ["0xYourAddress3"] },
 { contract: token, functionFragment: "totalSupply", args: [] },
];
// Execute a single eth_call via Multicall
const { blockNumber, returnData } = await mc1.aggregate(calls);
// Decode your results
const [balance1] = token.interface.decodeFunctionResult(
 "balanceOf",
 returnData[0]
);
const [balance2] = token.interface.decodeFunctionResult(
 "balanceOf",
 returnData[1]
);
const [balance3] = token.interface.decodeFunctionResult(
 "balanceOf",
 returnData[2]
);
const [supply] = token.interface.decodeFunctionResult(
 "totalSupply",
 returnData[3]
);
console.log({
 blockNumber,
 balance1,
 balance2,
 balance3,
 supply,
});
/* 
 console:
{
 blockNumber: 55038412n,
 balance1: 76950775000000000000000n,
 balance2: 0n,
 balance3: 1583902570428472973924450219389n,
 supply: 10000000000000000000000000000000000000000000n
} 
*/

βš™οΈ API Reference

Batch Methods

Method Description
aggregate(calls: Call[]) Reverts on any failing call. Returns
{ blockNumber, returnData: string[] }.
tryAggregate(requireSuccess, calls: Call[]) Optionally continue on failed calls. Returns
Array<{ success: boolean, returnData: string }>
blockAndAggregate(calls: Call[]) Alias for tryBlockAndAggregate(true, calls). Returns
{ blockNumber, blockHash, returnData }.
tryBlockAndAggregate(requireSuccess, calls: Call[]) Same as tryAggregate but also provides full block info plus per-call success flags.
aggregate3(calls: Call3[]) Multicall 3 style: each call has an allowFailure flag, and return values are auto-decoded to JS tuples/structs.
aggregate3Value(calls: Call3Value[]) Like aggregate3, but supports per-call native ETH value and automatically sums msg.value.
sendAggregate3Value(calls: Call3Value[], overrides: Overrides) Like aggregate3Value, but for real on-chain writes, accepts optional Ethers overrides (gasLimit, gasPrice, etc) and returns TransactionResponse, which you can .wait() on.
// ── aggregate3 example ─────────────────────────────────────────
// call two view methods in one batch, but let one of them fail
const calls3: Call3[] = [
 {
 contract: token,
 functionFragment: "nonExistedProperty", // this will throw
 args: [],
 allowFailure: true,
 },
 {
 contract: token,
 functionFragment: "balanceOf",
 args: ["0x5500..."], // wallet address here
 allowFailure: true,
 },
 ];
 const results3 = await mc1.aggregate3(calls3);
 console.log({ results3 });
 /*
console:
{
 results3: [
 [ false, 'Revert: (unrecognized revert: 0x...)' ],
 [ true, 76950775000000000000000n ]
 ]
}
 */
// ── aggregate3Value example ────────────────────────────────────
// imagine a payable helper that charges a small fee per call
const helper = new ethers.Contract(
 "0x...EHelperContract", // your helper address
 HelperABI, // your ABI
 provider
)
// send 0.001 ETH with each call to fetch some on-chain data
const fee = 0.001n * 10n**18n // 0.001 ETH in wei as bigint
const calls3Value: Call3Value[] = [
 {
 contract: helper,
 functionFragment:'getSomeData',
 args: [ user ],
 allowFailure: false,
 value: fee
 },
 {
 contract: helper,
 functionFragment:'getOtherData',
 args: [ user, 42 ],
 allowFailure: true,
 value: fee
 }
]
const results3Value = await mc1.aggregate3Value(calls3Value)
// returns Array<[success: boolean, data]>
{
 const [ok, getSomeData] = results3Value[0];
 if (ok) {
 console.log('getSomeData β†’', getSomeData)
 }
}
 {
 const [ok, getOtherData] = results3Value[1];
 if (ok) {
 console.log('getOtherData β†’', getOtherData)
 }
 }

What’s happening here?

  • aggregate3 You pass allowFailure: true on any call that might revertβ€”failed calls return [false, rawHex] while successes decode normally.

  • aggregate3Value Each call can carry its own ETH payment (value), and the SDK automatically sums them into one msg.value for the batch. Any call marked allowFailure: true won’t abort the entire batch if it reverts.

Sending State-Changing Multicall Transactions

Up until now we’ve only covered the "view" methods (aggregate, tryAggregate, aggregate3, etc). If you need to batch together state-changing calls (optionally with ETH attached) into a single on-chain tx, you can use sendAggregate3Value:

import { Multicall, Call3Value, ChainId } from "@evmlord/multicall-sdk";
import { ethers } from "ethers";
// 1) Create a signer-backed Multicall instance
const provider = new ethers.JsonRpcProvider("https://rpc.ankr.com/eth");
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);
const multicall = new Multicall({
 provider,
 chainId: ChainId.MAINNET,
 signer: wallet, // <- needed for txs
});
// 2) Prepare your payable calls
// each call3Value: { contract, functionFragment, args, allowFailure, value }
const fee = ethers.parseUnits("0.001", "ether"); // per-call ETH fee
const myHelper = new ethers.Contract("0xHelper...", HelperABI, provider);
const calls: Call3Value[] = [
 {
 contract: myHelper,
 functionFragment: "depositAndFetch",
 args: ["0xYourAddress"],
 allowFailure: false,
 value: fee,
 },
 {
 contract: myHelper,
 functionFragment: "updateRecord",
 args: [42, "hello"],
 allowFailure: true,
 value: fee,
 },
 // ...etc
];
// 3) Send them all in one tx
const tx = await mc4.sendAggregate3Value(calls, {
 gasLimit: 1_200_000,
});
console.log("Multicall tx hash:", tx.hash);
// 4) Wait for it to be mined
const receipt = await tx.wait();
console.log("β†’ mined in block", receipt.blockNumber);
API
/**
 * Batch-execute multiple non-view calls (each may carry its own ETH value)
 * in a single on-chain TX via Multicall3.aggregate3Value.
 *
 * @param calls – Array of { contract, functionFragment, args, allowFailure, value }
 * @param overrides – Ethers transaction overrides (gasLimit, maxPriorityFeePerGas, etc)
 * @returns Promise<TransactionResponse>
 * @throws if no Signer was provided in the constructor.
 */
sendAggregate3Value(
 calls: Call3Value[],
 overrides?: Overrides
): Promise<TransactionResponse>;
  • allowFailure: true on any Call3Value lets that individual call revert without failing the entire batch.

  • The SDK automatically sums up all value fields into one msg.value on the multicall.

Helper Functions

All return either Promise<bigint> or Promise<string>:

  • getEthBalance Gets the ETH balance of an address

    const ethBalance = await mc1.getEthBalance("address");
  • getBlockHash Gets the block hash

    Only works for 256 most recent, excluding current according to Solidity docs

    const blockHash = await mc1.getBlockHash(blockNumber);
  • getLastBlockHash Gets the last blocks hash

    const lastBlockHash = await mc1.getLastBlockHash();
  • getCurrentBlockTimestamp Gets the current block timestamp

    const currentBlockTimestamp = await mc1.getCurrentBlockTimestamp();
  • getCurrentBlockDifficulty Gets the current block difficulty

    const currentBlockDifficulty = await mc1.getCurrentBlockDifficulty();
  • getCurrentBlockGasLimit Gets the current block gas limit

    const currentBlockGasLimit = await mc1.getCurrentBlockGasLimit();
  • getCurrentBlockCoinbase Gets the current block coinbase

    const currentBlockCoinbase = await mc1.getCurrentBlockCoinbase();

πŸ§ͺ Testing

This SDK ships with a comprehensive Mocha + Chai + Sinon test suite.

# Run unit tests (Mocha + Chai + Sinon)
yarn test

🀝 Contributing

  1. Fork & clone
  2. yarn install
  3. Develop in src/, add tests in test/
  4. Run yarn test & Submit a PR

πŸ“œ LICENSE

Released under the MIT License.

Β© 2025 EVMlord

About

A lightweight library to batch multiple calls via a single eth_call using Multicall3 on 285+ chains.

Topics

Resources

Stars

Watchers

Forks

Packages

Contributors

AltStyle γ«γ‚ˆγ£γ¦ε€‰ζ›γ•γ‚ŒγŸγƒšγƒΌγ‚Έ (->γ‚ͺγƒͺγ‚ΈγƒŠγƒ«) /