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