Skip to main content

cronos_anchor_lang/
error.rs

1use anchor_lang::error_code;
2use borsh::maybestd::io::Error as BorshIoError;
3use solana_program::{program_error::ProgramError, pubkey::Pubkey};
4use std::fmt::{Debug, Display};
5
6/// The starting point for user defined error codes.
7pub const ERROR_CODE_OFFSET: u32 = 6000;
8
9/// Error codes that can be returned by internal framework code.
10///
11/// - >= 100 Instruction error codes
12/// - >= 1000 IDL error codes
13/// - >= 2000 constraint error codes
14/// - >= 3000 account error codes
15/// - = 4000 state error code
16/// - >= 4100 misc error codes
17/// - = 5000 deprecated error code
18///
19/// The starting point for user-defined errors is defined
20/// by the [ERROR_CODE_OFFSET](crate::error::ERROR_CODE_OFFSET).
21#[error_code(offset = 0)]
22pub enum ErrorCode {
23    // Instructions
24    /// 100 - 8 byte instruction identifier not provided
25    #[msg("8 byte instruction identifier not provided")]
26    InstructionMissing = 100,
27    /// 101 - Fallback functions are not supported
28    #[msg("Fallback functions are not supported")]
29    InstructionFallbackNotFound,
30    /// 102 - The program could not deserialize the given instruction
31    #[msg("The program could not deserialize the given instruction")]
32    InstructionDidNotDeserialize,
33    /// 103 - The program could not serialize the given instruction
34    #[msg("The program could not serialize the given instruction")]
35    InstructionDidNotSerialize,
36
37    // IDL instructions
38    /// 1000 - The program was compiled without idl instructions
39    #[msg("The program was compiled without idl instructions")]
40    IdlInstructionStub = 1000,
41    /// 1001 - Invalid program given to the IDL instruction
42    #[msg("Invalid program given to the IDL instruction")]
43    IdlInstructionInvalidProgram,
44
45    // Constraints
46    /// 2000 - A mut constraint was violated
47    #[msg("A mut constraint was violated")]
48    ConstraintMut = 2000,
49    /// 2001 - A has one constraint was violated
50    #[msg("A has one constraint was violated")]
51    ConstraintHasOne,
52    /// 2002 - A signer constraint was violated
53    #[msg("A signer constraint was violated")]
54    ConstraintSigner,
55    /// 2003 - A raw constraint was violated
56    #[msg("A raw constraint was violated")]
57    ConstraintRaw,
58    /// 2004 - An owner constraint was violated
59    #[msg("An owner constraint was violated")]
60    ConstraintOwner,
61    /// 2005 - A rent exemption constraint was violated
62    #[msg("A rent exemption constraint was violated")]
63    ConstraintRentExempt,
64    /// 2006 - A seeds constraint was violated
65    #[msg("A seeds constraint was violated")]
66    ConstraintSeeds,
67    /// 2007 - An executable constraint was violated
68    #[msg("An executable constraint was violated")]
69    ConstraintExecutable,
70    /// 2008 - A state constraint was violated
71    #[msg("A state constraint was violated")]
72    ConstraintState,
73    /// 2009 - An associated constraint was violated
74    #[msg("An associated constraint was violated")]
75    ConstraintAssociated,
76    /// 2010 - An associated init constraint was violated
77    #[msg("An associated init constraint was violated")]
78    ConstraintAssociatedInit,
79    /// 2011 - A close constraint was violated
80    #[msg("A close constraint was violated")]
81    ConstraintClose,
82    /// 2012 - An address constraint was violated
83    #[msg("An address constraint was violated")]
84    ConstraintAddress,
85    /// 2013 - Expected zero account discriminant
86    #[msg("Expected zero account discriminant")]
87    ConstraintZero,
88    /// 2014 - A token mint constraint was violated
89    #[msg("A token mint constraint was violated")]
90    ConstraintTokenMint,
91    /// 2015 - A token owner constraint was violated
92    #[msg("A token owner constraint was violated")]
93    ConstraintTokenOwner,
94    /// The mint mint is intentional -> a mint authority for the mint.
95    ///
96    /// 2016 - A mint mint authority constraint was violated
97    #[msg("A mint mint authority constraint was violated")]
98    ConstraintMintMintAuthority,
99    /// 2017 - A mint freeze authority constraint was violated
100    #[msg("A mint freeze authority constraint was violated")]
101    ConstraintMintFreezeAuthority,
102    /// 2018 - A mint decimals constraint was violated
103    #[msg("A mint decimals constraint was violated")]
104    ConstraintMintDecimals,
105    /// 2019 - A space constraint was violated
106    #[msg("A space constraint was violated")]
107    ConstraintSpace,
108
109    // Require
110    /// 2500 - A require expression was violated
111    #[msg("A require expression was violated")]
112    RequireViolated = 2500,
113    /// 2501 - A require_eq expression was violated
114    #[msg("A require_eq expression was violated")]
115    RequireEqViolated,
116    /// 2502 - A require_keys_eq expression was violated
117    #[msg("A require_keys_eq expression was violated")]
118    RequireKeysEqViolated,
119    /// 2503 - A require_neq expression was violated
120    #[msg("A require_neq expression was violated")]
121    RequireNeqViolated,
122    /// 2504 - A require_keys_neq expression was violated
123    #[msg("A require_keys_neq expression was violated")]
124    RequireKeysNeqViolated,
125    /// 2505 - A require_gt expression was violated
126    #[msg("A require_gt expression was violated")]
127    RequireGtViolated,
128    /// 2506 - A require_gte expression was violated
129    #[msg("A require_gte expression was violated")]
130    RequireGteViolated,
131
132    // Accounts.
133    /// 3000 - The account discriminator was already set on this account
134    #[msg("The account discriminator was already set on this account")]
135    AccountDiscriminatorAlreadySet = 3000,
136    /// 3001 - No 8 byte discriminator was found on the account
137    #[msg("No 8 byte discriminator was found on the account")]
138    AccountDiscriminatorNotFound,
139    /// 3002 - 8 byte discriminator did not match what was expected
140    #[msg("8 byte discriminator did not match what was expected")]
141    AccountDiscriminatorMismatch,
142    /// 3003 - Failed to deserialize the account
143    #[msg("Failed to deserialize the account")]
144    AccountDidNotDeserialize,
145    /// 3004 - Failed to serialize the account
146    #[msg("Failed to serialize the account")]
147    AccountDidNotSerialize,
148    /// 3005 - Not enough account keys given to the instruction
149    #[msg("Not enough account keys given to the instruction")]
150    AccountNotEnoughKeys,
151    /// 3006 - The given account is not mutable
152    #[msg("The given account is not mutable")]
153    AccountNotMutable,
154    /// 3007 - The given account is owned by a different program than expected
155    #[msg("The given account is owned by a different program than expected")]
156    AccountOwnedByWrongProgram,
157    /// 3008 - Program ID was not as expected
158    #[msg("Program ID was not as expected")]
159    InvalidProgramId,
160    /// 3009 - Program account is not executable
161    #[msg("Program account is not executable")]
162    InvalidProgramExecutable,
163    /// 3010 - The given account did not sign
164    #[msg("The given account did not sign")]
165    AccountNotSigner,
166    /// 3011 - The given account is not owned by the system program
167    #[msg("The given account is not owned by the system program")]
168    AccountNotSystemOwned,
169    /// 3012 - The program expected this account to be already initialized
170    #[msg("The program expected this account to be already initialized")]
171    AccountNotInitialized,
172    /// 3013 - The given account is not a program data account
173    #[msg("The given account is not a program data account")]
174    AccountNotProgramData,
175    /// 3014 - The given account is not the associated token account
176    #[msg("The given account is not the associated token account")]
177    AccountNotAssociatedTokenAccount,
178    /// 3015 - The given public key does not match the required sysvar
179    #[msg("The given public key does not match the required sysvar")]
180    AccountSysvarMismatch,
181
182    // State.
183    /// 4000 - The given state account does not have the correct address
184    #[msg("The given state account does not have the correct address")]
185    StateInvalidAddress = 4000,
186
187    // Miscellaneous
188    /// 4100 - The declared program id does not match actual program id
189    #[msg("The declared program id does not match the actual program id")]
190    DeclaredProgramIdMismatch = 4100,
191
192    // Deprecated
193    /// 5000 - The API being used is deprecated and should no longer be used
194    #[msg("The API being used is deprecated and should no longer be used")]
195    Deprecated = 5000,
196}
197
198#[derive(Debug, PartialEq, Eq)]
199pub enum Error {
200    AnchorError(AnchorError),
201    ProgramError(ProgramErrorWithOrigin),
202}
203
204impl std::error::Error for Error {}
205
206impl Display for Error {
207    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
208        match self {
209            Error::AnchorError(ae) => Display::fmt(&ae, f),
210            Error::ProgramError(pe) => Display::fmt(&pe, f),
211        }
212    }
213}
214
215impl From<AnchorError> for Error {
216    fn from(ae: AnchorError) -> Self {
217        Self::AnchorError(ae)
218    }
219}
220
221impl From<ProgramError> for Error {
222    fn from(program_error: ProgramError) -> Self {
223        Self::ProgramError(program_error.into())
224    }
225}
226impl From<BorshIoError> for Error {
227    fn from(error: BorshIoError) -> Self {
228        Error::ProgramError(ProgramError::from(error).into())
229    }
230}
231
232impl From<ProgramErrorWithOrigin> for Error {
233    fn from(pe: ProgramErrorWithOrigin) -> Self {
234        Self::ProgramError(pe)
235    }
236}
237
238impl Error {
239    pub fn log(&self) {
240        match self {
241            Error::ProgramError(program_error) => program_error.log(),
242            Error::AnchorError(anchor_error) => anchor_error.log(),
243        }
244    }
245
246    pub fn with_account_name(mut self, account_name: impl ToString) -> Self {
247        match &mut self {
248            Error::AnchorError(ae) => {
249                ae.error_origin = Some(ErrorOrigin::AccountName(account_name.to_string()));
250            }
251            Error::ProgramError(pe) => {
252                pe.error_origin = Some(ErrorOrigin::AccountName(account_name.to_string()));
253            }
254        };
255        self
256    }
257
258    pub fn with_source(mut self, source: Source) -> Self {
259        match &mut self {
260            Error::AnchorError(ae) => {
261                ae.error_origin = Some(ErrorOrigin::Source(source));
262            }
263            Error::ProgramError(pe) => {
264                pe.error_origin = Some(ErrorOrigin::Source(source));
265            }
266        };
267        self
268    }
269
270    pub fn with_pubkeys(mut self, pubkeys: (Pubkey, Pubkey)) -> Self {
271        let pubkeys = Some(ComparedValues::Pubkeys((pubkeys.0, pubkeys.1)));
272        match &mut self {
273            Error::AnchorError(ae) => ae.compared_values = pubkeys,
274            Error::ProgramError(pe) => pe.compared_values = pubkeys,
275        };
276        self
277    }
278
279    pub fn with_values(mut self, values: (impl ToString, impl ToString)) -> Self {
280        match &mut self {
281            Error::AnchorError(ae) => {
282                ae.compared_values = Some(ComparedValues::Values((
283                    values.0.to_string(),
284                    values.1.to_string(),
285                )))
286            }
287            Error::ProgramError(pe) => {
288                pe.compared_values = Some(ComparedValues::Values((
289                    values.0.to_string(),
290                    values.1.to_string(),
291                )))
292            }
293        };
294        self
295    }
296}
297
298#[derive(Debug)]
299pub struct ProgramErrorWithOrigin {
300    pub program_error: ProgramError,
301    pub error_origin: Option<ErrorOrigin>,
302    pub compared_values: Option<ComparedValues>,
303}
304
305// Two ProgramErrors are equal when they have the same error code
306impl PartialEq for ProgramErrorWithOrigin {
307    fn eq(&self, other: &Self) -> bool {
308        self.program_error == other.program_error
309    }
310}
311impl Eq for ProgramErrorWithOrigin {}
312
313impl Display for ProgramErrorWithOrigin {
314    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
315        Display::fmt(&self.program_error, f)
316    }
317}
318
319impl ProgramErrorWithOrigin {
320    pub fn log(&self) {
321        match &self.error_origin {
322            None => {
323                anchor_lang::solana_program::msg!(
324                    "ProgramError occurred. Error Code: {:?}. Error Number: {}. Error Message: {}.",
325                    self.program_error,
326                    u64::from(self.program_error.clone()),
327                    self.program_error
328                );
329            }
330            Some(ErrorOrigin::Source(source)) => {
331                anchor_lang::solana_program::msg!(
332                    "ProgramError thrown in {}:{}. Error Code: {:?}. Error Number: {}. Error Message: {}.",
333                    source.filename,
334                    source.line,
335                    self.program_error,
336                    u64::from(self.program_error.clone()),
337                    self.program_error
338                );
339            }
340            Some(ErrorOrigin::AccountName(account_name)) => {
341                // using sol_log because msg! wrongly interprets 5 inputs as u64
342                anchor_lang::solana_program::log::sol_log(&format!(
343                    "ProgramError caused by account: {}. Error Code: {:?}. Error Number: {}. Error Message: {}.",
344                    account_name,
345                    self.program_error,
346                    u64::from(self.program_error.clone()),
347                    self.program_error
348                ));
349            }
350        }
351        match &self.compared_values {
352            Some(ComparedValues::Pubkeys((left, right))) => {
353                anchor_lang::solana_program::msg!("Left:");
354                left.log();
355                anchor_lang::solana_program::msg!("Right:");
356                right.log();
357            }
358            Some(ComparedValues::Values((left, right))) => {
359                anchor_lang::solana_program::msg!("Left: {}", left);
360                anchor_lang::solana_program::msg!("Right: {}", right);
361            }
362            None => (),
363        }
364    }
365
366    pub fn with_source(mut self, source: Source) -> Self {
367        self.error_origin = Some(ErrorOrigin::Source(source));
368        self
369    }
370
371    pub fn with_account_name(mut self, account_name: impl ToString) -> Self {
372        self.error_origin = Some(ErrorOrigin::AccountName(account_name.to_string()));
373        self
374    }
375}
376
377impl From<ProgramError> for ProgramErrorWithOrigin {
378    fn from(program_error: ProgramError) -> Self {
379        Self {
380            program_error,
381            error_origin: None,
382            compared_values: None,
383        }
384    }
385}
386
387#[derive(Debug)]
388pub enum ComparedValues {
389    Values((String, String)),
390    Pubkeys((Pubkey, Pubkey)),
391}
392
393#[derive(Debug)]
394pub enum ErrorOrigin {
395    Source(Source),
396    AccountName(String),
397}
398
399#[derive(Debug)]
400pub struct AnchorError {
401    pub error_name: String,
402    pub error_code_number: u32,
403    pub error_msg: String,
404    pub error_origin: Option<ErrorOrigin>,
405    pub compared_values: Option<ComparedValues>,
406}
407
408impl AnchorError {
409    pub fn log(&self) {
410        match &self.error_origin {
411            None => {
412                anchor_lang::solana_program::log::sol_log(&format!(
413                    "AnchorError occurred. Error Code: {}. Error Number: {}. Error Message: {}.",
414                    self.error_name, self.error_code_number, self.error_msg
415                ));
416            }
417            Some(ErrorOrigin::Source(source)) => {
418                anchor_lang::solana_program::msg!(
419                    "AnchorError thrown in {}:{}. Error Code: {}. Error Number: {}. Error Message: {}.",
420                    source.filename,
421                    source.line,
422                    self.error_name,
423                    self.error_code_number,
424                    self.error_msg
425                );
426            }
427            Some(ErrorOrigin::AccountName(account_name)) => {
428                anchor_lang::solana_program::log::sol_log(&format!(
429                    "AnchorError caused by account: {}. Error Code: {}. Error Number: {}. Error Message: {}.",
430                    account_name,
431                    self.error_name,
432                    self.error_code_number,
433                    self.error_msg
434                ));
435            }
436        }
437        match &self.compared_values {
438            Some(ComparedValues::Pubkeys((left, right))) => {
439                anchor_lang::solana_program::msg!("Left:");
440                left.log();
441                anchor_lang::solana_program::msg!("Right:");
442                right.log();
443            }
444            Some(ComparedValues::Values((left, right))) => {
445                anchor_lang::solana_program::msg!("Left: {}", left);
446                anchor_lang::solana_program::msg!("Right: {}", right);
447            }
448            None => (),
449        }
450    }
451
452    pub fn with_source(mut self, source: Source) -> Self {
453        self.error_origin = Some(ErrorOrigin::Source(source));
454        self
455    }
456
457    pub fn with_account_name(mut self, account_name: impl ToString) -> Self {
458        self.error_origin = Some(ErrorOrigin::AccountName(account_name.to_string()));
459        self
460    }
461}
462
463impl Display for AnchorError {
464    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
465        Debug::fmt(&self, f)
466    }
467}
468
469/// Two `AnchorError`s are equal when they have the same error code
470impl PartialEq for AnchorError {
471    fn eq(&self, other: &Self) -> bool {
472        self.error_code_number == other.error_code_number
473    }
474}
475
476impl Eq for AnchorError {}
477
478impl std::convert::From<Error> for anchor_lang::solana_program::program_error::ProgramError {
479    fn from(e: Error) -> anchor_lang::solana_program::program_error::ProgramError {
480        match e {
481            Error::AnchorError(AnchorError {
482                error_code_number, ..
483            }) => {
484                anchor_lang::solana_program::program_error::ProgramError::Custom(error_code_number)
485            }
486            Error::ProgramError(program_error) => program_error.program_error,
487        }
488    }
489}
490
491#[derive(Debug)]
492pub struct Source {
493    pub filename: &'static str,
494    pub line: u32,
495}