Skip to main content

alloy_provider/provider/
trait.rs

1//! Ethereum JSON-RPC provider.
2
3#![allow(unknown_lints, mismatched_lifetime_syntaxes)]
4
5#[cfg(feature = "pubsub")]
6use super::get_block::SubFullBlocks;
7use super::{DynProvider, Empty, EthCallMany, MulticallBuilder, WatchBlocks, WatchHeaders};
8#[cfg(feature = "pubsub")]
9use crate::GetSubscription;
10use crate::{
11    heart::PendingTransactionError,
12    utils::{self, Eip1559Estimation, Eip1559Estimator},
13    EthCall, EthGetBlock, Identity, PendingTransaction, PendingTransactionBuilder,
14    PendingTransactionConfig, ProviderBuilder, ProviderCall, RootProvider, RpcWithBlock,
15    SendableTx,
16};
17use alloy_consensus::BlockHeader;
18use alloy_eips::eip2718::Encodable2718;
19use alloy_json_rpc::{RpcError, RpcRecv, RpcSend};
20use alloy_network::{Ethereum, Network};
21use alloy_network_primitives::{BlockResponse, ReceiptResponse};
22use alloy_primitives::{
23    hex, Address, BlockHash, BlockNumber, Bytes, StorageKey, StorageValue, TxHash, B256, U128,
24    U256, U64,
25};
26use alloy_rpc_client::{ClientRef, NoParams, PollerBuilder, WeakClient};
27#[cfg(feature = "pubsub")]
28use alloy_rpc_types_eth::pubsub::{Params, SubscriptionKind};
29use alloy_rpc_types_eth::{
30    erc4337::TransactionConditional,
31    simulate::{SimulatePayload, SimulatedBlock},
32    AccessListResult, BlockId, BlockNumberOrTag, Bundle, EIP1186AccountProofResponse,
33    EthCallResponse, FeeHistory, FillTransaction, Filter, FilterChanges, Index, Log,
34    StorageValuesRequest, StorageValuesResponse, SyncStatus,
35};
36use alloy_transport::TransportResult;
37use serde_json::value::RawValue;
38use std::borrow::Cow;
39
40/// A task that polls the provider with `eth_getFilterChanges`, returning a list of `R`.
41///
42/// See [`PollerBuilder`] for more details.
43pub type FilterPollerBuilder<R> = PollerBuilder<(U256,), Vec<R>>;
44
45/// Ethereum JSON-RPC interface.
46///
47/// # Subscriptions
48///
49/// The provider supports `pubsub` subscriptions to new block headers and
50/// pending transactions. This is only available on `pubsub` clients, such as
51/// Websockets or IPC.
52///
53/// For a polling alternatives available over HTTP, use the `watch_*` methods.
54/// However, be aware that polling increases RPC usage drastically.
55///
56/// ## Special treatment of EIP-1559
57///
58/// While many RPC features are encapsulated by extension traits,
59/// [EIP-1559] fee estimation is generally assumed to be on by default. We
60/// generally assume that [EIP-1559] is supported by the client and will
61/// proactively use it by default.
62///
63/// As a result, the provider supports [EIP-1559] fee estimation the ethereum
64/// [`TransactionBuilder`] will use it by default. We acknowledge that this
65/// means [EIP-1559] has a privileged status in comparison to other transaction
66/// types. Networks that DO NOT support [EIP-1559] should create their own
67/// [`TransactionBuilder`] and Fillers to change this behavior.
68///
69/// [`TransactionBuilder`]: alloy_network::TransactionBuilder
70/// [EIP-1559]: https://eips.ethereum.org/EIPS/eip-1559
71#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
72#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
73#[auto_impl::auto_impl(&, &mut, Rc, Arc, Box)]
74pub trait Provider<N: Network = Ethereum>: Send + Sync {
75    /// Returns the root provider.
76    fn root(&self) -> &RootProvider<N>;
77
78    /// Returns the [`ProviderBuilder`] to build on.
79    fn builder() -> ProviderBuilder<Identity, Identity, N>
80    where
81        Self: Sized,
82    {
83        ProviderBuilder::default()
84    }
85
86    /// Returns the RPC client used to send requests.
87    ///
88    /// NOTE: this method should not be overridden.
89    #[inline]
90    fn client(&self) -> ClientRef<'_> {
91        self.root().client()
92    }
93
94    /// Returns a [`Weak`](std::sync::Weak) RPC client used to send requests.
95    ///
96    /// NOTE: this method should not be overridden.
97    #[inline]
98    fn weak_client(&self) -> WeakClient {
99        self.root().weak_client()
100    }
101
102    /// Returns a type erased provider wrapped in Arc. See [`DynProvider`].
103    ///
104    /// ```no_run
105    /// use alloy_provider::{DynProvider, Provider, ProviderBuilder};
106    ///
107    /// # async fn f() -> Result<(), Box<dyn std::error::Error>> {
108    /// let provider: DynProvider =
109    ///     ProviderBuilder::new().connect("http://localhost:8080").await?.erased();
110    /// let block = provider.get_block_number().await?;
111    /// # Ok(())
112    /// # }
113    /// ```
114    #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
115    #[doc(alias = "boxed")]
116    fn erased(self) -> DynProvider<N>
117    where
118        Self: Sized + 'static,
119    {
120        DynProvider::new(self)
121    }
122
123    /// Gets the accounts in the remote node. This is usually empty unless you're using a local
124    /// node.
125    fn get_accounts(&self) -> ProviderCall<NoParams, Vec<Address>> {
126        self.client().request_noparams("eth_accounts").into()
127    }
128
129    /// Returns the base fee per blob gas (blob gas price) in wei.
130    fn get_blob_base_fee(&self) -> ProviderCall<NoParams, U128, u128> {
131        self.client()
132            .request_noparams("eth_blobBaseFee")
133            .map_resp(utils::convert_u128 as fn(U128) -> u128)
134            .into()
135    }
136
137    /// Get the last block number available.
138    fn get_block_number(&self) -> ProviderCall<NoParams, U64, BlockNumber> {
139        self.client()
140            .request_noparams("eth_blockNumber")
141            .map_resp(utils::convert_u64 as fn(U64) -> u64)
142            .into()
143    }
144
145    /// Get the block number for a given block identifier.
146    ///
147    /// This is a convenience function that fetches the block header when the block identifier is
148    /// not a number. Falls back to fetching the full block if header RPC is not supported.
149    async fn get_block_number_by_id(
150        &self,
151        block_id: BlockId,
152    ) -> TransportResult<Option<BlockNumber>> {
153        match block_id {
154            BlockId::Number(BlockNumberOrTag::Number(num)) => Ok(Some(num)),
155            BlockId::Number(BlockNumberOrTag::Latest) => self.get_block_number().await.map(Some),
156            _ => Ok(self.get_header(block_id).await?.map(|h| h.number())),
157        }
158    }
159
160    /// Execute a smart contract call with a transaction request and state
161    /// overrides, without publishing a transaction.
162    ///
163    /// This function returns [`EthCall`] which can be used to execute the
164    /// call, or to add a [`StateOverride`] or a [`BlockId`]. If no overrides
165    /// or block ID is provided, the call will be executed on the pending block
166    /// with the current state.
167    ///
168    /// [`StateOverride`]: alloy_rpc_types_eth::state::StateOverride
169    ///
170    /// # Examples
171    ///
172    /// ```no_run
173    /// # use alloy_provider::Provider;
174    /// # use alloy_eips::BlockId;
175    /// # use alloy_rpc_types_eth::state::StateOverride;
176    /// # use alloy_transport::BoxTransport;
177    /// # async fn example<P: Provider>(
178    /// #    provider: P,
179    /// #    my_overrides: StateOverride
180    /// # ) -> Result<(), Box<dyn std::error::Error>> {
181    /// # let tx = alloy_rpc_types_eth::transaction::TransactionRequest::default();
182    /// // Execute a call on the latest block, with no state overrides
183    /// let output = provider.call(tx).await?;
184    /// # Ok(())
185    /// # }
186    /// ```
187    #[doc(alias = "eth_call")]
188    #[doc(alias = "call_with_overrides")]
189    fn call(&self, tx: N::TransactionRequest) -> EthCall<N, Bytes> {
190        EthCall::call(self.weak_client(), tx).block(BlockNumberOrTag::Pending.into())
191    }
192
193    /// Execute a list of [`Bundle`]s against the provided [`StateContext`] and [`StateOverride`],
194    /// without publishing a transaction.
195    ///
196    /// This function returns an [`EthCallMany`] builder which is used to execute the call, and also
197    /// set the [`StateContext`] and [`StateOverride`].
198    ///
199    /// [`StateContext`]: alloy_rpc_types_eth::StateContext
200    /// [`StateOverride`]: alloy_rpc_types_eth::state::StateOverride
201    #[doc(alias = "eth_callMany")]
202    fn call_many<'req>(
203        &self,
204        bundles: &'req [Bundle],
205    ) -> EthCallMany<'req, N, Vec<Vec<EthCallResponse>>> {
206        EthCallMany::new(self.weak_client(), bundles)
207    }
208
209    /// Execute a multicall by leveraging the [`MulticallBuilder`].
210    ///
211    /// Call [`MulticallBuilder::dynamic`] to add calls dynamically instead.
212    ///
213    /// See the [`MulticallBuilder`] documentation for more details.
214    #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
215    fn multicall(&self) -> MulticallBuilder<Empty, &Self, N>
216    where
217        Self: Sized,
218    {
219        MulticallBuilder::new(self)
220    }
221
222    /// Executes an arbitrary number of transactions on top of the requested state.
223    ///
224    /// The transactions are packed into individual blocks. Overrides can be provided.
225    #[doc(alias = "eth_simulateV1")]
226    fn simulate<'req>(
227        &self,
228        payload: &'req SimulatePayload,
229    ) -> RpcWithBlock<&'req SimulatePayload, Vec<SimulatedBlock<N::BlockResponse>>> {
230        self.client().request("eth_simulateV1", payload).into()
231    }
232
233    /// Gets the chain ID.
234    fn get_chain_id(&self) -> ProviderCall<NoParams, U64, u64> {
235        self.client()
236            .request_noparams("eth_chainId")
237            .map_resp(utils::convert_u64 as fn(U64) -> u64)
238            .into()
239    }
240
241    /// Create an [EIP-2930] access list.
242    ///
243    /// [EIP-2930]: https://eips.ethereum.org/EIPS/eip-2930
244    fn create_access_list<'a>(
245        &self,
246        request: &'a N::TransactionRequest,
247    ) -> RpcWithBlock<&'a N::TransactionRequest, AccessListResult> {
248        self.client().request("eth_createAccessList", request).into()
249    }
250
251    /// Create an [`EthCall`] future to estimate the gas required for a
252    /// transaction.
253    ///
254    /// The future can be used to specify a [`StateOverride`] or [`BlockId`]
255    /// before dispatching the call. If no overrides or block ID is provided,
256    /// the gas estimate will be computed for the pending block with the
257    /// current state.
258    ///
259    /// [`StateOverride`]: alloy_rpc_types_eth::state::StateOverride
260    ///
261    /// # Note
262    ///
263    /// Not all client implementations support state overrides for `eth_estimateGas`.
264    fn estimate_gas(&self, tx: N::TransactionRequest) -> EthCall<N, U64, u64> {
265        EthCall::gas_estimate(self.weak_client(), tx)
266            .block(BlockNumberOrTag::Pending.into())
267            .map_resp(utils::convert_u64)
268    }
269
270    /// Estimates the [EIP-1559] `maxFeePerGas` and `maxPriorityFeePerGas` fields.
271    ///
272    /// Receives an [`Eip1559Estimator`] that can be used to modify
273    /// how to estimate these fees.
274    ///
275    /// [EIP-1559]: https://eips.ethereum.org/EIPS/eip-1559
276    async fn estimate_eip1559_fees_with(
277        &self,
278        estimator: Eip1559Estimator,
279    ) -> TransportResult<Eip1559Estimation> {
280        let fee_history = self
281            .get_fee_history(
282                utils::EIP1559_FEE_ESTIMATION_PAST_BLOCKS,
283                BlockNumberOrTag::Latest,
284                &[utils::EIP1559_FEE_ESTIMATION_REWARD_PERCENTILE],
285            )
286            .await?;
287
288        // if the base fee of the Latest block is 0 then we need check if the latest block even has
289        // a base fee/supports EIP1559
290        let base_fee_per_gas = match fee_history.latest_block_base_fee() {
291            Some(base_fee) if base_fee != 0 => base_fee,
292            _ => {
293                // empty response, fetch basefee from latest block directly
294                self.get_block_by_number(BlockNumberOrTag::Latest)
295                    .await?
296                    .ok_or(RpcError::NullResp)?
297                    .header()
298                    .as_ref()
299                    .base_fee_per_gas()
300                    .ok_or(RpcError::UnsupportedFeature("eip1559"))?
301                    .into()
302            }
303        };
304
305        Ok(estimator.estimate(base_fee_per_gas, &fee_history.reward.unwrap_or_default()))
306    }
307
308    /// Estimates the [EIP-1559] `maxFeePerGas` and `maxPriorityFeePerGas` fields.
309    ///
310    /// Uses the builtin estimator [`utils::eip1559_default_estimator`] function.
311    ///
312    /// [EIP-1559]: https://eips.ethereum.org/EIPS/eip-1559
313    async fn estimate_eip1559_fees(&self) -> TransportResult<Eip1559Estimation> {
314        self.estimate_eip1559_fees_with(Eip1559Estimator::default()).await
315    }
316
317    /// Returns a collection of historical gas information [`FeeHistory`] which
318    /// can be used to calculate the [EIP-1559] fields `maxFeePerGas` and `maxPriorityFeePerGas`.
319    /// `block_count` can range from 1 to 1024 blocks in a single request.
320    ///
321    /// [EIP-1559]: https://eips.ethereum.org/EIPS/eip-1559
322    async fn get_fee_history(
323        &self,
324        block_count: u64,
325        last_block: BlockNumberOrTag,
326        reward_percentiles: &[f64],
327    ) -> TransportResult<FeeHistory> {
328        self.client()
329            .request("eth_feeHistory", (U64::from(block_count), last_block, reward_percentiles))
330            .await
331    }
332
333    /// Gets the current gas price in wei.
334    fn get_gas_price(&self) -> ProviderCall<NoParams, U128, u128> {
335        self.client()
336            .request_noparams("eth_gasPrice")
337            .map_resp(utils::convert_u128 as fn(U128) -> u128)
338            .into()
339    }
340
341    /// Retrieves account information ([`Account`](alloy_rpc_types_eth::Account)) for the given
342    /// [`Address`] at the particular [`BlockId`].
343    ///
344    /// Note: This is slightly different than `eth_getAccount` and not all clients support this
345    /// endpoint.
346    fn get_account_info(
347        &self,
348        address: Address,
349    ) -> RpcWithBlock<Address, alloy_rpc_types_eth::AccountInfo> {
350        self.client().request("eth_getAccountInfo", address).into()
351    }
352
353    /// Retrieves account information ([`TrieAccount`](alloy_consensus::TrieAccount)) for the given
354    /// [`Address`] at the particular [`BlockId`].
355    fn get_account(&self, address: Address) -> RpcWithBlock<Address, alloy_consensus::TrieAccount> {
356        self.client().request("eth_getAccount", address).into()
357    }
358
359    /// Gets the balance of the account.
360    ///
361    /// Defaults to the latest block. See also [`RpcWithBlock::block_id`].
362    fn get_balance(&self, address: Address) -> RpcWithBlock<Address, U256, U256> {
363        self.client().request("eth_getBalance", address).into()
364    }
365
366    /// Gets a block by either its hash, tag, or number
367    ///
368    /// By default this fetches the block with only the transaction hashes, and not full
369    /// transactions.
370    ///
371    /// To get full transactions one can do:
372    ///
373    /// ```ignore
374    /// let block = provider.get_block(BlockId::latest()).full().await.unwrap();
375    /// ```
376    fn get_block(&self, block: BlockId) -> EthGetBlock<N::BlockResponse> {
377        match block {
378            BlockId::Hash(hash) => EthGetBlock::by_hash(hash.block_hash, self.client()),
379            BlockId::Number(number) => EthGetBlock::by_number(number, self.client()),
380        }
381    }
382
383    /// Gets a block by its [`BlockHash`]
384    ///
385    /// By default this fetches the block with only the transaction hashes populated in the block,
386    /// and not the full transactions.
387    ///
388    /// # Examples
389    ///
390    /// ```no_run
391    /// # use alloy_provider::{Provider, ProviderBuilder};
392    /// # use alloy_primitives::b256;
393    ///
394    /// #[tokio::main]
395    /// async fn main() {
396    ///     let provider =
397    ///         ProviderBuilder::new().connect_http("https://eth.merkle.io".parse().unwrap());
398    ///     let block_hash = b256!("6032d03ee8e43e8999c2943152a4daebfc4b75b7f7a9647d2677299d215127da");
399    ///
400    ///     // Gets a block by its hash with only transactions hashes.
401    ///     let block = provider.get_block_by_hash(block_hash).await.unwrap();
402    ///
403    ///     // Gets a block by its hash with full transactions.
404    ///     let block = provider.get_block_by_hash(block_hash).full().await.unwrap();
405    /// }
406    /// ```
407    fn get_block_by_hash(&self, hash: BlockHash) -> EthGetBlock<N::BlockResponse> {
408        EthGetBlock::by_hash(hash, self.client())
409    }
410
411    /// Gets a block by its [`BlockNumberOrTag`]
412    ///
413    /// By default this fetches the block with only the transaction hashes populated in the block,
414    /// and not the full transactions.
415    ///
416    /// # Examples
417    ///
418    /// ```no_run
419    /// # use alloy_provider::{Provider, ProviderBuilder};
420    /// # use alloy_eips::BlockNumberOrTag;
421    ///
422    /// #[tokio::main]
423    /// async fn main() {
424    ///     let provider =
425    ///         ProviderBuilder::new().connect_http("https://eth.merkle.io".parse().unwrap());
426    ///     let num = BlockNumberOrTag::Number(0);
427    ///
428    ///     // Gets a block by its number with only transactions hashes.
429    ///     let block = provider.get_block_by_number(num).await.unwrap();
430    ///
431    ///     // Gets a block by its number with full transactions.
432    ///     let block = provider.get_block_by_number(num).full().await.unwrap();
433    /// }
434    /// ```
435    fn get_block_by_number(&self, number: BlockNumberOrTag) -> EthGetBlock<N::BlockResponse> {
436        EthGetBlock::by_number(number, self.client())
437    }
438
439    /// Returns the number of transactions in a block from a block matching the given block hash.
440    async fn get_block_transaction_count_by_hash(
441        &self,
442        hash: BlockHash,
443    ) -> TransportResult<Option<u64>> {
444        self.client()
445            .request("eth_getBlockTransactionCountByHash", (hash,))
446            .await
447            .map(|opt_count: Option<U64>| opt_count.map(|count| count.to::<u64>()))
448    }
449
450    /// Returns the number of transactions in a block matching the given block number.
451    async fn get_block_transaction_count_by_number(
452        &self,
453        block_number: BlockNumberOrTag,
454    ) -> TransportResult<Option<u64>> {
455        self.client()
456            .request("eth_getBlockTransactionCountByNumber", (block_number,))
457            .await
458            .map(|opt_count: Option<U64>| opt_count.map(|count| count.to::<u64>()))
459    }
460
461    /// Gets the selected block [`BlockId`] receipts.
462    fn get_block_receipts(
463        &self,
464        block: BlockId,
465    ) -> ProviderCall<(BlockId,), Option<Vec<N::ReceiptResponse>>> {
466        self.client().request("eth_getBlockReceipts", (block,)).into()
467    }
468
469    /// Gets the EIP-7928 block access list by [`BlockId`].
470    ///
471    /// Returns the RLP-encoded block access list, or `None` if the block is not found.
472    async fn get_block_access_list(&self, block: BlockId) -> TransportResult<Option<Bytes>> {
473        match block {
474            BlockId::Hash(hash) => self.get_block_access_list_by_hash(hash.block_hash).await,
475            BlockId::Number(number) => self.get_block_access_list_by_number(number).await,
476        }
477    }
478
479    /// Gets the EIP-7928 block access list by [`BlockHash`].
480    ///
481    /// Returns the RLP-encoded block access list, or `None` if the block is not found.
482    async fn get_block_access_list_by_hash(
483        &self,
484        hash: BlockHash,
485    ) -> TransportResult<Option<Bytes>> {
486        self.client().request("eth_getBlockAccessListByBlockHash", (hash,)).await
487    }
488
489    /// Gets the EIP-7928 block access list by [`BlockNumberOrTag`].
490    ///
491    /// Returns the RLP-encoded block access list, or `None` if the block is not found.
492    async fn get_block_access_list_by_number(
493        &self,
494        number: BlockNumberOrTag,
495    ) -> TransportResult<Option<Bytes>> {
496        self.client().request("eth_getBlockAccessListByBlockNumber", (number,)).await
497    }
498
499    /// Gets a block header by its [`BlockId`].
500    ///
501    /// # Examples
502    ///
503    /// ```no_run
504    /// # use alloy_provider::{Provider, ProviderBuilder};
505    /// # use alloy_eips::BlockId;
506    ///
507    /// #[tokio::main]
508    /// async fn main() {
509    ///     let provider =
510    ///         ProviderBuilder::new().connect_http("https://eth.merkle.io".parse().unwrap());
511    ///
512    ///     // Gets the latest block header.
513    ///     let header = provider.get_header(BlockId::latest()).await.unwrap();
514    ///
515    ///     // Gets the block header by number.
516    ///     let header = provider.get_header(BlockId::number(0)).await.unwrap();
517    /// }
518    /// ```
519    async fn get_header(&self, block: BlockId) -> TransportResult<Option<N::HeaderResponse>> {
520        match block {
521            BlockId::Hash(hash) => self.get_header_by_hash(hash.block_hash).await,
522            BlockId::Number(number) => self.get_header_by_number(number).await,
523        }
524    }
525
526    /// Gets a block header by its [`BlockHash`].
527    ///
528    /// # Examples
529    ///
530    /// ```no_run
531    /// # use alloy_provider::{Provider, ProviderBuilder};
532    /// # use alloy_primitives::b256;
533    ///
534    /// #[tokio::main]
535    /// async fn main() {
536    ///     let provider =
537    ///         ProviderBuilder::new().connect_http("https://eth.merkle.io".parse().unwrap());
538    ///     let block_hash = b256!("6032d03ee8e43e8999c2943152a4daebfc4b75b7f7a9647d2677299d215127da");
539    ///
540    ///     // Gets a block header by its hash.
541    ///     let header = provider.get_header_by_hash(block_hash).await.unwrap();
542    /// }
543    /// ```
544    async fn get_header_by_hash(
545        &self,
546        hash: BlockHash,
547    ) -> TransportResult<Option<N::HeaderResponse>> {
548        match self.client().request("eth_getHeaderByHash", (hash,)).await {
549            Ok(header) => Ok(header),
550            // eth_getHeaderByHash is non-standard; fall back to eth_getBlockByHash
551            Err(err) if err.as_error_resp().is_some_and(|e| e.code == -32601) => {
552                Ok(self.get_block_by_hash(hash).await?.map(|b| b.header().clone()))
553            }
554            Err(err) => Err(err),
555        }
556    }
557
558    /// Gets a block header by its [`BlockNumberOrTag`].
559    ///
560    /// # Examples
561    ///
562    /// ```no_run
563    /// # use alloy_provider::{Provider, ProviderBuilder};
564    /// # use alloy_eips::BlockNumberOrTag;
565    ///
566    /// #[tokio::main]
567    /// async fn main() {
568    ///     let provider =
569    ///         ProviderBuilder::new().connect_http("https://eth.merkle.io".parse().unwrap());
570    ///
571    ///     // Gets a block header by its number.
572    ///     let header = provider.get_header_by_number(BlockNumberOrTag::Number(0)).await.unwrap();
573    ///
574    ///     // Gets the latest block header.
575    ///     let header = provider.get_header_by_number(BlockNumberOrTag::Latest).await.unwrap();
576    /// }
577    /// ```
578    async fn get_header_by_number(
579        &self,
580        number: BlockNumberOrTag,
581    ) -> TransportResult<Option<N::HeaderResponse>> {
582        match self.client().request("eth_getHeaderByNumber", (number,)).await {
583            Ok(header) => Ok(header),
584            // eth_getHeaderByNumber is non-standard; fall back to eth_getBlockByNumber
585            Err(err) if err.as_error_resp().is_some_and(|e| e.code == -32601) => {
586                Ok(self.get_block_by_number(number).await?.map(|b| b.header().clone()))
587            }
588            Err(err) => Err(err),
589        }
590    }
591
592    /// Gets the bytecode located at the corresponding [`Address`].
593    fn get_code_at(&self, address: Address) -> RpcWithBlock<Address, Bytes> {
594        self.client().request("eth_getCode", address).into()
595    }
596
597    /// Watch for new blocks by polling the provider with
598    /// [`eth_getFilterChanges`](Self::get_filter_changes).
599    ///
600    /// Returns a builder that is used to configure the poller. See [`PollerBuilder`] for more
601    /// details.
602    ///
603    /// # Examples
604    ///
605    /// Get the next 5 blocks:
606    ///
607    /// ```no_run
608    /// # async fn example(provider: impl alloy_provider::Provider) -> Result<(), Box<dyn std::error::Error>> {
609    /// use futures::StreamExt;
610    ///
611    /// let poller = provider.watch_blocks().await?;
612    /// let mut stream = poller.into_stream().flat_map(futures::stream::iter).take(5);
613    /// while let Some(block_hash) = stream.next().await {
614    ///    println!("new block: {block_hash}");
615    /// }
616    /// # Ok(())
617    /// # }
618    /// ```
619    async fn watch_blocks(&self) -> TransportResult<FilterPollerBuilder<B256>> {
620        let id = self.new_block_filter().await?;
621        Ok(PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,)))
622    }
623
624    /// Watch for new blocks by polling the provider with
625    /// [`eth_getFilterChanges`](Self::get_filter_changes) and transforming the returned block
626    /// hashes into full blocks bodies.
627    ///
628    /// Returns the [`WatchBlocks`] type which consumes the stream of block hashes from
629    /// [`PollerBuilder`] and returns a stream of [`BlockResponse`]s.
630    ///
631    /// # Examples
632    ///
633    /// Get the next 5 full blocks:
634    ///
635    /// ```no_run
636    /// # async fn example(provider: impl alloy_provider::Provider) -> Result<(), Box<dyn std::error::Error>> {
637    /// use futures::StreamExt;
638    ///
639    /// let poller = provider.watch_full_blocks().await?.full();
640    /// let mut stream = poller.into_stream().flat_map(futures::stream::iter).take(5);
641    /// while let Some(block) = stream.next().await {
642    ///   println!("new block: {block:#?}");
643    /// }
644    /// # Ok(())
645    /// # }
646    /// ```
647    async fn watch_full_blocks(&self) -> TransportResult<WatchBlocks<N::BlockResponse>> {
648        let id = self.new_block_filter().await?;
649        let poller = PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,));
650
651        Ok(WatchBlocks::new(poller))
652    }
653
654    /// Watch for new blocks by polling the provider with
655    /// [`eth_getFilterChanges`](Self::get_filter_changes) and fetching the header for each
656    /// returned block hash.
657    ///
658    /// Returns the [`WatchHeaders`] type which consumes the stream of block hashes from
659    /// [`PollerBuilder`] and returns a stream of [`alloy_network_primitives::HeaderResponse`]s.
660    ///
661    /// Note that the backing RPC methods (`eth_getHeaderByHash` / `eth_getHeaderByNumber`) are
662    /// not supported by all clients.
663    ///
664    /// # Examples
665    ///
666    /// Get the next 5 headers:
667    ///
668    /// ```no_run
669    /// # async fn example(provider: impl alloy_provider::Provider) -> Result<(), Box<dyn std::error::Error>> {
670    /// use futures::StreamExt;
671    ///
672    /// let poller = provider.watch_headers().await?;
673    /// let mut stream = poller.into_stream().take(5);
674    /// while let Some(header) = stream.next().await {
675    ///   println!("new header: {header:#?}");
676    /// }
677    /// # Ok(())
678    /// # }
679    /// ```
680    async fn watch_headers(&self) -> TransportResult<WatchHeaders<N::HeaderResponse>> {
681        let id = self.new_block_filter().await?;
682        let poller = PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,));
683
684        Ok(WatchHeaders::new(poller))
685    }
686
687    /// Watch for new pending transaction by polling the provider with
688    /// [`eth_getFilterChanges`](Self::get_filter_changes).
689    ///
690    /// Returns a builder that is used to configure the poller. See [`PollerBuilder`] for more
691    /// details.
692    ///
693    /// # Examples
694    ///
695    /// Get the next 5 pending transaction hashes:
696    ///
697    /// ```no_run
698    /// # async fn example(provider: impl alloy_provider::Provider) -> Result<(), Box<dyn std::error::Error>> {
699    /// use futures::StreamExt;
700    ///
701    /// let poller = provider.watch_pending_transactions().await?;
702    /// let mut stream = poller.into_stream().flat_map(futures::stream::iter).take(5);
703    /// while let Some(tx_hash) = stream.next().await {
704    ///    println!("new pending transaction hash: {tx_hash}");
705    /// }
706    /// # Ok(())
707    /// # }
708    /// ```
709    async fn watch_pending_transactions(&self) -> TransportResult<FilterPollerBuilder<B256>> {
710        let id = self.new_pending_transactions_filter(false).await?;
711        Ok(PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,)))
712    }
713
714    /// Watch for new logs using the given filter by polling the provider with
715    /// [`eth_getFilterChanges`](Self::get_filter_changes).
716    ///
717    /// Returns a builder that is used to configure the poller. See [`PollerBuilder`] for more
718    /// details.
719    ///
720    /// # Examples
721    ///
722    /// Get the next 5 USDC transfer logs:
723    ///
724    /// ```no_run
725    /// # async fn example(provider: impl alloy_provider::Provider) -> Result<(), Box<dyn std::error::Error>> {
726    /// use alloy_primitives::{address, b256};
727    /// use alloy_rpc_types_eth::Filter;
728    /// use futures::StreamExt;
729    ///
730    /// let address = address!("a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48");
731    /// let transfer_signature = b256!("ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef");
732    /// let filter = Filter::new().address(address).event_signature(transfer_signature);
733    ///
734    /// let poller = provider.watch_logs(&filter).await?;
735    /// let mut stream = poller.into_stream().flat_map(futures::stream::iter).take(5);
736    /// while let Some(log) = stream.next().await {
737    ///    println!("new log: {log:#?}");
738    /// }
739    /// # Ok(())
740    /// # }
741    /// ```
742    async fn watch_logs(&self, filter: &Filter) -> TransportResult<FilterPollerBuilder<Log>> {
743        let id = self.new_filter(filter).await?;
744        Ok(PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,)))
745    }
746
747    /// Watch for new pending transaction bodies by polling the provider with
748    /// [`eth_getFilterChanges`](Self::get_filter_changes).
749    ///
750    /// Returns a builder that is used to configure the poller. See [`PollerBuilder`] for more
751    /// details.
752    ///
753    /// # Support
754    ///
755    /// This endpoint might not be supported by all clients.
756    ///
757    /// # Examples
758    ///
759    /// Get the next 5 pending transaction bodies:
760    ///
761    /// ```no_run
762    /// # async fn example(provider: impl alloy_provider::Provider) -> Result<(), Box<dyn std::error::Error>> {
763    /// use futures::StreamExt;
764    ///
765    /// let poller = provider.watch_full_pending_transactions().await?;
766    /// let mut stream = poller.into_stream().flat_map(futures::stream::iter).take(5);
767    /// while let Some(tx) = stream.next().await {
768    ///    println!("new pending transaction: {tx:#?}");
769    /// }
770    /// # Ok(())
771    /// # }
772    /// ```
773    async fn watch_full_pending_transactions(
774        &self,
775    ) -> TransportResult<FilterPollerBuilder<N::TransactionResponse>> {
776        let id = self.new_pending_transactions_filter(true).await?;
777        Ok(PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,)))
778    }
779
780    /// Get a list of values that have been added since the last poll.
781    ///
782    /// The return value depends on what stream `id` corresponds to.
783    /// See [`FilterChanges`] for all possible return values.
784    #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
785    async fn get_filter_changes<R: RpcRecv>(&self, id: U256) -> TransportResult<Vec<R>>
786    where
787        Self: Sized,
788    {
789        self.client().request("eth_getFilterChanges", (id,)).await
790    }
791
792    /// Get a list of values that have been added since the last poll.
793    ///
794    /// This returns an enum over all possible return values. You probably want to use
795    /// [`get_filter_changes`](Self::get_filter_changes) instead.
796    async fn get_filter_changes_dyn(&self, id: U256) -> TransportResult<FilterChanges> {
797        self.client().request("eth_getFilterChanges", (id,)).await
798    }
799
800    /// Retrieves a [`Vec<Log>`] for the given filter ID.
801    async fn get_filter_logs(&self, id: U256) -> TransportResult<Vec<Log>> {
802        self.client().request("eth_getFilterLogs", (id,)).await
803    }
804
805    /// Request provider to uninstall the filter with the given ID.
806    async fn uninstall_filter(&self, id: U256) -> TransportResult<bool> {
807        self.client().request("eth_uninstallFilter", (id,)).await
808    }
809
810    /// Watch for the confirmation of a single pending transaction with the given configuration.
811    ///
812    /// Note that this is handled internally rather than calling any specific RPC method, and as
813    /// such should not be overridden.
814    #[inline]
815    async fn watch_pending_transaction(
816        &self,
817        config: PendingTransactionConfig,
818    ) -> Result<PendingTransaction, PendingTransactionError> {
819        self.root().watch_pending_transaction(config).await
820    }
821
822    /// Retrieves a [`Vec<Log>`] with the given [`Filter`].
823    async fn get_logs(&self, filter: &Filter) -> TransportResult<Vec<Log>> {
824        self.client().request("eth_getLogs", (filter,)).await
825    }
826
827    /// Get the account and storage values of the specified account including the merkle proofs.
828    ///
829    /// This call can be used to verify that the data has not been tampered with.
830    fn get_proof(
831        &self,
832        address: Address,
833        keys: Vec<StorageKey>,
834    ) -> RpcWithBlock<(Address, Vec<StorageKey>), EIP1186AccountProofResponse> {
835        self.client().request("eth_getProof", (address, keys)).into()
836    }
837
838    /// Gets the specified storage value from [`Address`].
839    fn get_storage_at(
840        &self,
841        address: Address,
842        key: U256,
843    ) -> RpcWithBlock<(Address, U256), StorageValue> {
844        self.client().request("eth_getStorageAt", (address, key)).into()
845    }
846
847    /// Batch-fetches storage values from multiple addresses at multiple keys.
848    ///
849    /// See [EIP spec](https://github.com/ethereum/execution-apis/issues/752).
850    fn get_storage_values(
851        &self,
852        requests: StorageValuesRequest,
853    ) -> RpcWithBlock<(StorageValuesRequest,), StorageValuesResponse> {
854        self.client().request("eth_getStorageValues", (requests,)).into()
855    }
856
857    /// Gets a transaction by its sender and nonce.
858    ///
859    /// Note: not supported by all clients.
860    fn get_transaction_by_sender_nonce(
861        &self,
862        sender: Address,
863        nonce: u64,
864    ) -> ProviderCall<(Address, U64), Option<N::TransactionResponse>> {
865        self.client()
866            .request("eth_getTransactionBySenderAndNonce", (sender, U64::from(nonce)))
867            .into()
868    }
869
870    /// Gets a transaction by its [`TxHash`].
871    fn get_transaction_by_hash(
872        &self,
873        hash: TxHash,
874    ) -> ProviderCall<(TxHash,), Option<N::TransactionResponse>> {
875        self.client().request("eth_getTransactionByHash", (hash,)).into()
876    }
877
878    /// Gets a transaction by block hash and transaction index position.
879    fn get_transaction_by_block_hash_and_index(
880        &self,
881        block_hash: B256,
882        index: usize,
883    ) -> ProviderCall<(B256, Index), Option<N::TransactionResponse>> {
884        self.client()
885            .request("eth_getTransactionByBlockHashAndIndex", (block_hash, Index(index)))
886            .into()
887    }
888
889    /// Gets a raw transaction by block hash and transaction index position.
890    fn get_raw_transaction_by_block_hash_and_index(
891        &self,
892        block_hash: B256,
893        index: usize,
894    ) -> ProviderCall<(B256, Index), Option<Bytes>> {
895        self.client()
896            .request("eth_getRawTransactionByBlockHashAndIndex", (block_hash, Index(index)))
897            .into()
898    }
899
900    /// Gets a transaction by block number and transaction index position.
901    fn get_transaction_by_block_number_and_index(
902        &self,
903        block_number: BlockNumberOrTag,
904        index: usize,
905    ) -> ProviderCall<(BlockNumberOrTag, Index), Option<N::TransactionResponse>> {
906        self.client()
907            .request("eth_getTransactionByBlockNumberAndIndex", (block_number, Index(index)))
908            .into()
909    }
910
911    /// Gets a raw transaction by block number and transaction index position.
912    fn get_raw_transaction_by_block_number_and_index(
913        &self,
914        block_number: BlockNumberOrTag,
915        index: usize,
916    ) -> ProviderCall<(BlockNumberOrTag, Index), Option<Bytes>> {
917        self.client()
918            .request("eth_getRawTransactionByBlockNumberAndIndex", (block_number, Index(index)))
919            .into()
920    }
921
922    /// Returns the [EIP-2718] encoded transaction if it exists, see also
923    /// [`Decodable2718`](alloy_eips::eip2718::Decodable2718).
924    ///
925    /// If the transaction is an [EIP-4844] transaction that is still in the pool (pending) it will
926    /// include the sidecar, otherwise it will the consensus variant without the sidecar:
927    /// [`TxEip4844`](alloy_consensus::transaction::eip4844::TxEip4844).
928    ///
929    /// This can be decoded into [`TxEnvelope`](alloy_consensus::transaction::TxEnvelope).
930    ///
931    /// [EIP-2718]: https://eips.ethereum.org/EIPS/eip-2718
932    /// [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844
933    fn get_raw_transaction_by_hash(&self, hash: TxHash) -> ProviderCall<(TxHash,), Option<Bytes>> {
934        self.client().request("eth_getRawTransactionByHash", (hash,)).into()
935    }
936
937    /// Gets the transaction count (AKA "nonce") of the corresponding address.
938    #[doc(alias = "get_nonce")]
939    #[doc(alias = "get_account_nonce")]
940    fn get_transaction_count(
941        &self,
942        address: Address,
943    ) -> RpcWithBlock<Address, U64, u64, fn(U64) -> u64> {
944        self.client()
945            .request("eth_getTransactionCount", address)
946            .map_resp(utils::convert_u64 as fn(U64) -> u64)
947            .into()
948    }
949
950    /// Gets a transaction receipt if it exists, by its [`TxHash`].
951    fn get_transaction_receipt(
952        &self,
953        hash: TxHash,
954    ) -> ProviderCall<(TxHash,), Option<N::ReceiptResponse>> {
955        self.client().request("eth_getTransactionReceipt", (hash,)).into()
956    }
957
958    /// Gets an uncle block through the tag [`BlockId`] and index `u64`.
959    async fn get_uncle(&self, tag: BlockId, idx: u64) -> TransportResult<Option<N::BlockResponse>> {
960        let idx = U64::from(idx);
961        match tag {
962            BlockId::Hash(hash) => {
963                self.client()
964                    .request("eth_getUncleByBlockHashAndIndex", (hash.block_hash, idx))
965                    .await
966            }
967            BlockId::Number(number) => {
968                self.client().request("eth_getUncleByBlockNumberAndIndex", (number, idx)).await
969            }
970        }
971    }
972
973    /// Gets the number of uncles for the block specified by the tag [`BlockId`].
974    async fn get_uncle_count(&self, tag: BlockId) -> TransportResult<u64> {
975        match tag {
976            BlockId::Hash(hash) => self
977                .client()
978                .request("eth_getUncleCountByBlockHash", (hash.block_hash,))
979                .await
980                .map(|count: U64| count.to::<u64>()),
981            BlockId::Number(number) => self
982                .client()
983                .request("eth_getUncleCountByBlockNumber", (number,))
984                .await
985                .map(|count: U64| count.to::<u64>()),
986        }
987    }
988
989    /// Returns a suggestion for the current `maxPriorityFeePerGas` in wei.
990    fn get_max_priority_fee_per_gas(&self) -> ProviderCall<NoParams, U128, u128> {
991        self.client()
992            .request_noparams("eth_maxPriorityFeePerGas")
993            .map_resp(utils::convert_u128 as fn(U128) -> u128)
994            .into()
995    }
996
997    /// Notify the provider that we are interested in new blocks.
998    ///
999    /// Returns the ID to use with [`eth_getFilterChanges`](Self::get_filter_changes).
1000    ///
1001    /// See also [`watch_blocks`](Self::watch_blocks) to configure a poller.
1002    async fn new_block_filter(&self) -> TransportResult<U256> {
1003        self.client().request_noparams("eth_newBlockFilter").await
1004    }
1005
1006    /// Notify the provider that we are interested in logs that match the given [`Filter`].
1007    ///
1008    /// Returns the ID to use with [`eth_getFilterChanges`](Self::get_filter_changes).
1009    ///
1010    /// See also [`watch_logs`](Self::watch_logs) to configure a poller.
1011    async fn new_filter(&self, filter: &Filter) -> TransportResult<U256> {
1012        self.client().request("eth_newFilter", (filter,)).await
1013    }
1014
1015    /// Notify the provider that we are interested in new pending transactions.
1016    ///
1017    /// If `full` is `true`, the stream will consist of full transaction bodies instead of just the
1018    /// hashes. This not supported by all clients.
1019    ///
1020    /// Returns the ID to use with [`eth_getFilterChanges`](Self::get_filter_changes).
1021    ///
1022    /// See also [`watch_pending_transactions`](Self::watch_pending_transactions) to configure a
1023    /// poller.
1024    async fn new_pending_transactions_filter(&self, full: bool) -> TransportResult<U256> {
1025        // NOTE: We don't want to send `false` as the client might not support it.
1026        let param = if full { &[true][..] } else { &[] };
1027        self.client().request("eth_newPendingTransactionFilter", param).await
1028    }
1029
1030    /// Broadcasts a raw transaction RLP bytes to the network.
1031    ///
1032    /// See [`send_transaction`](Self::send_transaction) for more details.
1033    async fn send_raw_transaction(
1034        &self,
1035        encoded_tx: &[u8],
1036    ) -> TransportResult<PendingTransactionBuilder<N>> {
1037        let rlp_hex = hex::encode_prefixed(encoded_tx);
1038        let tx_hash = self.client().request("eth_sendRawTransaction", (rlp_hex,)).await?;
1039        Ok(PendingTransactionBuilder::new(self.root().clone(), tx_hash))
1040    }
1041
1042    /// Broadcasts a raw transaction RLP bytes to the network and returns the transaction receipt
1043    /// after it has been mined.
1044    ///
1045    /// Unlike send_raw_transaction which returns immediately with
1046    /// a transaction hash, this method waits on the server side until the transaction is included
1047    /// in a block and returns the receipt directly. This is an optimization that reduces the number
1048    /// of RPC calls needed to confirm a transaction.
1049    ///
1050    /// This method implements the `eth_sendRawTransactionSync` RPC method as defined in
1051    /// [EIP-7966].
1052    ///
1053    /// [EIP-7966]: https://github.com/ethereum/EIPs/pull/9151
1054    ///
1055    /// # Error Handling
1056    ///
1057    /// If the transaction fails, you can extract the transaction hash from the error using
1058    /// [`RpcError::tx_hash_data`]:
1059    ///
1060    /// ```no_run
1061    /// # use alloy_json_rpc::RpcError;
1062    /// # use alloy_network_primitives::ReceiptResponse;
1063    /// # async fn example<N: alloy_network::Network>(provider: impl alloy_provider::Provider<N>, encoded_tx: &[u8]) {
1064    /// match provider.send_raw_transaction_sync(encoded_tx).await {
1065    ///     Ok(receipt) => {
1066    ///         println!("Transaction successful: {}", receipt.transaction_hash());
1067    ///     }
1068    ///     Err(rpc_err) => {
1069    ///         if let Some(tx_hash) = rpc_err.tx_hash_data() {
1070    ///             println!("Transaction failed but hash available: {}", tx_hash);
1071    ///         }
1072    ///     }
1073    /// }
1074    /// # }
1075    /// ```
1076    ///
1077    /// Note: This is only available on certain clients that support the
1078    /// `eth_sendRawTransactionSync` RPC method, such as Anvil.
1079    async fn send_raw_transaction_sync(
1080        &self,
1081        encoded_tx: &[u8],
1082    ) -> TransportResult<N::ReceiptResponse> {
1083        let rlp_hex = hex::encode_prefixed(encoded_tx);
1084        self.client().request("eth_sendRawTransactionSync", (rlp_hex,)).await
1085    }
1086
1087    /// Broadcasts a raw transaction RLP bytes with a conditional [`TransactionConditional`] to the
1088    /// network.
1089    ///
1090    /// [`TransactionConditional`] represents the preconditions that determine the inclusion of the
1091    /// transaction, enforced out-of-protocol by the sequencer.
1092    ///
1093    /// Note: This endpoint is only available on certain networks, e.g. opstack chains, polygon,
1094    /// bsc.
1095    ///
1096    /// See [`TransactionConditional`] for more details.
1097    async fn send_raw_transaction_conditional(
1098        &self,
1099        encoded_tx: &[u8],
1100        conditional: TransactionConditional,
1101    ) -> TransportResult<PendingTransactionBuilder<N>> {
1102        let rlp_hex = hex::encode_prefixed(encoded_tx);
1103        let tx_hash = self
1104            .client()
1105            .request("eth_sendRawTransactionConditional", (rlp_hex, conditional))
1106            .await?;
1107        Ok(PendingTransactionBuilder::new(self.root().clone(), tx_hash))
1108    }
1109
1110    /// Broadcasts a transaction to the network.
1111    ///
1112    /// Returns a [`PendingTransactionBuilder`] which can be used to configure
1113    /// how and when to await the transaction's confirmation.
1114    ///
1115    /// # Examples
1116    ///
1117    /// See [`PendingTransactionBuilder`](crate::PendingTransactionBuilder) for more examples.
1118    ///
1119    /// ```no_run
1120    /// # async fn example<N: alloy_network::Network>(provider: impl alloy_provider::Provider, tx: alloy_rpc_types_eth::transaction::TransactionRequest) -> Result<(), Box<dyn std::error::Error>> {
1121    /// let tx_hash = provider.send_transaction(tx)
1122    ///     .await?
1123    ///     .with_required_confirmations(2)
1124    ///     .with_timeout(Some(std::time::Duration::from_secs(60)))
1125    ///     .watch()
1126    ///     .await?;
1127    /// # Ok(())
1128    /// # }
1129    /// ```
1130    async fn send_transaction(
1131        &self,
1132        tx: N::TransactionRequest,
1133    ) -> TransportResult<PendingTransactionBuilder<N>> {
1134        self.send_transaction_internal(SendableTx::Builder(tx)).await
1135    }
1136
1137    /// Broadcasts a transaction envelope to the network.
1138    ///
1139    /// Returns a [`PendingTransactionBuilder`] which can be used to configure
1140    /// how and when to await the transaction's confirmation.
1141    async fn send_tx_envelope(
1142        &self,
1143        tx: N::TxEnvelope,
1144    ) -> TransportResult<PendingTransactionBuilder<N>> {
1145        self.send_transaction_internal(SendableTx::Envelope(tx)).await
1146    }
1147
1148    /// This method allows [`ProviderLayer`] and [`TxFiller`] to build the
1149    /// transaction and send it to the network without changing user-facing
1150    /// APIs. Generally implementers should NOT override this method.
1151    ///
1152    /// [`ProviderLayer`]: crate::ProviderLayer
1153    /// [`TxFiller`]: crate::fillers::TxFiller
1154    #[doc(hidden)]
1155    async fn send_transaction_internal(
1156        &self,
1157        tx: SendableTx<N>,
1158    ) -> TransportResult<PendingTransactionBuilder<N>> {
1159        // Make sure to initialize heartbeat before we submit transaction, so that
1160        // we don't miss it if user will subscriber to it immediately after sending.
1161        let _handle = self.root().get_heart();
1162
1163        match tx {
1164            SendableTx::Builder(mut tx) => {
1165                alloy_network::NetworkTransactionBuilder::prep_for_submission(&mut tx);
1166                let tx_hash = self.client().request("eth_sendTransaction", (tx,)).await?;
1167                Ok(PendingTransactionBuilder::new(self.root().clone(), tx_hash))
1168            }
1169            SendableTx::Envelope(tx) => {
1170                let encoded_tx = tx.encoded_2718();
1171                self.send_raw_transaction(&encoded_tx).await
1172            }
1173        }
1174    }
1175
1176    /// Sends a transaction and waits for its receipt in a single call.
1177    ///
1178    /// This method combines transaction submission and receipt retrieval into a single
1179    /// async operation, providing a simpler API compared to the two-step process of
1180    /// [`send_transaction`](Self::send_transaction) followed by waiting for confirmation.
1181    ///
1182    /// Returns the transaction receipt directly after submission and confirmation.
1183    ///
1184    /// # Example
1185    /// ```no_run
1186    /// # use alloy_network_primitives::ReceiptResponse;
1187    /// # async fn example<N: alloy_network::Network>(provider: impl alloy_provider::Provider<N>, tx: N::TransactionRequest) -> Result<(), Box<dyn std::error::Error>> {
1188    /// let receipt = provider.send_transaction_sync(tx).await?;
1189    /// println!("Transaction hash: {}", receipt.transaction_hash());
1190    /// # Ok(())
1191    /// # }
1192    /// ```
1193    ///
1194    /// # Error Handling
1195    ///
1196    /// If the transaction fails, you can extract the transaction hash from the error using
1197    /// [`RpcError::tx_hash_data`]:
1198    ///
1199    /// ```no_run
1200    /// # use alloy_json_rpc::RpcError;
1201    /// # use alloy_network_primitives::ReceiptResponse;
1202    /// # async fn example<N: alloy_network::Network>(provider: impl alloy_provider::Provider<N>, tx: N::TransactionRequest) {
1203    /// match provider.send_transaction_sync(tx).await {
1204    ///     Ok(receipt) => {
1205    ///         println!("Transaction successful: {}", receipt.transaction_hash());
1206    ///     }
1207    ///     Err(rpc_err) => {
1208    ///         if let Some(tx_hash) = rpc_err.tx_hash_data() {
1209    ///             println!("Transaction failed but hash available: {}", tx_hash);
1210    ///         }
1211    ///     }
1212    /// }
1213    /// # }
1214    /// ```
1215    async fn send_transaction_sync(
1216        &self,
1217        tx: N::TransactionRequest,
1218    ) -> TransportResult<N::ReceiptResponse> {
1219        self.send_transaction_sync_internal(SendableTx::Builder(tx)).await
1220    }
1221
1222    /// This method allows [`ProviderLayer`] and [`TxFiller`] to build the
1223    /// transaction and send it to the network without changing user-facing
1224    /// APIs. Generally implementers should NOT override this method.
1225    ///
1226    /// If the input is a [`SendableTx::Builder`] then this utilizes `eth_sendTransactionSync` by
1227    /// default.
1228    ///
1229    /// [`ProviderLayer`]: crate::ProviderLayer
1230    /// [`TxFiller`]: crate::fillers::TxFiller
1231    #[doc(hidden)]
1232    async fn send_transaction_sync_internal(
1233        &self,
1234        tx: SendableTx<N>,
1235    ) -> TransportResult<N::ReceiptResponse> {
1236        // Make sure to initialize heartbeat before we submit transaction, so that
1237        // we don't miss it if user will subscriber to it immediately after sending.
1238        let _handle = self.root().get_heart();
1239
1240        match tx {
1241            SendableTx::Builder(mut tx) => {
1242                alloy_network::NetworkTransactionBuilder::prep_for_submission(&mut tx);
1243                let receipt = self.client().request("eth_sendTransactionSync", (tx,)).await?;
1244                Ok(receipt)
1245            }
1246            SendableTx::Envelope(tx) => {
1247                let encoded_tx = tx.encoded_2718();
1248                self.send_raw_transaction_sync(&encoded_tx).await
1249            }
1250        }
1251    }
1252
1253    /// Signs a transaction that can be submitted to the network later using
1254    /// [`send_raw_transaction`](Self::send_raw_transaction).
1255    ///
1256    /// The `eth_signTransaction` method is not supported by regular nodes.
1257    async fn sign_transaction(&self, tx: N::TransactionRequest) -> TransportResult<Bytes> {
1258        self.client().request("eth_signTransaction", (tx,)).await
1259    }
1260
1261    /// Fills a transaction with missing fields using default values.
1262    ///
1263    /// This method prepares a transaction by populating missing fields such as gas limit,
1264    /// gas price, or nonce with appropriate default values. The response includes both the
1265    /// RLP-encoded signed transaction and the filled transaction.
1266    async fn fill_transaction(
1267        &self,
1268        tx: N::TransactionRequest,
1269    ) -> TransportResult<FillTransaction<N::TxEnvelope>>
1270    where
1271        N::TxEnvelope: RpcRecv,
1272    {
1273        self.client().request("eth_fillTransaction", (tx,)).await
1274    }
1275
1276    /// Subscribe to a stream of new block headers.
1277    ///
1278    /// # Errors
1279    ///
1280    /// This method is only available on `pubsub` clients, such as WebSockets or IPC, and will
1281    /// return a [`PubsubUnavailable`](alloy_transport::TransportErrorKind::PubsubUnavailable)
1282    /// transport error if the client does not support it.
1283    ///
1284    /// For a polling alternative available over HTTP, use [`Provider::watch_blocks`].
1285    /// However, be aware that polling increases RPC usage drastically.
1286    ///
1287    /// # Examples
1288    ///
1289    /// ```no_run
1290    /// # async fn example(provider: impl alloy_provider::Provider) -> Result<(), Box<dyn std::error::Error>> {
1291    /// use futures::StreamExt;
1292    ///
1293    /// let sub = provider.subscribe_blocks().await?;
1294    /// let mut stream = sub.into_stream().take(5);
1295    /// while let Some(block) = stream.next().await {
1296    ///    println!("new block: {block:#?}");
1297    /// }
1298    /// # Ok(())
1299    /// # }
1300    /// ```
1301    #[cfg(feature = "pubsub")]
1302    fn subscribe_blocks(&self) -> GetSubscription<(SubscriptionKind,), N::HeaderResponse> {
1303        let rpc_call = self.client().request("eth_subscribe", (SubscriptionKind::NewHeads,));
1304        GetSubscription::new(self.weak_client(), rpc_call)
1305    }
1306
1307    /// Subscribe to a stream of full block bodies.
1308    ///
1309    /// # Errors
1310    ///
1311    /// This method is only available on `pubsub` clients, such as WebSockets or IPC, and will
1312    /// return a [`PubsubUnavailable`](alloy_transport::TransportErrorKind::PubsubUnavailable)
1313    /// transport error if the client does not support it.
1314    ///
1315    /// # Examples
1316    ///
1317    /// ```no_run
1318    /// # async fn example(provider: impl alloy_provider::Provider) -> Result<(), Box<dyn std::error::Error>> {
1319    /// use futures::StreamExt;
1320    ///
1321    /// let sub = provider.subscribe_full_blocks().full().channel_size(10);
1322    /// let mut stream = sub.into_stream().await?.take(5);
1323    ///
1324    /// while let Some(block) = stream.next().await {
1325    ///   println!("{block:#?}");
1326    /// }
1327    /// # Ok(())
1328    /// # }
1329    /// ```
1330    #[cfg(feature = "pubsub")]
1331    fn subscribe_full_blocks(&self) -> SubFullBlocks<N> {
1332        SubFullBlocks::new(self.subscribe_blocks(), self.weak_client())
1333    }
1334
1335    /// Subscribe to a stream of pending transaction hashes.
1336    ///
1337    /// # Errors
1338    ///
1339    /// This method is only available on `pubsub` clients, such as WebSockets or IPC, and will
1340    /// return a [`PubsubUnavailable`](alloy_transport::TransportErrorKind::PubsubUnavailable)
1341    /// transport error if the client does not support it.
1342    ///
1343    /// For a polling alternative available over HTTP, use [`Provider::watch_pending_transactions`].
1344    /// However, be aware that polling increases RPC usage drastically.
1345    ///
1346    /// # Examples
1347    ///
1348    /// ```no_run
1349    /// # async fn example(provider: impl alloy_provider::Provider) -> Result<(), Box<dyn std::error::Error>> {
1350    /// use futures::StreamExt;
1351    ///
1352    /// let sub = provider.subscribe_pending_transactions().await?;
1353    /// let mut stream = sub.into_stream().take(5);
1354    /// while let Some(tx_hash) = stream.next().await {
1355    ///    println!("new pending transaction hash: {tx_hash}");
1356    /// }
1357    /// # Ok(())
1358    /// # }
1359    /// ```
1360    #[cfg(feature = "pubsub")]
1361    fn subscribe_pending_transactions(&self) -> GetSubscription<(SubscriptionKind,), B256> {
1362        let rpc_call =
1363            self.client().request("eth_subscribe", (SubscriptionKind::NewPendingTransactions,));
1364        GetSubscription::new(self.weak_client(), rpc_call)
1365    }
1366
1367    /// Subscribe to a stream of pending transaction bodies.
1368    ///
1369    /// # Support
1370    ///
1371    /// This endpoint is compatible only with Geth client version 1.11.0 or later.
1372    ///
1373    /// # Errors
1374    ///
1375    /// This method is only available on `pubsub` clients, such as WebSockets or IPC, and will
1376    /// return a [`PubsubUnavailable`](alloy_transport::TransportErrorKind::PubsubUnavailable)
1377    /// transport error if the client does not support it.
1378    ///
1379    /// For a polling alternative available over HTTP, use
1380    /// [`Provider::watch_full_pending_transactions`]. However, be aware that polling increases
1381    /// RPC usage drastically.
1382    ///
1383    /// # Examples
1384    ///
1385    /// ```no_run
1386    /// # async fn example(provider: impl alloy_provider::Provider) -> Result<(), Box<dyn std::error::Error>> {
1387    /// use futures::StreamExt;
1388    ///
1389    /// let sub = provider.subscribe_full_pending_transactions().await?;
1390    /// let mut stream = sub.into_stream().take(5);
1391    /// while let Some(tx) = stream.next().await {
1392    ///    println!("{tx:#?}");
1393    /// }
1394    /// # Ok(())
1395    /// # }
1396    /// ```
1397    #[cfg(feature = "pubsub")]
1398    fn subscribe_full_pending_transactions(
1399        &self,
1400    ) -> GetSubscription<(SubscriptionKind, Params), N::TransactionResponse> {
1401        let rpc_call = self.client().request(
1402            "eth_subscribe",
1403            (SubscriptionKind::NewPendingTransactions, Params::Bool(true)),
1404        );
1405        GetSubscription::new(self.weak_client(), rpc_call)
1406    }
1407
1408    /// Subscribe to a stream of logs matching given filter.
1409    ///
1410    /// # Errors
1411    ///
1412    /// This method is only available on `pubsub` clients, such as WebSockets or IPC, and will
1413    /// return a [`PubsubUnavailable`](alloy_transport::TransportErrorKind::PubsubUnavailable)
1414    /// transport error if the client does not support it.
1415    ///
1416    /// For a polling alternative available over HTTP, use
1417    /// [`Provider::watch_logs`]. However, be aware that polling increases
1418    /// RPC usage drastically.
1419    ///
1420    /// # Examples
1421    ///
1422    /// ```no_run
1423    /// # async fn example(provider: impl alloy_provider::Provider) -> Result<(), Box<dyn std::error::Error>> {
1424    /// use futures::StreamExt;
1425    /// use alloy_primitives::keccak256;
1426    /// use alloy_rpc_types_eth::Filter;
1427    ///
1428    /// let signature = keccak256("Transfer(address,address,uint256)".as_bytes());
1429    ///
1430    /// let sub = provider.subscribe_logs(&Filter::new().event_signature(signature)).await?;
1431    /// let mut stream = sub.into_stream().take(5);
1432    /// while let Some(tx) = stream.next().await {
1433    ///    println!("{tx:#?}");
1434    /// }
1435    /// # Ok(())
1436    /// # }
1437    /// ```
1438    #[cfg(feature = "pubsub")]
1439    fn subscribe_logs(&self, filter: &Filter) -> GetSubscription<(SubscriptionKind, Params), Log> {
1440        let rpc_call = self.client().request(
1441            "eth_subscribe",
1442            (SubscriptionKind::Logs, Params::Logs(Box::new(filter.clone()))),
1443        );
1444        GetSubscription::new(self.weak_client(), rpc_call)
1445    }
1446
1447    /// Subscribe to an RPC event.
1448    #[cfg(feature = "pubsub")]
1449    #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
1450    fn subscribe<P, R>(&self, params: P) -> GetSubscription<P, R>
1451    where
1452        P: RpcSend,
1453        R: RpcRecv,
1454        Self: Sized,
1455    {
1456        let rpc_call = self.client().request("eth_subscribe", params);
1457        GetSubscription::new(self.weak_client(), rpc_call)
1458    }
1459
1460    /// Subscribe to a non-standard subscription method without parameters.
1461    ///
1462    /// This is a helper method for creating subscriptions to methods that are not
1463    /// "eth_subscribe" and don't require parameters. It automatically marks the
1464    /// request as a subscription.
1465    ///
1466    /// # Examples
1467    ///
1468    /// ```no_run
1469    /// # async fn example(provider: impl alloy_provider::Provider) -> Result<(), Box<dyn std::error::Error>> {
1470    /// use futures::StreamExt;
1471    ///
1472    /// let sub = provider.subscribe_to::<alloy_rpc_types_admin::PeerEvent>("admin_peerEvents").await?;
1473    /// let mut stream = sub.into_stream().take(5);
1474    /// while let Some(event) = stream.next().await {
1475    ///    println!("peer event: {event:#?}");
1476    /// }
1477    /// # Ok(())
1478    /// # }
1479    /// ```
1480    #[cfg(feature = "pubsub")]
1481    #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
1482    fn subscribe_to<R>(&self, method: &'static str) -> GetSubscription<NoParams, R>
1483    where
1484        R: RpcRecv,
1485        Self: Sized,
1486    {
1487        let mut rpc_call = self.client().request_noparams(method);
1488        rpc_call.set_is_subscription();
1489        GetSubscription::new(self.weak_client(), rpc_call)
1490    }
1491
1492    /// Cancels a subscription given the subscription ID.
1493    #[cfg(feature = "pubsub")]
1494    async fn unsubscribe(&self, id: B256) -> TransportResult<()> {
1495        self.root().unsubscribe(id)
1496    }
1497
1498    /// Gets syncing info.
1499    fn syncing(&self) -> ProviderCall<NoParams, SyncStatus> {
1500        self.client().request_noparams("eth_syncing").into()
1501    }
1502
1503    /// Gets the client version.
1504    #[doc(alias = "web3_client_version")]
1505    fn get_client_version(&self) -> ProviderCall<NoParams, String> {
1506        self.client().request_noparams("web3_clientVersion").into()
1507    }
1508
1509    /// Gets the `Keccak-256` hash of the given data.
1510    #[doc(alias = "web3_sha3")]
1511    fn get_sha3(&self, data: &[u8]) -> ProviderCall<(String,), B256> {
1512        self.client().request("web3_sha3", (hex::encode_prefixed(data),)).into()
1513    }
1514
1515    /// Gets the network ID. Same as `eth_chainId`.
1516    fn get_net_version(&self) -> ProviderCall<NoParams, U64, u64> {
1517        self.client()
1518            .request_noparams("net_version")
1519            .map_resp(utils::convert_u64 as fn(U64) -> u64)
1520            .into()
1521    }
1522
1523    /* ---------------------------------------- raw calls --------------------------------------- */
1524
1525    /// Sends a raw JSON-RPC request.
1526    ///
1527    /// # Examples
1528    ///
1529    /// ```no_run
1530    /// # async fn example(provider: impl alloy_provider::Provider) -> Result<(), Box<dyn std::error::Error>> {
1531    /// use alloy_rpc_types_eth::BlockNumberOrTag;
1532    /// use alloy_rpc_client::NoParams;
1533    ///
1534    /// // No parameters: `()`
1535    /// let block_number: String = provider.raw_request("eth_blockNumber".into(), NoParams::default()).await?;
1536    ///
1537    /// // One parameter: `(param,)` or `[param]`
1538    /// let block: serde_json::Value = provider.raw_request("eth_getBlockByNumber".into(), (BlockNumberOrTag::Latest,)).await?;
1539    ///
1540    /// // Two or more parameters: `(param1, param2, ...)` or `[param1, param2, ...]`
1541    /// let full_block: serde_json::Value = provider.raw_request("eth_getBlockByNumber".into(), (BlockNumberOrTag::Latest, true)).await?;
1542    /// # Ok(())
1543    /// # }
1544    /// ```
1545    ///
1546    /// [`PubsubUnavailable`]: alloy_transport::TransportErrorKind::PubsubUnavailable
1547    async fn raw_request<P, R>(&self, method: Cow<'static, str>, params: P) -> TransportResult<R>
1548    where
1549        P: RpcSend,
1550        R: RpcRecv,
1551        Self: Sized,
1552    {
1553        self.client().request(method, &params).await
1554    }
1555
1556    /// Sends a raw JSON-RPC request with type-erased parameters and return.
1557    ///
1558    /// # Examples
1559    ///
1560    /// ```no_run
1561    /// # async fn example(provider: impl alloy_provider::Provider) -> Result<(), Box<dyn std::error::Error>> {
1562    /// use alloy_rpc_types_eth::BlockNumberOrTag;
1563    ///
1564    /// // No parameters: `()`
1565    /// let params = serde_json::value::to_raw_value(&())?;
1566    /// let block_number = provider.raw_request_dyn("eth_blockNumber".into(), &params).await?;
1567    ///
1568    /// // One parameter: `(param,)` or `[param]`
1569    /// let params = serde_json::value::to_raw_value(&(BlockNumberOrTag::Latest,))?;
1570    /// let block = provider.raw_request_dyn("eth_getBlockByNumber".into(), &params).await?;
1571    ///
1572    /// // Two or more parameters: `(param1, param2, ...)` or `[param1, param2, ...]`
1573    /// let params = serde_json::value::to_raw_value(&(BlockNumberOrTag::Latest, true))?;
1574    /// let full_block = provider.raw_request_dyn("eth_getBlockByNumber".into(), &params).await?;
1575    /// # Ok(())
1576    /// # }
1577    /// ```
1578    async fn raw_request_dyn(
1579        &self,
1580        method: Cow<'static, str>,
1581        params: &RawValue,
1582    ) -> TransportResult<Box<RawValue>> {
1583        self.client().request(method, params).await
1584    }
1585
1586    /// Creates a new [`TransactionRequest`](alloy_network::Network).
1587    #[inline]
1588    fn transaction_request(&self) -> N::TransactionRequest {
1589        Default::default()
1590    }
1591}
1592
1593#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
1594#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
1595impl<N: Network> Provider<N> for RootProvider<N> {
1596    #[inline]
1597    fn root(&self) -> &Self {
1598        self
1599    }
1600
1601    #[inline]
1602    fn client(&self) -> ClientRef<'_> {
1603        self.inner.client_ref()
1604    }
1605
1606    #[inline]
1607    fn weak_client(&self) -> WeakClient {
1608        self.inner.weak_client()
1609    }
1610
1611    #[inline]
1612    async fn watch_pending_transaction(
1613        &self,
1614        config: PendingTransactionConfig,
1615    ) -> Result<PendingTransaction, PendingTransactionError> {
1616        let block_number =
1617            if let Some(receipt) = self.get_transaction_receipt(*config.tx_hash()).await? {
1618                // The transaction is already confirmed.
1619                if config.required_confirmations() <= 1 {
1620                    return Ok(PendingTransaction::ready(*config.tx_hash()));
1621                }
1622                // Transaction has custom confirmations, so let the heart know about its block
1623                // number and let it handle the situation.
1624                receipt.block_number()
1625            } else {
1626                None
1627            };
1628
1629        self.get_heart()
1630            .watch_tx(config, block_number)
1631            .await
1632            .map_err(|_| PendingTransactionError::FailedToRegister)
1633    }
1634}
1635
1636#[cfg(test)]
1637mod tests {
1638    use super::*;
1639    use crate::{builder, ext::test::async_ci_only, ProviderBuilder, WalletProvider};
1640    use alloy_consensus::{Transaction, TxEnvelope};
1641    use alloy_network::{
1642        AnyNetwork, EthereumWallet, NetworkTransactionBuilder, TransactionBuilder,
1643    };
1644    use alloy_node_bindings::{utils::run_with_tempdir, Anvil, Reth};
1645    use alloy_primitives::{address, b256, bytes, keccak256};
1646    use alloy_rlp::Decodable;
1647    use alloy_rpc_client::{BuiltInConnectionString, RpcClient};
1648    use alloy_rpc_types_eth::{request::TransactionRequest, Block};
1649    use alloy_signer_local::PrivateKeySigner;
1650    use alloy_transport::layers::{RetryBackoffLayer, RetryPolicy};
1651    use std::{io::Read, str::FromStr, time::Duration};
1652
1653    // For layer transport tests
1654    use alloy_consensus::transaction::SignerRecoverable;
1655    #[cfg(feature = "hyper")]
1656    use alloy_transport_http::{
1657        hyper,
1658        hyper::body::Bytes as HyperBytes,
1659        hyper_util::{
1660            client::legacy::{Client, Error},
1661            rt::TokioExecutor,
1662        },
1663        HyperResponse, HyperResponseFut,
1664    };
1665    #[cfg(feature = "hyper")]
1666    use http_body_util::Full;
1667    #[cfg(feature = "hyper")]
1668    use tower::{Layer, Service};
1669
1670    #[tokio::test]
1671    async fn test_provider_builder() {
1672        let provider =
1673            RootProvider::<Ethereum>::builder().with_recommended_fillers().connect_anvil();
1674        let num = provider.get_block_number().await.unwrap();
1675        assert_eq!(0, num);
1676    }
1677
1678    #[tokio::test]
1679    async fn test_builder_helper_fn() {
1680        let provider = builder::<Ethereum>().with_recommended_fillers().connect_anvil();
1681        let num = provider.get_block_number().await.unwrap();
1682        assert_eq!(0, num);
1683    }
1684
1685    #[cfg(feature = "hyper")]
1686    #[tokio::test]
1687    async fn test_default_hyper_transport() {
1688        let anvil = Anvil::new().spawn();
1689        let hyper_t = alloy_transport_http::HyperTransport::new_hyper(anvil.endpoint_url());
1690
1691        let rpc_client = alloy_rpc_client::RpcClient::new(hyper_t, true);
1692
1693        let provider = RootProvider::<Ethereum>::new(rpc_client);
1694        let num = provider.get_block_number().await.unwrap();
1695        assert_eq!(0, num);
1696    }
1697
1698    #[cfg(feature = "hyper")]
1699    #[tokio::test]
1700    async fn test_hyper_layer_transport() {
1701        struct LoggingLayer;
1702
1703        impl<S> Layer<S> for LoggingLayer {
1704            type Service = LoggingService<S>;
1705
1706            fn layer(&self, inner: S) -> Self::Service {
1707                LoggingService { inner }
1708            }
1709        }
1710
1711        #[derive(Clone)] // required
1712        struct LoggingService<S> {
1713            inner: S,
1714        }
1715
1716        impl<S, B> Service<hyper::Request<B>> for LoggingService<S>
1717        where
1718            S: Service<hyper::Request<B>, Response = HyperResponse, Error = Error>
1719                + Clone
1720                + Send
1721                + Sync
1722                + 'static,
1723            S::Future: Send,
1724            S::Error: std::error::Error + Send + Sync + 'static,
1725            B: From<Vec<u8>> + Send + 'static + Clone + Sync + std::fmt::Debug,
1726        {
1727            type Response = HyperResponse;
1728            type Error = Error;
1729            type Future = HyperResponseFut;
1730
1731            fn poll_ready(
1732                &mut self,
1733                cx: &mut std::task::Context<'_>,
1734            ) -> std::task::Poll<Result<(), Self::Error>> {
1735                self.inner.poll_ready(cx)
1736            }
1737
1738            fn call(&mut self, req: hyper::Request<B>) -> Self::Future {
1739                println!("Logging Layer - HyperRequest {req:?}");
1740
1741                let fut = self.inner.call(req);
1742
1743                Box::pin(fut)
1744            }
1745        }
1746        use http::header::{self, HeaderValue};
1747        use tower_http::{
1748            sensitive_headers::SetSensitiveRequestHeadersLayer, set_header::SetRequestHeaderLayer,
1749        };
1750        let anvil = Anvil::new().spawn();
1751        let hyper_client = Client::builder(TokioExecutor::new()).build_http::<Full<HyperBytes>>();
1752
1753        // Setup tower service with multiple layers modifying request headers
1754        let service = tower::ServiceBuilder::new()
1755            .layer(SetRequestHeaderLayer::if_not_present(
1756                header::USER_AGENT,
1757                HeaderValue::from_static("alloy app"),
1758            ))
1759            .layer(SetRequestHeaderLayer::overriding(
1760                header::AUTHORIZATION,
1761                HeaderValue::from_static("some-jwt-token"),
1762            ))
1763            .layer(SetRequestHeaderLayer::appending(
1764                header::SET_COOKIE,
1765                HeaderValue::from_static("cookie-value"),
1766            ))
1767            .layer(SetSensitiveRequestHeadersLayer::new([header::AUTHORIZATION])) // Hides the jwt token as sensitive.
1768            .layer(LoggingLayer)
1769            .service(hyper_client);
1770
1771        let layer_transport = alloy_transport_http::HyperClient::with_service(service);
1772
1773        let http_hyper =
1774            alloy_transport_http::Http::with_client(layer_transport, anvil.endpoint_url());
1775
1776        let rpc_client = alloy_rpc_client::RpcClient::new(http_hyper, true);
1777
1778        let provider = RootProvider::<Ethereum>::new(rpc_client);
1779        let num = provider.get_block_number().await.unwrap();
1780        assert_eq!(0, num);
1781
1782        // Test Cloning with service
1783        let cloned_t = provider.client().transport().clone();
1784
1785        let rpc_client = alloy_rpc_client::RpcClient::new(cloned_t, true);
1786
1787        let provider = RootProvider::<Ethereum>::new(rpc_client);
1788        let num = provider.get_block_number().await.unwrap();
1789        assert_eq!(0, num);
1790    }
1791
1792    #[cfg(feature = "hyper")]
1793    #[tokio::test]
1794    #[cfg_attr(windows, ignore = "no reth on windows")]
1795    async fn test_auth_layer_transport() {
1796        crate::ext::test::async_ci_only(|| async move {
1797            use alloy_node_bindings::Reth;
1798            use alloy_rpc_types_engine::JwtSecret;
1799            use alloy_transport_http::{AuthLayer, Http, HyperClient};
1800
1801            let secret = JwtSecret::random();
1802
1803            let reth =
1804                Reth::new().arg("--rpc.jwtsecret").arg(hex::encode(secret.as_bytes())).spawn();
1805
1806            let layer_transport = HyperClient::new().layer(AuthLayer::new(secret));
1807
1808            let http_hyper = Http::with_client(layer_transport, reth.endpoint_url());
1809
1810            let rpc_client = alloy_rpc_client::RpcClient::new(http_hyper, true);
1811
1812            let provider = RootProvider::<Ethereum>::new(rpc_client);
1813
1814            let num = provider.get_block_number().await.unwrap();
1815            assert_eq!(0, num);
1816        })
1817        .await;
1818    }
1819
1820    #[tokio::test]
1821    async fn test_builder_helper_fn_any_network() {
1822        let anvil = Anvil::new().spawn();
1823        let provider =
1824            builder::<AnyNetwork>().with_recommended_fillers().connect_http(anvil.endpoint_url());
1825        let num = provider.get_block_number().await.unwrap();
1826        assert_eq!(0, num);
1827    }
1828
1829    #[cfg(feature = "reqwest")]
1830    #[tokio::test]
1831    async fn object_safety() {
1832        let provider = ProviderBuilder::new().connect_anvil();
1833
1834        let refdyn = &provider as &dyn Provider<_>;
1835        let num = refdyn.get_block_number().await.unwrap();
1836        assert_eq!(0, num);
1837    }
1838
1839    #[cfg(feature = "ws")]
1840    #[tokio::test]
1841    async fn subscribe_blocks_http() {
1842        let provider = ProviderBuilder::new().connect_anvil_with_config(|a| a.block_time(1));
1843
1844        let err = provider.subscribe_blocks().await.unwrap_err();
1845        let alloy_json_rpc::RpcError::Transport(
1846            alloy_transport::TransportErrorKind::PubsubUnavailable,
1847        ) = err
1848        else {
1849            panic!("{err:?}");
1850        };
1851    }
1852
1853    // Ensures we can connect to a websocket using `wss`.
1854    #[cfg(feature = "ws")]
1855    #[tokio::test]
1856    async fn websocket_tls_setup() {
1857        for url in ["wss://mainnet.infura.io/ws/v3/b0f825787ba840af81e46c6a64d20754"] {
1858            let _ = ProviderBuilder::<_, _, Ethereum>::default().connect(url).await.unwrap();
1859        }
1860    }
1861
1862    #[cfg(feature = "ws")]
1863    #[tokio::test]
1864    async fn subscribe_blocks_ws() {
1865        use futures::stream::StreamExt;
1866
1867        let anvil = Anvil::new().block_time_f64(0.2).spawn();
1868        let ws = alloy_rpc_client::WsConnect::new(anvil.ws_endpoint());
1869        let client = alloy_rpc_client::RpcClient::connect_pubsub(ws).await.unwrap();
1870        let provider = RootProvider::<Ethereum>::new(client);
1871
1872        let sub = provider.subscribe_blocks().await.unwrap();
1873        let mut stream = sub.into_stream().take(5);
1874        let mut next = None;
1875        while let Some(header) = stream.next().await {
1876            if let Some(next) = &mut next {
1877                assert_eq!(header.number, *next);
1878                *next += 1;
1879            } else {
1880                next = Some(header.number + 1);
1881            }
1882        }
1883    }
1884
1885    #[cfg(feature = "ws")]
1886    #[tokio::test]
1887    async fn subscribe_full_blocks() {
1888        use futures::StreamExt;
1889
1890        let anvil = Anvil::new().block_time_f64(0.2).spawn();
1891        let ws = alloy_rpc_client::WsConnect::new(anvil.ws_endpoint());
1892        let client = alloy_rpc_client::RpcClient::connect_pubsub(ws).await.unwrap();
1893
1894        let provider = RootProvider::<Ethereum>::new(client);
1895
1896        let sub = provider.subscribe_full_blocks().hashes().channel_size(10);
1897
1898        let mut stream = sub.into_stream().await.unwrap().take(5);
1899
1900        let mut next = None;
1901        while let Some(Ok(block)) = stream.next().await {
1902            if let Some(next) = &mut next {
1903                assert_eq!(block.header().number, *next);
1904                *next += 1;
1905            } else {
1906                next = Some(block.header().number + 1);
1907            }
1908        }
1909    }
1910
1911    #[tokio::test]
1912    #[cfg(feature = "ws")]
1913    async fn subscribe_blocks_ws_remote() {
1914        use futures::stream::StreamExt;
1915
1916        let url = "wss://eth-mainnet.g.alchemy.com/v2/viFmeVzhg6bWKVMIWWS8MhmzREB-D4f7";
1917        let ws = alloy_rpc_client::WsConnect::new(url);
1918        let Ok(client) = alloy_rpc_client::RpcClient::connect_pubsub(ws).await else { return };
1919        let provider = RootProvider::<Ethereum>::new(client);
1920        let sub = provider.subscribe_blocks().await.unwrap();
1921        let mut stream = sub.into_stream().take(1);
1922        while let Some(header) = stream.next().await {
1923            println!("New block {header:?}");
1924            assert!(header.number > 0);
1925        }
1926    }
1927
1928    #[tokio::test]
1929    async fn test_custom_retry_policy() {
1930        #[derive(Debug, Clone)]
1931        struct CustomPolicy;
1932        impl RetryPolicy for CustomPolicy {
1933            fn should_retry(&self, _err: &alloy_transport::TransportError) -> bool {
1934                true
1935            }
1936
1937            fn backoff_hint(
1938                &self,
1939                _error: &alloy_transport::TransportError,
1940            ) -> Option<std::time::Duration> {
1941                None
1942            }
1943        }
1944
1945        let retry_layer = RetryBackoffLayer::new_with_policy(10, 100, 10000, CustomPolicy);
1946        let anvil = Anvil::new().spawn();
1947        let client = RpcClient::builder().layer(retry_layer).http(anvil.endpoint_url());
1948
1949        let provider = RootProvider::<Ethereum>::new(client);
1950        let num = provider.get_block_number().await.unwrap();
1951        assert_eq!(0, num);
1952    }
1953
1954    #[tokio::test]
1955    async fn test_send_tx() {
1956        let provider = ProviderBuilder::new().connect_anvil_with_wallet();
1957        let tx = TransactionRequest {
1958            value: Some(U256::from(100)),
1959            to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
1960            gas_price: Some(20e9 as u128),
1961            gas: Some(21000),
1962            ..Default::default()
1963        };
1964
1965        let builder = provider.send_transaction(tx.clone()).await.expect("failed to send tx");
1966        let hash1 = *builder.tx_hash();
1967        let hash2 = builder.watch().await.expect("failed to await pending tx");
1968        assert_eq!(hash1, hash2);
1969
1970        let builder = provider.send_transaction(tx).await.expect("failed to send tx");
1971        let hash1 = *builder.tx_hash();
1972        let hash2 =
1973            builder.get_receipt().await.expect("failed to await pending tx").transaction_hash;
1974        assert_eq!(hash1, hash2);
1975    }
1976
1977    #[tokio::test]
1978    async fn test_send_tx_sync() {
1979        let provider = ProviderBuilder::new().connect_anvil_with_wallet();
1980        let tx = TransactionRequest {
1981            value: Some(U256::from(100)),
1982            to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
1983            gas_price: Some(20e9 as u128),
1984            gas: Some(21000),
1985            ..Default::default()
1986        };
1987
1988        let _receipt =
1989            provider.send_transaction_sync(tx.clone()).await.expect("failed to send tx sync");
1990    }
1991
1992    #[tokio::test]
1993    async fn test_send_raw_transaction_sync() {
1994        let provider = ProviderBuilder::new().connect_anvil_with_wallet();
1995
1996        // Create a transaction
1997        let tx = TransactionRequest {
1998            nonce: Some(0),
1999            value: Some(U256::from(100)),
2000            to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
2001            gas_price: Some(20e9 as u128),
2002            gas: Some(21000),
2003            ..Default::default()
2004        };
2005
2006        // Build and sign the transaction to get the envelope
2007        let tx_envelope = tx.build(&provider.wallet()).await.expect("failed to build tx");
2008
2009        // Encode the transaction
2010        let encoded = tx_envelope.encoded_2718();
2011
2012        // Send using the sync method - this directly returns the receipt
2013        let receipt =
2014            provider.send_raw_transaction_sync(&encoded).await.expect("failed to send raw tx sync");
2015
2016        // Verify receipt
2017        assert_eq!(receipt.to(), Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045")));
2018        // The main idea that returned receipt should be already mined
2019        assert!(receipt.block_number().is_some(), "transaction should be mined");
2020        assert!(receipt.transaction_hash() != B256::ZERO, "should have valid tx hash");
2021    }
2022
2023    #[tokio::test]
2024    async fn test_watch_confirmed_tx() {
2025        let provider = ProviderBuilder::new().connect_anvil_with_wallet();
2026        let tx = TransactionRequest {
2027            value: Some(U256::from(100)),
2028            to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
2029            gas_price: Some(20e9 as u128),
2030            gas: Some(21000),
2031            ..Default::default()
2032        };
2033
2034        let builder = provider.send_transaction(tx).await.expect("failed to send tx");
2035        let hash1 = *builder.tx_hash();
2036
2037        // Wait until tx is confirmed.
2038        loop {
2039            if provider
2040                .get_transaction_receipt(hash1)
2041                .await
2042                .expect("failed to await pending tx")
2043                .is_some()
2044            {
2045                break;
2046            }
2047        }
2048
2049        // Submit another tx.
2050        let tx2 = TransactionRequest {
2051            value: Some(U256::from(100)),
2052            to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
2053            gas_price: Some(20e9 as u128),
2054            gas: Some(21000),
2055            ..Default::default()
2056        };
2057        provider.send_transaction(tx2).await.expect("failed to send tx").watch().await.unwrap();
2058
2059        // Only subscribe for watching _after_ tx was confirmed and we submitted a new one.
2060        let watch = builder.watch();
2061        // Wrap watch future in timeout to prevent it from hanging.
2062        let watch_with_timeout = tokio::time::timeout(Duration::from_secs(1), watch);
2063        let hash2 = watch_with_timeout
2064            .await
2065            .expect("Watching tx timed out")
2066            .expect("failed to await pending tx");
2067        assert_eq!(hash1, hash2);
2068    }
2069
2070    #[tokio::test]
2071    async fn gets_block_number() {
2072        let provider = ProviderBuilder::new().connect_anvil();
2073        let num = provider.get_block_number().await.unwrap();
2074        assert_eq!(0, num)
2075    }
2076
2077    #[tokio::test]
2078    async fn gets_block_number_for_id() {
2079        let provider = ProviderBuilder::new().connect_anvil();
2080
2081        let block_num = provider
2082            .get_block_number_by_id(BlockId::Number(BlockNumberOrTag::Number(0)))
2083            .await
2084            .unwrap();
2085        assert_eq!(block_num, Some(0));
2086
2087        let block_num = provider
2088            .get_block_number_by_id(BlockId::Number(BlockNumberOrTag::Latest))
2089            .await
2090            .unwrap();
2091        assert_eq!(block_num, Some(0));
2092
2093        let block =
2094            provider.get_block_by_number(BlockNumberOrTag::Number(0)).await.unwrap().unwrap();
2095        let hash = block.header.hash;
2096        let block_num = provider.get_block_number_by_id(BlockId::Hash(hash.into())).await.unwrap();
2097        assert_eq!(block_num, Some(0));
2098    }
2099
2100    #[tokio::test]
2101    async fn gets_block_number_with_raw_req() {
2102        let provider = ProviderBuilder::new().connect_anvil();
2103        let num: U64 =
2104            provider.raw_request("eth_blockNumber".into(), NoParams::default()).await.unwrap();
2105        assert_eq!(0, num.to::<u64>())
2106    }
2107
2108    #[cfg(feature = "anvil-api")]
2109    #[tokio::test]
2110    async fn gets_transaction_count() {
2111        let provider = ProviderBuilder::new().connect_anvil();
2112        let accounts = provider.get_accounts().await.unwrap();
2113        let sender = accounts[0];
2114
2115        // Initial tx count should be 0
2116        let count = provider.get_transaction_count(sender).await.unwrap();
2117        assert_eq!(count, 0);
2118
2119        // Send Tx
2120        let tx = TransactionRequest {
2121            value: Some(U256::from(100)),
2122            from: Some(sender),
2123            to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
2124            gas_price: Some(20e9 as u128),
2125            gas: Some(21000),
2126            ..Default::default()
2127        };
2128        let _ = provider.send_transaction(tx).await.unwrap().get_receipt().await;
2129
2130        // Tx count should be 1
2131        let count = provider.get_transaction_count(sender).await.unwrap();
2132        assert_eq!(count, 1);
2133
2134        // Tx count should be 0 at block 0
2135        let count = provider.get_transaction_count(sender).block_id(0.into()).await.unwrap();
2136        assert_eq!(count, 0);
2137    }
2138
2139    #[tokio::test]
2140    async fn gets_block_by_hash() {
2141        let provider = ProviderBuilder::new().connect_anvil();
2142        let num = 0;
2143        let tag: BlockNumberOrTag = num.into();
2144        let block = provider.get_block_by_number(tag).full().await.unwrap().unwrap();
2145        let hash = block.header.hash;
2146        let block = provider.get_block_by_hash(hash).full().await.unwrap().unwrap();
2147        assert_eq!(block.header.hash, hash);
2148    }
2149
2150    #[tokio::test]
2151    async fn gets_block_by_hash_with_raw_req() {
2152        let provider = ProviderBuilder::new().connect_anvil();
2153        let num = 0;
2154        let tag: BlockNumberOrTag = num.into();
2155        let block = provider.get_block_by_number(tag).full().await.unwrap().unwrap();
2156        let hash = block.header.hash;
2157        let block: Block = provider
2158            .raw_request::<(B256, bool), Block>("eth_getBlockByHash".into(), (hash, true))
2159            .await
2160            .unwrap();
2161        assert_eq!(block.header.hash, hash);
2162    }
2163
2164    #[tokio::test]
2165    async fn gets_block_by_number_full() {
2166        let provider = ProviderBuilder::new().connect_anvil();
2167        let num = 0;
2168        let tag: BlockNumberOrTag = num.into();
2169        let block = provider.get_block_by_number(tag).full().await.unwrap().unwrap();
2170        assert_eq!(block.header.number, num);
2171    }
2172
2173    #[tokio::test]
2174    async fn gets_block_by_number() {
2175        let provider = ProviderBuilder::new().connect_anvil();
2176        let num = 0;
2177        let tag: BlockNumberOrTag = num.into();
2178        let block = provider.get_block_by_number(tag).full().await.unwrap().unwrap();
2179        assert_eq!(block.header.number, num);
2180    }
2181
2182    #[tokio::test]
2183    async fn gets_client_version() {
2184        let provider = ProviderBuilder::new().connect_anvil();
2185        let version = provider.get_client_version().await.unwrap();
2186        assert!(version.contains("anvil"), "{version}");
2187    }
2188
2189    #[tokio::test]
2190    async fn gets_sha3() {
2191        let provider = ProviderBuilder::new().connect_anvil();
2192        let data = b"alloy";
2193        let hash = provider.get_sha3(data).await.unwrap();
2194        assert_eq!(hash, keccak256(data));
2195    }
2196
2197    #[tokio::test]
2198    async fn gets_chain_id() {
2199        let dev_chain_id: u64 = 13371337;
2200
2201        let provider =
2202            ProviderBuilder::new().connect_anvil_with_config(|a| a.chain_id(dev_chain_id));
2203
2204        let chain_id = provider.get_chain_id().await.unwrap();
2205        assert_eq!(chain_id, dev_chain_id);
2206    }
2207
2208    #[tokio::test]
2209    async fn gets_network_id() {
2210        let dev_chain_id: u64 = 13371337;
2211        let provider =
2212            ProviderBuilder::new().connect_anvil_with_config(|a| a.chain_id(dev_chain_id));
2213
2214        let chain_id = provider.get_net_version().await.unwrap();
2215        assert_eq!(chain_id, dev_chain_id);
2216    }
2217
2218    #[tokio::test]
2219    async fn gets_storage_at() {
2220        let provider = ProviderBuilder::new().connect_anvil();
2221        let addr = Address::with_last_byte(16);
2222        let storage = provider.get_storage_at(addr, U256::ZERO).await.unwrap();
2223        assert_eq!(storage, U256::ZERO);
2224    }
2225
2226    #[tokio::test]
2227    async fn gets_transaction_by_hash_not_found() {
2228        let provider = ProviderBuilder::new().connect_anvil();
2229        let tx_hash = b256!("5c03fab9114ceb98994b43892ade87ddfd9ae7e8f293935c3bd29d435dc9fd95");
2230        let tx = provider.get_transaction_by_hash(tx_hash).await.expect("failed to fetch tx");
2231
2232        assert!(tx.is_none());
2233    }
2234
2235    #[tokio::test]
2236    async fn gets_transaction_by_hash() {
2237        let provider = ProviderBuilder::new().connect_anvil_with_wallet();
2238
2239        let req = TransactionRequest::default()
2240            .from(provider.default_signer_address())
2241            .to(Address::repeat_byte(5))
2242            .value(U256::ZERO)
2243            .input(bytes!("deadbeef").into());
2244
2245        let tx_hash = *provider.send_transaction(req).await.expect("failed to send tx").tx_hash();
2246
2247        let tx = provider
2248            .get_transaction_by_hash(tx_hash)
2249            .await
2250            .expect("failed to fetch tx")
2251            .expect("tx not included");
2252        assert_eq!(tx.input(), &bytes!("deadbeef"));
2253    }
2254
2255    #[tokio::test]
2256    #[ignore]
2257    async fn gets_logs() {
2258        let provider = ProviderBuilder::new().connect_anvil();
2259        let filter = Filter::new()
2260            .at_block_hash(b256!(
2261                "b20e6f35d4b46b3c4cd72152faec7143da851a0dc281d390bdd50f58bfbdb5d3"
2262            ))
2263            .event_signature(b256!(
2264                "e1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c"
2265            ));
2266        let logs = provider.get_logs(&filter).await.unwrap();
2267        assert_eq!(logs.len(), 1);
2268    }
2269
2270    #[tokio::test]
2271    #[ignore]
2272    async fn gets_tx_receipt() {
2273        let provider = ProviderBuilder::new().connect_anvil();
2274        let receipt = provider
2275            .get_transaction_receipt(b256!(
2276                "5c03fab9114ceb98994b43892ade87ddfd9ae7e8f293935c3bd29d435dc9fd95"
2277            ))
2278            .await
2279            .unwrap();
2280        assert!(receipt.is_some());
2281        let receipt = receipt.unwrap();
2282        assert_eq!(
2283            receipt.transaction_hash,
2284            b256!("5c03fab9114ceb98994b43892ade87ddfd9ae7e8f293935c3bd29d435dc9fd95")
2285        );
2286    }
2287
2288    #[tokio::test]
2289    async fn gets_max_priority_fee_per_gas() {
2290        let provider = ProviderBuilder::new().connect_anvil();
2291        let _fee = provider.get_max_priority_fee_per_gas().await.unwrap();
2292    }
2293
2294    #[tokio::test]
2295    async fn gets_fee_history() {
2296        let provider = ProviderBuilder::new().connect_anvil();
2297        let block_number = provider.get_block_number().await.unwrap();
2298        let fee_history = provider
2299            .get_fee_history(
2300                utils::EIP1559_FEE_ESTIMATION_PAST_BLOCKS,
2301                BlockNumberOrTag::Number(block_number),
2302                &[utils::EIP1559_FEE_ESTIMATION_REWARD_PERCENTILE],
2303            )
2304            .await
2305            .unwrap();
2306        assert_eq!(fee_history.oldest_block, 0_u64);
2307    }
2308
2309    #[tokio::test]
2310    async fn gets_block_transaction_count_by_hash() {
2311        let provider = ProviderBuilder::new().connect_anvil();
2312        let block = provider.get_block(BlockId::latest()).await.unwrap().unwrap();
2313        let hash = block.header.hash;
2314        let tx_count = provider.get_block_transaction_count_by_hash(hash).await.unwrap();
2315        assert!(tx_count.is_some());
2316    }
2317
2318    #[tokio::test]
2319    async fn gets_block_transaction_count_by_number() {
2320        let provider = ProviderBuilder::new().connect_anvil();
2321        let tx_count =
2322            provider.get_block_transaction_count_by_number(BlockNumberOrTag::Latest).await.unwrap();
2323        assert!(tx_count.is_some());
2324    }
2325
2326    #[tokio::test]
2327    async fn gets_block_receipts() {
2328        let provider = ProviderBuilder::new().connect_anvil();
2329        let receipts =
2330            provider.get_block_receipts(BlockId::Number(BlockNumberOrTag::Latest)).await.unwrap();
2331        assert!(receipts.is_some());
2332    }
2333
2334    #[tokio::test]
2335    async fn sends_raw_transaction() {
2336        let provider = ProviderBuilder::new().connect_anvil();
2337        let pending = provider
2338            .send_raw_transaction(
2339                // Transfer 1 ETH from default EOA address to the Genesis address.
2340                bytes!("f865808477359400825208940000000000000000000000000000000000000000018082f4f5a00505e227c1c636c76fac55795db1a40a4d24840d81b40d2fe0cc85767f6bd202a01e91b437099a8a90234ac5af3cb7ca4fb1432e133f75f9a91678eaf5f487c74b").as_ref()
2341            )
2342            .await.unwrap();
2343        assert_eq!(
2344            pending.tx_hash().to_string(),
2345            "0x9dae5cf33694a02e8a7d5de3fe31e9d05ca0ba6e9180efac4ab20a06c9e598a3"
2346        );
2347    }
2348
2349    #[tokio::test]
2350    async fn connect_boxed() {
2351        let anvil = Anvil::new().spawn();
2352
2353        let provider = RootProvider::<Ethereum>::connect(anvil.endpoint().as_str()).await;
2354
2355        match provider {
2356            Ok(provider) => {
2357                let num = provider.get_block_number().await.unwrap();
2358                assert_eq!(0, num);
2359            }
2360            Err(e) => {
2361                assert_eq!(
2362                    format!("{e}"),
2363                    "hyper not supported by BuiltinConnectionString. Please instantiate a hyper client manually"
2364                );
2365            }
2366        }
2367    }
2368
2369    #[tokio::test]
2370    async fn any_network_wallet_filler() {
2371        use alloy_serde::WithOtherFields;
2372        let anvil = Anvil::new().spawn();
2373        let signer: PrivateKeySigner =
2374            "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80".parse().unwrap();
2375        let wallet = EthereumWallet::from(signer);
2376
2377        let provider = ProviderBuilder::new()
2378            .network::<AnyNetwork>()
2379            .wallet(wallet)
2380            .connect_http(anvil.endpoint_url());
2381
2382        let tx = TransactionRequest::default()
2383            .with_to(address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"))
2384            .value(U256::from(325235));
2385
2386        let tx = WithOtherFields::new(tx);
2387
2388        let builder = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();
2389
2390        assert!(builder.status());
2391    }
2392
2393    #[tokio::test]
2394    async fn builtin_connect_boxed() {
2395        let anvil = Anvil::new().spawn();
2396
2397        let conn: BuiltInConnectionString = anvil.endpoint().parse().unwrap();
2398
2399        let transport = conn.connect_boxed().await.unwrap();
2400
2401        let client = alloy_rpc_client::RpcClient::new(transport, true);
2402
2403        let provider = RootProvider::<Ethereum>::new(client);
2404
2405        let num = provider.get_block_number().await.unwrap();
2406        assert_eq!(0, num);
2407    }
2408
2409    #[tokio::test]
2410    async fn test_uncle_count() {
2411        let provider = ProviderBuilder::new().connect_anvil();
2412
2413        let count = provider.get_uncle_count(0.into()).await.unwrap();
2414        assert_eq!(count, 0);
2415    }
2416
2417    #[tokio::test]
2418    #[cfg(any(
2419        feature = "reqwest-default-tls",
2420        feature = "reqwest-rustls-tls",
2421        feature = "reqwest-native-tls",
2422    ))]
2423    #[ignore = "ignore until <https://github.com/paradigmxyz/reth/pull/14727> is in"]
2424    async fn call_mainnet() {
2425        use alloy_network::TransactionBuilder;
2426        use alloy_sol_types::SolValue;
2427
2428        let url = "https://docs-demo.quiknode.pro/";
2429        let provider = ProviderBuilder::new().connect_http(url.parse().unwrap());
2430        let req = TransactionRequest::default()
2431            .with_to(address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")) // WETH
2432            .with_input(bytes!("06fdde03")); // `name()`
2433        let result = provider.call(req.clone()).await.unwrap();
2434        assert_eq!(String::abi_decode(&result).unwrap(), "Wrapped Ether");
2435
2436        let result = provider.call(req).block(0.into()).await.unwrap();
2437        assert_eq!(result.to_string(), "0x");
2438    }
2439
2440    #[tokio::test]
2441    async fn call_many_mainnet() {
2442        use alloy_rpc_types_eth::{BlockOverrides, StateContext};
2443
2444        let url = "https://docs-demo.quiknode.pro/";
2445        let provider = ProviderBuilder::new().connect_http(url.parse().unwrap());
2446        let tx1 = TransactionRequest::default()
2447            .with_to(address!("6b175474e89094c44da98b954eedeac495271d0f"))
2448            .with_gas_limit(1000000)
2449            .with_gas_price(2023155498)
2450            .with_input(hex!("a9059cbb000000000000000000000000bc0E63965946815d105E7591407704e6e1964E590000000000000000000000000000000000000000000000000000000005f5e100"));
2451        let tx2 = TransactionRequest::default()
2452            .with_to(address!("833589fcd6edb6e08f4c7c32d4f71b54bda02913"))
2453            .with_gas_price(2023155498)
2454            .with_input(hex!(
2455                "70a08231000000000000000000000000bc0E63965946815d105E7591407704e6e1964E59"
2456            ));
2457
2458        let transactions = vec![tx1.clone(), tx2.clone()];
2459
2460        let block_override =
2461            BlockOverrides { number: Some(U256::from(12279785)), ..Default::default() };
2462
2463        let bundles = vec![Bundle { transactions, block_override: Some(block_override.clone()) }];
2464
2465        let context = StateContext {
2466            block_number: Some(BlockId::number(12279785)),
2467            transaction_index: Some(1.into()),
2468        };
2469
2470        let results = provider.call_many(&bundles).context(&context).await.unwrap();
2471
2472        let tx1_res = EthCallResponse {
2473            value: Some(
2474                hex!("0000000000000000000000000000000000000000000000000000000000000001").into(),
2475            ),
2476            error: None,
2477        };
2478        let tx2_res = EthCallResponse { value: Some(Bytes::new()), error: None };
2479        let expected = vec![vec![tx1_res.clone(), tx2_res.clone()]];
2480
2481        assert_eq!(results, expected);
2482
2483        // Two bundles
2484        let bundles = vec![
2485            Bundle {
2486                transactions: vec![tx1.clone()],
2487                block_override: Some(block_override.clone()),
2488            },
2489            Bundle {
2490                transactions: vec![tx2.clone()],
2491                block_override: Some(block_override.clone()),
2492            },
2493        ];
2494
2495        let results = provider.call_many(&bundles).context(&context).await.unwrap();
2496        let expected = vec![vec![tx1_res.clone()], vec![tx2_res.clone()]];
2497        assert_eq!(results, expected);
2498
2499        // Two bundles by extending existing.
2500        let b1 =
2501            vec![Bundle { transactions: vec![tx1], block_override: Some(block_override.clone()) }];
2502        let b2 = vec![Bundle { transactions: vec![tx2], block_override: Some(block_override) }];
2503
2504        let results = provider.call_many(&b1).context(&context).extend_bundles(&b2).await.unwrap();
2505        assert_eq!(results, expected);
2506    }
2507
2508    #[tokio::test]
2509    #[cfg(feature = "hyper-tls")]
2510    async fn hyper_https() {
2511        let url = "https://reth-ethereum.ithaca.xyz/rpc";
2512
2513        // With the `hyper` feature enabled .connect builds the provider based on
2514        // `HyperTransport`.
2515        let provider = ProviderBuilder::new().connect(url).await.unwrap();
2516
2517        let _num = provider.get_block_number().await.unwrap();
2518    }
2519
2520    #[tokio::test]
2521    async fn test_empty_transactions() {
2522        let provider = ProviderBuilder::new().connect_anvil();
2523
2524        let block = provider.get_block_by_number(0.into()).await.unwrap().unwrap();
2525        assert!(block.transactions.is_hashes());
2526    }
2527
2528    #[tokio::test]
2529    async fn disable_test() {
2530        let provider = ProviderBuilder::new()
2531            .disable_recommended_fillers()
2532            .with_cached_nonce_management()
2533            .connect_anvil();
2534
2535        let tx = TransactionRequest::default()
2536            .with_kind(alloy_primitives::TxKind::Create)
2537            .value(U256::from(1235))
2538            .with_input(Bytes::from_str("ffffffffffffff").unwrap());
2539
2540        let err = provider.send_transaction(tx).await.unwrap_err().to_string();
2541        assert!(err.contains("missing properties: [(\"NonceManager\", [\"from\"])]"));
2542    }
2543
2544    #[tokio::test]
2545    async fn capture_anvil_logs() {
2546        let mut anvil = Anvil::new().keep_stdout().spawn();
2547
2548        let provider = ProviderBuilder::new().connect_http(anvil.endpoint_url());
2549
2550        let tx = TransactionRequest::default()
2551            .with_from(address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"))
2552            .with_to(address!("70997970C51812dc3A010C7d01b50e0d17dc79C8"))
2553            .value(U256::from(100));
2554
2555        let _ = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();
2556
2557        anvil.child_mut().kill().unwrap();
2558
2559        let mut output = String::new();
2560        anvil.child_mut().stdout.take().unwrap().read_to_string(&mut output).unwrap();
2561
2562        assert_eq!(anvil.chain_id(), 31337);
2563        assert_eq!(anvil.addresses().len(), 10);
2564        assert_eq!(anvil.keys().len(), 10);
2565
2566        assert!(output.contains("eth_sendTransaction"));
2567        assert!(output.contains("Block Number: 1"))
2568    }
2569
2570    #[tokio::test]
2571    async fn custom_estimator() {
2572        let provider = ProviderBuilder::new()
2573            .disable_recommended_fillers()
2574            .with_cached_nonce_management()
2575            .connect_anvil();
2576
2577        let _ = provider
2578            .estimate_eip1559_fees_with(Eip1559Estimator::new(|_fee, _rewards| Eip1559Estimation {
2579                max_fee_per_gas: 0,
2580                max_priority_fee_per_gas: 0,
2581            }))
2582            .await;
2583    }
2584
2585    #[tokio::test]
2586    #[cfg(not(windows))]
2587    async fn eth_sign_transaction() {
2588        async_ci_only(|| async {
2589            run_with_tempdir("reth-sign-tx", |dir| async {
2590                let reth = Reth::new().dev().disable_discovery().data_dir(dir).spawn();
2591                let provider = ProviderBuilder::new().connect_http(reth.endpoint_url());
2592
2593                let accounts = provider.get_accounts().await.unwrap();
2594                let from = accounts[0];
2595
2596                let tx = TransactionRequest::default()
2597                    .from(from)
2598                    .to(Address::random())
2599                    .value(U256::from(100))
2600                    .gas_limit(21000);
2601
2602                let signed_tx = provider.sign_transaction(tx).await.unwrap().to_vec();
2603
2604                let tx = TxEnvelope::decode(&mut signed_tx.as_slice()).unwrap();
2605
2606                let signer = tx.recover_signer().unwrap();
2607
2608                assert_eq!(signer, from);
2609            })
2610            .await
2611        })
2612        .await;
2613    }
2614
2615    #[cfg(feature = "throttle")]
2616    use alloy_transport::layers::ThrottleLayer;
2617
2618    #[cfg(feature = "throttle")]
2619    #[tokio::test]
2620    async fn test_throttled_provider() {
2621        let request_per_second = 10;
2622        let throttle_layer = ThrottleLayer::new(request_per_second);
2623
2624        let anvil = Anvil::new().spawn();
2625        let client = RpcClient::builder().layer(throttle_layer).http(anvil.endpoint_url());
2626        let provider = RootProvider::<Ethereum>::new(client);
2627
2628        let num_requests = 10;
2629        let start = std::time::Instant::now();
2630        for _ in 0..num_requests {
2631            provider.get_block_number().await.unwrap();
2632        }
2633
2634        let elapsed = start.elapsed();
2635        assert_eq!(elapsed.as_secs_f64().round() as u32, 1);
2636    }
2637
2638    #[tokio::test]
2639    #[cfg(feature = "hyper")]
2640    async fn test_connect_hyper_tls() {
2641        let p =
2642            ProviderBuilder::new().connect("https://reth-ethereum.ithaca.xyz/rpc").await.unwrap();
2643
2644        let _num = p.get_block_number().await.unwrap();
2645
2646        let anvil = Anvil::new().spawn();
2647        let p = ProviderBuilder::new().connect(&anvil.endpoint()).await.unwrap();
2648
2649        let _num = p.get_block_number().await.unwrap();
2650    }
2651
2652    #[tokio::test]
2653    async fn test_send_transaction_sync() {
2654        use alloy_network::TransactionBuilder;
2655        use alloy_primitives::{address, U256};
2656
2657        let anvil = Anvil::new().spawn();
2658        let provider = ProviderBuilder::new().connect_http(anvil.endpoint_url());
2659
2660        let tx = TransactionRequest::default()
2661            .with_from(address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"))
2662            .with_to(address!("70997970C51812dc3A010C7d01b50e0d17dc79C8"))
2663            .with_value(U256::from(100));
2664
2665        // Test the sync transaction sending
2666        let receipt = provider.send_transaction_sync(tx).await.unwrap();
2667
2668        // Verify we can access transaction metadata from the receipt
2669        let tx_hash = receipt.transaction_hash;
2670        assert!(!tx_hash.is_zero());
2671        assert_eq!(receipt.transaction_hash, tx_hash);
2672        assert!(receipt.status());
2673    }
2674
2675    #[tokio::test]
2676    async fn test_send_transaction_sync_with_fillers() {
2677        use alloy_network::TransactionBuilder;
2678        use alloy_primitives::{address, U256};
2679
2680        let provider = ProviderBuilder::new().connect_anvil_with_wallet();
2681
2682        // Create transaction without specifying gas or nonce - fillers should handle this
2683        let tx = TransactionRequest::default()
2684            .with_from(provider.default_signer_address())
2685            .with_to(address!("70997970C51812dc3A010C7d01b50e0d17dc79C8"))
2686            .with_value(U256::from(100));
2687        // Note: No gas limit, gas price, or nonce specified - fillers will provide these
2688
2689        // Test that sync transactions work with filler pipeline
2690        let receipt = provider.send_transaction_sync(tx).await.unwrap();
2691
2692        // Verify immediate access works
2693        let tx_hash = receipt.transaction_hash;
2694        assert!(!tx_hash.is_zero());
2695
2696        // Verify receipt shows fillers worked (gas was estimated and used)
2697        assert_eq!(receipt.transaction_hash, tx_hash);
2698        assert!(receipt.status());
2699        assert!(receipt.gas_used() > 0, "fillers should have estimated gas");
2700    }
2701
2702    #[tokio::test]
2703    async fn test_fill_transaction() {
2704        use alloy_network::TransactionBuilder;
2705        use alloy_primitives::{address, U256};
2706
2707        let provider = ProviderBuilder::new().connect_anvil_with_wallet();
2708
2709        let tx = TransactionRequest::default()
2710            .with_from(provider.default_signer_address())
2711            .with_to(address!("70997970C51812dc3A010C7d01b50e0d17dc79C8"))
2712            .with_value(U256::from(100));
2713
2714        let filled = provider.fill_transaction(tx).await.unwrap();
2715
2716        // Verify the response contains RLP-encoded raw bytes
2717        assert!(!filled.raw.is_empty(), "raw transaction bytes should not be empty");
2718
2719        // Verify the filled transaction has required fields populated
2720        let filled_tx = &filled.tx;
2721        assert!(filled_tx.to().is_some(), "filled transaction should have to address");
2722        assert!(filled_tx.gas_limit() > 0, "filled transaction should have gas limit");
2723        assert!(filled_tx.max_fee_per_gas() > 0, "filled transaction should have max fee per gas");
2724    }
2725}