|
| 1 | +//! This example demonstrates how to use the [`MulticallBuilder`] to make multicalls using the |
| 2 | +//! [`IMulticall3`] contract. |
| 3 | +
|
| 4 | +use alloy::{ |
| 5 | + primitives::{address, U256}, |
| 6 | + providers::{CallItemBuilder, Failure, Provider, ProviderBuilder}, |
| 7 | + sol, |
| 8 | +}; |
| 9 | +use IWETH9::IWETH9Instance; |
| 10 | + |
| 11 | +sol!( |
| 12 | + #[allow(missing_docs)] |
| 13 | + #[sol(rpc)] |
| 14 | + #[derive(Debug)] |
| 15 | + IWETH9, |
| 16 | + "examples/abi/IWETH9.json" |
| 17 | +); |
| 18 | + |
| 19 | +#[tokio::main] |
| 20 | +async fn main() -> eyre::Result<()> { |
| 21 | + // Create a new provider |
| 22 | + let provider = ProviderBuilder::new() |
| 23 | + .on_anvil_with_wallet_and_config(|a| a.fork("https://eth.merkle.io"))?; |
| 24 | + // Deploy the Multicall3 contract |
| 25 | + // let multicall3 = deploy_multicall3(&provider).await; |
| 26 | + // Deploy the WETH contract |
| 27 | + // let weth = deploy_weth(&provider).await; |
| 28 | + let weth = |
| 29 | + IWETH9Instance::new(address!("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), &provider); |
| 30 | + |
| 31 | + let alice = address!("70997970C51812dc3A010C7d01b50e0d17dc79C8"); |
| 32 | + let bob = address!("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"); |
| 33 | + |
| 34 | + let multicall = provider |
| 35 | + .multicall() |
| 36 | + // Set the address of the Multicall3 contract. If unset it uses the default address from <https://github.com/mds1/multicall>: 0xcA11bde05977b3631167028862bE2a173976CA11 |
| 37 | + // .address(multicall3) |
| 38 | + // Get the total supply of WETH on our anvil fork. |
| 39 | + .add(weth.totalSupply()) |
| 40 | + // Get Alice's WETH balance. |
| 41 | + .add(weth.balanceOf(alice)) |
| 42 | + // Also fetch Alice's ETH balance. |
| 43 | + .get_eth_balance(alice); |
| 44 | + |
| 45 | + let (init_total_supply, alice_weth, alice_eth_bal) = multicall.aggregate().await?; |
| 46 | + |
| 47 | + println!( |
| 48 | + "Initial total supply: {}, Alice's WETH balance: {}, Alice's ETH balance: {}", |
| 49 | + init_total_supply._0, alice_weth._0, alice_eth_bal.balance |
| 50 | + ); |
| 51 | + |
| 52 | + // Simulate a transfer of WETH from Alice to Bob. |
| 53 | + let wad = U256::from(20); |
| 54 | + |
| 55 | + // This would fail as Alice doesn't have any WETH. |
| 56 | + let tx = CallItemBuilder::new(weth.transfer(bob, U256::from(10))).allow_failure(true); |
| 57 | + let deposit = CallItemBuilder::new(weth.deposit()).value(wad); // Set the amount of eth that should be deposited into the contract. |
| 58 | + let multicall = provider |
| 59 | + .multicall() |
| 60 | + // Bob's intial WETH balance. |
| 61 | + .add(weth.balanceOf(bob)) |
| 62 | + // Attempted WETH transfer from Alice to Bob which would fail. |
| 63 | + .add_call(tx.clone()) |
| 64 | + // Alices deposits ETH and mints WETH. |
| 65 | + .add_call(deposit) |
| 66 | + // Attempt transfer again. Succeeds! |
| 67 | + .add_call(tx) |
| 68 | + // Alice's WETH balance after the transfer. |
| 69 | + .add(weth.balanceOf(alice)) |
| 70 | + // Bob's final balance. |
| 71 | + .add(weth.balanceOf(bob)); |
| 72 | + |
| 73 | + assert_eq!(multicall.len(), 6); |
| 74 | + |
| 75 | + // It is important to use `aggregate3_value` as we're trying to simulate calls to payable |
| 76 | + // functions that should be sent a value, using any other multicall3 method would result in an |
| 77 | + // error. |
| 78 | + let (init_bob, failed_transfer, deposit, succ_transfer, alice_weth, bob_weth) = |
| 79 | + multicall.aggregate3_value().await?; |
| 80 | + |
| 81 | + // Since, `aggregate3_value` allows for calls to fail without reverting, it returns a tuple of |
| 82 | + // results which contain the decoded return value in Ok(_) variant and the `Failure` type in the |
| 83 | + // Err(_) variant. |
| 84 | + assert!(matches!(failed_transfer.unwrap_err(), Failure { idx: 1, return_data: _ })); |
| 85 | + |
| 86 | + let init_bob = init_bob?; |
| 87 | + assert_eq!(init_bob._0, U256::ZERO); |
| 88 | + |
| 89 | + assert!(deposit.is_ok()); |
| 90 | + assert!(succ_transfer.is_ok()); |
| 91 | + |
| 92 | + let alice_weth = alice_weth?; |
| 93 | + let bob_weth = bob_weth?; |
| 94 | + |
| 95 | + println!("Alice's WETH balance: {}, Bob's WETH balance: {}", alice_weth._0, bob_weth._0); |
| 96 | + |
| 97 | + Ok(()) |
| 98 | +} |
0 commit comments