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}