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