error.rs 22 KB

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