riglr_evm_common/
error.rs1use thiserror::Error;
7
8#[derive(Debug, Error)]
10pub enum EvmCommonError {
11 #[error("Invalid EVM address: {0}")]
13 InvalidAddress(String),
14
15 #[error("Unsupported chain ID: {0}. Configure RPC_URL_{0} environment variable")]
17 UnsupportedChain(u64),
18
19 #[error("Invalid chain name: {0}")]
21 InvalidChainName(String),
22
23 #[error("RPC provider error: {0}")]
25 ProviderError(String),
26
27 #[error("Configuration error: {0}")]
29 InvalidConfig(String),
30
31 #[error("Invalid transaction data: {0}")]
33 InvalidData(String),
34
35 #[error("Network error: {0}")]
37 NetworkError(String),
38
39 #[error("Parse error: {0}")]
41 ParseError(String),
42}
43
44impl EvmCommonError {
45 pub fn is_retriable(&self) -> bool {
47 matches!(
48 self,
49 EvmCommonError::ProviderError(_) | EvmCommonError::NetworkError(_)
50 )
51 }
52
53 pub fn is_permanent(&self) -> bool {
55 !self.is_retriable()
56 }
57}
58
59pub type EvmResult<T> = Result<T, EvmCommonError>;
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65
66 #[test]
67 fn test_error_classification() {
68 let network_err = EvmCommonError::NetworkError("timeout".to_string());
69 assert!(network_err.is_retriable());
70 assert!(!network_err.is_permanent());
71
72 let config_err = EvmCommonError::InvalidConfig("bad config".to_string());
73 assert!(!config_err.is_retriable());
74 assert!(config_err.is_permanent());
75
76 let address_err = EvmCommonError::InvalidAddress("bad address".to_string());
77 assert!(address_err.is_permanent());
78 }
79
80 #[test]
81 fn test_error_display() {
82 let err = EvmCommonError::UnsupportedChain(999);
83 let msg = err.to_string();
84 assert!(msg.contains("999"));
85 assert!(msg.contains("RPC_URL_999"));
86 }
87
88 #[test]
89 fn test_invalid_address_error_display() {
90 let err = EvmCommonError::InvalidAddress("0xinvalid".to_string());
91 let msg = err.to_string();
92 assert_eq!(msg, "Invalid EVM address: 0xinvalid");
93 }
94
95 #[test]
96 fn test_invalid_address_error_empty_string() {
97 let err = EvmCommonError::InvalidAddress("".to_string());
98 let msg = err.to_string();
99 assert_eq!(msg, "Invalid EVM address: ");
100 }
101
102 #[test]
103 fn test_unsupported_chain_error_display() {
104 let err = EvmCommonError::UnsupportedChain(1);
105 let msg = err.to_string();
106 assert_eq!(
107 msg,
108 "Unsupported chain ID: 1. Configure RPC_URL_1 environment variable"
109 );
110 }
111
112 #[test]
113 fn test_unsupported_chain_error_large_chain_id() {
114 let err = EvmCommonError::UnsupportedChain(u64::MAX);
115 let msg = err.to_string();
116 assert!(msg.contains(&u64::MAX.to_string()));
117 assert!(msg.contains(&format!("RPC_URL_{}", u64::MAX)));
118 }
119
120 #[test]
121 fn test_invalid_chain_name_error_display() {
122 let err = EvmCommonError::InvalidChainName("unknown_chain".to_string());
123 let msg = err.to_string();
124 assert_eq!(msg, "Invalid chain name: unknown_chain");
125 }
126
127 #[test]
128 fn test_invalid_chain_name_error_empty_string() {
129 let err = EvmCommonError::InvalidChainName("".to_string());
130 let msg = err.to_string();
131 assert_eq!(msg, "Invalid chain name: ");
132 }
133
134 #[test]
135 fn test_provider_error_display() {
136 let err = EvmCommonError::ProviderError("connection failed".to_string());
137 let msg = err.to_string();
138 assert_eq!(msg, "RPC provider error: connection failed");
139 }
140
141 #[test]
142 fn test_provider_error_empty_string() {
143 let err = EvmCommonError::ProviderError("".to_string());
144 let msg = err.to_string();
145 assert_eq!(msg, "RPC provider error: ");
146 }
147
148 #[test]
149 fn test_invalid_config_error_display() {
150 let err = EvmCommonError::InvalidConfig("missing key".to_string());
151 let msg = err.to_string();
152 assert_eq!(msg, "Configuration error: missing key");
153 }
154
155 #[test]
156 fn test_invalid_config_error_empty_string() {
157 let err = EvmCommonError::InvalidConfig("".to_string());
158 let msg = err.to_string();
159 assert_eq!(msg, "Configuration error: ");
160 }
161
162 #[test]
163 fn test_invalid_data_error_display() {
164 let err = EvmCommonError::InvalidData("malformed hex".to_string());
165 let msg = err.to_string();
166 assert_eq!(msg, "Invalid transaction data: malformed hex");
167 }
168
169 #[test]
170 fn test_invalid_data_error_empty_string() {
171 let err = EvmCommonError::InvalidData("".to_string());
172 let msg = err.to_string();
173 assert_eq!(msg, "Invalid transaction data: ");
174 }
175
176 #[test]
177 fn test_network_error_display() {
178 let err = EvmCommonError::NetworkError("timeout".to_string());
179 let msg = err.to_string();
180 assert_eq!(msg, "Network error: timeout");
181 }
182
183 #[test]
184 fn test_network_error_empty_string() {
185 let err = EvmCommonError::NetworkError("".to_string());
186 let msg = err.to_string();
187 assert_eq!(msg, "Network error: ");
188 }
189
190 #[test]
191 fn test_parse_error_display() {
192 let err = EvmCommonError::ParseError("invalid format".to_string());
193 let msg = err.to_string();
194 assert_eq!(msg, "Parse error: invalid format");
195 }
196
197 #[test]
198 fn test_parse_error_empty_string() {
199 let err = EvmCommonError::ParseError("".to_string());
200 let msg = err.to_string();
201 assert_eq!(msg, "Parse error: ");
202 }
203
204 #[test]
205 fn test_provider_error_is_retriable() {
206 let err = EvmCommonError::ProviderError("connection timeout".to_string());
207 assert!(err.is_retriable());
208 assert!(!err.is_permanent());
209 }
210
211 #[test]
212 fn test_network_error_is_retriable() {
213 let err = EvmCommonError::NetworkError("dns resolution failed".to_string());
214 assert!(err.is_retriable());
215 assert!(!err.is_permanent());
216 }
217
218 #[test]
219 fn test_all_permanent_errors_are_not_retriable() {
220 let errors = vec![
221 EvmCommonError::InvalidAddress("0xinvalid".to_string()),
222 EvmCommonError::UnsupportedChain(999),
223 EvmCommonError::InvalidChainName("unknown".to_string()),
224 EvmCommonError::InvalidConfig("bad config".to_string()),
225 EvmCommonError::InvalidData("bad data".to_string()),
226 EvmCommonError::ParseError("parse failed".to_string()),
227 ];
228
229 for err in errors {
230 assert!(!err.is_retriable());
231 assert!(err.is_permanent());
232 }
233 }
234
235 #[test]
236 fn test_evm_result_type_alias_ok() {
237 let result: EvmResult<String> = Ok("success".to_string());
238 assert!(result.is_ok());
239 assert_eq!(result.unwrap(), "success");
240 }
241
242 #[test]
243 fn test_evm_result_type_alias_err() {
244 let result: EvmResult<String> =
245 Err(EvmCommonError::InvalidAddress("0xinvalid".to_string()));
246 assert!(result.is_err());
247 match result.unwrap_err() {
248 EvmCommonError::InvalidAddress(addr) => assert_eq!(addr, "0xinvalid"),
249 _ => panic!("Expected InvalidAddress error"),
250 }
251 }
252
253 #[test]
254 fn test_error_debug_trait() {
255 let err = EvmCommonError::InvalidAddress("0xinvalid".to_string());
256 let debug_str = format!("{:?}", err);
257 assert!(debug_str.contains("InvalidAddress"));
258 assert!(debug_str.contains("0xinvalid"));
259 }
260}