1use std::{fmt::Display, future::Future, pin::Pin};
2
3use crossbeam_channel::TrySendError;
4use jsonrpc_core::{Error, Result};
5use serde::Serialize;
6use serde_json::json;
7use solana_client::{client_error::ClientError, rpc_request::TokenAccountsFilter};
8use solana_pubkey::Pubkey;
9use solana_sdk::slot_history::Slot;
10use solana_transaction_status::EncodeError;
11
12pub type SurfpoolResult<T> = std::result::Result<T, SurfpoolError>;
13
14#[derive(Debug, Clone)]
15pub struct SurfpoolError(Error);
16
17impl From<SurfpoolError> for String {
18 fn from(e: SurfpoolError) -> Self {
19 e.0.to_string()
20 }
21}
22
23impl From<SurfpoolError> for Error {
24 fn from(e: SurfpoolError) -> Self {
25 e.0
26 }
27}
28
29impl From<EncodeError> for SurfpoolError {
30 fn from(e: EncodeError) -> Self {
31 let mut error = Error::internal_error();
32 error.data = Some(json!(format!(
33 "Transaction encoding error: {}",
34 e.to_string()
35 )));
36 Self(error)
37 }
38}
39
40impl std::error::Error for SurfpoolError {}
41
42impl std::fmt::Display for SurfpoolError {
43 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
44 let Error {
45 code,
46 message,
47 data,
48 } = &self.0;
49
50 let core = if code.description().eq(message) {
51 code.description()
52 } else {
53 format!("{}: {}", code.description(), message)
54 };
55
56 if let Some(data_value) = data {
57 write!(f, "{}: {}", core, data_value.to_string().as_str())
58 } else {
59 write!(f, "{}", core)
60 }
61 }
62}
63
64impl<T> From<SurfpoolError> for Pin<Box<dyn Future<Output = Result<T>> + Send>> {
65 fn from(e: SurfpoolError) -> Self {
66 Box::pin(async move { Err(e.into()) })
67 }
68}
69
70impl<T> From<TrySendError<T>> for SurfpoolError {
71 fn from(val: TrySendError<T>) -> Self {
72 SurfpoolError::from_try_send_error(val)
73 }
74}
75
76impl From<solana_client::client_error::ClientError> for SurfpoolError {
77 fn from(e: solana_client::client_error::ClientError) -> Self {
78 SurfpoolError::client_error(e)
79 }
80}
81
82impl SurfpoolError {
83 pub fn from_try_send_error<T>(e: TrySendError<T>) -> Self {
84 let mut error = Error::internal_error();
85 error.data = Some(json!(format!(
86 "Failed to send command on channel: {}",
87 e.to_string()
88 )));
89 Self(error)
90 }
91
92 pub fn client_error(e: solana_client::client_error::ClientError) -> Self {
93 let mut error = Error::internal_error();
94 error.data = Some(json!(format!("Solana RPC client error: {}", e.to_string())));
95 Self(error)
96 }
97
98 pub fn no_locker() -> Self {
99 let mut error = Error::internal_error();
100 error.data = Some(json!("Failed to access internal SVM state"));
101 Self(error)
102 }
103
104 pub fn set_account<T>(pubkey: Pubkey, e: T) -> Self
105 where
106 T: ToString,
107 {
108 let mut error = Error::internal_error();
109 error.data = Some(json!(format!(
110 "Failed to set account {}: {}",
111 pubkey,
112 e.to_string()
113 )));
114 Self(error)
115 }
116 pub fn get_account<T>(pubkey: Pubkey, e: T) -> Self
117 where
118 T: ToString,
119 {
120 let mut error = Error::internal_error();
121 error.data = Some(json!(format!(
122 "Failed to fetch account {} from remote: {}",
123 pubkey,
124 e.to_string()
125 )));
126 Self(error)
127 }
128
129 pub fn get_token_accounts<T>(owner: Pubkey, filter: &TokenAccountsFilter, e: T) -> Self
130 where
131 T: ToString,
132 {
133 let mut error = Error::internal_error();
134 error.data = Some(json!(format!(
135 "Failed to get token accounts by owner {owner} for {}: {}",
136 match filter {
137 TokenAccountsFilter::ProgramId(token_program) => format!("program {token_program}"),
138 TokenAccountsFilter::Mint(mint) => format!("mint {mint}"),
139 },
140 e.to_string()
141 )));
142 Self(error)
143 }
144
145 pub fn get_token_accounts_by_delegate_error<T>(
146 delegate: Pubkey,
147 filter: &TokenAccountsFilter,
148 e: T,
149 ) -> Self
150 where
151 T: ToString,
152 {
153 let mut error = Error::internal_error();
154
155 let filter_description = match filter {
156 TokenAccountsFilter::ProgramId(program_id) => {
157 let program_name = if *program_id == spl_token::ID {
158 "SPL Token program"
159 } else if *program_id == spl_token_2022::ID {
160 "Token 2022 program"
161 } else {
162 "custom token program"
163 };
164 format!("{} ({})", program_id, program_name)
165 }
166 TokenAccountsFilter::Mint(mint) => format!("mint {}", mint),
167 };
168
169 error.data = Some(json!(format!(
170 "Failed to get token accounts by delegate {} for {}: {}",
171 delegate,
172 filter_description,
173 e.to_string()
174 )));
175
176 Self(error)
177 }
178
179 pub fn unsupported_token_program(program_id: Pubkey) -> Self {
180 let mut error = Error::internal_error();
181 error.data = Some(json!(format!(
182 "Unsupported token program: {}. Only SPL Token ({}) and Token 2022 ({}) are currently supported.",
183 program_id,
184 spl_token::ID,
185 spl_token_2022::ID
186 )));
187 Self(error)
188 }
189
190 pub fn get_program_accounts<T>(program_id: Pubkey, e: T) -> Self
191 where
192 T: ToString,
193 {
194 let mut error = Error::internal_error();
195 error.data = Some(json!(format!(
196 "Failed to fetch program accounts for {program_id}: {}",
197 e.to_string()
198 )));
199 Self(error)
200 }
201
202 pub fn get_token_largest_accounts<T>(mint: Pubkey, e: T) -> Self
203 where
204 T: ToString,
205 {
206 let mut error = Error::internal_error();
207 error.data = Some(json!(format!(
208 "Failed to get largest token accounts for mint {mint}: {}",
209 e.to_string()
210 )));
211 Self(error)
212 }
213
214 pub fn get_multiple_accounts<T>(e: T) -> Self
215 where
216 T: ToString,
217 {
218 let mut error = Error::internal_error();
219 error.data = Some(json!(format!(
220 "Failed to fetch accounts from remote: {}",
221 e.to_string()
222 )));
223 Self(error)
224 }
225 pub fn get_largest_accounts<T>(e: T) -> Self
226 where
227 T: ToString,
228 {
229 let mut error = Error::internal_error();
230 error.data = Some(json!(format!(
231 "Failed to fetch largest accounts from remote: {}",
232 e.to_string()
233 )));
234 Self(error)
235 }
236
237 pub fn get_signatures_for_address<T>(e: T) -> Self
238 where
239 T: ToString,
240 {
241 let mut error = Error::internal_error();
242 error.data = Some(json!(format!(
243 "Failed to fetch signatures for address from remote: {}",
244 e.to_string()
245 )));
246 Self(error)
247 }
248
249 pub fn invalid_pubkey<D>(pubkey: &str, data: D) -> Self
250 where
251 D: Serialize,
252 {
253 let mut error = Error::invalid_params(format!("Invalid pubkey '{pubkey}'"));
254 error.data = Some(json!(data));
255 Self(error)
256 }
257
258 pub fn invalid_pubkey_at_index<D>(pubkey: &str, index: usize, data: D) -> Self
259 where
260 D: Serialize,
261 {
262 let mut error =
263 Error::invalid_params(format!("Invalid pubkey '{pubkey}' at index {index}"));
264 error.data = Some(json!(data));
265 Self(error)
266 }
267
268 pub fn invalid_signature<D>(signature: &str, data: D) -> Self
269 where
270 D: Serialize,
271 {
272 let mut error = Error::invalid_params(format!("Invalid signature {signature}"));
273 error.data = Some(json!(data));
274 Self(error)
275 }
276
277 pub fn invalid_program_account<P, D>(program_id: P, data: D) -> Self
278 where
279 P: Display,
280 D: Serialize,
281 {
282 let mut error = Error::invalid_params(format!("Invalid program account {program_id}"));
283 error.data = Some(json!(data));
284 Self(error)
285 }
286
287 pub fn expected_program_account<P>(program_id: P) -> Self
288 where
289 P: Display,
290 {
291 let error = Error::invalid_params(format!("Account {program_id} is not a program account"));
292 Self(error)
293 }
294
295 pub fn account_not_found<P>(pubkey: P) -> Self
296 where
297 P: Display,
298 {
299 let error = Error::invalid_params(format!("Account {pubkey} not found"));
300 Self(error)
301 }
302
303 pub fn transaction_not_found<S>(signature: S) -> Self
304 where
305 S: Display,
306 {
307 let error = Error::invalid_params(format!("Transaction {signature} not found"));
308 Self(error)
309 }
310
311 pub fn invalid_account_data<P, D, M>(pubkey: P, data: D, message: Option<M>) -> Self
312 where
313 P: Display,
314 D: Serialize,
315 M: Display,
316 {
317 let base_msg = format!("invalid account data {pubkey}");
318 let full_msg = if let Some(msg) = message {
319 format!("{base_msg}: {msg}")
320 } else {
321 base_msg
322 };
323 let mut error = Error::invalid_params(full_msg);
324 error.data = Some(json!(data));
325 Self(error)
326 }
327
328 pub fn invalid_account_owner<P, M>(pubkey: P, message: Option<M>) -> Self
329 where
330 P: Display,
331 M: Display,
332 {
333 let base_msg = format!("invalid account owner {pubkey}");
334 let full_msg = if let Some(msg) = message {
335 format!("{base_msg}: {msg}")
336 } else {
337 base_msg
338 };
339 let error = Error::invalid_params(full_msg);
340 Self(error)
341 }
342 pub fn invalid_lookup_index<P>(pubkey: P) -> Self
343 where
344 P: Display,
345 {
346 let error =
347 Error::invalid_params(format!("Address lookup {pubkey} contains an invalid index"));
348 Self(error)
349 }
350
351 pub fn invalid_base64_data<D>(typing: &str, data: D) -> Self
352 where
353 D: Display,
354 {
355 let mut error = Error::invalid_params(format!("Invalid base64 {typing}"));
356 error.data = Some(json!(data.to_string()));
357 Self(error)
358 }
359
360 pub fn deserialize_error<D>(typing: &str, data: D) -> Self
361 where
362 D: Display,
363 {
364 let mut error = Error::invalid_params(format!("Failed to deserialize {typing}"));
365 error.data = Some(json!(data.to_string()));
366 Self(error)
367 }
368
369 pub fn internal<D>(data: D) -> Self
370 where
371 D: Serialize,
372 {
373 let mut error = Error::internal_error();
374 error.data = Some(json!(data));
375 Self(error)
376 }
377
378 pub fn sig_verify_replace_recent_blockhash_collision() -> Self {
379 Self(Error::invalid_params(
380 "sigVerify may not be used with replaceRecentBlockhash",
381 ))
382 }
383
384 pub fn slot_too_old(slot: Slot) -> Self {
385 Self(Error::invalid_params(format!(
386 "Requested {slot} is before the first local slot, and no remote RPC was provided."
387 )))
388 }
389
390 pub fn get_block(e: ClientError, block: Slot) -> Self {
391 let mut error = Error::internal_error();
392 error.data = Some(json!(format!(
393 "Failed to get block {block} from remote: {e}"
394 )));
395 Self(error)
396 }
397
398 pub fn token_mint_not_found(mint: Pubkey) -> Self {
399 let mut error = Error::internal_error();
400 error.message = format!("Token mint {mint} not found");
401 Self(error)
402 }
403
404 pub fn unpack_token_account() -> Self {
405 let mut error = Error::parse_error();
406 error.message = "Failed to unpack token account".to_string();
407 Self(error)
408 }
409
410 pub fn unpack_mint_account() -> Self {
411 let mut error = Error::parse_error();
412 error.message = "Failed to unpack mint account".to_string();
413 Self(error)
414 }
415
416 pub fn invalid_token_account_state(state: &str) -> Self {
417 let error = Error::invalid_params(format!("Invalid token account state {state}"));
418 Self(error)
419 }
420
421 pub fn transaction_not_found_in_svm<S>(signature: S) -> Self
422 where
423 S: Display,
424 {
425 let mut error = Error::internal_error();
426 error.message =
427 format!("Transaction with signature '{signature}' was not found in the SVM");
428 Self(error)
429 }
430
431 pub fn tag_not_found(tag: &str) -> Self {
432 let mut error = Error::internal_error();
433 error.message = format!("Profile result associated with tag '{tag}' not found in the SVM");
434 Self(error)
435 }
436}