1use {
2 anchor_attribute_error::error_code,
3 solana_program_error::ProgramError,
4 solana_pubkey::Pubkey,
5 std::{
6 fmt::{Debug, Display},
7 num::TryFromIntError,
8 },
9};
10
11pub const ERROR_CODE_OFFSET: u32 = 6000;
13
14mod anchor_lang {
17 pub(crate) mod error {
18 pub(crate) use crate::{AnchorError, Error};
19 }
20}
21
22#[error_code(offset = 0)]
34pub enum ErrorCode {
35 #[msg("Instruction discriminator not provided")]
38 InstructionMissing = 100,
39 #[msg("Fallback functions are not supported")]
41 InstructionFallbackNotFound,
42 #[msg("The program could not deserialize the given instruction")]
44 InstructionDidNotDeserialize,
45 #[msg("The program could not serialize the given instruction")]
47 InstructionDidNotSerialize,
48
49 #[msg("The program was compiled without idl instructions")]
52 IdlInstructionStub = 1000,
53 #[msg("Invalid program given to the IDL instruction")]
55 IdlInstructionInvalidProgram,
56 #[msg("IDL account must be empty in order to resize, try closing first")]
58 IdlAccountNotEmpty,
59
60 #[msg("The program was compiled without `event-cpi` feature")]
63 EventInstructionStub = 1500,
64
65 #[msg("A mut constraint was violated")]
68 ConstraintMut = 2000,
69 #[msg("A has one constraint was violated")]
71 ConstraintHasOne,
72 #[msg("A signer constraint was violated")]
74 ConstraintSigner,
75 #[msg("A raw constraint was violated")]
77 ConstraintRaw,
78 #[msg("An owner constraint was violated")]
80 ConstraintOwner,
81 #[msg("A rent exemption constraint was violated")]
83 ConstraintRentExempt,
84 #[msg("A seeds constraint was violated")]
86 ConstraintSeeds,
87 #[msg("An executable constraint was violated")]
89 ConstraintExecutable,
90 #[msg("Deprecated Error, feel free to replace with something else")]
92 ConstraintState,
93 #[msg("An associated constraint was violated")]
95 ConstraintAssociated,
96 #[msg("An associated init constraint was violated")]
98 ConstraintAssociatedInit,
99 #[msg("A close constraint was violated")]
101 ConstraintClose,
102 #[msg("An address constraint was violated")]
104 ConstraintAddress,
105 #[msg("Expected zero account discriminant")]
107 ConstraintZero,
108 #[msg("A token mint constraint was violated")]
110 ConstraintTokenMint,
111 #[msg("A token owner constraint was violated")]
113 ConstraintTokenOwner,
114 #[msg("A mint mint authority constraint was violated")]
118 ConstraintMintMintAuthority,
119 #[msg("A mint freeze authority constraint was violated")]
121 ConstraintMintFreezeAuthority,
122 #[msg("A mint decimals constraint was violated")]
124 ConstraintMintDecimals,
125 #[msg("A space constraint was violated")]
127 ConstraintSpace,
128 #[msg("A required account for the constraint is None")]
130 ConstraintAccountIsNone,
131 #[msg("A token account token program constraint was violated")]
135 ConstraintTokenTokenProgram,
136 #[msg("A mint token program constraint was violated")]
138 ConstraintMintTokenProgram,
139 #[msg("An associated token account token program constraint was violated")]
141 ConstraintAssociatedTokenTokenProgram,
142 #[msg("A group pointer extension constraint was violated")]
146 ConstraintMintGroupPointerExtension,
147 #[msg("A group pointer extension authority constraint was violated")]
149 ConstraintMintGroupPointerExtensionAuthority,
150 #[msg("A group pointer extension group address constraint was violated")]
152 ConstraintMintGroupPointerExtensionGroupAddress,
153 #[msg("A group member pointer extension constraint was violated")]
155 ConstraintMintGroupMemberPointerExtension,
156 #[msg("A group member pointer extension authority constraint was violated")]
158 ConstraintMintGroupMemberPointerExtensionAuthority,
159 #[msg("A group member pointer extension group address constraint was violated")]
161 ConstraintMintGroupMemberPointerExtensionMemberAddress,
162 #[msg("A metadata pointer extension constraint was violated")]
164 ConstraintMintMetadataPointerExtension,
165 #[msg("A metadata pointer extension authority constraint was violated")]
167 ConstraintMintMetadataPointerExtensionAuthority,
168 #[msg("A metadata pointer extension metadata address constraint was violated")]
170 ConstraintMintMetadataPointerExtensionMetadataAddress,
171 #[msg("A close authority constraint was violated")]
173 ConstraintMintCloseAuthorityExtension,
174 #[msg("A close authority extension authority constraint was violated")]
176 ConstraintMintCloseAuthorityExtensionAuthority,
177 #[msg("A permanent delegate extension constraint was violated")]
179 ConstraintMintPermanentDelegateExtension,
180 #[msg("A permanent delegate extension delegate constraint was violated")]
182 ConstraintMintPermanentDelegateExtensionDelegate,
183 #[msg("A transfer hook extension constraint was violated")]
185 ConstraintMintTransferHookExtension,
186 #[msg("A transfer hook extension authority constraint was violated")]
188 ConstraintMintTransferHookExtensionAuthority,
189 #[msg("A transfer hook extension transfer hook program id constraint was violated")]
191 ConstraintMintTransferHookExtensionProgramId,
192 #[msg("A duplicate mutable account constraint was violated")]
194 ConstraintDuplicateMutableAccount,
195
196 #[msg("Account is already migrated")]
199 AccountAlreadyMigrated,
200 #[msg("Account must be migrated before exiting")]
202 AccountNotMigrated,
203
204 #[msg("A pausable extension constraint was violated")]
206 ConstraintMintPausableExtension,
207 #[msg("A pausable extension authority constraint was violated")]
209 ConstraintMintPausableAuthority,
210
211 #[msg("A require expression was violated")]
214 RequireViolated = 2500,
215 #[msg("A require_eq expression was violated")]
217 RequireEqViolated,
218 #[msg("A require_keys_eq expression was violated")]
220 RequireKeysEqViolated,
221 #[msg("A require_neq expression was violated")]
223 RequireNeqViolated,
224 #[msg("A require_keys_neq expression was violated")]
226 RequireKeysNeqViolated,
227 #[msg("A require_gt expression was violated")]
229 RequireGtViolated,
230 #[msg("A require_gte expression was violated")]
232 RequireGteViolated,
233
234 #[msg("The account discriminator was already set on this account")]
237 AccountDiscriminatorAlreadySet = 3000,
238 #[msg("No discriminator was found on the account")]
240 AccountDiscriminatorNotFound,
241 #[msg("Account discriminator did not match what was expected")]
243 AccountDiscriminatorMismatch,
244 #[msg("Failed to deserialize the account")]
246 AccountDidNotDeserialize,
247 #[msg("Failed to serialize the account")]
249 AccountDidNotSerialize,
250 #[msg("Not enough account keys given to the instruction")]
252 AccountNotEnoughKeys,
253 #[msg("The given account is not mutable")]
255 AccountNotMutable,
256 #[msg("The given account is owned by a different program than expected")]
258 AccountOwnedByWrongProgram,
259 #[msg("Program ID was not as expected")]
261 InvalidProgramId,
262 #[msg("Program account is not executable")]
264 InvalidProgramExecutable,
265 #[msg("The given account did not sign")]
267 AccountNotSigner,
268 #[msg("The given account is not owned by the system program")]
270 AccountNotSystemOwned,
271 #[msg("The program expected this account to be already initialized")]
273 AccountNotInitialized,
274 #[msg("The given account is not a program data account")]
276 AccountNotProgramData,
277 #[msg("The given account is not the associated token account")]
279 AccountNotAssociatedTokenAccount,
280 #[msg("The given public key does not match the required sysvar")]
282 AccountSysvarMismatch,
283 #[msg("The account reallocation exceeds the MAX_PERMITTED_DATA_INCREASE limit")]
285 AccountReallocExceedsLimit,
286 #[msg("The account was duplicated for more than one reallocation")]
288 AccountDuplicateReallocs,
289
290 #[msg("The declared program id does not match the actual program id")]
293 DeclaredProgramIdMismatch = 4100,
294 #[msg("You cannot/should not initialize the payer account as a program account")]
296 TryingToInitPayerAsProgramAccount = 4101,
297 #[msg("Error during numeric conversion")]
299 InvalidNumericConversion = 4102,
300
301 #[msg("The API being used is deprecated and should no longer be used")]
304 Deprecated = 5000,
305}
306
307#[derive(Debug, PartialEq, Eq)]
308pub enum Error {
309 AnchorError(Box<AnchorError>),
310 ProgramError(Box<ProgramErrorWithOrigin>),
311}
312
313impl std::error::Error for Error {}
314
315impl Display for Error {
316 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
317 match self {
318 Error::AnchorError(ae) => Display::fmt(&ae, f),
319 Error::ProgramError(pe) => Display::fmt(&pe, f),
320 }
321 }
322}
323
324impl From<AnchorError> for Error {
325 fn from(ae: AnchorError) -> Self {
326 Self::AnchorError(Box::new(ae))
327 }
328}
329
330impl From<ProgramError> for Error {
331 fn from(program_error: ProgramError) -> Self {
332 Self::ProgramError(Box::new(program_error.into()))
333 }
334}
335
336#[cfg(feature = "borsh")]
337impl From<borsh::io::Error> for Error {
338 fn from(error: borsh::io::Error) -> Self {
339 Error::ProgramError(Box::new(ProgramError::from(error).into()))
340 }
341}
342
343impl From<ProgramErrorWithOrigin> for Error {
344 fn from(pe: ProgramErrorWithOrigin) -> Self {
345 Self::ProgramError(Box::new(pe))
346 }
347}
348
349impl From<TryFromIntError> for Error {
350 fn from(e: TryFromIntError) -> Self {
351 Self::AnchorError(Box::new(AnchorError {
352 error_name: ErrorCode::InvalidNumericConversion.name(),
353 error_code_number: ErrorCode::InvalidNumericConversion.into(),
354 error_msg: format!("{e}"),
355 error_origin: None,
356 compared_values: None,
357 }))
358 }
359}
360
361impl From<std::convert::Infallible> for Error {
362 fn from(_: std::convert::Infallible) -> Self {
363 unreachable!("Infallible has no inhabitants")
364 }
365}
366
367impl Error {
368 pub fn log(&self) {
369 match self {
370 Error::ProgramError(program_error) => program_error.log(),
371 Error::AnchorError(anchor_error) => anchor_error.log(),
372 }
373 }
374
375 pub fn with_account_name(mut self, account_name: impl ToString) -> Self {
376 match &mut self {
377 Error::AnchorError(ae) => {
378 ae.error_origin = Some(ErrorOrigin::AccountName(account_name.to_string()));
379 }
380 Error::ProgramError(pe) => {
381 pe.error_origin = Some(ErrorOrigin::AccountName(account_name.to_string()));
382 }
383 };
384 self
385 }
386
387 pub fn with_source(mut self, source: Source) -> Self {
388 match &mut self {
389 Error::AnchorError(ae) => {
390 ae.error_origin = Some(ErrorOrigin::Source(source));
391 }
392 Error::ProgramError(pe) => {
393 pe.error_origin = Some(ErrorOrigin::Source(source));
394 }
395 };
396 self
397 }
398
399 pub fn with_pubkeys(mut self, pubkeys: (Pubkey, Pubkey)) -> Self {
400 let pubkeys = Some(ComparedValues::Pubkeys((pubkeys.0, pubkeys.1)));
401 match &mut self {
402 Error::AnchorError(ae) => ae.compared_values = pubkeys,
403 Error::ProgramError(pe) => pe.compared_values = pubkeys,
404 };
405 self
406 }
407
408 pub fn with_values(mut self, values: (impl ToString, impl ToString)) -> Self {
409 match &mut self {
410 Error::AnchorError(ae) => {
411 ae.compared_values = Some(ComparedValues::Values((
412 values.0.to_string(),
413 values.1.to_string(),
414 )))
415 }
416 Error::ProgramError(pe) => {
417 pe.compared_values = Some(ComparedValues::Values((
418 values.0.to_string(),
419 values.1.to_string(),
420 )))
421 }
422 };
423 self
424 }
425}
426
427#[derive(Debug)]
428pub struct ProgramErrorWithOrigin {
429 pub program_error: ProgramError,
430 pub error_origin: Option<ErrorOrigin>,
431 pub compared_values: Option<ComparedValues>,
432}
433
434impl PartialEq for ProgramErrorWithOrigin {
436 fn eq(&self, other: &Self) -> bool {
437 self.program_error == other.program_error
438 }
439}
440impl Eq for ProgramErrorWithOrigin {}
441
442impl Display for ProgramErrorWithOrigin {
443 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
444 Display::fmt(&self.program_error, f)
445 }
446}
447
448impl ProgramErrorWithOrigin {
449 pub fn log(&self) {
450 match &self.error_origin {
451 None => {
452 solana_msg::msg!(
453 "ProgramError occurred. Error Code: {:?}. Error Number: {}. Error Message: {}.",
454 self.program_error,
455 u64::from(self.program_error.clone()),
456 self.program_error
457 );
458 }
459 Some(ErrorOrigin::Source(source)) => {
460 solana_msg::msg!(
461 "ProgramError thrown in {}:{}. Error Code: {:?}. Error Number: {}. Error \
462 Message: {}.",
463 source.filename,
464 source.line,
465 self.program_error,
466 u64::from(self.program_error.clone()),
467 self.program_error
468 );
469 }
470 Some(ErrorOrigin::AccountName(account_name)) => {
471 solana_msg::msg!(&format!(
473 "ProgramError caused by account: {}. Error Code: {:?}. Error Number: {}. \
474 Error Message: {}.",
475 account_name,
476 self.program_error,
477 u64::from(self.program_error.clone()),
478 self.program_error
479 ));
480 }
481 }
482 match &self.compared_values {
483 Some(ComparedValues::Pubkeys((left, right))) => {
484 solana_msg::msg!("Left:");
485 left.log();
486 solana_msg::msg!("Right:");
487 right.log();
488 }
489 Some(ComparedValues::Values((left, right))) => {
490 solana_msg::msg!("Left: {}", left);
491 solana_msg::msg!("Right: {}", right);
492 }
493 None => (),
494 }
495 }
496
497 pub fn with_source(mut self, source: Source) -> Self {
498 self.error_origin = Some(ErrorOrigin::Source(source));
499 self
500 }
501
502 pub fn with_account_name(mut self, account_name: impl ToString) -> Self {
503 self.error_origin = Some(ErrorOrigin::AccountName(account_name.to_string()));
504 self
505 }
506}
507
508impl From<ProgramError> for ProgramErrorWithOrigin {
509 fn from(program_error: ProgramError) -> Self {
510 Self {
511 program_error,
512 error_origin: None,
513 compared_values: None,
514 }
515 }
516}
517
518#[derive(Debug)]
519pub enum ComparedValues {
520 Values((String, String)),
521 Pubkeys((Pubkey, Pubkey)),
522}
523
524#[derive(Debug)]
525pub enum ErrorOrigin {
526 Source(Source),
527 AccountName(String),
528}
529
530#[derive(Debug)]
531pub struct AnchorError {
532 pub error_name: String,
533 pub error_code_number: u32,
534 pub error_msg: String,
535 pub error_origin: Option<ErrorOrigin>,
536 pub compared_values: Option<ComparedValues>,
537}
538
539impl AnchorError {
540 pub fn log(&self) {
541 match &self.error_origin {
542 None => {
543 solana_msg::msg!(
544 "AnchorError occurred. Error Code: {}. Error Number: {}. Error Message: {}.",
545 self.error_name,
546 self.error_code_number,
547 self.error_msg
548 );
549 }
550 Some(ErrorOrigin::Source(source)) => {
551 solana_msg::msg!(
552 "AnchorError thrown in {}:{}. Error Code: {}. Error Number: {}. Error \
553 Message: {}.",
554 source.filename,
555 source.line,
556 self.error_name,
557 self.error_code_number,
558 self.error_msg
559 );
560 }
561 Some(ErrorOrigin::AccountName(account_name)) => {
562 solana_msg::msg!(
563 "AnchorError caused by account: {}. Error Code: {}. Error Number: {}. Error \
564 Message: {}.",
565 account_name,
566 self.error_name,
567 self.error_code_number,
568 self.error_msg
569 );
570 }
571 }
572 match &self.compared_values {
573 Some(ComparedValues::Pubkeys((left, right))) => {
574 solana_msg::msg!("Left:");
575 left.log();
576 solana_msg::msg!("Right:");
577 right.log();
578 }
579 Some(ComparedValues::Values((left, right))) => {
580 solana_msg::msg!("Left: {}", left);
581 solana_msg::msg!("Right: {}", right);
582 }
583 None => (),
584 }
585 }
586
587 pub fn with_source(mut self, source: Source) -> Self {
588 self.error_origin = Some(ErrorOrigin::Source(source));
589 self
590 }
591
592 pub fn with_account_name(mut self, account_name: impl ToString) -> Self {
593 self.error_origin = Some(ErrorOrigin::AccountName(account_name.to_string()));
594 self
595 }
596}
597
598impl Display for AnchorError {
599 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
600 Debug::fmt(&self, f)
601 }
602}
603
604impl PartialEq for AnchorError {
606 fn eq(&self, other: &Self) -> bool {
607 self.error_code_number == other.error_code_number
608 }
609}
610
611impl Eq for AnchorError {}
612
613impl std::convert::From<Error> for ProgramError {
614 fn from(e: Error) -> ProgramError {
615 match e {
616 Error::AnchorError(error) => ProgramError::Custom(error.error_code_number),
617 Error::ProgramError(program_error) => program_error.program_error,
618 }
619 }
620}
621
622#[derive(Debug)]
623pub struct Source {
624 pub filename: &'static str,
625 pub line: u32,
626}