starknet_gateway/
provider.rs

1use async_trait::async_trait;
2use auto_impl::auto_impl;
3use starknet_core::types::{
4    BlockHashAndNumber, BlockId, BroadcastedDeclareTransaction,
5    BroadcastedDeployAccountTransaction, BroadcastedInvokeTransaction, BroadcastedTransaction,
6    ContractClass, DeclareTransactionResult, DeployAccountTransactionResult, EventFilter,
7    EventsPage, FeeEstimate, FieldElement, FunctionCall, InvokeTransactionResult,
8    MaybePendingBlockWithTxHashes, MaybePendingBlockWithTxs, MaybePendingStateUpdate,
9    MaybePendingTransactionReceipt, MsgFromL1, StarknetError, SyncStatusType, Transaction,
10};
11use std::error::Error;
12
13#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
14#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
15#[auto_impl(&, Box, Arc)]
16pub trait Provider {
17    type Error: Error + Send + Sync;
18
19    /// Get block information with transaction hashes given the block id
20    async fn get_block_with_tx_hashes<B>(
21        &self,
22        block_id: B,
23    ) -> Result<MaybePendingBlockWithTxHashes, ProviderError<Self::Error>>
24    where
25        B: AsRef<BlockId> + Send + Sync;
26
27    /// Get block information with full transactions given the block id
28    async fn get_block_with_txs<B>(
29        &self,
30        block_id: B,
31    ) -> Result<MaybePendingBlockWithTxs, ProviderError<Self::Error>>
32    where
33        B: AsRef<BlockId> + Send + Sync;
34
35    /// Get the information about the result of executing the requested block
36    async fn get_state_update<B>(
37        &self,
38        block_id: B,
39    ) -> Result<MaybePendingStateUpdate, ProviderError<Self::Error>>
40    where
41        B: AsRef<BlockId> + Send + Sync;
42
43    /// Get the value of the storage at the given address and key
44    async fn get_storage_at<A, K, B>(
45        &self,
46        contract_address: A,
47        key: K,
48        block_id: B,
49    ) -> Result<FieldElement, ProviderError<Self::Error>>
50    where
51        A: AsRef<FieldElement> + Send + Sync,
52        K: AsRef<FieldElement> + Send + Sync,
53        B: AsRef<BlockId> + Send + Sync;
54
55    /// Get the details and status of a submitted transaction
56    async fn get_transaction_by_hash<H>(
57        &self,
58        transaction_hash: H,
59    ) -> Result<Transaction, ProviderError<Self::Error>>
60    where
61        H: AsRef<FieldElement> + Send + Sync;
62
63    /// Get the details of a transaction by a given block id and index
64    async fn get_transaction_by_block_id_and_index<B>(
65        &self,
66        block_id: B,
67        index: u64,
68    ) -> Result<Transaction, ProviderError<Self::Error>>
69    where
70        B: AsRef<BlockId> + Send + Sync;
71
72    /// Get the details of a transaction by a given block number and index
73    async fn get_transaction_receipt<H>(
74        &self,
75        transaction_hash: H,
76    ) -> Result<MaybePendingTransactionReceipt, ProviderError<Self::Error>>
77    where
78        H: AsRef<FieldElement> + Send + Sync;
79
80    /// Get the contract class definition in the given block associated with the given hash
81    async fn get_class<B, H>(
82        &self,
83        block_id: B,
84        class_hash: H,
85    ) -> Result<ContractClass, ProviderError<Self::Error>>
86    where
87        B: AsRef<BlockId> + Send + Sync,
88        H: AsRef<FieldElement> + Send + Sync;
89
90    /// Get the contract class hash in the given block for the contract deployed at the given address
91    async fn get_class_hash_at<B, A>(
92        &self,
93        block_id: B,
94        contract_address: A,
95    ) -> Result<FieldElement, ProviderError<Self::Error>>
96    where
97        B: AsRef<BlockId> + Send + Sync,
98        A: AsRef<FieldElement> + Send + Sync;
99
100    /// Get the contract class definition in the given block at the given address
101    async fn get_class_at<B, A>(
102        &self,
103        block_id: B,
104        contract_address: A,
105    ) -> Result<ContractClass, ProviderError<Self::Error>>
106    where
107        B: AsRef<BlockId> + Send + Sync,
108        A: AsRef<FieldElement> + Send + Sync;
109
110    /// Get the number of transactions in a block given a block id
111    async fn get_block_transaction_count<B>(
112        &self,
113        block_id: B,
114    ) -> Result<u64, ProviderError<Self::Error>>
115    where
116        B: AsRef<BlockId> + Send + Sync;
117
118    /// Call a starknet function without creating a Starknet transaction
119    async fn call<R, B>(
120        &self,
121        request: R,
122        block_id: B,
123    ) -> Result<Vec<FieldElement>, ProviderError<Self::Error>>
124    where
125        R: AsRef<FunctionCall> + Send + Sync,
126        B: AsRef<BlockId> + Send + Sync;
127
128    /// Estimate the fee for a given Starknet transaction
129    async fn estimate_fee<R, B>(
130        &self,
131        request: R,
132        block_id: B,
133    ) -> Result<Vec<FeeEstimate>, ProviderError<Self::Error>>
134    where
135        R: AsRef<[BroadcastedTransaction]> + Send + Sync,
136        B: AsRef<BlockId> + Send + Sync;
137
138    async fn estimate_message_fee<M, B>(
139        &self,
140        message: M,
141        block_id: B,
142    ) -> Result<FeeEstimate, ProviderError<Self::Error>>
143    where
144        M: AsRef<MsgFromL1> + Send + Sync,
145        B: AsRef<BlockId> + Send + Sync;
146
147    /// Get the most recent accepted block number
148    async fn block_number(&self) -> Result<u64, ProviderError<Self::Error>>;
149
150    /// Get the most recent accepted block hash and number
151    async fn block_hash_and_number(&self)
152        -> Result<BlockHashAndNumber, ProviderError<Self::Error>>;
153
154    /// Return the currently configured Starknet chain id
155    async fn chain_id(&self) -> Result<FieldElement, ProviderError<Self::Error>>;
156
157    /// Returns the transactions in the transaction pool, recognized by this sequencer
158    async fn pending_transactions(&self) -> Result<Vec<Transaction>, ProviderError<Self::Error>>;
159
160    /// Returns an object about the sync status, or false if the node is not synching
161    async fn syncing(&self) -> Result<SyncStatusType, ProviderError<Self::Error>>;
162
163    /// Returns all events matching the given filter
164    async fn get_events(
165        &self,
166        filter: EventFilter,
167        continuation_token: Option<String>,
168        chunk_size: u64,
169    ) -> Result<EventsPage, ProviderError<Self::Error>>;
170
171    /// Get the nonce associated with the given address in the given block
172    async fn get_nonce<B, A>(
173        &self,
174        block_id: B,
175        contract_address: A,
176    ) -> Result<FieldElement, ProviderError<Self::Error>>
177    where
178        B: AsRef<BlockId> + Send + Sync,
179        A: AsRef<FieldElement> + Send + Sync;
180
181    /// Submit a new transaction to be added to the chain
182    async fn add_invoke_transaction<I>(
183        &self,
184        invoke_transaction: I,
185    ) -> Result<InvokeTransactionResult, ProviderError<Self::Error>>
186    where
187        I: AsRef<BroadcastedInvokeTransaction> + Send + Sync;
188
189    /// Submit a new transaction to be added to the chain
190    async fn add_declare_transaction<D>(
191        &self,
192        declare_transaction: D,
193    ) -> Result<DeclareTransactionResult, ProviderError<Self::Error>>
194    where
195        D: AsRef<BroadcastedDeclareTransaction> + Send + Sync;
196
197    /// Submit a new deploy account transaction
198    async fn add_deploy_account_transaction<D>(
199        &self,
200        deploy_account_transaction: D,
201    ) -> Result<DeployAccountTransactionResult, ProviderError<Self::Error>>
202    where
203        D: AsRef<BroadcastedDeployAccountTransaction> + Send + Sync;
204
205    /// Same as [estimate_fee], but only with one estimate.
206    async fn estimate_fee_single<R, B>(
207        &self,
208        request: R,
209        block_id: B,
210    ) -> Result<FeeEstimate, ProviderError<Self::Error>>
211    where
212        R: AsRef<BroadcastedTransaction> + Send + Sync,
213        B: AsRef<BlockId> + Send + Sync,
214    {
215        let mut result = self
216            .estimate_fee([request.as_ref().to_owned()], block_id)
217            .await?;
218
219        if result.len() == 1 {
220            // Unwrapping here is safe becuase we already checked length
221            Ok(result.pop().unwrap())
222        } else {
223            Err(ProviderError::ArrayLengthMismatch)
224        }
225    }
226}
227
228#[derive(Debug, thiserror::Error)]
229pub enum ProviderError<E> {
230    #[error(transparent)]
231    StarknetError(StarknetErrorWithMessage),
232    #[error("Request rate limited")]
233    RateLimited,
234    #[error("Array length mismatch")]
235    ArrayLengthMismatch,
236    #[error(transparent)]
237    Other(E),
238}
239
240#[derive(Debug, thiserror::Error)]
241#[error("code={code}, message=\"{message}\"")]
242pub struct StarknetErrorWithMessage {
243    pub code: MaybeUnknownErrorCode,
244    pub message: String,
245}
246
247#[derive(Debug)]
248pub enum MaybeUnknownErrorCode {
249    Known(StarknetError),
250    Unknown(i64),
251}
252
253impl core::fmt::Display for MaybeUnknownErrorCode {
254    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
255        match self {
256            MaybeUnknownErrorCode::Known(code) => write!(f, "{}", code),
257            MaybeUnknownErrorCode::Unknown(code) => write!(f, "{}", code),
258        }
259    }
260}