error.rs 18 KB

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