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