1use ccxt_core::error::Error;
7use serde_json::Value;
8use std::time::Duration;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum OkxErrorCode {
15 InvalidRequest,
17 InvalidApiKey,
19 InvalidSignature,
21 InvalidTimestamp,
23 RateLimitExceeded,
25 InvalidPassphrase,
27 BadSymbol,
29 ParameterError,
31 InsufficientFunds,
33 OrderNotFound,
35 InsufficientBalance,
37 Unknown(i64),
39}
40
41impl OkxErrorCode {
42 pub fn from_code(code: &str) -> Self {
44 match code.parse::<i64>() {
45 Ok(50000) => OkxErrorCode::InvalidRequest,
46 Ok(50001) => OkxErrorCode::InvalidApiKey,
47 Ok(50002) => OkxErrorCode::InvalidSignature,
48 Ok(50003) => OkxErrorCode::InvalidTimestamp,
49 Ok(50004) => OkxErrorCode::RateLimitExceeded,
50 Ok(50005) => OkxErrorCode::InvalidPassphrase,
51 Ok(50011) => OkxErrorCode::BadSymbol,
52 Ok(51000) => OkxErrorCode::ParameterError,
53 Ok(51001) => OkxErrorCode::InsufficientFunds,
54 Ok(51008) => OkxErrorCode::InsufficientBalance,
55 Ok(51400) => OkxErrorCode::OrderNotFound,
56 Ok(n) => OkxErrorCode::Unknown(n),
57 Err(_) => OkxErrorCode::Unknown(0),
58 }
59 }
60
61 pub fn code(&self) -> i64 {
63 match self {
64 OkxErrorCode::InvalidRequest => 50000,
65 OkxErrorCode::InvalidApiKey => 50001,
66 OkxErrorCode::InvalidSignature => 50002,
67 OkxErrorCode::InvalidTimestamp => 50003,
68 OkxErrorCode::RateLimitExceeded => 50004,
69 OkxErrorCode::InvalidPassphrase => 50005,
70 OkxErrorCode::BadSymbol => 50011,
71 OkxErrorCode::ParameterError => 51000,
72 OkxErrorCode::InsufficientFunds => 51001,
73 OkxErrorCode::InsufficientBalance => 51008,
74 OkxErrorCode::OrderNotFound => 51400,
75 OkxErrorCode::Unknown(n) => *n,
76 }
77 }
78}
79
80pub fn parse_error(response: &Value) -> Error {
114 let code = response
115 .get("code")
116 .and_then(serde_json::Value::as_str)
117 .unwrap_or("unknown");
118
119 let msg = response
120 .get("msg")
121 .and_then(serde_json::Value::as_str)
122 .unwrap_or("Unknown error");
123
124 let error_code = OkxErrorCode::from_code(code);
125
126 match error_code {
127 OkxErrorCode::InvalidApiKey
128 | OkxErrorCode::InvalidSignature
129 | OkxErrorCode::InvalidTimestamp
130 | OkxErrorCode::InvalidPassphrase => Error::authentication(msg.to_string()),
131 OkxErrorCode::RateLimitExceeded => {
132 Error::rate_limit(msg.to_string(), Some(Duration::from_secs(1)))
134 }
135 OkxErrorCode::InvalidRequest | OkxErrorCode::ParameterError => {
136 Error::invalid_request(msg.to_string())
137 }
138 OkxErrorCode::InsufficientFunds | OkxErrorCode::InsufficientBalance => {
139 Error::insufficient_balance(msg.to_string())
140 }
141 OkxErrorCode::BadSymbol => Error::bad_symbol(msg.to_string()),
142 OkxErrorCode::OrderNotFound | OkxErrorCode::Unknown(_) => Error::exchange(code, msg),
143 }
144}
145
146pub fn is_error_response(response: &Value) -> bool {
158 response.get("code").and_then(serde_json::Value::as_str) != Some("0")
159}
160
161pub fn extract_error_code(response: &Value) -> &str {
171 response
172 .get("code")
173 .and_then(serde_json::Value::as_str)
174 .unwrap_or("unknown")
175}
176
177pub fn extract_error_message(response: &Value) -> &str {
187 response
188 .get("msg")
189 .and_then(serde_json::Value::as_str)
190 .unwrap_or("Unknown error")
191}
192
193#[cfg(test)]
194mod tests {
195 use super::*;
196 use serde_json::json;
197
198 #[test]
199 fn test_parse_authentication_error_invalid_api_key() {
200 let response = json!({
201 "code": "50001",
202 "msg": "Invalid API key"
203 });
204
205 let error = parse_error(&response);
206 assert!(error.as_authentication().is_some());
207 assert!(error.to_string().contains("Invalid API key"));
208 }
209
210 #[test]
211 fn test_parse_authentication_error_invalid_signature() {
212 let response = json!({
213 "code": "50002",
214 "msg": "Invalid signature"
215 });
216
217 let error = parse_error(&response);
218 assert!(error.as_authentication().is_some());
219 assert!(error.to_string().contains("Invalid signature"));
220 }
221
222 #[test]
223 fn test_parse_authentication_error_invalid_passphrase() {
224 let response = json!({
225 "code": "50005",
226 "msg": "Invalid passphrase"
227 });
228
229 let error = parse_error(&response);
230 assert!(error.as_authentication().is_some());
231 assert!(error.to_string().contains("Invalid passphrase"));
232 }
233
234 #[test]
235 fn test_parse_rate_limit_error() {
236 let response = json!({
237 "code": "50004",
238 "msg": "Rate limit exceeded"
239 });
240
241 let error = parse_error(&response);
242 assert!(error.as_rate_limit().is_some());
243 let (msg, retry_after) = error.as_rate_limit().unwrap();
244 assert!(msg.contains("Rate limit"));
245 assert!(retry_after.is_some());
246 }
247
248 #[test]
249 fn test_parse_invalid_request_error() {
250 let response = json!({
251 "code": "50000",
252 "msg": "Invalid request parameters"
253 });
254
255 let error = parse_error(&response);
256 let display = error.to_string();
257 assert!(display.contains("Invalid request"));
258 }
259
260 #[test]
261 fn test_parse_parameter_error() {
262 let response = json!({
263 "code": "51000",
264 "msg": "Parameter error"
265 });
266
267 let error = parse_error(&response);
268 let display = error.to_string();
269 assert!(display.contains("Parameter error"));
270 }
271
272 #[test]
273 fn test_parse_insufficient_funds_error() {
274 let response = json!({
275 "code": "51001",
276 "msg": "Insufficient balance"
277 });
278
279 let error = parse_error(&response);
280 let display = error.to_string();
281 assert!(display.contains("Insufficient balance"));
282 }
283
284 #[test]
285 fn test_parse_insufficient_balance_error() {
286 let response = json!({
287 "code": "51008",
288 "msg": "Insufficient balance for order"
289 });
290
291 let error = parse_error(&response);
292 let display = error.to_string();
293 assert!(display.contains("Insufficient balance"));
294 }
295
296 #[test]
297 fn test_parse_bad_symbol_error() {
298 let response = json!({
299 "code": "50011",
300 "msg": "Invalid instrument"
301 });
302
303 let error = parse_error(&response);
304 let display = error.to_string();
305 assert!(display.contains("Bad symbol"));
306 }
307
308 #[test]
309 fn test_parse_order_not_found_error() {
310 let response = json!({
311 "code": "51400",
312 "msg": "Order does not exist"
313 });
314
315 let error = parse_error(&response);
316 let display = error.to_string();
317 assert!(display.contains("Order does not exist"));
318 }
319
320 #[test]
321 fn test_parse_unknown_error() {
322 let response = json!({
323 "code": "99999",
324 "msg": "Some unknown error"
325 });
326
327 let error = parse_error(&response);
328 let display = error.to_string();
329 assert!(display.contains("Some unknown error"));
330 }
331
332 #[test]
333 fn test_parse_error_missing_code() {
334 let response = json!({
335 "msg": "Error without code"
336 });
337
338 let error = parse_error(&response);
339 let display = error.to_string();
340 assert!(display.contains("Error without code"));
341 }
342
343 #[test]
344 fn test_parse_error_missing_message() {
345 let response = json!({
346 "code": "50001"
347 });
348
349 let error = parse_error(&response);
350 let display = error.to_string();
351 assert!(display.contains("Unknown error"));
352 }
353
354 #[test]
355 fn test_is_error_response_success() {
356 let response = json!({
357 "code": "0",
358 "msg": "success",
359 "data": []
360 });
361
362 assert!(!is_error_response(&response));
363 }
364
365 #[test]
366 fn test_is_error_response_error() {
367 let response = json!({
368 "code": "50001",
369 "msg": "Invalid API key"
370 });
371
372 assert!(is_error_response(&response));
373 }
374
375 #[test]
376 fn test_is_error_response_missing_code() {
377 let response = json!({
378 "msg": "No code field"
379 });
380
381 assert!(is_error_response(&response));
383 }
384
385 #[test]
386 fn test_extract_error_code() {
387 let response = json!({
388 "code": "50001",
389 "msg": "Invalid API key"
390 });
391
392 assert_eq!(extract_error_code(&response), "50001");
393 }
394
395 #[test]
396 fn test_extract_error_code_missing() {
397 let response = json!({
398 "msg": "No code"
399 });
400
401 assert_eq!(extract_error_code(&response), "unknown");
402 }
403
404 #[test]
405 fn test_extract_error_message() {
406 let response = json!({
407 "code": "50001",
408 "msg": "Invalid API key"
409 });
410
411 assert_eq!(extract_error_message(&response), "Invalid API key");
412 }
413
414 #[test]
415 fn test_extract_error_message_missing() {
416 let response = json!({
417 "code": "50001"
418 });
419
420 assert_eq!(extract_error_message(&response), "Unknown error");
421 }
422
423 #[test]
424 fn test_okx_error_code_from_code() {
425 assert_eq!(
426 OkxErrorCode::from_code("50000"),
427 OkxErrorCode::InvalidRequest
428 );
429 assert_eq!(
430 OkxErrorCode::from_code("50001"),
431 OkxErrorCode::InvalidApiKey
432 );
433 assert_eq!(
434 OkxErrorCode::from_code("50002"),
435 OkxErrorCode::InvalidSignature
436 );
437 assert_eq!(
438 OkxErrorCode::from_code("50003"),
439 OkxErrorCode::InvalidTimestamp
440 );
441 assert_eq!(
442 OkxErrorCode::from_code("50004"),
443 OkxErrorCode::RateLimitExceeded
444 );
445 assert_eq!(
446 OkxErrorCode::from_code("50005"),
447 OkxErrorCode::InvalidPassphrase
448 );
449 assert_eq!(OkxErrorCode::from_code("50011"), OkxErrorCode::BadSymbol);
450 assert_eq!(
451 OkxErrorCode::from_code("51000"),
452 OkxErrorCode::ParameterError
453 );
454 assert_eq!(
455 OkxErrorCode::from_code("51001"),
456 OkxErrorCode::InsufficientFunds
457 );
458 assert_eq!(
459 OkxErrorCode::from_code("51008"),
460 OkxErrorCode::InsufficientBalance
461 );
462 assert_eq!(
463 OkxErrorCode::from_code("51400"),
464 OkxErrorCode::OrderNotFound
465 );
466 assert_eq!(
467 OkxErrorCode::from_code("99999"),
468 OkxErrorCode::Unknown(99999)
469 );
470 assert_eq!(OkxErrorCode::from_code("invalid"), OkxErrorCode::Unknown(0));
471 }
472
473 #[test]
474 fn test_okx_error_code_code() {
475 assert_eq!(OkxErrorCode::InvalidRequest.code(), 50000);
476 assert_eq!(OkxErrorCode::InvalidApiKey.code(), 50001);
477 assert_eq!(OkxErrorCode::InvalidSignature.code(), 50002);
478 assert_eq!(OkxErrorCode::InvalidTimestamp.code(), 50003);
479 assert_eq!(OkxErrorCode::RateLimitExceeded.code(), 50004);
480 assert_eq!(OkxErrorCode::InvalidPassphrase.code(), 50005);
481 assert_eq!(OkxErrorCode::BadSymbol.code(), 50011);
482 assert_eq!(OkxErrorCode::ParameterError.code(), 51000);
483 assert_eq!(OkxErrorCode::InsufficientFunds.code(), 51001);
484 assert_eq!(OkxErrorCode::InsufficientBalance.code(), 51008);
485 assert_eq!(OkxErrorCode::OrderNotFound.code(), 51400);
486 assert_eq!(OkxErrorCode::Unknown(12345).code(), 12345);
487 }
488}