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