Skip to main content

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