openzeppelin_relayer/utils/
error_sanitization.rs1use crate::{
10 models::{OpenZeppelinErrorCodes, RpcErrorCodes},
11 services::provider::ProviderError,
12};
13
14pub fn map_provider_error(error: &ProviderError) -> (i32, &'static str) {
41 match error {
42 ProviderError::InvalidAddress(_) => (RpcErrorCodes::INVALID_PARAMS, "Invalid params"),
43 ProviderError::NetworkConfiguration(_) => (
44 OpenZeppelinErrorCodes::NETWORK_CONFIGURATION,
45 "Network configuration error",
46 ),
47 ProviderError::Timeout => (OpenZeppelinErrorCodes::TIMEOUT, "Request timeout"),
48 ProviderError::RateLimited => (OpenZeppelinErrorCodes::RATE_LIMITED, "Rate limited"),
49 ProviderError::BadGateway => (OpenZeppelinErrorCodes::BAD_GATEWAY, "Bad gateway"),
50 ProviderError::RequestError { .. } => {
51 (OpenZeppelinErrorCodes::REQUEST_ERROR, "Request error")
52 }
53 ProviderError::Other(_) => (RpcErrorCodes::INTERNAL_ERROR, "Internal error"),
54 _ => (RpcErrorCodes::INTERNAL_ERROR, "Internal error"),
55 }
56}
57
58pub fn sanitize_error_description(error: &ProviderError) -> String {
72 match error {
73 ProviderError::InvalidAddress(_) => "The provided address is invalid".to_string(),
74 ProviderError::NetworkConfiguration(_) => {
75 "Network configuration error. Please check your network settings".to_string()
76 }
77 ProviderError::Timeout => "The request timed out. Please try again later".to_string(),
78 ProviderError::RateLimited => "Rate limit exceeded. Please try again later".to_string(),
79 ProviderError::BadGateway => {
80 "Service temporarily unavailable. Please try again later".to_string()
81 }
82 ProviderError::RequestError { status_code, .. } => {
83 format!("Request failed with status code {status_code}")
84 }
85 ProviderError::RpcErrorCode { code, .. } => {
86 format!("RPC error occurred (code: {code})")
87 }
88 ProviderError::TransportError(_) => {
89 "Network error occurred. Please try again later".to_string()
90 }
91 ProviderError::SolanaRpcError(_) => {
92 "RPC request failed. Please try again later".to_string()
93 }
94 ProviderError::Other(_) => "An internal error occurred. Please try again later".to_string(),
95 }
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101 use crate::services::provider::{rpc_selector::RpcSelectorError, SolanaProviderError};
102
103 #[test]
104 fn test_map_provider_error_invalid_address() {
105 let error = ProviderError::InvalidAddress("invalid address".to_string());
106 let (code, _message) = map_provider_error(&error);
107
108 assert_eq!(code, RpcErrorCodes::INVALID_PARAMS);
109 }
110
111 #[test]
112 fn test_map_provider_error_invalid_address_empty() {
113 let error = ProviderError::InvalidAddress("".to_string());
114 let (code, _message) = map_provider_error(&error);
115
116 assert_eq!(code, RpcErrorCodes::INVALID_PARAMS);
117 }
118
119 #[test]
120 fn test_map_provider_error_network_configuration() {
121 let error = ProviderError::NetworkConfiguration("network config error".to_string());
122 let (code, _message) = map_provider_error(&error);
123
124 assert_eq!(code, OpenZeppelinErrorCodes::NETWORK_CONFIGURATION);
125 }
126
127 #[test]
128 fn test_map_provider_error_network_configuration_empty() {
129 let error = ProviderError::NetworkConfiguration("".to_string());
130 let (code, _message) = map_provider_error(&error);
131
132 assert_eq!(code, OpenZeppelinErrorCodes::NETWORK_CONFIGURATION);
133 }
134
135 #[test]
136 fn test_map_provider_error_timeout() {
137 let error = ProviderError::Timeout;
138 let (code, _message) = map_provider_error(&error);
139
140 assert_eq!(code, OpenZeppelinErrorCodes::TIMEOUT);
141 }
142
143 #[test]
144 fn test_map_provider_error_rate_limited() {
145 let error = ProviderError::RateLimited;
146 let (code, _message) = map_provider_error(&error);
147
148 assert_eq!(code, OpenZeppelinErrorCodes::RATE_LIMITED);
149 }
150
151 #[test]
152 fn test_map_provider_error_bad_gateway() {
153 let error = ProviderError::BadGateway;
154 let (code, _message) = map_provider_error(&error);
155
156 assert_eq!(code, OpenZeppelinErrorCodes::BAD_GATEWAY);
157 }
158
159 #[test]
160 fn test_map_provider_error_request_error_400() {
161 let error = ProviderError::RequestError {
162 error: "Bad request".to_string(),
163 status_code: 400,
164 };
165 let (code, _message) = map_provider_error(&error);
166
167 assert_eq!(code, OpenZeppelinErrorCodes::REQUEST_ERROR);
168 }
169
170 #[test]
171 fn test_map_provider_error_request_error_500() {
172 let error = ProviderError::RequestError {
173 error: "Internal server error".to_string(),
174 status_code: 500,
175 };
176 let (code, _message) = map_provider_error(&error);
177
178 assert_eq!(code, OpenZeppelinErrorCodes::REQUEST_ERROR);
179 }
180
181 #[test]
182 fn test_map_provider_error_request_error_empty_message() {
183 let error = ProviderError::RequestError {
184 error: "".to_string(),
185 status_code: 404,
186 };
187 let (code, _message) = map_provider_error(&error);
188
189 assert_eq!(code, OpenZeppelinErrorCodes::REQUEST_ERROR);
190 }
191
192 #[test]
193 fn test_map_provider_error_request_error_zero_status() {
194 let error = ProviderError::RequestError {
195 error: "No status".to_string(),
196 status_code: 0,
197 };
198 let (code, _message) = map_provider_error(&error);
199
200 assert_eq!(code, OpenZeppelinErrorCodes::REQUEST_ERROR);
201 }
202
203 #[test]
204 fn test_map_provider_error_other() {
205 let error = ProviderError::Other("some other error".to_string());
206 let (code, _message) = map_provider_error(&error);
207
208 assert_eq!(code, RpcErrorCodes::INTERNAL_ERROR);
209 }
210
211 #[test]
212 fn test_map_provider_error_other_empty() {
213 let error = ProviderError::Other("".to_string());
214 let (code, _message) = map_provider_error(&error);
215
216 assert_eq!(code, RpcErrorCodes::INTERNAL_ERROR);
217 }
218
219 #[test]
220 fn test_map_provider_error_solana_rpc_error() {
221 let solana_error = SolanaProviderError::RpcError("Solana RPC failed".to_string());
222 let error = ProviderError::SolanaRpcError(solana_error);
223 let (code, _message) = map_provider_error(&error);
224
225 assert_eq!(code, RpcErrorCodes::INTERNAL_ERROR);
227 }
228
229 #[test]
230 fn test_map_provider_error_solana_invalid_address() {
231 let solana_error =
232 SolanaProviderError::InvalidAddress("Invalid Solana address".to_string());
233 let error = ProviderError::SolanaRpcError(solana_error);
234 let (code, _message) = map_provider_error(&error);
235
236 assert_eq!(code, RpcErrorCodes::INTERNAL_ERROR);
238 }
239
240 #[test]
241 fn test_map_provider_error_solana_selector_error() {
242 let selector_error = RpcSelectorError::NoProviders;
243 let solana_error = SolanaProviderError::SelectorError(selector_error);
244 let error = ProviderError::SolanaRpcError(solana_error);
245 let (code, _message) = map_provider_error(&error);
246
247 assert_eq!(code, RpcErrorCodes::INTERNAL_ERROR);
249 }
250
251 #[test]
252 fn test_map_provider_error_solana_network_configuration() {
253 let solana_error =
254 SolanaProviderError::NetworkConfiguration("Solana network config error".to_string());
255 let error = ProviderError::SolanaRpcError(solana_error);
256 let (code, _message) = map_provider_error(&error);
257
258 assert_eq!(code, RpcErrorCodes::INTERNAL_ERROR);
260 }
261
262 #[test]
263 fn test_map_provider_error_wildcard_pattern() {
264 let test_cases = vec![
267 ProviderError::SolanaRpcError(SolanaProviderError::RpcError("test".to_string())),
268 ProviderError::SolanaRpcError(SolanaProviderError::InvalidAddress("test".to_string())),
269 ProviderError::SolanaRpcError(SolanaProviderError::NetworkConfiguration(
270 "test".to_string(),
271 )),
272 ProviderError::SolanaRpcError(SolanaProviderError::SelectorError(
273 RpcSelectorError::NoProviders,
274 )),
275 ];
276
277 for error in test_cases {
278 let (code, _message) = map_provider_error(&error);
279 assert_eq!(code, RpcErrorCodes::INTERNAL_ERROR);
280 }
281 }
282
283 #[test]
284 fn test_sanitize_error_description_invalid_address() {
285 let error = ProviderError::InvalidAddress("0xinvalid".to_string());
286 let description = sanitize_error_description(&error);
287 assert_eq!(description, "The provided address is invalid");
288 assert!(!description.contains("0xinvalid"));
290 }
291
292 #[test]
293 fn test_sanitize_error_description_network_configuration() {
294 let error =
295 ProviderError::NetworkConfiguration("RPC selector error: No providers".to_string());
296 let description = sanitize_error_description(&error);
297 assert_eq!(
298 description,
299 "Network configuration error. Please check your network settings"
300 );
301 assert!(!description.contains("RPC selector"));
303 assert!(!description.contains("No providers"));
304 }
305
306 #[test]
307 fn test_sanitize_error_description_timeout() {
308 let error = ProviderError::Timeout;
309 let description = sanitize_error_description(&error);
310 assert_eq!(description, "The request timed out. Please try again later");
311 }
312
313 #[test]
314 fn test_sanitize_error_description_rate_limited() {
315 let error = ProviderError::RateLimited;
316 let description = sanitize_error_description(&error);
317 assert_eq!(description, "Rate limit exceeded. Please try again later");
318 }
319
320 #[test]
321 fn test_sanitize_error_description_bad_gateway() {
322 let error = ProviderError::BadGateway;
323 let description = sanitize_error_description(&error);
324 assert_eq!(
325 description,
326 "Service temporarily unavailable. Please try again later"
327 );
328 }
329
330 #[test]
331 fn test_sanitize_error_description_request_error() {
332 let error = ProviderError::RequestError {
333 error: "API key invalid: abc123".to_string(),
334 status_code: 401,
335 };
336 let description = sanitize_error_description(&error);
337 assert_eq!(description, "Request failed with status code 401");
338 assert!(!description.contains("API key"));
340 assert!(!description.contains("abc123"));
341 }
342
343 #[test]
344 fn test_sanitize_error_description_rpc_error_code() {
345 let error = ProviderError::RpcErrorCode {
346 code: -32000,
347 message: "Server error: Invalid API key".to_string(),
348 };
349 let description = sanitize_error_description(&error);
350 assert_eq!(description, "RPC error occurred (code: -32000)");
351 assert!(!description.contains("Server error"));
353 assert!(!description.contains("API key"));
354 }
355
356 #[test]
357 fn test_sanitize_error_description_transport_error() {
358 let error = ProviderError::TransportError(
359 "Connection failed: https://rpc.example.com/api?key=secret".to_string(),
360 );
361 let description = sanitize_error_description(&error);
362 assert_eq!(
363 description,
364 "Network error occurred. Please try again later"
365 );
366 assert!(!description.contains("https://"));
368 assert!(!description.contains("key="));
369 assert!(!description.contains("secret"));
370 }
371
372 #[test]
373 fn test_sanitize_error_description_solana_rpc_error() {
374 let solana_error =
375 SolanaProviderError::RpcError("RPC failed: Invalid API key abc123".to_string());
376 let error = ProviderError::SolanaRpcError(solana_error);
377 let description = sanitize_error_description(&error);
378 assert_eq!(description, "RPC request failed. Please try again later");
379 assert!(!description.contains("API key"));
381 assert!(!description.contains("abc123"));
382 }
383
384 #[test]
385 fn test_sanitize_error_description_other() {
386 let error = ProviderError::Other(
387 "Internal error: Failed to connect to https://rpc.example.com with key abc123"
388 .to_string(),
389 );
390 let description = sanitize_error_description(&error);
391 assert_eq!(
392 description,
393 "An internal error occurred. Please try again later"
394 );
395 assert!(!description.contains("Failed to connect"));
397 assert!(!description.contains("https://"));
398 assert!(!description.contains("key"));
399 assert!(!description.contains("abc123"));
400 }
401}