1#![allow(unknown_lints, elided_named_lifetimes)]
4
5use super::{DynProvider, Empty, EthCallMany, MulticallBuilder};
6use crate::{
7 heart::PendingTransactionError,
8 utils::{self, Eip1559Estimation, Eip1559Estimator},
9 EthCall, EthGetBlock, Identity, PendingTransaction, PendingTransactionBuilder,
10 PendingTransactionConfig, ProviderBuilder, ProviderCall, RootProvider, RpcWithBlock,
11 SendableTx,
12};
13use alloy_consensus::BlockHeader;
14use alloy_eips::eip2718::Encodable2718;
15use alloy_json_rpc::{RpcError, RpcRecv, RpcSend};
16use alloy_network::{Ethereum, Network};
17use alloy_network_primitives::{BlockResponse, ReceiptResponse};
18use alloy_primitives::{
19 hex, Address, BlockHash, BlockNumber, Bytes, StorageKey, StorageValue, TxHash, B256, U128,
20 U256, U64,
21};
22use alloy_rpc_client::{ClientRef, NoParams, PollerBuilder, WeakClient};
23use alloy_rpc_types_eth::{
24 erc4337::TransactionConditional,
25 simulate::{SimulatePayload, SimulatedBlock},
26 AccessListResult, BlockId, BlockNumberOrTag, Bundle, EIP1186AccountProofResponse,
27 EthCallResponse, FeeHistory, Filter, FilterChanges, Index, Log, SyncStatus,
28};
29use alloy_transport::TransportResult;
30use serde_json::value::RawValue;
31use std::borrow::Cow;
32
33pub type FilterPollerBuilder<R> = PollerBuilder<(U256,), Vec<R>>;
37
38#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
65#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
66#[auto_impl::auto_impl(&, &mut, Rc, Arc, Box)]
67pub trait Provider<N: Network = Ethereum>: Send + Sync {
68 fn root(&self) -> &RootProvider<N>;
70
71 fn builder() -> ProviderBuilder<Identity, Identity, N>
73 where
74 Self: Sized,
75 {
76 ProviderBuilder::default()
77 }
78
79 #[inline]
83 fn client(&self) -> ClientRef<'_> {
84 self.root().client()
85 }
86
87 #[inline]
91 fn weak_client(&self) -> WeakClient {
92 self.root().weak_client()
93 }
94
95 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
108 #[doc(alias = "boxed")]
109 fn erased(self) -> DynProvider<N>
110 where
111 Self: Sized + 'static,
112 {
113 DynProvider::new(self)
114 }
115
116 fn get_accounts(&self) -> ProviderCall<NoParams, Vec<Address>> {
119 self.client().request_noparams("eth_accounts").into()
120 }
121
122 fn get_blob_base_fee(&self) -> ProviderCall<NoParams, U128, u128> {
124 self.client()
125 .request_noparams("eth_blobBaseFee")
126 .map_resp(utils::convert_u128 as fn(U128) -> u128)
127 .into()
128 }
129
130 fn get_block_number(&self) -> ProviderCall<NoParams, U64, BlockNumber> {
132 self.client()
133 .request_noparams("eth_blockNumber")
134 .map_resp(utils::convert_u64 as fn(U64) -> u64)
135 .into()
136 }
137
138 #[doc(alias = "eth_call")]
166 #[doc(alias = "call_with_overrides")]
167 fn call(&self, tx: N::TransactionRequest) -> EthCall<N, Bytes> {
168 EthCall::call(self.weak_client(), tx).block(BlockNumberOrTag::Pending.into())
169 }
170
171 #[doc(alias = "eth_callMany")]
180 fn call_many<'req>(
181 &self,
182 bundles: &'req Vec<Bundle>,
183 ) -> EthCallMany<'req, N, Vec<Vec<EthCallResponse>>> {
184 EthCallMany::new(self.weak_client(), bundles)
185 }
186
187 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
225 fn multicall(&self) -> MulticallBuilder<Empty, &Self, N>
226 where
227 Self: Sized,
228 {
229 MulticallBuilder::new(self)
230 }
231
232 #[doc(alias = "eth_simulateV1")]
236 fn simulate<'req>(
237 &self,
238 payload: &'req SimulatePayload,
239 ) -> RpcWithBlock<&'req SimulatePayload, Vec<SimulatedBlock<N::BlockResponse>>> {
240 self.client().request("eth_simulateV1", payload).into()
241 }
242
243 fn get_chain_id(&self) -> ProviderCall<NoParams, U64, u64> {
245 self.client()
246 .request_noparams("eth_chainId")
247 .map_resp(utils::convert_u64 as fn(U64) -> u64)
248 .into()
249 }
250
251 fn create_access_list<'a>(
255 &self,
256 request: &'a N::TransactionRequest,
257 ) -> RpcWithBlock<&'a N::TransactionRequest, AccessListResult> {
258 self.client().request("eth_createAccessList", request).into()
259 }
260
261 fn estimate_gas(&self, tx: N::TransactionRequest) -> EthCall<N, U64, u64> {
275 EthCall::gas_estimate(self.weak_client(), tx)
276 .block(BlockNumberOrTag::Pending.into())
277 .map_resp(utils::convert_u64)
278 }
279
280 async fn estimate_eip1559_fees_with(
285 &self,
286 estimator: Eip1559Estimator,
287 ) -> TransportResult<Eip1559Estimation> {
288 let fee_history = self
289 .get_fee_history(
290 utils::EIP1559_FEE_ESTIMATION_PAST_BLOCKS,
291 BlockNumberOrTag::Latest,
292 &[utils::EIP1559_FEE_ESTIMATION_REWARD_PERCENTILE],
293 )
294 .await?;
295
296 let base_fee_per_gas = match fee_history.latest_block_base_fee() {
299 Some(base_fee) if base_fee != 0 => base_fee,
300 _ => {
301 self.get_block_by_number(BlockNumberOrTag::Latest)
303 .await?
304 .ok_or(RpcError::NullResp)?
305 .header()
306 .as_ref()
307 .base_fee_per_gas()
308 .ok_or(RpcError::UnsupportedFeature("eip1559"))?
309 .into()
310 }
311 };
312
313 Ok(estimator.estimate(base_fee_per_gas, &fee_history.reward.unwrap_or_default()))
314 }
315
316 async fn estimate_eip1559_fees(&self) -> TransportResult<Eip1559Estimation> {
320 self.estimate_eip1559_fees_with(Eip1559Estimator::default()).await
321 }
322
323 async fn get_fee_history(
327 &self,
328 block_count: u64,
329 last_block: BlockNumberOrTag,
330 reward_percentiles: &[f64],
331 ) -> TransportResult<FeeHistory> {
332 self.client()
333 .request("eth_feeHistory", (U64::from(block_count), last_block, reward_percentiles))
334 .await
335 }
336
337 fn get_gas_price(&self) -> ProviderCall<NoParams, U128, u128> {
339 self.client()
340 .request_noparams("eth_gasPrice")
341 .map_resp(utils::convert_u128 as fn(U128) -> u128)
342 .into()
343 }
344
345 fn get_account(&self, address: Address) -> RpcWithBlock<Address, alloy_consensus::Account> {
348 self.client().request("eth_getAccount", address).into()
349 }
350
351 fn get_balance(&self, address: Address) -> RpcWithBlock<Address, U256, U256> {
355 self.client().request("eth_getBalance", address).into()
356 }
357
358 fn get_block(&self, block: BlockId) -> EthGetBlock<N::BlockResponse> {
369 match block {
370 BlockId::Hash(hash) => EthGetBlock::by_hash(hash.block_hash, self.client()),
371 BlockId::Number(number) => EthGetBlock::by_number(number, self.client()),
372 }
373 }
374
375 fn get_block_by_hash(&self, hash: BlockHash) -> EthGetBlock<N::BlockResponse> {
401 EthGetBlock::by_hash(hash, self.client())
402 }
403
404 fn get_block_by_number(&self, number: BlockNumberOrTag) -> EthGetBlock<N::BlockResponse> {
428 EthGetBlock::by_number(number, self.client())
429 }
430
431 async fn get_block_transaction_count_by_hash(
433 &self,
434 hash: BlockHash,
435 ) -> TransportResult<Option<u64>> {
436 self.client()
437 .request("eth_getBlockTransactionCountByHash", (hash,))
438 .await
439 .map(|opt_count: Option<U64>| opt_count.map(|count| count.to::<u64>()))
440 }
441
442 async fn get_block_transaction_count_by_number(
444 &self,
445 block_number: BlockNumberOrTag,
446 ) -> TransportResult<Option<u64>> {
447 self.client()
448 .request("eth_getBlockTransactionCountByNumber", (block_number,))
449 .await
450 .map(|opt_count: Option<U64>| opt_count.map(|count| count.to::<u64>()))
451 }
452
453 fn get_block_receipts(
455 &self,
456 block: BlockId,
457 ) -> ProviderCall<(BlockId,), Option<Vec<N::ReceiptResponse>>> {
458 self.client().request("eth_getBlockReceipts", (block,)).into()
459 }
460
461 fn get_code_at(&self, address: Address) -> RpcWithBlock<Address, Bytes> {
463 self.client().request("eth_getCode", address).into()
464 }
465
466 async fn watch_blocks(&self) -> TransportResult<FilterPollerBuilder<B256>> {
489 let id = self.new_block_filter().await?;
490 Ok(PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,)))
491 }
492
493 async fn watch_pending_transactions(&self) -> TransportResult<FilterPollerBuilder<B256>> {
516 let id = self.new_pending_transactions_filter(false).await?;
517 Ok(PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,)))
518 }
519
520 async fn watch_logs(&self, filter: &Filter) -> TransportResult<FilterPollerBuilder<Log>> {
549 let id = self.new_filter(filter).await?;
550 Ok(PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,)))
551 }
552
553 async fn watch_full_pending_transactions(
580 &self,
581 ) -> TransportResult<FilterPollerBuilder<N::TransactionResponse>> {
582 let id = self.new_pending_transactions_filter(true).await?;
583 Ok(PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,)))
584 }
585
586 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
591 async fn get_filter_changes<R: RpcRecv>(&self, id: U256) -> TransportResult<Vec<R>>
592 where
593 Self: Sized,
594 {
595 self.client().request("eth_getFilterChanges", (id,)).await
596 }
597
598 async fn get_filter_changes_dyn(&self, id: U256) -> TransportResult<FilterChanges> {
603 self.client().request("eth_getFilterChanges", (id,)).await
604 }
605
606 async fn get_filter_logs(&self, id: U256) -> TransportResult<Vec<Log>> {
608 self.client().request("eth_getFilterLogs", (id,)).await
609 }
610
611 async fn uninstall_filter(&self, id: U256) -> TransportResult<bool> {
613 self.client().request("eth_uninstallFilter", (id,)).await
614 }
615
616 #[inline]
621 async fn watch_pending_transaction(
622 &self,
623 config: PendingTransactionConfig,
624 ) -> Result<PendingTransaction, PendingTransactionError> {
625 self.root().watch_pending_transaction(config).await
626 }
627
628 async fn get_logs(&self, filter: &Filter) -> TransportResult<Vec<Log>> {
630 self.client().request("eth_getLogs", (filter,)).await
631 }
632
633 fn get_proof(
637 &self,
638 address: Address,
639 keys: Vec<StorageKey>,
640 ) -> RpcWithBlock<(Address, Vec<StorageKey>), EIP1186AccountProofResponse> {
641 self.client().request("eth_getProof", (address, keys)).into()
642 }
643
644 fn get_storage_at(
646 &self,
647 address: Address,
648 key: U256,
649 ) -> RpcWithBlock<(Address, U256), StorageValue> {
650 self.client().request("eth_getStorageAt", (address, key)).into()
651 }
652
653 fn get_transaction_by_hash(
655 &self,
656 hash: TxHash,
657 ) -> ProviderCall<(TxHash,), Option<N::TransactionResponse>> {
658 self.client().request("eth_getTransactionByHash", (hash,)).into()
659 }
660
661 fn get_transaction_by_block_hash_and_index(
663 &self,
664 block_hash: B256,
665 index: usize,
666 ) -> ProviderCall<(B256, Index), Option<N::TransactionResponse>> {
667 self.client()
668 .request("eth_getTransactionByBlockHashAndIndex", (block_hash, Index(index)))
669 .into()
670 }
671
672 fn get_raw_transaction_by_block_hash_and_index(
674 &self,
675 block_hash: B256,
676 index: usize,
677 ) -> ProviderCall<(B256, Index), Option<Bytes>> {
678 self.client()
679 .request("eth_getRawTransactionByBlockHashAndIndex", (block_hash, Index(index)))
680 .into()
681 }
682
683 fn get_transaction_by_block_number_and_index(
685 &self,
686 block_number: BlockNumberOrTag,
687 index: usize,
688 ) -> ProviderCall<(BlockNumberOrTag, Index), Option<N::TransactionResponse>> {
689 self.client()
690 .request("eth_getTransactionByBlockNumberAndIndex", (block_number, Index(index)))
691 .into()
692 }
693
694 fn get_raw_transaction_by_block_number_and_index(
696 &self,
697 block_number: BlockNumberOrTag,
698 index: usize,
699 ) -> ProviderCall<(BlockNumberOrTag, Index), Option<Bytes>> {
700 self.client()
701 .request("eth_getRawTransactionByBlockNumberAndIndex", (block_number, Index(index)))
702 .into()
703 }
704
705 fn get_raw_transaction_by_hash(&self, hash: TxHash) -> ProviderCall<(TxHash,), Option<Bytes>> {
714 self.client().request("eth_getRawTransactionByHash", (hash,)).into()
715 }
716
717 #[doc(alias = "get_nonce")]
719 #[doc(alias = "get_account_nonce")]
720 fn get_transaction_count(
721 &self,
722 address: Address,
723 ) -> RpcWithBlock<Address, U64, u64, fn(U64) -> u64> {
724 self.client()
725 .request("eth_getTransactionCount", address)
726 .map_resp(utils::convert_u64 as fn(U64) -> u64)
727 .into()
728 }
729
730 fn get_transaction_receipt(
732 &self,
733 hash: TxHash,
734 ) -> ProviderCall<(TxHash,), Option<N::ReceiptResponse>> {
735 self.client().request("eth_getTransactionReceipt", (hash,)).into()
736 }
737
738 async fn get_uncle(&self, tag: BlockId, idx: u64) -> TransportResult<Option<N::BlockResponse>> {
740 let idx = U64::from(idx);
741 match tag {
742 BlockId::Hash(hash) => {
743 self.client()
744 .request("eth_getUncleByBlockHashAndIndex", (hash.block_hash, idx))
745 .await
746 }
747 BlockId::Number(number) => {
748 self.client().request("eth_getUncleByBlockNumberAndIndex", (number, idx)).await
749 }
750 }
751 }
752
753 async fn get_uncle_count(&self, tag: BlockId) -> TransportResult<u64> {
755 match tag {
756 BlockId::Hash(hash) => self
757 .client()
758 .request("eth_getUncleCountByBlockHash", (hash.block_hash,))
759 .await
760 .map(|count: U64| count.to::<u64>()),
761 BlockId::Number(number) => self
762 .client()
763 .request("eth_getUncleCountByBlockNumber", (number,))
764 .await
765 .map(|count: U64| count.to::<u64>()),
766 }
767 }
768
769 fn get_max_priority_fee_per_gas(&self) -> ProviderCall<NoParams, U128, u128> {
771 self.client()
772 .request_noparams("eth_maxPriorityFeePerGas")
773 .map_resp(utils::convert_u128 as fn(U128) -> u128)
774 .into()
775 }
776
777 async fn new_block_filter(&self) -> TransportResult<U256> {
783 self.client().request_noparams("eth_newBlockFilter").await
784 }
785
786 async fn new_filter(&self, filter: &Filter) -> TransportResult<U256> {
792 self.client().request("eth_newFilter", (filter,)).await
793 }
794
795 async fn new_pending_transactions_filter(&self, full: bool) -> TransportResult<U256> {
805 let param = if full { &[true][..] } else { &[] };
807 self.client().request("eth_newPendingTransactionFilter", param).await
808 }
809
810 async fn send_raw_transaction(
814 &self,
815 encoded_tx: &[u8],
816 ) -> TransportResult<PendingTransactionBuilder<N>> {
817 let rlp_hex = hex::encode_prefixed(encoded_tx);
818 let tx_hash = self.client().request("eth_sendRawTransaction", (rlp_hex,)).await?;
819 Ok(PendingTransactionBuilder::new(self.root().clone(), tx_hash))
820 }
821
822 async fn send_raw_transaction_conditional(
833 &self,
834 encoded_tx: &[u8],
835 conditional: TransactionConditional,
836 ) -> TransportResult<PendingTransactionBuilder<N>> {
837 let rlp_hex = hex::encode_prefixed(encoded_tx);
838 let tx_hash = self
839 .client()
840 .request("eth_sendRawTransactionConditional", (rlp_hex, conditional))
841 .await?;
842 Ok(PendingTransactionBuilder::new(self.root().clone(), tx_hash))
843 }
844
845 async fn send_transaction(
866 &self,
867 tx: N::TransactionRequest,
868 ) -> TransportResult<PendingTransactionBuilder<N>> {
869 self.send_transaction_internal(SendableTx::Builder(tx)).await
870 }
871
872 async fn send_tx_envelope(
877 &self,
878 tx: N::TxEnvelope,
879 ) -> TransportResult<PendingTransactionBuilder<N>> {
880 self.send_transaction_internal(SendableTx::Envelope(tx)).await
881 }
882
883 #[doc(hidden)]
891 async fn send_transaction_internal(
892 &self,
893 tx: SendableTx<N>,
894 ) -> TransportResult<PendingTransactionBuilder<N>> {
895 let _handle = self.root().get_heart();
898
899 match tx {
900 SendableTx::Builder(mut tx) => {
901 alloy_network::TransactionBuilder::prep_for_submission(&mut tx);
902 let tx_hash = self.client().request("eth_sendTransaction", (tx,)).await?;
903 Ok(PendingTransactionBuilder::new(self.root().clone(), tx_hash))
904 }
905 SendableTx::Envelope(tx) => {
906 let encoded_tx = tx.encoded_2718();
907 self.send_raw_transaction(&encoded_tx).await
908 }
909 }
910 }
911
912 #[cfg(feature = "pubsub")]
938 async fn subscribe_blocks(
939 &self,
940 ) -> TransportResult<alloy_pubsub::Subscription<N::HeaderResponse>> {
941 self.root().pubsub_frontend()?;
942 let id = self.client().request("eth_subscribe", ("newHeads",)).await?;
943 self.root().get_subscription(id).await
944 }
945
946 #[cfg(feature = "pubsub")]
972 async fn subscribe_pending_transactions(
973 &self,
974 ) -> TransportResult<alloy_pubsub::Subscription<B256>> {
975 self.root().pubsub_frontend()?;
976 let id = self.client().request("eth_subscribe", ("newPendingTransactions",)).await?;
977 self.root().get_subscription(id).await
978 }
979
980 #[cfg(feature = "pubsub")]
1011 async fn subscribe_full_pending_transactions(
1012 &self,
1013 ) -> TransportResult<alloy_pubsub::Subscription<N::TransactionResponse>> {
1014 self.root().pubsub_frontend()?;
1015 let id = self.client().request("eth_subscribe", ("newPendingTransactions", true)).await?;
1016 self.root().get_subscription(id).await
1017 }
1018
1019 #[cfg(feature = "pubsub")]
1050 async fn subscribe_logs(
1051 &self,
1052 filter: &Filter,
1053 ) -> TransportResult<alloy_pubsub::Subscription<Log>> {
1054 self.root().pubsub_frontend()?;
1055 let id = self.client().request("eth_subscribe", ("logs", filter)).await?;
1056 self.root().get_subscription(id).await
1057 }
1058
1059 #[cfg(feature = "pubsub")]
1061 #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
1062 async fn subscribe<P, R>(&self, params: P) -> TransportResult<alloy_pubsub::Subscription<R>>
1063 where
1064 P: RpcSend,
1065 R: RpcRecv,
1066 Self: Sized,
1067 {
1068 self.root().pubsub_frontend()?;
1069 let id = self.client().request("eth_subscribe", params).await?;
1070 self.root().get_subscription(id).await
1071 }
1072
1073 #[cfg(feature = "pubsub")]
1075 async fn unsubscribe(&self, id: B256) -> TransportResult<()> {
1076 self.root().unsubscribe(id)
1077 }
1078
1079 fn syncing(&self) -> ProviderCall<NoParams, SyncStatus> {
1081 self.client().request_noparams("eth_syncing").into()
1082 }
1083
1084 #[doc(alias = "web3_client_version")]
1086 fn get_client_version(&self) -> ProviderCall<NoParams, String> {
1087 self.client().request_noparams("web3_clientVersion").into()
1088 }
1089
1090 #[doc(alias = "web3_sha3")]
1092 fn get_sha3(&self, data: &[u8]) -> ProviderCall<(String,), B256> {
1093 self.client().request("web3_sha3", (hex::encode_prefixed(data),)).into()
1094 }
1095
1096 fn get_net_version(&self) -> ProviderCall<NoParams, U64, u64> {
1098 self.client()
1099 .request_noparams("net_version")
1100 .map_resp(utils::convert_u64 as fn(U64) -> u64)
1101 .into()
1102 }
1103
1104 async fn raw_request<P, R>(&self, method: Cow<'static, str>, params: P) -> TransportResult<R>
1129 where
1130 P: RpcSend,
1131 R: RpcRecv,
1132 Self: Sized,
1133 {
1134 self.client().request(method, ¶ms).await
1135 }
1136
1137 async fn raw_request_dyn(
1160 &self,
1161 method: Cow<'static, str>,
1162 params: &RawValue,
1163 ) -> TransportResult<Box<RawValue>> {
1164 self.client().request(method, params).await
1165 }
1166
1167 #[inline]
1169 fn transaction_request(&self) -> N::TransactionRequest {
1170 Default::default()
1171 }
1172}
1173
1174#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
1175#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
1176impl<N: Network> Provider<N> for RootProvider<N> {
1177 #[inline]
1178 fn root(&self) -> &Self {
1179 self
1180 }
1181
1182 #[inline]
1183 fn client(&self) -> ClientRef<'_> {
1184 self.inner.client_ref()
1185 }
1186
1187 #[inline]
1188 fn weak_client(&self) -> WeakClient {
1189 self.inner.weak_client()
1190 }
1191
1192 #[inline]
1193 async fn watch_pending_transaction(
1194 &self,
1195 config: PendingTransactionConfig,
1196 ) -> Result<PendingTransaction, PendingTransactionError> {
1197 let block_number =
1198 if let Some(receipt) = self.get_transaction_receipt(*config.tx_hash()).await? {
1199 if config.required_confirmations() <= 1 {
1201 return Ok(PendingTransaction::ready(*config.tx_hash()));
1202 }
1203 receipt.block_number()
1206 } else {
1207 None
1208 };
1209
1210 self.get_heart()
1211 .watch_tx(config, block_number)
1212 .await
1213 .map_err(|_| PendingTransactionError::FailedToRegister)
1214 }
1215}
1216
1217#[cfg(test)]
1218mod tests {
1219 use super::*;
1220 use crate::{builder, ProviderBuilder, WalletProvider};
1221 use alloy_consensus::Transaction;
1222 use alloy_network::{AnyNetwork, EthereumWallet, TransactionBuilder};
1223 use alloy_node_bindings::Anvil;
1224 use alloy_primitives::{address, b256, bytes, keccak256};
1225 use alloy_rpc_client::{BuiltInConnectionString, RpcClient};
1226 use alloy_rpc_types_eth::{request::TransactionRequest, Block};
1227 use alloy_signer_local::PrivateKeySigner;
1228 use alloy_transport::layers::{RetryBackoffLayer, RetryPolicy};
1229 use std::{io::Read, str::FromStr, time::Duration};
1230
1231 #[cfg(feature = "hyper")]
1233 use alloy_transport_http::{
1234 hyper,
1235 hyper::body::Bytes as HyperBytes,
1236 hyper_util::{
1237 client::legacy::{Client, Error},
1238 rt::TokioExecutor,
1239 },
1240 HyperResponse, HyperResponseFut,
1241 };
1242 #[cfg(feature = "hyper")]
1243 use http_body_util::Full;
1244 #[cfg(feature = "hyper")]
1245 use tower::{Layer, Service};
1246
1247 #[tokio::test]
1248 async fn test_provider_builder() {
1249 let provider = RootProvider::builder().with_recommended_fillers().on_anvil();
1250 let num = provider.get_block_number().await.unwrap();
1251 assert_eq!(0, num);
1252 }
1253
1254 #[tokio::test]
1255 async fn test_builder_helper_fn() {
1256 let provider = builder().with_recommended_fillers().on_anvil();
1257 let num = provider.get_block_number().await.unwrap();
1258 assert_eq!(0, num);
1259 }
1260
1261 #[cfg(feature = "hyper")]
1262 #[tokio::test]
1263 async fn test_default_hyper_transport() {
1264 let anvil = Anvil::new().spawn();
1265 let hyper_t = alloy_transport_http::HyperTransport::new_hyper(anvil.endpoint_url());
1266
1267 let rpc_client = alloy_rpc_client::RpcClient::new(hyper_t, true);
1268
1269 let provider = RootProvider::<Ethereum>::new(rpc_client);
1270 let num = provider.get_block_number().await.unwrap();
1271 assert_eq!(0, num);
1272 }
1273
1274 #[cfg(feature = "hyper")]
1275 #[tokio::test]
1276 async fn test_hyper_layer_transport() {
1277 struct LoggingLayer;
1278
1279 impl<S> Layer<S> for LoggingLayer {
1280 type Service = LoggingService<S>;
1281
1282 fn layer(&self, inner: S) -> Self::Service {
1283 LoggingService { inner }
1284 }
1285 }
1286
1287 #[derive(Clone)] struct LoggingService<S> {
1289 inner: S,
1290 }
1291
1292 impl<S, B> Service<hyper::Request<B>> for LoggingService<S>
1293 where
1294 S: Service<hyper::Request<B>, Response = HyperResponse, Error = Error>
1295 + Clone
1296 + Send
1297 + Sync
1298 + 'static,
1299 S::Future: Send,
1300 S::Error: std::error::Error + Send + Sync + 'static,
1301 B: From<Vec<u8>> + Send + 'static + Clone + Sync + std::fmt::Debug,
1302 {
1303 type Response = HyperResponse;
1304 type Error = Error;
1305 type Future = HyperResponseFut;
1306
1307 fn poll_ready(
1308 &mut self,
1309 cx: &mut std::task::Context<'_>,
1310 ) -> std::task::Poll<Result<(), Self::Error>> {
1311 self.inner.poll_ready(cx)
1312 }
1313
1314 fn call(&mut self, req: hyper::Request<B>) -> Self::Future {
1315 println!("Logging Layer - HyperRequest {req:?}");
1316
1317 let fut = self.inner.call(req);
1318
1319 Box::pin(fut)
1320 }
1321 }
1322 use http::header::{self, HeaderValue};
1323 use tower_http::{
1324 sensitive_headers::SetSensitiveRequestHeadersLayer, set_header::SetRequestHeaderLayer,
1325 };
1326 let anvil = Anvil::new().spawn();
1327 let hyper_client = Client::builder(TokioExecutor::new()).build_http::<Full<HyperBytes>>();
1328
1329 let service = tower::ServiceBuilder::new()
1331 .layer(SetRequestHeaderLayer::if_not_present(
1332 header::USER_AGENT,
1333 HeaderValue::from_static("alloy app"),
1334 ))
1335 .layer(SetRequestHeaderLayer::overriding(
1336 header::AUTHORIZATION,
1337 HeaderValue::from_static("some-jwt-token"),
1338 ))
1339 .layer(SetRequestHeaderLayer::appending(
1340 header::SET_COOKIE,
1341 HeaderValue::from_static("cookie-value"),
1342 ))
1343 .layer(SetSensitiveRequestHeadersLayer::new([header::AUTHORIZATION])) .layer(LoggingLayer)
1345 .service(hyper_client);
1346
1347 let layer_transport = alloy_transport_http::HyperClient::with_service(service);
1348
1349 let http_hyper =
1350 alloy_transport_http::Http::with_client(layer_transport, anvil.endpoint_url());
1351
1352 let rpc_client = alloy_rpc_client::RpcClient::new(http_hyper, true);
1353
1354 let provider = RootProvider::<Ethereum>::new(rpc_client);
1355 let num = provider.get_block_number().await.unwrap();
1356 assert_eq!(0, num);
1357
1358 let cloned_t = provider.client().transport().clone();
1360
1361 let rpc_client = alloy_rpc_client::RpcClient::new(cloned_t, true);
1362
1363 let provider = RootProvider::<Ethereum>::new(rpc_client);
1364 let num = provider.get_block_number().await.unwrap();
1365 assert_eq!(0, num);
1366 }
1367
1368 #[cfg(feature = "hyper")]
1369 #[tokio::test]
1370 #[cfg_attr(windows, ignore = "no reth on windows")]
1371 async fn test_auth_layer_transport() {
1372 crate::ext::test::async_ci_only(|| async move {
1373 use alloy_node_bindings::Reth;
1374 use alloy_rpc_types_engine::JwtSecret;
1375 use alloy_transport_http::{AuthLayer, AuthService, Http, HyperClient};
1376
1377 let secret = JwtSecret::random();
1378
1379 let reth =
1380 Reth::new().arg("--rpc.jwtsecret").arg(hex::encode(secret.as_bytes())).spawn();
1381
1382 let hyper_client =
1383 Client::builder(TokioExecutor::new()).build_http::<Full<HyperBytes>>();
1384
1385 let service =
1386 tower::ServiceBuilder::new().layer(AuthLayer::new(secret)).service(hyper_client);
1387
1388 let layer_transport: HyperClient<
1389 Full<HyperBytes>,
1390 AuthService<
1391 Client<
1392 alloy_transport_http::hyper_util::client::legacy::connect::HttpConnector,
1393 Full<HyperBytes>,
1394 >,
1395 >,
1396 > = HyperClient::with_service(service);
1397
1398 let http_hyper = Http::with_client(layer_transport, reth.endpoint_url());
1399
1400 let rpc_client = alloy_rpc_client::RpcClient::new(http_hyper, true);
1401
1402 let provider = RootProvider::<Ethereum>::new(rpc_client);
1403
1404 let num = provider.get_block_number().await.unwrap();
1405 assert_eq!(0, num);
1406 })
1407 .await;
1408 }
1409
1410 #[tokio::test]
1411 async fn test_builder_helper_fn_any_network() {
1412 let anvil = Anvil::new().spawn();
1413 let provider =
1414 builder::<AnyNetwork>().with_recommended_fillers().on_http(anvil.endpoint_url());
1415 let num = provider.get_block_number().await.unwrap();
1416 assert_eq!(0, num);
1417 }
1418
1419 #[cfg(feature = "reqwest")]
1420 #[tokio::test]
1421 async fn object_safety() {
1422 let provider = ProviderBuilder::new().on_anvil();
1423
1424 let refdyn = &provider as &dyn Provider<_>;
1425 let num = refdyn.get_block_number().await.unwrap();
1426 assert_eq!(0, num);
1427 }
1428
1429 #[cfg(feature = "ws")]
1430 #[tokio::test]
1431 async fn subscribe_blocks_http() {
1432 let provider = ProviderBuilder::new().on_anvil_with_config(|a| a.block_time(1));
1433
1434 let err = provider.subscribe_blocks().await.unwrap_err();
1435 let alloy_json_rpc::RpcError::Transport(
1436 alloy_transport::TransportErrorKind::PubsubUnavailable,
1437 ) = err
1438 else {
1439 panic!("{err:?}");
1440 };
1441 }
1442
1443 #[cfg(feature = "ws")]
1445 #[tokio::test]
1446 async fn websocket_tls_setup() {
1447 for url in ["wss://mainnet.infura.io/ws/v3/b0f825787ba840af81e46c6a64d20754"] {
1448 let _ = ProviderBuilder::<_, _, Ethereum>::default().connect(url).await.unwrap();
1449 }
1450 }
1451
1452 #[cfg(feature = "ws")]
1453 #[tokio::test]
1454 async fn subscribe_blocks_ws() {
1455 use futures::stream::StreamExt;
1456
1457 let anvil = Anvil::new().block_time_f64(0.2).spawn();
1458 let ws = alloy_rpc_client::WsConnect::new(anvil.ws_endpoint());
1459 let client = alloy_rpc_client::RpcClient::connect_pubsub(ws).await.unwrap();
1460 let provider = RootProvider::<Ethereum>::new(client);
1461
1462 let sub = provider.subscribe_blocks().await.unwrap();
1463 let mut stream = sub.into_stream().take(5);
1464 let mut next = None;
1465 while let Some(header) = stream.next().await {
1466 if let Some(next) = &mut next {
1467 assert_eq!(header.number, *next);
1468 *next += 1;
1469 } else {
1470 next = Some(header.number + 1);
1471 }
1472 }
1473 }
1474
1475 #[tokio::test]
1476 #[cfg(feature = "ws")]
1477 async fn subscribe_blocks_ws_remote() {
1478 use futures::stream::StreamExt;
1479
1480 let url = "wss://eth-mainnet.g.alchemy.com/v2/viFmeVzhg6bWKVMIWWS8MhmzREB-D4f7";
1481 let ws = alloy_rpc_client::WsConnect::new(url);
1482 let Ok(client) = alloy_rpc_client::RpcClient::connect_pubsub(ws).await else { return };
1483 let provider = RootProvider::<Ethereum>::new(client);
1484 let sub = provider.subscribe_blocks().await.unwrap();
1485 let mut stream = sub.into_stream().take(1);
1486 while let Some(header) = stream.next().await {
1487 println!("New block {:?}", header);
1488 assert!(header.number > 0);
1489 }
1490 }
1491
1492 #[tokio::test]
1493 async fn test_custom_retry_policy() {
1494 #[derive(Debug, Clone)]
1495 struct CustomPolicy;
1496 impl RetryPolicy for CustomPolicy {
1497 fn should_retry(&self, _err: &alloy_transport::TransportError) -> bool {
1498 true
1499 }
1500
1501 fn backoff_hint(
1502 &self,
1503 _error: &alloy_transport::TransportError,
1504 ) -> Option<std::time::Duration> {
1505 None
1506 }
1507 }
1508
1509 let retry_layer = RetryBackoffLayer::new_with_policy(10, 100, 10000, CustomPolicy);
1510 let anvil = Anvil::new().spawn();
1511 let client = RpcClient::builder().layer(retry_layer).http(anvil.endpoint_url());
1512
1513 let provider = RootProvider::<Ethereum>::new(client);
1514 let num = provider.get_block_number().await.unwrap();
1515 assert_eq!(0, num);
1516 }
1517
1518 #[tokio::test]
1519 async fn test_send_tx() {
1520 let provider = ProviderBuilder::new().on_anvil_with_wallet();
1521 let tx = TransactionRequest {
1522 value: Some(U256::from(100)),
1523 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
1524 gas_price: Some(20e9 as u128),
1525 gas: Some(21000),
1526 ..Default::default()
1527 };
1528
1529 let builder = provider.send_transaction(tx.clone()).await.expect("failed to send tx");
1530 let hash1 = *builder.tx_hash();
1531 let hash2 = builder.watch().await.expect("failed to await pending tx");
1532 assert_eq!(hash1, hash2);
1533
1534 let builder = provider.send_transaction(tx).await.expect("failed to send tx");
1535 let hash1 = *builder.tx_hash();
1536 let hash2 =
1537 builder.get_receipt().await.expect("failed to await pending tx").transaction_hash;
1538 assert_eq!(hash1, hash2);
1539 }
1540
1541 #[tokio::test]
1542 async fn test_watch_confirmed_tx() {
1543 let provider = ProviderBuilder::new().on_anvil_with_wallet();
1544 let tx = TransactionRequest {
1545 value: Some(U256::from(100)),
1546 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
1547 gas_price: Some(20e9 as u128),
1548 gas: Some(21000),
1549 ..Default::default()
1550 };
1551
1552 let builder = provider.send_transaction(tx.clone()).await.expect("failed to send tx");
1553 let hash1 = *builder.tx_hash();
1554
1555 loop {
1557 if provider
1558 .get_transaction_receipt(hash1)
1559 .await
1560 .expect("failed to await pending tx")
1561 .is_some()
1562 {
1563 break;
1564 }
1565 }
1566
1567 let tx2 = TransactionRequest {
1569 value: Some(U256::from(100)),
1570 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
1571 gas_price: Some(20e9 as u128),
1572 gas: Some(21000),
1573 ..Default::default()
1574 };
1575 provider.send_transaction(tx2).await.expect("failed to send tx").watch().await.unwrap();
1576
1577 let watch = builder.watch();
1579 let watch_with_timeout = tokio::time::timeout(Duration::from_secs(1), watch);
1581 let hash2 = watch_with_timeout
1582 .await
1583 .expect("Watching tx timed out")
1584 .expect("failed to await pending tx");
1585 assert_eq!(hash1, hash2);
1586 }
1587
1588 #[tokio::test]
1589 async fn gets_block_number() {
1590 let provider = ProviderBuilder::new().on_anvil();
1591 let num = provider.get_block_number().await.unwrap();
1592 assert_eq!(0, num)
1593 }
1594
1595 #[tokio::test]
1596 async fn gets_block_number_with_raw_req() {
1597 let provider = ProviderBuilder::new().on_anvil();
1598 let num: U64 =
1599 provider.raw_request("eth_blockNumber".into(), NoParams::default()).await.unwrap();
1600 assert_eq!(0, num.to::<u64>())
1601 }
1602
1603 #[cfg(feature = "anvil-api")]
1604 #[tokio::test]
1605 async fn gets_transaction_count() {
1606 let provider = ProviderBuilder::new().on_anvil();
1607 let accounts = provider.get_accounts().await.unwrap();
1608 let sender = accounts[0];
1609
1610 let count = provider.get_transaction_count(sender).await.unwrap();
1612 assert_eq!(count, 0);
1613
1614 let tx = TransactionRequest {
1616 value: Some(U256::from(100)),
1617 from: Some(sender),
1618 to: Some(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()),
1619 gas_price: Some(20e9 as u128),
1620 gas: Some(21000),
1621 ..Default::default()
1622 };
1623 let _ = provider.send_transaction(tx).await.unwrap().get_receipt().await;
1624
1625 let count = provider.get_transaction_count(sender).await.unwrap();
1627 assert_eq!(count, 1);
1628
1629 let count = provider.get_transaction_count(sender).block_id(0.into()).await.unwrap();
1631 assert_eq!(count, 0);
1632 }
1633
1634 #[tokio::test]
1635 async fn gets_block_by_hash() {
1636 let provider = ProviderBuilder::new().on_anvil();
1637 let num = 0;
1638 let tag: BlockNumberOrTag = num.into();
1639 let block = provider.get_block_by_number(tag).full().await.unwrap().unwrap();
1640 let hash = block.header.hash;
1641 let block = provider.get_block_by_hash(hash).full().await.unwrap().unwrap();
1642 assert_eq!(block.header.hash, hash);
1643 }
1644
1645 #[tokio::test]
1646 async fn gets_block_by_hash_with_raw_req() {
1647 let provider = ProviderBuilder::new().on_anvil();
1648 let num = 0;
1649 let tag: BlockNumberOrTag = num.into();
1650 let block = provider.get_block_by_number(tag).full().await.unwrap().unwrap();
1651 let hash = block.header.hash;
1652 let block: Block = provider
1653 .raw_request::<(B256, bool), Block>("eth_getBlockByHash".into(), (hash, true))
1654 .await
1655 .unwrap();
1656 assert_eq!(block.header.hash, hash);
1657 }
1658
1659 #[tokio::test]
1660 async fn gets_block_by_number_full() {
1661 let provider = ProviderBuilder::new().on_anvil();
1662 let num = 0;
1663 let tag: BlockNumberOrTag = num.into();
1664 let block = provider.get_block_by_number(tag).full().await.unwrap().unwrap();
1665 assert_eq!(block.header.number, num);
1666 }
1667
1668 #[tokio::test]
1669 async fn gets_block_by_number() {
1670 let provider = ProviderBuilder::new().on_anvil();
1671 let num = 0;
1672 let tag: BlockNumberOrTag = num.into();
1673 let block = provider.get_block_by_number(tag).full().await.unwrap().unwrap();
1674 assert_eq!(block.header.number, num);
1675 }
1676
1677 #[tokio::test]
1678 async fn gets_client_version() {
1679 let provider = ProviderBuilder::new().on_anvil();
1680 let version = provider.get_client_version().await.unwrap();
1681 assert!(version.contains("anvil"), "{version}");
1682 }
1683
1684 #[tokio::test]
1685 async fn gets_sha3() {
1686 let provider = ProviderBuilder::new().on_anvil();
1687 let data = b"alloy";
1688 let hash = provider.get_sha3(data).await.unwrap();
1689 assert_eq!(hash, keccak256(data));
1690 }
1691
1692 #[tokio::test]
1693 async fn gets_chain_id() {
1694 let dev_chain_id: u64 = 13371337;
1695
1696 let provider = ProviderBuilder::new().on_anvil_with_config(|a| a.chain_id(dev_chain_id));
1697
1698 let chain_id = provider.get_chain_id().await.unwrap();
1699 assert_eq!(chain_id, dev_chain_id);
1700 }
1701
1702 #[tokio::test]
1703 async fn gets_network_id() {
1704 let dev_chain_id: u64 = 13371337;
1705 let provider = ProviderBuilder::new().on_anvil_with_config(|a| a.chain_id(dev_chain_id));
1706
1707 let chain_id = provider.get_net_version().await.unwrap();
1708 assert_eq!(chain_id, dev_chain_id);
1709 }
1710
1711 #[tokio::test]
1712 async fn gets_storage_at() {
1713 let provider = ProviderBuilder::new().on_anvil();
1714 let addr = Address::with_last_byte(16);
1715 let storage = provider.get_storage_at(addr, U256::ZERO).await.unwrap();
1716 assert_eq!(storage, U256::ZERO);
1717 }
1718
1719 #[tokio::test]
1720 async fn gets_transaction_by_hash_not_found() {
1721 let provider = ProviderBuilder::new().on_anvil();
1722 let tx_hash = b256!("5c03fab9114ceb98994b43892ade87ddfd9ae7e8f293935c3bd29d435dc9fd95");
1723 let tx = provider.get_transaction_by_hash(tx_hash).await.expect("failed to fetch tx");
1724
1725 assert!(tx.is_none());
1726 }
1727
1728 #[tokio::test]
1729 async fn gets_transaction_by_hash() {
1730 let provider = ProviderBuilder::new().on_anvil_with_wallet();
1731
1732 let req = TransactionRequest::default()
1733 .from(provider.default_signer_address())
1734 .to(Address::repeat_byte(5))
1735 .value(U256::ZERO)
1736 .input(bytes!("deadbeef").into());
1737
1738 let tx_hash = *provider.send_transaction(req).await.expect("failed to send tx").tx_hash();
1739
1740 let tx = provider
1741 .get_transaction_by_hash(tx_hash)
1742 .await
1743 .expect("failed to fetch tx")
1744 .expect("tx not included");
1745 assert_eq!(tx.input(), &bytes!("deadbeef"));
1746 }
1747
1748 #[tokio::test]
1749 #[ignore]
1750 async fn gets_logs() {
1751 let provider = ProviderBuilder::new().on_anvil();
1752 let filter = Filter::new()
1753 .at_block_hash(b256!(
1754 "b20e6f35d4b46b3c4cd72152faec7143da851a0dc281d390bdd50f58bfbdb5d3"
1755 ))
1756 .event_signature(b256!(
1757 "e1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c"
1758 ));
1759 let logs = provider.get_logs(&filter).await.unwrap();
1760 assert_eq!(logs.len(), 1);
1761 }
1762
1763 #[tokio::test]
1764 #[ignore]
1765 async fn gets_tx_receipt() {
1766 let provider = ProviderBuilder::new().on_anvil();
1767 let receipt = provider
1768 .get_transaction_receipt(b256!(
1769 "5c03fab9114ceb98994b43892ade87ddfd9ae7e8f293935c3bd29d435dc9fd95"
1770 ))
1771 .await
1772 .unwrap();
1773 assert!(receipt.is_some());
1774 let receipt = receipt.unwrap();
1775 assert_eq!(
1776 receipt.transaction_hash,
1777 b256!("5c03fab9114ceb98994b43892ade87ddfd9ae7e8f293935c3bd29d435dc9fd95")
1778 );
1779 }
1780
1781 #[tokio::test]
1782 async fn gets_max_priority_fee_per_gas() {
1783 let provider = ProviderBuilder::new().on_anvil();
1784 let _fee = provider.get_max_priority_fee_per_gas().await.unwrap();
1785 }
1786
1787 #[tokio::test]
1788 async fn gets_fee_history() {
1789 let provider = ProviderBuilder::new().on_anvil();
1790 let block_number = provider.get_block_number().await.unwrap();
1791 let fee_history = provider
1792 .get_fee_history(
1793 utils::EIP1559_FEE_ESTIMATION_PAST_BLOCKS,
1794 BlockNumberOrTag::Number(block_number),
1795 &[utils::EIP1559_FEE_ESTIMATION_REWARD_PERCENTILE],
1796 )
1797 .await
1798 .unwrap();
1799 assert_eq!(fee_history.oldest_block, 0_u64);
1800 }
1801
1802 #[tokio::test]
1803 async fn gets_block_transaction_count_by_hash() {
1804 let provider = ProviderBuilder::new().on_anvil();
1805 let block = provider.get_block(BlockId::latest()).await.unwrap().unwrap();
1806 let hash = block.header.hash;
1807 let tx_count = provider.get_block_transaction_count_by_hash(hash).await.unwrap();
1808 assert!(tx_count.is_some());
1809 }
1810
1811 #[tokio::test]
1812 async fn gets_block_transaction_count_by_number() {
1813 let provider = ProviderBuilder::new().on_anvil();
1814 let tx_count =
1815 provider.get_block_transaction_count_by_number(BlockNumberOrTag::Latest).await.unwrap();
1816 assert!(tx_count.is_some());
1817 }
1818
1819 #[tokio::test]
1820 async fn gets_block_receipts() {
1821 let provider = ProviderBuilder::new().on_anvil();
1822 let receipts =
1823 provider.get_block_receipts(BlockId::Number(BlockNumberOrTag::Latest)).await.unwrap();
1824 assert!(receipts.is_some());
1825 }
1826
1827 #[tokio::test]
1828 async fn sends_raw_transaction() {
1829 let provider = ProviderBuilder::new().on_anvil();
1830 let pending = provider
1831 .send_raw_transaction(
1832 bytes!("f865808477359400825208940000000000000000000000000000000000000000018082f4f5a00505e227c1c636c76fac55795db1a40a4d24840d81b40d2fe0cc85767f6bd202a01e91b437099a8a90234ac5af3cb7ca4fb1432e133f75f9a91678eaf5f487c74b").as_ref()
1834 )
1835 .await.unwrap();
1836 assert_eq!(
1837 pending.tx_hash().to_string(),
1838 "0x9dae5cf33694a02e8a7d5de3fe31e9d05ca0ba6e9180efac4ab20a06c9e598a3"
1839 );
1840 }
1841
1842 #[tokio::test]
1843 async fn connect_boxed() {
1844 let anvil = Anvil::new().spawn();
1845
1846 let provider = RootProvider::<Ethereum>::connect(anvil.endpoint().as_str()).await;
1847
1848 match provider {
1849 Ok(provider) => {
1850 let num = provider.get_block_number().await.unwrap();
1851 assert_eq!(0, num);
1852 }
1853 Err(e) => {
1854 assert_eq!(
1855 format!("{}",e),
1856 "hyper not supported by BuiltinConnectionString. Please instantiate a hyper client manually"
1857 );
1858 }
1859 }
1860 }
1861
1862 #[tokio::test]
1863 async fn any_network_wallet_filler() {
1864 use alloy_serde::WithOtherFields;
1865 let anvil = Anvil::new().spawn();
1866 let signer: PrivateKeySigner =
1867 "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80".parse().unwrap();
1868 let wallet = EthereumWallet::from(signer);
1869
1870 let provider = ProviderBuilder::new()
1871 .network::<AnyNetwork>()
1872 .wallet(wallet)
1873 .on_http(anvil.endpoint_url());
1874
1875 let tx = TransactionRequest::default()
1876 .with_to(address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"))
1877 .value(U256::from(325235));
1878
1879 let tx = WithOtherFields::new(tx);
1880
1881 let builder = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();
1882
1883 assert!(builder.status());
1884 }
1885
1886 #[tokio::test]
1887 async fn builtin_connect_boxed() {
1888 let anvil = Anvil::new().spawn();
1889
1890 let conn: BuiltInConnectionString = anvil.endpoint().parse().unwrap();
1891
1892 let transport = conn.connect_boxed().await.unwrap();
1893
1894 let client = alloy_rpc_client::RpcClient::new(transport, true);
1895
1896 let provider = RootProvider::<Ethereum>::new(client);
1897
1898 let num = provider.get_block_number().await.unwrap();
1899 assert_eq!(0, num);
1900 }
1901
1902 #[tokio::test]
1903 async fn test_uncle_count() {
1904 let provider = ProviderBuilder::new().on_anvil();
1905
1906 let count = provider.get_uncle_count(0.into()).await.unwrap();
1907 assert_eq!(count, 0);
1908 }
1909
1910 #[tokio::test]
1911 #[cfg(any(
1912 feature = "reqwest-default-tls",
1913 feature = "reqwest-rustls-tls",
1914 feature = "reqwest-native-tls",
1915 ))]
1916 #[ignore = "ignore until <https://github.com/paradigmxyz/reth/pull/14727> is in"]
1917 async fn call_mainnet() {
1918 use alloy_network::TransactionBuilder;
1919 use alloy_sol_types::SolValue;
1920
1921 let url = "https://docs-demo.quiknode.pro/";
1922 let provider = ProviderBuilder::new().on_http(url.parse().unwrap());
1923 let req = TransactionRequest::default()
1924 .with_to(address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")) .with_input(bytes!("06fdde03")); let result = provider.call(req.clone()).await.unwrap();
1927 assert_eq!(String::abi_decode(&result, true).unwrap(), "Wrapped Ether");
1928
1929 let result = provider.call(req).block(0.into()).await.unwrap();
1930 assert_eq!(result.to_string(), "0x");
1931 }
1932
1933 #[tokio::test]
1934 async fn call_many_mainnet() {
1935 use alloy_rpc_types_eth::{BlockOverrides, StateContext};
1936
1937 let url = "https://docs-demo.quiknode.pro/";
1938 let provider = ProviderBuilder::new().on_http(url.parse().unwrap());
1939 let tx1 = TransactionRequest::default()
1940 .with_to(address!("6b175474e89094c44da98b954eedeac495271d0f"))
1941 .with_gas_limit(1000000)
1942 .with_gas_price(2023155498)
1943 .with_input(hex!("a9059cbb000000000000000000000000bc0E63965946815d105E7591407704e6e1964E590000000000000000000000000000000000000000000000000000000005f5e100"));
1944 let tx2 = TransactionRequest::default()
1945 .with_to(address!("833589fcd6edb6e08f4c7c32d4f71b54bda02913"))
1946 .with_gas_price(2023155498)
1947 .with_input(hex!(
1948 "70a08231000000000000000000000000bc0E63965946815d105E7591407704e6e1964E59"
1949 ));
1950
1951 let transactions = vec![tx1.clone(), tx2.clone()];
1952
1953 let block_override =
1954 BlockOverrides { number: Some(U256::from(12279785)), ..Default::default() };
1955
1956 let bundles = vec![Bundle { transactions, block_override: Some(block_override.clone()) }];
1957
1958 let context = StateContext {
1959 block_number: Some(BlockId::number(12279785)),
1960 transaction_index: Some(1.into()),
1961 };
1962
1963 let results = provider.call_many(&bundles).context(&context).await.unwrap();
1964
1965 let tx1_res = EthCallResponse {
1966 value: Some(
1967 hex!("0000000000000000000000000000000000000000000000000000000000000001").into(),
1968 ),
1969 error: None,
1970 };
1971 let tx2_res = EthCallResponse { value: Some(Bytes::new()), error: None };
1972 let expected = vec![vec![tx1_res.clone(), tx2_res.clone()]];
1973
1974 assert_eq!(results, expected);
1975
1976 let bundles = vec![
1978 Bundle {
1979 transactions: vec![tx1.clone()],
1980 block_override: Some(block_override.clone()),
1981 },
1982 Bundle {
1983 transactions: vec![tx2.clone()],
1984 block_override: Some(block_override.clone()),
1985 },
1986 ];
1987
1988 let results = provider.call_many(&bundles).context(&context).await.unwrap();
1989 let expected = vec![vec![tx1_res.clone()], vec![tx2_res.clone()]];
1990 assert_eq!(results, expected);
1991
1992 let b1 =
1994 vec![Bundle { transactions: vec![tx1], block_override: Some(block_override.clone()) }];
1995 let b2 = vec![Bundle { transactions: vec![tx2], block_override: Some(block_override) }];
1996
1997 let results = provider.call_many(&b1).context(&context).extend_bundles(&b2).await.unwrap();
1998 assert_eq!(results, expected);
1999 }
2000
2001 #[tokio::test]
2002 #[cfg(feature = "hyper-tls")]
2003 async fn hyper_https() {
2004 let url = "https://reth-ethereum.ithaca.xyz/rpc";
2005
2006 let provider = ProviderBuilder::new().connect(url).await.unwrap();
2009
2010 let _num = provider.get_block_number().await.unwrap();
2011 }
2012
2013 #[tokio::test]
2014 async fn test_empty_transactions() {
2015 let provider = ProviderBuilder::new().on_anvil();
2016
2017 let block = provider.get_block_by_number(0.into()).await.unwrap().unwrap();
2018 assert!(block.transactions.is_hashes());
2019 }
2020
2021 #[tokio::test]
2022 async fn disable_test() {
2023 let provider = ProviderBuilder::new()
2024 .disable_recommended_fillers()
2025 .with_cached_nonce_management()
2026 .on_anvil();
2027
2028 let tx = TransactionRequest::default()
2029 .with_kind(alloy_primitives::TxKind::Create)
2030 .value(U256::from(1235))
2031 .with_input(Bytes::from_str("ffffffffffffff").unwrap());
2032
2033 let err = provider.send_transaction(tx).await.unwrap_err().to_string();
2034 assert!(err.contains("missing properties: [(\"NonceManager\", [\"from\"])]"));
2035 }
2036
2037 #[tokio::test]
2038 async fn capture_anvil_logs() {
2039 let mut anvil = Anvil::new().keep_stdout().spawn();
2040
2041 let provider = ProviderBuilder::new().on_http(anvil.endpoint_url());
2042
2043 let tx = TransactionRequest::default()
2044 .with_from(address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"))
2045 .with_to(address!("70997970C51812dc3A010C7d01b50e0d17dc79C8"))
2046 .value(U256::from(100));
2047
2048 let _ = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();
2049
2050 anvil.child_mut().kill().unwrap();
2051
2052 let mut output = String::new();
2053 anvil.child_mut().stdout.take().unwrap().read_to_string(&mut output).unwrap();
2054
2055 assert_eq!(anvil.chain_id(), 31337);
2056 assert_eq!(anvil.addresses().len(), 10);
2057 assert_eq!(anvil.keys().len(), 10);
2058
2059 assert!(output.contains("eth_sendTransaction"));
2060 assert!(output.contains("Block Number: 1"))
2061 }
2062
2063 #[tokio::test]
2064 async fn custom_estimator() {
2065 let provider = ProviderBuilder::new()
2066 .disable_recommended_fillers()
2067 .with_cached_nonce_management()
2068 .on_anvil();
2069
2070 let _ = provider
2071 .estimate_eip1559_fees_with(Eip1559Estimator::new(|_fee, _rewards| Eip1559Estimation {
2072 max_fee_per_gas: 0,
2073 max_priority_fee_per_gas: 0,
2074 }))
2075 .await;
2076 }
2077}