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