tensor_vipers/
error.rs

1#![allow(missing_docs)]
2
3use std::fmt::Display;
4
5use anchor_lang::prelude::*;
6
7/// Vipers validation error.
8#[error_code(offset = 1100)]
9pub enum VipersError {
10    #[msg("Keys do not match.")]
11    KeyMismatch,
12    #[msg("Associated token account does not match.")]
13    ATAMismatch,
14    #[msg("Program ID does not match.")]
15    ProgramIDMismatch,
16    #[msg("Integer overflow.")]
17    IntegerOverflow,
18    #[msg("The provided account is not owned by the specified program.")]
19    OwnerMismatch,
20    #[msg("The provided token account is not an associated token account.")]
21    InvalidATA,
22    #[msg("Invariant failed.")]
23    InvariantFailed,
24    #[msg("Option unwrap failed.")]
25    OptionUnwrapFailed,
26    #[msg("Keys must not match.")]
27    KeysMustNotMatch,
28    #[msg("The provided token account is non-zero: amount must be zero, it should not have a delegate, and it should not have a close authority.")]
29    TokenAccountIsNonZero,
30    #[msg("Bump not found.")]
31    UnknownBump,
32}
33
34/// Conversions into a [CmpError].
35pub trait IntoCmpError {
36    /// Converts the value into a [CmpError].
37    fn into_cmp_error(self) -> Option<CmpError>;
38}
39
40impl<T> IntoCmpError for Result<T> {
41    fn into_cmp_error(self) -> Option<CmpError> {
42        self.err()?.into_cmp_error()
43    }
44}
45
46impl IntoCmpError for anchor_lang::error::Error {
47    fn into_cmp_error(self) -> Option<CmpError> {
48        Some(CmpError(self))
49    }
50}
51
52impl IntoCmpError for Option<anchor_lang::error::Error> {
53    fn into_cmp_error(self) -> Option<CmpError> {
54        self?.into_cmp_error()
55    }
56}
57
58impl From<anchor_lang::error::Error> for CmpError {
59    fn from(err: anchor_lang::error::Error) -> Self {
60        CmpError(err)
61    }
62}
63
64/// A comparable error: an error that can be compared (via equality) to other errors.
65#[repr(transparent)]
66#[derive(Debug)]
67pub struct CmpError(pub anchor_lang::error::Error);
68
69impl PartialEq for CmpError {
70    fn eq(&self, other: &Self) -> bool {
71        let (CmpError(a), CmpError(b)) = (self, other);
72        match (a, b) {
73            (Error::AnchorError(err_a), Error::AnchorError(err_b)) => {
74                err_a.error_code_number == err_b.error_code_number
75            }
76            (Error::ProgramError(err_a), Error::ProgramError(err_b)) => {
77                err_a.program_error == err_b.program_error
78            }
79            _ => false,
80        }
81    }
82}
83
84impl Eq for CmpError {}
85
86impl Display for CmpError {
87    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88        self.0.fmt(f)
89    }
90}
91
92#[cfg(test)]
93#[cfg(not(tarpaulin_include))]
94mod tests {
95    use super::*;
96
97    #[test]
98    fn test_program_errors_equal() {
99        assert_eq!(
100            anchor_lang::error::Error::ProgramError(Box::new(ProgramError::InvalidArgument.into()))
101                .into_cmp_error(),
102            anchor_lang::error::Error::ProgramError(Box::new(ProgramError::InvalidArgument.into()))
103                .into_cmp_error()
104        );
105    }
106
107    #[test]
108    fn test_program_errors_equal_custom() {
109        assert_eq!(
110            anchor_lang::error::Error::ProgramError(Box::new(ProgramError::Custom(10).into()))
111                .into_cmp_error(),
112            anchor_lang::error::Error::ProgramError(Box::new(ProgramError::Custom(10).into()))
113                .into_cmp_error()
114        );
115    }
116
117    #[test]
118    fn test_program_errors_mismatch() {
119        assert_ne!(
120            anchor_lang::error::Error::ProgramError(Box::new(ProgramError::InvalidArgument.into()))
121                .into_cmp_error(),
122            anchor_lang::error::Error::ProgramError(Box::new(
123                ProgramError::AccountAlreadyInitialized.into()
124            ))
125            .into_cmp_error()
126        );
127    }
128
129    #[test]
130    fn test_program_errors_mismatch_custom() {
131        assert_ne!(
132            anchor_lang::error::Error::ProgramError(Box::new(ProgramError::Custom(10).into()))
133                .into_cmp_error(),
134            anchor_lang::error::Error::ProgramError(Box::new(ProgramError::Custom(11).into()))
135                .into_cmp_error()
136        );
137    }
138
139    #[test]
140    fn test_program_errors_equal_none() {
141        assert_eq!(None.into_cmp_error(), None.into_cmp_error());
142    }
143
144    #[test]
145    fn test_program_errors_mismatch_random() {
146        assert_ne!(
147            None.into_cmp_error(),
148            anchor_lang::error::Error::ProgramError(Box::new(ProgramError::Custom(11).into()))
149                .into_cmp_error()
150        );
151    }
152
153    #[test]
154    fn test_program_errors_mismatch_anchor_program() {
155        assert_ne!(
156            error!(ErrorCode::MyError).into_cmp_error(),
157            anchor_lang::error::Error::ProgramError(Box::new(ProgramError::Custom(11).into()))
158                .into_cmp_error()
159        );
160    }
161
162    #[test]
163    fn test_display_anchor_error() {
164        let anchor_error = error!(ErrorCode::MyError);
165        assert_eq!(
166            format!("{}", anchor_error),
167            format!("{}", anchor_error.into_cmp_error().unwrap())
168        );
169    }
170
171    #[error_code]
172    pub enum ErrorCode {
173        MyError,
174        MyOtherError,
175    }
176
177    #[test]
178    fn test_anchor_errors_eq() {
179        assert_eq!(
180            error!(ErrorCode::MyError).into_cmp_error(),
181            error!(ErrorCode::MyError).into_cmp_error(),
182        );
183    }
184
185    #[test]
186    fn test_anchor_errors_eq_result() {
187        assert_eq!(
188            (err!(ErrorCode::MyError) as Result<()>).into_cmp_error(),
189            (err!(ErrorCode::MyError) as Result<()>).into_cmp_error(),
190        );
191    }
192
193    #[test]
194    fn test_anchor_errors_ne_result() {
195        assert_ne!(
196            (err!(ErrorCode::MyError) as Result<()>).into_cmp_error(),
197            (err!(ErrorCode::MyOtherError) as Result<()>).into_cmp_error(),
198        );
199    }
200
201    #[test]
202    fn test_from_anchor_error() {
203        let error_a: CmpError = (error!(ErrorCode::MyError)).into();
204        let error_b: CmpError = (error!(ErrorCode::MyError)).into();
205        assert_eq!(error_a, error_b);
206    }
207}