1use super::{EthCallMany, EthGetBlock, FilterPollerBuilder};
2#[cfg(feature = "pubsub")]
3use crate::GetSubscription;
4use crate::{
5 heart::PendingTransactionError,
6 utils::{Eip1559Estimation, Eip1559Estimator},
7 EthCall, PendingTransaction, PendingTransactionBuilder, PendingTransactionConfig, Provider,
8 ProviderCall, RootProvider, RpcWithBlock, SendableTx,
9};
10use alloy_network::{Ethereum, Network};
11use alloy_primitives::{
12 Address, BlockHash, BlockNumber, Bytes, StorageKey, StorageValue, TxHash, B256, U128, U256, U64,
13};
14use alloy_rpc_client::{ClientRef, NoParams, WeakClient};
15#[cfg(feature = "pubsub")]
16use alloy_rpc_types_eth::pubsub::{Params, SubscriptionKind};
17use alloy_rpc_types_eth::{
18 erc4337::TransactionConditional,
19 simulate::{SimulatePayload, SimulatedBlock},
20 AccessListResult, BlockId, BlockNumberOrTag, Bundle, EIP1186AccountProofResponse,
21 EthCallResponse, FeeHistory, Filter, FilterChanges, Index, Log, SyncStatus,
22};
23use alloy_transport::TransportResult;
24use serde_json::value::RawValue;
25use std::{borrow::Cow, sync::Arc};
26
27#[derive(Clone)]
34#[doc(alias = "BoxProvider")]
35pub struct DynProvider<N = Ethereum>(Arc<dyn Provider<N> + 'static>);
36
37impl<N: Network> DynProvider<N> {
38 pub fn new<P: Provider<N> + 'static>(provider: P) -> Self {
42 Self(Arc::new(provider))
43 }
44}
45
46#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
47#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
48impl<N: Network> Provider<N> for DynProvider<N> {
49 fn root(&self) -> &RootProvider<N> {
50 self.0.root()
51 }
52
53 fn client(&self) -> ClientRef<'_> {
54 self.0.client()
55 }
56
57 fn weak_client(&self) -> WeakClient {
58 self.0.weak_client()
59 }
60
61 fn erased(self) -> Self
62 where
63 Self: Sized + 'static,
64 {
65 self
66 }
67
68 fn get_accounts(&self) -> ProviderCall<NoParams, Vec<Address>> {
69 self.0.get_accounts()
70 }
71
72 fn get_blob_base_fee(&self) -> ProviderCall<NoParams, U128, u128> {
73 self.0.get_blob_base_fee()
74 }
75
76 fn get_block_number(&self) -> ProviderCall<NoParams, U64, BlockNumber> {
77 self.0.get_block_number()
78 }
79
80 fn call(&self, tx: N::TransactionRequest) -> EthCall<N, Bytes> {
81 self.0.call(tx)
82 }
83
84 fn call_many<'req>(
85 &self,
86 bundles: &'req [Bundle],
87 ) -> EthCallMany<'req, N, Vec<Vec<EthCallResponse>>> {
88 self.0.call_many(bundles)
89 }
90
91 fn simulate<'req>(
92 &self,
93 payload: &'req SimulatePayload,
94 ) -> RpcWithBlock<&'req SimulatePayload, Vec<SimulatedBlock<N::BlockResponse>>> {
95 self.0.simulate(payload)
96 }
97
98 fn get_chain_id(&self) -> ProviderCall<NoParams, U64, u64> {
99 self.0.get_chain_id()
100 }
101
102 fn create_access_list<'a>(
103 &self,
104 request: &'a N::TransactionRequest,
105 ) -> RpcWithBlock<&'a N::TransactionRequest, AccessListResult> {
106 self.0.create_access_list(request)
107 }
108
109 fn estimate_gas(&self, tx: N::TransactionRequest) -> EthCall<N, U64, u64> {
110 self.0.estimate_gas(tx)
111 }
112
113 async fn estimate_eip1559_fees_with(
114 &self,
115 estimator: Eip1559Estimator,
116 ) -> TransportResult<Eip1559Estimation> {
117 self.0.estimate_eip1559_fees_with(estimator).await
118 }
119
120 async fn estimate_eip1559_fees(&self) -> TransportResult<Eip1559Estimation> {
121 self.0.estimate_eip1559_fees().await
122 }
123
124 async fn get_fee_history(
125 &self,
126 block_count: u64,
127 last_block: BlockNumberOrTag,
128 reward_percentiles: &[f64],
129 ) -> TransportResult<FeeHistory> {
130 self.0.get_fee_history(block_count, last_block, reward_percentiles).await
131 }
132
133 fn get_gas_price(&self) -> ProviderCall<NoParams, U128, u128> {
134 self.0.get_gas_price()
135 }
136
137 fn get_account_info(
138 &self,
139 address: Address,
140 ) -> RpcWithBlock<Address, alloy_rpc_types_eth::AccountInfo> {
141 self.0.get_account_info(address)
142 }
143
144 fn get_account(&self, address: Address) -> RpcWithBlock<Address, alloy_consensus::Account> {
145 self.0.get_account(address)
146 }
147
148 fn get_balance(&self, address: Address) -> RpcWithBlock<Address, U256, U256> {
149 self.0.get_balance(address)
150 }
151
152 fn get_block(&self, block: BlockId) -> EthGetBlock<N::BlockResponse> {
153 self.0.get_block(block)
154 }
155
156 fn get_block_by_hash(&self, hash: BlockHash) -> EthGetBlock<N::BlockResponse> {
157 self.0.get_block_by_hash(hash)
158 }
159
160 fn get_block_by_number(&self, number: BlockNumberOrTag) -> EthGetBlock<N::BlockResponse> {
161 self.0.get_block_by_number(number)
162 }
163
164 async fn get_block_transaction_count_by_hash(
165 &self,
166 hash: BlockHash,
167 ) -> TransportResult<Option<u64>> {
168 self.0.get_block_transaction_count_by_hash(hash).await
169 }
170
171 async fn get_block_transaction_count_by_number(
172 &self,
173 block_number: BlockNumberOrTag,
174 ) -> TransportResult<Option<u64>> {
175 self.0.get_block_transaction_count_by_number(block_number).await
176 }
177
178 fn get_block_receipts(
179 &self,
180 block: BlockId,
181 ) -> ProviderCall<(BlockId,), Option<Vec<N::ReceiptResponse>>> {
182 self.0.get_block_receipts(block)
183 }
184
185 fn get_code_at(&self, address: Address) -> RpcWithBlock<Address, Bytes> {
186 self.0.get_code_at(address)
187 }
188
189 async fn watch_blocks(&self) -> TransportResult<FilterPollerBuilder<B256>> {
190 self.0.watch_blocks().await
191 }
192
193 async fn watch_pending_transactions(&self) -> TransportResult<FilterPollerBuilder<B256>> {
194 self.0.watch_pending_transactions().await
195 }
196
197 async fn watch_logs(&self, filter: &Filter) -> TransportResult<FilterPollerBuilder<Log>> {
198 self.0.watch_logs(filter).await
199 }
200
201 async fn watch_full_pending_transactions(
202 &self,
203 ) -> TransportResult<FilterPollerBuilder<N::TransactionResponse>> {
204 self.0.watch_full_pending_transactions().await
205 }
206
207 async fn get_filter_changes_dyn(&self, id: U256) -> TransportResult<FilterChanges> {
208 self.0.get_filter_changes_dyn(id).await
209 }
210
211 async fn get_filter_logs(&self, id: U256) -> TransportResult<Vec<Log>> {
212 self.0.get_filter_logs(id).await
213 }
214
215 async fn uninstall_filter(&self, id: U256) -> TransportResult<bool> {
216 self.0.uninstall_filter(id).await
217 }
218
219 async fn watch_pending_transaction(
220 &self,
221 config: PendingTransactionConfig,
222 ) -> Result<PendingTransaction, PendingTransactionError> {
223 self.0.watch_pending_transaction(config).await
224 }
225
226 async fn get_logs(&self, filter: &Filter) -> TransportResult<Vec<Log>> {
227 self.0.get_logs(filter).await
228 }
229
230 fn get_proof(
231 &self,
232 address: Address,
233 keys: Vec<StorageKey>,
234 ) -> RpcWithBlock<(Address, Vec<StorageKey>), EIP1186AccountProofResponse> {
235 self.0.get_proof(address, keys)
236 }
237
238 fn get_storage_at(
239 &self,
240 address: Address,
241 key: U256,
242 ) -> RpcWithBlock<(Address, U256), StorageValue> {
243 self.0.get_storage_at(address, key)
244 }
245
246 fn get_transaction_by_hash(
247 &self,
248 hash: TxHash,
249 ) -> ProviderCall<(TxHash,), Option<N::TransactionResponse>> {
250 self.0.get_transaction_by_hash(hash)
251 }
252
253 fn get_transaction_by_sender_nonce(
254 &self,
255 sender: Address,
256 nonce: u64,
257 ) -> ProviderCall<(Address, U64), Option<N::TransactionResponse>> {
258 self.0.get_transaction_by_sender_nonce(sender, nonce)
259 }
260
261 fn get_transaction_by_block_hash_and_index(
262 &self,
263 block_hash: B256,
264 index: usize,
265 ) -> ProviderCall<(B256, Index), Option<N::TransactionResponse>> {
266 self.0.get_transaction_by_block_hash_and_index(block_hash, index)
267 }
268
269 fn get_raw_transaction_by_block_hash_and_index(
270 &self,
271 block_hash: B256,
272 index: usize,
273 ) -> ProviderCall<(B256, Index), Option<Bytes>> {
274 self.0.get_raw_transaction_by_block_hash_and_index(block_hash, index)
275 }
276
277 fn get_transaction_by_block_number_and_index(
278 &self,
279 block_number: BlockNumberOrTag,
280 index: usize,
281 ) -> ProviderCall<(BlockNumberOrTag, Index), Option<N::TransactionResponse>> {
282 self.0.get_transaction_by_block_number_and_index(block_number, index)
283 }
284
285 fn get_raw_transaction_by_block_number_and_index(
286 &self,
287 block_number: BlockNumberOrTag,
288 index: usize,
289 ) -> ProviderCall<(BlockNumberOrTag, Index), Option<Bytes>> {
290 self.0.get_raw_transaction_by_block_number_and_index(block_number, index)
291 }
292
293 fn get_raw_transaction_by_hash(&self, hash: TxHash) -> ProviderCall<(TxHash,), Option<Bytes>> {
294 self.0.get_raw_transaction_by_hash(hash)
295 }
296
297 fn get_transaction_count(
298 &self,
299 address: Address,
300 ) -> RpcWithBlock<Address, U64, u64, fn(U64) -> u64> {
301 self.0.get_transaction_count(address)
302 }
303
304 fn get_transaction_receipt(
305 &self,
306 hash: TxHash,
307 ) -> ProviderCall<(TxHash,), Option<N::ReceiptResponse>> {
308 self.0.get_transaction_receipt(hash)
309 }
310
311 async fn get_uncle(&self, tag: BlockId, idx: u64) -> TransportResult<Option<N::BlockResponse>> {
312 self.0.get_uncle(tag, idx).await
313 }
314
315 async fn get_uncle_count(&self, tag: BlockId) -> TransportResult<u64> {
316 self.0.get_uncle_count(tag).await
317 }
318
319 fn get_max_priority_fee_per_gas(&self) -> ProviderCall<NoParams, U128, u128> {
320 self.0.get_max_priority_fee_per_gas()
321 }
322
323 async fn new_block_filter(&self) -> TransportResult<U256> {
324 self.0.new_block_filter().await
325 }
326
327 async fn new_filter(&self, filter: &Filter) -> TransportResult<U256> {
328 self.0.new_filter(filter).await
329 }
330
331 async fn new_pending_transactions_filter(&self, full: bool) -> TransportResult<U256> {
332 self.0.new_pending_transactions_filter(full).await
333 }
334
335 async fn send_raw_transaction(
336 &self,
337 encoded_tx: &[u8],
338 ) -> TransportResult<PendingTransactionBuilder<N>> {
339 self.0.send_raw_transaction(encoded_tx).await
340 }
341
342 async fn send_raw_transaction_conditional(
343 &self,
344 encoded_tx: &[u8],
345 conditional: TransactionConditional,
346 ) -> TransportResult<PendingTransactionBuilder<N>> {
347 self.0.send_raw_transaction_conditional(encoded_tx, conditional).await
348 }
349
350 async fn send_transaction(
351 &self,
352 tx: N::TransactionRequest,
353 ) -> TransportResult<PendingTransactionBuilder<N>> {
354 self.0.send_transaction(tx).await
355 }
356
357 async fn send_tx_envelope(
358 &self,
359 tx: N::TxEnvelope,
360 ) -> TransportResult<PendingTransactionBuilder<N>> {
361 self.0.send_tx_envelope(tx).await
362 }
363
364 async fn send_transaction_internal(
365 &self,
366 tx: SendableTx<N>,
367 ) -> TransportResult<PendingTransactionBuilder<N>> {
368 self.0.send_transaction_internal(tx).await
369 }
370
371 async fn sign_transaction(&self, tx: N::TransactionRequest) -> TransportResult<Bytes> {
372 self.0.sign_transaction(tx).await
373 }
374
375 #[cfg(feature = "pubsub")]
376 fn subscribe_blocks(&self) -> GetSubscription<(SubscriptionKind,), N::HeaderResponse> {
377 self.0.subscribe_blocks()
378 }
379
380 #[cfg(feature = "pubsub")]
381 fn subscribe_pending_transactions(&self) -> GetSubscription<(SubscriptionKind,), B256> {
382 self.0.subscribe_pending_transactions()
383 }
384
385 #[cfg(feature = "pubsub")]
386 fn subscribe_full_pending_transactions(
387 &self,
388 ) -> GetSubscription<(SubscriptionKind, Params), N::TransactionResponse> {
389 self.0.subscribe_full_pending_transactions()
390 }
391
392 #[cfg(feature = "pubsub")]
393 fn subscribe_logs(&self, filter: &Filter) -> GetSubscription<(SubscriptionKind, Params), Log> {
394 self.0.subscribe_logs(filter)
395 }
396
397 #[cfg(feature = "pubsub")]
398 async fn unsubscribe(&self, id: B256) -> TransportResult<()> {
399 self.0.unsubscribe(id).await
400 }
401
402 fn syncing(&self) -> ProviderCall<NoParams, SyncStatus> {
403 self.0.syncing()
404 }
405
406 fn get_client_version(&self) -> ProviderCall<NoParams, String> {
407 self.0.get_client_version()
408 }
409
410 fn get_sha3(&self, data: &[u8]) -> ProviderCall<(String,), B256> {
411 self.0.get_sha3(data)
412 }
413
414 fn get_net_version(&self) -> ProviderCall<NoParams, U64, u64> {
415 self.0.get_net_version()
416 }
417
418 async fn raw_request_dyn(
419 &self,
420 method: Cow<'static, str>,
421 params: &RawValue,
422 ) -> TransportResult<Box<RawValue>> {
423 self.0.raw_request_dyn(method, params).await
424 }
425
426 fn transaction_request(&self) -> N::TransactionRequest {
427 self.0.transaction_request()
428 }
429}
430
431impl<N> std::fmt::Debug for DynProvider<N> {
432 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
433 f.debug_tuple("DynProvider").field(&"<dyn Provider>").finish()
434 }
435}
436
437#[cfg(test)]
438mod tests {
439 use super::*;
440 use crate::ProviderBuilder;
441 fn assert_provider<P: Provider + Sized + Clone + Unpin + 'static>(_: P) {}
442
443 #[test]
444 fn test_erased_provider() {
445 let provider =
446 ProviderBuilder::new().connect_http("http://localhost:8080".parse().unwrap()).erased();
447 assert_provider(provider);
448 }
449}