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