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