alloy_provider/provider/
erased.rs

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/// A wrapper struct around a type erased [`Provider`].
24///
25/// This type will delegate all functions to the wrapped provider, with the exception of non
26/// object-safe functions (e.g. [`Provider::subscribe`]) which use the default trait implementation.
27///
28/// This is a convenience type for `Arc<dyn Provider<N> + 'static>`.
29#[derive(Clone)]
30#[doc(alias = "BoxProvider")]
31pub struct DynProvider<N = Ethereum>(Arc<dyn Provider<N> + 'static>);
32
33impl<N: Network> DynProvider<N> {
34    /// Creates a new [`DynProvider`] by erasing the type.
35    ///
36    /// This is the same as [`provider.erased()`](Provider::erased).
37    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}