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, Filter, FilterChanges, Index, Log, SyncStatus,
34};
35use alloy_transport::TransportResult;
36use serde_json::value::RawValue;
37use std::borrow::Cow;
38
39pub type FilterPollerBuilder<R> = PollerBuilder<(U256,), Vec<R>>;
43
44#[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 fn root(&self) -> &RootProvider<N>;
75
76 fn builder() -> ProviderBuilder<Identity, Identity, N>
78 where
79 Self: Sized,
80 {
81 ProviderBuilder::default()
82 }
83
84 #[inline]
88 fn client(&self) -> ClientRef<'_> {
89 self.root().client()
90 }
91
92 #[inline]
96 fn weak_client(&self) -> WeakClient {
97 self.root().weak_client()
98 }
99
100 #[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 fn get_accounts(&self) -> ProviderCall<NoParams, Vec<Address>> {
124 self.client().request_noparams("eth_accounts").into()
125 }
126
127 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 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 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 #[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 #[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 #[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 #[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 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 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 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 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 let base_fee_per_gas = match fee_history.latest_block_base_fee() {
290 Some(base_fee) if base_fee != 0 => base_fee,
291 _ => {
292 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 async fn estimate_eip1559_fees(&self) -> TransportResult<Eip1559Estimation> {
311 self.estimate_eip1559_fees_with(Eip1559Estimator::default()).await
312 }
313
314 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 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 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 fn get_account(&self, address: Address) -> RpcWithBlock<Address, alloy_consensus::Account> {
351 self.client().request("eth_getAccount", address).into()
352 }
353
354 fn get_balance(&self, address: Address) -> RpcWithBlock<Address, U256, U256> {
358 self.client().request("eth_getBalance", address).into()
359 }
360
361 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 fn get_block_by_hash(&self, hash: BlockHash) -> EthGetBlock<N::BlockResponse> {
403 EthGetBlock::by_hash(hash, self.client())
404 }
405
406 fn get_block_by_number(&self, number: BlockNumberOrTag) -> EthGetBlock<N::BlockResponse> {
431 EthGetBlock::by_number(number, self.client())
432 }
433
434 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 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 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 fn get_code_at(&self, address: Address) -> RpcWithBlock<Address, Bytes> {
466 self.client().request("eth_getCode", address).into()
467 }
468
469 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 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 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 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 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 #[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 async fn get_filter_changes_dyn(&self, id: U256) -> TransportResult<FilterChanges> {
636 self.client().request("eth_getFilterChanges", (id,)).await
637 }
638
639 async fn get_filter_logs(&self, id: U256) -> TransportResult<Vec<Log>> {
641 self.client().request("eth_getFilterLogs", (id,)).await
642 }
643
644 async fn uninstall_filter(&self, id: U256) -> TransportResult<bool> {
646 self.client().request("eth_uninstallFilter", (id,)).await
647 }
648
649 #[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 async fn get_logs(&self, filter: &Filter) -> TransportResult<Vec<Log>> {
663 self.client().request("eth_getLogs", (filter,)).await
664 }
665
666 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 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 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 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 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 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 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 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 fn get_raw_transaction_by_hash(&self, hash: TxHash) -> ProviderCall<(TxHash,), Option<Bytes>> {
760 self.client().request("eth_getRawTransactionByHash", (hash,)).into()
761 }
762
763 #[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 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 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 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 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 async fn new_block_filter(&self) -> TransportResult<U256> {
829 self.client().request_noparams("eth_newBlockFilter").await
830 }
831
832 async fn new_filter(&self, filter: &Filter) -> TransportResult<U256> {
838 self.client().request("eth_newFilter", (filter,)).await
839 }
840
841 async fn new_pending_transactions_filter(&self, full: bool) -> TransportResult<U256> {
851 let param = if full { &[true][..] } else { &[] };
853 self.client().request("eth_newPendingTransactionFilter", param).await
854 }
855
856 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 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 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 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 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 #[doc(hidden)]
980 async fn send_transaction_internal(
981 &self,
982 tx: SendableTx<N>,
983 ) -> TransportResult<PendingTransactionBuilder<N>> {
984 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 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 #[doc(hidden)]
1058 async fn send_transaction_sync_internal(
1059 &self,
1060 tx: SendableTx<N>,
1061 ) -> TransportResult<N::ReceiptResponse> {
1062 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 async fn sign_transaction(&self, tx: N::TransactionRequest) -> TransportResult<Bytes> {
1084 self.client().request("eth_signTransaction", (tx,)).await
1085 }
1086
1087 #[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 #[cfg(feature = "pubsub")]
1142 fn subscribe_full_blocks(&self) -> SubFullBlocks<N> {
1143 SubFullBlocks::new(self.subscribe_blocks(), self.weak_client())
1144 }
1145
1146 #[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 #[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 #[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 #[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 #[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 #[cfg(feature = "pubsub")]
1305 async fn unsubscribe(&self, id: B256) -> TransportResult<()> {
1306 self.root().unsubscribe(id)
1307 }
1308
1309 fn syncing(&self) -> ProviderCall<NoParams, SyncStatus> {
1311 self.client().request_noparams("eth_syncing").into()
1312 }
1313
1314 #[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 #[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 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 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, ¶ms).await
1365 }
1366
1367 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 #[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 if config.required_confirmations() <= 1 {
1431 return Ok(PendingTransaction::ready(*config.tx_hash()));
1432 }
1433 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 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)] 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 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])) .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 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 #[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 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 let tx_envelope = tx.build(&provider.wallet()).await.expect("failed to build tx");
1817
1818 let encoded = tx_envelope.encoded_2718();
1820
1821 let receipt =
1823 provider.send_raw_transaction_sync(&encoded).await.expect("failed to send raw tx sync");
1824
1825 assert_eq!(receipt.to(), Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045")));
1827 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 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 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 let watch = builder.watch();
1870 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 let count = provider.get_transaction_count(sender).await.unwrap();
1926 assert_eq!(count, 0);
1927
1928 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 let count = provider.get_transaction_count(sender).await.unwrap();
1941 assert_eq!(count, 1);
1942
1943 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 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")) .with_input(bytes!("06fdde03")); 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 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 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 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 let receipt = provider.send_transaction_sync(tx).await.unwrap();
2476
2477 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 let tx = TransactionRequest::default()
2493 .with_from(provider.default_signer_address())
2494 .with_to(address!("70997970C51812dc3A010C7d01b50e0d17dc79C8"))
2495 .with_value(U256::from(100));
2496 let receipt = provider.send_transaction_sync(tx).await.unwrap();
2500
2501 let tx_hash = receipt.transaction_hash;
2503 assert!(!tx_hash.is_zero());
2504
2505 assert_eq!(receipt.transaction_hash, tx_hash);
2507 assert!(receipt.status());
2508 assert!(receipt.gas_used() > 0, "fillers should have estimated gas");
2509 }
2510}