#![warn(missing_docs)]
use alloy_primitives::{address, Address};
use alloy_provider::{network::Ethereum, Provider};
use alloy_sol_types::sol;
use anyhow::Result;
sol! {
#[sol(rpc)]
interface IMulticall3 {
#[derive(Debug, PartialEq, Eq)]
struct Call3 {
address target;
bool allowFailure;
bytes callData;
}
#[derive(Debug, PartialEq, Eq)]
struct Result {
bool success;
bytes returnData;
}
function aggregate3(Call3[] calldata calls)
external payable returns (Result[] memory returnData);
function getBlockNumber() external view returns (uint256 blockNumber);
}
}
pub const MULTICALL3_ADDRESS: Address = address!("cA11bde05977b3631167028862bE2a173976CA11");
pub async fn aggregate3<P: Provider<Ethereum>>(
provider: &P,
multicall: Address,
calls: Vec<IMulticall3::Call3>,
) -> Result<Vec<IMulticall3::Result>> {
let contract = IMulticall3::new(multicall, provider);
let returns = contract.aggregate3(calls).call().await?;
Ok(returns)
}
#[cfg(test)]
mod tests {
use super::*;
use alloy_sol_types::SolCall;
#[test]
fn canonical_multicall3_address() {
assert_eq!(MULTICALL3_ADDRESS, address!("cA11bde05977b3631167028862bE2a173976CA11"),);
}
#[test]
fn aggregate3_selector_matches_known_value() {
assert_eq!(IMulticall3::aggregate3Call::SELECTOR, [0x82, 0xad, 0x56, 0xcb],);
}
#[test]
fn get_block_number_selector_matches_known_value() {
assert_eq!(IMulticall3::getBlockNumberCall::SELECTOR, [0x42, 0xcb, 0xb1, 0x5c],);
}
}