starknet_providers/
provider.rs

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, MaybePendingBlockWithReceipts, MaybePendingBlockWithTxHashes,
10    MaybePendingBlockWithTxs, MaybePendingStateUpdate, MessageWithStatus, MsgFromL1,
11    SimulatedTransaction, SimulationFlag, SimulationFlagForEstimateFee, StarknetError,
12    StorageProof, SyncStatusType, Transaction, TransactionReceiptWithBlockInfo, TransactionStatus,
13    TransactionTrace, TransactionTraceWithHash,
14};
15use std::{any::Any, error::Error, fmt::Debug};
16
17/// A generic interface for any type allowing communication with a Starknet network.
18///
19/// Historically, the only official way to access the network is through the sequencer gateway,
20/// implemented by [`SequencerGatewayProvider`](crate::sequencer::SequencerGatewayProvider), which
21/// has since been deprecated. Currently, the recommended way of accessing the network is via the
22/// JSON-RPC specification, implemented with [`JsonRpcClient`](crate::jsonrpc::JsonRpcClient).
23///
24/// The legacy [`SequencerGatewayProvider`](crate::sequencer::SequencerGatewayProvider) still
25/// implements this trait for backward compatibility reasons, but most of its methods no longer work
26/// in practice, as public sequencer servers have generally block access to most methods.
27#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
28#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
29#[auto_impl(&, Box, Arc)]
30pub trait Provider {
31    /// Returns the version of the Starknet JSON-RPC specification being used.
32    async fn spec_version(&self) -> Result<String, ProviderError>;
33
34    /// Gets block information with transaction hashes given the block id.
35    async fn get_block_with_tx_hashes<B>(
36        &self,
37        block_id: B,
38    ) -> Result<MaybePendingBlockWithTxHashes, ProviderError>
39    where
40        B: AsRef<BlockId> + Send + Sync;
41
42    /// Gets block information with full transactions given the block id.
43    async fn get_block_with_txs<B>(
44        &self,
45        block_id: B,
46    ) -> Result<MaybePendingBlockWithTxs, ProviderError>
47    where
48        B: AsRef<BlockId> + Send + Sync;
49
50    /// Gets block information with full transactions and receipts given the block id.
51    async fn get_block_with_receipts<B>(
52        &self,
53        block_id: B,
54    ) -> Result<MaybePendingBlockWithReceipts, ProviderError>
55    where
56        B: AsRef<BlockId> + Send + Sync;
57
58    /// Gets the information about the result of executing the requested block.
59    async fn get_state_update<B>(
60        &self,
61        block_id: B,
62    ) -> Result<MaybePendingStateUpdate, ProviderError>
63    where
64        B: AsRef<BlockId> + Send + Sync;
65
66    /// Gets the value of the storage at the given address and key.
67    async fn get_storage_at<A, K, B>(
68        &self,
69        contract_address: A,
70        key: K,
71        block_id: B,
72    ) -> Result<Felt, ProviderError>
73    where
74        A: AsRef<Felt> + Send + Sync,
75        K: AsRef<Felt> + Send + Sync,
76        B: AsRef<BlockId> + Send + Sync;
77
78    /// Given an l1 tx hash, returns the associated l1_handler tx hashes and statuses for all L1 ->
79    /// L2 messages sent by the l1 transaction, ordered by the l1 tx sending order
80    async fn get_messages_status(
81        &self,
82        transaction_hash: Hash256,
83    ) -> Result<Vec<MessageWithStatus>, ProviderError>;
84
85    /// Gets the transaction status (possibly reflecting that the tx is still in the mempool, or
86    /// dropped from it).
87    async fn get_transaction_status<H>(
88        &self,
89        transaction_hash: H,
90    ) -> Result<TransactionStatus, ProviderError>
91    where
92        H: AsRef<Felt> + Send + Sync;
93
94    /// Gets the details and status of a submitted transaction.
95    async fn get_transaction_by_hash<H>(
96        &self,
97        transaction_hash: H,
98    ) -> Result<Transaction, ProviderError>
99    where
100        H: AsRef<Felt> + Send + Sync;
101
102    /// Gets the details of a transaction by a given block id and index.
103    async fn get_transaction_by_block_id_and_index<B>(
104        &self,
105        block_id: B,
106        index: u64,
107    ) -> Result<Transaction, ProviderError>
108    where
109        B: AsRef<BlockId> + Send + Sync;
110
111    /// Gets the details of a transaction by a given block number and index.
112    async fn get_transaction_receipt<H>(
113        &self,
114        transaction_hash: H,
115    ) -> Result<TransactionReceiptWithBlockInfo, ProviderError>
116    where
117        H: AsRef<Felt> + Send + Sync;
118
119    /// Gets the contract class definition in the given block associated with the given hash.
120    async fn get_class<B, H>(
121        &self,
122        block_id: B,
123        class_hash: H,
124    ) -> Result<ContractClass, ProviderError>
125    where
126        B: AsRef<BlockId> + Send + Sync,
127        H: AsRef<Felt> + Send + Sync;
128
129    /// Gets the contract class hash in the given block for the contract deployed at the given
130    /// address.
131    async fn get_class_hash_at<B, A>(
132        &self,
133        block_id: B,
134        contract_address: A,
135    ) -> Result<Felt, ProviderError>
136    where
137        B: AsRef<BlockId> + Send + Sync,
138        A: AsRef<Felt> + Send + Sync;
139
140    /// Gets the contract class definition in the given block at the given address.
141    async fn get_class_at<B, A>(
142        &self,
143        block_id: B,
144        contract_address: A,
145    ) -> Result<ContractClass, ProviderError>
146    where
147        B: AsRef<BlockId> + Send + Sync,
148        A: AsRef<Felt> + Send + Sync;
149
150    /// Gets the number of transactions in a block given a block id.
151    async fn get_block_transaction_count<B>(&self, block_id: B) -> Result<u64, ProviderError>
152    where
153        B: AsRef<BlockId> + Send + Sync;
154
155    /// Calls a starknet function without creating a Starknet transaction.
156    async fn call<R, B>(&self, request: R, block_id: B) -> Result<Vec<Felt>, ProviderError>
157    where
158        R: AsRef<FunctionCall> + Send + Sync,
159        B: AsRef<BlockId> + Send + Sync;
160
161    /// Estimates the fee for a given Starknet transaction.
162    async fn estimate_fee<R, S, B>(
163        &self,
164        request: R,
165        simulation_flags: S,
166        block_id: B,
167    ) -> Result<Vec<FeeEstimate>, ProviderError>
168    where
169        R: AsRef<[BroadcastedTransaction]> + Send + Sync,
170        S: AsRef<[SimulationFlagForEstimateFee]> + Send + Sync,
171        B: AsRef<BlockId> + Send + Sync;
172
173    /// Estimates the fee for sending an L1-to-L2 message.
174    async fn estimate_message_fee<M, B>(
175        &self,
176        message: M,
177        block_id: B,
178    ) -> Result<FeeEstimate, ProviderError>
179    where
180        M: AsRef<MsgFromL1> + Send + Sync,
181        B: AsRef<BlockId> + Send + Sync;
182
183    /// Gets the most recent accepted block number.
184    async fn block_number(&self) -> Result<u64, ProviderError>;
185
186    /// Gets the most recent accepted block hash and number.
187    async fn block_hash_and_number(&self) -> Result<BlockHashAndNumber, ProviderError>;
188
189    /// Returns the currently configured Starknet chain id.
190    async fn chain_id(&self) -> Result<Felt, ProviderError>;
191
192    /// Returns an object about the sync status, or false if the node is not synching.
193    async fn syncing(&self) -> Result<SyncStatusType, ProviderError>;
194
195    /// Returns all events matching the given filter.
196    async fn get_events(
197        &self,
198        filter: EventFilter,
199        continuation_token: Option<String>,
200        chunk_size: u64,
201    ) -> Result<EventsPage, ProviderError>;
202
203    /// Gets the nonce associated with the given address in the given block.
204    async fn get_nonce<B, A>(
205        &self,
206        block_id: B,
207        contract_address: A,
208    ) -> Result<Felt, ProviderError>
209    where
210        B: AsRef<BlockId> + Send + Sync,
211        A: AsRef<Felt> + Send + Sync;
212
213    /// Get merkle paths in one of the state tries: global state, classes, individual contract.
214    /// A single request can query for any mix of the three types of storage proofs (classes,
215    /// contracts, and storage).
216    async fn get_storage_proof<B, H, A, K>(
217        &self,
218        block_id: B,
219        class_hashes: H,
220        contract_addresses: A,
221        contracts_storage_keys: K,
222    ) -> Result<StorageProof, ProviderError>
223    where
224        B: AsRef<ConfirmedBlockId> + Send + Sync,
225        H: AsRef<[Felt]> + Send + Sync,
226        A: AsRef<[Felt]> + Send + Sync,
227        K: AsRef<[ContractStorageKeys]> + Send + Sync;
228
229    /// Submits a new transaction to be added to the chain.
230    async fn add_invoke_transaction<I>(
231        &self,
232        invoke_transaction: I,
233    ) -> Result<InvokeTransactionResult, ProviderError>
234    where
235        I: AsRef<BroadcastedInvokeTransaction> + Send + Sync;
236
237    /// Submits a new transaction to be added to the chain.
238    async fn add_declare_transaction<D>(
239        &self,
240        declare_transaction: D,
241    ) -> Result<DeclareTransactionResult, ProviderError>
242    where
243        D: AsRef<BroadcastedDeclareTransaction> + Send + Sync;
244
245    /// Submits a new deploy account transaction.
246    async fn add_deploy_account_transaction<D>(
247        &self,
248        deploy_account_transaction: D,
249    ) -> Result<DeployAccountTransactionResult, ProviderError>
250    where
251        D: AsRef<BroadcastedDeployAccountTransaction> + Send + Sync;
252
253    /// For a given executed transaction, returns the trace of its execution, including internal
254    /// calls.
255    async fn trace_transaction<H>(
256        &self,
257        transaction_hash: H,
258    ) -> Result<TransactionTrace, ProviderError>
259    where
260        H: AsRef<Felt> + Send + Sync;
261
262    /// Simulates a given sequence of transactions on the requested state, and generate the
263    /// execution traces. Note that some of the transactions may revert, in which case no error is
264    /// thrown, but revert details can be seen on the returned trace object.
265    ///
266    /// Note that some of the transactions may revert, this will be reflected by the `revert_error`
267    /// property in the trace. Other types of failures (e.g. unexpected error or failure in the
268    /// validation phase) will result in `TRANSACTION_EXECUTION_ERROR`.
269    async fn simulate_transactions<B, T, S>(
270        &self,
271        block_id: B,
272        transactions: T,
273        simulation_flags: S,
274    ) -> Result<Vec<SimulatedTransaction>, ProviderError>
275    where
276        B: AsRef<BlockId> + Send + Sync,
277        T: AsRef<[BroadcastedTransaction]> + Send + Sync,
278        S: AsRef<[SimulationFlag]> + Send + Sync;
279
280    /// Retrieves traces for all transactions in the given block.
281    async fn trace_block_transactions<B>(
282        &self,
283        block_id: B,
284    ) -> Result<Vec<TransactionTraceWithHash>, ProviderError>
285    where
286        B: AsRef<BlockId> + Send + Sync;
287
288    /// Sends multiple requests in parallel. The function call fails if any of the requests fails.
289    /// Implementations must guarantee that responses follow the exact order as the requests.
290    async fn batch_requests<R>(
291        &self,
292        requests: R,
293    ) -> Result<Vec<ProviderResponseData>, ProviderError>
294    where
295        R: AsRef<[ProviderRequestData]> + Send + Sync;
296
297    /// Same as [`estimate_fee`](fn.estimate_fee), but only with one estimate.
298    async fn estimate_fee_single<R, S, B>(
299        &self,
300        request: R,
301        simulation_flags: S,
302        block_id: B,
303    ) -> Result<FeeEstimate, ProviderError>
304    where
305        R: AsRef<BroadcastedTransaction> + Send + Sync,
306        S: AsRef<[SimulationFlagForEstimateFee]> + Send + Sync,
307        B: AsRef<BlockId> + Send + Sync,
308    {
309        let mut result = self
310            .estimate_fee([request.as_ref().to_owned()], simulation_flags, block_id)
311            .await?;
312
313        if result.len() == 1 {
314            // Unwrapping here is safe becuase we already checked length
315            Ok(result.pop().unwrap())
316        } else {
317            Err(ProviderError::ArrayLengthMismatch)
318        }
319    }
320
321    /// Same as [`simulate_transactions`](fn.simulate_transactions), but only with one simulation.
322    async fn simulate_transaction<B, T, S>(
323        &self,
324        block_id: B,
325        transaction: T,
326        simulation_flags: S,
327    ) -> Result<SimulatedTransaction, ProviderError>
328    where
329        B: AsRef<BlockId> + Send + Sync,
330        T: AsRef<BroadcastedTransaction> + Send + Sync,
331        S: AsRef<[SimulationFlag]> + Send + Sync,
332    {
333        let mut result = self
334            .simulate_transactions(
335                block_id,
336                [transaction.as_ref().to_owned()],
337                simulation_flags,
338            )
339            .await?;
340
341        if result.len() == 1 {
342            // Unwrapping here is safe becuase we already checked length
343            Ok(result.pop().unwrap())
344        } else {
345            Err(ProviderError::ArrayLengthMismatch)
346        }
347    }
348}
349
350/// Trait for implementation-specific error type. These errors are irrelevant in most cases,
351/// assuming that users typically care more about the specifics of RPC errors instead of the
352/// underlying transport. Therefore, it makes little sense to bloat [`ProviderError`] with a generic
353/// parameter just for these errors. Instead, they're erased to this trait object.
354///
355/// This trait is used instead of a plain [`std::error::Error`] to allow downcasting, in case access
356/// to the specific error type is indeed desired. This is achieved with the `as_any()` method.
357pub trait ProviderImplError: Error + Debug + Send + Sync {
358    fn as_any(&self) -> &dyn Any;
359}
360
361/// Errors using any [`Provider`] implementation. This type is deliberately not made generic such
362/// that:
363///
364/// - the [`Provider`] trait itself can be boxed;
365/// - error handling is easier.
366///
367/// As a downside, the [`Other`](ProviderError::Other) variant contains a boxed implementation-
368/// specific error. It's generally expected that users of [`Provider`] would not need to care about
369/// these errors, but in the case where they do, it's slightly harder to access than if generics are
370/// used instead.
371#[derive(Debug, thiserror::Error)]
372pub enum ProviderError {
373    /// A Starknet-related error, usually regarding the state or transaction.
374    #[error(transparent)]
375    StarknetError(StarknetError),
376    /// The request fails as the client is rate-limited.
377    #[error("Request rate limited")]
378    RateLimited,
379    /// When estimating fees for or simulating a single transaction, the server unexpectedly returns
380    /// data for zero or more than one transactions.
381    #[error("Array length mismatch")]
382    ArrayLengthMismatch,
383    /// Boxed implementation-specific errors.
384    #[error("{0}")]
385    Other(Box<dyn ProviderImplError>),
386}
387
388/// Typed request data for [`Provider`] requests.
389#[derive(Debug, Clone, Serialize)]
390#[serde(untagged)]
391pub enum ProviderRequestData {
392    /// Request data for `starknet_specVersion`.
393    SpecVersion(SpecVersionRequest),
394    /// Request data for `starknet_getBlockWithTxHashes`.
395    GetBlockWithTxHashes(GetBlockWithTxHashesRequest),
396    /// Request data for `starknet_getBlockWithTxs`.
397    GetBlockWithTxs(GetBlockWithTxsRequest),
398    /// Request data for `starknet_getBlockWithReceipts`.
399    GetBlockWithReceipts(GetBlockWithReceiptsRequest),
400    /// Request data for `starknet_getStateUpdate`.
401    GetStateUpdate(GetStateUpdateRequest),
402    /// Request data for `starknet_getStorageAt`.
403    GetStorageAt(GetStorageAtRequest),
404    /// Request data for `starknet_getMessagesStatus`.
405    GetMessagesStatus(GetMessagesStatusRequest),
406    /// Request data for `starknet_getTransactionStatus`.
407    GetTransactionStatus(GetTransactionStatusRequest),
408    /// Request data for `starknet_getTransactionByHash`.
409    GetTransactionByHash(GetTransactionByHashRequest),
410    /// Request data for `starknet_getTransactionByBlockIdAndIndex`.
411    GetTransactionByBlockIdAndIndex(GetTransactionByBlockIdAndIndexRequest),
412    /// Request data for `starknet_getTransactionReceipt`.
413    GetTransactionReceipt(GetTransactionReceiptRequest),
414    /// Request data for `starknet_getClass`.
415    GetClass(GetClassRequest),
416    /// Request data for `starknet_getClassHashAt`.
417    GetClassHashAt(GetClassHashAtRequest),
418    /// Request data for `starknet_getClassAt`.
419    GetClassAt(GetClassAtRequest),
420    /// Request data for `starknet_getBlockTransactionCount`.
421    GetBlockTransactionCount(GetBlockTransactionCountRequest),
422    /// Request data for `starknet_call`.
423    Call(CallRequest),
424    /// Request data for `starknet_estimateFee`.
425    EstimateFee(EstimateFeeRequest),
426    /// Request data for `starknet_estimateMessageFee`.
427    EstimateMessageFee(EstimateMessageFeeRequest),
428    /// Request data for `starknet_blockNumber`.
429    BlockNumber(BlockNumberRequest),
430    /// Request data for `starknet_blockHashAndNumber`.
431    BlockHashAndNumber(BlockHashAndNumberRequest),
432    /// Request data for `starknet_chainId`.
433    ChainId(ChainIdRequest),
434    /// Request data for `starknet_syncing`.
435    Syncing(SyncingRequest),
436    /// Request data for `starknet_getEvents`.
437    GetEvents(GetEventsRequest),
438    /// Request data for `starknet_getNonce`.
439    GetNonce(GetNonceRequest),
440    /// Request data for `starknet_getStorageProof`.
441    GetStorageProof(GetStorageProofRequest),
442    /// Request data for `starknet_addInvokeTransaction`.
443    AddInvokeTransaction(AddInvokeTransactionRequest),
444    /// Request data for `starknet_addDeclareTransaction`.
445    AddDeclareTransaction(AddDeclareTransactionRequest),
446    /// Request data for `starknet_addDeployAccountTransaction`.
447    AddDeployAccountTransaction(AddDeployAccountTransactionRequest),
448    /// Request data for `starknet_traceTransaction`.
449    TraceTransaction(TraceTransactionRequest),
450    /// Request data for `starknet_simulateTransactions`.
451    SimulateTransactions(SimulateTransactionsRequest),
452    /// Request data for `starknet_traceBlockTransactions`.
453    TraceBlockTransactions(TraceBlockTransactionsRequest),
454}
455
456/// Typed response data for [`Provider`] responses.
457#[allow(clippy::large_enum_variant)]
458#[derive(Debug, Clone)]
459pub enum ProviderResponseData {
460    /// Response data for `starknet_specVersion`.
461    SpecVersion(String),
462    /// Response data for `starknet_getBlockWithTxHashes`.
463    GetBlockWithTxHashes(MaybePendingBlockWithTxHashes),
464    /// Response data for `starknet_getBlockWithTxs`.
465    GetBlockWithTxs(MaybePendingBlockWithTxs),
466    /// Response data for `starknet_getBlockWithReceipts`.
467    GetBlockWithReceipts(MaybePendingBlockWithReceipts),
468    /// Response data for `starknet_getStateUpdate`.
469    GetStateUpdate(MaybePendingStateUpdate),
470    /// Response data for `starknet_getStorageAt`.
471    GetStorageAt(Felt),
472    /// Response data for `starknet_getMessagesStatus`.
473    GetMessagesStatus(Vec<MessageWithStatus>),
474    /// Response data for `starknet_getTransactionStatus`.
475    GetTransactionStatus(TransactionStatus),
476    /// Response data for `starknet_getTransactionByHash`.
477    GetTransactionByHash(Transaction),
478    /// Response data for `starknet_getTransactionByBlockIdAndIndex`.
479    GetTransactionByBlockIdAndIndex(Transaction),
480    /// Response data for `starknet_getTransactionReceipt`.
481    GetTransactionReceipt(TransactionReceiptWithBlockInfo),
482    /// Response data for `starknet_getClass`.
483    GetClass(ContractClass),
484    /// Response data for `starknet_getClassHashAt`.
485    GetClassHashAt(Felt),
486    /// Response data for `starknet_getClassAt`.
487    GetClassAt(ContractClass),
488    /// Response data for `starknet_getBlockTransactionCount`.
489    GetBlockTransactionCount(u64),
490    /// Response data for `starknet_call`.
491    Call(Vec<Felt>),
492    /// Response data for `starknet_estimateFee`.
493    EstimateFee(Vec<FeeEstimate>),
494    /// Response data for `starknet_estimateMessageFee`.
495    EstimateMessageFee(FeeEstimate),
496    /// Response data for `starknet_blockNumber`.
497    BlockNumber(u64),
498    /// Response data for `starknet_blockHashAndNumber`.
499    BlockHashAndNumber(BlockHashAndNumber),
500    /// Response data for `starknet_chainId`.
501    ChainId(Felt),
502    /// Response data for `starknet_syncing`.
503    Syncing(SyncStatusType),
504    /// Response data for `starknet_getEvents`.
505    GetEvents(EventsPage),
506    /// Response data for `starknet_getNonce`.
507    GetNonce(Felt),
508    /// Response data for `starknet_getStorageProof`.
509    GetStorageProof(StorageProof),
510    /// Response data for `starknet_addInvokeTransaction`.
511    AddInvokeTransaction(InvokeTransactionResult),
512    /// Response data for `starknet_addDeclareTransaction`.
513    AddDeclareTransaction(DeclareTransactionResult),
514    /// Response data for `starknet_addDeployAccountTransaction`.
515    AddDeployAccountTransaction(DeployAccountTransactionResult),
516    /// Response data for `starknet_traceTransaction`.
517    TraceTransaction(TransactionTrace),
518    /// Response data for `starknet_simulateTransactions`.
519    SimulateTransactions(Vec<SimulatedTransaction>),
520    /// Response data for `starknet_traceBlockTransactions`.
521    TraceBlockTransactions(Vec<TransactionTraceWithHash>),
522}