Skip to main content

ows_core/
error.rs

1use serde::{Serialize, Serializer};
2
3#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
4#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
5pub enum OwsErrorCode {
6    WalletNotFound,
7    ChainNotSupported,
8    InvalidPassphrase,
9    InvalidInput,
10    CaipParseError,
11}
12
13#[derive(Debug, Clone, thiserror::Error)]
14pub enum OwsError {
15    #[error("wallet not found: {id}")]
16    WalletNotFound { id: String },
17
18    #[error("chain not supported: {chain}")]
19    ChainNotSupported { chain: String },
20
21    #[error("invalid passphrase")]
22    InvalidPassphrase,
23
24    #[error("invalid input: {message}")]
25    InvalidInput { message: String },
26
27    #[error("CAIP parse error: {message}")]
28    CaipParseError { message: String },
29}
30
31impl OwsError {
32    pub fn code(&self) -> OwsErrorCode {
33        match self {
34            OwsError::WalletNotFound { .. } => OwsErrorCode::WalletNotFound,
35            OwsError::ChainNotSupported { .. } => OwsErrorCode::ChainNotSupported,
36            OwsError::InvalidPassphrase => OwsErrorCode::InvalidPassphrase,
37            OwsError::InvalidInput { .. } => OwsErrorCode::InvalidInput,
38            OwsError::CaipParseError { .. } => OwsErrorCode::CaipParseError,
39        }
40    }
41}
42
43#[derive(Serialize)]
44struct ErrorPayload {
45    code: OwsErrorCode,
46    message: String,
47}
48
49impl Serialize for OwsError {
50    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
51        let payload = ErrorPayload {
52            code: self.code(),
53            message: self.to_string(),
54        };
55        payload.serialize(serializer)
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62
63    #[test]
64    fn test_code_mapping_wallet_not_found() {
65        let err = OwsError::WalletNotFound {
66            id: "abc".to_string(),
67        };
68        assert_eq!(err.code(), OwsErrorCode::WalletNotFound);
69    }
70
71    #[test]
72    fn test_code_mapping_all_variants() {
73        assert_eq!(
74            OwsError::ChainNotSupported { chain: "x".into() }.code(),
75            OwsErrorCode::ChainNotSupported
76        );
77        assert_eq!(
78            OwsError::InvalidPassphrase.code(),
79            OwsErrorCode::InvalidPassphrase
80        );
81        assert_eq!(
82            OwsError::InvalidInput {
83                message: "x".into()
84            }
85            .code(),
86            OwsErrorCode::InvalidInput
87        );
88        assert_eq!(
89            OwsError::CaipParseError {
90                message: "x".into()
91            }
92            .code(),
93            OwsErrorCode::CaipParseError
94        );
95    }
96
97    #[test]
98    fn test_display_output() {
99        let err = OwsError::WalletNotFound {
100            id: "abc-123".to_string(),
101        };
102        assert_eq!(err.to_string(), "wallet not found: abc-123");
103    }
104
105    #[test]
106    fn test_json_serialization_shape() {
107        let err = OwsError::WalletNotFound {
108            id: "abc-123".to_string(),
109        };
110        let json = serde_json::to_value(&err).unwrap();
111        assert_eq!(json["code"], "WALLET_NOT_FOUND");
112        assert_eq!(json["message"], "wallet not found: abc-123");
113    }
114
115    #[test]
116    fn test_caip_parse_error_serialization() {
117        let err = OwsError::CaipParseError {
118            message: "bad format".to_string(),
119        };
120        let json = serde_json::to_value(&err).unwrap();
121        assert_eq!(json["code"], "CAIP_PARSE_ERROR");
122        assert!(json["message"].as_str().unwrap().contains("bad format"));
123    }
124}