alloy_provider/provider/
trait.rs

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