alloy_provider/provider/multicall/mod.rs
1//! A Multicall Builder
2
3use crate::Provider;
4use alloy_network::{Network, TransactionBuilder};
5use alloy_primitives::{address, Address, BlockNumber, Bytes, B256, U256};
6use alloy_rpc_types_eth::{state::StateOverride, BlockId};
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/// ## Example
42///
43/// ```ignore
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 = ProviderBuilder::new().connect_http("https://eth.merkle.io".parse().unwrap());
61/// let erc20 = ERC20::new(weth, &provider);
62///
63/// let ts_call = erc20.totalSupply();
64/// let balance_call = erc20.balanceOf(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"));
65///
66/// let multicall = provider.multicall().add(ts_call).add(balance_call);
67///
68/// let (total_supply, balance) = multicall.aggregate().await.unwrap();
69///
70/// println!("Total Supply: {:?}, Balance: {:?}", total_supply, balance);
71/// }
72/// ```
73#[derive(Debug)]
74pub struct MulticallBuilder<T: CallTuple, P: Provider<N>, N: Network> {
75 /// Batched calls
76 calls: Vec<Call3Value>,
77 /// The provider to use
78 provider: P,
79 /// The [`BlockId`] to use for the call
80 block: Option<BlockId>,
81 /// The [`StateOverride`] for the call
82 state_override: Option<StateOverride>,
83 /// This is the address of the [`IMulticall3`](crate::bindings::IMulticall3)
84 /// contract.
85 ///
86 /// By default it is set to [`MULTICALL3_ADDRESS`].
87 address: Address,
88 _pd: std::marker::PhantomData<(T, N)>,
89}
90
91impl<P, N> MulticallBuilder<Empty, P, N>
92where
93 P: Provider<N>,
94 N: Network,
95{
96 /// Instantiate a new [`MulticallBuilder`]
97 pub fn new(provider: P) -> Self {
98 Self {
99 calls: Vec::new(),
100 provider,
101 _pd: Default::default(),
102 block: None,
103 state_override: None,
104 address: MULTICALL3_ADDRESS,
105 }
106 }
107}
108
109impl<D: SolCall + 'static, P, N> MulticallBuilder<Dynamic<D>, P, N>
110where
111 P: Provider<N>,
112 N: Network,
113{
114 /// Instantiate a new [`MulticallBuilder`] that restricts the calls to a specific call type.
115 ///
116 /// Multicalls made using this builder return a vector of the decoded return values.
117 ///
118 /// An example would be trying to fetch multiple ERC20 balances of an address.
119 ///
120 /// ## Example
121 ///
122 /// ```ignore
123 /// use alloy_primitives::address;
124 /// use alloy_provider::{MulticallBuilder, Provider, ProviderBuilder};
125 /// use alloy_sol_types::sol;
126 ///
127 /// sol! {
128 /// #[sol(rpc)]
129 /// #[derive(Debug, PartialEq)]
130 /// interface ERC20 {
131 /// function balanceOf(address owner) external view returns (uint256 balance);
132 /// }
133 /// }
134 ///
135 /// #[tokio::main]
136 /// async fn main() {
137 /// let weth = address!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2");
138 /// let usdc = address!("A0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48");
139 ///
140 /// let provider = ProviderBuilder::new().connect_http("https://eth.merkle.io".parse().unwrap());
141 /// let weth = ERC20::new(weth, &provider);
142 /// let usdc = ERC20::new(usdc, &provider);
143 ///
144 /// let owner = address!("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045");
145 ///
146 /// let mut erc20_balances = MulticallBuilder::new_dynamic(provider);
147 ///
148 /// for token in &[weth, usdc] {
149 /// erc20_balances = erc20_balances.add_dynamic(token.balanceOf(owner));
150 /// }
151 ///
152 /// let balances: Vec<ERC20::balanceOfReturn> = erc20_balances.aggregate().await.unwrap();
153 ///
154 /// let weth_bal = &balances[0];
155 /// let usdc_bal = &balances[1];
156 /// println!("WETH Balance: {:?}, USDC Balance: {:?}", weth_bal, usdc_bal);
157 /// }
158 pub fn new_dynamic(provider: P) -> Self {
159 Self {
160 calls: Vec::new(),
161 provider,
162 block: None,
163 state_override: None,
164 address: MULTICALL3_ADDRESS,
165 _pd: Default::default(),
166 }
167 }
168
169 /// Add a dynamic call to the builder
170 pub fn add_dynamic(mut self, item: impl MulticallItem<Decoder = D>) -> Self {
171 let target = item.target();
172 let input = item.input();
173
174 let call = CallItem::<D>::new(target, input);
175
176 self.calls.push(call.to_call3_value());
177 self
178 }
179
180 /// Add a dynamic [`CallItem`] to the builder
181 pub fn add_call_dynamic(mut self, call: CallItem<D>) -> Self {
182 self.calls.push(call.to_call3_value());
183 self
184 }
185
186 /// Extend the builder with a sequence of calls
187 pub fn extend(
188 mut self,
189 items: impl IntoIterator<Item = impl MulticallItem<Decoder = D>>,
190 ) -> Self {
191 for item in items {
192 self = self.add_dynamic(item);
193 }
194 self
195 }
196
197 /// Extend the builder with a sequence of [`CallItem`]s
198 pub fn extend_calls(mut self, calls: impl IntoIterator<Item = CallItem<D>>) -> Self {
199 for call in calls {
200 self = self.add_call_dynamic(call);
201 }
202 self
203 }
204}
205
206impl<T, P, N> MulticallBuilder<T, &P, N>
207where
208 T: CallTuple,
209 P: Provider<N> + Clone,
210 N: Network,
211{
212 /// Clones the underlying provider and returns a new [`MulticallBuilder`].
213 pub fn with_cloned_provider(&self) -> MulticallBuilder<Empty, P, N> {
214 MulticallBuilder {
215 calls: Vec::new(),
216 provider: self.provider.clone(),
217 block: None,
218 state_override: None,
219 address: MULTICALL3_ADDRESS,
220 _pd: Default::default(),
221 }
222 }
223}
224
225impl<T, P, N> MulticallBuilder<T, P, N>
226where
227 T: CallTuple,
228 P: Provider<N>,
229 N: Network,
230{
231 /// Set the address of the multicall3 contract
232 ///
233 /// Default is [`MULTICALL3_ADDRESS`].
234 pub const fn address(mut self, address: Address) -> Self {
235 self.address = address;
236 self
237 }
238
239 /// Sets the block to be used for the call.
240 pub const fn block(mut self, block: BlockId) -> Self {
241 self.block = Some(block);
242 self
243 }
244
245 /// Set the state overrides for the call.
246 pub fn overrides(mut self, state_override: impl Into<StateOverride>) -> Self {
247 self.state_override = Some(state_override.into());
248 self
249 }
250
251 /// Appends a [`SolCall`] to the stack.
252 #[expect(clippy::should_implement_trait)]
253 pub fn add<Item: MulticallItem>(self, item: Item) -> MulticallBuilder<T::Pushed, P, N>
254 where
255 Item::Decoder: 'static,
256 T: TuplePush<Item::Decoder>,
257 <T as TuplePush<Item::Decoder>>::Pushed: CallTuple,
258 {
259 let target = item.target();
260 let input = item.input();
261
262 let call = CallItem::<Item::Decoder>::new(target, input);
263
264 self.add_call(call)
265 }
266
267 /// Appends a [`CallItem`] to the stack.
268 pub fn add_call<D>(mut self, call: CallItem<D>) -> MulticallBuilder<T::Pushed, P, N>
269 where
270 D: SolCall + 'static,
271 T: TuplePush<D>,
272 <T as TuplePush<D>>::Pushed: CallTuple,
273 {
274 self.calls.push(call.to_call3_value());
275 MulticallBuilder {
276 calls: self.calls,
277 provider: self.provider,
278 block: self.block,
279 state_override: self.state_override,
280 address: self.address,
281 _pd: Default::default(),
282 }
283 }
284
285 /// Calls the `aggregate` function
286 ///
287 /// Requires that all calls succeed, else reverts.
288 ///
289 /// ## Solidity Function Signature
290 ///
291 /// ```ignore
292 /// sol! {
293 /// function aggregate(Call[] memory calls) external returns (uint256 blockNumber, bytes[] memory returnData);
294 /// }
295 /// ```
296 ///
297 /// ## Returns
298 ///
299 /// - `returnData`: A tuple of the decoded return values for the calls
300 ///
301 /// One can obtain the block context such as block number and block hash by using the
302 /// [MulticallBuilder::block_and_aggregate] function.
303 ///
304 /// ## Example
305 ///
306 /// ```ignore
307 /// use alloy_primitives::address;
308 /// use alloy_provider::{MulticallBuilder, Provider, ProviderBuilder};
309 /// use alloy_sol_types::sol;
310 ///
311 /// sol! {
312 /// #[sol(rpc)]
313 /// #[derive(Debug, PartialEq)]
314 /// interface ERC20 {
315 /// function totalSupply() external view returns (uint256 totalSupply);
316 /// function balanceOf(address owner) external view returns (uint256 balance);
317 /// }
318 /// }
319 ///
320 /// #[tokio::main]
321 /// async fn main() {
322 /// let weth = address!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2");
323 /// let provider = ProviderBuilder::new().connect_http("https://eth.merkle.io".parse().unwrap());
324 /// let erc20 = ERC20::new(weth, &provider);
325 ///
326 /// let ts_call = erc20.totalSupply();
327 /// let balance_call = erc20.balanceOf(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"));
328 ///
329 /// let multicall = provider.multicall().add(ts_call).add(balance_call);
330 ///
331 /// let (total_supply, balance) = multicall.aggregate().await.unwrap();
332 ///
333 /// println!("Total Supply: {:?}, Balance: {:?}", total_supply, balance);
334 /// }
335 /// ```
336 pub async fn aggregate(&self) -> Result<T::SuccessReturns> {
337 let calls = self
338 .calls
339 .iter()
340 .map(|c| Call { target: c.target, callData: c.callData.clone() })
341 .collect::<Vec<_>>();
342 let call = aggregateCall { calls: calls.to_vec() };
343 let output = self.build_and_call(call, None).await?;
344 T::decode_returns(&output.returnData)
345 }
346
347 /// Call the `tryAggregate` function
348 ///
349 /// Allows for calls to fail by setting `require_success` to false.
350 ///
351 /// ## Solidity Function Signature
352 ///
353 /// ```ignore
354 /// sol! {
355 /// function tryAggregate(bool requireSuccess, Call[] calldata calls) external payable returns (Result[] memory returnData);
356 /// }
357 /// ```
358 ///
359 /// ## Returns
360 ///
361 /// - A tuple of the decoded return values for the calls.
362 /// - Each return value is wrapped in a [`Result`] struct.
363 /// - The [`Result::Ok`] variant contains the decoded return value.
364 /// - The [`Result::Err`] variant contains the [`Failure`] struct which holds the
365 /// index(-position) of the call and the returned data as [`Bytes`].
366 ///
367 /// ## Example
368 ///
369 /// ```ignore
370 /// use alloy_primitives::address;
371 /// use alloy_provider::{MulticallBuilder, Provider, ProviderBuilder};
372 /// use alloy_sol_types::sol;
373 ///
374 /// sol! {
375 /// #[sol(rpc)]
376 /// #[derive(Debug, PartialEq)]
377 /// interface ERC20 {
378 /// function totalSupply() external view returns (uint256 totalSupply);
379 /// function balanceOf(address owner) external view returns (uint256 balance);
380 /// }
381 /// }
382 ///
383 /// #[tokio::main]
384 /// async fn main() {
385 /// let weth = address!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2");
386 /// let provider = ProviderBuilder::new().connect_http("https://eth.merkle.io".parse().unwrap());
387 /// let erc20 = ERC20::new(weth, &provider);
388 ///
389 /// let ts_call = erc20.totalSupply();
390 /// let balance_call = erc20.balanceOf(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"));
391 ///
392 /// let multicall = provider.multicall().add(ts_call).add(balance_call);
393 ///
394 /// let (total_supply, balance) = multicall.try_aggregate(true).await.unwrap();
395 ///
396 /// assert!(total_supply.is_ok());
397 /// assert!(balance.is_ok());
398 /// }
399 /// ```
400 pub async fn try_aggregate(&self, require_success: bool) -> Result<T::Returns> {
401 let calls = &self
402 .calls
403 .iter()
404 .map(|c| Call { target: c.target, callData: c.callData.clone() })
405 .collect::<Vec<_>>();
406 let call = tryAggregateCall { requireSuccess: require_success, calls: calls.to_vec() };
407 let output = self.build_and_call(call, None).await?;
408 T::decode_return_results(&output)
409 }
410
411 /// Call the `aggregate3` function
412 ///
413 /// Doesn't require that all calls succeed, reverts only if a call with `allowFailure` set to
414 /// false, fails.
415 ///
416 /// By default, adding a call via [`MulticallBuilder::add`] sets `allow_failure` to false.
417 ///
418 /// You can add a call that allows failure by using [`MulticallBuilder::add_call`], and setting
419 /// `allow_failure` to true in [`CallItem`].
420 ///
421 /// ## Solidity Function Signature
422 ///
423 /// ```ignore
424 /// sol! {
425 /// function aggregate3(Call3[] 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 pub async fn aggregate3(&self) -> Result<T::Returns> {
437 let calls = self
438 .calls
439 .iter()
440 .map(|c| Call3 {
441 target: c.target,
442 callData: c.callData.clone(),
443 allowFailure: c.allowFailure,
444 })
445 .collect::<Vec<_>>();
446 let call = aggregate3Call { calls: calls.to_vec() };
447 let output = self.build_and_call(call, None).await?;
448 T::decode_return_results(&output)
449 }
450
451 /// Call the `aggregate3Value` function
452 ///
453 /// Similar to `aggregate3` allows for calls to fail. Moreover, it allows for calling into
454 /// `payable` functions with the `value` parameter.
455 ///
456 /// One can set the `value` field in the [`CallItem`] struct and use
457 /// [`MulticallBuilder::add_call`] to add it to the stack.
458 ///
459 /// It is important to note the `aggregate3Value` only succeeds when `msg.value` is _strictly_
460 /// equal to the sum of the values of all calls. Summing up the values of all calls and setting
461 /// it in the transaction request is handled internally by the builder.
462 ///
463 /// ## Solidity Function Signature
464 ///
465 /// ```ignore
466 /// sol! {
467 /// function aggregate3Value(Call3Value[] calldata calls) external payable returns (Result[] memory returnData);
468 /// }
469 /// ```
470 ///
471 /// ## Returns
472 ///
473 /// - A tuple of the decoded return values for the calls.
474 /// - Each return value is wrapped in a [`Result`] struct.
475 /// - The [`Result::Ok`] variant contains the decoded return value.
476 /// - The [`Result::Err`] variant contains the [`Failure`] struct which holds the
477 /// index(-position) of the call and the returned data as [`Bytes`].
478 pub async fn aggregate3_value(&self) -> Result<T::Returns> {
479 let total_value = self.calls.iter().map(|c| c.value).fold(U256::ZERO, |acc, x| acc + x);
480 let call = aggregate3ValueCall { calls: self.calls.to_vec() };
481 let output = self.build_and_call(call, Some(total_value)).await?;
482 T::decode_return_results(&output)
483 }
484
485 /// Call the `blockAndAggregate` function
486 pub async fn block_and_aggregate(&self) -> Result<(u64, B256, T::SuccessReturns)> {
487 let calls = self
488 .calls
489 .iter()
490 .map(|c| Call { target: c.target, callData: c.callData.clone() })
491 .collect::<Vec<_>>();
492 let call = blockAndAggregateCall { calls: calls.to_vec() };
493 let output = self.build_and_call(call, None).await?;
494 let blockAndAggregateReturn { blockNumber, blockHash, returnData } = output;
495 let result = T::decode_return_results(&returnData)?;
496 Ok((blockNumber.to::<u64>(), blockHash, T::try_into_success(result)?))
497 }
498
499 /// Call the `tryBlockAndAggregate` function
500 pub async fn try_block_and_aggregate(
501 &self,
502 require_success: bool,
503 ) -> Result<(u64, B256, T::Returns)> {
504 let calls = self
505 .calls
506 .iter()
507 .map(|c| Call { target: c.target, callData: c.callData.clone() })
508 .collect::<Vec<_>>();
509 let call =
510 tryBlockAndAggregateCall { requireSuccess: require_success, calls: calls.to_vec() };
511 let output = self.build_and_call(call, None).await?;
512 let tryBlockAndAggregateReturn { blockNumber, blockHash, returnData } = output;
513 Ok((blockNumber.to::<u64>(), blockHash, T::decode_return_results(&returnData)?))
514 }
515
516 /// Helper fn to build a tx and call the multicall contract
517 ///
518 /// ## Params
519 ///
520 /// - `call_type`: The [`SolCall`] being made.
521 /// - `value`: Total value to send with the call in case of `aggregate3Value` request.
522 async fn build_and_call<M: SolCall>(
523 &self,
524 call_type: M,
525 value: Option<U256>,
526 ) -> Result<M::Return> {
527 let call = call_type.abi_encode();
528 let mut tx = N::TransactionRequest::default()
529 .with_to(self.address)
530 .with_input(Bytes::from_iter(call));
531
532 if let Some(value) = value {
533 tx.set_value(value);
534 }
535
536 let mut eth_call = self.provider.root().call(tx);
537
538 if let Some(block) = self.block {
539 eth_call = eth_call.block(block);
540 }
541
542 if let Some(overrides) = self.state_override.clone() {
543 eth_call = eth_call.overrides(overrides);
544 }
545
546 let res = eth_call.await.map_err(MulticallError::TransportError)?;
547 M::abi_decode_returns(&res).map_err(MulticallError::DecodeError)
548 }
549
550 /// Add a call to get the block hash from a block number
551 pub fn get_block_hash(self, number: BlockNumber) -> MulticallBuilder<T::Pushed, P, N>
552 where
553 T: TuplePush<getBlockHashCall>,
554 T::Pushed: CallTuple,
555 {
556 let call = CallItem::<getBlockHashCall>::new(
557 self.address,
558 getBlockHashCall { blockNumber: U256::from(number) }.abi_encode().into(),
559 );
560 self.add_call(call)
561 }
562
563 /// Add a call to get the coinbase of the current block
564 pub fn get_current_block_coinbase(self) -> MulticallBuilder<T::Pushed, P, N>
565 where
566 T: TuplePush<getCurrentBlockCoinbaseCall>,
567 T::Pushed: CallTuple,
568 {
569 let call = CallItem::<getCurrentBlockCoinbaseCall>::new(
570 self.address,
571 getCurrentBlockCoinbaseCall {}.abi_encode().into(),
572 );
573 self.add_call(call)
574 }
575
576 /// Add a call to get the current block number
577 pub fn get_block_number(self) -> MulticallBuilder<T::Pushed, P, N>
578 where
579 T: TuplePush<getBlockNumberCall>,
580 T::Pushed: CallTuple,
581 {
582 let call = CallItem::<getBlockNumberCall>::new(
583 self.address,
584 getBlockNumberCall {}.abi_encode().into(),
585 );
586 self.add_call(call)
587 }
588
589 /// Add a call to get the current block difficulty
590 pub fn get_current_block_difficulty(self) -> MulticallBuilder<T::Pushed, P, N>
591 where
592 T: TuplePush<getCurrentBlockDifficultyCall>,
593 T::Pushed: CallTuple,
594 {
595 let call = CallItem::<getCurrentBlockDifficultyCall>::new(
596 self.address,
597 getCurrentBlockDifficultyCall {}.abi_encode().into(),
598 );
599 self.add_call(call)
600 }
601
602 /// Add a call to get the current block gas limit
603 pub fn get_current_block_gas_limit(self) -> MulticallBuilder<T::Pushed, P, N>
604 where
605 T: TuplePush<getCurrentBlockGasLimitCall>,
606 T::Pushed: CallTuple,
607 {
608 let call = CallItem::<getCurrentBlockGasLimitCall>::new(
609 self.address,
610 getCurrentBlockGasLimitCall {}.abi_encode().into(),
611 );
612 self.add_call(call)
613 }
614
615 /// Add a call to get the current block timestamp
616 pub fn get_current_block_timestamp(self) -> MulticallBuilder<T::Pushed, P, N>
617 where
618 T: TuplePush<getCurrentBlockTimestampCall>,
619 T::Pushed: CallTuple,
620 {
621 let call = CallItem::<getCurrentBlockTimestampCall>::new(
622 self.address,
623 getCurrentBlockTimestampCall {}.abi_encode().into(),
624 );
625 self.add_call(call)
626 }
627
628 /// Add a call to get the chain id
629 pub fn get_chain_id(self) -> MulticallBuilder<T::Pushed, P, N>
630 where
631 T: TuplePush<getChainIdCall>,
632 T::Pushed: CallTuple,
633 {
634 let call =
635 CallItem::<getChainIdCall>::new(self.address, getChainIdCall {}.abi_encode().into());
636 self.add_call(call)
637 }
638
639 /// Add a call to get the base fee
640 pub fn get_base_fee(self) -> MulticallBuilder<T::Pushed, P, N>
641 where
642 T: TuplePush<getBasefeeCall>,
643 T::Pushed: CallTuple,
644 {
645 let call =
646 CallItem::<getBasefeeCall>::new(self.address, getBasefeeCall {}.abi_encode().into());
647 self.add_call(call)
648 }
649
650 /// Add a call to get the eth balance of an address
651 pub fn get_eth_balance(self, address: Address) -> MulticallBuilder<T::Pushed, P, N>
652 where
653 T: TuplePush<getEthBalanceCall>,
654 T::Pushed: CallTuple,
655 {
656 let call = CallItem::<getEthBalanceCall>::new(
657 self.address,
658 getEthBalanceCall { addr: address }.abi_encode().into(),
659 );
660 self.add_call(call)
661 }
662
663 /// Add a call to get the last block hash
664 pub fn get_last_block_hash(self) -> MulticallBuilder<T::Pushed, P, N>
665 where
666 T: TuplePush<getLastBlockHashCall>,
667 T::Pushed: CallTuple,
668 {
669 let call = CallItem::<getLastBlockHashCall>::new(
670 self.address,
671 getLastBlockHashCall {}.abi_encode().into(),
672 );
673 self.add_call(call)
674 }
675
676 /// Returns an [`Empty`] builder
677 ///
678 /// Retains previously set provider, address, block and state_override settings.
679 pub fn clear(self) -> MulticallBuilder<Empty, P, N> {
680 MulticallBuilder {
681 calls: Vec::new(),
682 provider: self.provider,
683 block: self.block,
684 state_override: self.state_override,
685 address: self.address,
686 _pd: Default::default(),
687 }
688 }
689
690 /// Get the number of calls in the builder
691 pub fn len(&self) -> usize {
692 self.calls.len()
693 }
694
695 /// Check if the builder is empty
696 pub fn is_empty(&self) -> bool {
697 self.calls.is_empty()
698 }
699}