surfpool_core/
error.rs

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_pubkey::Pubkey;
8
9pub type SurfpoolResult<T> = std::result::Result<T, SurfpoolError>;
10
11#[derive(Debug, Clone)]
12pub struct SurfpoolError(Error);
13
14impl From<SurfpoolError> for String {
15    fn from(e: SurfpoolError) -> Self {
16        e.0.to_string()
17    }
18}
19
20impl From<SurfpoolError> for Error {
21    fn from(e: SurfpoolError) -> Self {
22        e.0
23    }
24}
25
26impl std::error::Error for SurfpoolError {}
27
28impl std::fmt::Display for SurfpoolError {
29    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
30        let Error {
31            code,
32            message,
33            data,
34        } = &self.0;
35
36        let core = if code.description().eq(message) {
37            code.description()
38        } else {
39            format!("{}: {}", code.description(), message)
40        };
41
42        if let Some(data_value) = data {
43            write!(f, "{}: {}", core, data_value.to_string().as_str())
44        } else {
45            write!(f, "{}", core)
46        }
47    }
48}
49
50impl<T> From<SurfpoolError> for Pin<Box<dyn Future<Output = Result<T>> + Send>> {
51    fn from(e: SurfpoolError) -> Self {
52        Box::pin(async move { Err(e.into()) })
53    }
54}
55
56impl<T> From<TrySendError<T>> for SurfpoolError {
57    fn from(val: TrySendError<T>) -> Self {
58        SurfpoolError::from_try_send_error(val)
59    }
60}
61
62impl From<solana_client::client_error::ClientError> for SurfpoolError {
63    fn from(e: solana_client::client_error::ClientError) -> Self {
64        SurfpoolError::client_error(e)
65    }
66}
67
68impl SurfpoolError {
69    pub fn from_try_send_error<T>(e: TrySendError<T>) -> Self {
70        let mut error = Error::internal_error();
71        error.data = Some(json!(format!(
72            "Failed to send command on channel: {}",
73            e.to_string()
74        )));
75        Self(error)
76    }
77
78    pub fn client_error(e: solana_client::client_error::ClientError) -> Self {
79        let mut error = Error::internal_error();
80        error.data = Some(json!(format!("Solana RPC client error: {}", e.to_string())));
81        Self(error)
82    }
83
84    pub fn no_locker() -> Self {
85        let mut error = Error::internal_error();
86        error.data = Some(json!("Failed to access internal SVM state"));
87        Self(error)
88    }
89
90    pub fn set_account<T>(pubkey: Pubkey, e: T) -> Self
91    where
92        T: ToString,
93    {
94        let mut error = Error::internal_error();
95        error.data = Some(json!(format!(
96            "Failed to set account {}: {}",
97            pubkey,
98            e.to_string()
99        )));
100        Self(error)
101    }
102    pub fn get_account<T>(pubkey: Pubkey, e: T) -> Self
103    where
104        T: ToString,
105    {
106        let mut error = Error::internal_error();
107        error.data = Some(json!(format!(
108            "Failed to fetch account {} from remote: {}",
109            pubkey,
110            e.to_string()
111        )));
112        Self(error)
113    }
114
115    pub fn get_token_accounts<T>(owner: Pubkey, token_program: Pubkey, e: T) -> Self
116    where
117        T: ToString,
118    {
119        let mut error = Error::internal_error();
120        error.data = Some(json!(format!(
121            "Failed to get token accounts by owner {owner} for program {token_program}: {}",
122            e.to_string()
123        )));
124        Self(error)
125    }
126
127    pub fn get_multiple_accounts<T>(e: T) -> Self
128    where
129        T: ToString,
130    {
131        let mut error = Error::internal_error();
132        error.data = Some(json!(format!(
133            "Failed to fetch accounts from remote: {}",
134            e.to_string()
135        )));
136        Self(error)
137    }
138
139    pub fn invalid_pubkey<D>(pubkey: &str, data: D) -> Self
140    where
141        D: Serialize,
142    {
143        let mut error = Error::invalid_params(format!("Invalid pubkey {pubkey}"));
144        error.data = Some(json!(data));
145        Self(error)
146    }
147
148    pub fn invalid_signature<D>(signature: &str, data: D) -> Self
149    where
150        D: Serialize,
151    {
152        let mut error = Error::invalid_params(format!("Invalid signature {signature}"));
153        error.data = Some(json!(data));
154        Self(error)
155    }
156
157    pub fn invalid_program_account<P, D>(program_id: P, data: D) -> Self
158    where
159        P: Display,
160        D: Serialize,
161    {
162        let mut error = Error::invalid_params(format!("Invalid program account {program_id}"));
163        error.data = Some(json!(data));
164        Self(error)
165    }
166
167    pub fn expected_program_account<P>(program_id: P) -> Self
168    where
169        P: Display,
170    {
171        let error = Error::invalid_params(format!("Account {program_id} is not a program account"));
172        Self(error)
173    }
174
175    pub fn account_not_found<P>(pubkey: P) -> Self
176    where
177        P: Display,
178    {
179        let error = Error::invalid_params(format!("Account {pubkey} not found"));
180        Self(error)
181    }
182
183    pub fn transaction_not_found<S>(signature: S) -> Self
184    where
185        S: Display,
186    {
187        let error = Error::invalid_params(format!("Transaction {signature} not found"));
188        Self(error)
189    }
190
191    pub fn invalid_account_data<P, D, M>(pubkey: P, data: D, message: Option<M>) -> Self
192    where
193        P: Display,
194        D: Serialize,
195        M: Display,
196    {
197        let base_msg = format!("invalid account data {pubkey}");
198        let full_msg = if let Some(msg) = message {
199            format!("{base_msg}: {msg}")
200        } else {
201            base_msg
202        };
203        let mut error = Error::invalid_params(full_msg);
204        error.data = Some(json!(data));
205        Self(error)
206    }
207
208    pub fn invalid_account_owner<P, M>(pubkey: P, message: Option<M>) -> Self
209    where
210        P: Display,
211        M: Display,
212    {
213        let base_msg = format!("invalid account owner {pubkey}");
214        let full_msg = if let Some(msg) = message {
215            format!("{base_msg}: {msg}")
216        } else {
217            base_msg
218        };
219        let error = Error::invalid_params(full_msg);
220        Self(error)
221    }
222    pub fn invalid_lookup_index<P>(pubkey: P) -> Self
223    where
224        P: Display,
225    {
226        let error =
227            Error::invalid_params(format!("Address lookup {pubkey} contains an invalid index"));
228        Self(error)
229    }
230
231    pub fn internal<D>(data: D) -> Self
232    where
233        D: Serialize,
234    {
235        let mut error = Error::internal_error();
236        error.data = Some(json!(data));
237        Self(error)
238    }
239}