error.rs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  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. // Constraints
  44. /// 2000 - A mut constraint was violated
  45. #[msg("A mut constraint was violated")]
  46. ConstraintMut = 2000,
  47. /// 2001 - A has one constraint was violated
  48. #[msg("A has one constraint was violated")]
  49. ConstraintHasOne,
  50. /// 2002 - A signer constraint was violated
  51. #[msg("A signer constraint was violated")]
  52. ConstraintSigner,
  53. /// 2003 - A raw constraint was violated
  54. #[msg("A raw constraint was violated")]
  55. ConstraintRaw,
  56. /// 2004 - An owner constraint was violated
  57. #[msg("An owner constraint was violated")]
  58. ConstraintOwner,
  59. /// 2005 - A rent exemption constraint was violated
  60. #[msg("A rent exemption constraint was violated")]
  61. ConstraintRentExempt,
  62. /// 2006 - A seeds constraint was violated
  63. #[msg("A seeds constraint was violated")]
  64. ConstraintSeeds,
  65. /// 2007 - An executable constraint was violated
  66. #[msg("An executable constraint was violated")]
  67. ConstraintExecutable,
  68. /// 2008 - Deprecated Error, feel free to replace with something else
  69. #[msg("Deprecated Error, feel free to replace with something else")]
  70. ConstraintState,
  71. /// 2009 - An associated constraint was violated
  72. #[msg("An associated constraint was violated")]
  73. ConstraintAssociated,
  74. /// 2010 - An associated init constraint was violated
  75. #[msg("An associated init constraint was violated")]
  76. ConstraintAssociatedInit,
  77. /// 2011 - A close constraint was violated
  78. #[msg("A close constraint was violated")]
  79. ConstraintClose,
  80. /// 2012 - An address constraint was violated
  81. #[msg("An address constraint was violated")]
  82. ConstraintAddress,
  83. /// 2013 - Expected zero account discriminant
  84. #[msg("Expected zero account discriminant")]
  85. ConstraintZero,
  86. /// 2014 - A token mint constraint was violated
  87. #[msg("A token mint constraint was violated")]
  88. ConstraintTokenMint,
  89. /// 2015 - A token owner constraint was violated
  90. #[msg("A token owner constraint was violated")]
  91. ConstraintTokenOwner,
  92. /// The mint mint is intentional -> a mint authority for the mint.
  93. ///
  94. /// 2016 - A mint mint authority constraint was violated
  95. #[msg("A mint mint authority constraint was violated")]
  96. ConstraintMintMintAuthority,
  97. /// 2017 - A mint freeze authority constraint was violated
  98. #[msg("A mint freeze authority constraint was violated")]
  99. ConstraintMintFreezeAuthority,
  100. /// 2018 - A mint decimals constraint was violated
  101. #[msg("A mint decimals constraint was violated")]
  102. ConstraintMintDecimals,
  103. /// 2019 - A space constraint was violated
  104. #[msg("A space constraint was violated")]
  105. ConstraintSpace,
  106. /// 2020 - A required account for the constraint is None
  107. #[msg("A required account for the constraint is None")]
  108. ConstraintAccountIsNone,
  109. // Require
  110. /// 2500 - A require expression was violated
  111. #[msg("A require expression was violated")]
  112. RequireViolated = 2500,
  113. /// 2501 - A require_eq expression was violated
  114. #[msg("A require_eq expression was violated")]
  115. RequireEqViolated,
  116. /// 2502 - A require_keys_eq expression was violated
  117. #[msg("A require_keys_eq expression was violated")]
  118. RequireKeysEqViolated,
  119. /// 2503 - A require_neq expression was violated
  120. #[msg("A require_neq expression was violated")]
  121. RequireNeqViolated,
  122. /// 2504 - A require_keys_neq expression was violated
  123. #[msg("A require_keys_neq expression was violated")]
  124. RequireKeysNeqViolated,
  125. /// 2505 - A require_gt expression was violated
  126. #[msg("A require_gt expression was violated")]
  127. RequireGtViolated,
  128. /// 2506 - A require_gte expression was violated
  129. #[msg("A require_gte expression was violated")]
  130. RequireGteViolated,
  131. // Accounts.
  132. /// 3000 - The account discriminator was already set on this account
  133. #[msg("The account discriminator was already set on this account")]
  134. AccountDiscriminatorAlreadySet = 3000,
  135. /// 3001 - No 8 byte discriminator was found on the account
  136. #[msg("No 8 byte discriminator was found on the account")]
  137. AccountDiscriminatorNotFound,
  138. /// 3002 - 8 byte discriminator did not match what was expected
  139. #[msg("8 byte discriminator did not match what was expected")]
  140. AccountDiscriminatorMismatch,
  141. /// 3003 - Failed to deserialize the account
  142. #[msg("Failed to deserialize the account")]
  143. AccountDidNotDeserialize,
  144. /// 3004 - Failed to serialize the account
  145. #[msg("Failed to serialize the account")]
  146. AccountDidNotSerialize,
  147. /// 3005 - Not enough account keys given to the instruction
  148. #[msg("Not enough account keys given to the instruction")]
  149. AccountNotEnoughKeys,
  150. /// 3006 - The given account is not mutable
  151. #[msg("The given account is not mutable")]
  152. AccountNotMutable,
  153. /// 3007 - The given account is owned by a different program than expected
  154. #[msg("The given account is owned by a different program than expected")]
  155. AccountOwnedByWrongProgram,
  156. /// 3008 - Program ID was not as expected
  157. #[msg("Program ID was not as expected")]
  158. InvalidProgramId,
  159. /// 3009 - Program account is not executable
  160. #[msg("Program account is not executable")]
  161. InvalidProgramExecutable,
  162. /// 3010 - The given account did not sign
  163. #[msg("The given account did not sign")]
  164. AccountNotSigner,
  165. /// 3011 - The given account is not owned by the system program
  166. #[msg("The given account is not owned by the system program")]
  167. AccountNotSystemOwned,
  168. /// 3012 - The program expected this account to be already initialized
  169. #[msg("The program expected this account to be already initialized")]
  170. AccountNotInitialized,
  171. /// 3013 - The given account is not a program data account
  172. #[msg("The given account is not a program data account")]
  173. AccountNotProgramData,
  174. /// 3014 - The given account is not the associated token account
  175. #[msg("The given account is not the associated token account")]
  176. AccountNotAssociatedTokenAccount,
  177. /// 3015 - The given public key does not match the required sysvar
  178. #[msg("The given public key does not match the required sysvar")]
  179. AccountSysvarMismatch,
  180. /// 3016 - The account reallocation exceeds the MAX_PERMITTED_DATA_INCREASE limit
  181. #[msg("The account reallocation exceeds the MAX_PERMITTED_DATA_INCREASE limit")]
  182. AccountReallocExceedsLimit,
  183. /// 3017 - The account was duplicated for more than one reallocation
  184. #[msg("The account was duplicated for more than one reallocation")]
  185. AccountDuplicateReallocs,
  186. // Miscellaneous
  187. /// 4100 - The declared program id does not match actual program id
  188. #[msg("The declared program id does not match the actual program id")]
  189. DeclaredProgramIdMismatch = 4100,
  190. /// 4101 - You cannot/should not initialize the payer account as a program account
  191. #[msg("You cannot/should not initialize the payer account as a program account")]
  192. TryingToInitPayerAsProgramAccount = 4101,
  193. // Deprecated
  194. /// 5000 - The API being used is deprecated and should no longer be used
  195. #[msg("The API being used is deprecated and should no longer be used")]
  196. Deprecated = 5000,
  197. }
  198. #[derive(Debug, PartialEq, Eq)]
  199. pub enum Error {
  200. AnchorError(AnchorError),
  201. ProgramError(ProgramErrorWithOrigin),
  202. }
  203. impl std::error::Error for Error {}
  204. impl Display for Error {
  205. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  206. match self {
  207. Error::AnchorError(ae) => Display::fmt(&ae, f),
  208. Error::ProgramError(pe) => Display::fmt(&pe, f),
  209. }
  210. }
  211. }
  212. impl From<AnchorError> for Error {
  213. fn from(ae: AnchorError) -> Self {
  214. Self::AnchorError(ae)
  215. }
  216. }
  217. impl From<ProgramError> for Error {
  218. fn from(program_error: ProgramError) -> Self {
  219. Self::ProgramError(program_error.into())
  220. }
  221. }
  222. impl From<BorshIoError> for Error {
  223. fn from(error: BorshIoError) -> Self {
  224. Error::ProgramError(ProgramError::from(error).into())
  225. }
  226. }
  227. impl From<ProgramErrorWithOrigin> for Error {
  228. fn from(pe: ProgramErrorWithOrigin) -> Self {
  229. Self::ProgramError(pe)
  230. }
  231. }
  232. impl Error {
  233. pub fn log(&self) {
  234. match self {
  235. Error::ProgramError(program_error) => program_error.log(),
  236. Error::AnchorError(anchor_error) => anchor_error.log(),
  237. }
  238. }
  239. pub fn with_account_name(mut self, account_name: impl ToString) -> Self {
  240. match &mut self {
  241. Error::AnchorError(ae) => {
  242. ae.error_origin = Some(ErrorOrigin::AccountName(account_name.to_string()));
  243. }
  244. Error::ProgramError(pe) => {
  245. pe.error_origin = Some(ErrorOrigin::AccountName(account_name.to_string()));
  246. }
  247. };
  248. self
  249. }
  250. pub fn with_source(mut self, source: Source) -> Self {
  251. match &mut self {
  252. Error::AnchorError(ae) => {
  253. ae.error_origin = Some(ErrorOrigin::Source(source));
  254. }
  255. Error::ProgramError(pe) => {
  256. pe.error_origin = Some(ErrorOrigin::Source(source));
  257. }
  258. };
  259. self
  260. }
  261. pub fn with_pubkeys(mut self, pubkeys: (Pubkey, Pubkey)) -> Self {
  262. let pubkeys = Some(ComparedValues::Pubkeys((pubkeys.0, pubkeys.1)));
  263. match &mut self {
  264. Error::AnchorError(ae) => ae.compared_values = pubkeys,
  265. Error::ProgramError(pe) => pe.compared_values = pubkeys,
  266. };
  267. self
  268. }
  269. pub fn with_values(mut self, values: (impl ToString, impl ToString)) -> Self {
  270. match &mut self {
  271. Error::AnchorError(ae) => {
  272. ae.compared_values = Some(ComparedValues::Values((
  273. values.0.to_string(),
  274. values.1.to_string(),
  275. )))
  276. }
  277. Error::ProgramError(pe) => {
  278. pe.compared_values = Some(ComparedValues::Values((
  279. values.0.to_string(),
  280. values.1.to_string(),
  281. )))
  282. }
  283. };
  284. self
  285. }
  286. }
  287. #[derive(Debug)]
  288. pub struct ProgramErrorWithOrigin {
  289. pub program_error: ProgramError,
  290. pub error_origin: Option<ErrorOrigin>,
  291. pub compared_values: Option<ComparedValues>,
  292. }
  293. // Two ProgramErrors are equal when they have the same error code
  294. impl PartialEq for ProgramErrorWithOrigin {
  295. fn eq(&self, other: &Self) -> bool {
  296. self.program_error == other.program_error
  297. }
  298. }
  299. impl Eq for ProgramErrorWithOrigin {}
  300. impl Display for ProgramErrorWithOrigin {
  301. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  302. Display::fmt(&self.program_error, f)
  303. }
  304. }
  305. impl ProgramErrorWithOrigin {
  306. pub fn log(&self) {
  307. match &self.error_origin {
  308. None => {
  309. anchor_lang::solana_program::msg!(
  310. "ProgramError occurred. Error Code: {:?}. Error Number: {}. Error Message: {}.",
  311. self.program_error,
  312. u64::from(self.program_error.clone()),
  313. self.program_error
  314. );
  315. }
  316. Some(ErrorOrigin::Source(source)) => {
  317. anchor_lang::solana_program::msg!(
  318. "ProgramError thrown in {}:{}. Error Code: {:?}. Error Number: {}. Error Message: {}.",
  319. source.filename,
  320. source.line,
  321. self.program_error,
  322. u64::from(self.program_error.clone()),
  323. self.program_error
  324. );
  325. }
  326. Some(ErrorOrigin::AccountName(account_name)) => {
  327. // using sol_log because msg! wrongly interprets 5 inputs as u64
  328. anchor_lang::solana_program::log::sol_log(&format!(
  329. "ProgramError caused by account: {}. Error Code: {:?}. Error Number: {}. Error Message: {}.",
  330. account_name,
  331. self.program_error,
  332. u64::from(self.program_error.clone()),
  333. self.program_error
  334. ));
  335. }
  336. }
  337. match &self.compared_values {
  338. Some(ComparedValues::Pubkeys((left, right))) => {
  339. anchor_lang::solana_program::msg!("Left:");
  340. left.log();
  341. anchor_lang::solana_program::msg!("Right:");
  342. right.log();
  343. }
  344. Some(ComparedValues::Values((left, right))) => {
  345. anchor_lang::solana_program::msg!("Left: {}", left);
  346. anchor_lang::solana_program::msg!("Right: {}", right);
  347. }
  348. None => (),
  349. }
  350. }
  351. pub fn with_source(mut self, source: Source) -> Self {
  352. self.error_origin = Some(ErrorOrigin::Source(source));
  353. self
  354. }
  355. pub fn with_account_name(mut self, account_name: impl ToString) -> Self {
  356. self.error_origin = Some(ErrorOrigin::AccountName(account_name.to_string()));
  357. self
  358. }
  359. }
  360. impl From<ProgramError> for ProgramErrorWithOrigin {
  361. fn from(program_error: ProgramError) -> Self {
  362. Self {
  363. program_error,
  364. error_origin: None,
  365. compared_values: None,
  366. }
  367. }
  368. }
  369. #[derive(Debug)]
  370. pub enum ComparedValues {
  371. Values((String, String)),
  372. Pubkeys((Pubkey, Pubkey)),
  373. }
  374. #[derive(Debug)]
  375. pub enum ErrorOrigin {
  376. Source(Source),
  377. AccountName(String),
  378. }
  379. #[derive(Debug)]
  380. pub struct AnchorError {
  381. pub error_name: String,
  382. pub error_code_number: u32,
  383. pub error_msg: String,
  384. pub error_origin: Option<ErrorOrigin>,
  385. pub compared_values: Option<ComparedValues>,
  386. }
  387. impl AnchorError {
  388. pub fn log(&self) {
  389. match &self.error_origin {
  390. None => {
  391. anchor_lang::solana_program::log::sol_log(&format!(
  392. "AnchorError occurred. Error Code: {}. Error Number: {}. Error Message: {}.",
  393. self.error_name, self.error_code_number, self.error_msg
  394. ));
  395. }
  396. Some(ErrorOrigin::Source(source)) => {
  397. anchor_lang::solana_program::msg!(
  398. "AnchorError thrown in {}:{}. Error Code: {}. Error Number: {}. Error Message: {}.",
  399. source.filename,
  400. source.line,
  401. self.error_name,
  402. self.error_code_number,
  403. self.error_msg
  404. );
  405. }
  406. Some(ErrorOrigin::AccountName(account_name)) => {
  407. anchor_lang::solana_program::log::sol_log(&format!(
  408. "AnchorError caused by account: {}. Error Code: {}. Error Number: {}. Error Message: {}.",
  409. account_name,
  410. self.error_name,
  411. self.error_code_number,
  412. self.error_msg
  413. ));
  414. }
  415. }
  416. match &self.compared_values {
  417. Some(ComparedValues::Pubkeys((left, right))) => {
  418. anchor_lang::solana_program::msg!("Left:");
  419. left.log();
  420. anchor_lang::solana_program::msg!("Right:");
  421. right.log();
  422. }
  423. Some(ComparedValues::Values((left, right))) => {
  424. anchor_lang::solana_program::msg!("Left: {}", left);
  425. anchor_lang::solana_program::msg!("Right: {}", right);
  426. }
  427. None => (),
  428. }
  429. }
  430. pub fn with_source(mut self, source: Source) -> Self {
  431. self.error_origin = Some(ErrorOrigin::Source(source));
  432. self
  433. }
  434. pub fn with_account_name(mut self, account_name: impl ToString) -> Self {
  435. self.error_origin = Some(ErrorOrigin::AccountName(account_name.to_string()));
  436. self
  437. }
  438. }
  439. impl Display for AnchorError {
  440. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  441. Debug::fmt(&self, f)
  442. }
  443. }
  444. /// Two `AnchorError`s are equal when they have the same error code
  445. impl PartialEq for AnchorError {
  446. fn eq(&self, other: &Self) -> bool {
  447. self.error_code_number == other.error_code_number
  448. }
  449. }
  450. impl Eq for AnchorError {}
  451. impl std::convert::From<Error> for anchor_lang::solana_program::program_error::ProgramError {
  452. fn from(e: Error) -> anchor_lang::solana_program::program_error::ProgramError {
  453. match e {
  454. Error::AnchorError(AnchorError {
  455. error_code_number, ..
  456. }) => {
  457. anchor_lang::solana_program::program_error::ProgramError::Custom(error_code_number)
  458. }
  459. Error::ProgramError(program_error) => program_error.program_error,
  460. }
  461. }
  462. }
  463. #[derive(Debug)]
  464. pub struct Source {
  465. pub filename: &'static str,
  466. pub line: u32,
  467. }