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