1use {
2 crate::solana_program::{program_error::ProgramError, pubkey::Pubkey},
3 anchor_lang::error_code,
4 borsh::io::Error as BorshIoError,
5 std::{
6 fmt::{Debug, Display},
7 num::TryFromIntError,
8 },
9};
10
11pub const ERROR_CODE_OFFSET: u32 = 6000;
13
14#[error_code(offset = 0)]
26pub enum ErrorCode {
27 #[msg("Instruction discriminator not provided")]
30 InstructionMissing = 100,
31 #[msg("Fallback functions are not supported")]
33 InstructionFallbackNotFound,
34 #[msg("The program could not deserialize the given instruction")]
36 InstructionDidNotDeserialize,
37 #[msg("The program could not serialize the given instruction")]
39 InstructionDidNotSerialize,
40
41 #[msg("The program was compiled without `event-cpi` feature")]
46 EventInstructionStub = 1500,
47
48 #[msg("A mut constraint was violated")]
51 ConstraintMut = 2000,
52 #[msg("A has one constraint was violated")]
54 ConstraintHasOne,
55 #[msg("A signer constraint was violated")]
57 ConstraintSigner,
58 #[msg("A raw constraint was violated")]
60 ConstraintRaw,
61 #[msg("An owner constraint was violated")]
63 ConstraintOwner,
64 #[msg("A rent exemption constraint was violated")]
66 ConstraintRentExempt,
67 #[msg("A seeds constraint was violated")]
69 ConstraintSeeds,
70 #[msg("An executable constraint was violated")]
72 ConstraintExecutable,
73 #[msg("Deprecated Error, feel free to replace with something else")]
75 ConstraintState,
76 #[msg("An associated constraint was violated")]
78 ConstraintAssociated,
79 #[msg("An associated init constraint was violated")]
81 ConstraintAssociatedInit,
82 #[msg("A close constraint was violated")]
84 ConstraintClose,
85 #[msg("An address constraint was violated")]
87 ConstraintAddress,
88 #[msg("Expected zero account discriminant")]
90 ConstraintZero,
91 #[msg("A token mint constraint was violated")]
93 ConstraintTokenMint,
94 #[msg("A token owner constraint was violated")]
96 ConstraintTokenOwner,
97 #[msg("A mint mint authority constraint was violated")]
101 ConstraintMintMintAuthority,
102 #[msg("A mint freeze authority constraint was violated")]
104 ConstraintMintFreezeAuthority,
105 #[msg("A mint decimals constraint was violated")]
107 ConstraintMintDecimals,
108 #[msg("A space constraint was violated")]
110 ConstraintSpace,
111 #[msg("A required account for the constraint is None")]
113 ConstraintAccountIsNone,
114 #[msg("A token account token program constraint was violated")]
118 ConstraintTokenTokenProgram,
119 #[msg("A mint token program constraint was violated")]
121 ConstraintMintTokenProgram,
122 #[msg("An associated token account token program constraint was violated")]
124 ConstraintAssociatedTokenTokenProgram,
125 #[msg("A group pointer extension constraint was violated")]
129 ConstraintMintGroupPointerExtension,
130 #[msg("A group pointer extension authority constraint was violated")]
132 ConstraintMintGroupPointerExtensionAuthority,
133 #[msg("A group pointer extension group address constraint was violated")]
135 ConstraintMintGroupPointerExtensionGroupAddress,
136 #[msg("A group member pointer extension constraint was violated")]
138 ConstraintMintGroupMemberPointerExtension,
139 #[msg("A group member pointer extension authority constraint was violated")]
141 ConstraintMintGroupMemberPointerExtensionAuthority,
142 #[msg("A group member pointer extension group address constraint was violated")]
144 ConstraintMintGroupMemberPointerExtensionMemberAddress,
145 #[msg("A metadata pointer extension constraint was violated")]
147 ConstraintMintMetadataPointerExtension,
148 #[msg("A metadata pointer extension authority constraint was violated")]
150 ConstraintMintMetadataPointerExtensionAuthority,
151 #[msg("A metadata pointer extension metadata address constraint was violated")]
153 ConstraintMintMetadataPointerExtensionMetadataAddress,
154 #[msg("A close authority constraint was violated")]
156 ConstraintMintCloseAuthorityExtension,
157 #[msg("A close authority extension authority constraint was violated")]
159 ConstraintMintCloseAuthorityExtensionAuthority,
160 #[msg("A permanent delegate extension constraint was violated")]
162 ConstraintMintPermanentDelegateExtension,
163 #[msg("A permanent delegate extension delegate constraint was violated")]
165 ConstraintMintPermanentDelegateExtensionDelegate,
166 #[msg("A transfer hook extension constraint was violated")]
168 ConstraintMintTransferHookExtension,
169 #[msg("A transfer hook extension authority constraint was violated")]
171 ConstraintMintTransferHookExtensionAuthority,
172 #[msg("A transfer hook extension transfer hook program id constraint was violated")]
174 ConstraintMintTransferHookExtensionProgramId,
175 #[msg("A duplicate mutable account constraint was violated")]
177 ConstraintDuplicateMutableAccount,
178
179 #[msg("Account is already migrated")]
182 AccountAlreadyMigrated,
183 #[msg("Account must be migrated before exiting")]
185 AccountNotMigrated,
186
187 #[msg("A require expression was violated")]
190 RequireViolated = 2500,
191 #[msg("A require_eq expression was violated")]
193 RequireEqViolated,
194 #[msg("A require_keys_eq expression was violated")]
196 RequireKeysEqViolated,
197 #[msg("A require_neq expression was violated")]
199 RequireNeqViolated,
200 #[msg("A require_keys_neq expression was violated")]
202 RequireKeysNeqViolated,
203 #[msg("A require_gt expression was violated")]
205 RequireGtViolated,
206 #[msg("A require_gte expression was violated")]
208 RequireGteViolated,
209
210 #[msg("The account discriminator was already set on this account")]
213 AccountDiscriminatorAlreadySet = 3000,
214 #[msg("No discriminator was found on the account")]
216 AccountDiscriminatorNotFound,
217 #[msg("Account discriminator did not match what was expected")]
219 AccountDiscriminatorMismatch,
220 #[msg("Failed to deserialize the account")]
222 AccountDidNotDeserialize,
223 #[msg("Failed to serialize the account")]
225 AccountDidNotSerialize,
226 #[msg("Not enough account keys given to the instruction")]
228 AccountNotEnoughKeys,
229 #[msg("The given account is not mutable")]
231 AccountNotMutable,
232 #[msg("The given account is owned by a different program than expected")]
234 AccountOwnedByWrongProgram,
235 #[msg("Program ID was not as expected")]
237 InvalidProgramId,
238 #[msg("Program account is not executable")]
240 InvalidProgramExecutable,
241 #[msg("The given account did not sign")]
243 AccountNotSigner,
244 #[msg("The given account is not owned by the system program")]
246 AccountNotSystemOwned,
247 #[msg("The program expected this account to be already initialized")]
249 AccountNotInitialized,
250 #[msg("The given account is not a program data account")]
252 AccountNotProgramData,
253 #[msg("The given account is not the associated token account")]
255 AccountNotAssociatedTokenAccount,
256 #[msg("The given public key does not match the required sysvar")]
258 AccountSysvarMismatch,
259 #[msg("The account reallocation exceeds the MAX_PERMITTED_DATA_INCREASE limit")]
261 AccountReallocExceedsLimit,
262 #[msg("The account was duplicated for more than one reallocation")]
264 AccountDuplicateReallocs,
265
266 #[msg("The declared program id does not match the actual program id")]
269 DeclaredProgramIdMismatch = 4100,
270 #[msg("You cannot/should not initialize the payer account as a program account")]
272 TryingToInitPayerAsProgramAccount = 4101,
273 #[msg("Error during numeric conversion")]
275 InvalidNumericConversion = 4102,
276
277 #[msg("The API being used is deprecated and should no longer be used")]
280 Deprecated = 5000,
281}
282
283#[derive(Debug, PartialEq, Eq)]
284pub enum Error {
285 AnchorError(Box<AnchorError>),
286 ProgramError(Box<ProgramErrorWithOrigin>),
287}
288
289impl std::error::Error for Error {}
290
291impl Display for Error {
292 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
293 match self {
294 Error::AnchorError(ae) => Display::fmt(&ae, f),
295 Error::ProgramError(pe) => Display::fmt(&pe, f),
296 }
297 }
298}
299
300impl From<AnchorError> for Error {
301 fn from(ae: AnchorError) -> Self {
302 Self::AnchorError(Box::new(ae))
303 }
304}
305
306impl From<ProgramError> for Error {
307 fn from(program_error: ProgramError) -> Self {
308 Self::ProgramError(Box::new(program_error.into()))
309 }
310}
311impl From<BorshIoError> for Error {
312 fn from(error: BorshIoError) -> Self {
313 Error::ProgramError(Box::new(ProgramError::from(error).into()))
314 }
315}
316
317impl From<ProgramErrorWithOrigin> for Error {
318 fn from(pe: ProgramErrorWithOrigin) -> Self {
319 Self::ProgramError(Box::new(pe))
320 }
321}
322
323impl From<TryFromIntError> for Error {
324 fn from(e: TryFromIntError) -> Self {
325 Self::AnchorError(Box::new(AnchorError {
326 error_name: ErrorCode::InvalidNumericConversion.name(),
327 error_code_number: ErrorCode::InvalidNumericConversion.into(),
328 error_msg: format!("{e}"),
329 error_origin: None,
330 compared_values: None,
331 }))
332 }
333}
334
335impl Error {
336 pub fn log(&self) {
337 match self {
338 Error::ProgramError(program_error) => program_error.log(),
339 Error::AnchorError(anchor_error) => anchor_error.log(),
340 }
341 }
342
343 pub fn with_account_name(mut self, account_name: impl ToString) -> Self {
344 match &mut self {
345 Error::AnchorError(ae) => {
346 ae.error_origin = Some(ErrorOrigin::AccountName(account_name.to_string()));
347 }
348 Error::ProgramError(pe) => {
349 pe.error_origin = Some(ErrorOrigin::AccountName(account_name.to_string()));
350 }
351 };
352 self
353 }
354
355 pub fn with_source(mut self, source: Source) -> Self {
356 match &mut self {
357 Error::AnchorError(ae) => {
358 ae.error_origin = Some(ErrorOrigin::Source(source));
359 }
360 Error::ProgramError(pe) => {
361 pe.error_origin = Some(ErrorOrigin::Source(source));
362 }
363 };
364 self
365 }
366
367 pub fn with_pubkeys(mut self, pubkeys: (Pubkey, Pubkey)) -> Self {
368 let pubkeys = Some(ComparedValues::Pubkeys((pubkeys.0, pubkeys.1)));
369 match &mut self {
370 Error::AnchorError(ae) => ae.compared_values = pubkeys,
371 Error::ProgramError(pe) => pe.compared_values = pubkeys,
372 };
373 self
374 }
375
376 pub fn with_values(mut self, values: (impl ToString, impl ToString)) -> Self {
377 match &mut self {
378 Error::AnchorError(ae) => {
379 ae.compared_values = Some(ComparedValues::Values((
380 values.0.to_string(),
381 values.1.to_string(),
382 )))
383 }
384 Error::ProgramError(pe) => {
385 pe.compared_values = Some(ComparedValues::Values((
386 values.0.to_string(),
387 values.1.to_string(),
388 )))
389 }
390 };
391 self
392 }
393}
394
395#[derive(Debug)]
396pub struct ProgramErrorWithOrigin {
397 pub program_error: ProgramError,
398 pub error_origin: Option<ErrorOrigin>,
399 pub compared_values: Option<ComparedValues>,
400}
401
402impl PartialEq for ProgramErrorWithOrigin {
404 fn eq(&self, other: &Self) -> bool {
405 self.program_error == other.program_error
406 }
407}
408impl Eq for ProgramErrorWithOrigin {}
409
410impl Display for ProgramErrorWithOrigin {
411 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
412 Display::fmt(&self.program_error, f)
413 }
414}
415
416impl ProgramErrorWithOrigin {
417 pub fn log(&self) {
418 match &self.error_origin {
419 None => {
420 anchor_lang::solana_program::msg!(
421 "ProgramError occurred. Error Code: {:?}. Error Number: {}. Error Message: {}.",
422 self.program_error,
423 u64::from(self.program_error.clone()),
424 self.program_error
425 );
426 }
427 Some(ErrorOrigin::Source(source)) => {
428 anchor_lang::solana_program::msg!(
429 "ProgramError thrown in {}:{}. Error Code: {:?}. Error Number: {}. Error \
430 Message: {}.",
431 source.filename,
432 source.line,
433 self.program_error,
434 u64::from(self.program_error.clone()),
435 self.program_error
436 );
437 }
438 Some(ErrorOrigin::AccountName(account_name)) => {
439 anchor_lang::solana_program::log::sol_log(&format!(
441 "ProgramError caused by account: {}. Error Code: {:?}. Error Number: {}. \
442 Error Message: {}.",
443 account_name,
444 self.program_error,
445 u64::from(self.program_error.clone()),
446 self.program_error
447 ));
448 }
449 }
450 match &self.compared_values {
451 Some(ComparedValues::Pubkeys((left, right))) => {
452 anchor_lang::solana_program::msg!("Left:");
453 left.log();
454 anchor_lang::solana_program::msg!("Right:");
455 right.log();
456 }
457 Some(ComparedValues::Values((left, right))) => {
458 anchor_lang::solana_program::msg!("Left: {}", left);
459 anchor_lang::solana_program::msg!("Right: {}", right);
460 }
461 None => (),
462 }
463 }
464
465 pub fn with_source(mut self, source: Source) -> Self {
466 self.error_origin = Some(ErrorOrigin::Source(source));
467 self
468 }
469
470 pub fn with_account_name(mut self, account_name: impl ToString) -> Self {
471 self.error_origin = Some(ErrorOrigin::AccountName(account_name.to_string()));
472 self
473 }
474}
475
476impl From<ProgramError> for ProgramErrorWithOrigin {
477 fn from(program_error: ProgramError) -> Self {
478 Self {
479 program_error,
480 error_origin: None,
481 compared_values: None,
482 }
483 }
484}
485
486#[derive(Debug)]
487pub enum ComparedValues {
488 Values((String, String)),
489 Pubkeys((Pubkey, Pubkey)),
490}
491
492#[derive(Debug)]
493pub enum ErrorOrigin {
494 Source(Source),
495 AccountName(String),
496}
497
498#[derive(Debug)]
499pub struct AnchorError {
500 pub error_name: String,
501 pub error_code_number: u32,
502 pub error_msg: String,
503 pub error_origin: Option<ErrorOrigin>,
504 pub compared_values: Option<ComparedValues>,
505}
506
507impl AnchorError {
508 pub fn log(&self) {
509 match &self.error_origin {
510 None => {
511 anchor_lang::solana_program::log::sol_log(&format!(
512 "AnchorError occurred. Error Code: {}. Error Number: {}. Error Message: {}.",
513 self.error_name, self.error_code_number, self.error_msg
514 ));
515 }
516 Some(ErrorOrigin::Source(source)) => {
517 anchor_lang::solana_program::msg!(
518 "AnchorError thrown in {}:{}. Error Code: {}. Error Number: {}. Error \
519 Message: {}.",
520 source.filename,
521 source.line,
522 self.error_name,
523 self.error_code_number,
524 self.error_msg
525 );
526 }
527 Some(ErrorOrigin::AccountName(account_name)) => {
528 anchor_lang::solana_program::log::sol_log(&format!(
529 "AnchorError caused by account: {}. Error Code: {}. Error Number: {}. Error \
530 Message: {}.",
531 account_name, self.error_name, self.error_code_number, self.error_msg
532 ));
533 }
534 }
535 match &self.compared_values {
536 Some(ComparedValues::Pubkeys((left, right))) => {
537 anchor_lang::solana_program::msg!("Left:");
538 left.log();
539 anchor_lang::solana_program::msg!("Right:");
540 right.log();
541 }
542 Some(ComparedValues::Values((left, right))) => {
543 anchor_lang::solana_program::msg!("Left: {}", left);
544 anchor_lang::solana_program::msg!("Right: {}", right);
545 }
546 None => (),
547 }
548 }
549
550 pub fn with_source(mut self, source: Source) -> Self {
551 self.error_origin = Some(ErrorOrigin::Source(source));
552 self
553 }
554
555 pub fn with_account_name(mut self, account_name: impl ToString) -> Self {
556 self.error_origin = Some(ErrorOrigin::AccountName(account_name.to_string()));
557 self
558 }
559}
560
561impl Display for AnchorError {
562 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
563 Debug::fmt(&self, f)
564 }
565}
566
567impl PartialEq for AnchorError {
569 fn eq(&self, other: &Self) -> bool {
570 self.error_code_number == other.error_code_number
571 }
572}
573
574impl Eq for AnchorError {}
575
576impl std::convert::From<Error> for anchor_lang::solana_program::program_error::ProgramError {
577 fn from(e: Error) -> anchor_lang::solana_program::program_error::ProgramError {
578 match e {
579 Error::AnchorError(error) => {
580 anchor_lang::solana_program::program_error::ProgramError::Custom(
581 error.error_code_number,
582 )
583 }
584 Error::ProgramError(program_error) => program_error.program_error,
585 }
586 }
587}
588
589#[derive(Debug)]
590pub struct Source {
591 pub filename: &'static str,
592 pub line: u32,
593}