Skip to main content

typhoon_errors/
lib.rs

1#![no_std]
2
3mod error_code;
4mod extension;
5
6pub use {error_code::*, extension::*};
7use {
8    solana_address::error::AddressError,
9    solana_program_error::{ProgramError, ToStr},
10};
11
12pub struct Error {
13    error: ProgramError,
14    account_name: Option<&'static str>,
15}
16
17impl Error {
18    pub fn new(error: impl Into<ProgramError>) -> Self {
19        Error {
20            error: error.into(),
21            account_name: None,
22        }
23    }
24
25    pub fn with_account(mut self, name: &'static str) -> Self {
26        self.account_name = Some(name);
27        self
28    }
29
30    pub fn account_name(&self) -> Option<&str> {
31        self.account_name
32    }
33
34    pub fn to_str<E>(&self) -> &'static str
35    where
36        E: ToStr + TryFrom<u32> + 'static,
37    {
38        if let ProgramError::Custom(code) = self.error {
39            if (100..200).contains(&code) {
40                return self.error.to_str::<ErrorCode>();
41            }
42        }
43        self.error.to_str::<E>()
44    }
45}
46
47impl From<ProgramError> for Error {
48    fn from(error: ProgramError) -> Self {
49        Error {
50            error,
51            account_name: None,
52        }
53    }
54}
55
56impl From<ErrorCode> for Error {
57    fn from(value: ErrorCode) -> Self {
58        Error {
59            error: value.into(),
60            account_name: None,
61        }
62    }
63}
64
65impl From<Error> for ProgramError {
66    fn from(value: Error) -> Self {
67        value.error
68    }
69}
70
71impl From<AddressError> for Error {
72    fn from(value: AddressError) -> Self {
73        Self {
74            error: value.into(),
75            account_name: None,
76        }
77    }
78}
79
80#[cfg(feature = "logging")]
81pub type LogError = ErrorCode;
82
83#[cfg(feature = "logging")]
84#[cold]
85pub fn log_error<E>(error: &Error)
86where
87    E: ToStr + TryFrom<u32> + 'static,
88{
89    solana_program_log::log(error.to_str::<E>());
90
91    if let Some(account_name) = error.account_name() {
92        let mut logger = solana_program_log::Logger::<50>::default();
93        logger.append("Account origin: ");
94        logger.append(unsafe { str::from_utf8_unchecked(account_name.as_bytes()) });
95        logger.log();
96    }
97}
98
99#[macro_export]
100macro_rules! require {
101    ( $constraint:expr, $error:expr ) => {
102        if pinocchio::hint::unlikely(!$constraint) {
103            return Err($error.into());
104        }
105    };
106}