1#![allow(unknown_lints, mismatched_lifetime_syntaxes)]
4
5#[cfg(feature = "pubsub")]
6use super::get_block::SubFullBlocks;
7use super::{DynProvider, Empty, EthCallMany, MulticallBuilder, WatchBlocks, WatchHeaders};
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, eip7928::BlockAccessList};
19use alloy_json_rpc::{RpcError, RpcRecv, RpcSend};
20use alloy_network::{Ethereum, Network};
21use alloy_network_primitives::{BlockResponse, ReceiptResponse};
22use alloy_primitives::{
23 hex, Address, BlockHash, BlockNumber, Bytes, StorageKey, StorageValue, TxHash, B256, U128,
24 U256, U64,
25};
26use alloy_rpc_client::{ClientRef, NoParams, PollerBuilder, WeakClient};
27#[cfg(feature = "pubsub")]
28use alloy_rpc_types_eth::pubsub::{Params, SubscriptionKind};
29use alloy_rpc_types_eth::{
30 erc4337::TransactionConditional,
31 simulate::{SimulatePayload, SimulatedBlock},
32 AccessListResult, BlockId, BlockNumberOrTag, Bundle, EIP1186AccountProofResponse,
33 EthCallResponse, FeeHistory, FillTransaction, Filter, FilterChanges, Index, Log,
34 StorageValuesRequest, StorageValuesResponse, SyncStatus,
35};
36use alloy_transport::TransportResult;
37use serde_json::value::RawValue;
38use std::borrow::Cow;
39
40pub type FilterPollerBuilder<R> = PollerBuilder<(U256,), Vec<R>>;
44
45#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
72#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
73#[auto_impl::auto_impl(&, &mut, Rc, Arc, Box)]
74pub trait Provider<N: Network = Ethereum>: Send + Sync {
75 fn root(&self) -> &RootProvider<N>;
77
78 fn builder() -> ProviderBuilder<Identity, Identity, N>
80 where
81 Self: Sized,
82 {
83 ProviderBuilder::default()
84 }
85
86 #[inline]
90 fn client(&self) -> ClientRef<'_> {
91 self.root().client()
92 }
93
94 #[inline]
98 fn weak_client(&self) -> WeakClient {
99 self.root().weak_client()
100 }
101
102 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
115 #[doc(alias = "boxed")]
116 fn erased(self) -> DynProvider<N>
117 where
118 Self: Sized + 'static,
119 {
120 DynProvider::new(self)
121 }
122
123 fn get_accounts(&self) -> ProviderCall<NoParams, Vec<Address>> {
126 self.client().request_noparams("eth_accounts").into()
127 }
128
129 fn get_blob_base_fee(&self) -> ProviderCall<NoParams, U128, u128> {
131 self.client()
132 .request_noparams("eth_blobBaseFee")
133 .map_resp(utils::convert_u128 as fn(U128) -> u128)
134 .into()
135 }
136
137 fn get_block_number(&self) -> ProviderCall<NoParams, U64, BlockNumber> {
139 self.client()
140 .request_noparams("eth_blockNumber")
141 .map_resp(utils::convert_u64 as fn(U64) -> u64)
142 .into()
143 }
144
145 async fn get_block_number_by_id(
150 &self,
151 block_id: BlockId,
152 ) -> TransportResult<Option<BlockNumber>> {
153 match block_id {
154 BlockId::Number(BlockNumberOrTag::Number(num)) => Ok(Some(num)),
155 BlockId::Number(BlockNumberOrTag::Latest) => self.get_block_number().await.map(Some),
156 _ => Ok(self.get_header(block_id).await?.map(|h| h.number())),
157 }
158 }
159
160 #[doc(alias = "eth_call")]
188 #[doc(alias = "call_with_overrides")]
189 fn call(&self, tx: N::TransactionRequest) -> EthCall<N, Bytes> {
190 EthCall::call(self.weak_client(), tx).block(BlockNumberOrTag::Pending.into())
191 }
192
193 #[doc(alias = "eth_callMany")]
202 fn call_many<'req>(
203 &self,
204 bundles: &'req [Bundle],
205 ) -> EthCallMany<'req, N, Vec<Vec<EthCallResponse>>> {
206 EthCallMany::new(self.weak_client(), bundles)
207 }
208
209 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
215 fn multicall(&self) -> MulticallBuilder<Empty, &Self, N>
216 where
217 Self: Sized,
218 {
219 MulticallBuilder::new(self)
220 }
221
222 #[doc(alias = "eth_simulateV1")]
226 fn simulate<'req>(
227 &self,
228 payload: &'req SimulatePayload,
229 ) -> RpcWithBlock<&'req SimulatePayload, Vec<SimulatedBlock<N::BlockResponse>>> {
230 self.client().request("eth_simulateV1", payload).into()
231 }
232
233 fn get_chain_id(&self) -> ProviderCall<NoParams, U64, u64> {
235 self.client()
236 .request_noparams("eth_chainId")
237 .map_resp(utils::convert_u64 as fn(U64) -> u64)
238 .into()
239 }
240
241 fn create_access_list<'a>(
245 &self,
246 request: &'a N::TransactionRequest,
247 ) -> RpcWithBlock<&'a N::TransactionRequest, AccessListResult> {
248 self.client().request("eth_createAccessList", request).into()
249 }
250
251 fn estimate_gas(&self, tx: N::TransactionRequest) -> EthCall<N, U64, u64> {
265 EthCall::gas_estimate(self.weak_client(), tx)
266 .block(BlockNumberOrTag::Pending.into())
267 .map_resp(utils::convert_u64)
268 }
269
270 async fn estimate_eip1559_fees_with(
277 &self,
278 estimator: Eip1559Estimator,
279 ) -> TransportResult<Eip1559Estimation> {
280 let fee_history = self
281 .get_fee_history(
282 utils::EIP1559_FEE_ESTIMATION_PAST_BLOCKS,
283 BlockNumberOrTag::Latest,
284 &[utils::EIP1559_FEE_ESTIMATION_REWARD_PERCENTILE],
285 )
286 .await?;
287
288 let base_fee_per_gas = match fee_history.latest_block_base_fee() {
291 Some(base_fee) if base_fee != 0 => base_fee,
292 _ => {
293 self.get_block_by_number(BlockNumberOrTag::Latest)
295 .await?
296 .ok_or(RpcError::NullResp)?
297 .header()
298 .as_ref()
299 .base_fee_per_gas()
300 .ok_or(RpcError::UnsupportedFeature("eip1559"))?
301 .into()
302 }
303 };
304
305 Ok(estimator.estimate(base_fee_per_gas, &fee_history.reward.unwrap_or_default()))
306 }
307
308 async fn estimate_eip1559_fees(&self) -> TransportResult<Eip1559Estimation> {
314 self.estimate_eip1559_fees_with(Eip1559Estimator::default()).await
315 }
316
317 async fn get_fee_history(
323 &self,
324 block_count: u64,
325 last_block: BlockNumberOrTag,
326 reward_percentiles: &[f64],
327 ) -> TransportResult<FeeHistory> {
328 self.client()
329 .request("eth_feeHistory", (U64::from(block_count), last_block, reward_percentiles))
330 .await
331 }
332
333 fn get_gas_price(&self) -> ProviderCall<NoParams, U128, u128> {
335 self.client()
336 .request_noparams("eth_gasPrice")
337 .map_resp(utils::convert_u128 as fn(U128) -> u128)
338 .into()
339 }
340
341 fn get_account_info(
347 &self,
348 address: Address,
349 ) -> RpcWithBlock<Address, alloy_rpc_types_eth::AccountInfo> {
350 self.client().request("eth_getAccountInfo", address).into()
351 }
352
353 fn get_account(&self, address: Address) -> RpcWithBlock<Address, alloy_consensus::TrieAccount> {
356 self.client().request("eth_getAccount", address).into()
357 }
358
359 fn get_balance(&self, address: Address) -> RpcWithBlock<Address, U256, U256> {
363 self.client().request("eth_getBalance", address).into()
364 }
365
366 fn get_block(&self, block: BlockId) -> EthGetBlock<N::BlockResponse> {
377 match block {
378 BlockId::Hash(hash) => EthGetBlock::by_hash(hash.block_hash, self.client()),
379 BlockId::Number(number) => EthGetBlock::by_number(number, self.client()),
380 }
381 }
382
383 fn get_block_by_hash(&self, hash: BlockHash) -> EthGetBlock<N::BlockResponse> {
408 EthGetBlock::by_hash(hash, self.client())
409 }
410
411 fn get_block_by_number(&self, number: BlockNumberOrTag) -> EthGetBlock<N::BlockResponse> {
436 EthGetBlock::by_number(number, self.client())
437 }
438
439 async fn get_block_transaction_count_by_hash(
441 &self,
442 hash: BlockHash,
443 ) -> TransportResult<Option<u64>> {
444 self.client()
445 .request("eth_getBlockTransactionCountByHash", (hash,))
446 .await
447 .map(|opt_count: Option<U64>| opt_count.map(|count| count.to::<u64>()))
448 }
449
450 async fn get_block_transaction_count_by_number(
452 &self,
453 block_number: BlockNumberOrTag,
454 ) -> TransportResult<Option<u64>> {
455 self.client()
456 .request("eth_getBlockTransactionCountByNumber", (block_number,))
457 .await
458 .map(|opt_count: Option<U64>| opt_count.map(|count| count.to::<u64>()))
459 }
460
461 fn get_block_receipts(
463 &self,
464 block: BlockId,
465 ) -> ProviderCall<(BlockId,), Option<Vec<N::ReceiptResponse>>> {
466 self.client().request("eth_getBlockReceipts", (block,)).into()
467 }
468
469 async fn get_block_access_list(
473 &self,
474 block: BlockId,
475 ) -> TransportResult<Option<BlockAccessList>> {
476 match block {
477 BlockId::Hash(hash) => self.get_block_access_list_by_hash(hash.block_hash).await,
478 BlockId::Number(number) => self.get_block_access_list_by_number(number).await,
479 }
480 }
481
482 async fn get_block_access_list_by_hash(
486 &self,
487 hash: BlockHash,
488 ) -> TransportResult<Option<BlockAccessList>> {
489 self.client().request("eth_getBlockAccessListByBlockHash", (hash,)).await
490 }
491
492 async fn get_block_access_list_by_number(
496 &self,
497 number: BlockNumberOrTag,
498 ) -> TransportResult<Option<BlockAccessList>> {
499 self.client().request("eth_getBlockAccessListByBlockNumber", (number,)).await
500 }
501
502 async fn get_block_access_list_raw(&self, block: BlockId) -> TransportResult<Option<Bytes>> {
506 self.client().request("eth_getBlockAccessListRaw", (block,)).await
507 }
508
509 async fn get_header(&self, block: BlockId) -> TransportResult<Option<N::HeaderResponse>> {
530 match block {
531 BlockId::Hash(hash) => self.get_header_by_hash(hash.block_hash).await,
532 BlockId::Number(number) => self.get_header_by_number(number).await,
533 }
534 }
535
536 async fn get_header_by_hash(
555 &self,
556 hash: BlockHash,
557 ) -> TransportResult<Option<N::HeaderResponse>> {
558 match self.client().request("eth_getHeaderByHash", (hash,)).await {
559 Ok(header) => Ok(header),
560 Err(err) if err.as_error_resp().is_some_and(|e| e.code == -32601) => {
562 Ok(self.get_block_by_hash(hash).await?.map(|b| b.header().clone()))
563 }
564 Err(err) => Err(err),
565 }
566 }
567
568 async fn get_header_by_number(
589 &self,
590 number: BlockNumberOrTag,
591 ) -> TransportResult<Option<N::HeaderResponse>> {
592 match self.client().request("eth_getHeaderByNumber", (number,)).await {
593 Ok(header) => Ok(header),
594 Err(err) if err.as_error_resp().is_some_and(|e| e.code == -32601) => {
596 Ok(self.get_block_by_number(number).await?.map(|b| b.header().clone()))
597 }
598 Err(err) => Err(err),
599 }
600 }
601
602 fn get_code_at(&self, address: Address) -> RpcWithBlock<Address, Bytes> {
604 self.client().request("eth_getCode", address).into()
605 }
606
607 async fn watch_blocks(&self) -> TransportResult<FilterPollerBuilder<B256>> {
630 let id = self.new_block_filter().await?;
631 Ok(PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,)))
632 }
633
634 async fn watch_full_blocks(&self) -> TransportResult<WatchBlocks<N::BlockResponse>> {
658 let id = self.new_block_filter().await?;
659 let poller = PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,));
660
661 Ok(WatchBlocks::new(poller))
662 }
663
664 async fn watch_headers(&self) -> TransportResult<WatchHeaders<N::HeaderResponse>> {
691 let id = self.new_block_filter().await?;
692 let poller = PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,));
693
694 Ok(WatchHeaders::new(poller))
695 }
696
697 async fn watch_pending_transactions(&self) -> TransportResult<FilterPollerBuilder<B256>> {
720 let id = self.new_pending_transactions_filter(false).await?;
721 Ok(PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,)))
722 }
723
724 async fn watch_logs(&self, filter: &Filter) -> TransportResult<FilterPollerBuilder<Log>> {
753 let id = self.new_filter(filter).await?;
754 Ok(PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,)))
755 }
756
757 async fn watch_full_pending_transactions(
784 &self,
785 ) -> TransportResult<FilterPollerBuilder<N::TransactionResponse>> {
786 let id = self.new_pending_transactions_filter(true).await?;
787 Ok(PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,)))
788 }
789
790 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
795 async fn get_filter_changes<R: RpcRecv>(&self, id: U256) -> TransportResult<Vec<R>>
796 where
797 Self: Sized,
798 {
799 self.client().request("eth_getFilterChanges", (id,)).await
800 }
801
802 async fn get_filter_changes_dyn(&self, id: U256) -> TransportResult<FilterChanges> {
807 self.client().request("eth_getFilterChanges", (id,)).await
808 }
809
810 async fn get_filter_logs(&self, id: U256) -> TransportResult<Vec<Log>> {
812 self.client().request("eth_getFilterLogs", (id,)).await
813 }
814
815 async fn uninstall_filter(&self, id: U256) -> TransportResult<bool> {
817 self.client().request("eth_uninstallFilter", (id,)).await
818 }
819
820 #[inline]
825 async fn watch_pending_transaction(
826 &self,
827 config: PendingTransactionConfig,
828 ) -> Result<PendingTransaction, PendingTransactionError> {
829 self.root().watch_pending_transaction(config).await
830 }
831
832 async fn get_logs(&self, filter: &Filter) -> TransportResult<Vec<Log>> {
834 self.client().request("eth_getLogs", (filter,)).await
835 }
836
837 fn get_proof(
841 &self,
842 address: Address,
843 keys: Vec<StorageKey>,
844 ) -> RpcWithBlock<(Address, Vec<StorageKey>), EIP1186AccountProofResponse> {
845 self.client().request("eth_getProof", (address, keys)).into()
846 }
847
848 fn get_storage_at(
850 &self,
851 address: Address,
852 key: U256,
853 ) -> RpcWithBlock<(Address, U256), StorageValue> {
854 self.client().request("eth_getStorageAt", (address, key)).into()
855 }
856
857 fn get_storage_values(
861 &self,
862 requests: StorageValuesRequest,
863 ) -> RpcWithBlock<(StorageValuesRequest,), StorageValuesResponse> {
864 self.client().request("eth_getStorageValues", (requests,)).into()
865 }
866
867 fn get_transaction_by_sender_nonce(
871 &self,
872 sender: Address,
873 nonce: u64,
874 ) -> ProviderCall<(Address, U64), Option<N::TransactionResponse>> {
875 self.client()
876 .request("eth_getTransactionBySenderAndNonce", (sender, U64::from(nonce)))
877 .into()
878 }
879
880 fn get_transaction_by_hash(
882 &self,
883 hash: TxHash,
884 ) -> ProviderCall<(TxHash,), Option<N::TransactionResponse>> {
885 self.client().request("eth_getTransactionByHash", (hash,)).into()
886 }
887
888 fn get_transaction_by_block_hash_and_index(
890 &self,
891 block_hash: B256,
892 index: usize,
893 ) -> ProviderCall<(B256, Index), Option<N::TransactionResponse>> {
894 self.client()
895 .request("eth_getTransactionByBlockHashAndIndex", (block_hash, Index(index)))
896 .into()
897 }
898
899 fn get_raw_transaction_by_block_hash_and_index(
901 &self,
902 block_hash: B256,
903 index: usize,
904 ) -> ProviderCall<(B256, Index), Option<Bytes>> {
905 self.client()
906 .request("eth_getRawTransactionByBlockHashAndIndex", (block_hash, Index(index)))
907 .into()
908 }
909
910 fn get_transaction_by_block_number_and_index(
912 &self,
913 block_number: BlockNumberOrTag,
914 index: usize,
915 ) -> ProviderCall<(BlockNumberOrTag, Index), Option<N::TransactionResponse>> {
916 self.client()
917 .request("eth_getTransactionByBlockNumberAndIndex", (block_number, Index(index)))
918 .into()
919 }
920
921 fn get_raw_transaction_by_block_number_and_index(
923 &self,
924 block_number: BlockNumberOrTag,
925 index: usize,
926 ) -> ProviderCall<(BlockNumberOrTag, Index), Option<Bytes>> {
927 self.client()
928 .request("eth_getRawTransactionByBlockNumberAndIndex", (block_number, Index(index)))
929 .into()
930 }
931
932 fn get_raw_transaction_by_hash(&self, hash: TxHash) -> ProviderCall<(TxHash,), Option<Bytes>> {
944 self.client().request("eth_getRawTransactionByHash", (hash,)).into()
945 }
946
947 #[doc(alias = "get_nonce")]
949 #[doc(alias = "get_account_nonce")]
950 fn get_transaction_count(
951 &self,
952 address: Address,
953 ) -> RpcWithBlock<Address, U64, u64, fn(U64) -> u64> {
954 self.client()
955 .request("eth_getTransactionCount", address)
956 .map_resp(utils::convert_u64 as fn(U64) -> u64)
957 .into()
958 }
959
960 fn get_transaction_receipt(
962 &self,
963 hash: TxHash,
964 ) -> ProviderCall<(TxHash,), Option<N::ReceiptResponse>> {
965 self.client().request("eth_getTransactionReceipt", (hash,)).into()
966 }
967
968 async fn get_uncle(&self, tag: BlockId, idx: u64) -> TransportResult<Option<N::BlockResponse>> {
970 let idx = U64::from(idx);
971 match tag {
972 BlockId::Hash(hash) => {
973 self.client()
974 .request("eth_getUncleByBlockHashAndIndex", (hash.block_hash, idx))
975 .await
976 }
977 BlockId::Number(number) => {
978 self.client().request("eth_getUncleByBlockNumberAndIndex", (number, idx)).await
979 }
980 }
981 }
982
983 async fn get_uncle_count(&self, tag: BlockId) -> TransportResult<u64> {
985 match tag {
986 BlockId::Hash(hash) => self
987 .client()
988 .request("eth_getUncleCountByBlockHash", (hash.block_hash,))
989 .await
990 .map(|count: U64| count.to::<u64>()),
991 BlockId::Number(number) => self
992 .client()
993 .request("eth_getUncleCountByBlockNumber", (number,))
994 .await
995 .map(|count: U64| count.to::<u64>()),
996 }
997 }
998
999 fn get_max_priority_fee_per_gas(&self) -> ProviderCall<NoParams, U128, u128> {
1001 self.client()
1002 .request_noparams("eth_maxPriorityFeePerGas")
1003 .map_resp(utils::convert_u128 as fn(U128) -> u128)
1004 .into()
1005 }
1006
1007 async fn new_block_filter(&self) -> TransportResult<U256> {
1013 self.client().request_noparams("eth_newBlockFilter").await
1014 }
1015
1016 async fn new_filter(&self, filter: &Filter) -> TransportResult<U256> {
1022 self.client().request("eth_newFilter", (filter,)).await
1023 }
1024
1025 async fn new_pending_transactions_filter(&self, full: bool) -> TransportResult<U256> {
1035 let param = if full { &[true][..] } else { &[] };
1037 self.client().request("eth_newPendingTransactionFilter", param).await
1038 }
1039
1040 async fn send_raw_transaction(
1044 &self,
1045 encoded_tx: &[u8],
1046 ) -> TransportResult<PendingTransactionBuilder<N>> {
1047 let rlp_hex = hex::encode_prefixed(encoded_tx);
1048 let tx_hash = self.client().request("eth_sendRawTransaction", (rlp_hex,)).await?;
1049 Ok(PendingTransactionBuilder::new(self.root().clone(), tx_hash))
1050 }
1051
1052 async fn send_raw_transaction_sync(
1090 &self,
1091 encoded_tx: &[u8],
1092 ) -> TransportResult<N::ReceiptResponse> {
1093 let rlp_hex = hex::encode_prefixed(encoded_tx);
1094 self.client().request("eth_sendRawTransactionSync", (rlp_hex,)).await
1095 }
1096
1097 async fn send_raw_transaction_conditional(
1108 &self,
1109 encoded_tx: &[u8],
1110 conditional: TransactionConditional,
1111 ) -> TransportResult<PendingTransactionBuilder<N>> {
1112 let rlp_hex = hex::encode_prefixed(encoded_tx);
1113 let tx_hash = self
1114 .client()
1115 .request("eth_sendRawTransactionConditional", (rlp_hex, conditional))
1116 .await?;
1117 Ok(PendingTransactionBuilder::new(self.root().clone(), tx_hash))
1118 }
1119
1120 async fn send_transaction(
1141 &self,
1142 tx: N::TransactionRequest,
1143 ) -> TransportResult<PendingTransactionBuilder<N>> {
1144 self.send_transaction_internal(SendableTx::Builder(tx)).await
1145 }
1146
1147 async fn send_tx_envelope(
1152 &self,
1153 tx: N::TxEnvelope,
1154 ) -> TransportResult<PendingTransactionBuilder<N>> {
1155 self.send_transaction_internal(SendableTx::Envelope(tx)).await
1156 }
1157
1158 #[doc(hidden)]
1165 async fn send_transaction_internal(
1166 &self,
1167 tx: SendableTx<N>,
1168 ) -> TransportResult<PendingTransactionBuilder<N>> {
1169 let _handle = self.root().get_heart();
1172
1173 match tx {
1174 SendableTx::Builder(mut tx) => {
1175 alloy_network::NetworkTransactionBuilder::prep_for_submission(&mut tx);
1176 let tx_hash = self.client().request("eth_sendTransaction", (tx,)).await?;
1177 Ok(PendingTransactionBuilder::new(self.root().clone(), tx_hash))
1178 }
1179 SendableTx::Envelope(tx) => {
1180 let encoded_tx = tx.encoded_2718();
1181 self.send_raw_transaction(&encoded_tx).await
1182 }
1183 }
1184 }
1185
1186 async fn send_transaction_sync(
1226 &self,
1227 tx: N::TransactionRequest,
1228 ) -> TransportResult<N::ReceiptResponse> {
1229 self.send_transaction_sync_internal(SendableTx::Builder(tx)).await
1230 }
1231
1232 #[doc(hidden)]
1242 async fn send_transaction_sync_internal(
1243 &self,
1244 tx: SendableTx<N>,
1245 ) -> TransportResult<N::ReceiptResponse> {
1246 let _handle = self.root().get_heart();
1249
1250 match tx {
1251 SendableTx::Builder(mut tx) => {
1252 alloy_network::NetworkTransactionBuilder::prep_for_submission(&mut tx);
1253 let receipt = self.client().request("eth_sendTransactionSync", (tx,)).await?;
1254 Ok(receipt)
1255 }
1256 SendableTx::Envelope(tx) => {
1257 let encoded_tx = tx.encoded_2718();
1258 self.send_raw_transaction_sync(&encoded_tx).await
1259 }
1260 }
1261 }
1262
1263 async fn sign_transaction(&self, tx: N::TransactionRequest) -> TransportResult<Bytes> {
1268 self.client().request("eth_signTransaction", (tx,)).await
1269 }
1270
1271 async fn fill_transaction(
1277 &self,
1278 tx: N::TransactionRequest,
1279 ) -> TransportResult<FillTransaction<N::TxEnvelope>>
1280 where
1281 N::TxEnvelope: RpcRecv,
1282 {
1283 self.client().request("eth_fillTransaction", (tx,)).await
1284 }
1285
1286 #[cfg(feature = "pubsub")]
1312 fn subscribe_blocks(&self) -> GetSubscription<(SubscriptionKind,), N::HeaderResponse> {
1313 let rpc_call = self.client().request("eth_subscribe", (SubscriptionKind::NewHeads,));
1314 GetSubscription::new(self.weak_client(), rpc_call)
1315 }
1316
1317 #[cfg(feature = "pubsub")]
1341 fn subscribe_full_blocks(&self) -> SubFullBlocks<N> {
1342 SubFullBlocks::new(self.subscribe_blocks(), self.weak_client())
1343 }
1344
1345 #[cfg(feature = "pubsub")]
1371 fn subscribe_pending_transactions(&self) -> GetSubscription<(SubscriptionKind,), B256> {
1372 let rpc_call =
1373 self.client().request("eth_subscribe", (SubscriptionKind::NewPendingTransactions,));
1374 GetSubscription::new(self.weak_client(), rpc_call)
1375 }
1376
1377 #[cfg(feature = "pubsub")]
1408 fn subscribe_full_pending_transactions(
1409 &self,
1410 ) -> GetSubscription<(SubscriptionKind, Params), N::TransactionResponse> {
1411 let rpc_call = self.client().request(
1412 "eth_subscribe",
1413 (SubscriptionKind::NewPendingTransactions, Params::Bool(true)),
1414 );
1415 GetSubscription::new(self.weak_client(), rpc_call)
1416 }
1417
1418 #[cfg(feature = "pubsub")]
1449 fn subscribe_logs(&self, filter: &Filter) -> GetSubscription<(SubscriptionKind, Params), Log> {
1450 let rpc_call = self.client().request(
1451 "eth_subscribe",
1452 (SubscriptionKind::Logs, Params::Logs(Box::new(filter.clone()))),
1453 );
1454 GetSubscription::new(self.weak_client(), rpc_call)
1455 }
1456
1457 #[cfg(feature = "pubsub")]
1459 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
1460 fn subscribe<P, R>(&self, params: P) -> GetSubscription<P, R>
1461 where
1462 P: RpcSend,
1463 R: RpcRecv,
1464 Self: Sized,
1465 {
1466 let rpc_call = self.client().request("eth_subscribe", params);
1467 GetSubscription::new(self.weak_client(), rpc_call)
1468 }
1469
1470 #[cfg(feature = "pubsub")]
1491 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
1492 fn subscribe_to<R>(&self, method: &'static str) -> GetSubscription<NoParams, R>
1493 where
1494 R: RpcRecv,
1495 Self: Sized,
1496 {
1497 let mut rpc_call = self.client().request_noparams(method);
1498 rpc_call.set_is_subscription();
1499 GetSubscription::new(self.weak_client(), rpc_call)
1500 }
1501
1502 #[cfg(feature = "pubsub")]
1504 async fn unsubscribe(&self, id: B256) -> TransportResult<()> {
1505 self.root().unsubscribe(id)
1506 }
1507
1508 fn syncing(&self) -> ProviderCall<NoParams, SyncStatus> {
1510 self.client().request_noparams("eth_syncing").into()
1511 }
1512
1513 #[doc(alias = "web3_client_version")]
1515 fn get_client_version(&self) -> ProviderCall<NoParams, String> {
1516 self.client().request_noparams("web3_clientVersion").into()
1517 }
1518
1519 #[doc(alias = "web3_sha3")]
1521 fn get_sha3(&self, data: &[u8]) -> ProviderCall<(String,), B256> {
1522 self.client().request("web3_sha3", (hex::encode_prefixed(data),)).into()
1523 }
1524
1525 fn get_net_version(&self) -> ProviderCall<NoParams, U64, u64> {
1527 self.client()
1528 .request_noparams("net_version")
1529 .map_resp(utils::convert_u64 as fn(U64) -> u64)
1530 .into()
1531 }
1532
1533 async fn raw_request<P, R>(&self, method: Cow<'static, str>, params: P) -> TransportResult<R>
1558 where
1559 P: RpcSend,
1560 R: RpcRecv,
1561 Self: Sized,
1562 {
1563 self.client().request(method, ¶ms).await
1564 }
1565
1566 async fn raw_request_dyn(
1589 &self,
1590 method: Cow<'static, str>,
1591 params: &RawValue,
1592 ) -> TransportResult<Box<RawValue>> {
1593 self.client().request(method, params).await
1594 }
1595
1596 #[inline]
1598 fn transaction_request(&self) -> N::TransactionRequest {
1599 Default::default()
1600 }
1601}
1602
1603#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
1604#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
1605impl<N: Network> Provider<N> for RootProvider<N> {
1606 #[inline]
1607 fn root(&self) -> &Self {
1608 self
1609 }
1610
1611 #[inline]
1612 fn client(&self) -> ClientRef<'_> {
1613 self.inner.client_ref()
1614 }
1615
1616 #[inline]
1617 fn weak_client(&self) -> WeakClient {
1618 self.inner.weak_client()
1619 }
1620
1621 #[inline]
1622 async fn watch_pending_transaction(
1623 &self,
1624 config: PendingTransactionConfig,
1625 ) -> Result<PendingTransaction, PendingTransactionError> {
1626 let block_number =
1627 if let Some(receipt) = self.get_transaction_receipt(*config.tx_hash()).await? {
1628 if config.required_confirmations() <= 1 {
1630 return Ok(PendingTransaction::ready(*config.tx_hash()));
1631 }
1632 receipt.block_number()
1635 } else {
1636 None
1637 };
1638
1639 self.get_heart()
1640 .watch_tx(config, block_number)
1641 .await
1642 .map_err(|_| PendingTransactionError::FailedToRegister)
1643 }
1644}
1645
1646#[cfg(test)]
1647mod tests {
1648 use super::*;
1649 use crate::{builder, ext::test::async_ci_only, ProviderBuilder, WalletProvider};
1650 use alloy_consensus::{Transaction, TxEnvelope};
1651 use alloy_network::{
1652 AnyNetwork, EthereumWallet, NetworkTransactionBuilder, TransactionBuilder,
1653 };
1654 use alloy_node_bindings::{utils::run_with_tempdir, Anvil, Reth};
1655 use alloy_primitives::{address, b256, bytes, keccak256};
1656 use alloy_rlp::Decodable;
1657 use alloy_rpc_client::{BuiltInConnectionString, RpcClient};
1658 use alloy_rpc_types_eth::{request::TransactionRequest, Block};
1659 use alloy_signer_local::PrivateKeySigner;
1660 use alloy_transport::layers::{RetryBackoffLayer, RetryPolicy};
1661 use std::{io::Read, str::FromStr, time::Duration};
1662
1663 use alloy_consensus::transaction::SignerRecoverable;
1665 #[cfg(feature = "hyper")]
1666 use alloy_transport_http::{
1667 hyper,
1668 hyper::body::Bytes as HyperBytes,
1669 hyper_util::{
1670 client::legacy::{Client, Error},
1671 rt::TokioExecutor,
1672 },
1673 HyperResponse, HyperResponseFut,
1674 };
1675 #[cfg(feature = "hyper")]
1676 use http_body_util::Full;
1677 #[cfg(feature = "hyper")]
1678 use tower::{Layer, Service};
1679
1680 #[tokio::test]
1681 async fn test_provider_builder() {
1682 let provider =
1683 RootProvider::<Ethereum>::builder().with_recommended_fillers().connect_anvil();
1684 let num = provider.get_block_number().await.unwrap();
1685 assert_eq!(0, num);
1686 }
1687
1688 #[tokio::test]
1689 async fn test_builder_helper_fn() {
1690 let provider = builder::<Ethereum>().with_recommended_fillers().connect_anvil();
1691 let num = provider.get_block_number().await.unwrap();
1692 assert_eq!(0, num);
1693 }
1694
1695 #[cfg(feature = "hyper")]
1696 #[tokio::test]
1697 async fn test_default_hyper_transport() {
1698 let anvil = Anvil::new().spawn();
1699 let hyper_t = alloy_transport_http::HyperTransport::new_hyper(anvil.endpoint_url());
1700
1701 let rpc_client = alloy_rpc_client::RpcClient::new(hyper_t, true);
1702
1703 let provider = RootProvider::<Ethereum>::new(rpc_client);
1704 let num = provider.get_block_number().await.unwrap();
1705 assert_eq!(0, num);
1706 }
1707
1708 #[cfg(feature = "hyper")]
1709 #[tokio::test]
1710 async fn test_hyper_layer_transport() {
1711 struct LoggingLayer;
1712
1713 impl<S> Layer<S> for LoggingLayer {
1714 type Service = LoggingService<S>;
1715
1716 fn layer(&self, inner: S) -> Self::Service {
1717 LoggingService { inner }
1718 }
1719 }
1720
1721 #[derive(Clone)] struct LoggingService<S> {
1723 inner: S,
1724 }
1725
1726 impl<S, B> Service<hyper::Request<B>> for LoggingService<S>
1727 where
1728 S: Service<hyper::Request<B>, Response = HyperResponse, Error = Error>
1729 + Clone
1730 + Send
1731 + Sync
1732 + 'static,
1733 S::Future: Send,
1734 S::Error: std::error::Error + Send + Sync + 'static,
1735 B: From<Vec<u8>> + Send + 'static + Clone + Sync + std::fmt::Debug,
1736 {
1737 type Response = HyperResponse;
1738 type Error = Error;
1739 type Future = HyperResponseFut;
1740
1741 fn poll_ready(
1742 &mut self,
1743 cx: &mut std::task::Context<'_>,
1744 ) -> std::task::Poll<Result<(), Self::Error>> {
1745 self.inner.poll_ready(cx)
1746 }
1747
1748 fn call(&mut self, req: hyper::Request<B>) -> Self::Future {
1749 println!("Logging Layer - HyperRequest {req:?}");
1750
1751 let fut = self.inner.call(req);
1752
1753 Box::pin(fut)
1754 }
1755 }
1756 use http::header::{self, HeaderValue};
1757 use tower_http::{
1758 sensitive_headers::SetSensitiveRequestHeadersLayer, set_header::SetRequestHeaderLayer,
1759 };
1760 let anvil = Anvil::new().spawn();
1761 let hyper_client = Client::builder(TokioExecutor::new()).build_http::<Full<HyperBytes>>();
1762
1763 let service = tower::ServiceBuilder::new()
1765 .layer(SetRequestHeaderLayer::if_not_present(
1766 header::USER_AGENT,
1767 HeaderValue::from_static("alloy app"),
1768 ))
1769 .layer(SetRequestHeaderLayer::overriding(
1770 header::AUTHORIZATION,
1771 HeaderValue::from_static("some-jwt-token"),
1772 ))
1773 .layer(SetRequestHeaderLayer::appending(
1774 header::SET_COOKIE,
1775 HeaderValue::from_static("cookie-value"),
1776 ))
1777 .layer(SetSensitiveRequestHeadersLayer::new([header::AUTHORIZATION])) .layer(LoggingLayer)
1779 .service(hyper_client);
1780
1781 let layer_transport = alloy_transport_http::HyperClient::with_service(service);
1782
1783 let http_hyper =
1784 alloy_transport_http::Http::with_client(layer_transport, anvil.endpoint_url());
1785
1786 let rpc_client = alloy_rpc_client::RpcClient::new(http_hyper, true);
1787
1788 let provider = RootProvider::<Ethereum>::new(rpc_client);
1789 let num = provider.get_block_number().await.unwrap();
1790 assert_eq!(0, num);
1791
1792 let cloned_t = provider.client().transport().clone();
1794
1795 let rpc_client = alloy_rpc_client::RpcClient::new(cloned_t, true);
1796
1797 let provider = RootProvider::<Ethereum>::new(rpc_client);
1798 let num = provider.get_block_number().await.unwrap();
1799 assert_eq!(0, num);
1800 }
1801
1802 #[cfg(feature = "hyper")]
1803 #[tokio::test]
1804 #[cfg_attr(windows, ignore = "no reth on windows")]
1805 async fn test_auth_layer_transport() {
1806 crate::ext::test::async_ci_only(|| async move {
1807 use alloy_node_bindings::Reth;
1808 use alloy_rpc_types_engine::JwtSecret;
1809 use alloy_transport_http::{AuthLayer, Http, HyperClient};
1810
1811 let secret = JwtSecret::random();
1812
1813 let reth =
1814 Reth::new().arg("--rpc.jwtsecret").arg(hex::encode(secret.as_bytes())).spawn();
1815
1816 let layer_transport = HyperClient::new().layer(AuthLayer::new(secret));
1817
1818 let http_hyper = Http::with_client(layer_transport, reth.endpoint_url());
1819
1820 let rpc_client = alloy_rpc_client::RpcClient::new(http_hyper, true);
1821
1822 let provider = RootProvider::<Ethereum>::new(rpc_client);
1823
1824 let num = provider.get_block_number().await.unwrap();
1825 assert_eq!(0, num);
1826 })
1827 .await;
1828 }
1829
1830 #[tokio::test]
1831 async fn test_builder_helper_fn_any_network() {
1832 let anvil = Anvil::new().spawn();
1833 let provider =
1834 builder::<AnyNetwork>().with_recommended_fillers().connect_http(anvil.endpoint_url());
1835 let num = provider.get_block_number().await.unwrap();
1836 assert_eq!(0, num);
1837 }
1838
1839 #[cfg(feature = "reqwest")]
1840 #[tokio::test]
1841 async fn object_safety() {
1842 let provider = ProviderBuilder::new().connect_anvil();
1843
1844 let refdyn = &provider as &dyn Provider<_>;
1845 let num = refdyn.get_block_number().await.unwrap();
1846 assert_eq!(0, num);
1847 }
1848
1849 #[cfg(feature = "ws")]
1850 #[tokio::test]
1851 async fn subscribe_blocks_http() {
1852 let provider = ProviderBuilder::new().connect_anvil_with_config(|a| a.block_time(1));
1853
1854 let err = provider.subscribe_blocks().await.unwrap_err();
1855 let alloy_json_rpc::RpcError::Transport(
1856 alloy_transport::TransportErrorKind::PubsubUnavailable,
1857 ) = err
1858 else {
1859 panic!("{err:?}");
1860 };
1861 }
1862
1863 #[cfg(feature = "ws")]
1865 #[tokio::test]
1866 async fn websocket_tls_setup() {
1867 for url in ["wss://mainnet.infura.io/ws/v3/b0f825787ba840af81e46c6a64d20754"] {
1868 let _ = ProviderBuilder::<_, _, Ethereum>::default().connect(url).await.unwrap();
1869 }
1870 }
1871
1872 #[cfg(feature = "ws")]
1873 #[tokio::test]
1874 async fn subscribe_blocks_ws() {
1875 use futures::stream::StreamExt;
1876
1877 let anvil = Anvil::new().block_time_f64(0.2).spawn();
1878 let ws = alloy_rpc_client::WsConnect::new(anvil.ws_endpoint());
1879 let client = alloy_rpc_client::RpcClient::connect_pubsub(ws).await.unwrap();
1880 let provider = RootProvider::<Ethereum>::new(client);
1881
1882 let sub = provider.subscribe_blocks().await.unwrap();
1883 let mut stream = sub.into_stream().take(5);
1884 let mut next = None;
1885 while let Some(header) = stream.next().await {
1886 if let Some(next) = &mut next {
1887 assert_eq!(header.number, *next);
1888 *next += 1;
1889 } else {
1890 next = Some(header.number + 1);
1891 }
1892 }
1893 }
1894
1895 #[cfg(feature = "ws")]
1896 #[tokio::test]
1897 async fn subscribe_full_blocks() {
1898 use futures::StreamExt;
1899
1900 let anvil = Anvil::new().block_time_f64(0.2).spawn();
1901 let ws = alloy_rpc_client::WsConnect::new(anvil.ws_endpoint());
1902 let client = alloy_rpc_client::RpcClient::connect_pubsub(ws).await.unwrap();
1903
1904 let provider = RootProvider::<Ethereum>::new(client);
1905
1906 let sub = provider.subscribe_full_blocks().hashes().channel_size(10);
1907
1908 let mut stream = sub.into_stream().await.unwrap().take(5);
1909
1910 let mut next = None;
1911 while let Some(Ok(block)) = stream.next().await {
1912 if let Some(next) = &mut next {
1913 assert_eq!(block.header().number, *next);
1914 *next += 1;
1915 } else {
1916 next = Some(block.header().number + 1);
1917 }
1918 }
1919 }
1920
1921 #[tokio::test]
1922 #[cfg(feature = "ws")]
1923 async fn subscribe_blocks_ws_remote() {
1924 use futures::stream::StreamExt;
1925
1926 let url = "wss://eth-mainnet.g.alchemy.com/v2/viFmeVzhg6bWKVMIWWS8MhmzREB-D4f7";
1927 let ws = alloy_rpc_client::WsConnect::new(url);
1928 let Ok(client) = alloy_rpc_client::RpcClient::connect_pubsub(ws).await else { return };
1929 let provider = RootProvider::<Ethereum>::new(client);
1930 let sub = provider.subscribe_blocks().await.unwrap();
1931 let mut stream = sub.into_stream().take(1);
1932 while let Some(header) = stream.next().await {
1933 println!("New block {header:?}");
1934 assert!(header.number > 0);
1935 }
1936 }
1937
1938 #[tokio::test]
1939 async fn test_custom_retry_policy() {
1940 #[derive(Debug, Clone)]
1941 struct CustomPolicy;
1942 impl RetryPolicy for CustomPolicy {
1943 fn should_retry(&self, _err: &alloy_transport::TransportError) -> bool {
1944 true
1945 }
1946
1947 fn backoff_hint(
1948 &self,
1949 _error: &alloy_transport::TransportError,
1950 ) -> Option<std::time::Duration> {
1951 None
1952 }
1953 }
1954
1955 let retry_layer = RetryBackoffLayer::new_with_policy(10, 100, 10000, CustomPolicy);
1956 let anvil = Anvil::new().spawn();
1957 let client = RpcClient::builder().layer(retry_layer).http(anvil.endpoint_url());
1958
1959 let provider = RootProvider::<Ethereum>::new(client);
1960 let num = provider.get_block_number().await.unwrap();
1961 assert_eq!(0, num);
1962 }
1963
1964 #[tokio::test]
1965 async fn test_send_tx() {
1966 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
1967 let tx = TransactionRequest {
1968 value: Some(U256::from(100)),
1969 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
1970 gas_price: Some(20e9 as u128),
1971 gas: Some(21000),
1972 ..Default::default()
1973 };
1974
1975 let builder = provider.send_transaction(tx.clone()).await.expect("failed to send tx");
1976 let hash1 = *builder.tx_hash();
1977 let hash2 = builder.watch().await.expect("failed to await pending tx");
1978 assert_eq!(hash1, hash2);
1979
1980 let builder = provider.send_transaction(tx).await.expect("failed to send tx");
1981 let hash1 = *builder.tx_hash();
1982 let hash2 =
1983 builder.get_receipt().await.expect("failed to await pending tx").transaction_hash;
1984 assert_eq!(hash1, hash2);
1985 }
1986
1987 #[tokio::test]
1988 async fn test_send_tx_sync() {
1989 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
1990 let tx = TransactionRequest {
1991 value: Some(U256::from(100)),
1992 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
1993 gas_price: Some(20e9 as u128),
1994 gas: Some(21000),
1995 ..Default::default()
1996 };
1997
1998 let _receipt =
1999 provider.send_transaction_sync(tx.clone()).await.expect("failed to send tx sync");
2000 }
2001
2002 #[tokio::test]
2003 async fn test_send_raw_transaction_sync() {
2004 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
2005
2006 let tx = TransactionRequest {
2008 nonce: Some(0),
2009 value: Some(U256::from(100)),
2010 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
2011 gas_price: Some(20e9 as u128),
2012 gas: Some(21000),
2013 ..Default::default()
2014 };
2015
2016 let tx_envelope = tx.build(&provider.wallet()).await.expect("failed to build tx");
2018
2019 let encoded = tx_envelope.encoded_2718();
2021
2022 let receipt =
2024 provider.send_raw_transaction_sync(&encoded).await.expect("failed to send raw tx sync");
2025
2026 assert_eq!(receipt.to(), Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045")));
2028 assert!(receipt.block_number().is_some(), "transaction should be mined");
2030 assert!(receipt.transaction_hash() != B256::ZERO, "should have valid tx hash");
2031 }
2032
2033 #[tokio::test]
2034 async fn test_watch_confirmed_tx() {
2035 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
2036 let tx = TransactionRequest {
2037 value: Some(U256::from(100)),
2038 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
2039 gas_price: Some(20e9 as u128),
2040 gas: Some(21000),
2041 ..Default::default()
2042 };
2043
2044 let builder = provider.send_transaction(tx).await.expect("failed to send tx");
2045 let hash1 = *builder.tx_hash();
2046
2047 loop {
2049 if provider
2050 .get_transaction_receipt(hash1)
2051 .await
2052 .expect("failed to await pending tx")
2053 .is_some()
2054 {
2055 break;
2056 }
2057 }
2058
2059 let tx2 = TransactionRequest {
2061 value: Some(U256::from(100)),
2062 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
2063 gas_price: Some(20e9 as u128),
2064 gas: Some(21000),
2065 ..Default::default()
2066 };
2067 provider.send_transaction(tx2).await.expect("failed to send tx").watch().await.unwrap();
2068
2069 let watch = builder.watch();
2071 let watch_with_timeout = tokio::time::timeout(Duration::from_secs(1), watch);
2073 let hash2 = watch_with_timeout
2074 .await
2075 .expect("Watching tx timed out")
2076 .expect("failed to await pending tx");
2077 assert_eq!(hash1, hash2);
2078 }
2079
2080 #[tokio::test]
2081 async fn gets_block_number() {
2082 let provider = ProviderBuilder::new().connect_anvil();
2083 let num = provider.get_block_number().await.unwrap();
2084 assert_eq!(0, num)
2085 }
2086
2087 #[tokio::test]
2088 async fn gets_block_number_for_id() {
2089 let provider = ProviderBuilder::new().connect_anvil();
2090
2091 let block_num = provider
2092 .get_block_number_by_id(BlockId::Number(BlockNumberOrTag::Number(0)))
2093 .await
2094 .unwrap();
2095 assert_eq!(block_num, Some(0));
2096
2097 let block_num = provider
2098 .get_block_number_by_id(BlockId::Number(BlockNumberOrTag::Latest))
2099 .await
2100 .unwrap();
2101 assert_eq!(block_num, Some(0));
2102
2103 let block =
2104 provider.get_block_by_number(BlockNumberOrTag::Number(0)).await.unwrap().unwrap();
2105 let hash = block.header.hash;
2106 let block_num = provider.get_block_number_by_id(BlockId::Hash(hash.into())).await.unwrap();
2107 assert_eq!(block_num, Some(0));
2108 }
2109
2110 #[tokio::test]
2111 async fn gets_block_number_with_raw_req() {
2112 let provider = ProviderBuilder::new().connect_anvil();
2113 let num: U64 =
2114 provider.raw_request("eth_blockNumber".into(), NoParams::default()).await.unwrap();
2115 assert_eq!(0, num.to::<u64>())
2116 }
2117
2118 #[cfg(feature = "anvil-api")]
2119 #[tokio::test]
2120 async fn gets_transaction_count() {
2121 let provider = ProviderBuilder::new().connect_anvil();
2122 let accounts = provider.get_accounts().await.unwrap();
2123 let sender = accounts[0];
2124
2125 let count = provider.get_transaction_count(sender).await.unwrap();
2127 assert_eq!(count, 0);
2128
2129 let tx = TransactionRequest {
2131 value: Some(U256::from(100)),
2132 from: Some(sender),
2133 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
2134 gas_price: Some(20e9 as u128),
2135 gas: Some(21000),
2136 ..Default::default()
2137 };
2138 let _ = provider.send_transaction(tx).await.unwrap().get_receipt().await;
2139
2140 let count = provider.get_transaction_count(sender).await.unwrap();
2142 assert_eq!(count, 1);
2143
2144 let count = provider.get_transaction_count(sender).block_id(0.into()).await.unwrap();
2146 assert_eq!(count, 0);
2147 }
2148
2149 #[tokio::test]
2150 async fn gets_block_by_hash() {
2151 let provider = ProviderBuilder::new().connect_anvil();
2152 let num = 0;
2153 let tag: BlockNumberOrTag = num.into();
2154 let block = provider.get_block_by_number(tag).full().await.unwrap().unwrap();
2155 let hash = block.header.hash;
2156 let block = provider.get_block_by_hash(hash).full().await.unwrap().unwrap();
2157 assert_eq!(block.header.hash, hash);
2158 }
2159
2160 #[tokio::test]
2161 async fn gets_block_by_hash_with_raw_req() {
2162 let provider = ProviderBuilder::new().connect_anvil();
2163 let num = 0;
2164 let tag: BlockNumberOrTag = num.into();
2165 let block = provider.get_block_by_number(tag).full().await.unwrap().unwrap();
2166 let hash = block.header.hash;
2167 let block: Block = provider
2168 .raw_request::<(B256, bool), Block>("eth_getBlockByHash".into(), (hash, true))
2169 .await
2170 .unwrap();
2171 assert_eq!(block.header.hash, hash);
2172 }
2173
2174 #[tokio::test]
2175 async fn gets_block_by_number_full() {
2176 let provider = ProviderBuilder::new().connect_anvil();
2177 let num = 0;
2178 let tag: BlockNumberOrTag = num.into();
2179 let block = provider.get_block_by_number(tag).full().await.unwrap().unwrap();
2180 assert_eq!(block.header.number, num);
2181 }
2182
2183 #[tokio::test]
2184 async fn gets_block_by_number() {
2185 let provider = ProviderBuilder::new().connect_anvil();
2186 let num = 0;
2187 let tag: BlockNumberOrTag = num.into();
2188 let block = provider.get_block_by_number(tag).full().await.unwrap().unwrap();
2189 assert_eq!(block.header.number, num);
2190 }
2191
2192 #[tokio::test]
2193 async fn gets_client_version() {
2194 let provider = ProviderBuilder::new().connect_anvil();
2195 let version = provider.get_client_version().await.unwrap();
2196 assert!(version.contains("anvil"), "{version}");
2197 }
2198
2199 #[tokio::test]
2200 async fn gets_sha3() {
2201 let provider = ProviderBuilder::new().connect_anvil();
2202 let data = b"alloy";
2203 let hash = provider.get_sha3(data).await.unwrap();
2204 assert_eq!(hash, keccak256(data));
2205 }
2206
2207 #[tokio::test]
2208 async fn gets_chain_id() {
2209 let dev_chain_id: u64 = 13371337;
2210
2211 let provider =
2212 ProviderBuilder::new().connect_anvil_with_config(|a| a.chain_id(dev_chain_id));
2213
2214 let chain_id = provider.get_chain_id().await.unwrap();
2215 assert_eq!(chain_id, dev_chain_id);
2216 }
2217
2218 #[tokio::test]
2219 async fn gets_network_id() {
2220 let dev_chain_id: u64 = 13371337;
2221 let provider =
2222 ProviderBuilder::new().connect_anvil_with_config(|a| a.chain_id(dev_chain_id));
2223
2224 let chain_id = provider.get_net_version().await.unwrap();
2225 assert_eq!(chain_id, dev_chain_id);
2226 }
2227
2228 #[tokio::test]
2229 async fn gets_storage_at() {
2230 let provider = ProviderBuilder::new().connect_anvil();
2231 let addr = Address::with_last_byte(16);
2232 let storage = provider.get_storage_at(addr, U256::ZERO).await.unwrap();
2233 assert_eq!(storage, U256::ZERO);
2234 }
2235
2236 #[tokio::test]
2237 async fn gets_transaction_by_hash_not_found() {
2238 let provider = ProviderBuilder::new().connect_anvil();
2239 let tx_hash = b256!("5c03fab9114ceb98994b43892ade87ddfd9ae7e8f293935c3bd29d435dc9fd95");
2240 let tx = provider.get_transaction_by_hash(tx_hash).await.expect("failed to fetch tx");
2241
2242 assert!(tx.is_none());
2243 }
2244
2245 #[tokio::test]
2246 async fn gets_transaction_by_hash() {
2247 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
2248
2249 let req = TransactionRequest::default()
2250 .from(provider.default_signer_address())
2251 .to(Address::repeat_byte(5))
2252 .value(U256::ZERO)
2253 .input(bytes!("deadbeef").into());
2254
2255 let tx_hash = *provider.send_transaction(req).await.expect("failed to send tx").tx_hash();
2256
2257 let tx = provider
2258 .get_transaction_by_hash(tx_hash)
2259 .await
2260 .expect("failed to fetch tx")
2261 .expect("tx not included");
2262 assert_eq!(tx.input(), &bytes!("deadbeef"));
2263 }
2264
2265 #[tokio::test]
2266 #[ignore]
2267 async fn gets_logs() {
2268 let provider = ProviderBuilder::new().connect_anvil();
2269 let filter = Filter::new()
2270 .at_block_hash(b256!(
2271 "b20e6f35d4b46b3c4cd72152faec7143da851a0dc281d390bdd50f58bfbdb5d3"
2272 ))
2273 .event_signature(b256!(
2274 "e1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c"
2275 ));
2276 let logs = provider.get_logs(&filter).await.unwrap();
2277 assert_eq!(logs.len(), 1);
2278 }
2279
2280 #[tokio::test]
2281 #[ignore]
2282 async fn gets_tx_receipt() {
2283 let provider = ProviderBuilder::new().connect_anvil();
2284 let receipt = provider
2285 .get_transaction_receipt(b256!(
2286 "5c03fab9114ceb98994b43892ade87ddfd9ae7e8f293935c3bd29d435dc9fd95"
2287 ))
2288 .await
2289 .unwrap();
2290 assert!(receipt.is_some());
2291 let receipt = receipt.unwrap();
2292 assert_eq!(
2293 receipt.transaction_hash,
2294 b256!("5c03fab9114ceb98994b43892ade87ddfd9ae7e8f293935c3bd29d435dc9fd95")
2295 );
2296 }
2297
2298 #[tokio::test]
2299 async fn gets_max_priority_fee_per_gas() {
2300 let provider = ProviderBuilder::new().connect_anvil();
2301 let _fee = provider.get_max_priority_fee_per_gas().await.unwrap();
2302 }
2303
2304 #[tokio::test]
2305 async fn gets_fee_history() {
2306 let provider = ProviderBuilder::new().connect_anvil();
2307 let block_number = provider.get_block_number().await.unwrap();
2308 let fee_history = provider
2309 .get_fee_history(
2310 utils::EIP1559_FEE_ESTIMATION_PAST_BLOCKS,
2311 BlockNumberOrTag::Number(block_number),
2312 &[utils::EIP1559_FEE_ESTIMATION_REWARD_PERCENTILE],
2313 )
2314 .await
2315 .unwrap();
2316 assert_eq!(fee_history.oldest_block, 0_u64);
2317 }
2318
2319 #[tokio::test]
2320 async fn gets_block_transaction_count_by_hash() {
2321 let provider = ProviderBuilder::new().connect_anvil();
2322 let block = provider.get_block(BlockId::latest()).await.unwrap().unwrap();
2323 let hash = block.header.hash;
2324 let tx_count = provider.get_block_transaction_count_by_hash(hash).await.unwrap();
2325 assert!(tx_count.is_some());
2326 }
2327
2328 #[tokio::test]
2329 async fn gets_block_transaction_count_by_number() {
2330 let provider = ProviderBuilder::new().connect_anvil();
2331 let tx_count =
2332 provider.get_block_transaction_count_by_number(BlockNumberOrTag::Latest).await.unwrap();
2333 assert!(tx_count.is_some());
2334 }
2335
2336 #[tokio::test]
2337 async fn gets_block_receipts() {
2338 let provider = ProviderBuilder::new().connect_anvil();
2339 let receipts =
2340 provider.get_block_receipts(BlockId::Number(BlockNumberOrTag::Latest)).await.unwrap();
2341 assert!(receipts.is_some());
2342 }
2343
2344 #[tokio::test]
2345 async fn sends_raw_transaction() {
2346 let provider = ProviderBuilder::new().connect_anvil();
2347 let pending = provider
2348 .send_raw_transaction(
2349 bytes!("f865808477359400825208940000000000000000000000000000000000000000018082f4f5a00505e227c1c636c76fac55795db1a40a4d24840d81b40d2fe0cc85767f6bd202a01e91b437099a8a90234ac5af3cb7ca4fb1432e133f75f9a91678eaf5f487c74b").as_ref()
2351 )
2352 .await.unwrap();
2353 assert_eq!(
2354 pending.tx_hash().to_string(),
2355 "0x9dae5cf33694a02e8a7d5de3fe31e9d05ca0ba6e9180efac4ab20a06c9e598a3"
2356 );
2357 }
2358
2359 #[tokio::test]
2360 async fn connect_boxed() {
2361 let anvil = Anvil::new().spawn();
2362
2363 let provider = RootProvider::<Ethereum>::connect(anvil.endpoint().as_str()).await;
2364
2365 match provider {
2366 Ok(provider) => {
2367 let num = provider.get_block_number().await.unwrap();
2368 assert_eq!(0, num);
2369 }
2370 Err(e) => {
2371 assert_eq!(
2372 format!("{e}"),
2373 "hyper not supported by BuiltinConnectionString. Please instantiate a hyper client manually"
2374 );
2375 }
2376 }
2377 }
2378
2379 #[tokio::test]
2380 async fn any_network_wallet_filler() {
2381 use alloy_serde::WithOtherFields;
2382 let anvil = Anvil::new().spawn();
2383 let signer: PrivateKeySigner =
2384 "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80".parse().unwrap();
2385 let wallet = EthereumWallet::from(signer);
2386
2387 let provider = ProviderBuilder::new()
2388 .network::<AnyNetwork>()
2389 .wallet(wallet)
2390 .connect_http(anvil.endpoint_url());
2391
2392 let tx = TransactionRequest::default()
2393 .with_to(address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"))
2394 .value(U256::from(325235));
2395
2396 let tx = WithOtherFields::new(tx);
2397
2398 let builder = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();
2399
2400 assert!(builder.status());
2401 }
2402
2403 #[tokio::test]
2404 async fn builtin_connect_boxed() {
2405 let anvil = Anvil::new().spawn();
2406
2407 let conn: BuiltInConnectionString = anvil.endpoint().parse().unwrap();
2408
2409 let transport = conn.connect_boxed().await.unwrap();
2410
2411 let client = alloy_rpc_client::RpcClient::new(transport, true);
2412
2413 let provider = RootProvider::<Ethereum>::new(client);
2414
2415 let num = provider.get_block_number().await.unwrap();
2416 assert_eq!(0, num);
2417 }
2418
2419 #[tokio::test]
2420 async fn test_uncle_count() {
2421 let provider = ProviderBuilder::new().connect_anvil();
2422
2423 let count = provider.get_uncle_count(0.into()).await.unwrap();
2424 assert_eq!(count, 0);
2425 }
2426
2427 #[tokio::test]
2428 #[cfg(any(
2429 feature = "reqwest-default-tls",
2430 feature = "reqwest-rustls-tls",
2431 feature = "reqwest-native-tls",
2432 ))]
2433 #[ignore = "ignore until <https://github.com/paradigmxyz/reth/pull/14727> is in"]
2434 async fn call_mainnet() {
2435 use alloy_network::TransactionBuilder;
2436 use alloy_sol_types::SolValue;
2437
2438 let url = "https://docs-demo.quiknode.pro/";
2439 let provider = ProviderBuilder::new().connect_http(url.parse().unwrap());
2440 let req = TransactionRequest::default()
2441 .with_to(address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")) .with_input(bytes!("06fdde03")); let result = provider.call(req.clone()).await.unwrap();
2444 assert_eq!(String::abi_decode(&result).unwrap(), "Wrapped Ether");
2445
2446 let result = provider.call(req).block(0.into()).await.unwrap();
2447 assert_eq!(result.to_string(), "0x");
2448 }
2449
2450 #[tokio::test]
2451 async fn call_many_mainnet() {
2452 use alloy_rpc_types_eth::{BlockOverrides, StateContext};
2453
2454 let url = "https://docs-demo.quiknode.pro/";
2455 let provider = ProviderBuilder::new().connect_http(url.parse().unwrap());
2456 let tx1 = TransactionRequest::default()
2457 .with_to(address!("6b175474e89094c44da98b954eedeac495271d0f"))
2458 .with_gas_limit(1000000)
2459 .with_gas_price(2023155498)
2460 .with_input(hex!("a9059cbb000000000000000000000000bc0E63965946815d105E7591407704e6e1964E590000000000000000000000000000000000000000000000000000000005f5e100"));
2461 let tx2 = TransactionRequest::default()
2462 .with_to(address!("833589fcd6edb6e08f4c7c32d4f71b54bda02913"))
2463 .with_gas_price(2023155498)
2464 .with_input(hex!(
2465 "70a08231000000000000000000000000bc0E63965946815d105E7591407704e6e1964E59"
2466 ));
2467
2468 let transactions = vec![tx1.clone(), tx2.clone()];
2469
2470 let block_override =
2471 BlockOverrides { number: Some(U256::from(12279785)), ..Default::default() };
2472
2473 let bundles = vec![Bundle { transactions, block_override: Some(block_override.clone()) }];
2474
2475 let context = StateContext {
2476 block_number: Some(BlockId::number(12279785)),
2477 transaction_index: Some(1.into()),
2478 };
2479
2480 let results = provider.call_many(&bundles).context(&context).await.unwrap();
2481
2482 let tx1_res = EthCallResponse {
2483 value: Some(
2484 hex!("0000000000000000000000000000000000000000000000000000000000000001").into(),
2485 ),
2486 error: None,
2487 };
2488 let tx2_res = EthCallResponse { value: Some(Bytes::new()), error: None };
2489 let expected = vec![vec![tx1_res.clone(), tx2_res.clone()]];
2490
2491 assert_eq!(results, expected);
2492
2493 let bundles = vec![
2495 Bundle {
2496 transactions: vec![tx1.clone()],
2497 block_override: Some(block_override.clone()),
2498 },
2499 Bundle {
2500 transactions: vec![tx2.clone()],
2501 block_override: Some(block_override.clone()),
2502 },
2503 ];
2504
2505 let results = provider.call_many(&bundles).context(&context).await.unwrap();
2506 let expected = vec![vec![tx1_res.clone()], vec![tx2_res.clone()]];
2507 assert_eq!(results, expected);
2508
2509 let b1 =
2511 vec![Bundle { transactions: vec![tx1], block_override: Some(block_override.clone()) }];
2512 let b2 = vec![Bundle { transactions: vec![tx2], block_override: Some(block_override) }];
2513
2514 let results = provider.call_many(&b1).context(&context).extend_bundles(&b2).await.unwrap();
2515 assert_eq!(results, expected);
2516 }
2517
2518 #[tokio::test]
2519 #[cfg(feature = "hyper-tls")]
2520 async fn hyper_https() {
2521 let url = "https://ethereum.reth.rs/rpc";
2522
2523 let provider = ProviderBuilder::new().connect(url).await.unwrap();
2526
2527 let _num = provider.get_block_number().await.unwrap();
2528 }
2529
2530 #[tokio::test]
2531 async fn test_empty_transactions() {
2532 let provider = ProviderBuilder::new().connect_anvil();
2533
2534 let block = provider.get_block_by_number(0.into()).await.unwrap().unwrap();
2535 assert!(block.transactions.is_hashes());
2536 }
2537
2538 #[tokio::test]
2539 async fn disable_test() {
2540 let provider = ProviderBuilder::new()
2541 .disable_recommended_fillers()
2542 .with_cached_nonce_management()
2543 .connect_anvil();
2544
2545 let tx = TransactionRequest::default()
2546 .with_kind(alloy_primitives::TxKind::Create)
2547 .value(U256::from(1235))
2548 .with_input(Bytes::from_str("ffffffffffffff").unwrap());
2549
2550 let err = provider.send_transaction(tx).await.unwrap_err().to_string();
2551 assert!(err.contains("missing properties: [(\"NonceManager\", [\"from\"])]"));
2552 }
2553
2554 #[tokio::test]
2555 async fn capture_anvil_logs() {
2556 let mut anvil = Anvil::new().keep_stdout().spawn();
2557
2558 let provider = ProviderBuilder::new().connect_http(anvil.endpoint_url());
2559
2560 let tx = TransactionRequest::default()
2561 .with_from(address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"))
2562 .with_to(address!("70997970C51812dc3A010C7d01b50e0d17dc79C8"))
2563 .value(U256::from(100));
2564
2565 let _ = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();
2566
2567 anvil.child_mut().kill().unwrap();
2568
2569 let mut output = String::new();
2570 anvil.child_mut().stdout.take().unwrap().read_to_string(&mut output).unwrap();
2571
2572 assert_eq!(anvil.chain_id(), 31337);
2573 assert_eq!(anvil.addresses().len(), 10);
2574 assert_eq!(anvil.keys().len(), 10);
2575
2576 assert!(output.contains("eth_sendTransaction"));
2577 assert!(output.contains("Block Number: 1"))
2578 }
2579
2580 #[tokio::test]
2581 async fn custom_estimator() {
2582 let provider = ProviderBuilder::new()
2583 .disable_recommended_fillers()
2584 .with_cached_nonce_management()
2585 .connect_anvil();
2586
2587 let _ = provider
2588 .estimate_eip1559_fees_with(Eip1559Estimator::new(|_fee, _rewards| Eip1559Estimation {
2589 max_fee_per_gas: 0,
2590 max_priority_fee_per_gas: 0,
2591 }))
2592 .await;
2593 }
2594
2595 #[tokio::test]
2596 #[cfg(not(windows))]
2597 async fn eth_sign_transaction() {
2598 async_ci_only(|| async {
2599 run_with_tempdir("reth-sign-tx", |dir| async {
2600 let reth = Reth::new().dev().disable_discovery().data_dir(dir).spawn();
2601 let provider = ProviderBuilder::new().connect_http(reth.endpoint_url());
2602
2603 let accounts = provider.get_accounts().await.unwrap();
2604 let from = accounts[0];
2605
2606 let tx = TransactionRequest::default()
2607 .from(from)
2608 .to(Address::random())
2609 .value(U256::from(100))
2610 .gas_limit(21000);
2611
2612 let signed_tx = provider.sign_transaction(tx).await.unwrap().to_vec();
2613
2614 let tx = TxEnvelope::decode(&mut signed_tx.as_slice()).unwrap();
2615
2616 let signer = tx.recover_signer().unwrap();
2617
2618 assert_eq!(signer, from);
2619 })
2620 .await
2621 })
2622 .await;
2623 }
2624
2625 #[cfg(feature = "throttle")]
2626 use alloy_transport::layers::ThrottleLayer;
2627
2628 #[cfg(feature = "throttle")]
2629 #[tokio::test]
2630 async fn test_throttled_provider() {
2631 let request_per_second = 10;
2632 let throttle_layer = ThrottleLayer::new(request_per_second);
2633
2634 let anvil = Anvil::new().spawn();
2635 let client = RpcClient::builder().layer(throttle_layer).http(anvil.endpoint_url());
2636 let provider = RootProvider::<Ethereum>::new(client);
2637
2638 let num_requests = 10;
2639 let start = std::time::Instant::now();
2640 for _ in 0..num_requests {
2641 provider.get_block_number().await.unwrap();
2642 }
2643
2644 let elapsed = start.elapsed();
2645 assert_eq!(elapsed.as_secs_f64().round() as u32, 1);
2646 }
2647
2648 #[tokio::test]
2649 #[cfg(feature = "hyper")]
2650 async fn test_connect_hyper_tls() {
2651 let p = ProviderBuilder::new().connect("https://ethereum.reth.rs/rpc").await.unwrap();
2652
2653 let _num = p.get_block_number().await.unwrap();
2654
2655 let anvil = Anvil::new().spawn();
2656 let p = ProviderBuilder::new().connect(&anvil.endpoint()).await.unwrap();
2657
2658 let _num = p.get_block_number().await.unwrap();
2659 }
2660
2661 #[tokio::test]
2662 async fn test_send_transaction_sync() {
2663 use alloy_network::TransactionBuilder;
2664 use alloy_primitives::{address, U256};
2665
2666 let anvil = Anvil::new().spawn();
2667 let provider = ProviderBuilder::new().connect_http(anvil.endpoint_url());
2668
2669 let tx = TransactionRequest::default()
2670 .with_from(address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"))
2671 .with_to(address!("70997970C51812dc3A010C7d01b50e0d17dc79C8"))
2672 .with_value(U256::from(100));
2673
2674 let receipt = provider.send_transaction_sync(tx).await.unwrap();
2676
2677 let tx_hash = receipt.transaction_hash;
2679 assert!(!tx_hash.is_zero());
2680 assert_eq!(receipt.transaction_hash, tx_hash);
2681 assert!(receipt.status());
2682 }
2683
2684 #[tokio::test]
2685 async fn test_send_transaction_sync_with_fillers() {
2686 use alloy_network::TransactionBuilder;
2687 use alloy_primitives::{address, U256};
2688
2689 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
2690
2691 let tx = TransactionRequest::default()
2693 .with_from(provider.default_signer_address())
2694 .with_to(address!("70997970C51812dc3A010C7d01b50e0d17dc79C8"))
2695 .with_value(U256::from(100));
2696 let receipt = provider.send_transaction_sync(tx).await.unwrap();
2700
2701 let tx_hash = receipt.transaction_hash;
2703 assert!(!tx_hash.is_zero());
2704
2705 assert_eq!(receipt.transaction_hash, tx_hash);
2707 assert!(receipt.status());
2708 assert!(receipt.gas_used() > 0, "fillers should have estimated gas");
2709 }
2710
2711 #[tokio::test]
2712 async fn test_fill_transaction() {
2713 use alloy_network::TransactionBuilder;
2714 use alloy_primitives::{address, U256};
2715
2716 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
2717
2718 let tx = TransactionRequest::default()
2719 .with_from(provider.default_signer_address())
2720 .with_to(address!("70997970C51812dc3A010C7d01b50e0d17dc79C8"))
2721 .with_value(U256::from(100));
2722
2723 let filled = provider.fill_transaction(tx).await.unwrap();
2724
2725 assert!(!filled.raw.is_empty(), "raw transaction bytes should not be empty");
2727
2728 let filled_tx = &filled.tx;
2730 assert!(filled_tx.to().is_some(), "filled transaction should have to address");
2731 assert!(filled_tx.gas_limit() > 0, "filled transaction should have gas limit");
2732 assert!(filled_tx.max_fee_per_gas() > 0, "filled transaction should have max fee per gas");
2733 }
2734}