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, 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))]
71#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
72#[auto_impl::auto_impl(&, &mut, Rc, Arc, Box)]
73pub trait Provider<N: Network = Ethereum>: Send + Sync {
74 fn root(&self) -> &RootProvider<N>;
76
77 fn builder() -> ProviderBuilder<Identity, Identity, N>
79 where
80 Self: Sized,
81 {
82 ProviderBuilder::default()
83 }
84
85 #[inline]
89 fn client(&self) -> ClientRef<'_> {
90 self.root().client()
91 }
92
93 #[inline]
97 fn weak_client(&self) -> WeakClient {
98 self.root().weak_client()
99 }
100
101 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
114 #[doc(alias = "boxed")]
115 fn erased(self) -> DynProvider<N>
116 where
117 Self: Sized + 'static,
118 {
119 DynProvider::new(self)
120 }
121
122 fn get_accounts(&self) -> ProviderCall<NoParams, Vec<Address>> {
125 self.client().request_noparams("eth_accounts").into()
126 }
127
128 fn get_blob_base_fee(&self) -> ProviderCall<NoParams, U128, u128> {
130 self.client()
131 .request_noparams("eth_blobBaseFee")
132 .map_resp(utils::convert_u128 as fn(U128) -> u128)
133 .into()
134 }
135
136 fn get_block_number(&self) -> ProviderCall<NoParams, U64, BlockNumber> {
138 self.client()
139 .request_noparams("eth_blockNumber")
140 .map_resp(utils::convert_u64 as fn(U64) -> u64)
141 .into()
142 }
143
144 async fn get_block_number_by_id(
149 &self,
150 block_id: BlockId,
151 ) -> TransportResult<Option<BlockNumber>> {
152 match block_id {
153 BlockId::Number(BlockNumberOrTag::Number(num)) => Ok(Some(num)),
154 BlockId::Number(BlockNumberOrTag::Latest) => self.get_block_number().await.map(Some),
155 _ => {
156 let block = self.get_block(block_id).await?;
157 Ok(block.map(|b| b.header().number()))
158 }
159 }
160 }
161
162 #[doc(alias = "eth_call")]
190 #[doc(alias = "call_with_overrides")]
191 fn call(&self, tx: N::TransactionRequest) -> EthCall<N, Bytes> {
192 EthCall::call(self.weak_client(), tx).block(BlockNumberOrTag::Pending.into())
193 }
194
195 #[doc(alias = "eth_callMany")]
204 fn call_many<'req>(
205 &self,
206 bundles: &'req [Bundle],
207 ) -> EthCallMany<'req, N, Vec<Vec<EthCallResponse>>> {
208 EthCallMany::new(self.weak_client(), bundles)
209 }
210
211 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
217 fn multicall(&self) -> MulticallBuilder<Empty, &Self, N>
218 where
219 Self: Sized,
220 {
221 MulticallBuilder::new(self)
222 }
223
224 #[doc(alias = "eth_simulateV1")]
228 fn simulate<'req>(
229 &self,
230 payload: &'req SimulatePayload,
231 ) -> RpcWithBlock<&'req SimulatePayload, Vec<SimulatedBlock<N::BlockResponse>>> {
232 self.client().request("eth_simulateV1", payload).into()
233 }
234
235 fn get_chain_id(&self) -> ProviderCall<NoParams, U64, u64> {
237 self.client()
238 .request_noparams("eth_chainId")
239 .map_resp(utils::convert_u64 as fn(U64) -> u64)
240 .into()
241 }
242
243 fn create_access_list<'a>(
247 &self,
248 request: &'a N::TransactionRequest,
249 ) -> RpcWithBlock<&'a N::TransactionRequest, AccessListResult> {
250 self.client().request("eth_createAccessList", request).into()
251 }
252
253 fn estimate_gas(&self, tx: N::TransactionRequest) -> EthCall<N, U64, u64> {
267 EthCall::gas_estimate(self.weak_client(), tx)
268 .block(BlockNumberOrTag::Pending.into())
269 .map_resp(utils::convert_u64)
270 }
271
272 async fn estimate_eip1559_fees_with(
279 &self,
280 estimator: Eip1559Estimator,
281 ) -> TransportResult<Eip1559Estimation> {
282 let fee_history = self
283 .get_fee_history(
284 utils::EIP1559_FEE_ESTIMATION_PAST_BLOCKS,
285 BlockNumberOrTag::Latest,
286 &[utils::EIP1559_FEE_ESTIMATION_REWARD_PERCENTILE],
287 )
288 .await?;
289
290 let base_fee_per_gas = match fee_history.latest_block_base_fee() {
293 Some(base_fee) if base_fee != 0 => base_fee,
294 _ => {
295 self.get_block_by_number(BlockNumberOrTag::Latest)
297 .await?
298 .ok_or(RpcError::NullResp)?
299 .header()
300 .as_ref()
301 .base_fee_per_gas()
302 .ok_or(RpcError::UnsupportedFeature("eip1559"))?
303 .into()
304 }
305 };
306
307 Ok(estimator.estimate(base_fee_per_gas, &fee_history.reward.unwrap_or_default()))
308 }
309
310 async fn estimate_eip1559_fees(&self) -> TransportResult<Eip1559Estimation> {
316 self.estimate_eip1559_fees_with(Eip1559Estimator::default()).await
317 }
318
319 async fn get_fee_history(
325 &self,
326 block_count: u64,
327 last_block: BlockNumberOrTag,
328 reward_percentiles: &[f64],
329 ) -> TransportResult<FeeHistory> {
330 self.client()
331 .request("eth_feeHistory", (U64::from(block_count), last_block, reward_percentiles))
332 .await
333 }
334
335 fn get_gas_price(&self) -> ProviderCall<NoParams, U128, u128> {
337 self.client()
338 .request_noparams("eth_gasPrice")
339 .map_resp(utils::convert_u128 as fn(U128) -> u128)
340 .into()
341 }
342
343 fn get_account_info(
349 &self,
350 address: Address,
351 ) -> RpcWithBlock<Address, alloy_rpc_types_eth::AccountInfo> {
352 self.client().request("eth_getAccountInfo", address).into()
353 }
354
355 fn get_account(&self, address: Address) -> RpcWithBlock<Address, alloy_consensus::TrieAccount> {
358 self.client().request("eth_getAccount", address).into()
359 }
360
361 fn get_balance(&self, address: Address) -> RpcWithBlock<Address, U256, U256> {
365 self.client().request("eth_getBalance", address).into()
366 }
367
368 fn get_block(&self, block: BlockId) -> EthGetBlock<N::BlockResponse> {
379 match block {
380 BlockId::Hash(hash) => EthGetBlock::by_hash(hash.block_hash, self.client()),
381 BlockId::Number(number) => EthGetBlock::by_number(number, self.client()),
382 }
383 }
384
385 fn get_block_by_hash(&self, hash: BlockHash) -> EthGetBlock<N::BlockResponse> {
410 EthGetBlock::by_hash(hash, self.client())
411 }
412
413 fn get_block_by_number(&self, number: BlockNumberOrTag) -> EthGetBlock<N::BlockResponse> {
438 EthGetBlock::by_number(number, self.client())
439 }
440
441 async fn get_block_transaction_count_by_hash(
443 &self,
444 hash: BlockHash,
445 ) -> TransportResult<Option<u64>> {
446 self.client()
447 .request("eth_getBlockTransactionCountByHash", (hash,))
448 .await
449 .map(|opt_count: Option<U64>| opt_count.map(|count| count.to::<u64>()))
450 }
451
452 async fn get_block_transaction_count_by_number(
454 &self,
455 block_number: BlockNumberOrTag,
456 ) -> TransportResult<Option<u64>> {
457 self.client()
458 .request("eth_getBlockTransactionCountByNumber", (block_number,))
459 .await
460 .map(|opt_count: Option<U64>| opt_count.map(|count| count.to::<u64>()))
461 }
462
463 fn get_block_receipts(
465 &self,
466 block: BlockId,
467 ) -> ProviderCall<(BlockId,), Option<Vec<N::ReceiptResponse>>> {
468 self.client().request("eth_getBlockReceipts", (block,)).into()
469 }
470
471 fn get_code_at(&self, address: Address) -> RpcWithBlock<Address, Bytes> {
473 self.client().request("eth_getCode", address).into()
474 }
475
476 async fn watch_blocks(&self) -> TransportResult<FilterPollerBuilder<B256>> {
499 let id = self.new_block_filter().await?;
500 Ok(PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,)))
501 }
502
503 async fn watch_full_blocks(&self) -> TransportResult<WatchBlocks<N::BlockResponse>> {
527 let id = self.new_block_filter().await?;
528 let poller = PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,));
529
530 Ok(WatchBlocks::new(poller))
531 }
532
533 async fn watch_pending_transactions(&self) -> TransportResult<FilterPollerBuilder<B256>> {
556 let id = self.new_pending_transactions_filter(false).await?;
557 Ok(PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,)))
558 }
559
560 async fn watch_logs(&self, filter: &Filter) -> TransportResult<FilterPollerBuilder<Log>> {
589 let id = self.new_filter(filter).await?;
590 Ok(PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,)))
591 }
592
593 async fn watch_full_pending_transactions(
620 &self,
621 ) -> TransportResult<FilterPollerBuilder<N::TransactionResponse>> {
622 let id = self.new_pending_transactions_filter(true).await?;
623 Ok(PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,)))
624 }
625
626 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
631 async fn get_filter_changes<R: RpcRecv>(&self, id: U256) -> TransportResult<Vec<R>>
632 where
633 Self: Sized,
634 {
635 self.client().request("eth_getFilterChanges", (id,)).await
636 }
637
638 async fn get_filter_changes_dyn(&self, id: U256) -> TransportResult<FilterChanges> {
643 self.client().request("eth_getFilterChanges", (id,)).await
644 }
645
646 async fn get_filter_logs(&self, id: U256) -> TransportResult<Vec<Log>> {
648 self.client().request("eth_getFilterLogs", (id,)).await
649 }
650
651 async fn uninstall_filter(&self, id: U256) -> TransportResult<bool> {
653 self.client().request("eth_uninstallFilter", (id,)).await
654 }
655
656 #[inline]
661 async fn watch_pending_transaction(
662 &self,
663 config: PendingTransactionConfig,
664 ) -> Result<PendingTransaction, PendingTransactionError> {
665 self.root().watch_pending_transaction(config).await
666 }
667
668 async fn get_logs(&self, filter: &Filter) -> TransportResult<Vec<Log>> {
670 self.client().request("eth_getLogs", (filter,)).await
671 }
672
673 fn get_proof(
677 &self,
678 address: Address,
679 keys: Vec<StorageKey>,
680 ) -> RpcWithBlock<(Address, Vec<StorageKey>), EIP1186AccountProofResponse> {
681 self.client().request("eth_getProof", (address, keys)).into()
682 }
683
684 fn get_storage_at(
686 &self,
687 address: Address,
688 key: U256,
689 ) -> RpcWithBlock<(Address, U256), StorageValue> {
690 self.client().request("eth_getStorageAt", (address, key)).into()
691 }
692
693 fn get_transaction_by_sender_nonce(
697 &self,
698 sender: Address,
699 nonce: u64,
700 ) -> ProviderCall<(Address, U64), Option<N::TransactionResponse>> {
701 self.client()
702 .request("eth_getTransactionBySenderAndNonce", (sender, U64::from(nonce)))
703 .into()
704 }
705
706 fn get_transaction_by_hash(
708 &self,
709 hash: TxHash,
710 ) -> ProviderCall<(TxHash,), Option<N::TransactionResponse>> {
711 self.client().request("eth_getTransactionByHash", (hash,)).into()
712 }
713
714 fn get_transaction_by_block_hash_and_index(
716 &self,
717 block_hash: B256,
718 index: usize,
719 ) -> ProviderCall<(B256, Index), Option<N::TransactionResponse>> {
720 self.client()
721 .request("eth_getTransactionByBlockHashAndIndex", (block_hash, Index(index)))
722 .into()
723 }
724
725 fn get_raw_transaction_by_block_hash_and_index(
727 &self,
728 block_hash: B256,
729 index: usize,
730 ) -> ProviderCall<(B256, Index), Option<Bytes>> {
731 self.client()
732 .request("eth_getRawTransactionByBlockHashAndIndex", (block_hash, Index(index)))
733 .into()
734 }
735
736 fn get_transaction_by_block_number_and_index(
738 &self,
739 block_number: BlockNumberOrTag,
740 index: usize,
741 ) -> ProviderCall<(BlockNumberOrTag, Index), Option<N::TransactionResponse>> {
742 self.client()
743 .request("eth_getTransactionByBlockNumberAndIndex", (block_number, Index(index)))
744 .into()
745 }
746
747 fn get_raw_transaction_by_block_number_and_index(
749 &self,
750 block_number: BlockNumberOrTag,
751 index: usize,
752 ) -> ProviderCall<(BlockNumberOrTag, Index), Option<Bytes>> {
753 self.client()
754 .request("eth_getRawTransactionByBlockNumberAndIndex", (block_number, Index(index)))
755 .into()
756 }
757
758 fn get_raw_transaction_by_hash(&self, hash: TxHash) -> ProviderCall<(TxHash,), Option<Bytes>> {
770 self.client().request("eth_getRawTransactionByHash", (hash,)).into()
771 }
772
773 #[doc(alias = "get_nonce")]
775 #[doc(alias = "get_account_nonce")]
776 fn get_transaction_count(
777 &self,
778 address: Address,
779 ) -> RpcWithBlock<Address, U64, u64, fn(U64) -> u64> {
780 self.client()
781 .request("eth_getTransactionCount", address)
782 .map_resp(utils::convert_u64 as fn(U64) -> u64)
783 .into()
784 }
785
786 fn get_transaction_receipt(
788 &self,
789 hash: TxHash,
790 ) -> ProviderCall<(TxHash,), Option<N::ReceiptResponse>> {
791 self.client().request("eth_getTransactionReceipt", (hash,)).into()
792 }
793
794 async fn get_uncle(&self, tag: BlockId, idx: u64) -> TransportResult<Option<N::BlockResponse>> {
796 let idx = U64::from(idx);
797 match tag {
798 BlockId::Hash(hash) => {
799 self.client()
800 .request("eth_getUncleByBlockHashAndIndex", (hash.block_hash, idx))
801 .await
802 }
803 BlockId::Number(number) => {
804 self.client().request("eth_getUncleByBlockNumberAndIndex", (number, idx)).await
805 }
806 }
807 }
808
809 async fn get_uncle_count(&self, tag: BlockId) -> TransportResult<u64> {
811 match tag {
812 BlockId::Hash(hash) => self
813 .client()
814 .request("eth_getUncleCountByBlockHash", (hash.block_hash,))
815 .await
816 .map(|count: U64| count.to::<u64>()),
817 BlockId::Number(number) => self
818 .client()
819 .request("eth_getUncleCountByBlockNumber", (number,))
820 .await
821 .map(|count: U64| count.to::<u64>()),
822 }
823 }
824
825 fn get_max_priority_fee_per_gas(&self) -> ProviderCall<NoParams, U128, u128> {
827 self.client()
828 .request_noparams("eth_maxPriorityFeePerGas")
829 .map_resp(utils::convert_u128 as fn(U128) -> u128)
830 .into()
831 }
832
833 async fn new_block_filter(&self) -> TransportResult<U256> {
839 self.client().request_noparams("eth_newBlockFilter").await
840 }
841
842 async fn new_filter(&self, filter: &Filter) -> TransportResult<U256> {
848 self.client().request("eth_newFilter", (filter,)).await
849 }
850
851 async fn new_pending_transactions_filter(&self, full: bool) -> TransportResult<U256> {
861 let param = if full { &[true][..] } else { &[] };
863 self.client().request("eth_newPendingTransactionFilter", param).await
864 }
865
866 async fn send_raw_transaction(
870 &self,
871 encoded_tx: &[u8],
872 ) -> TransportResult<PendingTransactionBuilder<N>> {
873 let rlp_hex = hex::encode_prefixed(encoded_tx);
874 let tx_hash = self.client().request("eth_sendRawTransaction", (rlp_hex,)).await?;
875 Ok(PendingTransactionBuilder::new(self.root().clone(), tx_hash))
876 }
877
878 async fn send_raw_transaction_sync(
916 &self,
917 encoded_tx: &[u8],
918 ) -> TransportResult<N::ReceiptResponse> {
919 let rlp_hex = hex::encode_prefixed(encoded_tx);
920 self.client().request("eth_sendRawTransactionSync", (rlp_hex,)).await
921 }
922
923 async fn send_raw_transaction_conditional(
934 &self,
935 encoded_tx: &[u8],
936 conditional: TransactionConditional,
937 ) -> TransportResult<PendingTransactionBuilder<N>> {
938 let rlp_hex = hex::encode_prefixed(encoded_tx);
939 let tx_hash = self
940 .client()
941 .request("eth_sendRawTransactionConditional", (rlp_hex, conditional))
942 .await?;
943 Ok(PendingTransactionBuilder::new(self.root().clone(), tx_hash))
944 }
945
946 async fn send_transaction(
967 &self,
968 tx: N::TransactionRequest,
969 ) -> TransportResult<PendingTransactionBuilder<N>> {
970 self.send_transaction_internal(SendableTx::Builder(tx)).await
971 }
972
973 async fn send_tx_envelope(
978 &self,
979 tx: N::TxEnvelope,
980 ) -> TransportResult<PendingTransactionBuilder<N>> {
981 self.send_transaction_internal(SendableTx::Envelope(tx)).await
982 }
983
984 #[doc(hidden)]
991 async fn send_transaction_internal(
992 &self,
993 tx: SendableTx<N>,
994 ) -> TransportResult<PendingTransactionBuilder<N>> {
995 let _handle = self.root().get_heart();
998
999 match tx {
1000 SendableTx::Builder(mut tx) => {
1001 alloy_network::TransactionBuilder::prep_for_submission(&mut tx);
1002 let tx_hash = self.client().request("eth_sendTransaction", (tx,)).await?;
1003 Ok(PendingTransactionBuilder::new(self.root().clone(), tx_hash))
1004 }
1005 SendableTx::Envelope(tx) => {
1006 let encoded_tx = tx.encoded_2718();
1007 self.send_raw_transaction(&encoded_tx).await
1008 }
1009 }
1010 }
1011
1012 async fn send_transaction_sync(
1052 &self,
1053 tx: N::TransactionRequest,
1054 ) -> TransportResult<N::ReceiptResponse> {
1055 self.send_transaction_sync_internal(SendableTx::Builder(tx)).await
1056 }
1057
1058 #[doc(hidden)]
1068 async fn send_transaction_sync_internal(
1069 &self,
1070 tx: SendableTx<N>,
1071 ) -> TransportResult<N::ReceiptResponse> {
1072 let _handle = self.root().get_heart();
1075
1076 match tx {
1077 SendableTx::Builder(mut tx) => {
1078 alloy_network::TransactionBuilder::prep_for_submission(&mut tx);
1079 let receipt = self.client().request("eth_sendTransactionSync", (tx,)).await?;
1080 Ok(receipt)
1081 }
1082 SendableTx::Envelope(tx) => {
1083 let encoded_tx = tx.encoded_2718();
1084 self.send_raw_transaction_sync(&encoded_tx).await
1085 }
1086 }
1087 }
1088
1089 async fn sign_transaction(&self, tx: N::TransactionRequest) -> TransportResult<Bytes> {
1094 self.client().request("eth_signTransaction", (tx,)).await
1095 }
1096
1097 async fn fill_transaction(
1103 &self,
1104 tx: N::TransactionRequest,
1105 ) -> TransportResult<FillTransaction<N::TxEnvelope>>
1106 where
1107 N::TxEnvelope: RpcRecv,
1108 {
1109 self.client().request("eth_fillTransaction", (tx,)).await
1110 }
1111
1112 #[cfg(feature = "pubsub")]
1138 fn subscribe_blocks(&self) -> GetSubscription<(SubscriptionKind,), N::HeaderResponse> {
1139 let rpc_call = self.client().request("eth_subscribe", (SubscriptionKind::NewHeads,));
1140 GetSubscription::new(self.weak_client(), rpc_call)
1141 }
1142
1143 #[cfg(feature = "pubsub")]
1167 fn subscribe_full_blocks(&self) -> SubFullBlocks<N> {
1168 SubFullBlocks::new(self.subscribe_blocks(), self.weak_client())
1169 }
1170
1171 #[cfg(feature = "pubsub")]
1197 fn subscribe_pending_transactions(&self) -> GetSubscription<(SubscriptionKind,), B256> {
1198 let rpc_call =
1199 self.client().request("eth_subscribe", (SubscriptionKind::NewPendingTransactions,));
1200 GetSubscription::new(self.weak_client(), rpc_call)
1201 }
1202
1203 #[cfg(feature = "pubsub")]
1234 fn subscribe_full_pending_transactions(
1235 &self,
1236 ) -> GetSubscription<(SubscriptionKind, Params), N::TransactionResponse> {
1237 let rpc_call = self.client().request(
1238 "eth_subscribe",
1239 (SubscriptionKind::NewPendingTransactions, Params::Bool(true)),
1240 );
1241 GetSubscription::new(self.weak_client(), rpc_call)
1242 }
1243
1244 #[cfg(feature = "pubsub")]
1275 fn subscribe_logs(&self, filter: &Filter) -> GetSubscription<(SubscriptionKind, Params), Log> {
1276 let rpc_call = self.client().request(
1277 "eth_subscribe",
1278 (SubscriptionKind::Logs, Params::Logs(Box::new(filter.clone()))),
1279 );
1280 GetSubscription::new(self.weak_client(), rpc_call)
1281 }
1282
1283 #[cfg(feature = "pubsub")]
1285 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
1286 fn subscribe<P, R>(&self, params: P) -> GetSubscription<P, R>
1287 where
1288 P: RpcSend,
1289 R: RpcRecv,
1290 Self: Sized,
1291 {
1292 let rpc_call = self.client().request("eth_subscribe", params);
1293 GetSubscription::new(self.weak_client(), rpc_call)
1294 }
1295
1296 #[cfg(feature = "pubsub")]
1317 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
1318 fn subscribe_to<R>(&self, method: &'static str) -> GetSubscription<NoParams, R>
1319 where
1320 R: RpcRecv,
1321 Self: Sized,
1322 {
1323 let mut rpc_call = self.client().request_noparams(method);
1324 rpc_call.set_is_subscription();
1325 GetSubscription::new(self.weak_client(), rpc_call)
1326 }
1327
1328 #[cfg(feature = "pubsub")]
1330 async fn unsubscribe(&self, id: B256) -> TransportResult<()> {
1331 self.root().unsubscribe(id)
1332 }
1333
1334 fn syncing(&self) -> ProviderCall<NoParams, SyncStatus> {
1336 self.client().request_noparams("eth_syncing").into()
1337 }
1338
1339 #[doc(alias = "web3_client_version")]
1341 fn get_client_version(&self) -> ProviderCall<NoParams, String> {
1342 self.client().request_noparams("web3_clientVersion").into()
1343 }
1344
1345 #[doc(alias = "web3_sha3")]
1347 fn get_sha3(&self, data: &[u8]) -> ProviderCall<(String,), B256> {
1348 self.client().request("web3_sha3", (hex::encode_prefixed(data),)).into()
1349 }
1350
1351 fn get_net_version(&self) -> ProviderCall<NoParams, U64, u64> {
1353 self.client()
1354 .request_noparams("net_version")
1355 .map_resp(utils::convert_u64 as fn(U64) -> u64)
1356 .into()
1357 }
1358
1359 async fn raw_request<P, R>(&self, method: Cow<'static, str>, params: P) -> TransportResult<R>
1384 where
1385 P: RpcSend,
1386 R: RpcRecv,
1387 Self: Sized,
1388 {
1389 self.client().request(method, ¶ms).await
1390 }
1391
1392 async fn raw_request_dyn(
1415 &self,
1416 method: Cow<'static, str>,
1417 params: &RawValue,
1418 ) -> TransportResult<Box<RawValue>> {
1419 self.client().request(method, params).await
1420 }
1421
1422 #[inline]
1424 fn transaction_request(&self) -> N::TransactionRequest {
1425 Default::default()
1426 }
1427}
1428
1429#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
1430#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
1431impl<N: Network> Provider<N> for RootProvider<N> {
1432 #[inline]
1433 fn root(&self) -> &Self {
1434 self
1435 }
1436
1437 #[inline]
1438 fn client(&self) -> ClientRef<'_> {
1439 self.inner.client_ref()
1440 }
1441
1442 #[inline]
1443 fn weak_client(&self) -> WeakClient {
1444 self.inner.weak_client()
1445 }
1446
1447 #[inline]
1448 async fn watch_pending_transaction(
1449 &self,
1450 config: PendingTransactionConfig,
1451 ) -> Result<PendingTransaction, PendingTransactionError> {
1452 let block_number =
1453 if let Some(receipt) = self.get_transaction_receipt(*config.tx_hash()).await? {
1454 if config.required_confirmations() <= 1 {
1456 return Ok(PendingTransaction::ready(*config.tx_hash()));
1457 }
1458 receipt.block_number()
1461 } else {
1462 None
1463 };
1464
1465 self.get_heart()
1466 .watch_tx(config, block_number)
1467 .await
1468 .map_err(|_| PendingTransactionError::FailedToRegister)
1469 }
1470}
1471
1472#[cfg(test)]
1473mod tests {
1474 use super::*;
1475 use crate::{builder, ext::test::async_ci_only, ProviderBuilder, WalletProvider};
1476 use alloy_consensus::{Transaction, TxEnvelope};
1477 use alloy_network::{AnyNetwork, EthereumWallet, TransactionBuilder};
1478 use alloy_node_bindings::{utils::run_with_tempdir, Anvil, Reth};
1479 use alloy_primitives::{address, b256, bytes, keccak256};
1480 use alloy_rlp::Decodable;
1481 use alloy_rpc_client::{BuiltInConnectionString, RpcClient};
1482 use alloy_rpc_types_eth::{request::TransactionRequest, Block};
1483 use alloy_signer_local::PrivateKeySigner;
1484 use alloy_transport::layers::{RetryBackoffLayer, RetryPolicy};
1485 use std::{io::Read, str::FromStr, time::Duration};
1486
1487 use alloy_consensus::transaction::SignerRecoverable;
1489 #[cfg(feature = "hyper")]
1490 use alloy_transport_http::{
1491 hyper,
1492 hyper::body::Bytes as HyperBytes,
1493 hyper_util::{
1494 client::legacy::{Client, Error},
1495 rt::TokioExecutor,
1496 },
1497 HyperResponse, HyperResponseFut,
1498 };
1499 #[cfg(feature = "hyper")]
1500 use http_body_util::Full;
1501 #[cfg(feature = "hyper")]
1502 use tower::{Layer, Service};
1503
1504 #[tokio::test]
1505 async fn test_provider_builder() {
1506 let provider =
1507 RootProvider::<Ethereum>::builder().with_recommended_fillers().connect_anvil();
1508 let num = provider.get_block_number().await.unwrap();
1509 assert_eq!(0, num);
1510 }
1511
1512 #[tokio::test]
1513 async fn test_builder_helper_fn() {
1514 let provider = builder::<Ethereum>().with_recommended_fillers().connect_anvil();
1515 let num = provider.get_block_number().await.unwrap();
1516 assert_eq!(0, num);
1517 }
1518
1519 #[cfg(feature = "hyper")]
1520 #[tokio::test]
1521 async fn test_default_hyper_transport() {
1522 let anvil = Anvil::new().spawn();
1523 let hyper_t = alloy_transport_http::HyperTransport::new_hyper(anvil.endpoint_url());
1524
1525 let rpc_client = alloy_rpc_client::RpcClient::new(hyper_t, true);
1526
1527 let provider = RootProvider::<Ethereum>::new(rpc_client);
1528 let num = provider.get_block_number().await.unwrap();
1529 assert_eq!(0, num);
1530 }
1531
1532 #[cfg(feature = "hyper")]
1533 #[tokio::test]
1534 async fn test_hyper_layer_transport() {
1535 struct LoggingLayer;
1536
1537 impl<S> Layer<S> for LoggingLayer {
1538 type Service = LoggingService<S>;
1539
1540 fn layer(&self, inner: S) -> Self::Service {
1541 LoggingService { inner }
1542 }
1543 }
1544
1545 #[derive(Clone)] struct LoggingService<S> {
1547 inner: S,
1548 }
1549
1550 impl<S, B> Service<hyper::Request<B>> for LoggingService<S>
1551 where
1552 S: Service<hyper::Request<B>, Response = HyperResponse, Error = Error>
1553 + Clone
1554 + Send
1555 + Sync
1556 + 'static,
1557 S::Future: Send,
1558 S::Error: std::error::Error + Send + Sync + 'static,
1559 B: From<Vec<u8>> + Send + 'static + Clone + Sync + std::fmt::Debug,
1560 {
1561 type Response = HyperResponse;
1562 type Error = Error;
1563 type Future = HyperResponseFut;
1564
1565 fn poll_ready(
1566 &mut self,
1567 cx: &mut std::task::Context<'_>,
1568 ) -> std::task::Poll<Result<(), Self::Error>> {
1569 self.inner.poll_ready(cx)
1570 }
1571
1572 fn call(&mut self, req: hyper::Request<B>) -> Self::Future {
1573 println!("Logging Layer - HyperRequest {req:?}");
1574
1575 let fut = self.inner.call(req);
1576
1577 Box::pin(fut)
1578 }
1579 }
1580 use http::header::{self, HeaderValue};
1581 use tower_http::{
1582 sensitive_headers::SetSensitiveRequestHeadersLayer, set_header::SetRequestHeaderLayer,
1583 };
1584 let anvil = Anvil::new().spawn();
1585 let hyper_client = Client::builder(TokioExecutor::new()).build_http::<Full<HyperBytes>>();
1586
1587 let service = tower::ServiceBuilder::new()
1589 .layer(SetRequestHeaderLayer::if_not_present(
1590 header::USER_AGENT,
1591 HeaderValue::from_static("alloy app"),
1592 ))
1593 .layer(SetRequestHeaderLayer::overriding(
1594 header::AUTHORIZATION,
1595 HeaderValue::from_static("some-jwt-token"),
1596 ))
1597 .layer(SetRequestHeaderLayer::appending(
1598 header::SET_COOKIE,
1599 HeaderValue::from_static("cookie-value"),
1600 ))
1601 .layer(SetSensitiveRequestHeadersLayer::new([header::AUTHORIZATION])) .layer(LoggingLayer)
1603 .service(hyper_client);
1604
1605 let layer_transport = alloy_transport_http::HyperClient::with_service(service);
1606
1607 let http_hyper =
1608 alloy_transport_http::Http::with_client(layer_transport, anvil.endpoint_url());
1609
1610 let rpc_client = alloy_rpc_client::RpcClient::new(http_hyper, true);
1611
1612 let provider = RootProvider::<Ethereum>::new(rpc_client);
1613 let num = provider.get_block_number().await.unwrap();
1614 assert_eq!(0, num);
1615
1616 let cloned_t = provider.client().transport().clone();
1618
1619 let rpc_client = alloy_rpc_client::RpcClient::new(cloned_t, true);
1620
1621 let provider = RootProvider::<Ethereum>::new(rpc_client);
1622 let num = provider.get_block_number().await.unwrap();
1623 assert_eq!(0, num);
1624 }
1625
1626 #[cfg(feature = "hyper")]
1627 #[tokio::test]
1628 #[cfg_attr(windows, ignore = "no reth on windows")]
1629 async fn test_auth_layer_transport() {
1630 crate::ext::test::async_ci_only(|| async move {
1631 use alloy_node_bindings::Reth;
1632 use alloy_rpc_types_engine::JwtSecret;
1633 use alloy_transport_http::{AuthLayer, Http, HyperClient};
1634
1635 let secret = JwtSecret::random();
1636
1637 let reth =
1638 Reth::new().arg("--rpc.jwtsecret").arg(hex::encode(secret.as_bytes())).spawn();
1639
1640 let layer_transport = HyperClient::new().layer(AuthLayer::new(secret));
1641
1642 let http_hyper = Http::with_client(layer_transport, reth.endpoint_url());
1643
1644 let rpc_client = alloy_rpc_client::RpcClient::new(http_hyper, true);
1645
1646 let provider = RootProvider::<Ethereum>::new(rpc_client);
1647
1648 let num = provider.get_block_number().await.unwrap();
1649 assert_eq!(0, num);
1650 })
1651 .await;
1652 }
1653
1654 #[tokio::test]
1655 async fn test_builder_helper_fn_any_network() {
1656 let anvil = Anvil::new().spawn();
1657 let provider =
1658 builder::<AnyNetwork>().with_recommended_fillers().connect_http(anvil.endpoint_url());
1659 let num = provider.get_block_number().await.unwrap();
1660 assert_eq!(0, num);
1661 }
1662
1663 #[cfg(feature = "reqwest")]
1664 #[tokio::test]
1665 async fn object_safety() {
1666 let provider = ProviderBuilder::new().connect_anvil();
1667
1668 let refdyn = &provider as &dyn Provider<_>;
1669 let num = refdyn.get_block_number().await.unwrap();
1670 assert_eq!(0, num);
1671 }
1672
1673 #[cfg(feature = "ws")]
1674 #[tokio::test]
1675 async fn subscribe_blocks_http() {
1676 let provider = ProviderBuilder::new().connect_anvil_with_config(|a| a.block_time(1));
1677
1678 let err = provider.subscribe_blocks().await.unwrap_err();
1679 let alloy_json_rpc::RpcError::Transport(
1680 alloy_transport::TransportErrorKind::PubsubUnavailable,
1681 ) = err
1682 else {
1683 panic!("{err:?}");
1684 };
1685 }
1686
1687 #[cfg(feature = "ws")]
1689 #[tokio::test]
1690 async fn websocket_tls_setup() {
1691 for url in ["wss://mainnet.infura.io/ws/v3/b0f825787ba840af81e46c6a64d20754"] {
1692 let _ = ProviderBuilder::<_, _, Ethereum>::default().connect(url).await.unwrap();
1693 }
1694 }
1695
1696 #[cfg(feature = "ws")]
1697 #[tokio::test]
1698 async fn subscribe_blocks_ws() {
1699 use futures::stream::StreamExt;
1700
1701 let anvil = Anvil::new().block_time_f64(0.2).spawn();
1702 let ws = alloy_rpc_client::WsConnect::new(anvil.ws_endpoint());
1703 let client = alloy_rpc_client::RpcClient::connect_pubsub(ws).await.unwrap();
1704 let provider = RootProvider::<Ethereum>::new(client);
1705
1706 let sub = provider.subscribe_blocks().await.unwrap();
1707 let mut stream = sub.into_stream().take(5);
1708 let mut next = None;
1709 while let Some(header) = stream.next().await {
1710 if let Some(next) = &mut next {
1711 assert_eq!(header.number, *next);
1712 *next += 1;
1713 } else {
1714 next = Some(header.number + 1);
1715 }
1716 }
1717 }
1718
1719 #[cfg(feature = "ws")]
1720 #[tokio::test]
1721 async fn subscribe_full_blocks() {
1722 use futures::StreamExt;
1723
1724 let anvil = Anvil::new().block_time_f64(0.2).spawn();
1725 let ws = alloy_rpc_client::WsConnect::new(anvil.ws_endpoint());
1726 let client = alloy_rpc_client::RpcClient::connect_pubsub(ws).await.unwrap();
1727
1728 let provider = RootProvider::<Ethereum>::new(client);
1729
1730 let sub = provider.subscribe_full_blocks().hashes().channel_size(10);
1731
1732 let mut stream = sub.into_stream().await.unwrap().take(5);
1733
1734 let mut next = None;
1735 while let Some(Ok(block)) = stream.next().await {
1736 if let Some(next) = &mut next {
1737 assert_eq!(block.header().number, *next);
1738 *next += 1;
1739 } else {
1740 next = Some(block.header().number + 1);
1741 }
1742 }
1743 }
1744
1745 #[tokio::test]
1746 #[cfg(feature = "ws")]
1747 async fn subscribe_blocks_ws_remote() {
1748 use futures::stream::StreamExt;
1749
1750 let url = "wss://eth-mainnet.g.alchemy.com/v2/viFmeVzhg6bWKVMIWWS8MhmzREB-D4f7";
1751 let ws = alloy_rpc_client::WsConnect::new(url);
1752 let Ok(client) = alloy_rpc_client::RpcClient::connect_pubsub(ws).await else { return };
1753 let provider = RootProvider::<Ethereum>::new(client);
1754 let sub = provider.subscribe_blocks().await.unwrap();
1755 let mut stream = sub.into_stream().take(1);
1756 while let Some(header) = stream.next().await {
1757 println!("New block {header:?}");
1758 assert!(header.number > 0);
1759 }
1760 }
1761
1762 #[tokio::test]
1763 async fn test_custom_retry_policy() {
1764 #[derive(Debug, Clone)]
1765 struct CustomPolicy;
1766 impl RetryPolicy for CustomPolicy {
1767 fn should_retry(&self, _err: &alloy_transport::TransportError) -> bool {
1768 true
1769 }
1770
1771 fn backoff_hint(
1772 &self,
1773 _error: &alloy_transport::TransportError,
1774 ) -> Option<std::time::Duration> {
1775 None
1776 }
1777 }
1778
1779 let retry_layer = RetryBackoffLayer::new_with_policy(10, 100, 10000, CustomPolicy);
1780 let anvil = Anvil::new().spawn();
1781 let client = RpcClient::builder().layer(retry_layer).http(anvil.endpoint_url());
1782
1783 let provider = RootProvider::<Ethereum>::new(client);
1784 let num = provider.get_block_number().await.unwrap();
1785 assert_eq!(0, num);
1786 }
1787
1788 #[tokio::test]
1789 async fn test_send_tx() {
1790 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
1791 let tx = TransactionRequest {
1792 value: Some(U256::from(100)),
1793 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
1794 gas_price: Some(20e9 as u128),
1795 gas: Some(21000),
1796 ..Default::default()
1797 };
1798
1799 let builder = provider.send_transaction(tx.clone()).await.expect("failed to send tx");
1800 let hash1 = *builder.tx_hash();
1801 let hash2 = builder.watch().await.expect("failed to await pending tx");
1802 assert_eq!(hash1, hash2);
1803
1804 let builder = provider.send_transaction(tx).await.expect("failed to send tx");
1805 let hash1 = *builder.tx_hash();
1806 let hash2 =
1807 builder.get_receipt().await.expect("failed to await pending tx").transaction_hash;
1808 assert_eq!(hash1, hash2);
1809 }
1810
1811 #[tokio::test]
1812 async fn test_send_tx_sync() {
1813 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
1814 let tx = TransactionRequest {
1815 value: Some(U256::from(100)),
1816 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
1817 gas_price: Some(20e9 as u128),
1818 gas: Some(21000),
1819 ..Default::default()
1820 };
1821
1822 let _receipt =
1823 provider.send_transaction_sync(tx.clone()).await.expect("failed to send tx sync");
1824 }
1825
1826 #[tokio::test]
1827 async fn test_send_raw_transaction_sync() {
1828 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
1829
1830 let tx = TransactionRequest {
1832 nonce: Some(0),
1833 value: Some(U256::from(100)),
1834 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
1835 gas_price: Some(20e9 as u128),
1836 gas: Some(21000),
1837 ..Default::default()
1838 };
1839
1840 let tx_envelope = tx.build(&provider.wallet()).await.expect("failed to build tx");
1842
1843 let encoded = tx_envelope.encoded_2718();
1845
1846 let receipt =
1848 provider.send_raw_transaction_sync(&encoded).await.expect("failed to send raw tx sync");
1849
1850 assert_eq!(receipt.to(), Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045")));
1852 assert!(receipt.block_number().is_some(), "transaction should be mined");
1854 assert!(receipt.transaction_hash() != B256::ZERO, "should have valid tx hash");
1855 }
1856
1857 #[tokio::test]
1858 async fn test_watch_confirmed_tx() {
1859 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
1860 let tx = TransactionRequest {
1861 value: Some(U256::from(100)),
1862 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
1863 gas_price: Some(20e9 as u128),
1864 gas: Some(21000),
1865 ..Default::default()
1866 };
1867
1868 let builder = provider.send_transaction(tx).await.expect("failed to send tx");
1869 let hash1 = *builder.tx_hash();
1870
1871 loop {
1873 if provider
1874 .get_transaction_receipt(hash1)
1875 .await
1876 .expect("failed to await pending tx")
1877 .is_some()
1878 {
1879 break;
1880 }
1881 }
1882
1883 let tx2 = TransactionRequest {
1885 value: Some(U256::from(100)),
1886 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
1887 gas_price: Some(20e9 as u128),
1888 gas: Some(21000),
1889 ..Default::default()
1890 };
1891 provider.send_transaction(tx2).await.expect("failed to send tx").watch().await.unwrap();
1892
1893 let watch = builder.watch();
1895 let watch_with_timeout = tokio::time::timeout(Duration::from_secs(1), watch);
1897 let hash2 = watch_with_timeout
1898 .await
1899 .expect("Watching tx timed out")
1900 .expect("failed to await pending tx");
1901 assert_eq!(hash1, hash2);
1902 }
1903
1904 #[tokio::test]
1905 async fn gets_block_number() {
1906 let provider = ProviderBuilder::new().connect_anvil();
1907 let num = provider.get_block_number().await.unwrap();
1908 assert_eq!(0, num)
1909 }
1910
1911 #[tokio::test]
1912 async fn gets_block_number_for_id() {
1913 let provider = ProviderBuilder::new().connect_anvil();
1914
1915 let block_num = provider
1916 .get_block_number_by_id(BlockId::Number(BlockNumberOrTag::Number(0)))
1917 .await
1918 .unwrap();
1919 assert_eq!(block_num, Some(0));
1920
1921 let block_num = provider
1922 .get_block_number_by_id(BlockId::Number(BlockNumberOrTag::Latest))
1923 .await
1924 .unwrap();
1925 assert_eq!(block_num, Some(0));
1926
1927 let block =
1928 provider.get_block_by_number(BlockNumberOrTag::Number(0)).await.unwrap().unwrap();
1929 let hash = block.header.hash;
1930 let block_num = provider.get_block_number_by_id(BlockId::Hash(hash.into())).await.unwrap();
1931 assert_eq!(block_num, Some(0));
1932 }
1933
1934 #[tokio::test]
1935 async fn gets_block_number_with_raw_req() {
1936 let provider = ProviderBuilder::new().connect_anvil();
1937 let num: U64 =
1938 provider.raw_request("eth_blockNumber".into(), NoParams::default()).await.unwrap();
1939 assert_eq!(0, num.to::<u64>())
1940 }
1941
1942 #[cfg(feature = "anvil-api")]
1943 #[tokio::test]
1944 async fn gets_transaction_count() {
1945 let provider = ProviderBuilder::new().connect_anvil();
1946 let accounts = provider.get_accounts().await.unwrap();
1947 let sender = accounts[0];
1948
1949 let count = provider.get_transaction_count(sender).await.unwrap();
1951 assert_eq!(count, 0);
1952
1953 let tx = TransactionRequest {
1955 value: Some(U256::from(100)),
1956 from: Some(sender),
1957 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
1958 gas_price: Some(20e9 as u128),
1959 gas: Some(21000),
1960 ..Default::default()
1961 };
1962 let _ = provider.send_transaction(tx).await.unwrap().get_receipt().await;
1963
1964 let count = provider.get_transaction_count(sender).await.unwrap();
1966 assert_eq!(count, 1);
1967
1968 let count = provider.get_transaction_count(sender).block_id(0.into()).await.unwrap();
1970 assert_eq!(count, 0);
1971 }
1972
1973 #[tokio::test]
1974 async fn gets_block_by_hash() {
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 let hash = block.header.hash;
1980 let block = provider.get_block_by_hash(hash).full().await.unwrap().unwrap();
1981 assert_eq!(block.header.hash, hash);
1982 }
1983
1984 #[tokio::test]
1985 async fn gets_block_by_hash_with_raw_req() {
1986 let provider = ProviderBuilder::new().connect_anvil();
1987 let num = 0;
1988 let tag: BlockNumberOrTag = num.into();
1989 let block = provider.get_block_by_number(tag).full().await.unwrap().unwrap();
1990 let hash = block.header.hash;
1991 let block: Block = provider
1992 .raw_request::<(B256, bool), Block>("eth_getBlockByHash".into(), (hash, true))
1993 .await
1994 .unwrap();
1995 assert_eq!(block.header.hash, hash);
1996 }
1997
1998 #[tokio::test]
1999 async fn gets_block_by_number_full() {
2000 let provider = ProviderBuilder::new().connect_anvil();
2001 let num = 0;
2002 let tag: BlockNumberOrTag = num.into();
2003 let block = provider.get_block_by_number(tag).full().await.unwrap().unwrap();
2004 assert_eq!(block.header.number, num);
2005 }
2006
2007 #[tokio::test]
2008 async fn gets_block_by_number() {
2009 let provider = ProviderBuilder::new().connect_anvil();
2010 let num = 0;
2011 let tag: BlockNumberOrTag = num.into();
2012 let block = provider.get_block_by_number(tag).full().await.unwrap().unwrap();
2013 assert_eq!(block.header.number, num);
2014 }
2015
2016 #[tokio::test]
2017 async fn gets_client_version() {
2018 let provider = ProviderBuilder::new().connect_anvil();
2019 let version = provider.get_client_version().await.unwrap();
2020 assert!(version.contains("anvil"), "{version}");
2021 }
2022
2023 #[tokio::test]
2024 async fn gets_sha3() {
2025 let provider = ProviderBuilder::new().connect_anvil();
2026 let data = b"alloy";
2027 let hash = provider.get_sha3(data).await.unwrap();
2028 assert_eq!(hash, keccak256(data));
2029 }
2030
2031 #[tokio::test]
2032 async fn gets_chain_id() {
2033 let dev_chain_id: u64 = 13371337;
2034
2035 let provider =
2036 ProviderBuilder::new().connect_anvil_with_config(|a| a.chain_id(dev_chain_id));
2037
2038 let chain_id = provider.get_chain_id().await.unwrap();
2039 assert_eq!(chain_id, dev_chain_id);
2040 }
2041
2042 #[tokio::test]
2043 async fn gets_network_id() {
2044 let dev_chain_id: u64 = 13371337;
2045 let provider =
2046 ProviderBuilder::new().connect_anvil_with_config(|a| a.chain_id(dev_chain_id));
2047
2048 let chain_id = provider.get_net_version().await.unwrap();
2049 assert_eq!(chain_id, dev_chain_id);
2050 }
2051
2052 #[tokio::test]
2053 async fn gets_storage_at() {
2054 let provider = ProviderBuilder::new().connect_anvil();
2055 let addr = Address::with_last_byte(16);
2056 let storage = provider.get_storage_at(addr, U256::ZERO).await.unwrap();
2057 assert_eq!(storage, U256::ZERO);
2058 }
2059
2060 #[tokio::test]
2061 async fn gets_transaction_by_hash_not_found() {
2062 let provider = ProviderBuilder::new().connect_anvil();
2063 let tx_hash = b256!("5c03fab9114ceb98994b43892ade87ddfd9ae7e8f293935c3bd29d435dc9fd95");
2064 let tx = provider.get_transaction_by_hash(tx_hash).await.expect("failed to fetch tx");
2065
2066 assert!(tx.is_none());
2067 }
2068
2069 #[tokio::test]
2070 async fn gets_transaction_by_hash() {
2071 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
2072
2073 let req = TransactionRequest::default()
2074 .from(provider.default_signer_address())
2075 .to(Address::repeat_byte(5))
2076 .value(U256::ZERO)
2077 .input(bytes!("deadbeef").into());
2078
2079 let tx_hash = *provider.send_transaction(req).await.expect("failed to send tx").tx_hash();
2080
2081 let tx = provider
2082 .get_transaction_by_hash(tx_hash)
2083 .await
2084 .expect("failed to fetch tx")
2085 .expect("tx not included");
2086 assert_eq!(tx.input(), &bytes!("deadbeef"));
2087 }
2088
2089 #[tokio::test]
2090 #[ignore]
2091 async fn gets_logs() {
2092 let provider = ProviderBuilder::new().connect_anvil();
2093 let filter = Filter::new()
2094 .at_block_hash(b256!(
2095 "b20e6f35d4b46b3c4cd72152faec7143da851a0dc281d390bdd50f58bfbdb5d3"
2096 ))
2097 .event_signature(b256!(
2098 "e1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c"
2099 ));
2100 let logs = provider.get_logs(&filter).await.unwrap();
2101 assert_eq!(logs.len(), 1);
2102 }
2103
2104 #[tokio::test]
2105 #[ignore]
2106 async fn gets_tx_receipt() {
2107 let provider = ProviderBuilder::new().connect_anvil();
2108 let receipt = provider
2109 .get_transaction_receipt(b256!(
2110 "5c03fab9114ceb98994b43892ade87ddfd9ae7e8f293935c3bd29d435dc9fd95"
2111 ))
2112 .await
2113 .unwrap();
2114 assert!(receipt.is_some());
2115 let receipt = receipt.unwrap();
2116 assert_eq!(
2117 receipt.transaction_hash,
2118 b256!("5c03fab9114ceb98994b43892ade87ddfd9ae7e8f293935c3bd29d435dc9fd95")
2119 );
2120 }
2121
2122 #[tokio::test]
2123 async fn gets_max_priority_fee_per_gas() {
2124 let provider = ProviderBuilder::new().connect_anvil();
2125 let _fee = provider.get_max_priority_fee_per_gas().await.unwrap();
2126 }
2127
2128 #[tokio::test]
2129 async fn gets_fee_history() {
2130 let provider = ProviderBuilder::new().connect_anvil();
2131 let block_number = provider.get_block_number().await.unwrap();
2132 let fee_history = provider
2133 .get_fee_history(
2134 utils::EIP1559_FEE_ESTIMATION_PAST_BLOCKS,
2135 BlockNumberOrTag::Number(block_number),
2136 &[utils::EIP1559_FEE_ESTIMATION_REWARD_PERCENTILE],
2137 )
2138 .await
2139 .unwrap();
2140 assert_eq!(fee_history.oldest_block, 0_u64);
2141 }
2142
2143 #[tokio::test]
2144 async fn gets_block_transaction_count_by_hash() {
2145 let provider = ProviderBuilder::new().connect_anvil();
2146 let block = provider.get_block(BlockId::latest()).await.unwrap().unwrap();
2147 let hash = block.header.hash;
2148 let tx_count = provider.get_block_transaction_count_by_hash(hash).await.unwrap();
2149 assert!(tx_count.is_some());
2150 }
2151
2152 #[tokio::test]
2153 async fn gets_block_transaction_count_by_number() {
2154 let provider = ProviderBuilder::new().connect_anvil();
2155 let tx_count =
2156 provider.get_block_transaction_count_by_number(BlockNumberOrTag::Latest).await.unwrap();
2157 assert!(tx_count.is_some());
2158 }
2159
2160 #[tokio::test]
2161 async fn gets_block_receipts() {
2162 let provider = ProviderBuilder::new().connect_anvil();
2163 let receipts =
2164 provider.get_block_receipts(BlockId::Number(BlockNumberOrTag::Latest)).await.unwrap();
2165 assert!(receipts.is_some());
2166 }
2167
2168 #[tokio::test]
2169 async fn sends_raw_transaction() {
2170 let provider = ProviderBuilder::new().connect_anvil();
2171 let pending = provider
2172 .send_raw_transaction(
2173 bytes!("f865808477359400825208940000000000000000000000000000000000000000018082f4f5a00505e227c1c636c76fac55795db1a40a4d24840d81b40d2fe0cc85767f6bd202a01e91b437099a8a90234ac5af3cb7ca4fb1432e133f75f9a91678eaf5f487c74b").as_ref()
2175 )
2176 .await.unwrap();
2177 assert_eq!(
2178 pending.tx_hash().to_string(),
2179 "0x9dae5cf33694a02e8a7d5de3fe31e9d05ca0ba6e9180efac4ab20a06c9e598a3"
2180 );
2181 }
2182
2183 #[tokio::test]
2184 async fn connect_boxed() {
2185 let anvil = Anvil::new().spawn();
2186
2187 let provider = RootProvider::<Ethereum>::connect(anvil.endpoint().as_str()).await;
2188
2189 match provider {
2190 Ok(provider) => {
2191 let num = provider.get_block_number().await.unwrap();
2192 assert_eq!(0, num);
2193 }
2194 Err(e) => {
2195 assert_eq!(
2196 format!("{e}"),
2197 "hyper not supported by BuiltinConnectionString. Please instantiate a hyper client manually"
2198 );
2199 }
2200 }
2201 }
2202
2203 #[tokio::test]
2204 async fn any_network_wallet_filler() {
2205 use alloy_serde::WithOtherFields;
2206 let anvil = Anvil::new().spawn();
2207 let signer: PrivateKeySigner =
2208 "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80".parse().unwrap();
2209 let wallet = EthereumWallet::from(signer);
2210
2211 let provider = ProviderBuilder::new()
2212 .network::<AnyNetwork>()
2213 .wallet(wallet)
2214 .connect_http(anvil.endpoint_url());
2215
2216 let tx = TransactionRequest::default()
2217 .with_to(address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"))
2218 .value(U256::from(325235));
2219
2220 let tx = WithOtherFields::new(tx);
2221
2222 let builder = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();
2223
2224 assert!(builder.status());
2225 }
2226
2227 #[tokio::test]
2228 async fn builtin_connect_boxed() {
2229 let anvil = Anvil::new().spawn();
2230
2231 let conn: BuiltInConnectionString = anvil.endpoint().parse().unwrap();
2232
2233 let transport = conn.connect_boxed().await.unwrap();
2234
2235 let client = alloy_rpc_client::RpcClient::new(transport, true);
2236
2237 let provider = RootProvider::<Ethereum>::new(client);
2238
2239 let num = provider.get_block_number().await.unwrap();
2240 assert_eq!(0, num);
2241 }
2242
2243 #[tokio::test]
2244 async fn test_uncle_count() {
2245 let provider = ProviderBuilder::new().connect_anvil();
2246
2247 let count = provider.get_uncle_count(0.into()).await.unwrap();
2248 assert_eq!(count, 0);
2249 }
2250
2251 #[tokio::test]
2252 #[cfg(any(
2253 feature = "reqwest-default-tls",
2254 feature = "reqwest-rustls-tls",
2255 feature = "reqwest-native-tls",
2256 ))]
2257 #[ignore = "ignore until <https://github.com/paradigmxyz/reth/pull/14727> is in"]
2258 async fn call_mainnet() {
2259 use alloy_network::TransactionBuilder;
2260 use alloy_sol_types::SolValue;
2261
2262 let url = "https://docs-demo.quiknode.pro/";
2263 let provider = ProviderBuilder::new().connect_http(url.parse().unwrap());
2264 let req = TransactionRequest::default()
2265 .with_to(address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")) .with_input(bytes!("06fdde03")); let result = provider.call(req.clone()).await.unwrap();
2268 assert_eq!(String::abi_decode(&result).unwrap(), "Wrapped Ether");
2269
2270 let result = provider.call(req).block(0.into()).await.unwrap();
2271 assert_eq!(result.to_string(), "0x");
2272 }
2273
2274 #[tokio::test]
2275 async fn call_many_mainnet() {
2276 use alloy_rpc_types_eth::{BlockOverrides, StateContext};
2277
2278 let url = "https://docs-demo.quiknode.pro/";
2279 let provider = ProviderBuilder::new().connect_http(url.parse().unwrap());
2280 let tx1 = TransactionRequest::default()
2281 .with_to(address!("6b175474e89094c44da98b954eedeac495271d0f"))
2282 .with_gas_limit(1000000)
2283 .with_gas_price(2023155498)
2284 .with_input(hex!("a9059cbb000000000000000000000000bc0E63965946815d105E7591407704e6e1964E590000000000000000000000000000000000000000000000000000000005f5e100"));
2285 let tx2 = TransactionRequest::default()
2286 .with_to(address!("833589fcd6edb6e08f4c7c32d4f71b54bda02913"))
2287 .with_gas_price(2023155498)
2288 .with_input(hex!(
2289 "70a08231000000000000000000000000bc0E63965946815d105E7591407704e6e1964E59"
2290 ));
2291
2292 let transactions = vec![tx1.clone(), tx2.clone()];
2293
2294 let block_override =
2295 BlockOverrides { number: Some(U256::from(12279785)), ..Default::default() };
2296
2297 let bundles = vec![Bundle { transactions, block_override: Some(block_override.clone()) }];
2298
2299 let context = StateContext {
2300 block_number: Some(BlockId::number(12279785)),
2301 transaction_index: Some(1.into()),
2302 };
2303
2304 let results = provider.call_many(&bundles).context(&context).await.unwrap();
2305
2306 let tx1_res = EthCallResponse {
2307 value: Some(
2308 hex!("0000000000000000000000000000000000000000000000000000000000000001").into(),
2309 ),
2310 error: None,
2311 };
2312 let tx2_res = EthCallResponse { value: Some(Bytes::new()), error: None };
2313 let expected = vec![vec![tx1_res.clone(), tx2_res.clone()]];
2314
2315 assert_eq!(results, expected);
2316
2317 let bundles = vec![
2319 Bundle {
2320 transactions: vec![tx1.clone()],
2321 block_override: Some(block_override.clone()),
2322 },
2323 Bundle {
2324 transactions: vec![tx2.clone()],
2325 block_override: Some(block_override.clone()),
2326 },
2327 ];
2328
2329 let results = provider.call_many(&bundles).context(&context).await.unwrap();
2330 let expected = vec![vec![tx1_res.clone()], vec![tx2_res.clone()]];
2331 assert_eq!(results, expected);
2332
2333 let b1 =
2335 vec![Bundle { transactions: vec![tx1], block_override: Some(block_override.clone()) }];
2336 let b2 = vec![Bundle { transactions: vec![tx2], block_override: Some(block_override) }];
2337
2338 let results = provider.call_many(&b1).context(&context).extend_bundles(&b2).await.unwrap();
2339 assert_eq!(results, expected);
2340 }
2341
2342 #[tokio::test]
2343 #[cfg(feature = "hyper-tls")]
2344 async fn hyper_https() {
2345 let url = "https://reth-ethereum.ithaca.xyz/rpc";
2346
2347 let provider = ProviderBuilder::new().connect(url).await.unwrap();
2350
2351 let _num = provider.get_block_number().await.unwrap();
2352 }
2353
2354 #[tokio::test]
2355 async fn test_empty_transactions() {
2356 let provider = ProviderBuilder::new().connect_anvil();
2357
2358 let block = provider.get_block_by_number(0.into()).await.unwrap().unwrap();
2359 assert!(block.transactions.is_hashes());
2360 }
2361
2362 #[tokio::test]
2363 async fn disable_test() {
2364 let provider = ProviderBuilder::new()
2365 .disable_recommended_fillers()
2366 .with_cached_nonce_management()
2367 .connect_anvil();
2368
2369 let tx = TransactionRequest::default()
2370 .with_kind(alloy_primitives::TxKind::Create)
2371 .value(U256::from(1235))
2372 .with_input(Bytes::from_str("ffffffffffffff").unwrap());
2373
2374 let err = provider.send_transaction(tx).await.unwrap_err().to_string();
2375 assert!(err.contains("missing properties: [(\"NonceManager\", [\"from\"])]"));
2376 }
2377
2378 #[tokio::test]
2379 async fn capture_anvil_logs() {
2380 let mut anvil = Anvil::new().keep_stdout().spawn();
2381
2382 let provider = ProviderBuilder::new().connect_http(anvil.endpoint_url());
2383
2384 let tx = TransactionRequest::default()
2385 .with_from(address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"))
2386 .with_to(address!("70997970C51812dc3A010C7d01b50e0d17dc79C8"))
2387 .value(U256::from(100));
2388
2389 let _ = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();
2390
2391 anvil.child_mut().kill().unwrap();
2392
2393 let mut output = String::new();
2394 anvil.child_mut().stdout.take().unwrap().read_to_string(&mut output).unwrap();
2395
2396 assert_eq!(anvil.chain_id(), 31337);
2397 assert_eq!(anvil.addresses().len(), 10);
2398 assert_eq!(anvil.keys().len(), 10);
2399
2400 assert!(output.contains("eth_sendTransaction"));
2401 assert!(output.contains("Block Number: 1"))
2402 }
2403
2404 #[tokio::test]
2405 async fn custom_estimator() {
2406 let provider = ProviderBuilder::new()
2407 .disable_recommended_fillers()
2408 .with_cached_nonce_management()
2409 .connect_anvil();
2410
2411 let _ = provider
2412 .estimate_eip1559_fees_with(Eip1559Estimator::new(|_fee, _rewards| Eip1559Estimation {
2413 max_fee_per_gas: 0,
2414 max_priority_fee_per_gas: 0,
2415 }))
2416 .await;
2417 }
2418
2419 #[tokio::test]
2420 #[cfg(not(windows))]
2421 async fn eth_sign_transaction() {
2422 async_ci_only(|| async {
2423 run_with_tempdir("reth-sign-tx", |dir| async {
2424 let reth = Reth::new().dev().disable_discovery().data_dir(dir).spawn();
2425 let provider = ProviderBuilder::new().connect_http(reth.endpoint_url());
2426
2427 let accounts = provider.get_accounts().await.unwrap();
2428 let from = accounts[0];
2429
2430 let tx = TransactionRequest::default()
2431 .from(from)
2432 .to(Address::random())
2433 .value(U256::from(100))
2434 .gas_limit(21000);
2435
2436 let signed_tx = provider.sign_transaction(tx).await.unwrap().to_vec();
2437
2438 let tx = TxEnvelope::decode(&mut signed_tx.as_slice()).unwrap();
2439
2440 let signer = tx.recover_signer().unwrap();
2441
2442 assert_eq!(signer, from);
2443 })
2444 .await
2445 })
2446 .await;
2447 }
2448
2449 #[cfg(feature = "throttle")]
2450 use alloy_transport::layers::ThrottleLayer;
2451
2452 #[cfg(feature = "throttle")]
2453 #[tokio::test]
2454 async fn test_throttled_provider() {
2455 let request_per_second = 10;
2456 let throttle_layer = ThrottleLayer::new(request_per_second);
2457
2458 let anvil = Anvil::new().spawn();
2459 let client = RpcClient::builder().layer(throttle_layer).http(anvil.endpoint_url());
2460 let provider = RootProvider::<Ethereum>::new(client);
2461
2462 let num_requests = 10;
2463 let start = std::time::Instant::now();
2464 for _ in 0..num_requests {
2465 provider.get_block_number().await.unwrap();
2466 }
2467
2468 let elapsed = start.elapsed();
2469 assert_eq!(elapsed.as_secs_f64().round() as u32, 1);
2470 }
2471
2472 #[tokio::test]
2473 #[cfg(feature = "hyper")]
2474 async fn test_connect_hyper_tls() {
2475 let p =
2476 ProviderBuilder::new().connect("https://reth-ethereum.ithaca.xyz/rpc").await.unwrap();
2477
2478 let _num = p.get_block_number().await.unwrap();
2479
2480 let anvil = Anvil::new().spawn();
2481 let p = ProviderBuilder::new().connect(&anvil.endpoint()).await.unwrap();
2482
2483 let _num = p.get_block_number().await.unwrap();
2484 }
2485
2486 #[tokio::test]
2487 async fn test_send_transaction_sync() {
2488 use alloy_network::TransactionBuilder;
2489 use alloy_primitives::{address, U256};
2490
2491 let anvil = Anvil::new().spawn();
2492 let provider = ProviderBuilder::new().connect_http(anvil.endpoint_url());
2493
2494 let tx = TransactionRequest::default()
2495 .with_from(address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"))
2496 .with_to(address!("70997970C51812dc3A010C7d01b50e0d17dc79C8"))
2497 .with_value(U256::from(100));
2498
2499 let receipt = provider.send_transaction_sync(tx).await.unwrap();
2501
2502 let tx_hash = receipt.transaction_hash;
2504 assert!(!tx_hash.is_zero());
2505 assert_eq!(receipt.transaction_hash, tx_hash);
2506 assert!(receipt.status());
2507 }
2508
2509 #[tokio::test]
2510 async fn test_send_transaction_sync_with_fillers() {
2511 use alloy_network::TransactionBuilder;
2512 use alloy_primitives::{address, U256};
2513
2514 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
2515
2516 let tx = TransactionRequest::default()
2518 .with_from(provider.default_signer_address())
2519 .with_to(address!("70997970C51812dc3A010C7d01b50e0d17dc79C8"))
2520 .with_value(U256::from(100));
2521 let receipt = provider.send_transaction_sync(tx).await.unwrap();
2525
2526 let tx_hash = receipt.transaction_hash;
2528 assert!(!tx_hash.is_zero());
2529
2530 assert_eq!(receipt.transaction_hash, tx_hash);
2532 assert!(receipt.status());
2533 assert!(receipt.gas_used() > 0, "fillers should have estimated gas");
2534 }
2535
2536 #[tokio::test]
2537 async fn test_fill_transaction() {
2538 use alloy_network::TransactionBuilder;
2539 use alloy_primitives::{address, U256};
2540
2541 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
2542
2543 let tx = TransactionRequest::default()
2544 .with_from(provider.default_signer_address())
2545 .with_to(address!("70997970C51812dc3A010C7d01b50e0d17dc79C8"))
2546 .with_value(U256::from(100));
2547
2548 let filled = provider.fill_transaction(tx).await.unwrap();
2549
2550 assert!(!filled.raw.is_empty(), "raw transaction bytes should not be empty");
2552
2553 let filled_tx = &filled.tx;
2555 assert!(filled_tx.to().is_some(), "filled transaction should have to address");
2556 assert!(filled_tx.gas_limit() > 0, "filled transaction should have gas limit");
2557 assert!(filled_tx.max_fee_per_gas() > 0, "filled transaction should have max fee per gas");
2558 }
2559}