1use crate::{
2 fillers::{
3 BlobGasEstimator, BlobGasFiller, CachedNonceManager, ChainIdFiller, FillerControlFlow,
4 GasFiller, JoinFill, NonceFiller, NonceManager, RecommendedFillers, SimpleNonceManager,
5 TxFiller, WalletFiller,
6 },
7 layers::{BlockIdLayer, CallBatchLayer, ChainLayer},
8 provider::SendableTx,
9 utils::Eip1559Estimator,
10 Provider, RootProvider,
11};
12use alloy_chains::NamedChain;
13use alloy_network::{Ethereum, IntoWallet, Network};
14use alloy_primitives::ChainId;
15use alloy_rpc_client::{ClientBuilder, ConnectionConfig, RpcClient};
16use alloy_transport::{TransportConnect, TransportError, TransportResult};
17use std::marker::PhantomData;
18
19pub trait ProviderLayer<P: Provider<N>, N: Network = Ethereum> {
23 type Provider: Provider<N>;
25
26 fn layer(&self, inner: P) -> Self::Provider;
28}
29
30#[derive(Clone, Copy, Debug)]
32pub struct Identity;
33
34impl<N> TxFiller<N> for Identity
35where
36 N: Network,
37{
38 type Fillable = ();
39
40 fn status(&self, _tx: &<N as Network>::TransactionRequest) -> FillerControlFlow {
41 FillerControlFlow::Finished
42 }
43
44 fn fill_sync(&self, _tx: &mut SendableTx<N>) {}
45
46 async fn prepare<P>(
47 &self,
48 _provider: &P,
49 _tx: &N::TransactionRequest,
50 ) -> TransportResult<Self::Fillable> {
51 Ok(())
52 }
53
54 async fn fill(
55 &self,
56 _to_fill: Self::Fillable,
57 tx: SendableTx<N>,
58 ) -> TransportResult<SendableTx<N>> {
59 Ok(tx)
60 }
61}
62
63impl<P, N> ProviderLayer<P, N> for Identity
64where
65 N: Network,
66 P: Provider<N>,
67{
68 type Provider = P;
69
70 fn layer(&self, inner: P) -> Self::Provider {
71 inner
72 }
73}
74
75#[derive(Debug)]
77pub struct Stack<Inner, Outer> {
78 inner: Inner,
79 outer: Outer,
80}
81
82impl<Inner, Outer> Stack<Inner, Outer> {
83 pub const fn new(inner: Inner, outer: Outer) -> Self {
85 Self { inner, outer }
86 }
87}
88
89impl<P, N, Inner, Outer> ProviderLayer<P, N> for Stack<Inner, Outer>
90where
91 N: Network,
92 P: Provider<N>,
93 Inner: ProviderLayer<P, N>,
94 Outer: ProviderLayer<Inner::Provider, N>,
95{
96 type Provider = Outer::Provider;
97
98 fn layer(&self, provider: P) -> Self::Provider {
99 let inner = self.inner.layer(provider);
100
101 self.outer.layer(inner)
102 }
103}
104
105#[derive(Debug)]
146pub struct ProviderBuilder<L, F, N = Ethereum> {
147 layer: L,
148 filler: F,
149 network: PhantomData<fn() -> N>,
150}
151
152impl
153 ProviderBuilder<
154 Identity,
155 JoinFill<Identity, <Ethereum as RecommendedFillers>::RecommendedFillers>,
156 Ethereum,
157 >
158{
159 pub fn new() -> Self {
169 ProviderBuilder::default().with_recommended_fillers()
170 }
171
172 pub fn disable_recommended_fillers(self) -> ProviderBuilder<Identity, Identity, Ethereum> {
177 ProviderBuilder { layer: self.layer, filler: Identity, network: self.network }
178 }
179}
180
181impl<N> Default for ProviderBuilder<Identity, Identity, N> {
182 fn default() -> Self {
183 Self { layer: Identity, filler: Identity, network: PhantomData }
184 }
185}
186
187impl ProviderBuilder<Identity, Identity, Ethereum> {
188 pub fn new_with_network<Net: RecommendedFillers>(
191 ) -> ProviderBuilder<Identity, JoinFill<Identity, Net::RecommendedFillers>, Net> {
192 ProviderBuilder {
193 layer: Identity,
194 filler: JoinFill::new(Identity, Net::recommended_fillers()),
195 network: PhantomData,
196 }
197 }
198}
199
200impl<L, N: Network> ProviderBuilder<L, Identity, N> {
201 pub fn with_recommended_fillers(
203 self,
204 ) -> ProviderBuilder<L, JoinFill<Identity, N::RecommendedFillers>, N>
205 where
206 N: RecommendedFillers,
207 {
208 self.filler(N::recommended_fillers())
209 }
210}
211
212impl<L, F, N> ProviderBuilder<L, F, N> {
213 pub fn apply<T>(self, f: impl FnOnce(Self) -> T) -> T {
218 f(self)
219 }
220
221 pub fn map_layer<L2>(self, f: impl FnOnce(L) -> L2) -> ProviderBuilder<L2, F, N> {
225 ProviderBuilder { layer: f(self.layer), filler: self.filler, network: PhantomData }
226 }
227
228 pub fn map_filler<F2>(self, f: impl FnOnce(F) -> F2) -> ProviderBuilder<L, F2, N> {
232 ProviderBuilder { layer: self.layer, filler: f(self.filler), network: PhantomData }
233 }
234
235 pub fn layer<Inner>(self, layer: Inner) -> ProviderBuilder<Stack<Inner, L>, F, N> {
247 self.map_layer(|current| Stack::new(layer, current))
248 }
249
250 pub fn filler<F2>(self, filler: F2) -> ProviderBuilder<L, JoinFill<F, F2>, N> {
254 self.map_filler(|current| JoinFill::new(current, filler))
255 }
256
257 pub fn network<Net: RecommendedFillers>(
269 self,
270 ) -> ProviderBuilder<L, JoinFill<Identity, Net::RecommendedFillers>, Net> {
271 ProviderBuilder {
272 layer: self.layer,
273 filler: JoinFill::new(Identity, Net::recommended_fillers()),
274 network: PhantomData,
275 }
276 }
277
278 pub fn with_chain(self, chain: NamedChain) -> ProviderBuilder<Stack<ChainLayer, L>, F, N> {
283 self.layer(ChainLayer::new(chain))
284 }
285
286 pub fn with_blob_gas_estimation(self) -> ProviderBuilder<L, JoinFill<F, BlobGasFiller>, N> {
292 self.filler(BlobGasFiller::default())
293 }
294
295 pub fn with_blob_gas_estimator(
299 self,
300 estimator: BlobGasEstimator,
301 ) -> ProviderBuilder<L, JoinFill<F, BlobGasFiller>, N> {
302 self.filler(BlobGasFiller { estimator })
303 }
304
305 pub fn with_gas_estimation(self) -> ProviderBuilder<L, JoinFill<F, GasFiller>, N> {
309 self.filler(GasFiller::default())
310 }
311
312 pub fn with_eip1559_estimator(
316 self,
317 estimator: Eip1559Estimator,
318 ) -> ProviderBuilder<L, JoinFill<F, GasFiller>, N> {
319 self.filler(GasFiller { estimator })
320 }
321
322 pub fn with_nonce_management<M: NonceManager>(
326 self,
327 nonce_manager: M,
328 ) -> ProviderBuilder<L, JoinFill<F, NonceFiller<M>>, N> {
329 self.filler(NonceFiller::new(nonce_manager))
330 }
331
332 pub fn with_simple_nonce_management(
336 self,
337 ) -> ProviderBuilder<L, JoinFill<F, NonceFiller<SimpleNonceManager>>, N> {
338 self.with_nonce_management(SimpleNonceManager::default())
339 }
340
341 pub fn with_cached_nonce_management(
345 self,
346 ) -> ProviderBuilder<L, JoinFill<F, NonceFiller<CachedNonceManager>>, N> {
347 self.with_nonce_management(CachedNonceManager::default())
348 }
349
350 pub fn fetch_chain_id(self) -> ProviderBuilder<L, JoinFill<F, ChainIdFiller>, N> {
355 self.filler(ChainIdFiller::default())
356 }
357
358 pub fn with_chain_id(
362 self,
363 chain_id: ChainId,
364 ) -> ProviderBuilder<L, JoinFill<F, ChainIdFiller>, N> {
365 self.filler(ChainIdFiller::new(Some(chain_id)))
366 }
367
368 pub fn wallet<W: IntoWallet<N>>(
372 self,
373 wallet: W,
374 ) -> ProviderBuilder<L, JoinFill<F, WalletFiller<W::NetworkWallet>>, N>
375 where
376 N: Network,
377 {
378 self.filler(WalletFiller::new(wallet.into_wallet()))
379 }
380
381 pub fn with_call_batching(self) -> ProviderBuilder<Stack<CallBatchLayer, L>, F, N> {
387 self.layer(CallBatchLayer::new())
388 }
389
390 pub fn with_arbitrum_call_batching(self) -> ProviderBuilder<Stack<CallBatchLayer, L>, F, N> {
395 self.layer(CallBatchLayer::new().arbitrum_compat())
396 }
397
398 #[cfg(not(target_family = "wasm"))]
402 pub fn with_caching(
403 self,
404 max_items: u32,
405 ) -> ProviderBuilder<Stack<crate::layers::CacheLayer, L>, F, N> {
406 self.layer(crate::layers::CacheLayer::new(max_items))
407 }
408
409 #[cfg(not(target_family = "wasm"))]
413 pub fn with_default_caching(
414 self,
415 ) -> ProviderBuilder<Stack<crate::layers::CacheLayer, L>, F, N> {
416 self.with_caching(100)
417 }
418
419 pub fn with_default_block(
423 self,
424 block_id: alloy_eips::BlockId,
425 ) -> ProviderBuilder<Stack<BlockIdLayer, L>, F, N> {
426 self.layer(BlockIdLayer::new(block_id))
427 }
428
429 pub fn connect_provider<P>(self, provider: P) -> F::Provider
434 where
435 L: ProviderLayer<P, N>,
436 F: TxFiller<N> + ProviderLayer<L::Provider, N>,
437 P: Provider<N>,
438 N: Network,
439 {
440 let Self { layer, filler, network: PhantomData } = self;
441 let stack = Stack::new(layer, filler);
442 stack.layer(provider)
443 }
444
445 pub fn connect_client(self, client: RpcClient) -> F::Provider
451 where
452 L: ProviderLayer<RootProvider<N>, N>,
453 F: TxFiller<N> + ProviderLayer<L::Provider, N>,
454 N: Network,
455 {
456 self.connect_provider(RootProvider::new(client))
457 }
458
459 pub fn connect_mocked_client(self, asserter: alloy_transport::mock::Asserter) -> F::Provider
465 where
466 L: ProviderLayer<RootProvider<N>, N>,
467 F: TxFiller<N> + ProviderLayer<L::Provider, N>,
468 N: Network,
469 {
470 self.connect_client(RpcClient::mocked(asserter))
471 }
472
473 #[doc(alias = "on_builtin")]
477 pub async fn connect(self, s: &str) -> Result<F::Provider, TransportError>
478 where
479 L: ProviderLayer<RootProvider<N>, N>,
480 F: TxFiller<N> + ProviderLayer<L::Provider, N>,
481 N: Network,
482 {
483 let client = ClientBuilder::default().connect(s).await?;
484 Ok(self.connect_client(client))
485 }
486
487 pub async fn connect_with_config(
513 self,
514 s: &str,
515 config: ConnectionConfig,
516 ) -> Result<F::Provider, TransportError>
517 where
518 L: ProviderLayer<RootProvider<N>, N>,
519 F: TxFiller<N> + ProviderLayer<L::Provider, N>,
520 N: Network,
521 {
522 let client = ClientBuilder::default().connect_with_config(s, config).await?;
523 Ok(self.connect_client(client))
524 }
525
526 pub async fn connect_with<C>(self, connect: &C) -> Result<F::Provider, TransportError>
528 where
529 L: ProviderLayer<RootProvider<N>, N>,
530 F: TxFiller<N> + ProviderLayer<L::Provider, N>,
531 N: Network,
532 C: TransportConnect,
533 {
534 connect
535 .get_transport()
536 .await
537 .map(|t| RpcClient::new(t, connect.is_local()))
538 .map(|client| self.connect_client(client))
539 }
540
541 #[cfg(feature = "pubsub")]
546 pub async fn connect_pubsub_with<C>(self, connect: C) -> Result<F::Provider, TransportError>
547 where
548 L: ProviderLayer<RootProvider<N>, N>,
549 F: TxFiller<N> + ProviderLayer<L::Provider, N>,
550 N: Network,
551 C: alloy_pubsub::PubSubConnect,
552 {
553 ClientBuilder::default().pubsub(connect).await.map(|client| self.connect_client(client))
554 }
555
556 #[cfg(feature = "ws-base")]
558 pub async fn connect_ws(
559 self,
560 connect: alloy_transport_ws::WsConnect,
561 ) -> Result<F::Provider, TransportError>
562 where
563 L: ProviderLayer<RootProvider<N>, N>,
564 F: TxFiller<N> + ProviderLayer<L::Provider, N>,
565 N: Network,
566 {
567 let client = ClientBuilder::default().ws(connect).await?;
568 Ok(self.connect_client(client))
569 }
570
571 #[cfg(feature = "ipc")]
573 pub async fn connect_ipc<T>(
574 self,
575 connect: alloy_transport_ipc::IpcConnect<T>,
576 ) -> Result<F::Provider, TransportError>
577 where
578 alloy_transport_ipc::IpcConnect<T>: alloy_pubsub::PubSubConnect,
579 L: ProviderLayer<RootProvider<N>, N>,
580 F: TxFiller<N> + ProviderLayer<L::Provider, N>,
581 N: Network,
582 {
583 let client = ClientBuilder::default().ipc(connect).await?;
584 Ok(self.connect_client(client))
585 }
586
587 #[cfg(any(test, all(feature = "reqwest", not(all(target_os = "wasi", target_env = "p1")))))]
589 pub fn connect_http(self, url: reqwest::Url) -> F::Provider
590 where
591 L: ProviderLayer<crate::RootProvider<N>, N>,
592 F: TxFiller<N> + ProviderLayer<L::Provider, N>,
593 N: Network,
594 {
595 let client = ClientBuilder::default().http(url);
596 self.connect_client(client)
597 }
598
599 #[cfg(any(test, all(feature = "reqwest", not(all(target_os = "wasi", target_env = "p1")))))]
601 pub fn connect_reqwest<C>(self, client: C, url: reqwest::Url) -> F::Provider
602 where
603 L: ProviderLayer<crate::RootProvider<N>, N>,
604 F: TxFiller<N> + ProviderLayer<L::Provider, N>,
605 N: Network,
606 C: Into<reqwest::Client>,
607 {
608 let client = ClientBuilder::default().http_with_client(client.into(), url);
609 self.connect_client(client)
610 }
611
612 #[cfg(any(test, all(feature = "reqwest", not(all(target_os = "wasi", target_env = "p1")))))]
614 pub fn with_reqwest<B>(self, url: reqwest::Url, builder: B) -> F::Provider
615 where
616 L: ProviderLayer<crate::RootProvider<N>, N>,
617 F: TxFiller<N> + ProviderLayer<L::Provider, N>,
618 N: Network,
619 B: FnOnce(reqwest::ClientBuilder) -> reqwest::Client,
620 {
621 self.connect_reqwest(builder(reqwest::ClientBuilder::default()), url)
622 }
623
624 #[cfg(feature = "hyper")]
626 pub fn connect_hyper_http(self, url: url::Url) -> F::Provider
627 where
628 L: ProviderLayer<crate::RootProvider<N>, N>,
629 F: TxFiller<N> + ProviderLayer<L::Provider, N>,
630 N: Network,
631 {
632 let client = ClientBuilder::default().hyper_http(url);
633 self.connect_client(client)
634 }
635}
636
637#[cfg(any(test, feature = "anvil-node"))]
638type JoinedEthereumWalletFiller<F> = JoinFill<F, WalletFiller<alloy_network::EthereumWallet>>;
639
640#[cfg(any(test, feature = "anvil-node"))]
641type AnvilProviderResult<T> = Result<T, alloy_node_bindings::NodeError>;
642
643#[cfg(any(test, feature = "anvil-node"))]
644impl<L, F, N: Network> ProviderBuilder<L, F, N> {
645 #[cfg_attr(docsrs, doc(cfg(feature = "anvil-node")))]
651 pub fn connect_anvil(self) -> F::Provider
652 where
653 F: TxFiller<N> + ProviderLayer<L::Provider, N>,
654 L: crate::builder::ProviderLayer<
655 crate::layers::AnvilProvider<crate::provider::RootProvider<N>, N>,
656 N,
657 >,
658 {
659 self.connect_anvil_with_config(std::convert::identity)
660 }
661
662 #[cfg_attr(docsrs, doc(cfg(feature = "anvil-node")))]
670 pub fn connect_anvil_with_wallet(
671 self,
672 ) -> <JoinedEthereumWalletFiller<F> as ProviderLayer<L::Provider, N>>::Provider
673 where
674 F: TxFiller<N> + ProviderLayer<L::Provider, N>,
675 L: crate::builder::ProviderLayer<
676 crate::layers::AnvilProvider<crate::provider::RootProvider<N>, N>,
677 N,
678 >,
679 alloy_network::EthereumWallet: alloy_network::NetworkWallet<N>,
680 {
681 self.connect_anvil_with_wallet_and_config(std::convert::identity)
682 .expect("failed to build provider")
683 }
684
685 #[cfg_attr(docsrs, doc(cfg(feature = "anvil-node")))]
692 pub fn connect_anvil_with_config(
693 self,
694 f: impl FnOnce(alloy_node_bindings::Anvil) -> alloy_node_bindings::Anvil,
695 ) -> F::Provider
696 where
697 F: TxFiller<N> + ProviderLayer<L::Provider, N>,
698 L: crate::builder::ProviderLayer<
699 crate::layers::AnvilProvider<crate::provider::RootProvider<N>, N>,
700 N,
701 >,
702 {
703 let anvil_layer = crate::layers::AnvilLayer::from(f(Default::default()));
704 let url = anvil_layer.endpoint_url();
705
706 let rpc_client = ClientBuilder::default().http(url);
707
708 self.layer(anvil_layer).connect_client(rpc_client)
709 }
710
711 #[cfg_attr(docsrs, doc(cfg(feature = "anvil-node")))]
718 #[deprecated(since = "0.12.6", note = "use `connect_anvil_with_config` instead")]
719 pub fn on_anvil_with_config(
720 self,
721 f: impl FnOnce(alloy_node_bindings::Anvil) -> alloy_node_bindings::Anvil,
722 ) -> F::Provider
723 where
724 L: ProviderLayer<crate::layers::AnvilProvider<RootProvider<N>, N>, N>,
725 F: TxFiller<N> + ProviderLayer<L::Provider, N>,
726 {
727 let anvil_layer = crate::layers::AnvilLayer::from(f(Default::default()));
728 let url = anvil_layer.endpoint_url();
729
730 let rpc_client = ClientBuilder::default().http(url);
731
732 self.layer(anvil_layer).connect_client(rpc_client)
733 }
734
735 #[cfg_attr(docsrs, doc(cfg(feature = "anvil-node")))]
742 pub fn connect_anvil_with_wallet_and_config(
743 self,
744 f: impl FnOnce(alloy_node_bindings::Anvil) -> alloy_node_bindings::Anvil,
745 ) -> AnvilProviderResult<
746 <JoinedEthereumWalletFiller<F> as ProviderLayer<L::Provider, N>>::Provider,
747 >
748 where
749 F: TxFiller<N> + ProviderLayer<L::Provider, N>,
750 L: crate::builder::ProviderLayer<
751 crate::layers::AnvilProvider<crate::provider::RootProvider<N>, N>,
752 N,
753 >,
754 alloy_network::EthereumWallet: alloy_network::NetworkWallet<N>,
755 {
756 let anvil_layer = crate::layers::AnvilLayer::from(f(Default::default()));
757 let url = anvil_layer.endpoint_url();
758
759 let wallet = anvil_layer
760 .instance()
761 .wallet()
762 .ok_or(alloy_node_bindings::NodeError::NoKeysAvailable)?;
763
764 let rpc_client = ClientBuilder::default().http(url);
765
766 Ok(self.wallet(wallet).layer(anvil_layer).connect_client(rpc_client))
767 }
768
769 #[cfg_attr(docsrs, doc(cfg(feature = "anvil-node")))]
776 #[deprecated(since = "0.12.6", note = "use `connect_anvil_with_wallet_and_config` instead")]
777 pub fn on_anvil_with_wallet_and_config(
778 self,
779 f: impl FnOnce(alloy_node_bindings::Anvil) -> alloy_node_bindings::Anvil,
780 ) -> AnvilProviderResult<
781 <JoinedEthereumWalletFiller<F> as ProviderLayer<L::Provider, N>>::Provider,
782 >
783 where
784 F: TxFiller<N> + ProviderLayer<L::Provider, N>,
785 L: crate::builder::ProviderLayer<
786 crate::layers::AnvilProvider<crate::provider::RootProvider<N>, N>,
787 N,
788 >,
789 alloy_network::EthereumWallet: alloy_network::NetworkWallet<N>,
790 {
791 let anvil_layer = crate::layers::AnvilLayer::from(f(Default::default()));
792 let url = anvil_layer.endpoint_url();
793
794 let wallet = anvil_layer
795 .instance()
796 .wallet()
797 .ok_or(alloy_node_bindings::NodeError::NoKeysAvailable)?;
798
799 let rpc_client = ClientBuilder::default().http(url);
800
801 Ok(self.wallet(wallet).layer(anvil_layer).connect_client(rpc_client))
802 }
803}
804
805#[cfg(test)]
806mod tests {
807 use super::*;
808 use crate::Provider;
809 use alloy_network::AnyNetwork;
810
811 #[tokio::test]
812 async fn basic() {
813 let provider = ProviderBuilder::new()
814 .with_cached_nonce_management()
815 .with_call_batching()
816 .connect_http("http://localhost:8545".parse().unwrap());
817 let _ = provider.get_account(Default::default());
818 let provider = provider.erased();
819 let _ = provider.get_account(Default::default());
820 }
821
822 #[tokio::test]
823 #[cfg(feature = "reqwest")]
824 async fn test_connect_reqwest() {
825 let provider = ProviderBuilder::new()
826 .with_cached_nonce_management()
827 .with_call_batching()
828 .connect_reqwest(
829 reqwest::Client::new(),
830 reqwest::Url::parse("http://localhost:8545").unwrap(),
831 );
832 let _ = provider.get_account(Default::default());
833 let provider = provider.erased();
834 let _ = provider.get_account(Default::default());
835 }
836
837 #[tokio::test]
838 #[cfg(feature = "reqwest")]
839 async fn test_with_reqwest() {
840 let provider = ProviderBuilder::new()
841 .with_cached_nonce_management()
842 .with_call_batching()
843 .with_reqwest(reqwest::Url::parse("http://localhost:8545").unwrap(), |builder| {
844 builder
845 .user_agent("alloy/test")
846 .timeout(std::time::Duration::from_secs(10))
847 .build()
848 .expect("failed to build reqwest client")
849 });
850 let _ = provider.get_account(Default::default());
851 let provider = provider.erased();
852 let _ = provider.get_account(Default::default());
853 }
854
855 #[tokio::test]
856 async fn compile_with_network() {
857 let p = ProviderBuilder::new_with_network::<AnyNetwork>().connect_anvil();
858 let num = p.get_block_number().await.unwrap();
859 assert_eq!(num, 0);
860 }
861
862 #[test]
864 fn network_replaces_fillers() {
865 let builder = ProviderBuilder::new().filler(GasFiller::default()).network::<AnyNetwork>();
867
868 let _: ProviderBuilder<
869 Identity,
870 JoinFill<Identity, <AnyNetwork as RecommendedFillers>::RecommendedFillers>,
871 AnyNetwork,
872 > = builder;
873 }
874
875 #[test]
876 fn apply_transforms_builder() {
877 let builder = ProviderBuilder::new()
878 .apply(|builder| builder.disable_recommended_fillers().with_gas_estimation());
879
880 let _: ProviderBuilder<Identity, JoinFill<Identity, GasFiller>, Ethereum> = builder;
881 }
882
883 #[test]
884 fn map_filler_replaces_fillers() {
885 let builder = ProviderBuilder::new().map_filler(|_| GasFiller::default());
886
887 let _: ProviderBuilder<Identity, GasFiller, Ethereum> = builder;
888 }
889
890 #[test]
891 fn map_layer_replaces_layers() {
892 let builder = ProviderBuilder::<Identity, Identity>::default()
893 .map_layer(|_| ChainLayer::new(NamedChain::Mainnet));
894
895 let _: ProviderBuilder<ChainLayer, Identity, Ethereum> = builder;
896 }
897
898 #[tokio::test]
899 async fn network_swap_works_at_runtime() {
900 let p = ProviderBuilder::new().network::<AnyNetwork>().connect_anvil();
902 let num = p.get_block_number().await.unwrap();
903 assert_eq!(num, 0);
904 }
905}