1#![allow(unknown_lints, mismatched_lifetime_syntaxes)]
4
5#[cfg(feature = "pubsub")]
6use super::get_block::SubFullBlocks;
7use super::{DynProvider, Empty, EthCallMany, MulticallBuilder, WatchBlocks};
8#[cfg(feature = "pubsub")]
9use crate::GetSubscription;
10use crate::{
11 heart::PendingTransactionError,
12 utils::{self, Eip1559Estimation, Eip1559Estimator},
13 EthCall, EthGetBlock, Identity, PendingTransaction, PendingTransactionBuilder,
14 PendingTransactionConfig, ProviderBuilder, ProviderCall, RootProvider, RpcWithBlock,
15 SendableTx,
16};
17use alloy_consensus::BlockHeader;
18use alloy_eips::eip2718::Encodable2718;
19use alloy_json_rpc::{RpcError, RpcRecv, RpcSend};
20use alloy_network::{Ethereum, Network};
21use alloy_network_primitives::{BlockResponse, ReceiptResponse};
22use alloy_primitives::{
23 hex, Address, BlockHash, BlockNumber, Bytes, StorageKey, StorageValue, TxHash, B256, U128,
24 U256, U64,
25};
26use alloy_rpc_client::{ClientRef, NoParams, PollerBuilder, WeakClient};
27#[cfg(feature = "pubsub")]
28use alloy_rpc_types_eth::pubsub::{Params, SubscriptionKind};
29use alloy_rpc_types_eth::{
30 erc4337::TransactionConditional,
31 simulate::{SimulatePayload, SimulatedBlock},
32 AccessListResult, BlockId, BlockNumberOrTag, Bundle, EIP1186AccountProofResponse,
33 EthCallResponse, FeeHistory, FillTransaction, Filter, FilterChanges, Index, Log,
34 StorageValuesRequest, StorageValuesResponse, SyncStatus,
35};
36use alloy_transport::TransportResult;
37use serde_json::value::RawValue;
38use std::borrow::Cow;
39
40pub type FilterPollerBuilder<R> = PollerBuilder<(U256,), Vec<R>>;
44
45#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
72#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
73#[auto_impl::auto_impl(&, &mut, Rc, Arc, Box)]
74pub trait Provider<N: Network = Ethereum>: Send + Sync {
75 fn root(&self) -> &RootProvider<N>;
77
78 fn builder() -> ProviderBuilder<Identity, Identity, N>
80 where
81 Self: Sized,
82 {
83 ProviderBuilder::default()
84 }
85
86 #[inline]
90 fn client(&self) -> ClientRef<'_> {
91 self.root().client()
92 }
93
94 #[inline]
98 fn weak_client(&self) -> WeakClient {
99 self.root().weak_client()
100 }
101
102 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
115 #[doc(alias = "boxed")]
116 fn erased(self) -> DynProvider<N>
117 where
118 Self: Sized + 'static,
119 {
120 DynProvider::new(self)
121 }
122
123 fn get_accounts(&self) -> ProviderCall<NoParams, Vec<Address>> {
126 self.client().request_noparams("eth_accounts").into()
127 }
128
129 fn get_blob_base_fee(&self) -> ProviderCall<NoParams, U128, u128> {
131 self.client()
132 .request_noparams("eth_blobBaseFee")
133 .map_resp(utils::convert_u128 as fn(U128) -> u128)
134 .into()
135 }
136
137 fn get_block_number(&self) -> ProviderCall<NoParams, U64, BlockNumber> {
139 self.client()
140 .request_noparams("eth_blockNumber")
141 .map_resp(utils::convert_u64 as fn(U64) -> u64)
142 .into()
143 }
144
145 async fn get_block_number_by_id(
150 &self,
151 block_id: BlockId,
152 ) -> TransportResult<Option<BlockNumber>> {
153 match block_id {
154 BlockId::Number(BlockNumberOrTag::Number(num)) => Ok(Some(num)),
155 BlockId::Number(BlockNumberOrTag::Latest) => self.get_block_number().await.map(Some),
156 _ => {
157 if let Ok(header) = self.get_header(block_id).await {
160 return Ok(header.map(|h| h.number()));
161 }
162 let block = self.get_block(block_id).await?;
163 Ok(block.map(|b| b.header().number()))
164 }
165 }
166 }
167
168 #[doc(alias = "eth_call")]
196 #[doc(alias = "call_with_overrides")]
197 fn call(&self, tx: N::TransactionRequest) -> EthCall<N, Bytes> {
198 EthCall::call(self.weak_client(), tx).block(BlockNumberOrTag::Pending.into())
199 }
200
201 #[doc(alias = "eth_callMany")]
210 fn call_many<'req>(
211 &self,
212 bundles: &'req [Bundle],
213 ) -> EthCallMany<'req, N, Vec<Vec<EthCallResponse>>> {
214 EthCallMany::new(self.weak_client(), bundles)
215 }
216
217 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
223 fn multicall(&self) -> MulticallBuilder<Empty, &Self, N>
224 where
225 Self: Sized,
226 {
227 MulticallBuilder::new(self)
228 }
229
230 #[doc(alias = "eth_simulateV1")]
234 fn simulate<'req>(
235 &self,
236 payload: &'req SimulatePayload,
237 ) -> RpcWithBlock<&'req SimulatePayload, Vec<SimulatedBlock<N::BlockResponse>>> {
238 self.client().request("eth_simulateV1", payload).into()
239 }
240
241 fn get_chain_id(&self) -> ProviderCall<NoParams, U64, u64> {
243 self.client()
244 .request_noparams("eth_chainId")
245 .map_resp(utils::convert_u64 as fn(U64) -> u64)
246 .into()
247 }
248
249 fn create_access_list<'a>(
253 &self,
254 request: &'a N::TransactionRequest,
255 ) -> RpcWithBlock<&'a N::TransactionRequest, AccessListResult> {
256 self.client().request("eth_createAccessList", request).into()
257 }
258
259 fn estimate_gas(&self, tx: N::TransactionRequest) -> EthCall<N, U64, u64> {
273 EthCall::gas_estimate(self.weak_client(), tx)
274 .block(BlockNumberOrTag::Pending.into())
275 .map_resp(utils::convert_u64)
276 }
277
278 async fn estimate_eip1559_fees_with(
285 &self,
286 estimator: Eip1559Estimator,
287 ) -> TransportResult<Eip1559Estimation> {
288 let fee_history = self
289 .get_fee_history(
290 utils::EIP1559_FEE_ESTIMATION_PAST_BLOCKS,
291 BlockNumberOrTag::Latest,
292 &[utils::EIP1559_FEE_ESTIMATION_REWARD_PERCENTILE],
293 )
294 .await?;
295
296 let base_fee_per_gas = match fee_history.latest_block_base_fee() {
299 Some(base_fee) if base_fee != 0 => base_fee,
300 _ => {
301 self.get_block_by_number(BlockNumberOrTag::Latest)
303 .await?
304 .ok_or(RpcError::NullResp)?
305 .header()
306 .as_ref()
307 .base_fee_per_gas()
308 .ok_or(RpcError::UnsupportedFeature("eip1559"))?
309 .into()
310 }
311 };
312
313 Ok(estimator.estimate(base_fee_per_gas, &fee_history.reward.unwrap_or_default()))
314 }
315
316 async fn estimate_eip1559_fees(&self) -> TransportResult<Eip1559Estimation> {
322 self.estimate_eip1559_fees_with(Eip1559Estimator::default()).await
323 }
324
325 async fn get_fee_history(
331 &self,
332 block_count: u64,
333 last_block: BlockNumberOrTag,
334 reward_percentiles: &[f64],
335 ) -> TransportResult<FeeHistory> {
336 self.client()
337 .request("eth_feeHistory", (U64::from(block_count), last_block, reward_percentiles))
338 .await
339 }
340
341 fn get_gas_price(&self) -> ProviderCall<NoParams, U128, u128> {
343 self.client()
344 .request_noparams("eth_gasPrice")
345 .map_resp(utils::convert_u128 as fn(U128) -> u128)
346 .into()
347 }
348
349 fn get_account_info(
355 &self,
356 address: Address,
357 ) -> RpcWithBlock<Address, alloy_rpc_types_eth::AccountInfo> {
358 self.client().request("eth_getAccountInfo", address).into()
359 }
360
361 fn get_account(&self, address: Address) -> RpcWithBlock<Address, alloy_consensus::TrieAccount> {
364 self.client().request("eth_getAccount", address).into()
365 }
366
367 fn get_balance(&self, address: Address) -> RpcWithBlock<Address, U256, U256> {
371 self.client().request("eth_getBalance", address).into()
372 }
373
374 fn get_block(&self, block: BlockId) -> EthGetBlock<N::BlockResponse> {
385 match block {
386 BlockId::Hash(hash) => EthGetBlock::by_hash(hash.block_hash, self.client()),
387 BlockId::Number(number) => EthGetBlock::by_number(number, self.client()),
388 }
389 }
390
391 fn get_block_by_hash(&self, hash: BlockHash) -> EthGetBlock<N::BlockResponse> {
416 EthGetBlock::by_hash(hash, self.client())
417 }
418
419 fn get_block_by_number(&self, number: BlockNumberOrTag) -> EthGetBlock<N::BlockResponse> {
444 EthGetBlock::by_number(number, self.client())
445 }
446
447 async fn get_block_transaction_count_by_hash(
449 &self,
450 hash: BlockHash,
451 ) -> TransportResult<Option<u64>> {
452 self.client()
453 .request("eth_getBlockTransactionCountByHash", (hash,))
454 .await
455 .map(|opt_count: Option<U64>| opt_count.map(|count| count.to::<u64>()))
456 }
457
458 async fn get_block_transaction_count_by_number(
460 &self,
461 block_number: BlockNumberOrTag,
462 ) -> TransportResult<Option<u64>> {
463 self.client()
464 .request("eth_getBlockTransactionCountByNumber", (block_number,))
465 .await
466 .map(|opt_count: Option<U64>| opt_count.map(|count| count.to::<u64>()))
467 }
468
469 fn get_block_receipts(
471 &self,
472 block: BlockId,
473 ) -> ProviderCall<(BlockId,), Option<Vec<N::ReceiptResponse>>> {
474 self.client().request("eth_getBlockReceipts", (block,)).into()
475 }
476
477 async fn get_block_access_list(&self, block: BlockId) -> TransportResult<Option<Bytes>> {
481 match block {
482 BlockId::Hash(hash) => self.get_block_access_list_by_hash(hash.block_hash).await,
483 BlockId::Number(number) => self.get_block_access_list_by_number(number).await,
484 }
485 }
486
487 async fn get_block_access_list_by_hash(
491 &self,
492 hash: BlockHash,
493 ) -> TransportResult<Option<Bytes>> {
494 self.client().request("eth_getBlockAccessListByBlockHash", (hash,)).await
495 }
496
497 async fn get_block_access_list_by_number(
501 &self,
502 number: BlockNumberOrTag,
503 ) -> TransportResult<Option<Bytes>> {
504 self.client().request("eth_getBlockAccessListByBlockNumber", (number,)).await
505 }
506
507 async fn get_header(&self, block: BlockId) -> TransportResult<Option<N::HeaderResponse>> {
528 match block {
529 BlockId::Hash(hash) => self.get_header_by_hash(hash.block_hash).await,
530 BlockId::Number(number) => self.get_header_by_number(number).await,
531 }
532 }
533
534 async fn get_header_by_hash(
553 &self,
554 hash: BlockHash,
555 ) -> TransportResult<Option<N::HeaderResponse>> {
556 self.client().request("eth_getHeaderByHash", (hash,)).await
557 }
558
559 async fn get_header_by_number(
580 &self,
581 number: BlockNumberOrTag,
582 ) -> TransportResult<Option<N::HeaderResponse>> {
583 self.client().request("eth_getHeaderByNumber", (number,)).await
584 }
585
586 fn get_code_at(&self, address: Address) -> RpcWithBlock<Address, Bytes> {
588 self.client().request("eth_getCode", address).into()
589 }
590
591 async fn watch_blocks(&self) -> TransportResult<FilterPollerBuilder<B256>> {
614 let id = self.new_block_filter().await?;
615 Ok(PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,)))
616 }
617
618 async fn watch_full_blocks(&self) -> TransportResult<WatchBlocks<N::BlockResponse>> {
642 let id = self.new_block_filter().await?;
643 let poller = PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,));
644
645 Ok(WatchBlocks::new(poller))
646 }
647
648 async fn watch_pending_transactions(&self) -> TransportResult<FilterPollerBuilder<B256>> {
671 let id = self.new_pending_transactions_filter(false).await?;
672 Ok(PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,)))
673 }
674
675 async fn watch_logs(&self, filter: &Filter) -> TransportResult<FilterPollerBuilder<Log>> {
704 let id = self.new_filter(filter).await?;
705 Ok(PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,)))
706 }
707
708 async fn watch_full_pending_transactions(
735 &self,
736 ) -> TransportResult<FilterPollerBuilder<N::TransactionResponse>> {
737 let id = self.new_pending_transactions_filter(true).await?;
738 Ok(PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,)))
739 }
740
741 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
746 async fn get_filter_changes<R: RpcRecv>(&self, id: U256) -> TransportResult<Vec<R>>
747 where
748 Self: Sized,
749 {
750 self.client().request("eth_getFilterChanges", (id,)).await
751 }
752
753 async fn get_filter_changes_dyn(&self, id: U256) -> TransportResult<FilterChanges> {
758 self.client().request("eth_getFilterChanges", (id,)).await
759 }
760
761 async fn get_filter_logs(&self, id: U256) -> TransportResult<Vec<Log>> {
763 self.client().request("eth_getFilterLogs", (id,)).await
764 }
765
766 async fn uninstall_filter(&self, id: U256) -> TransportResult<bool> {
768 self.client().request("eth_uninstallFilter", (id,)).await
769 }
770
771 #[inline]
776 async fn watch_pending_transaction(
777 &self,
778 config: PendingTransactionConfig,
779 ) -> Result<PendingTransaction, PendingTransactionError> {
780 self.root().watch_pending_transaction(config).await
781 }
782
783 async fn get_logs(&self, filter: &Filter) -> TransportResult<Vec<Log>> {
785 self.client().request("eth_getLogs", (filter,)).await
786 }
787
788 fn get_proof(
792 &self,
793 address: Address,
794 keys: Vec<StorageKey>,
795 ) -> RpcWithBlock<(Address, Vec<StorageKey>), EIP1186AccountProofResponse> {
796 self.client().request("eth_getProof", (address, keys)).into()
797 }
798
799 fn get_storage_at(
801 &self,
802 address: Address,
803 key: U256,
804 ) -> RpcWithBlock<(Address, U256), StorageValue> {
805 self.client().request("eth_getStorageAt", (address, key)).into()
806 }
807
808 fn get_storage_values(
812 &self,
813 requests: StorageValuesRequest,
814 ) -> RpcWithBlock<(StorageValuesRequest,), StorageValuesResponse> {
815 self.client().request("eth_getStorageValues", (requests,)).into()
816 }
817
818 fn get_transaction_by_sender_nonce(
822 &self,
823 sender: Address,
824 nonce: u64,
825 ) -> ProviderCall<(Address, U64), Option<N::TransactionResponse>> {
826 self.client()
827 .request("eth_getTransactionBySenderAndNonce", (sender, U64::from(nonce)))
828 .into()
829 }
830
831 fn get_transaction_by_hash(
833 &self,
834 hash: TxHash,
835 ) -> ProviderCall<(TxHash,), Option<N::TransactionResponse>> {
836 self.client().request("eth_getTransactionByHash", (hash,)).into()
837 }
838
839 fn get_transaction_by_block_hash_and_index(
841 &self,
842 block_hash: B256,
843 index: usize,
844 ) -> ProviderCall<(B256, Index), Option<N::TransactionResponse>> {
845 self.client()
846 .request("eth_getTransactionByBlockHashAndIndex", (block_hash, Index(index)))
847 .into()
848 }
849
850 fn get_raw_transaction_by_block_hash_and_index(
852 &self,
853 block_hash: B256,
854 index: usize,
855 ) -> ProviderCall<(B256, Index), Option<Bytes>> {
856 self.client()
857 .request("eth_getRawTransactionByBlockHashAndIndex", (block_hash, Index(index)))
858 .into()
859 }
860
861 fn get_transaction_by_block_number_and_index(
863 &self,
864 block_number: BlockNumberOrTag,
865 index: usize,
866 ) -> ProviderCall<(BlockNumberOrTag, Index), Option<N::TransactionResponse>> {
867 self.client()
868 .request("eth_getTransactionByBlockNumberAndIndex", (block_number, Index(index)))
869 .into()
870 }
871
872 fn get_raw_transaction_by_block_number_and_index(
874 &self,
875 block_number: BlockNumberOrTag,
876 index: usize,
877 ) -> ProviderCall<(BlockNumberOrTag, Index), Option<Bytes>> {
878 self.client()
879 .request("eth_getRawTransactionByBlockNumberAndIndex", (block_number, Index(index)))
880 .into()
881 }
882
883 fn get_raw_transaction_by_hash(&self, hash: TxHash) -> ProviderCall<(TxHash,), Option<Bytes>> {
895 self.client().request("eth_getRawTransactionByHash", (hash,)).into()
896 }
897
898 #[doc(alias = "get_nonce")]
900 #[doc(alias = "get_account_nonce")]
901 fn get_transaction_count(
902 &self,
903 address: Address,
904 ) -> RpcWithBlock<Address, U64, u64, fn(U64) -> u64> {
905 self.client()
906 .request("eth_getTransactionCount", address)
907 .map_resp(utils::convert_u64 as fn(U64) -> u64)
908 .into()
909 }
910
911 fn get_transaction_receipt(
913 &self,
914 hash: TxHash,
915 ) -> ProviderCall<(TxHash,), Option<N::ReceiptResponse>> {
916 self.client().request("eth_getTransactionReceipt", (hash,)).into()
917 }
918
919 async fn get_uncle(&self, tag: BlockId, idx: u64) -> TransportResult<Option<N::BlockResponse>> {
921 let idx = U64::from(idx);
922 match tag {
923 BlockId::Hash(hash) => {
924 self.client()
925 .request("eth_getUncleByBlockHashAndIndex", (hash.block_hash, idx))
926 .await
927 }
928 BlockId::Number(number) => {
929 self.client().request("eth_getUncleByBlockNumberAndIndex", (number, idx)).await
930 }
931 }
932 }
933
934 async fn get_uncle_count(&self, tag: BlockId) -> TransportResult<u64> {
936 match tag {
937 BlockId::Hash(hash) => self
938 .client()
939 .request("eth_getUncleCountByBlockHash", (hash.block_hash,))
940 .await
941 .map(|count: U64| count.to::<u64>()),
942 BlockId::Number(number) => self
943 .client()
944 .request("eth_getUncleCountByBlockNumber", (number,))
945 .await
946 .map(|count: U64| count.to::<u64>()),
947 }
948 }
949
950 fn get_max_priority_fee_per_gas(&self) -> ProviderCall<NoParams, U128, u128> {
952 self.client()
953 .request_noparams("eth_maxPriorityFeePerGas")
954 .map_resp(utils::convert_u128 as fn(U128) -> u128)
955 .into()
956 }
957
958 async fn new_block_filter(&self) -> TransportResult<U256> {
964 self.client().request_noparams("eth_newBlockFilter").await
965 }
966
967 async fn new_filter(&self, filter: &Filter) -> TransportResult<U256> {
973 self.client().request("eth_newFilter", (filter,)).await
974 }
975
976 async fn new_pending_transactions_filter(&self, full: bool) -> TransportResult<U256> {
986 let param = if full { &[true][..] } else { &[] };
988 self.client().request("eth_newPendingTransactionFilter", param).await
989 }
990
991 async fn send_raw_transaction(
995 &self,
996 encoded_tx: &[u8],
997 ) -> TransportResult<PendingTransactionBuilder<N>> {
998 let rlp_hex = hex::encode_prefixed(encoded_tx);
999 let tx_hash = self.client().request("eth_sendRawTransaction", (rlp_hex,)).await?;
1000 Ok(PendingTransactionBuilder::new(self.root().clone(), tx_hash))
1001 }
1002
1003 async fn send_raw_transaction_sync(
1041 &self,
1042 encoded_tx: &[u8],
1043 ) -> TransportResult<N::ReceiptResponse> {
1044 let rlp_hex = hex::encode_prefixed(encoded_tx);
1045 self.client().request("eth_sendRawTransactionSync", (rlp_hex,)).await
1046 }
1047
1048 async fn send_raw_transaction_conditional(
1059 &self,
1060 encoded_tx: &[u8],
1061 conditional: TransactionConditional,
1062 ) -> TransportResult<PendingTransactionBuilder<N>> {
1063 let rlp_hex = hex::encode_prefixed(encoded_tx);
1064 let tx_hash = self
1065 .client()
1066 .request("eth_sendRawTransactionConditional", (rlp_hex, conditional))
1067 .await?;
1068 Ok(PendingTransactionBuilder::new(self.root().clone(), tx_hash))
1069 }
1070
1071 async fn send_transaction(
1092 &self,
1093 tx: N::TransactionRequest,
1094 ) -> TransportResult<PendingTransactionBuilder<N>> {
1095 self.send_transaction_internal(SendableTx::Builder(tx)).await
1096 }
1097
1098 async fn send_tx_envelope(
1103 &self,
1104 tx: N::TxEnvelope,
1105 ) -> TransportResult<PendingTransactionBuilder<N>> {
1106 self.send_transaction_internal(SendableTx::Envelope(tx)).await
1107 }
1108
1109 #[doc(hidden)]
1116 async fn send_transaction_internal(
1117 &self,
1118 tx: SendableTx<N>,
1119 ) -> TransportResult<PendingTransactionBuilder<N>> {
1120 let _handle = self.root().get_heart();
1123
1124 match tx {
1125 SendableTx::Builder(mut tx) => {
1126 alloy_network::TransactionBuilder::prep_for_submission(&mut tx);
1127 let tx_hash = self.client().request("eth_sendTransaction", (tx,)).await?;
1128 Ok(PendingTransactionBuilder::new(self.root().clone(), tx_hash))
1129 }
1130 SendableTx::Envelope(tx) => {
1131 let encoded_tx = tx.encoded_2718();
1132 self.send_raw_transaction(&encoded_tx).await
1133 }
1134 }
1135 }
1136
1137 async fn send_transaction_sync(
1177 &self,
1178 tx: N::TransactionRequest,
1179 ) -> TransportResult<N::ReceiptResponse> {
1180 self.send_transaction_sync_internal(SendableTx::Builder(tx)).await
1181 }
1182
1183 #[doc(hidden)]
1193 async fn send_transaction_sync_internal(
1194 &self,
1195 tx: SendableTx<N>,
1196 ) -> TransportResult<N::ReceiptResponse> {
1197 let _handle = self.root().get_heart();
1200
1201 match tx {
1202 SendableTx::Builder(mut tx) => {
1203 alloy_network::TransactionBuilder::prep_for_submission(&mut tx);
1204 let receipt = self.client().request("eth_sendTransactionSync", (tx,)).await?;
1205 Ok(receipt)
1206 }
1207 SendableTx::Envelope(tx) => {
1208 let encoded_tx = tx.encoded_2718();
1209 self.send_raw_transaction_sync(&encoded_tx).await
1210 }
1211 }
1212 }
1213
1214 async fn sign_transaction(&self, tx: N::TransactionRequest) -> TransportResult<Bytes> {
1219 self.client().request("eth_signTransaction", (tx,)).await
1220 }
1221
1222 async fn fill_transaction(
1228 &self,
1229 tx: N::TransactionRequest,
1230 ) -> TransportResult<FillTransaction<N::TxEnvelope>>
1231 where
1232 N::TxEnvelope: RpcRecv,
1233 {
1234 self.client().request("eth_fillTransaction", (tx,)).await
1235 }
1236
1237 #[cfg(feature = "pubsub")]
1263 fn subscribe_blocks(&self) -> GetSubscription<(SubscriptionKind,), N::HeaderResponse> {
1264 let rpc_call = self.client().request("eth_subscribe", (SubscriptionKind::NewHeads,));
1265 GetSubscription::new(self.weak_client(), rpc_call)
1266 }
1267
1268 #[cfg(feature = "pubsub")]
1292 fn subscribe_full_blocks(&self) -> SubFullBlocks<N> {
1293 SubFullBlocks::new(self.subscribe_blocks(), self.weak_client())
1294 }
1295
1296 #[cfg(feature = "pubsub")]
1322 fn subscribe_pending_transactions(&self) -> GetSubscription<(SubscriptionKind,), B256> {
1323 let rpc_call =
1324 self.client().request("eth_subscribe", (SubscriptionKind::NewPendingTransactions,));
1325 GetSubscription::new(self.weak_client(), rpc_call)
1326 }
1327
1328 #[cfg(feature = "pubsub")]
1359 fn subscribe_full_pending_transactions(
1360 &self,
1361 ) -> GetSubscription<(SubscriptionKind, Params), N::TransactionResponse> {
1362 let rpc_call = self.client().request(
1363 "eth_subscribe",
1364 (SubscriptionKind::NewPendingTransactions, Params::Bool(true)),
1365 );
1366 GetSubscription::new(self.weak_client(), rpc_call)
1367 }
1368
1369 #[cfg(feature = "pubsub")]
1400 fn subscribe_logs(&self, filter: &Filter) -> GetSubscription<(SubscriptionKind, Params), Log> {
1401 let rpc_call = self.client().request(
1402 "eth_subscribe",
1403 (SubscriptionKind::Logs, Params::Logs(Box::new(filter.clone()))),
1404 );
1405 GetSubscription::new(self.weak_client(), rpc_call)
1406 }
1407
1408 #[cfg(feature = "pubsub")]
1410 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
1411 fn subscribe<P, R>(&self, params: P) -> GetSubscription<P, R>
1412 where
1413 P: RpcSend,
1414 R: RpcRecv,
1415 Self: Sized,
1416 {
1417 let rpc_call = self.client().request("eth_subscribe", params);
1418 GetSubscription::new(self.weak_client(), rpc_call)
1419 }
1420
1421 #[cfg(feature = "pubsub")]
1442 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
1443 fn subscribe_to<R>(&self, method: &'static str) -> GetSubscription<NoParams, R>
1444 where
1445 R: RpcRecv,
1446 Self: Sized,
1447 {
1448 let mut rpc_call = self.client().request_noparams(method);
1449 rpc_call.set_is_subscription();
1450 GetSubscription::new(self.weak_client(), rpc_call)
1451 }
1452
1453 #[cfg(feature = "pubsub")]
1455 async fn unsubscribe(&self, id: B256) -> TransportResult<()> {
1456 self.root().unsubscribe(id)
1457 }
1458
1459 fn syncing(&self) -> ProviderCall<NoParams, SyncStatus> {
1461 self.client().request_noparams("eth_syncing").into()
1462 }
1463
1464 #[doc(alias = "web3_client_version")]
1466 fn get_client_version(&self) -> ProviderCall<NoParams, String> {
1467 self.client().request_noparams("web3_clientVersion").into()
1468 }
1469
1470 #[doc(alias = "web3_sha3")]
1472 fn get_sha3(&self, data: &[u8]) -> ProviderCall<(String,), B256> {
1473 self.client().request("web3_sha3", (hex::encode_prefixed(data),)).into()
1474 }
1475
1476 fn get_net_version(&self) -> ProviderCall<NoParams, U64, u64> {
1478 self.client()
1479 .request_noparams("net_version")
1480 .map_resp(utils::convert_u64 as fn(U64) -> u64)
1481 .into()
1482 }
1483
1484 async fn raw_request<P, R>(&self, method: Cow<'static, str>, params: P) -> TransportResult<R>
1509 where
1510 P: RpcSend,
1511 R: RpcRecv,
1512 Self: Sized,
1513 {
1514 self.client().request(method, ¶ms).await
1515 }
1516
1517 async fn raw_request_dyn(
1540 &self,
1541 method: Cow<'static, str>,
1542 params: &RawValue,
1543 ) -> TransportResult<Box<RawValue>> {
1544 self.client().request(method, params).await
1545 }
1546
1547 #[inline]
1549 fn transaction_request(&self) -> N::TransactionRequest {
1550 Default::default()
1551 }
1552}
1553
1554#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
1555#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
1556impl<N: Network> Provider<N> for RootProvider<N> {
1557 #[inline]
1558 fn root(&self) -> &Self {
1559 self
1560 }
1561
1562 #[inline]
1563 fn client(&self) -> ClientRef<'_> {
1564 self.inner.client_ref()
1565 }
1566
1567 #[inline]
1568 fn weak_client(&self) -> WeakClient {
1569 self.inner.weak_client()
1570 }
1571
1572 #[inline]
1573 async fn watch_pending_transaction(
1574 &self,
1575 config: PendingTransactionConfig,
1576 ) -> Result<PendingTransaction, PendingTransactionError> {
1577 let block_number =
1578 if let Some(receipt) = self.get_transaction_receipt(*config.tx_hash()).await? {
1579 if config.required_confirmations() <= 1 {
1581 return Ok(PendingTransaction::ready(*config.tx_hash()));
1582 }
1583 receipt.block_number()
1586 } else {
1587 None
1588 };
1589
1590 self.get_heart()
1591 .watch_tx(config, block_number)
1592 .await
1593 .map_err(|_| PendingTransactionError::FailedToRegister)
1594 }
1595}
1596
1597#[cfg(test)]
1598mod tests {
1599 use super::*;
1600 use crate::{builder, ext::test::async_ci_only, ProviderBuilder, WalletProvider};
1601 use alloy_consensus::{Transaction, TxEnvelope};
1602 use alloy_network::{AnyNetwork, EthereumWallet, TransactionBuilder};
1603 use alloy_node_bindings::{utils::run_with_tempdir, Anvil, Reth};
1604 use alloy_primitives::{address, b256, bytes, keccak256};
1605 use alloy_rlp::Decodable;
1606 use alloy_rpc_client::{BuiltInConnectionString, RpcClient};
1607 use alloy_rpc_types_eth::{request::TransactionRequest, Block};
1608 use alloy_signer_local::PrivateKeySigner;
1609 use alloy_transport::layers::{RetryBackoffLayer, RetryPolicy};
1610 use std::{io::Read, str::FromStr, time::Duration};
1611
1612 use alloy_consensus::transaction::SignerRecoverable;
1614 #[cfg(feature = "hyper")]
1615 use alloy_transport_http::{
1616 hyper,
1617 hyper::body::Bytes as HyperBytes,
1618 hyper_util::{
1619 client::legacy::{Client, Error},
1620 rt::TokioExecutor,
1621 },
1622 HyperResponse, HyperResponseFut,
1623 };
1624 #[cfg(feature = "hyper")]
1625 use http_body_util::Full;
1626 #[cfg(feature = "hyper")]
1627 use tower::{Layer, Service};
1628
1629 #[tokio::test]
1630 async fn test_provider_builder() {
1631 let provider =
1632 RootProvider::<Ethereum>::builder().with_recommended_fillers().connect_anvil();
1633 let num = provider.get_block_number().await.unwrap();
1634 assert_eq!(0, num);
1635 }
1636
1637 #[tokio::test]
1638 async fn test_builder_helper_fn() {
1639 let provider = builder::<Ethereum>().with_recommended_fillers().connect_anvil();
1640 let num = provider.get_block_number().await.unwrap();
1641 assert_eq!(0, num);
1642 }
1643
1644 #[cfg(feature = "hyper")]
1645 #[tokio::test]
1646 async fn test_default_hyper_transport() {
1647 let anvil = Anvil::new().spawn();
1648 let hyper_t = alloy_transport_http::HyperTransport::new_hyper(anvil.endpoint_url());
1649
1650 let rpc_client = alloy_rpc_client::RpcClient::new(hyper_t, true);
1651
1652 let provider = RootProvider::<Ethereum>::new(rpc_client);
1653 let num = provider.get_block_number().await.unwrap();
1654 assert_eq!(0, num);
1655 }
1656
1657 #[cfg(feature = "hyper")]
1658 #[tokio::test]
1659 async fn test_hyper_layer_transport() {
1660 struct LoggingLayer;
1661
1662 impl<S> Layer<S> for LoggingLayer {
1663 type Service = LoggingService<S>;
1664
1665 fn layer(&self, inner: S) -> Self::Service {
1666 LoggingService { inner }
1667 }
1668 }
1669
1670 #[derive(Clone)] struct LoggingService<S> {
1672 inner: S,
1673 }
1674
1675 impl<S, B> Service<hyper::Request<B>> for LoggingService<S>
1676 where
1677 S: Service<hyper::Request<B>, Response = HyperResponse, Error = Error>
1678 + Clone
1679 + Send
1680 + Sync
1681 + 'static,
1682 S::Future: Send,
1683 S::Error: std::error::Error + Send + Sync + 'static,
1684 B: From<Vec<u8>> + Send + 'static + Clone + Sync + std::fmt::Debug,
1685 {
1686 type Response = HyperResponse;
1687 type Error = Error;
1688 type Future = HyperResponseFut;
1689
1690 fn poll_ready(
1691 &mut self,
1692 cx: &mut std::task::Context<'_>,
1693 ) -> std::task::Poll<Result<(), Self::Error>> {
1694 self.inner.poll_ready(cx)
1695 }
1696
1697 fn call(&mut self, req: hyper::Request<B>) -> Self::Future {
1698 println!("Logging Layer - HyperRequest {req:?}");
1699
1700 let fut = self.inner.call(req);
1701
1702 Box::pin(fut)
1703 }
1704 }
1705 use http::header::{self, HeaderValue};
1706 use tower_http::{
1707 sensitive_headers::SetSensitiveRequestHeadersLayer, set_header::SetRequestHeaderLayer,
1708 };
1709 let anvil = Anvil::new().spawn();
1710 let hyper_client = Client::builder(TokioExecutor::new()).build_http::<Full<HyperBytes>>();
1711
1712 let service = tower::ServiceBuilder::new()
1714 .layer(SetRequestHeaderLayer::if_not_present(
1715 header::USER_AGENT,
1716 HeaderValue::from_static("alloy app"),
1717 ))
1718 .layer(SetRequestHeaderLayer::overriding(
1719 header::AUTHORIZATION,
1720 HeaderValue::from_static("some-jwt-token"),
1721 ))
1722 .layer(SetRequestHeaderLayer::appending(
1723 header::SET_COOKIE,
1724 HeaderValue::from_static("cookie-value"),
1725 ))
1726 .layer(SetSensitiveRequestHeadersLayer::new([header::AUTHORIZATION])) .layer(LoggingLayer)
1728 .service(hyper_client);
1729
1730 let layer_transport = alloy_transport_http::HyperClient::with_service(service);
1731
1732 let http_hyper =
1733 alloy_transport_http::Http::with_client(layer_transport, anvil.endpoint_url());
1734
1735 let rpc_client = alloy_rpc_client::RpcClient::new(http_hyper, true);
1736
1737 let provider = RootProvider::<Ethereum>::new(rpc_client);
1738 let num = provider.get_block_number().await.unwrap();
1739 assert_eq!(0, num);
1740
1741 let cloned_t = provider.client().transport().clone();
1743
1744 let rpc_client = alloy_rpc_client::RpcClient::new(cloned_t, true);
1745
1746 let provider = RootProvider::<Ethereum>::new(rpc_client);
1747 let num = provider.get_block_number().await.unwrap();
1748 assert_eq!(0, num);
1749 }
1750
1751 #[cfg(feature = "hyper")]
1752 #[tokio::test]
1753 #[cfg_attr(windows, ignore = "no reth on windows")]
1754 async fn test_auth_layer_transport() {
1755 crate::ext::test::async_ci_only(|| async move {
1756 use alloy_node_bindings::Reth;
1757 use alloy_rpc_types_engine::JwtSecret;
1758 use alloy_transport_http::{AuthLayer, Http, HyperClient};
1759
1760 let secret = JwtSecret::random();
1761
1762 let reth =
1763 Reth::new().arg("--rpc.jwtsecret").arg(hex::encode(secret.as_bytes())).spawn();
1764
1765 let layer_transport = HyperClient::new().layer(AuthLayer::new(secret));
1766
1767 let http_hyper = Http::with_client(layer_transport, reth.endpoint_url());
1768
1769 let rpc_client = alloy_rpc_client::RpcClient::new(http_hyper, true);
1770
1771 let provider = RootProvider::<Ethereum>::new(rpc_client);
1772
1773 let num = provider.get_block_number().await.unwrap();
1774 assert_eq!(0, num);
1775 })
1776 .await;
1777 }
1778
1779 #[tokio::test]
1780 async fn test_builder_helper_fn_any_network() {
1781 let anvil = Anvil::new().spawn();
1782 let provider =
1783 builder::<AnyNetwork>().with_recommended_fillers().connect_http(anvil.endpoint_url());
1784 let num = provider.get_block_number().await.unwrap();
1785 assert_eq!(0, num);
1786 }
1787
1788 #[cfg(feature = "reqwest")]
1789 #[tokio::test]
1790 async fn object_safety() {
1791 let provider = ProviderBuilder::new().connect_anvil();
1792
1793 let refdyn = &provider as &dyn Provider<_>;
1794 let num = refdyn.get_block_number().await.unwrap();
1795 assert_eq!(0, num);
1796 }
1797
1798 #[cfg(feature = "ws")]
1799 #[tokio::test]
1800 async fn subscribe_blocks_http() {
1801 let provider = ProviderBuilder::new().connect_anvil_with_config(|a| a.block_time(1));
1802
1803 let err = provider.subscribe_blocks().await.unwrap_err();
1804 let alloy_json_rpc::RpcError::Transport(
1805 alloy_transport::TransportErrorKind::PubsubUnavailable,
1806 ) = err
1807 else {
1808 panic!("{err:?}");
1809 };
1810 }
1811
1812 #[cfg(feature = "ws")]
1814 #[tokio::test]
1815 async fn websocket_tls_setup() {
1816 for url in ["wss://mainnet.infura.io/ws/v3/b0f825787ba840af81e46c6a64d20754"] {
1817 let _ = ProviderBuilder::<_, _, Ethereum>::default().connect(url).await.unwrap();
1818 }
1819 }
1820
1821 #[cfg(feature = "ws")]
1822 #[tokio::test]
1823 async fn subscribe_blocks_ws() {
1824 use futures::stream::StreamExt;
1825
1826 let anvil = Anvil::new().block_time_f64(0.2).spawn();
1827 let ws = alloy_rpc_client::WsConnect::new(anvil.ws_endpoint());
1828 let client = alloy_rpc_client::RpcClient::connect_pubsub(ws).await.unwrap();
1829 let provider = RootProvider::<Ethereum>::new(client);
1830
1831 let sub = provider.subscribe_blocks().await.unwrap();
1832 let mut stream = sub.into_stream().take(5);
1833 let mut next = None;
1834 while let Some(header) = stream.next().await {
1835 if let Some(next) = &mut next {
1836 assert_eq!(header.number, *next);
1837 *next += 1;
1838 } else {
1839 next = Some(header.number + 1);
1840 }
1841 }
1842 }
1843
1844 #[cfg(feature = "ws")]
1845 #[tokio::test]
1846 async fn subscribe_full_blocks() {
1847 use futures::StreamExt;
1848
1849 let anvil = Anvil::new().block_time_f64(0.2).spawn();
1850 let ws = alloy_rpc_client::WsConnect::new(anvil.ws_endpoint());
1851 let client = alloy_rpc_client::RpcClient::connect_pubsub(ws).await.unwrap();
1852
1853 let provider = RootProvider::<Ethereum>::new(client);
1854
1855 let sub = provider.subscribe_full_blocks().hashes().channel_size(10);
1856
1857 let mut stream = sub.into_stream().await.unwrap().take(5);
1858
1859 let mut next = None;
1860 while let Some(Ok(block)) = stream.next().await {
1861 if let Some(next) = &mut next {
1862 assert_eq!(block.header().number, *next);
1863 *next += 1;
1864 } else {
1865 next = Some(block.header().number + 1);
1866 }
1867 }
1868 }
1869
1870 #[tokio::test]
1871 #[cfg(feature = "ws")]
1872 async fn subscribe_blocks_ws_remote() {
1873 use futures::stream::StreamExt;
1874
1875 let url = "wss://eth-mainnet.g.alchemy.com/v2/viFmeVzhg6bWKVMIWWS8MhmzREB-D4f7";
1876 let ws = alloy_rpc_client::WsConnect::new(url);
1877 let Ok(client) = alloy_rpc_client::RpcClient::connect_pubsub(ws).await else { return };
1878 let provider = RootProvider::<Ethereum>::new(client);
1879 let sub = provider.subscribe_blocks().await.unwrap();
1880 let mut stream = sub.into_stream().take(1);
1881 while let Some(header) = stream.next().await {
1882 println!("New block {header:?}");
1883 assert!(header.number > 0);
1884 }
1885 }
1886
1887 #[tokio::test]
1888 async fn test_custom_retry_policy() {
1889 #[derive(Debug, Clone)]
1890 struct CustomPolicy;
1891 impl RetryPolicy for CustomPolicy {
1892 fn should_retry(&self, _err: &alloy_transport::TransportError) -> bool {
1893 true
1894 }
1895
1896 fn backoff_hint(
1897 &self,
1898 _error: &alloy_transport::TransportError,
1899 ) -> Option<std::time::Duration> {
1900 None
1901 }
1902 }
1903
1904 let retry_layer = RetryBackoffLayer::new_with_policy(10, 100, 10000, CustomPolicy);
1905 let anvil = Anvil::new().spawn();
1906 let client = RpcClient::builder().layer(retry_layer).http(anvil.endpoint_url());
1907
1908 let provider = RootProvider::<Ethereum>::new(client);
1909 let num = provider.get_block_number().await.unwrap();
1910 assert_eq!(0, num);
1911 }
1912
1913 #[tokio::test]
1914 async fn test_send_tx() {
1915 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
1916 let tx = TransactionRequest {
1917 value: Some(U256::from(100)),
1918 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
1919 gas_price: Some(20e9 as u128),
1920 gas: Some(21000),
1921 ..Default::default()
1922 };
1923
1924 let builder = provider.send_transaction(tx.clone()).await.expect("failed to send tx");
1925 let hash1 = *builder.tx_hash();
1926 let hash2 = builder.watch().await.expect("failed to await pending tx");
1927 assert_eq!(hash1, hash2);
1928
1929 let builder = provider.send_transaction(tx).await.expect("failed to send tx");
1930 let hash1 = *builder.tx_hash();
1931 let hash2 =
1932 builder.get_receipt().await.expect("failed to await pending tx").transaction_hash;
1933 assert_eq!(hash1, hash2);
1934 }
1935
1936 #[tokio::test]
1937 async fn test_send_tx_sync() {
1938 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
1939 let tx = TransactionRequest {
1940 value: Some(U256::from(100)),
1941 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
1942 gas_price: Some(20e9 as u128),
1943 gas: Some(21000),
1944 ..Default::default()
1945 };
1946
1947 let _receipt =
1948 provider.send_transaction_sync(tx.clone()).await.expect("failed to send tx sync");
1949 }
1950
1951 #[tokio::test]
1952 async fn test_send_raw_transaction_sync() {
1953 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
1954
1955 let tx = TransactionRequest {
1957 nonce: Some(0),
1958 value: Some(U256::from(100)),
1959 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
1960 gas_price: Some(20e9 as u128),
1961 gas: Some(21000),
1962 ..Default::default()
1963 };
1964
1965 let tx_envelope = tx.build(&provider.wallet()).await.expect("failed to build tx");
1967
1968 let encoded = tx_envelope.encoded_2718();
1970
1971 let receipt =
1973 provider.send_raw_transaction_sync(&encoded).await.expect("failed to send raw tx sync");
1974
1975 assert_eq!(receipt.to(), Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045")));
1977 assert!(receipt.block_number().is_some(), "transaction should be mined");
1979 assert!(receipt.transaction_hash() != B256::ZERO, "should have valid tx hash");
1980 }
1981
1982 #[tokio::test]
1983 async fn test_watch_confirmed_tx() {
1984 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
1985 let tx = TransactionRequest {
1986 value: Some(U256::from(100)),
1987 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
1988 gas_price: Some(20e9 as u128),
1989 gas: Some(21000),
1990 ..Default::default()
1991 };
1992
1993 let builder = provider.send_transaction(tx).await.expect("failed to send tx");
1994 let hash1 = *builder.tx_hash();
1995
1996 loop {
1998 if provider
1999 .get_transaction_receipt(hash1)
2000 .await
2001 .expect("failed to await pending tx")
2002 .is_some()
2003 {
2004 break;
2005 }
2006 }
2007
2008 let tx2 = TransactionRequest {
2010 value: Some(U256::from(100)),
2011 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
2012 gas_price: Some(20e9 as u128),
2013 gas: Some(21000),
2014 ..Default::default()
2015 };
2016 provider.send_transaction(tx2).await.expect("failed to send tx").watch().await.unwrap();
2017
2018 let watch = builder.watch();
2020 let watch_with_timeout = tokio::time::timeout(Duration::from_secs(1), watch);
2022 let hash2 = watch_with_timeout
2023 .await
2024 .expect("Watching tx timed out")
2025 .expect("failed to await pending tx");
2026 assert_eq!(hash1, hash2);
2027 }
2028
2029 #[tokio::test]
2030 async fn gets_block_number() {
2031 let provider = ProviderBuilder::new().connect_anvil();
2032 let num = provider.get_block_number().await.unwrap();
2033 assert_eq!(0, num)
2034 }
2035
2036 #[tokio::test]
2037 async fn gets_block_number_for_id() {
2038 let provider = ProviderBuilder::new().connect_anvil();
2039
2040 let block_num = provider
2041 .get_block_number_by_id(BlockId::Number(BlockNumberOrTag::Number(0)))
2042 .await
2043 .unwrap();
2044 assert_eq!(block_num, Some(0));
2045
2046 let block_num = provider
2047 .get_block_number_by_id(BlockId::Number(BlockNumberOrTag::Latest))
2048 .await
2049 .unwrap();
2050 assert_eq!(block_num, Some(0));
2051
2052 let block =
2053 provider.get_block_by_number(BlockNumberOrTag::Number(0)).await.unwrap().unwrap();
2054 let hash = block.header.hash;
2055 let block_num = provider.get_block_number_by_id(BlockId::Hash(hash.into())).await.unwrap();
2056 assert_eq!(block_num, Some(0));
2057 }
2058
2059 #[tokio::test]
2060 async fn gets_block_number_with_raw_req() {
2061 let provider = ProviderBuilder::new().connect_anvil();
2062 let num: U64 =
2063 provider.raw_request("eth_blockNumber".into(), NoParams::default()).await.unwrap();
2064 assert_eq!(0, num.to::<u64>())
2065 }
2066
2067 #[cfg(feature = "anvil-api")]
2068 #[tokio::test]
2069 async fn gets_transaction_count() {
2070 let provider = ProviderBuilder::new().connect_anvil();
2071 let accounts = provider.get_accounts().await.unwrap();
2072 let sender = accounts[0];
2073
2074 let count = provider.get_transaction_count(sender).await.unwrap();
2076 assert_eq!(count, 0);
2077
2078 let tx = TransactionRequest {
2080 value: Some(U256::from(100)),
2081 from: Some(sender),
2082 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
2083 gas_price: Some(20e9 as u128),
2084 gas: Some(21000),
2085 ..Default::default()
2086 };
2087 let _ = provider.send_transaction(tx).await.unwrap().get_receipt().await;
2088
2089 let count = provider.get_transaction_count(sender).await.unwrap();
2091 assert_eq!(count, 1);
2092
2093 let count = provider.get_transaction_count(sender).block_id(0.into()).await.unwrap();
2095 assert_eq!(count, 0);
2096 }
2097
2098 #[tokio::test]
2099 async fn gets_block_by_hash() {
2100 let provider = ProviderBuilder::new().connect_anvil();
2101 let num = 0;
2102 let tag: BlockNumberOrTag = num.into();
2103 let block = provider.get_block_by_number(tag).full().await.unwrap().unwrap();
2104 let hash = block.header.hash;
2105 let block = provider.get_block_by_hash(hash).full().await.unwrap().unwrap();
2106 assert_eq!(block.header.hash, hash);
2107 }
2108
2109 #[tokio::test]
2110 async fn gets_block_by_hash_with_raw_req() {
2111 let provider = ProviderBuilder::new().connect_anvil();
2112 let num = 0;
2113 let tag: BlockNumberOrTag = num.into();
2114 let block = provider.get_block_by_number(tag).full().await.unwrap().unwrap();
2115 let hash = block.header.hash;
2116 let block: Block = provider
2117 .raw_request::<(B256, bool), Block>("eth_getBlockByHash".into(), (hash, true))
2118 .await
2119 .unwrap();
2120 assert_eq!(block.header.hash, hash);
2121 }
2122
2123 #[tokio::test]
2124 async fn gets_block_by_number_full() {
2125 let provider = ProviderBuilder::new().connect_anvil();
2126 let num = 0;
2127 let tag: BlockNumberOrTag = num.into();
2128 let block = provider.get_block_by_number(tag).full().await.unwrap().unwrap();
2129 assert_eq!(block.header.number, num);
2130 }
2131
2132 #[tokio::test]
2133 async fn gets_block_by_number() {
2134 let provider = ProviderBuilder::new().connect_anvil();
2135 let num = 0;
2136 let tag: BlockNumberOrTag = num.into();
2137 let block = provider.get_block_by_number(tag).full().await.unwrap().unwrap();
2138 assert_eq!(block.header.number, num);
2139 }
2140
2141 #[tokio::test]
2142 async fn gets_client_version() {
2143 let provider = ProviderBuilder::new().connect_anvil();
2144 let version = provider.get_client_version().await.unwrap();
2145 assert!(version.contains("anvil"), "{version}");
2146 }
2147
2148 #[tokio::test]
2149 async fn gets_sha3() {
2150 let provider = ProviderBuilder::new().connect_anvil();
2151 let data = b"alloy";
2152 let hash = provider.get_sha3(data).await.unwrap();
2153 assert_eq!(hash, keccak256(data));
2154 }
2155
2156 #[tokio::test]
2157 async fn gets_chain_id() {
2158 let dev_chain_id: u64 = 13371337;
2159
2160 let provider =
2161 ProviderBuilder::new().connect_anvil_with_config(|a| a.chain_id(dev_chain_id));
2162
2163 let chain_id = provider.get_chain_id().await.unwrap();
2164 assert_eq!(chain_id, dev_chain_id);
2165 }
2166
2167 #[tokio::test]
2168 async fn gets_network_id() {
2169 let dev_chain_id: u64 = 13371337;
2170 let provider =
2171 ProviderBuilder::new().connect_anvil_with_config(|a| a.chain_id(dev_chain_id));
2172
2173 let chain_id = provider.get_net_version().await.unwrap();
2174 assert_eq!(chain_id, dev_chain_id);
2175 }
2176
2177 #[tokio::test]
2178 async fn gets_storage_at() {
2179 let provider = ProviderBuilder::new().connect_anvil();
2180 let addr = Address::with_last_byte(16);
2181 let storage = provider.get_storage_at(addr, U256::ZERO).await.unwrap();
2182 assert_eq!(storage, U256::ZERO);
2183 }
2184
2185 #[tokio::test]
2186 async fn gets_transaction_by_hash_not_found() {
2187 let provider = ProviderBuilder::new().connect_anvil();
2188 let tx_hash = b256!("5c03fab9114ceb98994b43892ade87ddfd9ae7e8f293935c3bd29d435dc9fd95");
2189 let tx = provider.get_transaction_by_hash(tx_hash).await.expect("failed to fetch tx");
2190
2191 assert!(tx.is_none());
2192 }
2193
2194 #[tokio::test]
2195 async fn gets_transaction_by_hash() {
2196 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
2197
2198 let req = TransactionRequest::default()
2199 .from(provider.default_signer_address())
2200 .to(Address::repeat_byte(5))
2201 .value(U256::ZERO)
2202 .input(bytes!("deadbeef").into());
2203
2204 let tx_hash = *provider.send_transaction(req).await.expect("failed to send tx").tx_hash();
2205
2206 let tx = provider
2207 .get_transaction_by_hash(tx_hash)
2208 .await
2209 .expect("failed to fetch tx")
2210 .expect("tx not included");
2211 assert_eq!(tx.input(), &bytes!("deadbeef"));
2212 }
2213
2214 #[tokio::test]
2215 #[ignore]
2216 async fn gets_logs() {
2217 let provider = ProviderBuilder::new().connect_anvil();
2218 let filter = Filter::new()
2219 .at_block_hash(b256!(
2220 "b20e6f35d4b46b3c4cd72152faec7143da851a0dc281d390bdd50f58bfbdb5d3"
2221 ))
2222 .event_signature(b256!(
2223 "e1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c"
2224 ));
2225 let logs = provider.get_logs(&filter).await.unwrap();
2226 assert_eq!(logs.len(), 1);
2227 }
2228
2229 #[tokio::test]
2230 #[ignore]
2231 async fn gets_tx_receipt() {
2232 let provider = ProviderBuilder::new().connect_anvil();
2233 let receipt = provider
2234 .get_transaction_receipt(b256!(
2235 "5c03fab9114ceb98994b43892ade87ddfd9ae7e8f293935c3bd29d435dc9fd95"
2236 ))
2237 .await
2238 .unwrap();
2239 assert!(receipt.is_some());
2240 let receipt = receipt.unwrap();
2241 assert_eq!(
2242 receipt.transaction_hash,
2243 b256!("5c03fab9114ceb98994b43892ade87ddfd9ae7e8f293935c3bd29d435dc9fd95")
2244 );
2245 }
2246
2247 #[tokio::test]
2248 async fn gets_max_priority_fee_per_gas() {
2249 let provider = ProviderBuilder::new().connect_anvil();
2250 let _fee = provider.get_max_priority_fee_per_gas().await.unwrap();
2251 }
2252
2253 #[tokio::test]
2254 async fn gets_fee_history() {
2255 let provider = ProviderBuilder::new().connect_anvil();
2256 let block_number = provider.get_block_number().await.unwrap();
2257 let fee_history = provider
2258 .get_fee_history(
2259 utils::EIP1559_FEE_ESTIMATION_PAST_BLOCKS,
2260 BlockNumberOrTag::Number(block_number),
2261 &[utils::EIP1559_FEE_ESTIMATION_REWARD_PERCENTILE],
2262 )
2263 .await
2264 .unwrap();
2265 assert_eq!(fee_history.oldest_block, 0_u64);
2266 }
2267
2268 #[tokio::test]
2269 async fn gets_block_transaction_count_by_hash() {
2270 let provider = ProviderBuilder::new().connect_anvil();
2271 let block = provider.get_block(BlockId::latest()).await.unwrap().unwrap();
2272 let hash = block.header.hash;
2273 let tx_count = provider.get_block_transaction_count_by_hash(hash).await.unwrap();
2274 assert!(tx_count.is_some());
2275 }
2276
2277 #[tokio::test]
2278 async fn gets_block_transaction_count_by_number() {
2279 let provider = ProviderBuilder::new().connect_anvil();
2280 let tx_count =
2281 provider.get_block_transaction_count_by_number(BlockNumberOrTag::Latest).await.unwrap();
2282 assert!(tx_count.is_some());
2283 }
2284
2285 #[tokio::test]
2286 async fn gets_block_receipts() {
2287 let provider = ProviderBuilder::new().connect_anvil();
2288 let receipts =
2289 provider.get_block_receipts(BlockId::Number(BlockNumberOrTag::Latest)).await.unwrap();
2290 assert!(receipts.is_some());
2291 }
2292
2293 #[tokio::test]
2294 async fn sends_raw_transaction() {
2295 let provider = ProviderBuilder::new().connect_anvil();
2296 let pending = provider
2297 .send_raw_transaction(
2298 bytes!("f865808477359400825208940000000000000000000000000000000000000000018082f4f5a00505e227c1c636c76fac55795db1a40a4d24840d81b40d2fe0cc85767f6bd202a01e91b437099a8a90234ac5af3cb7ca4fb1432e133f75f9a91678eaf5f487c74b").as_ref()
2300 )
2301 .await.unwrap();
2302 assert_eq!(
2303 pending.tx_hash().to_string(),
2304 "0x9dae5cf33694a02e8a7d5de3fe31e9d05ca0ba6e9180efac4ab20a06c9e598a3"
2305 );
2306 }
2307
2308 #[tokio::test]
2309 async fn connect_boxed() {
2310 let anvil = Anvil::new().spawn();
2311
2312 let provider = RootProvider::<Ethereum>::connect(anvil.endpoint().as_str()).await;
2313
2314 match provider {
2315 Ok(provider) => {
2316 let num = provider.get_block_number().await.unwrap();
2317 assert_eq!(0, num);
2318 }
2319 Err(e) => {
2320 assert_eq!(
2321 format!("{e}"),
2322 "hyper not supported by BuiltinConnectionString. Please instantiate a hyper client manually"
2323 );
2324 }
2325 }
2326 }
2327
2328 #[tokio::test]
2329 async fn any_network_wallet_filler() {
2330 use alloy_serde::WithOtherFields;
2331 let anvil = Anvil::new().spawn();
2332 let signer: PrivateKeySigner =
2333 "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80".parse().unwrap();
2334 let wallet = EthereumWallet::from(signer);
2335
2336 let provider = ProviderBuilder::new()
2337 .network::<AnyNetwork>()
2338 .wallet(wallet)
2339 .connect_http(anvil.endpoint_url());
2340
2341 let tx = TransactionRequest::default()
2342 .with_to(address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"))
2343 .value(U256::from(325235));
2344
2345 let tx = WithOtherFields::new(tx);
2346
2347 let builder = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();
2348
2349 assert!(builder.status());
2350 }
2351
2352 #[tokio::test]
2353 async fn builtin_connect_boxed() {
2354 let anvil = Anvil::new().spawn();
2355
2356 let conn: BuiltInConnectionString = anvil.endpoint().parse().unwrap();
2357
2358 let transport = conn.connect_boxed().await.unwrap();
2359
2360 let client = alloy_rpc_client::RpcClient::new(transport, true);
2361
2362 let provider = RootProvider::<Ethereum>::new(client);
2363
2364 let num = provider.get_block_number().await.unwrap();
2365 assert_eq!(0, num);
2366 }
2367
2368 #[tokio::test]
2369 async fn test_uncle_count() {
2370 let provider = ProviderBuilder::new().connect_anvil();
2371
2372 let count = provider.get_uncle_count(0.into()).await.unwrap();
2373 assert_eq!(count, 0);
2374 }
2375
2376 #[tokio::test]
2377 #[cfg(any(
2378 feature = "reqwest-default-tls",
2379 feature = "reqwest-rustls-tls",
2380 feature = "reqwest-native-tls",
2381 ))]
2382 #[ignore = "ignore until <https://github.com/paradigmxyz/reth/pull/14727> is in"]
2383 async fn call_mainnet() {
2384 use alloy_network::TransactionBuilder;
2385 use alloy_sol_types::SolValue;
2386
2387 let url = "https://docs-demo.quiknode.pro/";
2388 let provider = ProviderBuilder::new().connect_http(url.parse().unwrap());
2389 let req = TransactionRequest::default()
2390 .with_to(address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")) .with_input(bytes!("06fdde03")); let result = provider.call(req.clone()).await.unwrap();
2393 assert_eq!(String::abi_decode(&result).unwrap(), "Wrapped Ether");
2394
2395 let result = provider.call(req).block(0.into()).await.unwrap();
2396 assert_eq!(result.to_string(), "0x");
2397 }
2398
2399 #[tokio::test]
2400 async fn call_many_mainnet() {
2401 use alloy_rpc_types_eth::{BlockOverrides, StateContext};
2402
2403 let url = "https://docs-demo.quiknode.pro/";
2404 let provider = ProviderBuilder::new().connect_http(url.parse().unwrap());
2405 let tx1 = TransactionRequest::default()
2406 .with_to(address!("6b175474e89094c44da98b954eedeac495271d0f"))
2407 .with_gas_limit(1000000)
2408 .with_gas_price(2023155498)
2409 .with_input(hex!("a9059cbb000000000000000000000000bc0E63965946815d105E7591407704e6e1964E590000000000000000000000000000000000000000000000000000000005f5e100"));
2410 let tx2 = TransactionRequest::default()
2411 .with_to(address!("833589fcd6edb6e08f4c7c32d4f71b54bda02913"))
2412 .with_gas_price(2023155498)
2413 .with_input(hex!(
2414 "70a08231000000000000000000000000bc0E63965946815d105E7591407704e6e1964E59"
2415 ));
2416
2417 let transactions = vec![tx1.clone(), tx2.clone()];
2418
2419 let block_override =
2420 BlockOverrides { number: Some(U256::from(12279785)), ..Default::default() };
2421
2422 let bundles = vec![Bundle { transactions, block_override: Some(block_override.clone()) }];
2423
2424 let context = StateContext {
2425 block_number: Some(BlockId::number(12279785)),
2426 transaction_index: Some(1.into()),
2427 };
2428
2429 let results = provider.call_many(&bundles).context(&context).await.unwrap();
2430
2431 let tx1_res = EthCallResponse {
2432 value: Some(
2433 hex!("0000000000000000000000000000000000000000000000000000000000000001").into(),
2434 ),
2435 error: None,
2436 };
2437 let tx2_res = EthCallResponse { value: Some(Bytes::new()), error: None };
2438 let expected = vec![vec![tx1_res.clone(), tx2_res.clone()]];
2439
2440 assert_eq!(results, expected);
2441
2442 let bundles = vec![
2444 Bundle {
2445 transactions: vec![tx1.clone()],
2446 block_override: Some(block_override.clone()),
2447 },
2448 Bundle {
2449 transactions: vec![tx2.clone()],
2450 block_override: Some(block_override.clone()),
2451 },
2452 ];
2453
2454 let results = provider.call_many(&bundles).context(&context).await.unwrap();
2455 let expected = vec![vec![tx1_res.clone()], vec![tx2_res.clone()]];
2456 assert_eq!(results, expected);
2457
2458 let b1 =
2460 vec![Bundle { transactions: vec![tx1], block_override: Some(block_override.clone()) }];
2461 let b2 = vec![Bundle { transactions: vec![tx2], block_override: Some(block_override) }];
2462
2463 let results = provider.call_many(&b1).context(&context).extend_bundles(&b2).await.unwrap();
2464 assert_eq!(results, expected);
2465 }
2466
2467 #[tokio::test]
2468 #[cfg(feature = "hyper-tls")]
2469 async fn hyper_https() {
2470 let url = "https://reth-ethereum.ithaca.xyz/rpc";
2471
2472 let provider = ProviderBuilder::new().connect(url).await.unwrap();
2475
2476 let _num = provider.get_block_number().await.unwrap();
2477 }
2478
2479 #[tokio::test]
2480 async fn test_empty_transactions() {
2481 let provider = ProviderBuilder::new().connect_anvil();
2482
2483 let block = provider.get_block_by_number(0.into()).await.unwrap().unwrap();
2484 assert!(block.transactions.is_hashes());
2485 }
2486
2487 #[tokio::test]
2488 async fn disable_test() {
2489 let provider = ProviderBuilder::new()
2490 .disable_recommended_fillers()
2491 .with_cached_nonce_management()
2492 .connect_anvil();
2493
2494 let tx = TransactionRequest::default()
2495 .with_kind(alloy_primitives::TxKind::Create)
2496 .value(U256::from(1235))
2497 .with_input(Bytes::from_str("ffffffffffffff").unwrap());
2498
2499 let err = provider.send_transaction(tx).await.unwrap_err().to_string();
2500 assert!(err.contains("missing properties: [(\"NonceManager\", [\"from\"])]"));
2501 }
2502
2503 #[tokio::test]
2504 async fn capture_anvil_logs() {
2505 let mut anvil = Anvil::new().keep_stdout().spawn();
2506
2507 let provider = ProviderBuilder::new().connect_http(anvil.endpoint_url());
2508
2509 let tx = TransactionRequest::default()
2510 .with_from(address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"))
2511 .with_to(address!("70997970C51812dc3A010C7d01b50e0d17dc79C8"))
2512 .value(U256::from(100));
2513
2514 let _ = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();
2515
2516 anvil.child_mut().kill().unwrap();
2517
2518 let mut output = String::new();
2519 anvil.child_mut().stdout.take().unwrap().read_to_string(&mut output).unwrap();
2520
2521 assert_eq!(anvil.chain_id(), 31337);
2522 assert_eq!(anvil.addresses().len(), 10);
2523 assert_eq!(anvil.keys().len(), 10);
2524
2525 assert!(output.contains("eth_sendTransaction"));
2526 assert!(output.contains("Block Number: 1"))
2527 }
2528
2529 #[tokio::test]
2530 async fn custom_estimator() {
2531 let provider = ProviderBuilder::new()
2532 .disable_recommended_fillers()
2533 .with_cached_nonce_management()
2534 .connect_anvil();
2535
2536 let _ = provider
2537 .estimate_eip1559_fees_with(Eip1559Estimator::new(|_fee, _rewards| Eip1559Estimation {
2538 max_fee_per_gas: 0,
2539 max_priority_fee_per_gas: 0,
2540 }))
2541 .await;
2542 }
2543
2544 #[tokio::test]
2545 #[cfg(not(windows))]
2546 async fn eth_sign_transaction() {
2547 async_ci_only(|| async {
2548 run_with_tempdir("reth-sign-tx", |dir| async {
2549 let reth = Reth::new().dev().disable_discovery().data_dir(dir).spawn();
2550 let provider = ProviderBuilder::new().connect_http(reth.endpoint_url());
2551
2552 let accounts = provider.get_accounts().await.unwrap();
2553 let from = accounts[0];
2554
2555 let tx = TransactionRequest::default()
2556 .from(from)
2557 .to(Address::random())
2558 .value(U256::from(100))
2559 .gas_limit(21000);
2560
2561 let signed_tx = provider.sign_transaction(tx).await.unwrap().to_vec();
2562
2563 let tx = TxEnvelope::decode(&mut signed_tx.as_slice()).unwrap();
2564
2565 let signer = tx.recover_signer().unwrap();
2566
2567 assert_eq!(signer, from);
2568 })
2569 .await
2570 })
2571 .await;
2572 }
2573
2574 #[cfg(feature = "throttle")]
2575 use alloy_transport::layers::ThrottleLayer;
2576
2577 #[cfg(feature = "throttle")]
2578 #[tokio::test]
2579 async fn test_throttled_provider() {
2580 let request_per_second = 10;
2581 let throttle_layer = ThrottleLayer::new(request_per_second);
2582
2583 let anvil = Anvil::new().spawn();
2584 let client = RpcClient::builder().layer(throttle_layer).http(anvil.endpoint_url());
2585 let provider = RootProvider::<Ethereum>::new(client);
2586
2587 let num_requests = 10;
2588 let start = std::time::Instant::now();
2589 for _ in 0..num_requests {
2590 provider.get_block_number().await.unwrap();
2591 }
2592
2593 let elapsed = start.elapsed();
2594 assert_eq!(elapsed.as_secs_f64().round() as u32, 1);
2595 }
2596
2597 #[tokio::test]
2598 #[cfg(feature = "hyper")]
2599 async fn test_connect_hyper_tls() {
2600 let p =
2601 ProviderBuilder::new().connect("https://reth-ethereum.ithaca.xyz/rpc").await.unwrap();
2602
2603 let _num = p.get_block_number().await.unwrap();
2604
2605 let anvil = Anvil::new().spawn();
2606 let p = ProviderBuilder::new().connect(&anvil.endpoint()).await.unwrap();
2607
2608 let _num = p.get_block_number().await.unwrap();
2609 }
2610
2611 #[tokio::test]
2612 async fn test_send_transaction_sync() {
2613 use alloy_network::TransactionBuilder;
2614 use alloy_primitives::{address, U256};
2615
2616 let anvil = Anvil::new().spawn();
2617 let provider = ProviderBuilder::new().connect_http(anvil.endpoint_url());
2618
2619 let tx = TransactionRequest::default()
2620 .with_from(address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"))
2621 .with_to(address!("70997970C51812dc3A010C7d01b50e0d17dc79C8"))
2622 .with_value(U256::from(100));
2623
2624 let receipt = provider.send_transaction_sync(tx).await.unwrap();
2626
2627 let tx_hash = receipt.transaction_hash;
2629 assert!(!tx_hash.is_zero());
2630 assert_eq!(receipt.transaction_hash, tx_hash);
2631 assert!(receipt.status());
2632 }
2633
2634 #[tokio::test]
2635 async fn test_send_transaction_sync_with_fillers() {
2636 use alloy_network::TransactionBuilder;
2637 use alloy_primitives::{address, U256};
2638
2639 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
2640
2641 let tx = TransactionRequest::default()
2643 .with_from(provider.default_signer_address())
2644 .with_to(address!("70997970C51812dc3A010C7d01b50e0d17dc79C8"))
2645 .with_value(U256::from(100));
2646 let receipt = provider.send_transaction_sync(tx).await.unwrap();
2650
2651 let tx_hash = receipt.transaction_hash;
2653 assert!(!tx_hash.is_zero());
2654
2655 assert_eq!(receipt.transaction_hash, tx_hash);
2657 assert!(receipt.status());
2658 assert!(receipt.gas_used() > 0, "fillers should have estimated gas");
2659 }
2660
2661 #[tokio::test]
2662 async fn test_fill_transaction() {
2663 use alloy_network::TransactionBuilder;
2664 use alloy_primitives::{address, U256};
2665
2666 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
2667
2668 let tx = TransactionRequest::default()
2669 .with_from(provider.default_signer_address())
2670 .with_to(address!("70997970C51812dc3A010C7d01b50e0d17dc79C8"))
2671 .with_value(U256::from(100));
2672
2673 let filled = provider.fill_transaction(tx).await.unwrap();
2674
2675 assert!(!filled.raw.is_empty(), "raw transaction bytes should not be empty");
2677
2678 let filled_tx = &filled.tx;
2680 assert!(filled_tx.to().is_some(), "filled transaction should have to address");
2681 assert!(filled_tx.gas_limit() > 0, "filled transaction should have gas limit");
2682 assert!(filled_tx.max_fee_per_gas() > 0, "filled transaction should have max fee per gas");
2683 }
2684}