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
6pub const ERROR_CODE_OFFSET: u32 = 6000;
8
9#[error_code(offset = 0)]
22pub enum ErrorCode {
23 #[msg("8 byte instruction identifier 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
45 #[msg("A mut constraint was violated")]
48 ConstraintMut = 2000,
49 #[msg("A has one constraint was violated")]
51 ConstraintHasOne,
52 #[msg("A signer constraint was violated")]
54 ConstraintSigner,
55 #[msg("A raw constraint was violated")]
57 ConstraintRaw,
58 #[msg("An owner constraint was violated")]
60 ConstraintOwner,
61 #[msg("A rent exemption constraint was violated")]
63 ConstraintRentExempt,
64 #[msg("A seeds constraint was violated")]
66 ConstraintSeeds,
67 #[msg("An executable constraint was violated")]
69 ConstraintExecutable,
70 #[msg("A state constraint was violated")]
72 ConstraintState,
73 #[msg("An associated constraint was violated")]
75 ConstraintAssociated,
76 #[msg("An associated init constraint was violated")]
78 ConstraintAssociatedInit,
79 #[msg("A close constraint was violated")]
81 ConstraintClose,
82 #[msg("An address constraint was violated")]
84 ConstraintAddress,
85 #[msg("Expected zero account discriminant")]
87 ConstraintZero,
88 #[msg("A token mint constraint was violated")]
90 ConstraintTokenMint,
91 #[msg("A token owner constraint was violated")]
93 ConstraintTokenOwner,
94 #[msg("A mint mint authority constraint was violated")]
98 ConstraintMintMintAuthority,
99 #[msg("A mint freeze authority constraint was violated")]
101 ConstraintMintFreezeAuthority,
102 #[msg("A mint decimals constraint was violated")]
104 ConstraintMintDecimals,
105 #[msg("A space constraint was violated")]
107 ConstraintSpace,
108
109 #[msg("A require expression was violated")]
112 RequireViolated = 2500,
113 #[msg("A require_eq expression was violated")]
115 RequireEqViolated,
116 #[msg("A require_keys_eq expression was violated")]
118 RequireKeysEqViolated,
119 #[msg("A require_neq expression was violated")]
121 RequireNeqViolated,
122 #[msg("A require_keys_neq expression was violated")]
124 RequireKeysNeqViolated,
125 #[msg("A require_gt expression was violated")]
127 RequireGtViolated,
128 #[msg("A require_gte expression was violated")]
130 RequireGteViolated,
131
132 #[msg("The account discriminator was already set on this account")]
135 AccountDiscriminatorAlreadySet = 3000,
136 #[msg("No 8 byte discriminator was found on the account")]
138 AccountDiscriminatorNotFound,
139 #[msg("8 byte discriminator did not match what was expected")]
141 AccountDiscriminatorMismatch,
142 #[msg("Failed to deserialize the account")]
144 AccountDidNotDeserialize,
145 #[msg("Failed to serialize the account")]
147 AccountDidNotSerialize,
148 #[msg("Not enough account keys given to the instruction")]
150 AccountNotEnoughKeys,
151 #[msg("The given account is not mutable")]
153 AccountNotMutable,
154 #[msg("The given account is owned by a different program than expected")]
156 AccountOwnedByWrongProgram,
157 #[msg("Program ID was not as expected")]
159 InvalidProgramId,
160 #[msg("Program account is not executable")]
162 InvalidProgramExecutable,
163 #[msg("The given account did not sign")]
165 AccountNotSigner,
166 #[msg("The given account is not owned by the system program")]
168 AccountNotSystemOwned,
169 #[msg("The program expected this account to be already initialized")]
171 AccountNotInitialized,
172 #[msg("The given account is not a program data account")]
174 AccountNotProgramData,
175 #[msg("The given account is not the associated token account")]
177 AccountNotAssociatedTokenAccount,
178 #[msg("The given public key does not match the required sysvar")]
180 AccountSysvarMismatch,
181
182 #[msg("The given state account does not have the correct address")]
185 StateInvalidAddress = 4000,
186
187 #[msg("The declared program id does not match the actual program id")]
190 DeclaredProgramIdMismatch = 4100,
191
192 #[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
305impl 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 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
469impl 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}