alloy_provider/provider/
erased.rs

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