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