alloy_provider/provider/multicall/
mod.rs

1//! A Multicall Builder
2
3use crate::{PendingTransactionBuilder, Provider};
4use alloy_network::{Network, TransactionBuilder};
5use alloy_primitives::{address, Address, BlockNumber, Bytes, B256, U256};
6use alloy_rpc_types_eth::{state::StateOverride, BlockId, TransactionInputKind};
7use alloy_sol_types::SolCall;
8use bindings::IMulticall3::{
9    blockAndAggregateCall, blockAndAggregateReturn, tryBlockAndAggregateCall,
10    tryBlockAndAggregateReturn, Call, Call3, Call3Value,
11};
12
13/// Multicall bindings
14pub mod bindings;
15use crate::provider::multicall::bindings::IMulticall3::{
16    aggregate3Call, aggregate3ValueCall, aggregateCall, getBasefeeCall, getBlockHashCall,
17    getBlockNumberCall, getChainIdCall, getCurrentBlockCoinbaseCall, getCurrentBlockDifficultyCall,
18    getCurrentBlockGasLimitCall, getCurrentBlockTimestampCall, getEthBalanceCall,
19    getLastBlockHashCall, tryAggregateCall,
20};
21
22mod inner_types;
23pub use inner_types::{
24    CallInfoTrait, CallItem, CallItemBuilder, Dynamic, Failure, MulticallError, MulticallItem,
25    Result,
26};
27
28mod tuple;
29use tuple::TuplePush;
30pub use tuple::{CallTuple, Empty};
31
32/// Default address for the Multicall3 contract on most chains. See: <https://github.com/mds1/multicall>
33pub const MULTICALL3_ADDRESS: Address = address!("0xcA11bde05977b3631167028862bE2a173976CA11");
34
35/// Default address for the ArbSys precompile on arbitrum rollups. See: <https://docs.arbitrum.io/build-decentralized-apps/precompiles/reference#arbsys>
36pub const ARB_SYS_ADDRESS: Address = address!("0x0000000000000000000000000000000000000064");
37
38/// A Multicall3 builder
39///
40/// This builder implements a simple API interface to build and execute multicalls using the
41/// [`IMultiCall3`](crate::bindings::IMulticall3) contract which is available on 270+
42/// chains.
43///
44/// # Examples
45///
46/// ```ignore (missing alloy-contract)
47/// use alloy_primitives::address;
48/// use alloy_provider::{MulticallBuilder, Provider, ProviderBuilder};
49/// use alloy_sol_types::sol;
50///
51/// sol! {
52///     #[sol(rpc)]
53///     #[derive(Debug, PartialEq)]
54///     interface ERC20 {
55///         function totalSupply() external view returns (uint256 totalSupply);
56///         function balanceOf(address owner) external view returns (uint256 balance);
57///     }
58/// }
59///
60/// #[tokio::main]
61/// async fn main() {
62///     let weth = address!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2");
63///     let provider =
64///         ProviderBuilder::new().connect_http("https://eth.merkle.io".parse().unwrap());
65///     let erc20 = ERC20::new(weth, &provider);
66///
67///     let ts_call = erc20.totalSupply();
68///     let balance_call = erc20.balanceOf(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"));
69///
70///     let multicall = provider.multicall().add(ts_call).add(balance_call);
71///
72///     let (total_supply, balance) = multicall.aggregate().await.unwrap();
73///     println!("Total Supply: {total_supply}, Balance: {balance}");
74///
75///     // Or dynamically:
76///     let mut dynamic_multicall = provider.multicall().dynamic();
77///     let addresses = vec![
78///         address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"),
79///         address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96046"),
80///     ];
81///     for &address in &addresses {
82///         dynamic_multicall = dynamic_multicall.add_dynamic(erc20.balanceOf(address));
83///     }
84///     let balances: Vec<_> = dynamic_multicall.aggregate().await.unwrap();
85///     println!("Balances: {:#?}", balances);
86/// }
87/// ```
88#[derive(Debug)]
89pub struct MulticallBuilder<T: CallTuple, P: Provider<N>, N: Network> {
90    /// Batched calls
91    calls: Vec<Call3Value>,
92    /// The provider to use
93    provider: P,
94    /// The [`BlockId`] to use for the call
95    block: Option<BlockId>,
96    /// The [`StateOverride`] for the call
97    state_override: Option<StateOverride>,
98    /// This is the address of the [`IMulticall3`](crate::bindings::IMulticall3)
99    /// contract.
100    ///
101    /// By default it is set to [`MULTICALL3_ADDRESS`].
102    address: Address,
103    /// The input kind supported by this builder
104    input_kind: TransactionInputKind,
105    _pd: std::marker::PhantomData<(T, N)>,
106}
107
108impl<P, N> MulticallBuilder<Empty, P, N>
109where
110    P: Provider<N>,
111    N: Network,
112{
113    /// Instantiate a new [`MulticallBuilder`]
114    pub fn new(provider: P) -> Self {
115        Self {
116            calls: Vec::new(),
117            provider,
118            _pd: Default::default(),
119            block: None,
120            state_override: None,
121            address: MULTICALL3_ADDRESS,
122            input_kind: TransactionInputKind::default(),
123        }
124    }
125
126    /// Converts an empty [`MulticallBuilder`] into a dynamic one
127    pub fn dynamic<D: SolCall + 'static>(self) -> MulticallBuilder<Dynamic<D>, P, N> {
128        MulticallBuilder {
129            calls: self.calls,
130            provider: self.provider,
131            block: self.block,
132            state_override: self.state_override,
133            address: self.address,
134            input_kind: self.input_kind,
135            _pd: Default::default(),
136        }
137    }
138}
139
140impl<D: SolCall + 'static, P, N> MulticallBuilder<Dynamic<D>, P, N>
141where
142    P: Provider<N>,
143    N: Network,
144{
145    /// Instantiate a new [`MulticallBuilder`] that restricts the calls to a specific call type.
146    ///
147    /// Multicalls made using this builder return a vector of the decoded return values.
148    ///
149    /// An example would be trying to fetch multiple ERC20 balances of an address.
150    ///
151    /// This is equivalent to `provider.multicall().dynamic()`.
152    ///
153    /// # Examples
154    ///
155    /// ```ignore (missing alloy-contract)
156    /// use alloy_primitives::address;
157    /// use alloy_provider::{MulticallBuilder, Provider, ProviderBuilder};
158    /// use alloy_sol_types::sol;
159    ///
160    /// sol! {
161    ///     #[sol(rpc)]
162    ///     #[derive(Debug, PartialEq)]
163    ///     interface ERC20 {
164    ///         function balanceOf(address owner) external view returns (uint256 balance);
165    ///     }
166    /// }
167    ///
168    /// #[tokio::main]
169    /// async fn main() {
170    ///    let weth = address!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2");
171    ///    let usdc = address!("A0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48");
172    ///     
173    ///    let provider = ProviderBuilder::new().connect_http("https://eth.merkle.io".parse().unwrap());
174    ///    let weth = ERC20::new(weth, &provider);
175    ///    let usdc = ERC20::new(usdc, &provider);
176    ///
177    ///    let owner = address!("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045");
178    ///
179    ///    let mut erc20_balances = MulticallBuilder::new_dynamic(provider);
180    ///    // Or:
181    ///    let mut erc20_balances = provider.multicall().dynamic();
182    ///
183    ///    for token in &[weth, usdc] {
184    ///        erc20_balances = erc20_balances.add_dynamic(token.balanceOf(owner));
185    ///    }
186    ///
187    ///    let balances: Vec<ERC20::balanceOfReturn> = erc20_balances.aggregate().await.unwrap();
188    ///
189    ///    let weth_bal = &balances[0];
190    ///    let usdc_bal = &balances[1];
191    ///    println!("WETH Balance: {:?}, USDC Balance: {:?}", weth_bal, usdc_bal);
192    /// }
193    pub fn new_dynamic(provider: P) -> Self {
194        MulticallBuilder::new(provider).dynamic()
195    }
196
197    /// Add a dynamic call to the builder
198    ///
199    /// The call will have `allowFailure` set to `false`. To allow failure, use
200    /// [`Self::add_call_dynamic`], potentially converting a [`MulticallItem`] to a fallible
201    /// [`CallItem`] with [`MulticallItem::into_call`].
202    pub fn add_dynamic(mut self, item: impl MulticallItem<Decoder = D>) -> Self {
203        let call: CallItem<D> = item.into();
204
205        self.calls.push(call.to_call3_value());
206        self
207    }
208
209    /// Add a dynamic [`CallItem`] to the builder
210    pub fn add_call_dynamic(mut self, call: CallItem<D>) -> Self {
211        self.calls.push(call.to_call3_value());
212        self
213    }
214
215    /// Extend the builder with a sequence of calls
216    pub fn extend(
217        mut self,
218        items: impl IntoIterator<Item = impl MulticallItem<Decoder = D>>,
219    ) -> Self {
220        for item in items {
221            self = self.add_dynamic(item);
222        }
223        self
224    }
225
226    /// Extend the builder with a sequence of [`CallItem`]s
227    pub fn extend_calls(mut self, calls: impl IntoIterator<Item = CallItem<D>>) -> Self {
228        for call in calls {
229            self = self.add_call_dynamic(call);
230        }
231        self
232    }
233}
234
235impl<T, P, N> MulticallBuilder<T, &P, N>
236where
237    T: CallTuple,
238    P: Provider<N> + Clone,
239    N: Network,
240{
241    /// Clones the underlying provider and returns a new [`MulticallBuilder`].
242    pub fn with_cloned_provider(&self) -> MulticallBuilder<Empty, P, N> {
243        MulticallBuilder {
244            calls: Vec::new(),
245            provider: self.provider.clone(),
246            block: None,
247            state_override: None,
248            address: MULTICALL3_ADDRESS,
249            input_kind: TransactionInputKind::default(),
250            _pd: Default::default(),
251        }
252    }
253}
254
255impl<T, P, N> MulticallBuilder<T, P, N>
256where
257    T: CallTuple,
258    P: Provider<N>,
259    N: Network,
260{
261    /// Set the address of the multicall3 contract
262    ///
263    /// Default is [`MULTICALL3_ADDRESS`].
264    pub const fn address(mut self, address: Address) -> Self {
265        self.address = address;
266        self
267    }
268
269    /// Sets the block to be used for the call.
270    pub const fn block(mut self, block: BlockId) -> Self {
271        self.block = Some(block);
272        self
273    }
274
275    /// Set the state overrides for the call.
276    pub fn overrides(mut self, state_override: impl Into<StateOverride>) -> Self {
277        self.state_override = Some(state_override.into());
278        self
279    }
280
281    /// Appends a [`SolCall`] to the stack.
282    ///
283    /// The call will have `allowFailure` set to `false`. To allow failure, use [`Self::add_call`],
284    /// potentially converting a [`MulticallItem`] to a fallible [`CallItem`] with
285    /// [`MulticallItem::into_call`].
286    #[expect(clippy::should_implement_trait)]
287    pub fn add<Item: MulticallItem>(self, item: Item) -> MulticallBuilder<T::Pushed, P, N>
288    where
289        Item::Decoder: 'static,
290        T: TuplePush<Item::Decoder>,
291        <T as TuplePush<Item::Decoder>>::Pushed: CallTuple,
292    {
293        let call: CallItem<Item::Decoder> = item.into();
294        self.add_call(call)
295    }
296
297    /// Appends a [`CallItem`] to the stack.
298    pub fn add_call<D>(mut self, call: CallItem<D>) -> MulticallBuilder<T::Pushed, P, N>
299    where
300        D: SolCall + 'static,
301        T: TuplePush<D>,
302        <T as TuplePush<D>>::Pushed: CallTuple,
303    {
304        self.calls.push(call.to_call3_value());
305        MulticallBuilder {
306            calls: self.calls,
307            provider: self.provider,
308            block: self.block,
309            state_override: self.state_override,
310            address: self.address,
311            input_kind: self.input_kind,
312            _pd: Default::default(),
313        }
314    }
315    /// Creates the [`aggregate3ValueCall`]
316    fn to_aggregate3_value_call(&self) -> aggregate3ValueCall {
317        aggregate3ValueCall { calls: self.calls.to_vec() }
318    }
319
320    /// Creates the [`blockAndAggregateCall`]
321    fn to_block_and_aggregate_call(&self) -> blockAndAggregateCall {
322        let calls = self
323            .calls
324            .iter()
325            .map(|c| Call { target: c.target, callData: c.callData.clone() })
326            .collect::<Vec<_>>();
327        blockAndAggregateCall { calls }
328    }
329
330    /// Creates the [`tryBlockAndAggregateCall`]
331    fn to_try_block_and_aggregate_call(&self, require_success: bool) -> tryBlockAndAggregateCall {
332        let calls = self
333            .calls
334            .iter()
335            .map(|c| Call { target: c.target, callData: c.callData.clone() })
336            .collect::<Vec<_>>();
337        tryBlockAndAggregateCall { requireSuccess: require_success, calls }
338    }
339
340    /// Calls the `aggregate` function
341    ///
342    /// Requires that all calls succeed, else reverts.
343    ///
344    /// ## Solidity Function Signature
345    ///
346    /// ```ignore
347    /// sol! {
348    ///     function aggregate(Call[] memory calls) external returns (uint256 blockNumber, bytes[] memory returnData);
349    /// }
350    /// ```
351    ///
352    /// ## Returns
353    ///
354    /// - `returnData`: A tuple of the decoded return values for the calls
355    ///
356    /// One can obtain the block context such as block number and block hash by using the
357    /// [MulticallBuilder::block_and_aggregate] function.
358    ///
359    /// # Examples
360    ///
361    /// ```ignore (missing alloy-contract)
362    /// use alloy_primitives::address;
363    /// use alloy_provider::{MulticallBuilder, Provider, ProviderBuilder};
364    /// use alloy_sol_types::sol;
365    ///
366    /// sol! {
367    ///     #[sol(rpc)]
368    ///     #[derive(Debug, PartialEq)]
369    ///     interface ERC20 {
370    ///         function totalSupply() external view returns (uint256 totalSupply);
371    ///         function balanceOf(address owner) external view returns (uint256 balance);
372    ///     }
373    /// }
374    ///
375    /// #[tokio::main]
376    /// async fn main() {
377    ///     let weth = address!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2");
378    ///     let provider = ProviderBuilder::new().connect_http("https://eth.merkle.io".parse().unwrap());
379    ///     let erc20 = ERC20::new(weth, &provider);
380    ///
381    ///     let ts_call = erc20.totalSupply();
382    ///     let balance_call = erc20.balanceOf(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"));
383    ///
384    ///     let multicall = provider.multicall().add(ts_call).add(balance_call);
385    ///
386    ///     let (total_supply, balance) = multicall.aggregate().await.unwrap();
387    ///
388    ///     println!("Total Supply: {:?}, Balance: {:?}", total_supply, balance);
389    /// }
390    /// ```
391    pub async fn aggregate(&self) -> Result<T::SuccessReturns> {
392        let output = self.build_and_call(self.to_aggregate_call(), None).await?;
393        T::decode_returns(&output.returnData)
394    }
395
396    /// Sends the `aggregate` function as a transaction.
397    pub async fn send_aggregate(&self) -> Result<PendingTransactionBuilder<N>> {
398        self.build_and_send(self.to_aggregate_call(), None).await
399    }
400
401    /// Encodes the calls for the `aggregate` function and returns the populated transaction
402    /// request.
403    pub fn to_aggregate_request(&self) -> N::TransactionRequest {
404        self.build_request(self.to_aggregate_call(), None)
405    }
406
407    /// Creates the [`aggregate3Call`].
408    fn to_aggregate_call(&self) -> aggregateCall {
409        let calls = self
410            .calls
411            .iter()
412            .map(|c| Call { target: c.target, callData: c.callData.clone() })
413            .collect::<Vec<_>>();
414        aggregateCall { calls }
415    }
416
417    /// Call the `tryAggregate` function
418    ///
419    /// Allows for calls to fail by setting `require_success` to false.
420    ///
421    /// ## Solidity Function Signature
422    ///
423    /// ```ignore
424    /// sol! {
425    ///     function tryAggregate(bool requireSuccess, Call[] calldata calls) external payable returns (Result[] memory returnData);
426    /// }
427    /// ```
428    ///
429    /// ## Returns
430    ///
431    /// - A tuple of the decoded return values for the calls.
432    /// - Each return value is wrapped in a [`Result`] struct.
433    /// - The [`Result::Ok`] variant contains the decoded return value.
434    /// - The [`Result::Err`] variant contains the [`Failure`] struct which holds the
435    ///   index(-position) of the call and the returned data as [`Bytes`].
436    ///
437    /// # Examples
438    ///
439    /// ```ignore
440    /// use alloy_primitives::address;
441    /// use alloy_provider::{MulticallBuilder, Provider, ProviderBuilder};
442    /// use alloy_sol_types::sol;
443    ///
444    /// sol! {
445    ///    #[sol(rpc)]
446    ///    #[derive(Debug, PartialEq)]
447    ///    interface ERC20 {
448    ///        function totalSupply() external view returns (uint256 totalSupply);
449    ///        function balanceOf(address owner) external view returns (uint256 balance);
450    ///    }
451    /// }
452    ///
453    /// #[tokio::main]
454    /// async fn main() {
455    ///     let weth = address!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2");
456    ///     let provider = ProviderBuilder::new().connect_http("https://eth.merkle.io".parse().unwrap());
457    ///     let erc20 = ERC20::new(weth, &provider);
458    ///
459    ///     let ts_call = erc20.totalSupply();
460    ///     let balance_call = erc20.balanceOf(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"));
461    ///
462    ///     let multicall = provider.multicall().add(ts_call).add(balance_call);
463    ///
464    ///     let (total_supply, balance) = multicall.try_aggregate(true).await.unwrap();
465    ///
466    ///     assert!(total_supply.is_ok());
467    ///     assert!(balance.is_ok());
468    /// }
469    /// ```
470    pub async fn try_aggregate(&self, require_success: bool) -> Result<T::Returns> {
471        let output = self.build_and_call(self.to_try_aggregate_call(require_success), None).await?;
472        T::decode_return_results(&output)
473    }
474    /// Sends the `tryAggregate` function as a transaction
475    pub async fn send_try_aggregate(
476        &self,
477        require_success: bool,
478    ) -> Result<PendingTransactionBuilder<N>> {
479        self.build_and_send(self.to_try_aggregate_call(require_success), None).await
480    }
481
482    /// Encodes the calls for the `tryAggregateCall` function and returns the populated transaction
483    /// request.
484    pub fn to_try_aggregate_request(&self, require_success: bool) -> N::TransactionRequest {
485        self.build_request(self.to_try_aggregate_call(require_success), None)
486    }
487
488    /// Creates the [`tryAggregateCall`].
489    fn to_try_aggregate_call(&self, require_success: bool) -> tryAggregateCall {
490        let calls = self
491            .calls
492            .iter()
493            .map(|c| Call { target: c.target, callData: c.callData.clone() })
494            .collect::<Vec<_>>();
495        tryAggregateCall { requireSuccess: require_success, calls }
496    }
497
498    /// Call the `aggregate3` function
499    ///
500    /// Doesn't require that all calls succeed, reverts only if a call with `allowFailure` set to
501    /// false, fails.
502    ///
503    /// By default, adding a call via [`MulticallBuilder::add`] sets `allow_failure` to false.
504    ///
505    /// You can add a call that allows failure by using [`MulticallBuilder::add_call`], and setting
506    /// `allow_failure` to true in [`CallItem`].
507    ///
508    /// ## Solidity Function Signature
509    ///
510    /// ```ignore
511    /// sol! {
512    ///     function aggregate3(Call3[] calldata calls) external payable returns (Result[] memory returnData);
513    /// }
514    /// ```
515    ///
516    /// ## Returns
517    ///
518    /// - A tuple of the decoded return values for the calls.
519    /// - Each return value is wrapped in a [`Result`] struct.
520    /// - The [`Result::Ok`] variant contains the decoded return value.
521    /// - The [`Result::Err`] variant contains the [`Failure`] struct which holds the
522    ///   index(-position) of the call and the returned data as [`Bytes`].
523    pub async fn aggregate3(&self) -> Result<T::Returns> {
524        let call = self.to_aggregate3_call();
525        let output = self.build_and_call(call, None).await?;
526        T::decode_return_results(&output)
527    }
528
529    /// Sends the `aggregate3` function as a transaction
530    pub async fn send_aggregate3(&self) -> Result<PendingTransactionBuilder<N>> {
531        self.build_and_send(self.to_aggregate3_call(), None).await
532    }
533
534    /// Encodes the calls for the `aggregate3` function and returns the populated transaction
535    /// request.
536    pub fn to_aggregate3_request(&self) -> N::TransactionRequest {
537        self.build_request(self.to_aggregate3_call(), None)
538    }
539
540    /// Sends the `aggregate3Value` function as a transaction
541    pub async fn send_aggregate3_value(&self) -> Result<PendingTransactionBuilder<N>> {
542        let total_value = self.calls.iter().map(|c| c.value).fold(U256::ZERO, |acc, x| acc + x);
543        let call = self.to_aggregate3_value_call();
544        self.build_and_send(call, Some(total_value)).await
545    }
546
547    /// Creates the [`aggregate3Call`]
548    fn to_aggregate3_call(&self) -> aggregate3Call {
549        let calls = self
550            .calls
551            .iter()
552            .map(|c| Call3 {
553                target: c.target,
554                callData: c.callData.clone(),
555                allowFailure: c.allowFailure,
556            })
557            .collect::<Vec<_>>();
558        aggregate3Call { calls }
559    }
560
561    /// Call the `aggregate3Value` function
562    ///
563    /// Similar to `aggregate3` allows for calls to fail. Moreover, it allows for calling into
564    /// `payable` functions with the `value` parameter.
565    ///
566    /// One can set the `value` field in the [`CallItem`] struct and use
567    /// [`MulticallBuilder::add_call`] to add it to the stack.
568    ///
569    /// It is important to note the `aggregate3Value` only succeeds when `msg.value` is _strictly_
570    /// equal to the sum of the values of all calls. Summing up the values of all calls and setting
571    /// it in the transaction request is handled internally by the builder.
572    ///
573    /// ## Solidity Function Signature
574    ///
575    /// ```ignore
576    /// sol! {
577    ///     function aggregate3Value(Call3Value[] calldata calls) external payable returns (Result[] memory returnData);
578    /// }
579    /// ```
580    ///
581    /// ## Returns
582    ///
583    /// - A tuple of the decoded return values for the calls.
584    /// - Each return value is wrapped in a [`Result`] struct.
585    /// - The [`Result::Ok`] variant contains the decoded return value.
586    /// - The [`Result::Err`] variant contains the [`Failure`] struct which holds the
587    ///   index(-position) of the call and the returned data as [`Bytes`].
588    pub async fn aggregate3_value(&self) -> Result<T::Returns> {
589        let total_value = self.calls.iter().map(|c| c.value).fold(U256::ZERO, |acc, x| acc + x);
590        let call = aggregate3ValueCall { calls: self.calls.to_vec() };
591        let output = self.build_and_call(call, Some(total_value)).await?;
592        T::decode_return_results(&output)
593    }
594
595    /// Call the `blockAndAggregate` function
596    pub async fn block_and_aggregate(&self) -> Result<(u64, B256, T::SuccessReturns)> {
597        let calls = self
598            .calls
599            .iter()
600            .map(|c| Call { target: c.target, callData: c.callData.clone() })
601            .collect::<Vec<_>>();
602        let call = blockAndAggregateCall { calls };
603        let output = self.build_and_call(call, None).await?;
604        let blockAndAggregateReturn { blockNumber, blockHash, returnData } = output;
605        let result = T::decode_return_results(&returnData)?;
606        Ok((blockNumber.to::<u64>(), blockHash, T::try_into_success(result)?))
607    }
608    /// Sends the `blockAndAggregate` function as a transaction
609    pub async fn send_block_and_aggregate(&self) -> Result<PendingTransactionBuilder<N>> {
610        let call = self.to_block_and_aggregate_call();
611        self.build_and_send(call, None).await
612    }
613
614    /// Call the `tryBlockAndAggregate` function
615    pub async fn try_block_and_aggregate(
616        &self,
617        require_success: bool,
618    ) -> Result<(u64, B256, T::Returns)> {
619        let calls = self
620            .calls
621            .iter()
622            .map(|c| Call { target: c.target, callData: c.callData.clone() })
623            .collect::<Vec<_>>();
624        let call = tryBlockAndAggregateCall { requireSuccess: require_success, calls };
625        let output = self.build_and_call(call, None).await?;
626        let tryBlockAndAggregateReturn { blockNumber, blockHash, returnData } = output;
627        Ok((blockNumber.to::<u64>(), blockHash, T::decode_return_results(&returnData)?))
628    }
629
630    /// Sends the `tryBlockAndAggregate` function as a transaction  
631    pub async fn send_try_block_and_aggregate(
632        &self,
633        require_success: bool,
634    ) -> Result<PendingTransactionBuilder<N>> {
635        let call = self.to_try_block_and_aggregate_call(require_success);
636        self.build_and_send(call, None).await
637    }
638
639    /// Helper for building the transaction request for the given call type input.
640    fn build_request<M: SolCall>(
641        &self,
642        call_type: M,
643        value: Option<U256>,
644    ) -> N::TransactionRequest {
645        let call = call_type.abi_encode();
646        let mut tx = N::TransactionRequest::default()
647            .with_to(self.address)
648            .with_input_kind(Bytes::from_iter(call), self.input_kind);
649
650        if let Some(value) = value {
651            tx.set_value(value);
652        }
653        tx
654    }
655
656    /// Helper fn to build a tx and call the multicall contract
657    ///
658    /// ## Params
659    ///
660    /// - `call_type`: The [`SolCall`] being made.
661    /// - `value`: Total value to send with the call in case of `aggregate3Value` request.
662    async fn build_and_call<M: SolCall>(
663        &self,
664        call_type: M,
665        value: Option<U256>,
666    ) -> Result<M::Return> {
667        let tx = self.build_request(call_type, value);
668
669        let mut eth_call = self.provider.root().call(tx);
670
671        if let Some(block) = self.block {
672            eth_call = eth_call.block(block);
673        }
674
675        if let Some(overrides) = self.state_override.clone() {
676            eth_call = eth_call.overrides(overrides);
677        }
678
679        let res = eth_call.await.map_err(MulticallError::TransportError)?;
680        M::abi_decode_returns(&res).map_err(MulticallError::DecodeError)
681    }
682
683    async fn build_and_send<M: SolCall>(
684        &self,
685        call_type: M,
686        value: Option<U256>,
687    ) -> Result<PendingTransactionBuilder<N>> {
688        let tx = self.build_request(call_type, value);
689
690        let pending_tx =
691            self.provider.send_transaction(tx).await.map_err(MulticallError::TransportError)?;
692
693        Ok(pending_tx)
694    }
695
696    /// Add a call to get the block hash from a block number
697    pub fn get_block_hash(self, number: BlockNumber) -> MulticallBuilder<T::Pushed, P, N>
698    where
699        T: TuplePush<getBlockHashCall>,
700        T::Pushed: CallTuple,
701    {
702        let call = CallItem::<getBlockHashCall>::new(
703            self.address,
704            getBlockHashCall { blockNumber: U256::from(number) }.abi_encode().into(),
705        );
706        self.add_call(call)
707    }
708
709    /// Add a call to get the coinbase of the current block
710    pub fn get_current_block_coinbase(self) -> MulticallBuilder<T::Pushed, P, N>
711    where
712        T: TuplePush<getCurrentBlockCoinbaseCall>,
713        T::Pushed: CallTuple,
714    {
715        let call = CallItem::<getCurrentBlockCoinbaseCall>::new(
716            self.address,
717            getCurrentBlockCoinbaseCall {}.abi_encode().into(),
718        );
719        self.add_call(call)
720    }
721
722    /// Add a call to get the current block number
723    pub fn get_block_number(self) -> MulticallBuilder<T::Pushed, P, N>
724    where
725        T: TuplePush<getBlockNumberCall>,
726        T::Pushed: CallTuple,
727    {
728        let call = CallItem::<getBlockNumberCall>::new(
729            self.address,
730            getBlockNumberCall {}.abi_encode().into(),
731        );
732        self.add_call(call)
733    }
734
735    /// Add a call to get the current block difficulty
736    pub fn get_current_block_difficulty(self) -> MulticallBuilder<T::Pushed, P, N>
737    where
738        T: TuplePush<getCurrentBlockDifficultyCall>,
739        T::Pushed: CallTuple,
740    {
741        let call = CallItem::<getCurrentBlockDifficultyCall>::new(
742            self.address,
743            getCurrentBlockDifficultyCall {}.abi_encode().into(),
744        );
745        self.add_call(call)
746    }
747
748    /// Add a call to get the current block gas limit
749    pub fn get_current_block_gas_limit(self) -> MulticallBuilder<T::Pushed, P, N>
750    where
751        T: TuplePush<getCurrentBlockGasLimitCall>,
752        T::Pushed: CallTuple,
753    {
754        let call = CallItem::<getCurrentBlockGasLimitCall>::new(
755            self.address,
756            getCurrentBlockGasLimitCall {}.abi_encode().into(),
757        );
758        self.add_call(call)
759    }
760
761    /// Add a call to get the current block timestamp
762    pub fn get_current_block_timestamp(self) -> MulticallBuilder<T::Pushed, P, N>
763    where
764        T: TuplePush<getCurrentBlockTimestampCall>,
765        T::Pushed: CallTuple,
766    {
767        let call = CallItem::<getCurrentBlockTimestampCall>::new(
768            self.address,
769            getCurrentBlockTimestampCall {}.abi_encode().into(),
770        );
771        self.add_call(call)
772    }
773
774    /// Add a call to get the chain id
775    pub fn get_chain_id(self) -> MulticallBuilder<T::Pushed, P, N>
776    where
777        T: TuplePush<getChainIdCall>,
778        T::Pushed: CallTuple,
779    {
780        let call =
781            CallItem::<getChainIdCall>::new(self.address, getChainIdCall {}.abi_encode().into());
782        self.add_call(call)
783    }
784
785    /// Add a call to get the base fee
786    pub fn get_base_fee(self) -> MulticallBuilder<T::Pushed, P, N>
787    where
788        T: TuplePush<getBasefeeCall>,
789        T::Pushed: CallTuple,
790    {
791        let call =
792            CallItem::<getBasefeeCall>::new(self.address, getBasefeeCall {}.abi_encode().into());
793        self.add_call(call)
794    }
795
796    /// Add a call to get the eth balance of an address
797    pub fn get_eth_balance(self, address: Address) -> MulticallBuilder<T::Pushed, P, N>
798    where
799        T: TuplePush<getEthBalanceCall>,
800        T::Pushed: CallTuple,
801    {
802        let call = CallItem::<getEthBalanceCall>::new(
803            self.address,
804            getEthBalanceCall { addr: address }.abi_encode().into(),
805        );
806        self.add_call(call)
807    }
808
809    /// Add a call to get the last block hash
810    pub fn get_last_block_hash(self) -> MulticallBuilder<T::Pushed, P, N>
811    where
812        T: TuplePush<getLastBlockHashCall>,
813        T::Pushed: CallTuple,
814    {
815        let call = CallItem::<getLastBlockHashCall>::new(
816            self.address,
817            getLastBlockHashCall {}.abi_encode().into(),
818        );
819        self.add_call(call)
820    }
821
822    /// Returns an [`Empty`] builder
823    ///
824    /// Retains previously set provider, address, block and state_override settings.
825    pub fn clear(self) -> MulticallBuilder<Empty, P, N> {
826        MulticallBuilder {
827            calls: Vec::new(),
828            provider: self.provider,
829            block: self.block,
830            state_override: self.state_override,
831            address: self.address,
832            input_kind: self.input_kind,
833            _pd: Default::default(),
834        }
835    }
836
837    /// Get the number of calls in the builder
838    pub const fn len(&self) -> usize {
839        self.calls.len()
840    }
841
842    /// Check if the builder is empty
843    pub const fn is_empty(&self) -> bool {
844        self.calls.is_empty()
845    }
846
847    /// Set the input kind for this builder
848    pub const fn with_input_kind(mut self, input_kind: TransactionInputKind) -> Self {
849        self.input_kind = input_kind;
850        self
851    }
852
853    /// Get the input kind for this builder
854    pub const fn input_kind(&self) -> TransactionInputKind {
855        self.input_kind
856    }
857}