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 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 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 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 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 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 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 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 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 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 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 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 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 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 async fn block_number(&self) -> Result<u64, ProviderError<Self::Error>>;
149
150 async fn block_hash_and_number(&self)
152 -> Result<BlockHashAndNumber, ProviderError<Self::Error>>;
153
154 async fn chain_id(&self) -> Result<FieldElement, ProviderError<Self::Error>>;
156
157 async fn pending_transactions(&self) -> Result<Vec<Transaction>, ProviderError<Self::Error>>;
159
160 async fn syncing(&self) -> Result<SyncStatusType, ProviderError<Self::Error>>;
162
163 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 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 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 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 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 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 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}