1use async_trait::async_trait;
2use auto_impl::auto_impl;
3use serde::Serialize;
4use starknet_rust_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 starknet_version<B>(&self, block_id: B) -> Result<String, ProviderError>
37 where
38 B: AsRef<BlockId> + Send + Sync;
39
40 async fn get_block_with_tx_hashes<B>(
42 &self,
43 block_id: B,
44 ) -> Result<MaybePreConfirmedBlockWithTxHashes, ProviderError>
45 where
46 B: AsRef<BlockId> + Send + Sync;
47
48 async fn get_block_with_txs<B>(
50 &self,
51 block_id: B,
52 ) -> Result<MaybePreConfirmedBlockWithTxs, ProviderError>
53 where
54 B: AsRef<BlockId> + Send + Sync;
55
56 async fn get_block_with_receipts<B>(
58 &self,
59 block_id: B,
60 ) -> Result<MaybePreConfirmedBlockWithReceipts, ProviderError>
61 where
62 B: AsRef<BlockId> + Send + Sync;
63
64 async fn get_state_update<B>(
66 &self,
67 block_id: B,
68 ) -> Result<MaybePreConfirmedStateUpdate, ProviderError>
69 where
70 B: AsRef<BlockId> + Send + Sync;
71
72 async fn get_storage_at<A, K, B>(
74 &self,
75 contract_address: A,
76 key: K,
77 block_id: B,
78 ) -> Result<Felt, ProviderError>
79 where
80 A: AsRef<Felt> + Send + Sync,
81 K: AsRef<Felt> + Send + Sync,
82 B: AsRef<BlockId> + Send + Sync;
83
84 async fn get_messages_status(
87 &self,
88 transaction_hash: Hash256,
89 ) -> Result<Vec<MessageStatus>, ProviderError>;
90
91 async fn get_transaction_status<H>(
94 &self,
95 transaction_hash: H,
96 ) -> Result<TransactionStatus, ProviderError>
97 where
98 H: AsRef<Felt> + Send + Sync;
99
100 async fn get_transaction_by_hash<H>(
102 &self,
103 transaction_hash: H,
104 ) -> Result<Transaction, ProviderError>
105 where
106 H: AsRef<Felt> + Send + Sync;
107
108 async fn get_transaction_by_block_id_and_index<B>(
110 &self,
111 block_id: B,
112 index: u64,
113 ) -> Result<Transaction, ProviderError>
114 where
115 B: AsRef<BlockId> + Send + Sync;
116
117 async fn get_transaction_receipt<H>(
119 &self,
120 transaction_hash: H,
121 ) -> Result<TransactionReceiptWithBlockInfo, ProviderError>
122 where
123 H: AsRef<Felt> + Send + Sync;
124
125 async fn get_class<B, H>(
127 &self,
128 block_id: B,
129 class_hash: H,
130 ) -> Result<ContractClass, ProviderError>
131 where
132 B: AsRef<BlockId> + Send + Sync,
133 H: AsRef<Felt> + Send + Sync;
134
135 async fn get_class_hash_at<B, A>(
138 &self,
139 block_id: B,
140 contract_address: A,
141 ) -> Result<Felt, ProviderError>
142 where
143 B: AsRef<BlockId> + Send + Sync,
144 A: AsRef<Felt> + Send + Sync;
145
146 async fn get_class_at<B, A>(
148 &self,
149 block_id: B,
150 contract_address: A,
151 ) -> Result<ContractClass, ProviderError>
152 where
153 B: AsRef<BlockId> + Send + Sync,
154 A: AsRef<Felt> + Send + Sync;
155
156 async fn get_block_transaction_count<B>(&self, block_id: B) -> Result<u64, ProviderError>
158 where
159 B: AsRef<BlockId> + Send + Sync;
160
161 async fn call<R, B>(&self, request: R, block_id: B) -> Result<Vec<Felt>, ProviderError>
163 where
164 R: AsRef<FunctionCall> + Send + Sync,
165 B: AsRef<BlockId> + Send + Sync;
166
167 async fn estimate_fee<R, S, B>(
169 &self,
170 request: R,
171 simulation_flags: S,
172 block_id: B,
173 ) -> Result<Vec<FeeEstimate>, ProviderError>
174 where
175 R: AsRef<[BroadcastedTransaction]> + Send + Sync,
176 S: AsRef<[SimulationFlagForEstimateFee]> + Send + Sync,
177 B: AsRef<BlockId> + Send + Sync;
178
179 async fn estimate_message_fee<M, B>(
181 &self,
182 message: M,
183 block_id: B,
184 ) -> Result<MessageFeeEstimate, ProviderError>
185 where
186 M: AsRef<MsgFromL1> + Send + Sync,
187 B: AsRef<BlockId> + Send + Sync;
188
189 async fn block_number(&self) -> Result<u64, ProviderError>;
191
192 async fn block_hash_and_number(&self) -> Result<BlockHashAndNumber, ProviderError>;
194
195 async fn chain_id(&self) -> Result<Felt, ProviderError>;
197
198 async fn syncing(&self) -> Result<SyncStatusType, ProviderError>;
200
201 async fn get_events(
203 &self,
204 filter: EventFilter,
205 continuation_token: Option<String>,
206 chunk_size: u64,
207 ) -> Result<EventsPage, ProviderError>;
208
209 async fn get_nonce<B, A>(
211 &self,
212 block_id: B,
213 contract_address: A,
214 ) -> Result<Felt, ProviderError>
215 where
216 B: AsRef<BlockId> + Send + Sync,
217 A: AsRef<Felt> + Send + Sync;
218
219 async fn get_storage_proof<B, H, A, K>(
223 &self,
224 block_id: B,
225 class_hashes: H,
226 contract_addresses: A,
227 contracts_storage_keys: K,
228 ) -> Result<StorageProof, ProviderError>
229 where
230 B: AsRef<ConfirmedBlockId> + Send + Sync,
231 H: AsRef<[Felt]> + Send + Sync,
232 A: AsRef<[Felt]> + Send + Sync,
233 K: AsRef<[ContractStorageKeys]> + Send + Sync;
234
235 async fn add_invoke_transaction<I>(
237 &self,
238 invoke_transaction: I,
239 ) -> Result<InvokeTransactionResult, ProviderError>
240 where
241 I: AsRef<BroadcastedInvokeTransaction> + Send + Sync;
242
243 async fn add_declare_transaction<D>(
245 &self,
246 declare_transaction: D,
247 ) -> Result<DeclareTransactionResult, ProviderError>
248 where
249 D: AsRef<BroadcastedDeclareTransaction> + Send + Sync;
250
251 async fn add_deploy_account_transaction<D>(
253 &self,
254 deploy_account_transaction: D,
255 ) -> Result<DeployAccountTransactionResult, ProviderError>
256 where
257 D: AsRef<BroadcastedDeployAccountTransaction> + Send + Sync;
258
259 async fn trace_transaction<H>(
262 &self,
263 transaction_hash: H,
264 ) -> Result<TransactionTrace, ProviderError>
265 where
266 H: AsRef<Felt> + Send + Sync;
267
268 async fn simulate_transactions<B, T, S>(
276 &self,
277 block_id: B,
278 transactions: T,
279 simulation_flags: S,
280 ) -> Result<Vec<SimulatedTransaction>, ProviderError>
281 where
282 B: AsRef<BlockId> + Send + Sync,
283 T: AsRef<[BroadcastedTransaction]> + Send + Sync,
284 S: AsRef<[SimulationFlag]> + Send + Sync;
285
286 async fn trace_block_transactions<B>(
288 &self,
289 block_id: B,
290 ) -> Result<Vec<TransactionTraceWithHash>, ProviderError>
291 where
292 B: AsRef<ConfirmedBlockId> + Send + Sync;
293
294 async fn batch_requests<R>(
297 &self,
298 requests: R,
299 ) -> Result<Vec<ProviderResponseData>, ProviderError>
300 where
301 R: AsRef<[ProviderRequestData]> + Send + Sync;
302
303 async fn estimate_fee_single<R, S, B>(
305 &self,
306 request: R,
307 simulation_flags: S,
308 block_id: B,
309 ) -> Result<FeeEstimate, ProviderError>
310 where
311 R: AsRef<BroadcastedTransaction> + Send + Sync,
312 S: AsRef<[SimulationFlagForEstimateFee]> + Send + Sync,
313 B: AsRef<BlockId> + Send + Sync,
314 {
315 let mut result = self
316 .estimate_fee([request.as_ref().to_owned()], simulation_flags, block_id)
317 .await?;
318
319 if result.len() == 1 {
320 Ok(result.pop().unwrap())
322 } else {
323 Err(ProviderError::ArrayLengthMismatch)
324 }
325 }
326
327 async fn simulate_transaction<B, T, S>(
329 &self,
330 block_id: B,
331 transaction: T,
332 simulation_flags: S,
333 ) -> Result<SimulatedTransaction, ProviderError>
334 where
335 B: AsRef<BlockId> + Send + Sync,
336 T: AsRef<BroadcastedTransaction> + Send + Sync,
337 S: AsRef<[SimulationFlag]> + Send + Sync,
338 {
339 let mut result = self
340 .simulate_transactions(
341 block_id,
342 [transaction.as_ref().to_owned()],
343 simulation_flags,
344 )
345 .await?;
346
347 if result.len() == 1 {
348 Ok(result.pop().unwrap())
350 } else {
351 Err(ProviderError::ArrayLengthMismatch)
352 }
353 }
354}
355
356pub trait ProviderImplError: Error + Debug + Send + Sync {
364 fn as_any(&self) -> &dyn Any;
367}
368
369#[derive(Debug, thiserror::Error)]
380pub enum ProviderError {
381 #[error(transparent)]
383 StarknetError(StarknetError),
384 #[error("Request rate limited")]
386 RateLimited,
387 #[error("Array length mismatch")]
390 ArrayLengthMismatch,
391 #[error("{0}")]
393 Other(Box<dyn ProviderImplError>),
394}
395
396#[derive(Debug, Clone, Serialize)]
398#[serde(untagged)]
399pub enum ProviderRequestData {
400 SpecVersion(SpecVersionRequest),
402 GetBlockWithTxHashes(GetBlockWithTxHashesRequest),
404 GetBlockWithTxs(GetBlockWithTxsRequest),
406 GetBlockWithReceipts(GetBlockWithReceiptsRequest),
408 GetStateUpdate(GetStateUpdateRequest),
410 GetStorageAt(GetStorageAtRequest),
412 GetMessagesStatus(GetMessagesStatusRequest),
414 GetTransactionStatus(GetTransactionStatusRequest),
416 GetTransactionByHash(GetTransactionByHashRequest),
418 GetTransactionByBlockIdAndIndex(GetTransactionByBlockIdAndIndexRequest),
420 GetTransactionReceipt(GetTransactionReceiptRequest),
422 GetClass(GetClassRequest),
424 GetClassHashAt(GetClassHashAtRequest),
426 GetClassAt(GetClassAtRequest),
428 GetBlockTransactionCount(GetBlockTransactionCountRequest),
430 Call(CallRequest),
432 EstimateFee(EstimateFeeRequest),
434 EstimateMessageFee(EstimateMessageFeeRequest),
436 BlockNumber(BlockNumberRequest),
438 BlockHashAndNumber(BlockHashAndNumberRequest),
440 ChainId(ChainIdRequest),
442 Syncing(SyncingRequest),
444 GetEvents(GetEventsRequest),
446 GetNonce(GetNonceRequest),
448 GetStorageProof(GetStorageProofRequest),
450 AddInvokeTransaction(AddInvokeTransactionRequest),
452 AddDeclareTransaction(AddDeclareTransactionRequest),
454 AddDeployAccountTransaction(AddDeployAccountTransactionRequest),
456 TraceTransaction(TraceTransactionRequest),
458 SimulateTransactions(SimulateTransactionsRequest),
460 TraceBlockTransactions(TraceBlockTransactionsRequest),
462 SubscribeNewHeads(SubscribeNewHeadsRequest),
464 SubscribeEvents(SubscribeEventsRequest),
466 SubscribeTransactionStatus(SubscribeTransactionStatusRequest),
468 SubscribeNewTransactionReceipts(SubscribeNewTransactionReceiptsRequest),
470 SubscribeNewTransactions(SubscribeNewTransactionsRequest),
472 Unsubscribe(UnsubscribeRequest),
474}
475
476#[allow(clippy::large_enum_variant)]
478#[derive(Debug, Clone)]
479pub enum ProviderResponseData {
480 SpecVersion(String),
482 GetBlockWithTxHashes(MaybePreConfirmedBlockWithTxHashes),
484 GetBlockWithTxs(MaybePreConfirmedBlockWithTxs),
486 GetBlockWithReceipts(MaybePreConfirmedBlockWithReceipts),
488 GetStateUpdate(MaybePreConfirmedStateUpdate),
490 GetStorageAt(Felt),
492 GetMessagesStatus(Vec<MessageStatus>),
494 GetTransactionStatus(TransactionStatus),
496 GetTransactionByHash(Transaction),
498 GetTransactionByBlockIdAndIndex(Transaction),
500 GetTransactionReceipt(TransactionReceiptWithBlockInfo),
502 GetClass(ContractClass),
504 GetClassHashAt(Felt),
506 GetClassAt(ContractClass),
508 GetBlockTransactionCount(u64),
510 Call(Vec<Felt>),
512 EstimateFee(Vec<FeeEstimate>),
514 EstimateMessageFee(FeeEstimate),
516 BlockNumber(u64),
518 BlockHashAndNumber(BlockHashAndNumber),
520 ChainId(Felt),
522 Syncing(SyncStatusType),
524 GetEvents(EventsPage),
526 GetNonce(Felt),
528 GetStorageProof(StorageProof),
530 AddInvokeTransaction(InvokeTransactionResult),
532 AddDeclareTransaction(DeclareTransactionResult),
534 AddDeployAccountTransaction(DeployAccountTransactionResult),
536 TraceTransaction(TransactionTrace),
538 SimulateTransactions(Vec<SimulatedTransaction>),
540 TraceBlockTransactions(Vec<TransactionTraceWithHash>),
542 SubscribeNewHeads(SubscriptionId),
544 SubscribeEvents(SubscriptionId),
546 SubscribeTransactionStatus(SubscriptionId),
548 SubscribeNewTransactionReceipts(SubscriptionId),
550 SubscribeNewTransactions(SubscriptionId),
552 Unsubscribe(bool),
554}
555
556#[allow(clippy::enum_variant_names)]
558#[derive(Debug, Clone, Serialize)]
559#[serde(untagged)]
560pub enum StreamUpdateData {
561 SubscriptionNewHeads(SubscriptionNewHeadsRequest),
563 SubscriptionEvents(SubscriptionEventsRequest),
565 SubscriptionTransactionStatus(SubscriptionTransactionStatusRequest),
567 SubscriptionNewTransactionReceipts(SubscriptionNewTransactionReceiptsRequest),
569 SubscriptionNewTransaction(SubscriptionNewTransactionRequest),
571 SubscriptionReorg(SubscriptionReorgRequest),
573}
574
575impl StreamUpdateData {
576 pub fn subscription_id(&self) -> &SubscriptionId {
578 match self {
579 Self::SubscriptionNewHeads(update) => &update.subscription_id,
580 Self::SubscriptionEvents(update) => &update.subscription_id,
581 Self::SubscriptionTransactionStatus(update) => &update.subscription_id,
582 Self::SubscriptionNewTransactionReceipts(update) => &update.subscription_id,
583 Self::SubscriptionNewTransaction(update) => &update.subscription_id,
584 Self::SubscriptionReorg(update) => &update.subscription_id,
585 }
586 }
587}