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