1#![allow(missing_docs)]
2
3use std::fmt::Display;
4
5use anchor_lang::prelude::*;
6
7#[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
34pub trait IntoCmpError {
36 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#[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}