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