Skip to main content

alloy_provider/provider/
erased.rs

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