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;
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(&self, block: BlockId) -> TransportResult<Option<Bytes>> {
473 match block {
474 BlockId::Hash(hash) => self.get_block_access_list_by_hash(hash.block_hash).await,
475 BlockId::Number(number) => self.get_block_access_list_by_number(number).await,
476 }
477 }
478
479 async fn get_block_access_list_by_hash(
483 &self,
484 hash: BlockHash,
485 ) -> TransportResult<Option<Bytes>> {
486 self.client().request("eth_getBlockAccessListByBlockHash", (hash,)).await
487 }
488
489 async fn get_block_access_list_by_number(
493 &self,
494 number: BlockNumberOrTag,
495 ) -> TransportResult<Option<Bytes>> {
496 self.client().request("eth_getBlockAccessListByBlockNumber", (number,)).await
497 }
498
499 async fn get_header(&self, block: BlockId) -> TransportResult<Option<N::HeaderResponse>> {
520 match block {
521 BlockId::Hash(hash) => self.get_header_by_hash(hash.block_hash).await,
522 BlockId::Number(number) => self.get_header_by_number(number).await,
523 }
524 }
525
526 async fn get_header_by_hash(
545 &self,
546 hash: BlockHash,
547 ) -> TransportResult<Option<N::HeaderResponse>> {
548 match self.client().request("eth_getHeaderByHash", (hash,)).await {
549 Ok(header) => Ok(header),
550 Err(err) if err.as_error_resp().is_some_and(|e| e.code == -32601) => {
552 Ok(self.get_block_by_hash(hash).await?.map(|b| b.header().clone()))
553 }
554 Err(err) => Err(err),
555 }
556 }
557
558 async fn get_header_by_number(
579 &self,
580 number: BlockNumberOrTag,
581 ) -> TransportResult<Option<N::HeaderResponse>> {
582 match self.client().request("eth_getHeaderByNumber", (number,)).await {
583 Ok(header) => Ok(header),
584 Err(err) if err.as_error_resp().is_some_and(|e| e.code == -32601) => {
586 Ok(self.get_block_by_number(number).await?.map(|b| b.header().clone()))
587 }
588 Err(err) => Err(err),
589 }
590 }
591
592 fn get_code_at(&self, address: Address) -> RpcWithBlock<Address, Bytes> {
594 self.client().request("eth_getCode", address).into()
595 }
596
597 async fn watch_blocks(&self) -> TransportResult<FilterPollerBuilder<B256>> {
620 let id = self.new_block_filter().await?;
621 Ok(PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,)))
622 }
623
624 async fn watch_full_blocks(&self) -> TransportResult<WatchBlocks<N::BlockResponse>> {
648 let id = self.new_block_filter().await?;
649 let poller = PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,));
650
651 Ok(WatchBlocks::new(poller))
652 }
653
654 async fn watch_headers(&self) -> TransportResult<WatchHeaders<N::HeaderResponse>> {
681 let id = self.new_block_filter().await?;
682 let poller = PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,));
683
684 Ok(WatchHeaders::new(poller))
685 }
686
687 async fn watch_pending_transactions(&self) -> TransportResult<FilterPollerBuilder<B256>> {
710 let id = self.new_pending_transactions_filter(false).await?;
711 Ok(PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,)))
712 }
713
714 async fn watch_logs(&self, filter: &Filter) -> TransportResult<FilterPollerBuilder<Log>> {
743 let id = self.new_filter(filter).await?;
744 Ok(PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,)))
745 }
746
747 async fn watch_full_pending_transactions(
774 &self,
775 ) -> TransportResult<FilterPollerBuilder<N::TransactionResponse>> {
776 let id = self.new_pending_transactions_filter(true).await?;
777 Ok(PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,)))
778 }
779
780 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
785 async fn get_filter_changes<R: RpcRecv>(&self, id: U256) -> TransportResult<Vec<R>>
786 where
787 Self: Sized,
788 {
789 self.client().request("eth_getFilterChanges", (id,)).await
790 }
791
792 async fn get_filter_changes_dyn(&self, id: U256) -> TransportResult<FilterChanges> {
797 self.client().request("eth_getFilterChanges", (id,)).await
798 }
799
800 async fn get_filter_logs(&self, id: U256) -> TransportResult<Vec<Log>> {
802 self.client().request("eth_getFilterLogs", (id,)).await
803 }
804
805 async fn uninstall_filter(&self, id: U256) -> TransportResult<bool> {
807 self.client().request("eth_uninstallFilter", (id,)).await
808 }
809
810 #[inline]
815 async fn watch_pending_transaction(
816 &self,
817 config: PendingTransactionConfig,
818 ) -> Result<PendingTransaction, PendingTransactionError> {
819 self.root().watch_pending_transaction(config).await
820 }
821
822 async fn get_logs(&self, filter: &Filter) -> TransportResult<Vec<Log>> {
824 self.client().request("eth_getLogs", (filter,)).await
825 }
826
827 fn get_proof(
831 &self,
832 address: Address,
833 keys: Vec<StorageKey>,
834 ) -> RpcWithBlock<(Address, Vec<StorageKey>), EIP1186AccountProofResponse> {
835 self.client().request("eth_getProof", (address, keys)).into()
836 }
837
838 fn get_storage_at(
840 &self,
841 address: Address,
842 key: U256,
843 ) -> RpcWithBlock<(Address, U256), StorageValue> {
844 self.client().request("eth_getStorageAt", (address, key)).into()
845 }
846
847 fn get_storage_values(
851 &self,
852 requests: StorageValuesRequest,
853 ) -> RpcWithBlock<(StorageValuesRequest,), StorageValuesResponse> {
854 self.client().request("eth_getStorageValues", (requests,)).into()
855 }
856
857 fn get_transaction_by_sender_nonce(
861 &self,
862 sender: Address,
863 nonce: u64,
864 ) -> ProviderCall<(Address, U64), Option<N::TransactionResponse>> {
865 self.client()
866 .request("eth_getTransactionBySenderAndNonce", (sender, U64::from(nonce)))
867 .into()
868 }
869
870 fn get_transaction_by_hash(
872 &self,
873 hash: TxHash,
874 ) -> ProviderCall<(TxHash,), Option<N::TransactionResponse>> {
875 self.client().request("eth_getTransactionByHash", (hash,)).into()
876 }
877
878 fn get_transaction_by_block_hash_and_index(
880 &self,
881 block_hash: B256,
882 index: usize,
883 ) -> ProviderCall<(B256, Index), Option<N::TransactionResponse>> {
884 self.client()
885 .request("eth_getTransactionByBlockHashAndIndex", (block_hash, Index(index)))
886 .into()
887 }
888
889 fn get_raw_transaction_by_block_hash_and_index(
891 &self,
892 block_hash: B256,
893 index: usize,
894 ) -> ProviderCall<(B256, Index), Option<Bytes>> {
895 self.client()
896 .request("eth_getRawTransactionByBlockHashAndIndex", (block_hash, Index(index)))
897 .into()
898 }
899
900 fn get_transaction_by_block_number_and_index(
902 &self,
903 block_number: BlockNumberOrTag,
904 index: usize,
905 ) -> ProviderCall<(BlockNumberOrTag, Index), Option<N::TransactionResponse>> {
906 self.client()
907 .request("eth_getTransactionByBlockNumberAndIndex", (block_number, Index(index)))
908 .into()
909 }
910
911 fn get_raw_transaction_by_block_number_and_index(
913 &self,
914 block_number: BlockNumberOrTag,
915 index: usize,
916 ) -> ProviderCall<(BlockNumberOrTag, Index), Option<Bytes>> {
917 self.client()
918 .request("eth_getRawTransactionByBlockNumberAndIndex", (block_number, Index(index)))
919 .into()
920 }
921
922 fn get_raw_transaction_by_hash(&self, hash: TxHash) -> ProviderCall<(TxHash,), Option<Bytes>> {
934 self.client().request("eth_getRawTransactionByHash", (hash,)).into()
935 }
936
937 #[doc(alias = "get_nonce")]
939 #[doc(alias = "get_account_nonce")]
940 fn get_transaction_count(
941 &self,
942 address: Address,
943 ) -> RpcWithBlock<Address, U64, u64, fn(U64) -> u64> {
944 self.client()
945 .request("eth_getTransactionCount", address)
946 .map_resp(utils::convert_u64 as fn(U64) -> u64)
947 .into()
948 }
949
950 fn get_transaction_receipt(
952 &self,
953 hash: TxHash,
954 ) -> ProviderCall<(TxHash,), Option<N::ReceiptResponse>> {
955 self.client().request("eth_getTransactionReceipt", (hash,)).into()
956 }
957
958 async fn get_uncle(&self, tag: BlockId, idx: u64) -> TransportResult<Option<N::BlockResponse>> {
960 let idx = U64::from(idx);
961 match tag {
962 BlockId::Hash(hash) => {
963 self.client()
964 .request("eth_getUncleByBlockHashAndIndex", (hash.block_hash, idx))
965 .await
966 }
967 BlockId::Number(number) => {
968 self.client().request("eth_getUncleByBlockNumberAndIndex", (number, idx)).await
969 }
970 }
971 }
972
973 async fn get_uncle_count(&self, tag: BlockId) -> TransportResult<u64> {
975 match tag {
976 BlockId::Hash(hash) => self
977 .client()
978 .request("eth_getUncleCountByBlockHash", (hash.block_hash,))
979 .await
980 .map(|count: U64| count.to::<u64>()),
981 BlockId::Number(number) => self
982 .client()
983 .request("eth_getUncleCountByBlockNumber", (number,))
984 .await
985 .map(|count: U64| count.to::<u64>()),
986 }
987 }
988
989 fn get_max_priority_fee_per_gas(&self) -> ProviderCall<NoParams, U128, u128> {
991 self.client()
992 .request_noparams("eth_maxPriorityFeePerGas")
993 .map_resp(utils::convert_u128 as fn(U128) -> u128)
994 .into()
995 }
996
997 async fn new_block_filter(&self) -> TransportResult<U256> {
1003 self.client().request_noparams("eth_newBlockFilter").await
1004 }
1005
1006 async fn new_filter(&self, filter: &Filter) -> TransportResult<U256> {
1012 self.client().request("eth_newFilter", (filter,)).await
1013 }
1014
1015 async fn new_pending_transactions_filter(&self, full: bool) -> TransportResult<U256> {
1025 let param = if full { &[true][..] } else { &[] };
1027 self.client().request("eth_newPendingTransactionFilter", param).await
1028 }
1029
1030 async fn send_raw_transaction(
1034 &self,
1035 encoded_tx: &[u8],
1036 ) -> TransportResult<PendingTransactionBuilder<N>> {
1037 let rlp_hex = hex::encode_prefixed(encoded_tx);
1038 let tx_hash = self.client().request("eth_sendRawTransaction", (rlp_hex,)).await?;
1039 Ok(PendingTransactionBuilder::new(self.root().clone(), tx_hash))
1040 }
1041
1042 async fn send_raw_transaction_sync(
1080 &self,
1081 encoded_tx: &[u8],
1082 ) -> TransportResult<N::ReceiptResponse> {
1083 let rlp_hex = hex::encode_prefixed(encoded_tx);
1084 self.client().request("eth_sendRawTransactionSync", (rlp_hex,)).await
1085 }
1086
1087 async fn send_raw_transaction_conditional(
1098 &self,
1099 encoded_tx: &[u8],
1100 conditional: TransactionConditional,
1101 ) -> TransportResult<PendingTransactionBuilder<N>> {
1102 let rlp_hex = hex::encode_prefixed(encoded_tx);
1103 let tx_hash = self
1104 .client()
1105 .request("eth_sendRawTransactionConditional", (rlp_hex, conditional))
1106 .await?;
1107 Ok(PendingTransactionBuilder::new(self.root().clone(), tx_hash))
1108 }
1109
1110 async fn send_transaction(
1131 &self,
1132 tx: N::TransactionRequest,
1133 ) -> TransportResult<PendingTransactionBuilder<N>> {
1134 self.send_transaction_internal(SendableTx::Builder(tx)).await
1135 }
1136
1137 async fn send_tx_envelope(
1142 &self,
1143 tx: N::TxEnvelope,
1144 ) -> TransportResult<PendingTransactionBuilder<N>> {
1145 self.send_transaction_internal(SendableTx::Envelope(tx)).await
1146 }
1147
1148 #[doc(hidden)]
1155 async fn send_transaction_internal(
1156 &self,
1157 tx: SendableTx<N>,
1158 ) -> TransportResult<PendingTransactionBuilder<N>> {
1159 let _handle = self.root().get_heart();
1162
1163 match tx {
1164 SendableTx::Builder(mut tx) => {
1165 alloy_network::NetworkTransactionBuilder::prep_for_submission(&mut tx);
1166 let tx_hash = self.client().request("eth_sendTransaction", (tx,)).await?;
1167 Ok(PendingTransactionBuilder::new(self.root().clone(), tx_hash))
1168 }
1169 SendableTx::Envelope(tx) => {
1170 let encoded_tx = tx.encoded_2718();
1171 self.send_raw_transaction(&encoded_tx).await
1172 }
1173 }
1174 }
1175
1176 async fn send_transaction_sync(
1216 &self,
1217 tx: N::TransactionRequest,
1218 ) -> TransportResult<N::ReceiptResponse> {
1219 self.send_transaction_sync_internal(SendableTx::Builder(tx)).await
1220 }
1221
1222 #[doc(hidden)]
1232 async fn send_transaction_sync_internal(
1233 &self,
1234 tx: SendableTx<N>,
1235 ) -> TransportResult<N::ReceiptResponse> {
1236 let _handle = self.root().get_heart();
1239
1240 match tx {
1241 SendableTx::Builder(mut tx) => {
1242 alloy_network::NetworkTransactionBuilder::prep_for_submission(&mut tx);
1243 let receipt = self.client().request("eth_sendTransactionSync", (tx,)).await?;
1244 Ok(receipt)
1245 }
1246 SendableTx::Envelope(tx) => {
1247 let encoded_tx = tx.encoded_2718();
1248 self.send_raw_transaction_sync(&encoded_tx).await
1249 }
1250 }
1251 }
1252
1253 async fn sign_transaction(&self, tx: N::TransactionRequest) -> TransportResult<Bytes> {
1258 self.client().request("eth_signTransaction", (tx,)).await
1259 }
1260
1261 async fn fill_transaction(
1267 &self,
1268 tx: N::TransactionRequest,
1269 ) -> TransportResult<FillTransaction<N::TxEnvelope>>
1270 where
1271 N::TxEnvelope: RpcRecv,
1272 {
1273 self.client().request("eth_fillTransaction", (tx,)).await
1274 }
1275
1276 #[cfg(feature = "pubsub")]
1302 fn subscribe_blocks(&self) -> GetSubscription<(SubscriptionKind,), N::HeaderResponse> {
1303 let rpc_call = self.client().request("eth_subscribe", (SubscriptionKind::NewHeads,));
1304 GetSubscription::new(self.weak_client(), rpc_call)
1305 }
1306
1307 #[cfg(feature = "pubsub")]
1331 fn subscribe_full_blocks(&self) -> SubFullBlocks<N> {
1332 SubFullBlocks::new(self.subscribe_blocks(), self.weak_client())
1333 }
1334
1335 #[cfg(feature = "pubsub")]
1361 fn subscribe_pending_transactions(&self) -> GetSubscription<(SubscriptionKind,), B256> {
1362 let rpc_call =
1363 self.client().request("eth_subscribe", (SubscriptionKind::NewPendingTransactions,));
1364 GetSubscription::new(self.weak_client(), rpc_call)
1365 }
1366
1367 #[cfg(feature = "pubsub")]
1398 fn subscribe_full_pending_transactions(
1399 &self,
1400 ) -> GetSubscription<(SubscriptionKind, Params), N::TransactionResponse> {
1401 let rpc_call = self.client().request(
1402 "eth_subscribe",
1403 (SubscriptionKind::NewPendingTransactions, Params::Bool(true)),
1404 );
1405 GetSubscription::new(self.weak_client(), rpc_call)
1406 }
1407
1408 #[cfg(feature = "pubsub")]
1439 fn subscribe_logs(&self, filter: &Filter) -> GetSubscription<(SubscriptionKind, Params), Log> {
1440 let rpc_call = self.client().request(
1441 "eth_subscribe",
1442 (SubscriptionKind::Logs, Params::Logs(Box::new(filter.clone()))),
1443 );
1444 GetSubscription::new(self.weak_client(), rpc_call)
1445 }
1446
1447 #[cfg(feature = "pubsub")]
1449 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
1450 fn subscribe<P, R>(&self, params: P) -> GetSubscription<P, R>
1451 where
1452 P: RpcSend,
1453 R: RpcRecv,
1454 Self: Sized,
1455 {
1456 let rpc_call = self.client().request("eth_subscribe", params);
1457 GetSubscription::new(self.weak_client(), rpc_call)
1458 }
1459
1460 #[cfg(feature = "pubsub")]
1481 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
1482 fn subscribe_to<R>(&self, method: &'static str) -> GetSubscription<NoParams, R>
1483 where
1484 R: RpcRecv,
1485 Self: Sized,
1486 {
1487 let mut rpc_call = self.client().request_noparams(method);
1488 rpc_call.set_is_subscription();
1489 GetSubscription::new(self.weak_client(), rpc_call)
1490 }
1491
1492 #[cfg(feature = "pubsub")]
1494 async fn unsubscribe(&self, id: B256) -> TransportResult<()> {
1495 self.root().unsubscribe(id)
1496 }
1497
1498 fn syncing(&self) -> ProviderCall<NoParams, SyncStatus> {
1500 self.client().request_noparams("eth_syncing").into()
1501 }
1502
1503 #[doc(alias = "web3_client_version")]
1505 fn get_client_version(&self) -> ProviderCall<NoParams, String> {
1506 self.client().request_noparams("web3_clientVersion").into()
1507 }
1508
1509 #[doc(alias = "web3_sha3")]
1511 fn get_sha3(&self, data: &[u8]) -> ProviderCall<(String,), B256> {
1512 self.client().request("web3_sha3", (hex::encode_prefixed(data),)).into()
1513 }
1514
1515 fn get_net_version(&self) -> ProviderCall<NoParams, U64, u64> {
1517 self.client()
1518 .request_noparams("net_version")
1519 .map_resp(utils::convert_u64 as fn(U64) -> u64)
1520 .into()
1521 }
1522
1523 async fn raw_request<P, R>(&self, method: Cow<'static, str>, params: P) -> TransportResult<R>
1548 where
1549 P: RpcSend,
1550 R: RpcRecv,
1551 Self: Sized,
1552 {
1553 self.client().request(method, ¶ms).await
1554 }
1555
1556 async fn raw_request_dyn(
1579 &self,
1580 method: Cow<'static, str>,
1581 params: &RawValue,
1582 ) -> TransportResult<Box<RawValue>> {
1583 self.client().request(method, params).await
1584 }
1585
1586 #[inline]
1588 fn transaction_request(&self) -> N::TransactionRequest {
1589 Default::default()
1590 }
1591}
1592
1593#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
1594#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
1595impl<N: Network> Provider<N> for RootProvider<N> {
1596 #[inline]
1597 fn root(&self) -> &Self {
1598 self
1599 }
1600
1601 #[inline]
1602 fn client(&self) -> ClientRef<'_> {
1603 self.inner.client_ref()
1604 }
1605
1606 #[inline]
1607 fn weak_client(&self) -> WeakClient {
1608 self.inner.weak_client()
1609 }
1610
1611 #[inline]
1612 async fn watch_pending_transaction(
1613 &self,
1614 config: PendingTransactionConfig,
1615 ) -> Result<PendingTransaction, PendingTransactionError> {
1616 let block_number =
1617 if let Some(receipt) = self.get_transaction_receipt(*config.tx_hash()).await? {
1618 if config.required_confirmations() <= 1 {
1620 return Ok(PendingTransaction::ready(*config.tx_hash()));
1621 }
1622 receipt.block_number()
1625 } else {
1626 None
1627 };
1628
1629 self.get_heart()
1630 .watch_tx(config, block_number)
1631 .await
1632 .map_err(|_| PendingTransactionError::FailedToRegister)
1633 }
1634}
1635
1636#[cfg(test)]
1637mod tests {
1638 use super::*;
1639 use crate::{builder, ext::test::async_ci_only, ProviderBuilder, WalletProvider};
1640 use alloy_consensus::{Transaction, TxEnvelope};
1641 use alloy_network::{
1642 AnyNetwork, EthereumWallet, NetworkTransactionBuilder, TransactionBuilder,
1643 };
1644 use alloy_node_bindings::{utils::run_with_tempdir, Anvil, Reth};
1645 use alloy_primitives::{address, b256, bytes, keccak256};
1646 use alloy_rlp::Decodable;
1647 use alloy_rpc_client::{BuiltInConnectionString, RpcClient};
1648 use alloy_rpc_types_eth::{request::TransactionRequest, Block};
1649 use alloy_signer_local::PrivateKeySigner;
1650 use alloy_transport::layers::{RetryBackoffLayer, RetryPolicy};
1651 use std::{io::Read, str::FromStr, time::Duration};
1652
1653 use alloy_consensus::transaction::SignerRecoverable;
1655 #[cfg(feature = "hyper")]
1656 use alloy_transport_http::{
1657 hyper,
1658 hyper::body::Bytes as HyperBytes,
1659 hyper_util::{
1660 client::legacy::{Client, Error},
1661 rt::TokioExecutor,
1662 },
1663 HyperResponse, HyperResponseFut,
1664 };
1665 #[cfg(feature = "hyper")]
1666 use http_body_util::Full;
1667 #[cfg(feature = "hyper")]
1668 use tower::{Layer, Service};
1669
1670 #[tokio::test]
1671 async fn test_provider_builder() {
1672 let provider =
1673 RootProvider::<Ethereum>::builder().with_recommended_fillers().connect_anvil();
1674 let num = provider.get_block_number().await.unwrap();
1675 assert_eq!(0, num);
1676 }
1677
1678 #[tokio::test]
1679 async fn test_builder_helper_fn() {
1680 let provider = builder::<Ethereum>().with_recommended_fillers().connect_anvil();
1681 let num = provider.get_block_number().await.unwrap();
1682 assert_eq!(0, num);
1683 }
1684
1685 #[cfg(feature = "hyper")]
1686 #[tokio::test]
1687 async fn test_default_hyper_transport() {
1688 let anvil = Anvil::new().spawn();
1689 let hyper_t = alloy_transport_http::HyperTransport::new_hyper(anvil.endpoint_url());
1690
1691 let rpc_client = alloy_rpc_client::RpcClient::new(hyper_t, true);
1692
1693 let provider = RootProvider::<Ethereum>::new(rpc_client);
1694 let num = provider.get_block_number().await.unwrap();
1695 assert_eq!(0, num);
1696 }
1697
1698 #[cfg(feature = "hyper")]
1699 #[tokio::test]
1700 async fn test_hyper_layer_transport() {
1701 struct LoggingLayer;
1702
1703 impl<S> Layer<S> for LoggingLayer {
1704 type Service = LoggingService<S>;
1705
1706 fn layer(&self, inner: S) -> Self::Service {
1707 LoggingService { inner }
1708 }
1709 }
1710
1711 #[derive(Clone)] struct LoggingService<S> {
1713 inner: S,
1714 }
1715
1716 impl<S, B> Service<hyper::Request<B>> for LoggingService<S>
1717 where
1718 S: Service<hyper::Request<B>, Response = HyperResponse, Error = Error>
1719 + Clone
1720 + Send
1721 + Sync
1722 + 'static,
1723 S::Future: Send,
1724 S::Error: std::error::Error + Send + Sync + 'static,
1725 B: From<Vec<u8>> + Send + 'static + Clone + Sync + std::fmt::Debug,
1726 {
1727 type Response = HyperResponse;
1728 type Error = Error;
1729 type Future = HyperResponseFut;
1730
1731 fn poll_ready(
1732 &mut self,
1733 cx: &mut std::task::Context<'_>,
1734 ) -> std::task::Poll<Result<(), Self::Error>> {
1735 self.inner.poll_ready(cx)
1736 }
1737
1738 fn call(&mut self, req: hyper::Request<B>) -> Self::Future {
1739 println!("Logging Layer - HyperRequest {req:?}");
1740
1741 let fut = self.inner.call(req);
1742
1743 Box::pin(fut)
1744 }
1745 }
1746 use http::header::{self, HeaderValue};
1747 use tower_http::{
1748 sensitive_headers::SetSensitiveRequestHeadersLayer, set_header::SetRequestHeaderLayer,
1749 };
1750 let anvil = Anvil::new().spawn();
1751 let hyper_client = Client::builder(TokioExecutor::new()).build_http::<Full<HyperBytes>>();
1752
1753 let service = tower::ServiceBuilder::new()
1755 .layer(SetRequestHeaderLayer::if_not_present(
1756 header::USER_AGENT,
1757 HeaderValue::from_static("alloy app"),
1758 ))
1759 .layer(SetRequestHeaderLayer::overriding(
1760 header::AUTHORIZATION,
1761 HeaderValue::from_static("some-jwt-token"),
1762 ))
1763 .layer(SetRequestHeaderLayer::appending(
1764 header::SET_COOKIE,
1765 HeaderValue::from_static("cookie-value"),
1766 ))
1767 .layer(SetSensitiveRequestHeadersLayer::new([header::AUTHORIZATION])) .layer(LoggingLayer)
1769 .service(hyper_client);
1770
1771 let layer_transport = alloy_transport_http::HyperClient::with_service(service);
1772
1773 let http_hyper =
1774 alloy_transport_http::Http::with_client(layer_transport, anvil.endpoint_url());
1775
1776 let rpc_client = alloy_rpc_client::RpcClient::new(http_hyper, true);
1777
1778 let provider = RootProvider::<Ethereum>::new(rpc_client);
1779 let num = provider.get_block_number().await.unwrap();
1780 assert_eq!(0, num);
1781
1782 let cloned_t = provider.client().transport().clone();
1784
1785 let rpc_client = alloy_rpc_client::RpcClient::new(cloned_t, true);
1786
1787 let provider = RootProvider::<Ethereum>::new(rpc_client);
1788 let num = provider.get_block_number().await.unwrap();
1789 assert_eq!(0, num);
1790 }
1791
1792 #[cfg(feature = "hyper")]
1793 #[tokio::test]
1794 #[cfg_attr(windows, ignore = "no reth on windows")]
1795 async fn test_auth_layer_transport() {
1796 crate::ext::test::async_ci_only(|| async move {
1797 use alloy_node_bindings::Reth;
1798 use alloy_rpc_types_engine::JwtSecret;
1799 use alloy_transport_http::{AuthLayer, Http, HyperClient};
1800
1801 let secret = JwtSecret::random();
1802
1803 let reth =
1804 Reth::new().arg("--rpc.jwtsecret").arg(hex::encode(secret.as_bytes())).spawn();
1805
1806 let layer_transport = HyperClient::new().layer(AuthLayer::new(secret));
1807
1808 let http_hyper = Http::with_client(layer_transport, reth.endpoint_url());
1809
1810 let rpc_client = alloy_rpc_client::RpcClient::new(http_hyper, true);
1811
1812 let provider = RootProvider::<Ethereum>::new(rpc_client);
1813
1814 let num = provider.get_block_number().await.unwrap();
1815 assert_eq!(0, num);
1816 })
1817 .await;
1818 }
1819
1820 #[tokio::test]
1821 async fn test_builder_helper_fn_any_network() {
1822 let anvil = Anvil::new().spawn();
1823 let provider =
1824 builder::<AnyNetwork>().with_recommended_fillers().connect_http(anvil.endpoint_url());
1825 let num = provider.get_block_number().await.unwrap();
1826 assert_eq!(0, num);
1827 }
1828
1829 #[cfg(feature = "reqwest")]
1830 #[tokio::test]
1831 async fn object_safety() {
1832 let provider = ProviderBuilder::new().connect_anvil();
1833
1834 let refdyn = &provider as &dyn Provider<_>;
1835 let num = refdyn.get_block_number().await.unwrap();
1836 assert_eq!(0, num);
1837 }
1838
1839 #[cfg(feature = "ws")]
1840 #[tokio::test]
1841 async fn subscribe_blocks_http() {
1842 let provider = ProviderBuilder::new().connect_anvil_with_config(|a| a.block_time(1));
1843
1844 let err = provider.subscribe_blocks().await.unwrap_err();
1845 let alloy_json_rpc::RpcError::Transport(
1846 alloy_transport::TransportErrorKind::PubsubUnavailable,
1847 ) = err
1848 else {
1849 panic!("{err:?}");
1850 };
1851 }
1852
1853 #[cfg(feature = "ws")]
1855 #[tokio::test]
1856 async fn websocket_tls_setup() {
1857 for url in ["wss://mainnet.infura.io/ws/v3/b0f825787ba840af81e46c6a64d20754"] {
1858 let _ = ProviderBuilder::<_, _, Ethereum>::default().connect(url).await.unwrap();
1859 }
1860 }
1861
1862 #[cfg(feature = "ws")]
1863 #[tokio::test]
1864 async fn subscribe_blocks_ws() {
1865 use futures::stream::StreamExt;
1866
1867 let anvil = Anvil::new().block_time_f64(0.2).spawn();
1868 let ws = alloy_rpc_client::WsConnect::new(anvil.ws_endpoint());
1869 let client = alloy_rpc_client::RpcClient::connect_pubsub(ws).await.unwrap();
1870 let provider = RootProvider::<Ethereum>::new(client);
1871
1872 let sub = provider.subscribe_blocks().await.unwrap();
1873 let mut stream = sub.into_stream().take(5);
1874 let mut next = None;
1875 while let Some(header) = stream.next().await {
1876 if let Some(next) = &mut next {
1877 assert_eq!(header.number, *next);
1878 *next += 1;
1879 } else {
1880 next = Some(header.number + 1);
1881 }
1882 }
1883 }
1884
1885 #[cfg(feature = "ws")]
1886 #[tokio::test]
1887 async fn subscribe_full_blocks() {
1888 use futures::StreamExt;
1889
1890 let anvil = Anvil::new().block_time_f64(0.2).spawn();
1891 let ws = alloy_rpc_client::WsConnect::new(anvil.ws_endpoint());
1892 let client = alloy_rpc_client::RpcClient::connect_pubsub(ws).await.unwrap();
1893
1894 let provider = RootProvider::<Ethereum>::new(client);
1895
1896 let sub = provider.subscribe_full_blocks().hashes().channel_size(10);
1897
1898 let mut stream = sub.into_stream().await.unwrap().take(5);
1899
1900 let mut next = None;
1901 while let Some(Ok(block)) = stream.next().await {
1902 if let Some(next) = &mut next {
1903 assert_eq!(block.header().number, *next);
1904 *next += 1;
1905 } else {
1906 next = Some(block.header().number + 1);
1907 }
1908 }
1909 }
1910
1911 #[tokio::test]
1912 #[cfg(feature = "ws")]
1913 async fn subscribe_blocks_ws_remote() {
1914 use futures::stream::StreamExt;
1915
1916 let url = "wss://eth-mainnet.g.alchemy.com/v2/viFmeVzhg6bWKVMIWWS8MhmzREB-D4f7";
1917 let ws = alloy_rpc_client::WsConnect::new(url);
1918 let Ok(client) = alloy_rpc_client::RpcClient::connect_pubsub(ws).await else { return };
1919 let provider = RootProvider::<Ethereum>::new(client);
1920 let sub = provider.subscribe_blocks().await.unwrap();
1921 let mut stream = sub.into_stream().take(1);
1922 while let Some(header) = stream.next().await {
1923 println!("New block {header:?}");
1924 assert!(header.number > 0);
1925 }
1926 }
1927
1928 #[tokio::test]
1929 async fn test_custom_retry_policy() {
1930 #[derive(Debug, Clone)]
1931 struct CustomPolicy;
1932 impl RetryPolicy for CustomPolicy {
1933 fn should_retry(&self, _err: &alloy_transport::TransportError) -> bool {
1934 true
1935 }
1936
1937 fn backoff_hint(
1938 &self,
1939 _error: &alloy_transport::TransportError,
1940 ) -> Option<std::time::Duration> {
1941 None
1942 }
1943 }
1944
1945 let retry_layer = RetryBackoffLayer::new_with_policy(10, 100, 10000, CustomPolicy);
1946 let anvil = Anvil::new().spawn();
1947 let client = RpcClient::builder().layer(retry_layer).http(anvil.endpoint_url());
1948
1949 let provider = RootProvider::<Ethereum>::new(client);
1950 let num = provider.get_block_number().await.unwrap();
1951 assert_eq!(0, num);
1952 }
1953
1954 #[tokio::test]
1955 async fn test_send_tx() {
1956 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
1957 let tx = TransactionRequest {
1958 value: Some(U256::from(100)),
1959 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
1960 gas_price: Some(20e9 as u128),
1961 gas: Some(21000),
1962 ..Default::default()
1963 };
1964
1965 let builder = provider.send_transaction(tx.clone()).await.expect("failed to send tx");
1966 let hash1 = *builder.tx_hash();
1967 let hash2 = builder.watch().await.expect("failed to await pending tx");
1968 assert_eq!(hash1, hash2);
1969
1970 let builder = provider.send_transaction(tx).await.expect("failed to send tx");
1971 let hash1 = *builder.tx_hash();
1972 let hash2 =
1973 builder.get_receipt().await.expect("failed to await pending tx").transaction_hash;
1974 assert_eq!(hash1, hash2);
1975 }
1976
1977 #[tokio::test]
1978 async fn test_send_tx_sync() {
1979 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
1980 let tx = TransactionRequest {
1981 value: Some(U256::from(100)),
1982 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
1983 gas_price: Some(20e9 as u128),
1984 gas: Some(21000),
1985 ..Default::default()
1986 };
1987
1988 let _receipt =
1989 provider.send_transaction_sync(tx.clone()).await.expect("failed to send tx sync");
1990 }
1991
1992 #[tokio::test]
1993 async fn test_send_raw_transaction_sync() {
1994 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
1995
1996 let tx = TransactionRequest {
1998 nonce: Some(0),
1999 value: Some(U256::from(100)),
2000 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
2001 gas_price: Some(20e9 as u128),
2002 gas: Some(21000),
2003 ..Default::default()
2004 };
2005
2006 let tx_envelope = tx.build(&provider.wallet()).await.expect("failed to build tx");
2008
2009 let encoded = tx_envelope.encoded_2718();
2011
2012 let receipt =
2014 provider.send_raw_transaction_sync(&encoded).await.expect("failed to send raw tx sync");
2015
2016 assert_eq!(receipt.to(), Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045")));
2018 assert!(receipt.block_number().is_some(), "transaction should be mined");
2020 assert!(receipt.transaction_hash() != B256::ZERO, "should have valid tx hash");
2021 }
2022
2023 #[tokio::test]
2024 async fn test_watch_confirmed_tx() {
2025 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
2026 let tx = TransactionRequest {
2027 value: Some(U256::from(100)),
2028 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
2029 gas_price: Some(20e9 as u128),
2030 gas: Some(21000),
2031 ..Default::default()
2032 };
2033
2034 let builder = provider.send_transaction(tx).await.expect("failed to send tx");
2035 let hash1 = *builder.tx_hash();
2036
2037 loop {
2039 if provider
2040 .get_transaction_receipt(hash1)
2041 .await
2042 .expect("failed to await pending tx")
2043 .is_some()
2044 {
2045 break;
2046 }
2047 }
2048
2049 let tx2 = TransactionRequest {
2051 value: Some(U256::from(100)),
2052 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
2053 gas_price: Some(20e9 as u128),
2054 gas: Some(21000),
2055 ..Default::default()
2056 };
2057 provider.send_transaction(tx2).await.expect("failed to send tx").watch().await.unwrap();
2058
2059 let watch = builder.watch();
2061 let watch_with_timeout = tokio::time::timeout(Duration::from_secs(1), watch);
2063 let hash2 = watch_with_timeout
2064 .await
2065 .expect("Watching tx timed out")
2066 .expect("failed to await pending tx");
2067 assert_eq!(hash1, hash2);
2068 }
2069
2070 #[tokio::test]
2071 async fn gets_block_number() {
2072 let provider = ProviderBuilder::new().connect_anvil();
2073 let num = provider.get_block_number().await.unwrap();
2074 assert_eq!(0, num)
2075 }
2076
2077 #[tokio::test]
2078 async fn gets_block_number_for_id() {
2079 let provider = ProviderBuilder::new().connect_anvil();
2080
2081 let block_num = provider
2082 .get_block_number_by_id(BlockId::Number(BlockNumberOrTag::Number(0)))
2083 .await
2084 .unwrap();
2085 assert_eq!(block_num, Some(0));
2086
2087 let block_num = provider
2088 .get_block_number_by_id(BlockId::Number(BlockNumberOrTag::Latest))
2089 .await
2090 .unwrap();
2091 assert_eq!(block_num, Some(0));
2092
2093 let block =
2094 provider.get_block_by_number(BlockNumberOrTag::Number(0)).await.unwrap().unwrap();
2095 let hash = block.header.hash;
2096 let block_num = provider.get_block_number_by_id(BlockId::Hash(hash.into())).await.unwrap();
2097 assert_eq!(block_num, Some(0));
2098 }
2099
2100 #[tokio::test]
2101 async fn gets_block_number_with_raw_req() {
2102 let provider = ProviderBuilder::new().connect_anvil();
2103 let num: U64 =
2104 provider.raw_request("eth_blockNumber".into(), NoParams::default()).await.unwrap();
2105 assert_eq!(0, num.to::<u64>())
2106 }
2107
2108 #[cfg(feature = "anvil-api")]
2109 #[tokio::test]
2110 async fn gets_transaction_count() {
2111 let provider = ProviderBuilder::new().connect_anvil();
2112 let accounts = provider.get_accounts().await.unwrap();
2113 let sender = accounts[0];
2114
2115 let count = provider.get_transaction_count(sender).await.unwrap();
2117 assert_eq!(count, 0);
2118
2119 let tx = TransactionRequest {
2121 value: Some(U256::from(100)),
2122 from: Some(sender),
2123 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
2124 gas_price: Some(20e9 as u128),
2125 gas: Some(21000),
2126 ..Default::default()
2127 };
2128 let _ = provider.send_transaction(tx).await.unwrap().get_receipt().await;
2129
2130 let count = provider.get_transaction_count(sender).await.unwrap();
2132 assert_eq!(count, 1);
2133
2134 let count = provider.get_transaction_count(sender).block_id(0.into()).await.unwrap();
2136 assert_eq!(count, 0);
2137 }
2138
2139 #[tokio::test]
2140 async fn gets_block_by_hash() {
2141 let provider = ProviderBuilder::new().connect_anvil();
2142 let num = 0;
2143 let tag: BlockNumberOrTag = num.into();
2144 let block = provider.get_block_by_number(tag).full().await.unwrap().unwrap();
2145 let hash = block.header.hash;
2146 let block = provider.get_block_by_hash(hash).full().await.unwrap().unwrap();
2147 assert_eq!(block.header.hash, hash);
2148 }
2149
2150 #[tokio::test]
2151 async fn gets_block_by_hash_with_raw_req() {
2152 let provider = ProviderBuilder::new().connect_anvil();
2153 let num = 0;
2154 let tag: BlockNumberOrTag = num.into();
2155 let block = provider.get_block_by_number(tag).full().await.unwrap().unwrap();
2156 let hash = block.header.hash;
2157 let block: Block = provider
2158 .raw_request::<(B256, bool), Block>("eth_getBlockByHash".into(), (hash, true))
2159 .await
2160 .unwrap();
2161 assert_eq!(block.header.hash, hash);
2162 }
2163
2164 #[tokio::test]
2165 async fn gets_block_by_number_full() {
2166 let provider = ProviderBuilder::new().connect_anvil();
2167 let num = 0;
2168 let tag: BlockNumberOrTag = num.into();
2169 let block = provider.get_block_by_number(tag).full().await.unwrap().unwrap();
2170 assert_eq!(block.header.number, num);
2171 }
2172
2173 #[tokio::test]
2174 async fn gets_block_by_number() {
2175 let provider = ProviderBuilder::new().connect_anvil();
2176 let num = 0;
2177 let tag: BlockNumberOrTag = num.into();
2178 let block = provider.get_block_by_number(tag).full().await.unwrap().unwrap();
2179 assert_eq!(block.header.number, num);
2180 }
2181
2182 #[tokio::test]
2183 async fn gets_client_version() {
2184 let provider = ProviderBuilder::new().connect_anvil();
2185 let version = provider.get_client_version().await.unwrap();
2186 assert!(version.contains("anvil"), "{version}");
2187 }
2188
2189 #[tokio::test]
2190 async fn gets_sha3() {
2191 let provider = ProviderBuilder::new().connect_anvil();
2192 let data = b"alloy";
2193 let hash = provider.get_sha3(data).await.unwrap();
2194 assert_eq!(hash, keccak256(data));
2195 }
2196
2197 #[tokio::test]
2198 async fn gets_chain_id() {
2199 let dev_chain_id: u64 = 13371337;
2200
2201 let provider =
2202 ProviderBuilder::new().connect_anvil_with_config(|a| a.chain_id(dev_chain_id));
2203
2204 let chain_id = provider.get_chain_id().await.unwrap();
2205 assert_eq!(chain_id, dev_chain_id);
2206 }
2207
2208 #[tokio::test]
2209 async fn gets_network_id() {
2210 let dev_chain_id: u64 = 13371337;
2211 let provider =
2212 ProviderBuilder::new().connect_anvil_with_config(|a| a.chain_id(dev_chain_id));
2213
2214 let chain_id = provider.get_net_version().await.unwrap();
2215 assert_eq!(chain_id, dev_chain_id);
2216 }
2217
2218 #[tokio::test]
2219 async fn gets_storage_at() {
2220 let provider = ProviderBuilder::new().connect_anvil();
2221 let addr = Address::with_last_byte(16);
2222 let storage = provider.get_storage_at(addr, U256::ZERO).await.unwrap();
2223 assert_eq!(storage, U256::ZERO);
2224 }
2225
2226 #[tokio::test]
2227 async fn gets_transaction_by_hash_not_found() {
2228 let provider = ProviderBuilder::new().connect_anvil();
2229 let tx_hash = b256!("5c03fab9114ceb98994b43892ade87ddfd9ae7e8f293935c3bd29d435dc9fd95");
2230 let tx = provider.get_transaction_by_hash(tx_hash).await.expect("failed to fetch tx");
2231
2232 assert!(tx.is_none());
2233 }
2234
2235 #[tokio::test]
2236 async fn gets_transaction_by_hash() {
2237 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
2238
2239 let req = TransactionRequest::default()
2240 .from(provider.default_signer_address())
2241 .to(Address::repeat_byte(5))
2242 .value(U256::ZERO)
2243 .input(bytes!("deadbeef").into());
2244
2245 let tx_hash = *provider.send_transaction(req).await.expect("failed to send tx").tx_hash();
2246
2247 let tx = provider
2248 .get_transaction_by_hash(tx_hash)
2249 .await
2250 .expect("failed to fetch tx")
2251 .expect("tx not included");
2252 assert_eq!(tx.input(), &bytes!("deadbeef"));
2253 }
2254
2255 #[tokio::test]
2256 #[ignore]
2257 async fn gets_logs() {
2258 let provider = ProviderBuilder::new().connect_anvil();
2259 let filter = Filter::new()
2260 .at_block_hash(b256!(
2261 "b20e6f35d4b46b3c4cd72152faec7143da851a0dc281d390bdd50f58bfbdb5d3"
2262 ))
2263 .event_signature(b256!(
2264 "e1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c"
2265 ));
2266 let logs = provider.get_logs(&filter).await.unwrap();
2267 assert_eq!(logs.len(), 1);
2268 }
2269
2270 #[tokio::test]
2271 #[ignore]
2272 async fn gets_tx_receipt() {
2273 let provider = ProviderBuilder::new().connect_anvil();
2274 let receipt = provider
2275 .get_transaction_receipt(b256!(
2276 "5c03fab9114ceb98994b43892ade87ddfd9ae7e8f293935c3bd29d435dc9fd95"
2277 ))
2278 .await
2279 .unwrap();
2280 assert!(receipt.is_some());
2281 let receipt = receipt.unwrap();
2282 assert_eq!(
2283 receipt.transaction_hash,
2284 b256!("5c03fab9114ceb98994b43892ade87ddfd9ae7e8f293935c3bd29d435dc9fd95")
2285 );
2286 }
2287
2288 #[tokio::test]
2289 async fn gets_max_priority_fee_per_gas() {
2290 let provider = ProviderBuilder::new().connect_anvil();
2291 let _fee = provider.get_max_priority_fee_per_gas().await.unwrap();
2292 }
2293
2294 #[tokio::test]
2295 async fn gets_fee_history() {
2296 let provider = ProviderBuilder::new().connect_anvil();
2297 let block_number = provider.get_block_number().await.unwrap();
2298 let fee_history = provider
2299 .get_fee_history(
2300 utils::EIP1559_FEE_ESTIMATION_PAST_BLOCKS,
2301 BlockNumberOrTag::Number(block_number),
2302 &[utils::EIP1559_FEE_ESTIMATION_REWARD_PERCENTILE],
2303 )
2304 .await
2305 .unwrap();
2306 assert_eq!(fee_history.oldest_block, 0_u64);
2307 }
2308
2309 #[tokio::test]
2310 async fn gets_block_transaction_count_by_hash() {
2311 let provider = ProviderBuilder::new().connect_anvil();
2312 let block = provider.get_block(BlockId::latest()).await.unwrap().unwrap();
2313 let hash = block.header.hash;
2314 let tx_count = provider.get_block_transaction_count_by_hash(hash).await.unwrap();
2315 assert!(tx_count.is_some());
2316 }
2317
2318 #[tokio::test]
2319 async fn gets_block_transaction_count_by_number() {
2320 let provider = ProviderBuilder::new().connect_anvil();
2321 let tx_count =
2322 provider.get_block_transaction_count_by_number(BlockNumberOrTag::Latest).await.unwrap();
2323 assert!(tx_count.is_some());
2324 }
2325
2326 #[tokio::test]
2327 async fn gets_block_receipts() {
2328 let provider = ProviderBuilder::new().connect_anvil();
2329 let receipts =
2330 provider.get_block_receipts(BlockId::Number(BlockNumberOrTag::Latest)).await.unwrap();
2331 assert!(receipts.is_some());
2332 }
2333
2334 #[tokio::test]
2335 async fn sends_raw_transaction() {
2336 let provider = ProviderBuilder::new().connect_anvil();
2337 let pending = provider
2338 .send_raw_transaction(
2339 bytes!("f865808477359400825208940000000000000000000000000000000000000000018082f4f5a00505e227c1c636c76fac55795db1a40a4d24840d81b40d2fe0cc85767f6bd202a01e91b437099a8a90234ac5af3cb7ca4fb1432e133f75f9a91678eaf5f487c74b").as_ref()
2341 )
2342 .await.unwrap();
2343 assert_eq!(
2344 pending.tx_hash().to_string(),
2345 "0x9dae5cf33694a02e8a7d5de3fe31e9d05ca0ba6e9180efac4ab20a06c9e598a3"
2346 );
2347 }
2348
2349 #[tokio::test]
2350 async fn connect_boxed() {
2351 let anvil = Anvil::new().spawn();
2352
2353 let provider = RootProvider::<Ethereum>::connect(anvil.endpoint().as_str()).await;
2354
2355 match provider {
2356 Ok(provider) => {
2357 let num = provider.get_block_number().await.unwrap();
2358 assert_eq!(0, num);
2359 }
2360 Err(e) => {
2361 assert_eq!(
2362 format!("{e}"),
2363 "hyper not supported by BuiltinConnectionString. Please instantiate a hyper client manually"
2364 );
2365 }
2366 }
2367 }
2368
2369 #[tokio::test]
2370 async fn any_network_wallet_filler() {
2371 use alloy_serde::WithOtherFields;
2372 let anvil = Anvil::new().spawn();
2373 let signer: PrivateKeySigner =
2374 "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80".parse().unwrap();
2375 let wallet = EthereumWallet::from(signer);
2376
2377 let provider = ProviderBuilder::new()
2378 .network::<AnyNetwork>()
2379 .wallet(wallet)
2380 .connect_http(anvil.endpoint_url());
2381
2382 let tx = TransactionRequest::default()
2383 .with_to(address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"))
2384 .value(U256::from(325235));
2385
2386 let tx = WithOtherFields::new(tx);
2387
2388 let builder = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();
2389
2390 assert!(builder.status());
2391 }
2392
2393 #[tokio::test]
2394 async fn builtin_connect_boxed() {
2395 let anvil = Anvil::new().spawn();
2396
2397 let conn: BuiltInConnectionString = anvil.endpoint().parse().unwrap();
2398
2399 let transport = conn.connect_boxed().await.unwrap();
2400
2401 let client = alloy_rpc_client::RpcClient::new(transport, true);
2402
2403 let provider = RootProvider::<Ethereum>::new(client);
2404
2405 let num = provider.get_block_number().await.unwrap();
2406 assert_eq!(0, num);
2407 }
2408
2409 #[tokio::test]
2410 async fn test_uncle_count() {
2411 let provider = ProviderBuilder::new().connect_anvil();
2412
2413 let count = provider.get_uncle_count(0.into()).await.unwrap();
2414 assert_eq!(count, 0);
2415 }
2416
2417 #[tokio::test]
2418 #[cfg(any(
2419 feature = "reqwest-default-tls",
2420 feature = "reqwest-rustls-tls",
2421 feature = "reqwest-native-tls",
2422 ))]
2423 #[ignore = "ignore until <https://github.com/paradigmxyz/reth/pull/14727> is in"]
2424 async fn call_mainnet() {
2425 use alloy_network::TransactionBuilder;
2426 use alloy_sol_types::SolValue;
2427
2428 let url = "https://docs-demo.quiknode.pro/";
2429 let provider = ProviderBuilder::new().connect_http(url.parse().unwrap());
2430 let req = TransactionRequest::default()
2431 .with_to(address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")) .with_input(bytes!("06fdde03")); let result = provider.call(req.clone()).await.unwrap();
2434 assert_eq!(String::abi_decode(&result).unwrap(), "Wrapped Ether");
2435
2436 let result = provider.call(req).block(0.into()).await.unwrap();
2437 assert_eq!(result.to_string(), "0x");
2438 }
2439
2440 #[tokio::test]
2441 async fn call_many_mainnet() {
2442 use alloy_rpc_types_eth::{BlockOverrides, StateContext};
2443
2444 let url = "https://docs-demo.quiknode.pro/";
2445 let provider = ProviderBuilder::new().connect_http(url.parse().unwrap());
2446 let tx1 = TransactionRequest::default()
2447 .with_to(address!("6b175474e89094c44da98b954eedeac495271d0f"))
2448 .with_gas_limit(1000000)
2449 .with_gas_price(2023155498)
2450 .with_input(hex!("a9059cbb000000000000000000000000bc0E63965946815d105E7591407704e6e1964E590000000000000000000000000000000000000000000000000000000005f5e100"));
2451 let tx2 = TransactionRequest::default()
2452 .with_to(address!("833589fcd6edb6e08f4c7c32d4f71b54bda02913"))
2453 .with_gas_price(2023155498)
2454 .with_input(hex!(
2455 "70a08231000000000000000000000000bc0E63965946815d105E7591407704e6e1964E59"
2456 ));
2457
2458 let transactions = vec![tx1.clone(), tx2.clone()];
2459
2460 let block_override =
2461 BlockOverrides { number: Some(U256::from(12279785)), ..Default::default() };
2462
2463 let bundles = vec![Bundle { transactions, block_override: Some(block_override.clone()) }];
2464
2465 let context = StateContext {
2466 block_number: Some(BlockId::number(12279785)),
2467 transaction_index: Some(1.into()),
2468 };
2469
2470 let results = provider.call_many(&bundles).context(&context).await.unwrap();
2471
2472 let tx1_res = EthCallResponse {
2473 value: Some(
2474 hex!("0000000000000000000000000000000000000000000000000000000000000001").into(),
2475 ),
2476 error: None,
2477 };
2478 let tx2_res = EthCallResponse { value: Some(Bytes::new()), error: None };
2479 let expected = vec![vec![tx1_res.clone(), tx2_res.clone()]];
2480
2481 assert_eq!(results, expected);
2482
2483 let bundles = vec![
2485 Bundle {
2486 transactions: vec![tx1.clone()],
2487 block_override: Some(block_override.clone()),
2488 },
2489 Bundle {
2490 transactions: vec![tx2.clone()],
2491 block_override: Some(block_override.clone()),
2492 },
2493 ];
2494
2495 let results = provider.call_many(&bundles).context(&context).await.unwrap();
2496 let expected = vec![vec![tx1_res.clone()], vec![tx2_res.clone()]];
2497 assert_eq!(results, expected);
2498
2499 let b1 =
2501 vec![Bundle { transactions: vec![tx1], block_override: Some(block_override.clone()) }];
2502 let b2 = vec![Bundle { transactions: vec![tx2], block_override: Some(block_override) }];
2503
2504 let results = provider.call_many(&b1).context(&context).extend_bundles(&b2).await.unwrap();
2505 assert_eq!(results, expected);
2506 }
2507
2508 #[tokio::test]
2509 #[cfg(feature = "hyper-tls")]
2510 async fn hyper_https() {
2511 let url = "https://reth-ethereum.ithaca.xyz/rpc";
2512
2513 let provider = ProviderBuilder::new().connect(url).await.unwrap();
2516
2517 let _num = provider.get_block_number().await.unwrap();
2518 }
2519
2520 #[tokio::test]
2521 async fn test_empty_transactions() {
2522 let provider = ProviderBuilder::new().connect_anvil();
2523
2524 let block = provider.get_block_by_number(0.into()).await.unwrap().unwrap();
2525 assert!(block.transactions.is_hashes());
2526 }
2527
2528 #[tokio::test]
2529 async fn disable_test() {
2530 let provider = ProviderBuilder::new()
2531 .disable_recommended_fillers()
2532 .with_cached_nonce_management()
2533 .connect_anvil();
2534
2535 let tx = TransactionRequest::default()
2536 .with_kind(alloy_primitives::TxKind::Create)
2537 .value(U256::from(1235))
2538 .with_input(Bytes::from_str("ffffffffffffff").unwrap());
2539
2540 let err = provider.send_transaction(tx).await.unwrap_err().to_string();
2541 assert!(err.contains("missing properties: [(\"NonceManager\", [\"from\"])]"));
2542 }
2543
2544 #[tokio::test]
2545 async fn capture_anvil_logs() {
2546 let mut anvil = Anvil::new().keep_stdout().spawn();
2547
2548 let provider = ProviderBuilder::new().connect_http(anvil.endpoint_url());
2549
2550 let tx = TransactionRequest::default()
2551 .with_from(address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"))
2552 .with_to(address!("70997970C51812dc3A010C7d01b50e0d17dc79C8"))
2553 .value(U256::from(100));
2554
2555 let _ = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();
2556
2557 anvil.child_mut().kill().unwrap();
2558
2559 let mut output = String::new();
2560 anvil.child_mut().stdout.take().unwrap().read_to_string(&mut output).unwrap();
2561
2562 assert_eq!(anvil.chain_id(), 31337);
2563 assert_eq!(anvil.addresses().len(), 10);
2564 assert_eq!(anvil.keys().len(), 10);
2565
2566 assert!(output.contains("eth_sendTransaction"));
2567 assert!(output.contains("Block Number: 1"))
2568 }
2569
2570 #[tokio::test]
2571 async fn custom_estimator() {
2572 let provider = ProviderBuilder::new()
2573 .disable_recommended_fillers()
2574 .with_cached_nonce_management()
2575 .connect_anvil();
2576
2577 let _ = provider
2578 .estimate_eip1559_fees_with(Eip1559Estimator::new(|_fee, _rewards| Eip1559Estimation {
2579 max_fee_per_gas: 0,
2580 max_priority_fee_per_gas: 0,
2581 }))
2582 .await;
2583 }
2584
2585 #[tokio::test]
2586 #[cfg(not(windows))]
2587 async fn eth_sign_transaction() {
2588 async_ci_only(|| async {
2589 run_with_tempdir("reth-sign-tx", |dir| async {
2590 let reth = Reth::new().dev().disable_discovery().data_dir(dir).spawn();
2591 let provider = ProviderBuilder::new().connect_http(reth.endpoint_url());
2592
2593 let accounts = provider.get_accounts().await.unwrap();
2594 let from = accounts[0];
2595
2596 let tx = TransactionRequest::default()
2597 .from(from)
2598 .to(Address::random())
2599 .value(U256::from(100))
2600 .gas_limit(21000);
2601
2602 let signed_tx = provider.sign_transaction(tx).await.unwrap().to_vec();
2603
2604 let tx = TxEnvelope::decode(&mut signed_tx.as_slice()).unwrap();
2605
2606 let signer = tx.recover_signer().unwrap();
2607
2608 assert_eq!(signer, from);
2609 })
2610 .await
2611 })
2612 .await;
2613 }
2614
2615 #[cfg(feature = "throttle")]
2616 use alloy_transport::layers::ThrottleLayer;
2617
2618 #[cfg(feature = "throttle")]
2619 #[tokio::test]
2620 async fn test_throttled_provider() {
2621 let request_per_second = 10;
2622 let throttle_layer = ThrottleLayer::new(request_per_second);
2623
2624 let anvil = Anvil::new().spawn();
2625 let client = RpcClient::builder().layer(throttle_layer).http(anvil.endpoint_url());
2626 let provider = RootProvider::<Ethereum>::new(client);
2627
2628 let num_requests = 10;
2629 let start = std::time::Instant::now();
2630 for _ in 0..num_requests {
2631 provider.get_block_number().await.unwrap();
2632 }
2633
2634 let elapsed = start.elapsed();
2635 assert_eq!(elapsed.as_secs_f64().round() as u32, 1);
2636 }
2637
2638 #[tokio::test]
2639 #[cfg(feature = "hyper")]
2640 async fn test_connect_hyper_tls() {
2641 let p =
2642 ProviderBuilder::new().connect("https://reth-ethereum.ithaca.xyz/rpc").await.unwrap();
2643
2644 let _num = p.get_block_number().await.unwrap();
2645
2646 let anvil = Anvil::new().spawn();
2647 let p = ProviderBuilder::new().connect(&anvil.endpoint()).await.unwrap();
2648
2649 let _num = p.get_block_number().await.unwrap();
2650 }
2651
2652 #[tokio::test]
2653 async fn test_send_transaction_sync() {
2654 use alloy_network::TransactionBuilder;
2655 use alloy_primitives::{address, U256};
2656
2657 let anvil = Anvil::new().spawn();
2658 let provider = ProviderBuilder::new().connect_http(anvil.endpoint_url());
2659
2660 let tx = TransactionRequest::default()
2661 .with_from(address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"))
2662 .with_to(address!("70997970C51812dc3A010C7d01b50e0d17dc79C8"))
2663 .with_value(U256::from(100));
2664
2665 let receipt = provider.send_transaction_sync(tx).await.unwrap();
2667
2668 let tx_hash = receipt.transaction_hash;
2670 assert!(!tx_hash.is_zero());
2671 assert_eq!(receipt.transaction_hash, tx_hash);
2672 assert!(receipt.status());
2673 }
2674
2675 #[tokio::test]
2676 async fn test_send_transaction_sync_with_fillers() {
2677 use alloy_network::TransactionBuilder;
2678 use alloy_primitives::{address, U256};
2679
2680 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
2681
2682 let tx = TransactionRequest::default()
2684 .with_from(provider.default_signer_address())
2685 .with_to(address!("70997970C51812dc3A010C7d01b50e0d17dc79C8"))
2686 .with_value(U256::from(100));
2687 let receipt = provider.send_transaction_sync(tx).await.unwrap();
2691
2692 let tx_hash = receipt.transaction_hash;
2694 assert!(!tx_hash.is_zero());
2695
2696 assert_eq!(receipt.transaction_hash, tx_hash);
2698 assert!(receipt.status());
2699 assert!(receipt.gas_used() > 0, "fillers should have estimated gas");
2700 }
2701
2702 #[tokio::test]
2703 async fn test_fill_transaction() {
2704 use alloy_network::TransactionBuilder;
2705 use alloy_primitives::{address, U256};
2706
2707 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
2708
2709 let tx = TransactionRequest::default()
2710 .with_from(provider.default_signer_address())
2711 .with_to(address!("70997970C51812dc3A010C7d01b50e0d17dc79C8"))
2712 .with_value(U256::from(100));
2713
2714 let filled = provider.fill_transaction(tx).await.unwrap();
2715
2716 assert!(!filled.raw.is_empty(), "raw transaction bytes should not be empty");
2718
2719 let filled_tx = &filled.tx;
2721 assert!(filled_tx.to().is_some(), "filled transaction should have to address");
2722 assert!(filled_tx.gas_limit() > 0, "filled transaction should have gas limit");
2723 assert!(filled_tx.max_fee_per_gas() > 0, "filled transaction should have max fee per gas");
2724 }
2725}