1#![allow(unknown_lints, elided_named_lifetimes)]
4
5#[cfg(feature = "pubsub")]
6use super::get_block::SubFullBlocks;
7use super::{DynProvider, Empty, EthCallMany, MulticallBuilder, WatchBlocks};
8#[cfg(feature = "pubsub")]
9use crate::GetSubscription;
10use crate::{
11 heart::PendingTransactionError,
12 utils::{self, Eip1559Estimation, Eip1559Estimator},
13 EthCall, EthGetBlock, Identity, PendingTransaction, PendingTransactionBuilder,
14 PendingTransactionConfig, ProviderBuilder, ProviderCall, RootProvider, RpcWithBlock,
15 SendableTx,
16};
17use alloy_consensus::BlockHeader;
18use alloy_eips::eip2718::Encodable2718;
19use alloy_json_rpc::{RpcError, RpcRecv, RpcSend};
20use alloy_network::{Ethereum, Network};
21use alloy_network_primitives::{BlockResponse, ReceiptResponse};
22use alloy_primitives::{
23 hex, Address, BlockHash, BlockNumber, Bytes, StorageKey, StorageValue, TxHash, B256, U128,
24 U256, U64,
25};
26use alloy_rpc_client::{ClientRef, NoParams, PollerBuilder, WeakClient};
27#[cfg(feature = "pubsub")]
28use alloy_rpc_types_eth::pubsub::{Params, SubscriptionKind};
29use alloy_rpc_types_eth::{
30 erc4337::TransactionConditional,
31 simulate::{SimulatePayload, SimulatedBlock},
32 AccessListResult, BlockId, BlockNumberOrTag, Bundle, EIP1186AccountProofResponse,
33 EthCallResponse, FeeHistory, Filter, FilterChanges, Index, Log, SyncStatus,
34};
35use alloy_transport::TransportResult;
36use serde_json::value::RawValue;
37use std::borrow::Cow;
38
39pub type FilterPollerBuilder<R> = PollerBuilder<(U256,), Vec<R>>;
43
44#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
71#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
72#[auto_impl::auto_impl(&, &mut, Rc, Arc, Box)]
73pub trait Provider<N: Network = Ethereum>: Send + Sync {
74 fn root(&self) -> &RootProvider<N>;
76
77 fn builder() -> ProviderBuilder<Identity, Identity, N>
79 where
80 Self: Sized,
81 {
82 ProviderBuilder::default()
83 }
84
85 #[inline]
89 fn client(&self) -> ClientRef<'_> {
90 self.root().client()
91 }
92
93 #[inline]
97 fn weak_client(&self) -> WeakClient {
98 self.root().weak_client()
99 }
100
101 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
114 #[doc(alias = "boxed")]
115 fn erased(self) -> DynProvider<N>
116 where
117 Self: Sized + 'static,
118 {
119 DynProvider::new(self)
120 }
121
122 fn get_accounts(&self) -> ProviderCall<NoParams, Vec<Address>> {
125 self.client().request_noparams("eth_accounts").into()
126 }
127
128 fn get_blob_base_fee(&self) -> ProviderCall<NoParams, U128, u128> {
130 self.client()
131 .request_noparams("eth_blobBaseFee")
132 .map_resp(utils::convert_u128 as fn(U128) -> u128)
133 .into()
134 }
135
136 fn get_block_number(&self) -> ProviderCall<NoParams, U64, BlockNumber> {
138 self.client()
139 .request_noparams("eth_blockNumber")
140 .map_resp(utils::convert_u64 as fn(U64) -> u64)
141 .into()
142 }
143
144 #[doc(alias = "eth_call")]
172 #[doc(alias = "call_with_overrides")]
173 fn call(&self, tx: N::TransactionRequest) -> EthCall<N, Bytes> {
174 EthCall::call(self.weak_client(), tx).block(BlockNumberOrTag::Pending.into())
175 }
176
177 #[doc(alias = "eth_callMany")]
186 fn call_many<'req>(
187 &self,
188 bundles: &'req [Bundle],
189 ) -> EthCallMany<'req, N, Vec<Vec<EthCallResponse>>> {
190 EthCallMany::new(self.weak_client(), bundles)
191 }
192
193 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
231 fn multicall(&self) -> MulticallBuilder<Empty, &Self, N>
232 where
233 Self: Sized,
234 {
235 MulticallBuilder::new(self)
236 }
237
238 #[doc(alias = "eth_simulateV1")]
242 fn simulate<'req>(
243 &self,
244 payload: &'req SimulatePayload,
245 ) -> RpcWithBlock<&'req SimulatePayload, Vec<SimulatedBlock<N::BlockResponse>>> {
246 self.client().request("eth_simulateV1", payload).into()
247 }
248
249 fn get_chain_id(&self) -> ProviderCall<NoParams, U64, u64> {
251 self.client()
252 .request_noparams("eth_chainId")
253 .map_resp(utils::convert_u64 as fn(U64) -> u64)
254 .into()
255 }
256
257 fn create_access_list<'a>(
261 &self,
262 request: &'a N::TransactionRequest,
263 ) -> RpcWithBlock<&'a N::TransactionRequest, AccessListResult> {
264 self.client().request("eth_createAccessList", request).into()
265 }
266
267 fn estimate_gas(&self, tx: N::TransactionRequest) -> EthCall<N, U64, u64> {
281 EthCall::gas_estimate(self.weak_client(), tx)
282 .block(BlockNumberOrTag::Pending.into())
283 .map_resp(utils::convert_u64)
284 }
285
286 async fn estimate_eip1559_fees_with(
291 &self,
292 estimator: Eip1559Estimator,
293 ) -> TransportResult<Eip1559Estimation> {
294 let fee_history = self
295 .get_fee_history(
296 utils::EIP1559_FEE_ESTIMATION_PAST_BLOCKS,
297 BlockNumberOrTag::Latest,
298 &[utils::EIP1559_FEE_ESTIMATION_REWARD_PERCENTILE],
299 )
300 .await?;
301
302 let base_fee_per_gas = match fee_history.latest_block_base_fee() {
305 Some(base_fee) if base_fee != 0 => base_fee,
306 _ => {
307 self.get_block_by_number(BlockNumberOrTag::Latest)
309 .await?
310 .ok_or(RpcError::NullResp)?
311 .header()
312 .as_ref()
313 .base_fee_per_gas()
314 .ok_or(RpcError::UnsupportedFeature("eip1559"))?
315 .into()
316 }
317 };
318
319 Ok(estimator.estimate(base_fee_per_gas, &fee_history.reward.unwrap_or_default()))
320 }
321
322 async fn estimate_eip1559_fees(&self) -> TransportResult<Eip1559Estimation> {
326 self.estimate_eip1559_fees_with(Eip1559Estimator::default()).await
327 }
328
329 async fn get_fee_history(
333 &self,
334 block_count: u64,
335 last_block: BlockNumberOrTag,
336 reward_percentiles: &[f64],
337 ) -> TransportResult<FeeHistory> {
338 self.client()
339 .request("eth_feeHistory", (U64::from(block_count), last_block, reward_percentiles))
340 .await
341 }
342
343 fn get_gas_price(&self) -> ProviderCall<NoParams, U128, u128> {
345 self.client()
346 .request_noparams("eth_gasPrice")
347 .map_resp(utils::convert_u128 as fn(U128) -> u128)
348 .into()
349 }
350
351 fn get_account_info(
357 &self,
358 address: Address,
359 ) -> RpcWithBlock<Address, alloy_rpc_types_eth::AccountInfo> {
360 self.client().request("eth_getAccountInfo", address).into()
361 }
362
363 fn get_account(&self, address: Address) -> RpcWithBlock<Address, alloy_consensus::Account> {
366 self.client().request("eth_getAccount", address).into()
367 }
368
369 fn get_balance(&self, address: Address) -> RpcWithBlock<Address, U256, U256> {
373 self.client().request("eth_getBalance", address).into()
374 }
375
376 fn get_block(&self, block: BlockId) -> EthGetBlock<N::BlockResponse> {
387 match block {
388 BlockId::Hash(hash) => EthGetBlock::by_hash(hash.block_hash, self.client()),
389 BlockId::Number(number) => EthGetBlock::by_number(number, self.client()),
390 }
391 }
392
393 fn get_block_by_hash(&self, hash: BlockHash) -> EthGetBlock<N::BlockResponse> {
420 EthGetBlock::by_hash(hash, self.client())
421 }
422
423 fn get_block_by_number(&self, number: BlockNumberOrTag) -> EthGetBlock<N::BlockResponse> {
448 EthGetBlock::by_number(number, self.client())
449 }
450
451 async fn get_block_transaction_count_by_hash(
453 &self,
454 hash: BlockHash,
455 ) -> TransportResult<Option<u64>> {
456 self.client()
457 .request("eth_getBlockTransactionCountByHash", (hash,))
458 .await
459 .map(|opt_count: Option<U64>| opt_count.map(|count| count.to::<u64>()))
460 }
461
462 async fn get_block_transaction_count_by_number(
464 &self,
465 block_number: BlockNumberOrTag,
466 ) -> TransportResult<Option<u64>> {
467 self.client()
468 .request("eth_getBlockTransactionCountByNumber", (block_number,))
469 .await
470 .map(|opt_count: Option<U64>| opt_count.map(|count| count.to::<u64>()))
471 }
472
473 fn get_block_receipts(
475 &self,
476 block: BlockId,
477 ) -> ProviderCall<(BlockId,), Option<Vec<N::ReceiptResponse>>> {
478 self.client().request("eth_getBlockReceipts", (block,)).into()
479 }
480
481 fn get_code_at(&self, address: Address) -> RpcWithBlock<Address, Bytes> {
483 self.client().request("eth_getCode", address).into()
484 }
485
486 async fn watch_blocks(&self) -> TransportResult<FilterPollerBuilder<B256>> {
509 let id = self.new_block_filter().await?;
510 Ok(PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,)))
511 }
512
513 async fn watch_full_blocks(&self) -> TransportResult<WatchBlocks<N::BlockResponse>> {
537 let id = self.new_block_filter().await?;
538 let poller = PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,));
539
540 Ok(WatchBlocks::new(poller))
541 }
542
543 async fn watch_pending_transactions(&self) -> TransportResult<FilterPollerBuilder<B256>> {
566 let id = self.new_pending_transactions_filter(false).await?;
567 Ok(PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,)))
568 }
569
570 async fn watch_logs(&self, filter: &Filter) -> TransportResult<FilterPollerBuilder<Log>> {
599 let id = self.new_filter(filter).await?;
600 Ok(PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,)))
601 }
602
603 async fn watch_full_pending_transactions(
630 &self,
631 ) -> TransportResult<FilterPollerBuilder<N::TransactionResponse>> {
632 let id = self.new_pending_transactions_filter(true).await?;
633 Ok(PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,)))
634 }
635
636 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
641 async fn get_filter_changes<R: RpcRecv>(&self, id: U256) -> TransportResult<Vec<R>>
642 where
643 Self: Sized,
644 {
645 self.client().request("eth_getFilterChanges", (id,)).await
646 }
647
648 async fn get_filter_changes_dyn(&self, id: U256) -> TransportResult<FilterChanges> {
653 self.client().request("eth_getFilterChanges", (id,)).await
654 }
655
656 async fn get_filter_logs(&self, id: U256) -> TransportResult<Vec<Log>> {
658 self.client().request("eth_getFilterLogs", (id,)).await
659 }
660
661 async fn uninstall_filter(&self, id: U256) -> TransportResult<bool> {
663 self.client().request("eth_uninstallFilter", (id,)).await
664 }
665
666 #[inline]
671 async fn watch_pending_transaction(
672 &self,
673 config: PendingTransactionConfig,
674 ) -> Result<PendingTransaction, PendingTransactionError> {
675 self.root().watch_pending_transaction(config).await
676 }
677
678 async fn get_logs(&self, filter: &Filter) -> TransportResult<Vec<Log>> {
680 self.client().request("eth_getLogs", (filter,)).await
681 }
682
683 fn get_proof(
687 &self,
688 address: Address,
689 keys: Vec<StorageKey>,
690 ) -> RpcWithBlock<(Address, Vec<StorageKey>), EIP1186AccountProofResponse> {
691 self.client().request("eth_getProof", (address, keys)).into()
692 }
693
694 fn get_storage_at(
696 &self,
697 address: Address,
698 key: U256,
699 ) -> RpcWithBlock<(Address, U256), StorageValue> {
700 self.client().request("eth_getStorageAt", (address, key)).into()
701 }
702
703 fn get_transaction_by_sender_nonce(
707 &self,
708 sender: Address,
709 nonce: u64,
710 ) -> ProviderCall<(Address, U64), Option<N::TransactionResponse>> {
711 self.client()
712 .request("eth_getTransactionBySenderAndNonce", (sender, U64::from(nonce)))
713 .into()
714 }
715
716 fn get_transaction_by_hash(
718 &self,
719 hash: TxHash,
720 ) -> ProviderCall<(TxHash,), Option<N::TransactionResponse>> {
721 self.client().request("eth_getTransactionByHash", (hash,)).into()
722 }
723
724 fn get_transaction_by_block_hash_and_index(
726 &self,
727 block_hash: B256,
728 index: usize,
729 ) -> ProviderCall<(B256, Index), Option<N::TransactionResponse>> {
730 self.client()
731 .request("eth_getTransactionByBlockHashAndIndex", (block_hash, Index(index)))
732 .into()
733 }
734
735 fn get_raw_transaction_by_block_hash_and_index(
737 &self,
738 block_hash: B256,
739 index: usize,
740 ) -> ProviderCall<(B256, Index), Option<Bytes>> {
741 self.client()
742 .request("eth_getRawTransactionByBlockHashAndIndex", (block_hash, Index(index)))
743 .into()
744 }
745
746 fn get_transaction_by_block_number_and_index(
748 &self,
749 block_number: BlockNumberOrTag,
750 index: usize,
751 ) -> ProviderCall<(BlockNumberOrTag, Index), Option<N::TransactionResponse>> {
752 self.client()
753 .request("eth_getTransactionByBlockNumberAndIndex", (block_number, Index(index)))
754 .into()
755 }
756
757 fn get_raw_transaction_by_block_number_and_index(
759 &self,
760 block_number: BlockNumberOrTag,
761 index: usize,
762 ) -> ProviderCall<(BlockNumberOrTag, Index), Option<Bytes>> {
763 self.client()
764 .request("eth_getRawTransactionByBlockNumberAndIndex", (block_number, Index(index)))
765 .into()
766 }
767
768 fn get_raw_transaction_by_hash(&self, hash: TxHash) -> ProviderCall<(TxHash,), Option<Bytes>> {
777 self.client().request("eth_getRawTransactionByHash", (hash,)).into()
778 }
779
780 #[doc(alias = "get_nonce")]
782 #[doc(alias = "get_account_nonce")]
783 fn get_transaction_count(
784 &self,
785 address: Address,
786 ) -> RpcWithBlock<Address, U64, u64, fn(U64) -> u64> {
787 self.client()
788 .request("eth_getTransactionCount", address)
789 .map_resp(utils::convert_u64 as fn(U64) -> u64)
790 .into()
791 }
792
793 fn get_transaction_receipt(
795 &self,
796 hash: TxHash,
797 ) -> ProviderCall<(TxHash,), Option<N::ReceiptResponse>> {
798 self.client().request("eth_getTransactionReceipt", (hash,)).into()
799 }
800
801 async fn get_uncle(&self, tag: BlockId, idx: u64) -> TransportResult<Option<N::BlockResponse>> {
803 let idx = U64::from(idx);
804 match tag {
805 BlockId::Hash(hash) => {
806 self.client()
807 .request("eth_getUncleByBlockHashAndIndex", (hash.block_hash, idx))
808 .await
809 }
810 BlockId::Number(number) => {
811 self.client().request("eth_getUncleByBlockNumberAndIndex", (number, idx)).await
812 }
813 }
814 }
815
816 async fn get_uncle_count(&self, tag: BlockId) -> TransportResult<u64> {
818 match tag {
819 BlockId::Hash(hash) => self
820 .client()
821 .request("eth_getUncleCountByBlockHash", (hash.block_hash,))
822 .await
823 .map(|count: U64| count.to::<u64>()),
824 BlockId::Number(number) => self
825 .client()
826 .request("eth_getUncleCountByBlockNumber", (number,))
827 .await
828 .map(|count: U64| count.to::<u64>()),
829 }
830 }
831
832 fn get_max_priority_fee_per_gas(&self) -> ProviderCall<NoParams, U128, u128> {
834 self.client()
835 .request_noparams("eth_maxPriorityFeePerGas")
836 .map_resp(utils::convert_u128 as fn(U128) -> u128)
837 .into()
838 }
839
840 async fn new_block_filter(&self) -> TransportResult<U256> {
846 self.client().request_noparams("eth_newBlockFilter").await
847 }
848
849 async fn new_filter(&self, filter: &Filter) -> TransportResult<U256> {
855 self.client().request("eth_newFilter", (filter,)).await
856 }
857
858 async fn new_pending_transactions_filter(&self, full: bool) -> TransportResult<U256> {
868 let param = if full { &[true][..] } else { &[] };
870 self.client().request("eth_newPendingTransactionFilter", param).await
871 }
872
873 async fn send_raw_transaction(
877 &self,
878 encoded_tx: &[u8],
879 ) -> TransportResult<PendingTransactionBuilder<N>> {
880 let rlp_hex = hex::encode_prefixed(encoded_tx);
881 let tx_hash = self.client().request("eth_sendRawTransaction", (rlp_hex,)).await?;
882 Ok(PendingTransactionBuilder::new(self.root().clone(), tx_hash))
883 }
884
885 async fn send_raw_transaction_conditional(
896 &self,
897 encoded_tx: &[u8],
898 conditional: TransactionConditional,
899 ) -> TransportResult<PendingTransactionBuilder<N>> {
900 let rlp_hex = hex::encode_prefixed(encoded_tx);
901 let tx_hash = self
902 .client()
903 .request("eth_sendRawTransactionConditional", (rlp_hex, conditional))
904 .await?;
905 Ok(PendingTransactionBuilder::new(self.root().clone(), tx_hash))
906 }
907
908 async fn send_transaction(
929 &self,
930 tx: N::TransactionRequest,
931 ) -> TransportResult<PendingTransactionBuilder<N>> {
932 self.send_transaction_internal(SendableTx::Builder(tx)).await
933 }
934
935 async fn send_tx_envelope(
940 &self,
941 tx: N::TxEnvelope,
942 ) -> TransportResult<PendingTransactionBuilder<N>> {
943 self.send_transaction_internal(SendableTx::Envelope(tx)).await
944 }
945
946 #[doc(hidden)]
954 async fn send_transaction_internal(
955 &self,
956 tx: SendableTx<N>,
957 ) -> TransportResult<PendingTransactionBuilder<N>> {
958 let _handle = self.root().get_heart();
961
962 match tx {
963 SendableTx::Builder(mut tx) => {
964 alloy_network::TransactionBuilder::prep_for_submission(&mut tx);
965 let tx_hash = self.client().request("eth_sendTransaction", (tx,)).await?;
966 Ok(PendingTransactionBuilder::new(self.root().clone(), tx_hash))
967 }
968 SendableTx::Envelope(tx) => {
969 let encoded_tx = tx.encoded_2718();
970 self.send_raw_transaction(&encoded_tx).await
971 }
972 }
973 }
974
975 async fn sign_transaction(&self, tx: N::TransactionRequest) -> TransportResult<Bytes> {
980 self.client().request("eth_signTransaction", (tx,)).await
981 }
982
983 #[cfg(feature = "pubsub")]
1009 fn subscribe_blocks(&self) -> GetSubscription<(SubscriptionKind,), N::HeaderResponse> {
1010 let rpc_call = self.client().request("eth_subscribe", (SubscriptionKind::NewHeads,));
1011 GetSubscription::new(self.weak_client(), rpc_call)
1012 }
1013
1014 #[cfg(feature = "pubsub")]
1038 fn subscribe_full_blocks(&self) -> SubFullBlocks<N> {
1039 SubFullBlocks::new(self.subscribe_blocks(), self.weak_client())
1040 }
1041
1042 #[cfg(feature = "pubsub")]
1068 fn subscribe_pending_transactions(&self) -> GetSubscription<(SubscriptionKind,), B256> {
1069 let rpc_call =
1070 self.client().request("eth_subscribe", (SubscriptionKind::NewPendingTransactions,));
1071 GetSubscription::new(self.weak_client(), rpc_call)
1072 }
1073
1074 #[cfg(feature = "pubsub")]
1105 fn subscribe_full_pending_transactions(
1106 &self,
1107 ) -> GetSubscription<(SubscriptionKind, Params), N::TransactionResponse> {
1108 let rpc_call = self.client().request(
1109 "eth_subscribe",
1110 (SubscriptionKind::NewPendingTransactions, Params::Bool(true)),
1111 );
1112 GetSubscription::new(self.weak_client(), rpc_call)
1113 }
1114
1115 #[cfg(feature = "pubsub")]
1146 fn subscribe_logs(&self, filter: &Filter) -> GetSubscription<(SubscriptionKind, Params), Log> {
1147 let rpc_call = self.client().request(
1148 "eth_subscribe",
1149 (SubscriptionKind::Logs, Params::Logs(Box::new(filter.clone()))),
1150 );
1151 GetSubscription::new(self.weak_client(), rpc_call)
1152 }
1153
1154 #[cfg(feature = "pubsub")]
1156 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
1157 fn subscribe<P, R>(&self, params: P) -> GetSubscription<P, R>
1158 where
1159 P: RpcSend,
1160 R: RpcRecv,
1161 Self: Sized,
1162 {
1163 let rpc_call = self.client().request("eth_subscribe", params);
1164 GetSubscription::new(self.weak_client(), rpc_call)
1165 }
1166
1167 #[cfg(feature = "pubsub")]
1169 async fn unsubscribe(&self, id: B256) -> TransportResult<()> {
1170 self.root().unsubscribe(id)
1171 }
1172
1173 fn syncing(&self) -> ProviderCall<NoParams, SyncStatus> {
1175 self.client().request_noparams("eth_syncing").into()
1176 }
1177
1178 #[doc(alias = "web3_client_version")]
1180 fn get_client_version(&self) -> ProviderCall<NoParams, String> {
1181 self.client().request_noparams("web3_clientVersion").into()
1182 }
1183
1184 #[doc(alias = "web3_sha3")]
1186 fn get_sha3(&self, data: &[u8]) -> ProviderCall<(String,), B256> {
1187 self.client().request("web3_sha3", (hex::encode_prefixed(data),)).into()
1188 }
1189
1190 fn get_net_version(&self) -> ProviderCall<NoParams, U64, u64> {
1192 self.client()
1193 .request_noparams("net_version")
1194 .map_resp(utils::convert_u64 as fn(U64) -> u64)
1195 .into()
1196 }
1197
1198 async fn raw_request<P, R>(&self, method: Cow<'static, str>, params: P) -> TransportResult<R>
1223 where
1224 P: RpcSend,
1225 R: RpcRecv,
1226 Self: Sized,
1227 {
1228 self.client().request(method, ¶ms).await
1229 }
1230
1231 async fn raw_request_dyn(
1254 &self,
1255 method: Cow<'static, str>,
1256 params: &RawValue,
1257 ) -> TransportResult<Box<RawValue>> {
1258 self.client().request(method, params).await
1259 }
1260
1261 #[inline]
1263 fn transaction_request(&self) -> N::TransactionRequest {
1264 Default::default()
1265 }
1266}
1267
1268#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
1269#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
1270impl<N: Network> Provider<N> for RootProvider<N> {
1271 #[inline]
1272 fn root(&self) -> &Self {
1273 self
1274 }
1275
1276 #[inline]
1277 fn client(&self) -> ClientRef<'_> {
1278 self.inner.client_ref()
1279 }
1280
1281 #[inline]
1282 fn weak_client(&self) -> WeakClient {
1283 self.inner.weak_client()
1284 }
1285
1286 #[inline]
1287 async fn watch_pending_transaction(
1288 &self,
1289 config: PendingTransactionConfig,
1290 ) -> Result<PendingTransaction, PendingTransactionError> {
1291 let block_number =
1292 if let Some(receipt) = self.get_transaction_receipt(*config.tx_hash()).await? {
1293 if config.required_confirmations() <= 1 {
1295 return Ok(PendingTransaction::ready(*config.tx_hash()));
1296 }
1297 receipt.block_number()
1300 } else {
1301 None
1302 };
1303
1304 self.get_heart()
1305 .watch_tx(config, block_number)
1306 .await
1307 .map_err(|_| PendingTransactionError::FailedToRegister)
1308 }
1309}
1310
1311#[cfg(test)]
1312mod tests {
1313 use super::*;
1314 use crate::{builder, ext::test::async_ci_only, ProviderBuilder, WalletProvider};
1315 use alloy_consensus::{Transaction, TxEnvelope};
1316 use alloy_network::{AnyNetwork, EthereumWallet, TransactionBuilder};
1317 use alloy_node_bindings::{utils::run_with_tempdir, Anvil, Reth};
1318 use alloy_primitives::{address, b256, bytes, keccak256};
1319 use alloy_rlp::Decodable;
1320 use alloy_rpc_client::{BuiltInConnectionString, RpcClient};
1321 use alloy_rpc_types_eth::{request::TransactionRequest, Block};
1322 use alloy_signer_local::PrivateKeySigner;
1323 use alloy_transport::layers::{RetryBackoffLayer, RetryPolicy};
1324 use std::{io::Read, str::FromStr, time::Duration};
1325
1326 use alloy_consensus::transaction::SignerRecoverable;
1328 #[cfg(feature = "hyper")]
1329 use alloy_transport_http::{
1330 hyper,
1331 hyper::body::Bytes as HyperBytes,
1332 hyper_util::{
1333 client::legacy::{Client, Error},
1334 rt::TokioExecutor,
1335 },
1336 HyperResponse, HyperResponseFut,
1337 };
1338 #[cfg(feature = "hyper")]
1339 use http_body_util::Full;
1340 #[cfg(feature = "hyper")]
1341 use tower::{Layer, Service};
1342
1343 #[tokio::test]
1344 async fn test_provider_builder() {
1345 let provider =
1346 RootProvider::<Ethereum>::builder().with_recommended_fillers().connect_anvil();
1347 let num = provider.get_block_number().await.unwrap();
1348 assert_eq!(0, num);
1349 }
1350
1351 #[tokio::test]
1352 async fn test_builder_helper_fn() {
1353 let provider = builder::<Ethereum>().with_recommended_fillers().connect_anvil();
1354 let num = provider.get_block_number().await.unwrap();
1355 assert_eq!(0, num);
1356 }
1357
1358 #[cfg(feature = "hyper")]
1359 #[tokio::test]
1360 async fn test_default_hyper_transport() {
1361 let anvil = Anvil::new().spawn();
1362 let hyper_t = alloy_transport_http::HyperTransport::new_hyper(anvil.endpoint_url());
1363
1364 let rpc_client = alloy_rpc_client::RpcClient::new(hyper_t, true);
1365
1366 let provider = RootProvider::<Ethereum>::new(rpc_client);
1367 let num = provider.get_block_number().await.unwrap();
1368 assert_eq!(0, num);
1369 }
1370
1371 #[cfg(feature = "hyper")]
1372 #[tokio::test]
1373 async fn test_hyper_layer_transport() {
1374 struct LoggingLayer;
1375
1376 impl<S> Layer<S> for LoggingLayer {
1377 type Service = LoggingService<S>;
1378
1379 fn layer(&self, inner: S) -> Self::Service {
1380 LoggingService { inner }
1381 }
1382 }
1383
1384 #[derive(Clone)] struct LoggingService<S> {
1386 inner: S,
1387 }
1388
1389 impl<S, B> Service<hyper::Request<B>> for LoggingService<S>
1390 where
1391 S: Service<hyper::Request<B>, Response = HyperResponse, Error = Error>
1392 + Clone
1393 + Send
1394 + Sync
1395 + 'static,
1396 S::Future: Send,
1397 S::Error: std::error::Error + Send + Sync + 'static,
1398 B: From<Vec<u8>> + Send + 'static + Clone + Sync + std::fmt::Debug,
1399 {
1400 type Response = HyperResponse;
1401 type Error = Error;
1402 type Future = HyperResponseFut;
1403
1404 fn poll_ready(
1405 &mut self,
1406 cx: &mut std::task::Context<'_>,
1407 ) -> std::task::Poll<Result<(), Self::Error>> {
1408 self.inner.poll_ready(cx)
1409 }
1410
1411 fn call(&mut self, req: hyper::Request<B>) -> Self::Future {
1412 println!("Logging Layer - HyperRequest {req:?}");
1413
1414 let fut = self.inner.call(req);
1415
1416 Box::pin(fut)
1417 }
1418 }
1419 use http::header::{self, HeaderValue};
1420 use tower_http::{
1421 sensitive_headers::SetSensitiveRequestHeadersLayer, set_header::SetRequestHeaderLayer,
1422 };
1423 let anvil = Anvil::new().spawn();
1424 let hyper_client = Client::builder(TokioExecutor::new()).build_http::<Full<HyperBytes>>();
1425
1426 let service = tower::ServiceBuilder::new()
1428 .layer(SetRequestHeaderLayer::if_not_present(
1429 header::USER_AGENT,
1430 HeaderValue::from_static("alloy app"),
1431 ))
1432 .layer(SetRequestHeaderLayer::overriding(
1433 header::AUTHORIZATION,
1434 HeaderValue::from_static("some-jwt-token"),
1435 ))
1436 .layer(SetRequestHeaderLayer::appending(
1437 header::SET_COOKIE,
1438 HeaderValue::from_static("cookie-value"),
1439 ))
1440 .layer(SetSensitiveRequestHeadersLayer::new([header::AUTHORIZATION])) .layer(LoggingLayer)
1442 .service(hyper_client);
1443
1444 let layer_transport = alloy_transport_http::HyperClient::with_service(service);
1445
1446 let http_hyper =
1447 alloy_transport_http::Http::with_client(layer_transport, anvil.endpoint_url());
1448
1449 let rpc_client = alloy_rpc_client::RpcClient::new(http_hyper, true);
1450
1451 let provider = RootProvider::<Ethereum>::new(rpc_client);
1452 let num = provider.get_block_number().await.unwrap();
1453 assert_eq!(0, num);
1454
1455 let cloned_t = provider.client().transport().clone();
1457
1458 let rpc_client = alloy_rpc_client::RpcClient::new(cloned_t, true);
1459
1460 let provider = RootProvider::<Ethereum>::new(rpc_client);
1461 let num = provider.get_block_number().await.unwrap();
1462 assert_eq!(0, num);
1463 }
1464
1465 #[cfg(feature = "hyper")]
1466 #[tokio::test]
1467 #[cfg_attr(windows, ignore = "no reth on windows")]
1468 async fn test_auth_layer_transport() {
1469 crate::ext::test::async_ci_only(|| async move {
1470 use alloy_node_bindings::Reth;
1471 use alloy_rpc_types_engine::JwtSecret;
1472 use alloy_transport_http::{AuthLayer, AuthService, Http, HyperClient};
1473
1474 let secret = JwtSecret::random();
1475
1476 let reth =
1477 Reth::new().arg("--rpc.jwtsecret").arg(hex::encode(secret.as_bytes())).spawn();
1478
1479 let hyper_client =
1480 Client::builder(TokioExecutor::new()).build_http::<Full<HyperBytes>>();
1481
1482 let service =
1483 tower::ServiceBuilder::new().layer(AuthLayer::new(secret)).service(hyper_client);
1484
1485 let layer_transport: HyperClient<
1486 Full<HyperBytes>,
1487 AuthService<
1488 Client<
1489 alloy_transport_http::hyper_util::client::legacy::connect::HttpConnector,
1490 Full<HyperBytes>,
1491 >,
1492 >,
1493 > = HyperClient::with_service(service);
1494
1495 let http_hyper = Http::with_client(layer_transport, reth.endpoint_url());
1496
1497 let rpc_client = alloy_rpc_client::RpcClient::new(http_hyper, true);
1498
1499 let provider = RootProvider::<Ethereum>::new(rpc_client);
1500
1501 let num = provider.get_block_number().await.unwrap();
1502 assert_eq!(0, num);
1503 })
1504 .await;
1505 }
1506
1507 #[tokio::test]
1508 async fn test_builder_helper_fn_any_network() {
1509 let anvil = Anvil::new().spawn();
1510 let provider =
1511 builder::<AnyNetwork>().with_recommended_fillers().connect_http(anvil.endpoint_url());
1512 let num = provider.get_block_number().await.unwrap();
1513 assert_eq!(0, num);
1514 }
1515
1516 #[cfg(feature = "reqwest")]
1517 #[tokio::test]
1518 async fn object_safety() {
1519 let provider = ProviderBuilder::new().connect_anvil();
1520
1521 let refdyn = &provider as &dyn Provider<_>;
1522 let num = refdyn.get_block_number().await.unwrap();
1523 assert_eq!(0, num);
1524 }
1525
1526 #[cfg(feature = "ws")]
1527 #[tokio::test]
1528 async fn subscribe_blocks_http() {
1529 let provider = ProviderBuilder::new().connect_anvil_with_config(|a| a.block_time(1));
1530
1531 let err = provider.subscribe_blocks().await.unwrap_err();
1532 let alloy_json_rpc::RpcError::Transport(
1533 alloy_transport::TransportErrorKind::PubsubUnavailable,
1534 ) = err
1535 else {
1536 panic!("{err:?}");
1537 };
1538 }
1539
1540 #[cfg(feature = "ws")]
1542 #[tokio::test]
1543 async fn websocket_tls_setup() {
1544 for url in ["wss://mainnet.infura.io/ws/v3/b0f825787ba840af81e46c6a64d20754"] {
1545 let _ = ProviderBuilder::<_, _, Ethereum>::default().connect(url).await.unwrap();
1546 }
1547 }
1548
1549 #[cfg(feature = "ws")]
1550 #[tokio::test]
1551 async fn subscribe_blocks_ws() {
1552 use futures::stream::StreamExt;
1553
1554 let anvil = Anvil::new().block_time_f64(0.2).spawn();
1555 let ws = alloy_rpc_client::WsConnect::new(anvil.ws_endpoint());
1556 let client = alloy_rpc_client::RpcClient::connect_pubsub(ws).await.unwrap();
1557 let provider = RootProvider::<Ethereum>::new(client);
1558
1559 let sub = provider.subscribe_blocks().await.unwrap();
1560 let mut stream = sub.into_stream().take(5);
1561 let mut next = None;
1562 while let Some(header) = stream.next().await {
1563 if let Some(next) = &mut next {
1564 assert_eq!(header.number, *next);
1565 *next += 1;
1566 } else {
1567 next = Some(header.number + 1);
1568 }
1569 }
1570 }
1571
1572 #[cfg(feature = "ws")]
1573 #[tokio::test]
1574 async fn subscribe_full_blocks() {
1575 use futures::StreamExt;
1576
1577 let anvil = Anvil::new().block_time_f64(0.2).spawn();
1578 let ws = alloy_rpc_client::WsConnect::new(anvil.ws_endpoint());
1579 let client = alloy_rpc_client::RpcClient::connect_pubsub(ws).await.unwrap();
1580
1581 let provider = RootProvider::<Ethereum>::new(client);
1582
1583 let sub = provider.subscribe_full_blocks().hashes().channel_size(10);
1584
1585 let mut stream = sub.into_stream().await.unwrap().take(5);
1586
1587 let mut next = None;
1588 while let Some(Ok(block)) = stream.next().await {
1589 if let Some(next) = &mut next {
1590 assert_eq!(block.header().number, *next);
1591 *next += 1;
1592 } else {
1593 next = Some(block.header().number + 1);
1594 }
1595 }
1596 }
1597
1598 #[tokio::test]
1599 #[cfg(feature = "ws")]
1600 async fn subscribe_blocks_ws_remote() {
1601 use futures::stream::StreamExt;
1602
1603 let url = "wss://eth-mainnet.g.alchemy.com/v2/viFmeVzhg6bWKVMIWWS8MhmzREB-D4f7";
1604 let ws = alloy_rpc_client::WsConnect::new(url);
1605 let Ok(client) = alloy_rpc_client::RpcClient::connect_pubsub(ws).await else { return };
1606 let provider = RootProvider::<Ethereum>::new(client);
1607 let sub = provider.subscribe_blocks().await.unwrap();
1608 let mut stream = sub.into_stream().take(1);
1609 while let Some(header) = stream.next().await {
1610 println!("New block {header:?}");
1611 assert!(header.number > 0);
1612 }
1613 }
1614
1615 #[tokio::test]
1616 async fn test_custom_retry_policy() {
1617 #[derive(Debug, Clone)]
1618 struct CustomPolicy;
1619 impl RetryPolicy for CustomPolicy {
1620 fn should_retry(&self, _err: &alloy_transport::TransportError) -> bool {
1621 true
1622 }
1623
1624 fn backoff_hint(
1625 &self,
1626 _error: &alloy_transport::TransportError,
1627 ) -> Option<std::time::Duration> {
1628 None
1629 }
1630 }
1631
1632 let retry_layer = RetryBackoffLayer::new_with_policy(10, 100, 10000, CustomPolicy);
1633 let anvil = Anvil::new().spawn();
1634 let client = RpcClient::builder().layer(retry_layer).http(anvil.endpoint_url());
1635
1636 let provider = RootProvider::<Ethereum>::new(client);
1637 let num = provider.get_block_number().await.unwrap();
1638 assert_eq!(0, num);
1639 }
1640
1641 #[tokio::test]
1642 async fn test_send_tx() {
1643 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
1644 let tx = TransactionRequest {
1645 value: Some(U256::from(100)),
1646 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
1647 gas_price: Some(20e9 as u128),
1648 gas: Some(21000),
1649 ..Default::default()
1650 };
1651
1652 let builder = provider.send_transaction(tx.clone()).await.expect("failed to send tx");
1653 let hash1 = *builder.tx_hash();
1654 let hash2 = builder.watch().await.expect("failed to await pending tx");
1655 assert_eq!(hash1, hash2);
1656
1657 let builder = provider.send_transaction(tx).await.expect("failed to send tx");
1658 let hash1 = *builder.tx_hash();
1659 let hash2 =
1660 builder.get_receipt().await.expect("failed to await pending tx").transaction_hash;
1661 assert_eq!(hash1, hash2);
1662 }
1663
1664 #[tokio::test]
1665 async fn test_watch_confirmed_tx() {
1666 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
1667 let tx = TransactionRequest {
1668 value: Some(U256::from(100)),
1669 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
1670 gas_price: Some(20e9 as u128),
1671 gas: Some(21000),
1672 ..Default::default()
1673 };
1674
1675 let builder = provider.send_transaction(tx.clone()).await.expect("failed to send tx");
1676 let hash1 = *builder.tx_hash();
1677
1678 loop {
1680 if provider
1681 .get_transaction_receipt(hash1)
1682 .await
1683 .expect("failed to await pending tx")
1684 .is_some()
1685 {
1686 break;
1687 }
1688 }
1689
1690 let tx2 = TransactionRequest {
1692 value: Some(U256::from(100)),
1693 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
1694 gas_price: Some(20e9 as u128),
1695 gas: Some(21000),
1696 ..Default::default()
1697 };
1698 provider.send_transaction(tx2).await.expect("failed to send tx").watch().await.unwrap();
1699
1700 let watch = builder.watch();
1702 let watch_with_timeout = tokio::time::timeout(Duration::from_secs(1), watch);
1704 let hash2 = watch_with_timeout
1705 .await
1706 .expect("Watching tx timed out")
1707 .expect("failed to await pending tx");
1708 assert_eq!(hash1, hash2);
1709 }
1710
1711 #[tokio::test]
1712 async fn gets_block_number() {
1713 let provider = ProviderBuilder::new().connect_anvil();
1714 let num = provider.get_block_number().await.unwrap();
1715 assert_eq!(0, num)
1716 }
1717
1718 #[tokio::test]
1719 async fn gets_block_number_with_raw_req() {
1720 let provider = ProviderBuilder::new().connect_anvil();
1721 let num: U64 =
1722 provider.raw_request("eth_blockNumber".into(), NoParams::default()).await.unwrap();
1723 assert_eq!(0, num.to::<u64>())
1724 }
1725
1726 #[cfg(feature = "anvil-api")]
1727 #[tokio::test]
1728 async fn gets_transaction_count() {
1729 let provider = ProviderBuilder::new().connect_anvil();
1730 let accounts = provider.get_accounts().await.unwrap();
1731 let sender = accounts[0];
1732
1733 let count = provider.get_transaction_count(sender).await.unwrap();
1735 assert_eq!(count, 0);
1736
1737 let tx = TransactionRequest {
1739 value: Some(U256::from(100)),
1740 from: Some(sender),
1741 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
1742 gas_price: Some(20e9 as u128),
1743 gas: Some(21000),
1744 ..Default::default()
1745 };
1746 let _ = provider.send_transaction(tx).await.unwrap().get_receipt().await;
1747
1748 let count = provider.get_transaction_count(sender).await.unwrap();
1750 assert_eq!(count, 1);
1751
1752 let count = provider.get_transaction_count(sender).block_id(0.into()).await.unwrap();
1754 assert_eq!(count, 0);
1755 }
1756
1757 #[tokio::test]
1758 async fn gets_block_by_hash() {
1759 let provider = ProviderBuilder::new().connect_anvil();
1760 let num = 0;
1761 let tag: BlockNumberOrTag = num.into();
1762 let block = provider.get_block_by_number(tag).full().await.unwrap().unwrap();
1763 let hash = block.header.hash;
1764 let block = provider.get_block_by_hash(hash).full().await.unwrap().unwrap();
1765 assert_eq!(block.header.hash, hash);
1766 }
1767
1768 #[tokio::test]
1769 async fn gets_block_by_hash_with_raw_req() {
1770 let provider = ProviderBuilder::new().connect_anvil();
1771 let num = 0;
1772 let tag: BlockNumberOrTag = num.into();
1773 let block = provider.get_block_by_number(tag).full().await.unwrap().unwrap();
1774 let hash = block.header.hash;
1775 let block: Block = provider
1776 .raw_request::<(B256, bool), Block>("eth_getBlockByHash".into(), (hash, true))
1777 .await
1778 .unwrap();
1779 assert_eq!(block.header.hash, hash);
1780 }
1781
1782 #[tokio::test]
1783 async fn gets_block_by_number_full() {
1784 let provider = ProviderBuilder::new().connect_anvil();
1785 let num = 0;
1786 let tag: BlockNumberOrTag = num.into();
1787 let block = provider.get_block_by_number(tag).full().await.unwrap().unwrap();
1788 assert_eq!(block.header.number, num);
1789 }
1790
1791 #[tokio::test]
1792 async fn gets_block_by_number() {
1793 let provider = ProviderBuilder::new().connect_anvil();
1794 let num = 0;
1795 let tag: BlockNumberOrTag = num.into();
1796 let block = provider.get_block_by_number(tag).full().await.unwrap().unwrap();
1797 assert_eq!(block.header.number, num);
1798 }
1799
1800 #[tokio::test]
1801 async fn gets_client_version() {
1802 let provider = ProviderBuilder::new().connect_anvil();
1803 let version = provider.get_client_version().await.unwrap();
1804 assert!(version.contains("anvil"), "{version}");
1805 }
1806
1807 #[tokio::test]
1808 async fn gets_sha3() {
1809 let provider = ProviderBuilder::new().connect_anvil();
1810 let data = b"alloy";
1811 let hash = provider.get_sha3(data).await.unwrap();
1812 assert_eq!(hash, keccak256(data));
1813 }
1814
1815 #[tokio::test]
1816 async fn gets_chain_id() {
1817 let dev_chain_id: u64 = 13371337;
1818
1819 let provider =
1820 ProviderBuilder::new().connect_anvil_with_config(|a| a.chain_id(dev_chain_id));
1821
1822 let chain_id = provider.get_chain_id().await.unwrap();
1823 assert_eq!(chain_id, dev_chain_id);
1824 }
1825
1826 #[tokio::test]
1827 async fn gets_network_id() {
1828 let dev_chain_id: u64 = 13371337;
1829 let provider =
1830 ProviderBuilder::new().connect_anvil_with_config(|a| a.chain_id(dev_chain_id));
1831
1832 let chain_id = provider.get_net_version().await.unwrap();
1833 assert_eq!(chain_id, dev_chain_id);
1834 }
1835
1836 #[tokio::test]
1837 async fn gets_storage_at() {
1838 let provider = ProviderBuilder::new().connect_anvil();
1839 let addr = Address::with_last_byte(16);
1840 let storage = provider.get_storage_at(addr, U256::ZERO).await.unwrap();
1841 assert_eq!(storage, U256::ZERO);
1842 }
1843
1844 #[tokio::test]
1845 async fn gets_transaction_by_hash_not_found() {
1846 let provider = ProviderBuilder::new().connect_anvil();
1847 let tx_hash = b256!("5c03fab9114ceb98994b43892ade87ddfd9ae7e8f293935c3bd29d435dc9fd95");
1848 let tx = provider.get_transaction_by_hash(tx_hash).await.expect("failed to fetch tx");
1849
1850 assert!(tx.is_none());
1851 }
1852
1853 #[tokio::test]
1854 async fn gets_transaction_by_hash() {
1855 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
1856
1857 let req = TransactionRequest::default()
1858 .from(provider.default_signer_address())
1859 .to(Address::repeat_byte(5))
1860 .value(U256::ZERO)
1861 .input(bytes!("deadbeef").into());
1862
1863 let tx_hash = *provider.send_transaction(req).await.expect("failed to send tx").tx_hash();
1864
1865 let tx = provider
1866 .get_transaction_by_hash(tx_hash)
1867 .await
1868 .expect("failed to fetch tx")
1869 .expect("tx not included");
1870 assert_eq!(tx.input(), &bytes!("deadbeef"));
1871 }
1872
1873 #[tokio::test]
1874 #[ignore]
1875 async fn gets_logs() {
1876 let provider = ProviderBuilder::new().connect_anvil();
1877 let filter = Filter::new()
1878 .at_block_hash(b256!(
1879 "b20e6f35d4b46b3c4cd72152faec7143da851a0dc281d390bdd50f58bfbdb5d3"
1880 ))
1881 .event_signature(b256!(
1882 "e1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c"
1883 ));
1884 let logs = provider.get_logs(&filter).await.unwrap();
1885 assert_eq!(logs.len(), 1);
1886 }
1887
1888 #[tokio::test]
1889 #[ignore]
1890 async fn gets_tx_receipt() {
1891 let provider = ProviderBuilder::new().connect_anvil();
1892 let receipt = provider
1893 .get_transaction_receipt(b256!(
1894 "5c03fab9114ceb98994b43892ade87ddfd9ae7e8f293935c3bd29d435dc9fd95"
1895 ))
1896 .await
1897 .unwrap();
1898 assert!(receipt.is_some());
1899 let receipt = receipt.unwrap();
1900 assert_eq!(
1901 receipt.transaction_hash,
1902 b256!("5c03fab9114ceb98994b43892ade87ddfd9ae7e8f293935c3bd29d435dc9fd95")
1903 );
1904 }
1905
1906 #[tokio::test]
1907 async fn gets_max_priority_fee_per_gas() {
1908 let provider = ProviderBuilder::new().connect_anvil();
1909 let _fee = provider.get_max_priority_fee_per_gas().await.unwrap();
1910 }
1911
1912 #[tokio::test]
1913 async fn gets_fee_history() {
1914 let provider = ProviderBuilder::new().connect_anvil();
1915 let block_number = provider.get_block_number().await.unwrap();
1916 let fee_history = provider
1917 .get_fee_history(
1918 utils::EIP1559_FEE_ESTIMATION_PAST_BLOCKS,
1919 BlockNumberOrTag::Number(block_number),
1920 &[utils::EIP1559_FEE_ESTIMATION_REWARD_PERCENTILE],
1921 )
1922 .await
1923 .unwrap();
1924 assert_eq!(fee_history.oldest_block, 0_u64);
1925 }
1926
1927 #[tokio::test]
1928 async fn gets_block_transaction_count_by_hash() {
1929 let provider = ProviderBuilder::new().connect_anvil();
1930 let block = provider.get_block(BlockId::latest()).await.unwrap().unwrap();
1931 let hash = block.header.hash;
1932 let tx_count = provider.get_block_transaction_count_by_hash(hash).await.unwrap();
1933 assert!(tx_count.is_some());
1934 }
1935
1936 #[tokio::test]
1937 async fn gets_block_transaction_count_by_number() {
1938 let provider = ProviderBuilder::new().connect_anvil();
1939 let tx_count =
1940 provider.get_block_transaction_count_by_number(BlockNumberOrTag::Latest).await.unwrap();
1941 assert!(tx_count.is_some());
1942 }
1943
1944 #[tokio::test]
1945 async fn gets_block_receipts() {
1946 let provider = ProviderBuilder::new().connect_anvil();
1947 let receipts =
1948 provider.get_block_receipts(BlockId::Number(BlockNumberOrTag::Latest)).await.unwrap();
1949 assert!(receipts.is_some());
1950 }
1951
1952 #[tokio::test]
1953 async fn sends_raw_transaction() {
1954 let provider = ProviderBuilder::new().connect_anvil();
1955 let pending = provider
1956 .send_raw_transaction(
1957 bytes!("f865808477359400825208940000000000000000000000000000000000000000018082f4f5a00505e227c1c636c76fac55795db1a40a4d24840d81b40d2fe0cc85767f6bd202a01e91b437099a8a90234ac5af3cb7ca4fb1432e133f75f9a91678eaf5f487c74b").as_ref()
1959 )
1960 .await.unwrap();
1961 assert_eq!(
1962 pending.tx_hash().to_string(),
1963 "0x9dae5cf33694a02e8a7d5de3fe31e9d05ca0ba6e9180efac4ab20a06c9e598a3"
1964 );
1965 }
1966
1967 #[tokio::test]
1968 async fn connect_boxed() {
1969 let anvil = Anvil::new().spawn();
1970
1971 let provider = RootProvider::<Ethereum>::connect(anvil.endpoint().as_str()).await;
1972
1973 match provider {
1974 Ok(provider) => {
1975 let num = provider.get_block_number().await.unwrap();
1976 assert_eq!(0, num);
1977 }
1978 Err(e) => {
1979 assert_eq!(
1980 format!("{e}"),
1981 "hyper not supported by BuiltinConnectionString. Please instantiate a hyper client manually"
1982 );
1983 }
1984 }
1985 }
1986
1987 #[tokio::test]
1988 async fn any_network_wallet_filler() {
1989 use alloy_serde::WithOtherFields;
1990 let anvil = Anvil::new().spawn();
1991 let signer: PrivateKeySigner =
1992 "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80".parse().unwrap();
1993 let wallet = EthereumWallet::from(signer);
1994
1995 let provider = ProviderBuilder::new()
1996 .network::<AnyNetwork>()
1997 .wallet(wallet)
1998 .connect_http(anvil.endpoint_url());
1999
2000 let tx = TransactionRequest::default()
2001 .with_to(address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"))
2002 .value(U256::from(325235));
2003
2004 let tx = WithOtherFields::new(tx);
2005
2006 let builder = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();
2007
2008 assert!(builder.status());
2009 }
2010
2011 #[tokio::test]
2012 async fn builtin_connect_boxed() {
2013 let anvil = Anvil::new().spawn();
2014
2015 let conn: BuiltInConnectionString = anvil.endpoint().parse().unwrap();
2016
2017 let transport = conn.connect_boxed().await.unwrap();
2018
2019 let client = alloy_rpc_client::RpcClient::new(transport, true);
2020
2021 let provider = RootProvider::<Ethereum>::new(client);
2022
2023 let num = provider.get_block_number().await.unwrap();
2024 assert_eq!(0, num);
2025 }
2026
2027 #[tokio::test]
2028 async fn test_uncle_count() {
2029 let provider = ProviderBuilder::new().connect_anvil();
2030
2031 let count = provider.get_uncle_count(0.into()).await.unwrap();
2032 assert_eq!(count, 0);
2033 }
2034
2035 #[tokio::test]
2036 #[cfg(any(
2037 feature = "reqwest-default-tls",
2038 feature = "reqwest-rustls-tls",
2039 feature = "reqwest-native-tls",
2040 ))]
2041 #[ignore = "ignore until <https://github.com/paradigmxyz/reth/pull/14727> is in"]
2042 async fn call_mainnet() {
2043 use alloy_network::TransactionBuilder;
2044 use alloy_sol_types::SolValue;
2045
2046 let url = "https://docs-demo.quiknode.pro/";
2047 let provider = ProviderBuilder::new().connect_http(url.parse().unwrap());
2048 let req = TransactionRequest::default()
2049 .with_to(address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")) .with_input(bytes!("06fdde03")); let result = provider.call(req.clone()).await.unwrap();
2052 assert_eq!(String::abi_decode(&result).unwrap(), "Wrapped Ether");
2053
2054 let result = provider.call(req).block(0.into()).await.unwrap();
2055 assert_eq!(result.to_string(), "0x");
2056 }
2057
2058 #[tokio::test]
2059 async fn call_many_mainnet() {
2060 use alloy_rpc_types_eth::{BlockOverrides, StateContext};
2061
2062 let url = "https://docs-demo.quiknode.pro/";
2063 let provider = ProviderBuilder::new().connect_http(url.parse().unwrap());
2064 let tx1 = TransactionRequest::default()
2065 .with_to(address!("6b175474e89094c44da98b954eedeac495271d0f"))
2066 .with_gas_limit(1000000)
2067 .with_gas_price(2023155498)
2068 .with_input(hex!("a9059cbb000000000000000000000000bc0E63965946815d105E7591407704e6e1964E590000000000000000000000000000000000000000000000000000000005f5e100"));
2069 let tx2 = TransactionRequest::default()
2070 .with_to(address!("833589fcd6edb6e08f4c7c32d4f71b54bda02913"))
2071 .with_gas_price(2023155498)
2072 .with_input(hex!(
2073 "70a08231000000000000000000000000bc0E63965946815d105E7591407704e6e1964E59"
2074 ));
2075
2076 let transactions = vec![tx1.clone(), tx2.clone()];
2077
2078 let block_override =
2079 BlockOverrides { number: Some(U256::from(12279785)), ..Default::default() };
2080
2081 let bundles = vec![Bundle { transactions, block_override: Some(block_override.clone()) }];
2082
2083 let context = StateContext {
2084 block_number: Some(BlockId::number(12279785)),
2085 transaction_index: Some(1.into()),
2086 };
2087
2088 let results = provider.call_many(&bundles).context(&context).await.unwrap();
2089
2090 let tx1_res = EthCallResponse {
2091 value: Some(
2092 hex!("0000000000000000000000000000000000000000000000000000000000000001").into(),
2093 ),
2094 error: None,
2095 };
2096 let tx2_res = EthCallResponse { value: Some(Bytes::new()), error: None };
2097 let expected = vec![vec![tx1_res.clone(), tx2_res.clone()]];
2098
2099 assert_eq!(results, expected);
2100
2101 let bundles = vec![
2103 Bundle {
2104 transactions: vec![tx1.clone()],
2105 block_override: Some(block_override.clone()),
2106 },
2107 Bundle {
2108 transactions: vec![tx2.clone()],
2109 block_override: Some(block_override.clone()),
2110 },
2111 ];
2112
2113 let results = provider.call_many(&bundles).context(&context).await.unwrap();
2114 let expected = vec![vec![tx1_res.clone()], vec![tx2_res.clone()]];
2115 assert_eq!(results, expected);
2116
2117 let b1 =
2119 vec![Bundle { transactions: vec![tx1], block_override: Some(block_override.clone()) }];
2120 let b2 = vec![Bundle { transactions: vec![tx2], block_override: Some(block_override) }];
2121
2122 let results = provider.call_many(&b1).context(&context).extend_bundles(&b2).await.unwrap();
2123 assert_eq!(results, expected);
2124 }
2125
2126 #[tokio::test]
2127 #[cfg(feature = "hyper-tls")]
2128 async fn hyper_https() {
2129 let url = "https://reth-ethereum.ithaca.xyz/rpc";
2130
2131 let provider = ProviderBuilder::new().connect(url).await.unwrap();
2134
2135 let _num = provider.get_block_number().await.unwrap();
2136 }
2137
2138 #[tokio::test]
2139 async fn test_empty_transactions() {
2140 let provider = ProviderBuilder::new().connect_anvil();
2141
2142 let block = provider.get_block_by_number(0.into()).await.unwrap().unwrap();
2143 assert!(block.transactions.is_hashes());
2144 }
2145
2146 #[tokio::test]
2147 async fn disable_test() {
2148 let provider = ProviderBuilder::new()
2149 .disable_recommended_fillers()
2150 .with_cached_nonce_management()
2151 .connect_anvil();
2152
2153 let tx = TransactionRequest::default()
2154 .with_kind(alloy_primitives::TxKind::Create)
2155 .value(U256::from(1235))
2156 .with_input(Bytes::from_str("ffffffffffffff").unwrap());
2157
2158 let err = provider.send_transaction(tx).await.unwrap_err().to_string();
2159 assert!(err.contains("missing properties: [(\"NonceManager\", [\"from\"])]"));
2160 }
2161
2162 #[tokio::test]
2163 async fn capture_anvil_logs() {
2164 let mut anvil = Anvil::new().keep_stdout().spawn();
2165
2166 let provider = ProviderBuilder::new().connect_http(anvil.endpoint_url());
2167
2168 let tx = TransactionRequest::default()
2169 .with_from(address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"))
2170 .with_to(address!("70997970C51812dc3A010C7d01b50e0d17dc79C8"))
2171 .value(U256::from(100));
2172
2173 let _ = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();
2174
2175 anvil.child_mut().kill().unwrap();
2176
2177 let mut output = String::new();
2178 anvil.child_mut().stdout.take().unwrap().read_to_string(&mut output).unwrap();
2179
2180 assert_eq!(anvil.chain_id(), 31337);
2181 assert_eq!(anvil.addresses().len(), 10);
2182 assert_eq!(anvil.keys().len(), 10);
2183
2184 assert!(output.contains("eth_sendTransaction"));
2185 assert!(output.contains("Block Number: 1"))
2186 }
2187
2188 #[tokio::test]
2189 async fn custom_estimator() {
2190 let provider = ProviderBuilder::new()
2191 .disable_recommended_fillers()
2192 .with_cached_nonce_management()
2193 .connect_anvil();
2194
2195 let _ = provider
2196 .estimate_eip1559_fees_with(Eip1559Estimator::new(|_fee, _rewards| Eip1559Estimation {
2197 max_fee_per_gas: 0,
2198 max_priority_fee_per_gas: 0,
2199 }))
2200 .await;
2201 }
2202
2203 #[tokio::test]
2204 #[cfg(not(windows))]
2205 async fn eth_sign_transaction() {
2206 async_ci_only(|| async {
2207 run_with_tempdir("reth-sign-tx", |dir| async {
2208 let reth = Reth::new().dev().disable_discovery().data_dir(dir).spawn();
2209 let provider = ProviderBuilder::new().connect_http(reth.endpoint_url());
2210
2211 let accounts = provider.get_accounts().await.unwrap();
2212 let from = accounts[0];
2213
2214 let tx = TransactionRequest::default()
2215 .from(from)
2216 .to(Address::random())
2217 .value(U256::from(100))
2218 .gas_limit(21000);
2219
2220 let signed_tx = provider.sign_transaction(tx).await.unwrap().to_vec();
2221
2222 let tx = TxEnvelope::decode(&mut signed_tx.as_slice()).unwrap();
2223
2224 let signer = tx.recover_signer().unwrap();
2225
2226 assert_eq!(signer, from);
2227 })
2228 .await
2229 })
2230 .await;
2231 }
2232
2233 #[cfg(feature = "throttle")]
2234 use alloy_transport::layers::ThrottleLayer;
2235
2236 #[cfg(feature = "throttle")]
2237 #[tokio::test]
2238 async fn test_throttled_provider() {
2239 let request_per_second = 10;
2240 let throttle_layer = ThrottleLayer::new(request_per_second);
2241
2242 let anvil = Anvil::new().spawn();
2243 let client = RpcClient::builder().layer(throttle_layer).http(anvil.endpoint_url());
2244 let provider = RootProvider::<Ethereum>::new(client);
2245
2246 let num_requests = 10;
2247 let start = std::time::Instant::now();
2248 for _ in 0..num_requests {
2249 provider.get_block_number().await.unwrap();
2250 }
2251
2252 let elapsed = start.elapsed();
2253 assert_eq!(elapsed.as_secs_f64().round() as u32, 1);
2254 }
2255
2256 #[tokio::test]
2257 #[cfg(feature = "hyper")]
2258 async fn test_connect_hyper_tls() {
2259 let p =
2260 ProviderBuilder::new().connect("https://reth-ethereum.ithaca.xyz/rpc").await.unwrap();
2261
2262 let _num = p.get_block_number().await.unwrap();
2263
2264 let anvil = Anvil::new().spawn();
2265 let p = ProviderBuilder::new().connect(&anvil.endpoint()).await.unwrap();
2266
2267 let _num = p.get_block_number().await.unwrap();
2268 }
2269}