alloy_provider/
builder.rs

1use crate::{
2    fillers::{
3        CachedNonceManager, ChainIdFiller, FillerControlFlow, GasFiller, JoinFill, NonceFiller,
4        NonceManager, RecommendedFillers, SimpleNonceManager, TxFiller, WalletFiller,
5    },
6    layers::{CallBatchLayer, ChainLayer},
7    provider::SendableTx,
8    Provider, RootProvider,
9};
10use alloy_chains::NamedChain;
11use alloy_network::{Ethereum, IntoWallet, Network};
12use alloy_primitives::ChainId;
13use alloy_rpc_client::{ClientBuilder, RpcClient};
14use alloy_transport::{TransportConnect, TransportError, TransportResult};
15use std::marker::PhantomData;
16
17/// A layering abstraction in the vein of [`tower::Layer`]
18///
19/// [`tower::Layer`]: https://docs.rs/tower/latest/tower/trait.Layer.html
20pub trait ProviderLayer<P: Provider<N>, N: Network = Ethereum> {
21    /// The provider constructed by this layer.
22    type Provider: Provider<N>;
23
24    /// Wrap the given provider in the layer's provider.
25    fn layer(&self, inner: P) -> Self::Provider;
26}
27
28/// An identity layer that does nothing.
29#[derive(Clone, Copy, Debug)]
30pub struct Identity;
31
32impl<N> TxFiller<N> for Identity
33where
34    N: Network,
35{
36    type Fillable = ();
37
38    fn status(&self, _tx: &<N as Network>::TransactionRequest) -> FillerControlFlow {
39        FillerControlFlow::Finished
40    }
41
42    fn fill_sync(&self, _tx: &mut SendableTx<N>) {}
43
44    async fn prepare<P>(
45        &self,
46        _provider: &P,
47        _tx: &N::TransactionRequest,
48    ) -> TransportResult<Self::Fillable> {
49        Ok(())
50    }
51
52    async fn fill(
53        &self,
54        _to_fill: Self::Fillable,
55        tx: SendableTx<N>,
56    ) -> TransportResult<SendableTx<N>> {
57        Ok(tx)
58    }
59}
60
61impl<P, N> ProviderLayer<P, N> for Identity
62where
63    N: Network,
64    P: Provider<N>,
65{
66    type Provider = P;
67
68    fn layer(&self, inner: P) -> Self::Provider {
69        inner
70    }
71}
72
73/// A stack of two providers.
74#[derive(Debug)]
75pub struct Stack<Inner, Outer> {
76    inner: Inner,
77    outer: Outer,
78}
79
80impl<Inner, Outer> Stack<Inner, Outer> {
81    /// Create a new `Stack`.
82    pub const fn new(inner: Inner, outer: Outer) -> Self {
83        Self { inner, outer }
84    }
85}
86
87impl<P, N, Inner, Outer> ProviderLayer<P, N> for Stack<Inner, Outer>
88where
89    N: Network,
90    P: Provider<N>,
91    Inner: ProviderLayer<P, N>,
92    Outer: ProviderLayer<Inner::Provider, N>,
93{
94    type Provider = Outer::Provider;
95
96    fn layer(&self, provider: P) -> Self::Provider {
97        let inner = self.inner.layer(provider);
98
99        self.outer.layer(inner)
100    }
101}
102
103/// A builder for constructing a [`Provider`] from various layers.
104///
105/// This type is similar to [`tower::ServiceBuilder`], with extra complication
106/// around maintaining the network and transport types.
107///
108/// The [`ProviderBuilder`] can be instantiated in two ways, using `ProviderBuilder::new()` or
109/// `ProviderBuilder::default()`.
110///
111/// `ProviderBuilder::new()` will create a new [`ProviderBuilder`] with the [`RecommendedFillers`]
112/// enabled, whereas `ProviderBuilder::default()` will instantiate it in its vanilla
113/// [`ProviderBuilder`] form i.e with no fillers enabled.
114///
115/// [`tower::ServiceBuilder`]: https://docs.rs/tower/latest/tower/struct.ServiceBuilder.html
116#[derive(Debug)]
117pub struct ProviderBuilder<L, F, N = Ethereum> {
118    layer: L,
119    filler: F,
120    network: PhantomData<fn() -> N>,
121}
122
123impl
124    ProviderBuilder<
125        Identity,
126        JoinFill<Identity, <Ethereum as RecommendedFillers>::RecommendedFillers>,
127        Ethereum,
128    >
129{
130    /// Create a new [`ProviderBuilder`] with the recommended filler enabled.
131    ///
132    /// Recommended fillers are preconfigured set of fillers that handle gas estimation, nonce
133    /// management, and chain-id fetching.
134    ///
135    /// Building a provider with this setting enabled will return a [`crate::fillers::FillProvider`]
136    /// with [`crate::utils::JoinedRecommendedFillers`].
137    ///
138    /// You can opt-out of using these fillers by using the `.disable_recommended_fillers()` method.
139    pub fn new() -> Self {
140        ProviderBuilder::default().with_recommended_fillers()
141    }
142
143    /// Opt-out of the recommended fillers by resetting the fillers stack in the
144    /// [`ProviderBuilder`].
145    ///
146    /// This is equivalent to creating the builder using `ProviderBuilder::default()`.
147    pub fn disable_recommended_fillers(self) -> ProviderBuilder<Identity, Identity, Ethereum> {
148        ProviderBuilder { layer: self.layer, filler: Identity, network: self.network }
149    }
150}
151
152impl<N> Default for ProviderBuilder<Identity, Identity, N> {
153    fn default() -> Self {
154        Self { layer: Identity, filler: Identity, network: PhantomData }
155    }
156}
157
158impl ProviderBuilder<Identity, Identity, Ethereum> {
159    /// Create a new [`ProviderBuilder`] with the [`RecommendedFillers`] for the provided
160    /// [`Network`].
161    pub fn new_with_network<Net: RecommendedFillers>(
162    ) -> ProviderBuilder<Identity, JoinFill<Identity, Net::RecommendedFillers>, Net> {
163        ProviderBuilder {
164            layer: Identity,
165            filler: JoinFill::new(Identity, Net::recommended_fillers()),
166            network: PhantomData,
167        }
168    }
169}
170
171impl<L, N: Network> ProviderBuilder<L, Identity, N> {
172    /// Add preconfigured set of layers handling gas estimation, nonce
173    /// management, and chain-id fetching.
174    pub fn with_recommended_fillers(
175        self,
176    ) -> ProviderBuilder<L, JoinFill<Identity, N::RecommendedFillers>, N>
177    where
178        N: RecommendedFillers,
179    {
180        self.filler(N::recommended_fillers())
181    }
182}
183
184impl<L, F, N> ProviderBuilder<L, F, N> {
185    /// Add a layer to the stack being built. This is similar to
186    /// [`tower::ServiceBuilder::layer`].
187    ///
188    /// ## Note:
189    ///
190    /// Layers are added in outer-to-inner order, as in
191    /// [`tower::ServiceBuilder`]. The first layer added will be the first to
192    /// see the request.
193    ///
194    /// [`tower::ServiceBuilder::layer`]: https://docs.rs/tower/latest/tower/struct.ServiceBuilder.html#method.layer
195    /// [`tower::ServiceBuilder`]: https://docs.rs/tower/latest/tower/struct.ServiceBuilder.html
196    pub fn layer<Inner>(self, layer: Inner) -> ProviderBuilder<Stack<Inner, L>, F, N> {
197        ProviderBuilder {
198            layer: Stack::new(layer, self.layer),
199            filler: self.filler,
200            network: PhantomData,
201        }
202    }
203
204    /// Add a transaction filler to the stack being built. Transaction fillers
205    /// are used to fill in missing fields on transactions before they are sent,
206    /// and are all joined to form the outermost layer of the stack.
207    pub fn filler<F2>(self, filler: F2) -> ProviderBuilder<L, JoinFill<F, F2>, N> {
208        ProviderBuilder {
209            layer: self.layer,
210            filler: JoinFill::new(self.filler, filler),
211            network: PhantomData,
212        }
213    }
214
215    /// Change the network.
216    ///
217    /// By default, the network is `Ethereum`. This method must be called to configure a different
218    /// network.
219    ///
220    /// ```ignore
221    /// builder.network::<Arbitrum>()
222    /// ```
223    pub fn network<Net: Network>(self) -> ProviderBuilder<L, F, Net> {
224        ProviderBuilder { layer: self.layer, filler: self.filler, network: PhantomData }
225    }
226
227    /// Add a chain layer to the stack being built. The layer will set
228    /// the client's poll interval based on the average block time for this chain.
229    ///
230    /// Does nothing to the client with a local transport.
231    pub fn with_chain(self, chain: NamedChain) -> ProviderBuilder<Stack<ChainLayer, L>, F, N> {
232        self.layer(ChainLayer::new(chain))
233    }
234
235    // --- Fillers ---
236
237    /// Add gas estimation to the stack being built.
238    ///
239    /// See [`GasFiller`] for more information.
240    pub fn with_gas_estimation(self) -> ProviderBuilder<L, JoinFill<F, GasFiller>, N> {
241        self.filler(GasFiller)
242    }
243
244    /// Add nonce management to the stack being built.
245    ///
246    /// See [`NonceFiller`] for more information.
247    pub fn with_nonce_management<M: NonceManager>(
248        self,
249        nonce_manager: M,
250    ) -> ProviderBuilder<L, JoinFill<F, NonceFiller<M>>, N> {
251        self.filler(NonceFiller::new(nonce_manager))
252    }
253
254    /// Add simple nonce management to the stack being built.
255    ///
256    /// See [`SimpleNonceManager`] for more information.
257    pub fn with_simple_nonce_management(
258        self,
259    ) -> ProviderBuilder<L, JoinFill<F, NonceFiller<SimpleNonceManager>>, N> {
260        self.with_nonce_management(SimpleNonceManager::default())
261    }
262
263    /// Add cached nonce management to the stack being built.
264    ///
265    /// See [`CachedNonceManager`] for more information.
266    pub fn with_cached_nonce_management(
267        self,
268    ) -> ProviderBuilder<L, JoinFill<F, NonceFiller<CachedNonceManager>>, N> {
269        self.with_nonce_management(CachedNonceManager::default())
270    }
271
272    /// Add a chain ID filler to the stack being built. The filler will attempt
273    /// to fetch the chain ID from the provider using
274    /// [`Provider::get_chain_id`]. the first time a transaction is prepared,
275    /// and will cache it for future transactions.
276    pub fn fetch_chain_id(self) -> ProviderBuilder<L, JoinFill<F, ChainIdFiller>, N> {
277        self.filler(ChainIdFiller::default())
278    }
279
280    /// Add a specific chain ID to the stack being built. The filler will
281    /// fill transactions with the provided chain ID, regardless of the chain ID
282    /// that the provider reports via [`Provider::get_chain_id`].
283    pub fn with_chain_id(
284        self,
285        chain_id: ChainId,
286    ) -> ProviderBuilder<L, JoinFill<F, ChainIdFiller>, N> {
287        self.filler(ChainIdFiller::new(Some(chain_id)))
288    }
289
290    /// Add a wallet layer to the stack being built.
291    ///
292    /// See [`WalletFiller`].
293    pub fn wallet<W: IntoWallet<N>>(
294        self,
295        wallet: W,
296    ) -> ProviderBuilder<L, JoinFill<F, WalletFiller<W::NetworkWallet>>, N>
297    where
298        N: Network,
299    {
300        self.filler(WalletFiller::new(wallet.into_wallet()))
301    }
302
303    // --- Layers ---
304
305    /// Aggregate multiple `eth_call` requests into a single batch request using Multicall3.
306    ///
307    /// See [`CallBatchLayer`] for more information.
308    pub fn with_call_batching(self) -> ProviderBuilder<Stack<CallBatchLayer, L>, F, N> {
309        self.layer(CallBatchLayer::new())
310    }
311
312    /// Aggregate multiple `eth_call` requests with block number queries done by calling Arbsym
313    /// precompile.
314    ///
315    /// See [`CallBatchLayer`] for more information.
316    pub fn with_arbitrum_call_batching(self) -> ProviderBuilder<Stack<CallBatchLayer, L>, F, N> {
317        self.layer(CallBatchLayer::new().arbitrum_compat())
318    }
319
320    // --- Build to Provider ---
321
322    /// Finish the layer stack by providing a root [`Provider`], outputting
323    /// the final [`Provider`] type with all stack components.
324    pub fn connect_provider<P>(self, provider: P) -> F::Provider
325    where
326        L: ProviderLayer<P, N>,
327        F: TxFiller<N> + ProviderLayer<L::Provider, N>,
328        P: Provider<N>,
329        N: Network,
330    {
331        let Self { layer, filler, network: PhantomData } = self;
332        let stack = Stack::new(layer, filler);
333        stack.layer(provider)
334    }
335
336    /// Finish the layer stack by providing a root [`Provider`], outputting
337    /// the final [`Provider`] type with all stack components.
338    #[deprecated(since = "0.12.6", note = "use `connect_provider` instead")]
339    pub fn on_provider<P>(self, provider: P) -> F::Provider
340    where
341        L: ProviderLayer<P, N>,
342        F: TxFiller<N> + ProviderLayer<L::Provider, N>,
343        P: Provider<N>,
344        N: Network,
345    {
346        let Self { layer, filler, network: PhantomData } = self;
347        let stack = Stack::new(layer, filler);
348        stack.layer(provider)
349    }
350
351    /// Finish the layer stack by providing a root [`RpcClient`], outputting
352    /// the final [`Provider`] type with all stack components.
353    ///
354    /// This is a convenience function for
355    /// `ProviderBuilder::on_provider(RootProvider::new(client))`.
356    pub fn connect_client(self, client: RpcClient) -> F::Provider
357    where
358        L: ProviderLayer<RootProvider<N>, N>,
359        F: TxFiller<N> + ProviderLayer<L::Provider, N>,
360        N: Network,
361    {
362        self.connect_provider(RootProvider::new(client))
363    }
364
365    /// Finish the layer stack by providing a root [`RpcClient`], outputting
366    /// the final [`Provider`] type with all stack components.
367    ///
368    /// This is a convenience function for
369    /// `ProviderBuilder::on_provider(RootProvider::new(client))`.
370    #[deprecated(since = "0.12.6", note = "use `connect_client` instead")]
371    pub fn on_client(self, client: RpcClient) -> F::Provider
372    where
373        L: ProviderLayer<RootProvider<N>, N>,
374        F: TxFiller<N> + ProviderLayer<L::Provider, N>,
375        N: Network,
376    {
377        self.connect_provider(RootProvider::new(client))
378    }
379
380    /// Finish the layer stack by providing a [`RpcClient`] that mocks responses, outputting
381    /// the final [`Provider`] type with all stack components.
382    ///
383    /// This is a convenience function for
384    /// `ProviderBuilder::on_client(RpcClient::mocked(asserter))`.
385    pub fn connect_mocked_client(self, asserter: alloy_transport::mock::Asserter) -> F::Provider
386    where
387        L: ProviderLayer<RootProvider<N>, N>,
388        F: TxFiller<N> + ProviderLayer<L::Provider, N>,
389        N: Network,
390    {
391        self.connect_client(RpcClient::mocked(asserter))
392    }
393
394    /// Finish the layer stack by providing a [`RpcClient`] that mocks responses, outputting
395    /// the final [`Provider`] type with all stack components.
396    ///
397    /// This is a convenience function for
398    /// `ProviderBuilder::on_client(RpcClient::mocked(asserter))`.
399    #[deprecated(since = "0.12.6", note = "use `connect_mocked_client` instead")]
400    pub fn on_mocked_client(self, asserter: alloy_transport::mock::Asserter) -> F::Provider
401    where
402        L: ProviderLayer<RootProvider<N>, N>,
403        F: TxFiller<N> + ProviderLayer<L::Provider, N>,
404        N: Network,
405    {
406        self.connect_client(RpcClient::mocked(asserter))
407    }
408
409    /// Finish the layer stack by providing a connection string for a built-in
410    /// transport type, outputting the final [`Provider`] type with all stack
411    /// components.
412    #[doc(alias = "on_builtin")]
413    pub async fn connect(self, s: &str) -> Result<F::Provider, TransportError>
414    where
415        L: ProviderLayer<RootProvider<N>, N>,
416        F: TxFiller<N> + ProviderLayer<L::Provider, N>,
417        N: Network,
418    {
419        let client = ClientBuilder::default().connect(s).await?;
420        Ok(self.connect_client(client))
421    }
422
423    /// Finish the layer stack by providing a [`TransportConnect`] instance.
424    pub async fn connect_with<C>(self, connect: &C) -> Result<F::Provider, TransportError>
425    where
426        L: ProviderLayer<RootProvider<N>, N>,
427        F: TxFiller<N> + ProviderLayer<L::Provider, N>,
428        N: Network,
429        C: TransportConnect,
430    {
431        connect
432            .get_transport()
433            .await
434            .map(|t| RpcClient::new(t, connect.is_local()))
435            .map(|client| self.connect_client(client))
436    }
437
438    /// Finish the layer stack by providing a [`PubSubConnect`] instance,
439    /// producing a [`Provider`] with pubsub capabilities.
440    ///
441    /// [`PubSubConnect`]: alloy_pubsub::PubSubConnect
442    #[cfg(feature = "pubsub")]
443    pub async fn connect_pubsub_with<C>(self, connect: C) -> Result<F::Provider, TransportError>
444    where
445        L: ProviderLayer<RootProvider<N>, N>,
446        F: TxFiller<N> + ProviderLayer<L::Provider, N>,
447        N: Network,
448        C: alloy_pubsub::PubSubConnect,
449    {
450        ClientBuilder::default().pubsub(connect).await.map(|client| self.connect_client(client))
451    }
452
453    /// Finish the layer stack by providing a connection string for a built-in
454    /// transport type, outputting the final [`Provider`] type with all stack
455    /// components.
456    #[deprecated = "use `connect` instead"]
457    #[doc(hidden)]
458    pub async fn on_builtin(self, s: &str) -> Result<F::Provider, TransportError>
459    where
460        L: ProviderLayer<RootProvider<N>, N>,
461        F: TxFiller<N> + ProviderLayer<L::Provider, N>,
462        N: Network,
463    {
464        self.connect(s).await
465    }
466
467    /// Build this provider with a websocket connection.
468    #[cfg(feature = "ws")]
469    pub async fn connect_ws(
470        self,
471        connect: alloy_transport_ws::WsConnect,
472    ) -> Result<F::Provider, TransportError>
473    where
474        L: ProviderLayer<RootProvider<N>, N>,
475        F: TxFiller<N> + ProviderLayer<L::Provider, N>,
476        N: Network,
477    {
478        let client = ClientBuilder::default().ws(connect).await?;
479        Ok(self.connect_client(client))
480    }
481
482    /// Build this provider with a websocket connection.
483    #[cfg(feature = "ws")]
484    #[deprecated(since = "0.12.6", note = "use `connect_ws` instead")]
485    pub async fn on_ws(
486        self,
487        connect: alloy_transport_ws::WsConnect,
488    ) -> Result<F::Provider, TransportError>
489    where
490        L: ProviderLayer<RootProvider<N>, N>,
491        F: TxFiller<N> + ProviderLayer<L::Provider, N>,
492        N: Network,
493    {
494        let client = ClientBuilder::default().ws(connect).await?;
495        Ok(self.connect_client(client))
496    }
497
498    /// Build this provider with an IPC connection.
499    #[cfg(feature = "ipc")]
500    pub async fn connect_ipc<T>(
501        self,
502        connect: alloy_transport_ipc::IpcConnect<T>,
503    ) -> Result<F::Provider, TransportError>
504    where
505        alloy_transport_ipc::IpcConnect<T>: alloy_pubsub::PubSubConnect,
506        L: ProviderLayer<RootProvider<N>, N>,
507        F: TxFiller<N> + ProviderLayer<L::Provider, N>,
508        N: Network,
509    {
510        let client = ClientBuilder::default().ipc(connect).await?;
511        Ok(self.connect_client(client))
512    }
513
514    /// Build this provider with an IPC connection.
515    #[cfg(feature = "ipc")]
516    #[deprecated(since = "0.12.6", note = "use `connect_ipc` instead")]
517    pub async fn on_ipc<T>(
518        self,
519        connect: alloy_transport_ipc::IpcConnect<T>,
520    ) -> Result<F::Provider, TransportError>
521    where
522        alloy_transport_ipc::IpcConnect<T>: alloy_pubsub::PubSubConnect,
523        L: ProviderLayer<RootProvider<N>, N>,
524        F: TxFiller<N> + ProviderLayer<L::Provider, N>,
525        N: Network,
526    {
527        let client = ClientBuilder::default().ipc(connect).await?;
528        Ok(self.connect_client(client))
529    }
530
531    /// Build this provider with an Reqwest HTTP transport.
532    #[cfg(any(test, feature = "reqwest"))]
533    pub fn connect_http(self, url: reqwest::Url) -> F::Provider
534    where
535        L: ProviderLayer<crate::RootProvider<N>, N>,
536        F: TxFiller<N> + ProviderLayer<L::Provider, N>,
537        N: Network,
538    {
539        let client = ClientBuilder::default().http(url);
540        self.connect_client(client)
541    }
542
543    /// Build this provider with a pre-built Reqwest client.
544    #[cfg(any(test, feature = "reqwest"))]
545    pub fn connect_reqwest<C>(self, client: C, url: reqwest::Url) -> F::Provider
546    where
547        L: ProviderLayer<crate::RootProvider<N>, N>,
548        F: TxFiller<N> + ProviderLayer<L::Provider, N>,
549        N: Network,
550        C: Into<reqwest::Client>,
551    {
552        let client = ClientBuilder::default().http_with_client(client.into(), url);
553        self.connect_client(client)
554    }
555
556    /// Build this provider with a provided Reqwest client builder.
557    #[cfg(any(test, feature = "reqwest"))]
558    pub fn with_reqwest<B>(self, url: reqwest::Url, builder: B) -> F::Provider
559    where
560        L: ProviderLayer<crate::RootProvider<N>, N>,
561        F: TxFiller<N> + ProviderLayer<L::Provider, N>,
562        N: Network,
563        B: FnOnce(reqwest::ClientBuilder) -> reqwest::Client,
564    {
565        self.connect_reqwest(builder(reqwest::ClientBuilder::default()), url)
566    }
567
568    /// Build this provider with an Reqwest HTTP transport.
569    #[cfg(any(test, feature = "reqwest"))]
570    #[deprecated(since = "0.12.6", note = "use `connect_http` instead")]
571    pub fn on_http(self, url: reqwest::Url) -> F::Provider
572    where
573        L: ProviderLayer<RootProvider<N>, N>,
574        F: TxFiller<N> + ProviderLayer<L::Provider, N>,
575        N: Network,
576    {
577        let client = ClientBuilder::default().http(url);
578        self.connect_client(client)
579    }
580
581    /// Build this provider with an Hyper HTTP transport.
582    #[cfg(feature = "hyper")]
583    pub fn connect_hyper_http(self, url: url::Url) -> F::Provider
584    where
585        L: ProviderLayer<crate::RootProvider<N>, N>,
586        F: TxFiller<N> + ProviderLayer<L::Provider, N>,
587        N: Network,
588    {
589        let client = ClientBuilder::default().hyper_http(url);
590        self.connect_client(client)
591    }
592
593    /// Build this provider with an Hyper HTTP transport.
594    #[cfg(feature = "hyper")]
595    #[deprecated(since = "0.12.6", note = "use `connect_hyper_http` instead")]
596    pub fn on_hyper_http(self, url: url::Url) -> F::Provider
597    where
598        L: ProviderLayer<RootProvider<N>, N>,
599        F: TxFiller<N> + ProviderLayer<L::Provider, N>,
600        N: Network,
601    {
602        let client = ClientBuilder::default().hyper_http(url);
603        self.connect_client(client)
604    }
605}
606
607#[cfg(any(test, feature = "anvil-node"))]
608type JoinedEthereumWalletFiller<F> = JoinFill<F, WalletFiller<alloy_network::EthereumWallet>>;
609
610#[cfg(any(test, feature = "anvil-node"))]
611type AnvilProviderResult<T> = Result<T, alloy_node_bindings::NodeError>;
612
613#[cfg(any(test, feature = "anvil-node"))]
614impl<L, F, N: Network> ProviderBuilder<L, F, N> {
615    /// Build this provider with anvil, using the BoxTransport.
616    pub fn connect_anvil(self) -> F::Provider
617    where
618        F: TxFiller<N> + ProviderLayer<L::Provider, N>,
619        L: crate::builder::ProviderLayer<
620            crate::layers::AnvilProvider<crate::provider::RootProvider<N>, N>,
621            N,
622        >,
623    {
624        self.connect_anvil_with_config(std::convert::identity)
625    }
626
627    /// Build this provider with anvil, using the BoxTransport.
628    #[deprecated(since = "0.12.6", note = "use `connect_anvil` instead")]
629    pub fn on_anvil(self) -> F::Provider
630    where
631        L: ProviderLayer<crate::layers::AnvilProvider<RootProvider<N>, N>, N>,
632        F: TxFiller<N> + ProviderLayer<L::Provider, N>,
633    {
634        self.connect_anvil_with_config(std::convert::identity)
635    }
636
637    /// Build this provider with anvil, using the BoxTransport. This
638    /// function configures a wallet backed by anvil keys, and is intended for
639    /// use in tests.
640    pub fn connect_anvil_with_wallet(
641        self,
642    ) -> <JoinedEthereumWalletFiller<F> as ProviderLayer<L::Provider, N>>::Provider
643    where
644        F: TxFiller<N> + ProviderLayer<L::Provider, N>,
645        L: crate::builder::ProviderLayer<
646            crate::layers::AnvilProvider<crate::provider::RootProvider<N>, N>,
647            N,
648        >,
649        alloy_network::EthereumWallet: alloy_network::NetworkWallet<N>,
650    {
651        self.connect_anvil_with_wallet_and_config(std::convert::identity)
652            .expect("failed to build provider")
653    }
654
655    /// Build this provider with anvil, using the BoxTransport. This
656    /// function configures a wallet backed by anvil keys, and is intended for
657    /// use in tests.
658    #[deprecated(since = "0.12.6", note = "use `connect_anvil_with_wallet` instead")]
659    pub fn on_anvil_with_wallet(
660        self,
661    ) -> <JoinedEthereumWalletFiller<F> as ProviderLayer<L::Provider, N>>::Provider
662    where
663        F: TxFiller<N> + ProviderLayer<L::Provider, N>,
664        L: crate::builder::ProviderLayer<
665            crate::layers::AnvilProvider<crate::provider::RootProvider<N>, N>,
666            N,
667        >,
668        alloy_network::EthereumWallet: alloy_network::NetworkWallet<N>,
669    {
670        self.connect_anvil_with_wallet_and_config(std::convert::identity)
671            .expect("failed to build provider")
672    }
673
674    /// Build this provider with anvil, using the BoxTransport. The
675    /// given function is used to configure the anvil instance.
676    pub fn connect_anvil_with_config(
677        self,
678        f: impl FnOnce(alloy_node_bindings::Anvil) -> alloy_node_bindings::Anvil,
679    ) -> F::Provider
680    where
681        F: TxFiller<N> + ProviderLayer<L::Provider, N>,
682        L: crate::builder::ProviderLayer<
683            crate::layers::AnvilProvider<crate::provider::RootProvider<N>, N>,
684            N,
685        >,
686    {
687        let anvil_layer = crate::layers::AnvilLayer::from(f(Default::default()));
688        let url = anvil_layer.endpoint_url();
689
690        let rpc_client = ClientBuilder::default().http(url);
691
692        self.layer(anvil_layer).connect_client(rpc_client)
693    }
694
695    /// Build this provider with anvil, using the BoxTransport. The
696    /// given function is used to configure the anvil instance.
697    #[deprecated(since = "0.12.6", note = "use `connect_anvil_with_config` instead")]
698    pub fn on_anvil_with_config(
699        self,
700        f: impl FnOnce(alloy_node_bindings::Anvil) -> alloy_node_bindings::Anvil,
701    ) -> F::Provider
702    where
703        L: ProviderLayer<crate::layers::AnvilProvider<RootProvider<N>, N>, N>,
704        F: TxFiller<N> + ProviderLayer<L::Provider, N>,
705    {
706        let anvil_layer = crate::layers::AnvilLayer::from(f(Default::default()));
707        let url = anvil_layer.endpoint_url();
708
709        let rpc_client = ClientBuilder::default().http(url);
710
711        self.layer(anvil_layer).connect_client(rpc_client)
712    }
713
714    /// Build this provider with anvil, using the BoxTransport.
715    /// This calls `try_on_anvil_with_wallet_and_config` and panics on error.
716    pub fn connect_anvil_with_wallet_and_config(
717        self,
718        f: impl FnOnce(alloy_node_bindings::Anvil) -> alloy_node_bindings::Anvil,
719    ) -> AnvilProviderResult<
720        <JoinedEthereumWalletFiller<F> as ProviderLayer<L::Provider, N>>::Provider,
721    >
722    where
723        F: TxFiller<N> + ProviderLayer<L::Provider, N>,
724        L: crate::builder::ProviderLayer<
725            crate::layers::AnvilProvider<crate::provider::RootProvider<N>, N>,
726            N,
727        >,
728        alloy_network::EthereumWallet: alloy_network::NetworkWallet<N>,
729    {
730        let anvil_layer = crate::layers::AnvilLayer::from(f(Default::default()));
731        let url = anvil_layer.endpoint_url();
732
733        let wallet = anvil_layer
734            .instance()
735            .wallet()
736            .ok_or(alloy_node_bindings::NodeError::NoKeysAvailable)?;
737
738        let rpc_client = ClientBuilder::default().http(url);
739
740        Ok(self.wallet(wallet).layer(anvil_layer).connect_client(rpc_client))
741    }
742
743    /// Build this provider with anvil, using the BoxTransport.
744    /// This calls `try_on_anvil_with_wallet_and_config` and panics on error.
745    #[deprecated(since = "0.12.6", note = "use `connect_anvil_with_wallet_and_config` instead")]
746    pub fn on_anvil_with_wallet_and_config(
747        self,
748        f: impl FnOnce(alloy_node_bindings::Anvil) -> alloy_node_bindings::Anvil,
749    ) -> AnvilProviderResult<
750        <JoinedEthereumWalletFiller<F> as ProviderLayer<L::Provider, N>>::Provider,
751    >
752    where
753        F: TxFiller<N> + ProviderLayer<L::Provider, N>,
754        L: crate::builder::ProviderLayer<
755            crate::layers::AnvilProvider<crate::provider::RootProvider<N>, N>,
756            N,
757        >,
758        alloy_network::EthereumWallet: alloy_network::NetworkWallet<N>,
759    {
760        let anvil_layer = crate::layers::AnvilLayer::from(f(Default::default()));
761        let url = anvil_layer.endpoint_url();
762
763        let wallet = anvil_layer
764            .instance()
765            .wallet()
766            .ok_or(alloy_node_bindings::NodeError::NoKeysAvailable)?;
767
768        let rpc_client = ClientBuilder::default().http(url);
769
770        Ok(self.wallet(wallet).layer(anvil_layer).connect_client(rpc_client))
771    }
772}
773
774#[cfg(test)]
775mod tests {
776    use super::*;
777    use crate::Provider;
778    use alloy_network::AnyNetwork;
779
780    #[tokio::test]
781    async fn basic() {
782        let provider = ProviderBuilder::new()
783            .with_cached_nonce_management()
784            .with_call_batching()
785            .connect_http("http://localhost:8545".parse().unwrap());
786        let _ = provider.get_account(Default::default());
787        let provider = provider.erased();
788        let _ = provider.get_account(Default::default());
789    }
790
791    #[tokio::test]
792    #[cfg(feature = "reqwest")]
793    async fn test_connect_reqwest() {
794        let provider = ProviderBuilder::new()
795            .with_cached_nonce_management()
796            .with_call_batching()
797            .connect_reqwest(
798                reqwest::Client::new(),
799                reqwest::Url::parse("http://localhost:8545").unwrap(),
800            );
801        let _ = provider.get_account(Default::default());
802        let provider = provider.erased();
803        let _ = provider.get_account(Default::default());
804    }
805
806    #[tokio::test]
807    #[cfg(feature = "reqwest")]
808    async fn test_with_reqwest() {
809        let provider = ProviderBuilder::new()
810            .with_cached_nonce_management()
811            .with_call_batching()
812            .with_reqwest(reqwest::Url::parse("http://localhost:8545").unwrap(), |builder| {
813                builder
814                    .user_agent("alloy/test")
815                    .timeout(std::time::Duration::from_secs(10))
816                    .build()
817                    .expect("failed to build reqwest client")
818            });
819        let _ = provider.get_account(Default::default());
820        let provider = provider.erased();
821        let _ = provider.get_account(Default::default());
822    }
823
824    #[tokio::test]
825    async fn compile_with_network() {
826        let p = ProviderBuilder::new_with_network::<AnyNetwork>().connect_anvil();
827        let num = p.get_block_number().await.unwrap();
828        assert_eq!(num, 0);
829    }
830}