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