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