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