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}