1use async_trait::async_trait;
2use auto_impl::auto_impl;
3use serde::Serialize;
4use starknet_core::types::{
5    requests::*, BlockHashAndNumber, BlockId, BroadcastedDeclareTransaction,
6    BroadcastedDeployAccountTransaction, BroadcastedInvokeTransaction, BroadcastedTransaction,
7    ConfirmedBlockId, ContractClass, ContractStorageKeys, DeclareTransactionResult,
8    DeployAccountTransactionResult, EventFilter, EventsPage, FeeEstimate, Felt, FunctionCall,
9    Hash256, InvokeTransactionResult, MaybePreConfirmedBlockWithReceipts,
10    MaybePreConfirmedBlockWithTxHashes, MaybePreConfirmedBlockWithTxs,
11    MaybePreConfirmedStateUpdate, MessageFeeEstimate, MessageStatus, MsgFromL1,
12    SimulatedTransaction, SimulationFlag, SimulationFlagForEstimateFee, StarknetError,
13    StorageProof, SubscriptionId, SyncStatusType, Transaction, TransactionReceiptWithBlockInfo,
14    TransactionStatus, TransactionTrace, TransactionTraceWithHash,
15};
16use std::{any::Any, error::Error, fmt::Debug};
17
18#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
29#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
30#[auto_impl(&, Box, Arc)]
31pub trait Provider {
32    async fn spec_version(&self) -> Result<String, ProviderError>;
34
35    async fn get_block_with_tx_hashes<B>(
37        &self,
38        block_id: B,
39    ) -> Result<MaybePreConfirmedBlockWithTxHashes, ProviderError>
40    where
41        B: AsRef<BlockId> + Send + Sync;
42
43    async fn get_block_with_txs<B>(
45        &self,
46        block_id: B,
47    ) -> Result<MaybePreConfirmedBlockWithTxs, ProviderError>
48    where
49        B: AsRef<BlockId> + Send + Sync;
50
51    async fn get_block_with_receipts<B>(
53        &self,
54        block_id: B,
55    ) -> Result<MaybePreConfirmedBlockWithReceipts, ProviderError>
56    where
57        B: AsRef<BlockId> + Send + Sync;
58
59    async fn get_state_update<B>(
61        &self,
62        block_id: B,
63    ) -> Result<MaybePreConfirmedStateUpdate, ProviderError>
64    where
65        B: AsRef<BlockId> + Send + Sync;
66
67    async fn get_storage_at<A, K, B>(
69        &self,
70        contract_address: A,
71        key: K,
72        block_id: B,
73    ) -> Result<Felt, ProviderError>
74    where
75        A: AsRef<Felt> + Send + Sync,
76        K: AsRef<Felt> + Send + Sync,
77        B: AsRef<BlockId> + Send + Sync;
78
79    async fn get_messages_status(
82        &self,
83        transaction_hash: Hash256,
84    ) -> Result<Vec<MessageStatus>, ProviderError>;
85
86    async fn get_transaction_status<H>(
89        &self,
90        transaction_hash: H,
91    ) -> Result<TransactionStatus, ProviderError>
92    where
93        H: AsRef<Felt> + Send + Sync;
94
95    async fn get_transaction_by_hash<H>(
97        &self,
98        transaction_hash: H,
99    ) -> Result<Transaction, ProviderError>
100    where
101        H: AsRef<Felt> + Send + Sync;
102
103    async fn get_transaction_by_block_id_and_index<B>(
105        &self,
106        block_id: B,
107        index: u64,
108    ) -> Result<Transaction, ProviderError>
109    where
110        B: AsRef<BlockId> + Send + Sync;
111
112    async fn get_transaction_receipt<H>(
114        &self,
115        transaction_hash: H,
116    ) -> Result<TransactionReceiptWithBlockInfo, ProviderError>
117    where
118        H: AsRef<Felt> + Send + Sync;
119
120    async fn get_class<B, H>(
122        &self,
123        block_id: B,
124        class_hash: H,
125    ) -> Result<ContractClass, ProviderError>
126    where
127        B: AsRef<BlockId> + Send + Sync,
128        H: AsRef<Felt> + Send + Sync;
129
130    async fn get_class_hash_at<B, A>(
133        &self,
134        block_id: B,
135        contract_address: A,
136    ) -> Result<Felt, ProviderError>
137    where
138        B: AsRef<BlockId> + Send + Sync,
139        A: AsRef<Felt> + Send + Sync;
140
141    async fn get_class_at<B, A>(
143        &self,
144        block_id: B,
145        contract_address: A,
146    ) -> Result<ContractClass, ProviderError>
147    where
148        B: AsRef<BlockId> + Send + Sync,
149        A: AsRef<Felt> + Send + Sync;
150
151    async fn get_block_transaction_count<B>(&self, block_id: B) -> Result<u64, ProviderError>
153    where
154        B: AsRef<BlockId> + Send + Sync;
155
156    async fn call<R, B>(&self, request: R, block_id: B) -> Result<Vec<Felt>, ProviderError>
158    where
159        R: AsRef<FunctionCall> + Send + Sync,
160        B: AsRef<BlockId> + Send + Sync;
161
162    async fn estimate_fee<R, S, B>(
164        &self,
165        request: R,
166        simulation_flags: S,
167        block_id: B,
168    ) -> Result<Vec<FeeEstimate>, ProviderError>
169    where
170        R: AsRef<[BroadcastedTransaction]> + Send + Sync,
171        S: AsRef<[SimulationFlagForEstimateFee]> + Send + Sync,
172        B: AsRef<BlockId> + Send + Sync;
173
174    async fn estimate_message_fee<M, B>(
176        &self,
177        message: M,
178        block_id: B,
179    ) -> Result<MessageFeeEstimate, ProviderError>
180    where
181        M: AsRef<MsgFromL1> + Send + Sync,
182        B: AsRef<BlockId> + Send + Sync;
183
184    async fn block_number(&self) -> Result<u64, ProviderError>;
186
187    async fn block_hash_and_number(&self) -> Result<BlockHashAndNumber, ProviderError>;
189
190    async fn chain_id(&self) -> Result<Felt, ProviderError>;
192
193    async fn syncing(&self) -> Result<SyncStatusType, ProviderError>;
195
196    async fn get_events(
198        &self,
199        filter: EventFilter,
200        continuation_token: Option<String>,
201        chunk_size: u64,
202    ) -> Result<EventsPage, ProviderError>;
203
204    async fn get_nonce<B, A>(
206        &self,
207        block_id: B,
208        contract_address: A,
209    ) -> Result<Felt, ProviderError>
210    where
211        B: AsRef<BlockId> + Send + Sync,
212        A: AsRef<Felt> + Send + Sync;
213
214    async fn get_storage_proof<B, H, A, K>(
218        &self,
219        block_id: B,
220        class_hashes: H,
221        contract_addresses: A,
222        contracts_storage_keys: K,
223    ) -> Result<StorageProof, ProviderError>
224    where
225        B: AsRef<ConfirmedBlockId> + Send + Sync,
226        H: AsRef<[Felt]> + Send + Sync,
227        A: AsRef<[Felt]> + Send + Sync,
228        K: AsRef<[ContractStorageKeys]> + Send + Sync;
229
230    async fn add_invoke_transaction<I>(
232        &self,
233        invoke_transaction: I,
234    ) -> Result<InvokeTransactionResult, ProviderError>
235    where
236        I: AsRef<BroadcastedInvokeTransaction> + Send + Sync;
237
238    async fn add_declare_transaction<D>(
240        &self,
241        declare_transaction: D,
242    ) -> Result<DeclareTransactionResult, ProviderError>
243    where
244        D: AsRef<BroadcastedDeclareTransaction> + Send + Sync;
245
246    async fn add_deploy_account_transaction<D>(
248        &self,
249        deploy_account_transaction: D,
250    ) -> Result<DeployAccountTransactionResult, ProviderError>
251    where
252        D: AsRef<BroadcastedDeployAccountTransaction> + Send + Sync;
253
254    async fn trace_transaction<H>(
257        &self,
258        transaction_hash: H,
259    ) -> Result<TransactionTrace, ProviderError>
260    where
261        H: AsRef<Felt> + Send + Sync;
262
263    async fn simulate_transactions<B, T, S>(
271        &self,
272        block_id: B,
273        transactions: T,
274        simulation_flags: S,
275    ) -> Result<Vec<SimulatedTransaction>, ProviderError>
276    where
277        B: AsRef<BlockId> + Send + Sync,
278        T: AsRef<[BroadcastedTransaction]> + Send + Sync,
279        S: AsRef<[SimulationFlag]> + Send + Sync;
280
281    async fn trace_block_transactions<B>(
283        &self,
284        block_id: B,
285    ) -> Result<Vec<TransactionTraceWithHash>, ProviderError>
286    where
287        B: AsRef<ConfirmedBlockId> + Send + Sync;
288
289    async fn batch_requests<R>(
292        &self,
293        requests: R,
294    ) -> Result<Vec<ProviderResponseData>, ProviderError>
295    where
296        R: AsRef<[ProviderRequestData]> + Send + Sync;
297
298    async fn estimate_fee_single<R, S, B>(
300        &self,
301        request: R,
302        simulation_flags: S,
303        block_id: B,
304    ) -> Result<FeeEstimate, ProviderError>
305    where
306        R: AsRef<BroadcastedTransaction> + Send + Sync,
307        S: AsRef<[SimulationFlagForEstimateFee]> + Send + Sync,
308        B: AsRef<BlockId> + Send + Sync,
309    {
310        let mut result = self
311            .estimate_fee([request.as_ref().to_owned()], simulation_flags, block_id)
312            .await?;
313
314        if result.len() == 1 {
315            Ok(result.pop().unwrap())
317        } else {
318            Err(ProviderError::ArrayLengthMismatch)
319        }
320    }
321
322    async fn simulate_transaction<B, T, S>(
324        &self,
325        block_id: B,
326        transaction: T,
327        simulation_flags: S,
328    ) -> Result<SimulatedTransaction, ProviderError>
329    where
330        B: AsRef<BlockId> + Send + Sync,
331        T: AsRef<BroadcastedTransaction> + Send + Sync,
332        S: AsRef<[SimulationFlag]> + Send + Sync,
333    {
334        let mut result = self
335            .simulate_transactions(
336                block_id,
337                [transaction.as_ref().to_owned()],
338                simulation_flags,
339            )
340            .await?;
341
342        if result.len() == 1 {
343            Ok(result.pop().unwrap())
345        } else {
346            Err(ProviderError::ArrayLengthMismatch)
347        }
348    }
349}
350
351pub trait ProviderImplError: Error + Debug + Send + Sync {
359    fn as_any(&self) -> &dyn Any;
362}
363
364#[derive(Debug, thiserror::Error)]
375pub enum ProviderError {
376    #[error(transparent)]
378    StarknetError(StarknetError),
379    #[error("Request rate limited")]
381    RateLimited,
382    #[error("Array length mismatch")]
385    ArrayLengthMismatch,
386    #[error("{0}")]
388    Other(Box<dyn ProviderImplError>),
389}
390
391#[derive(Debug, Clone, Serialize)]
393#[serde(untagged)]
394pub enum ProviderRequestData {
395    SpecVersion(SpecVersionRequest),
397    GetBlockWithTxHashes(GetBlockWithTxHashesRequest),
399    GetBlockWithTxs(GetBlockWithTxsRequest),
401    GetBlockWithReceipts(GetBlockWithReceiptsRequest),
403    GetStateUpdate(GetStateUpdateRequest),
405    GetStorageAt(GetStorageAtRequest),
407    GetMessagesStatus(GetMessagesStatusRequest),
409    GetTransactionStatus(GetTransactionStatusRequest),
411    GetTransactionByHash(GetTransactionByHashRequest),
413    GetTransactionByBlockIdAndIndex(GetTransactionByBlockIdAndIndexRequest),
415    GetTransactionReceipt(GetTransactionReceiptRequest),
417    GetClass(GetClassRequest),
419    GetClassHashAt(GetClassHashAtRequest),
421    GetClassAt(GetClassAtRequest),
423    GetBlockTransactionCount(GetBlockTransactionCountRequest),
425    Call(CallRequest),
427    EstimateFee(EstimateFeeRequest),
429    EstimateMessageFee(EstimateMessageFeeRequest),
431    BlockNumber(BlockNumberRequest),
433    BlockHashAndNumber(BlockHashAndNumberRequest),
435    ChainId(ChainIdRequest),
437    Syncing(SyncingRequest),
439    GetEvents(GetEventsRequest),
441    GetNonce(GetNonceRequest),
443    GetStorageProof(GetStorageProofRequest),
445    AddInvokeTransaction(AddInvokeTransactionRequest),
447    AddDeclareTransaction(AddDeclareTransactionRequest),
449    AddDeployAccountTransaction(AddDeployAccountTransactionRequest),
451    TraceTransaction(TraceTransactionRequest),
453    SimulateTransactions(SimulateTransactionsRequest),
455    TraceBlockTransactions(TraceBlockTransactionsRequest),
457    SubscribeNewHeads(SubscribeNewHeadsRequest),
459    SubscribeEvents(SubscribeEventsRequest),
461    SubscribeTransactionStatus(SubscribeTransactionStatusRequest),
463    SubscribeNewTransactionReceipts(SubscribeNewTransactionReceiptsRequest),
465    SubscribeNewTransactions(SubscribeNewTransactionsRequest),
467    Unsubscribe(UnsubscribeRequest),
469}
470
471#[allow(clippy::large_enum_variant)]
473#[derive(Debug, Clone)]
474pub enum ProviderResponseData {
475    SpecVersion(String),
477    GetBlockWithTxHashes(MaybePreConfirmedBlockWithTxHashes),
479    GetBlockWithTxs(MaybePreConfirmedBlockWithTxs),
481    GetBlockWithReceipts(MaybePreConfirmedBlockWithReceipts),
483    GetStateUpdate(MaybePreConfirmedStateUpdate),
485    GetStorageAt(Felt),
487    GetMessagesStatus(Vec<MessageStatus>),
489    GetTransactionStatus(TransactionStatus),
491    GetTransactionByHash(Transaction),
493    GetTransactionByBlockIdAndIndex(Transaction),
495    GetTransactionReceipt(TransactionReceiptWithBlockInfo),
497    GetClass(ContractClass),
499    GetClassHashAt(Felt),
501    GetClassAt(ContractClass),
503    GetBlockTransactionCount(u64),
505    Call(Vec<Felt>),
507    EstimateFee(Vec<FeeEstimate>),
509    EstimateMessageFee(FeeEstimate),
511    BlockNumber(u64),
513    BlockHashAndNumber(BlockHashAndNumber),
515    ChainId(Felt),
517    Syncing(SyncStatusType),
519    GetEvents(EventsPage),
521    GetNonce(Felt),
523    GetStorageProof(StorageProof),
525    AddInvokeTransaction(InvokeTransactionResult),
527    AddDeclareTransaction(DeclareTransactionResult),
529    AddDeployAccountTransaction(DeployAccountTransactionResult),
531    TraceTransaction(TransactionTrace),
533    SimulateTransactions(Vec<SimulatedTransaction>),
535    TraceBlockTransactions(Vec<TransactionTraceWithHash>),
537    SubscribeNewHeads(SubscriptionId),
539    SubscribeEvents(SubscriptionId),
541    SubscribeTransactionStatus(SubscriptionId),
543    SubscribeNewTransactionReceipts(SubscriptionId),
545    SubscribeNewTransactions(SubscriptionId),
547    Unsubscribe(bool),
549}
550
551#[allow(clippy::enum_variant_names)]
553#[derive(Debug, Clone, Serialize)]
554#[serde(untagged)]
555pub enum StreamUpdateData {
556    SubscriptionNewHeads(SubscriptionNewHeadsRequest),
558    SubscriptionEvents(SubscriptionEventsRequest),
560    SubscriptionTransactionStatus(SubscriptionTransactionStatusRequest),
562    SubscriptionNewTransactionReceipts(SubscriptionNewTransactionReceiptsRequest),
564    SubscriptionNewTransaction(SubscriptionNewTransactionRequest),
566    SubscriptionReorg(SubscriptionReorgRequest),
568}
569
570impl StreamUpdateData {
571    pub fn subscription_id(&self) -> &SubscriptionId {
573        match self {
574            Self::SubscriptionNewHeads(update) => &update.subscription_id,
575            Self::SubscriptionEvents(update) => &update.subscription_id,
576            Self::SubscriptionTransactionStatus(update) => &update.subscription_id,
577            Self::SubscriptionNewTransactionReceipts(update) => &update.subscription_id,
578            Self::SubscriptionNewTransaction(update) => &update.subscription_id,
579            Self::SubscriptionReorg(update) => &update.subscription_id,
580        }
581    }
582}