Skip to content

Example: multicall_batching

To run this example:

  • Clone the examples repository: git clone git@github.com:alloy-rs/examples.git
  • Run: cargo run --example multicall_batching
//! Demonstrate the Multicall Batch Layer.
//! Provider layer that aggregates contract calls (`eth_call`) over a time period into a single
//! Multicall3 contract call. This is useful for reducing the number of requests made to the RPC.
 
use std::time::Duration;
 
use alloy::{
    primitives::address,
    providers::{layers::CallBatchLayer, Provider, ProviderBuilder},
    sol,
};
use eyre::Result;
use IWETH9::{balanceOfCall, totalSupplyCall, IWETH9Instance};
 
sol!(
    #[allow(missing_docs)]
    #[sol(rpc)]
    #[derive(Debug)]
    IWETH9,
    "examples/abi/IWETH9.json"
);
 
#[tokio::main]
async fn main() -> Result<()> {
    // Instantiate a provider with the `CallBatchLayer` enabled.
    let provider = ProviderBuilder::new()
        // Enables `eth_call` batching by leveraging the Multicall3 contract.
        // The `CallBatchLayer` will wait for a certain amount of time before sending a request. See: <https://docs.rs/alloy-provider/latest/alloy_provider/layers/struct.CallBatchLayer.html#method.wait>.
        // This delay is added to aggregate any incoming `eth_calls` that can be together.
        // In this case, we set the delay to 10ms.
        .layer(CallBatchLayer::new().wait(Duration::from_secs(10)))
        // Can also use the shorthand `with_call_batching` on the build which set the delay to 1ms.
        // .with_call_batching()
        .on_anvil_with_wallet_and_config(|a| a.fork("https://reth-ethereum.ithaca.xyz/rpc"))?;
 
    // Create a new instance of the IWETH9 contract.
    let weth =
        IWETH9Instance::new(address!("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), &provider);
 
    let alice = address!("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045");
    let bob = address!("0xc7bBeC68d12a0d1830360F8Ec58fA599bA1b0e9b");
 
    // Calls that will be batched.
    let alice_weth = weth.balanceOf(alice).into_transaction_request();
    let bob_weth = weth.balanceOf(bob).into_transaction_request();
    let total_supply = weth.totalSupply().into_transaction_request();
 
    // Requests need to be parallelized to be batched.
    let (alice_weth, bob_weth, total_supply, block_number, alice_eth) = tokio::try_join!(
        // Batch `eth_call` requests.
        provider.call(alice_weth).decode_resp::<balanceOfCall>(),
        provider.call(bob_weth).decode_resp::<balanceOfCall>(),
        provider.call(total_supply).decode_resp::<totalSupplyCall>(),
        // Get block number and get balance calls can also be batched.
        provider.get_block_number(),
        provider.get_balance(alice)
    )?;
 
    // Resolve `Ok`.
    let alice_weth = alice_weth?;
    let bob_weth = bob_weth?;
    let total_supply = total_supply?;
 
    println!("Block Number: {block_number}");
    println!(
        "Alice's WETH balance: {}\nBob's WETH balance: {}\nTotal WETH supply: {}\nAlice's ETH
    balance: {}",
        alice_weth, bob_weth, total_supply, alice_eth
    );
 
    Ok(())
}

Find the source code on Github here.