|  | 
|  | 1 | +//! Error types | 
|  | 2 | +
 | 
|  | 3 | +use { | 
|  | 4 | +    num_derive::FromPrimitive, | 
|  | 5 | +    solana_program_error::{ProgramError, ToStr}, | 
|  | 6 | +    thiserror::Error, | 
|  | 7 | +}; | 
|  | 8 | + | 
|  | 9 | +/// Errors that may be returned by the Token program. | 
|  | 10 | +#[cfg_attr(test, derive(strum_macros::FromRepr, strum_macros::EnumIter))] | 
|  | 11 | +#[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] | 
|  | 12 | +pub enum TokenError { | 
|  | 13 | +    // 0 | 
|  | 14 | +    /// Lamport balance below rent-exempt threshold. | 
|  | 15 | +    #[error("Lamport balance below rent-exempt threshold")] | 
|  | 16 | +    NotRentExempt, | 
|  | 17 | +    /// Insufficient funds for the operation requested. | 
|  | 18 | +    #[error("Insufficient funds")] | 
|  | 19 | +    InsufficientFunds, | 
|  | 20 | +    /// Invalid Mint. | 
|  | 21 | +    #[error("Invalid Mint")] | 
|  | 22 | +    InvalidMint, | 
|  | 23 | +    /// Account not associated with this Mint. | 
|  | 24 | +    #[error("Account not associated with this Mint")] | 
|  | 25 | +    MintMismatch, | 
|  | 26 | +    /// Owner does not match. | 
|  | 27 | +    #[error("Owner does not match")] | 
|  | 28 | +    OwnerMismatch, | 
|  | 29 | + | 
|  | 30 | +    // 5 | 
|  | 31 | +    /// This token's supply is fixed and new tokens cannot be minted. | 
|  | 32 | +    #[error("Fixed supply")] | 
|  | 33 | +    FixedSupply, | 
|  | 34 | +    /// The account cannot be initialized because it is already being used. | 
|  | 35 | +    #[error("Already in use")] | 
|  | 36 | +    AlreadyInUse, | 
|  | 37 | +    /// Invalid number of provided signers. | 
|  | 38 | +    #[error("Invalid number of provided signers")] | 
|  | 39 | +    InvalidNumberOfProvidedSigners, | 
|  | 40 | +    /// Invalid number of required signers. | 
|  | 41 | +    #[error("Invalid number of required signers")] | 
|  | 42 | +    InvalidNumberOfRequiredSigners, | 
|  | 43 | +    /// State is uninitialized. | 
|  | 44 | +    #[error("State is uninitialized")] | 
|  | 45 | +    UninitializedState, | 
|  | 46 | + | 
|  | 47 | +    // 10 | 
|  | 48 | +    /// Instruction does not support native tokens | 
|  | 49 | +    #[error("Instruction does not support native tokens")] | 
|  | 50 | +    NativeNotSupported, | 
|  | 51 | +    /// Non-native account can only be closed if its balance is zero | 
|  | 52 | +    #[error("Non-native account can only be closed if its balance is zero")] | 
|  | 53 | +    NonNativeHasBalance, | 
|  | 54 | +    /// Invalid instruction | 
|  | 55 | +    #[error("Invalid instruction")] | 
|  | 56 | +    InvalidInstruction, | 
|  | 57 | +    /// State is invalid for requested operation. | 
|  | 58 | +    #[error("State is invalid for requested operation")] | 
|  | 59 | +    InvalidState, | 
|  | 60 | +    /// Operation overflowed | 
|  | 61 | +    #[error("Operation overflowed")] | 
|  | 62 | +    Overflow, | 
|  | 63 | + | 
|  | 64 | +    // 15 | 
|  | 65 | +    /// Account does not support specified authority type. | 
|  | 66 | +    #[error("Account does not support specified authority type")] | 
|  | 67 | +    AuthorityTypeNotSupported, | 
|  | 68 | +    /// This token mint cannot freeze accounts. | 
|  | 69 | +    #[error("This token mint cannot freeze accounts")] | 
|  | 70 | +    MintCannotFreeze, | 
|  | 71 | +    /// Account is frozen; all account operations will fail | 
|  | 72 | +    #[error("Account is frozen")] | 
|  | 73 | +    AccountFrozen, | 
|  | 74 | +    /// Mint decimals mismatch between the client and mint | 
|  | 75 | +    #[error("The provided decimals value different from the Mint decimals")] | 
|  | 76 | +    MintDecimalsMismatch, | 
|  | 77 | +    /// Instruction does not support non-native tokens | 
|  | 78 | +    #[error("Instruction does not support non-native tokens")] | 
|  | 79 | +    NonNativeNotSupported, | 
|  | 80 | +} | 
|  | 81 | +impl From<TokenError> for ProgramError { | 
|  | 82 | +    fn from(e: TokenError) -> Self { | 
|  | 83 | +        ProgramError::Custom(e as u32) | 
|  | 84 | +    } | 
|  | 85 | +} | 
|  | 86 | + | 
|  | 87 | +impl TryFrom<u32> for TokenError { | 
|  | 88 | +    type Error = ProgramError; | 
|  | 89 | +    fn try_from(error: u32) -> Result<Self, Self::Error> { | 
|  | 90 | +        match error { | 
|  | 91 | +            0 => Ok(TokenError::NotRentExempt), | 
|  | 92 | +            1 => Ok(TokenError::InsufficientFunds), | 
|  | 93 | +            2 => Ok(TokenError::InvalidMint), | 
|  | 94 | +            3 => Ok(TokenError::MintMismatch), | 
|  | 95 | +            4 => Ok(TokenError::OwnerMismatch), | 
|  | 96 | +            5 => Ok(TokenError::FixedSupply), | 
|  | 97 | +            6 => Ok(TokenError::AlreadyInUse), | 
|  | 98 | +            7 => Ok(TokenError::InvalidNumberOfProvidedSigners), | 
|  | 99 | +            8 => Ok(TokenError::InvalidNumberOfRequiredSigners), | 
|  | 100 | +            9 => Ok(TokenError::UninitializedState), | 
|  | 101 | +            10 => Ok(TokenError::NativeNotSupported), | 
|  | 102 | +            11 => Ok(TokenError::NonNativeHasBalance), | 
|  | 103 | +            12 => Ok(TokenError::InvalidInstruction), | 
|  | 104 | +            13 => Ok(TokenError::InvalidState), | 
|  | 105 | +            14 => Ok(TokenError::Overflow), | 
|  | 106 | +            15 => Ok(TokenError::AuthorityTypeNotSupported), | 
|  | 107 | +            16 => Ok(TokenError::MintCannotFreeze), | 
|  | 108 | +            17 => Ok(TokenError::AccountFrozen), | 
|  | 109 | +            18 => Ok(TokenError::MintDecimalsMismatch), | 
|  | 110 | +            19 => Ok(TokenError::NonNativeNotSupported), | 
|  | 111 | +            _ => Err(ProgramError::InvalidArgument), | 
|  | 112 | +        } | 
|  | 113 | +    } | 
|  | 114 | +} | 
|  | 115 | + | 
|  | 116 | +impl ToStr for TokenError { | 
|  | 117 | +    fn to_str<E>(&self) -> &'static str { | 
|  | 118 | +        match self { | 
|  | 119 | +            TokenError::NotRentExempt => "Error: Lamport balance below rent-exempt threshold", | 
|  | 120 | +            TokenError::InsufficientFunds => "Error: insufficient funds", | 
|  | 121 | +            TokenError::InvalidMint => "Error: Invalid Mint", | 
|  | 122 | +            TokenError::MintMismatch => "Error: Account not associated with this Mint", | 
|  | 123 | +            TokenError::OwnerMismatch => "Error: owner does not match", | 
|  | 124 | +            TokenError::FixedSupply => "Error: the total supply of this token is fixed", | 
|  | 125 | +            TokenError::AlreadyInUse => "Error: account or token already in use", | 
|  | 126 | +            TokenError::InvalidNumberOfProvidedSigners => { | 
|  | 127 | +                "Error: Invalid number of provided signers" | 
|  | 128 | +            } | 
|  | 129 | +            TokenError::InvalidNumberOfRequiredSigners => { | 
|  | 130 | +                "Error: Invalid number of required signers" | 
|  | 131 | +            } | 
|  | 132 | +            TokenError::UninitializedState => "Error: State is uninitialized", | 
|  | 133 | +            TokenError::NativeNotSupported => "Error: Instruction does not support native tokens", | 
|  | 134 | +            TokenError::NonNativeHasBalance => { | 
|  | 135 | +                "Error: Non-native account can only be closed if its balance is zero" | 
|  | 136 | +            } | 
|  | 137 | +            TokenError::InvalidInstruction => "Error: Invalid instruction", | 
|  | 138 | +            TokenError::InvalidState => "Error: Invalid account state for operation", | 
|  | 139 | +            TokenError::Overflow => "Error: Operation overflowed", | 
|  | 140 | +            TokenError::AuthorityTypeNotSupported => { | 
|  | 141 | +                "Error: Account does not support specified authority type" | 
|  | 142 | +            } | 
|  | 143 | +            TokenError::MintCannotFreeze => "Error: This token mint cannot freeze accounts", | 
|  | 144 | +            TokenError::AccountFrozen => "Error: Account is frozen", | 
|  | 145 | +            TokenError::MintDecimalsMismatch => "Error: decimals different from the Mint decimals", | 
|  | 146 | +            TokenError::NonNativeNotSupported => { | 
|  | 147 | +                "Error: Instruction does not support non-native tokens" | 
|  | 148 | +            } | 
|  | 149 | +        } | 
|  | 150 | +    } | 
|  | 151 | +} | 
|  | 152 | + | 
|  | 153 | +#[cfg(test)] | 
|  | 154 | +mod test { | 
|  | 155 | +    use {super::*, strum::IntoEnumIterator}; | 
|  | 156 | +    #[test] | 
|  | 157 | +    fn test_parse_error_from_primitive_exhaustive() { | 
|  | 158 | +        for variant in TokenError::iter() { | 
|  | 159 | +            let variant_u32 = variant as u32; | 
|  | 160 | +            assert_eq!( | 
|  | 161 | +                TokenError::from_repr(variant_u32 as usize).unwrap(), | 
|  | 162 | +                TokenError::try_from(variant_u32).unwrap() | 
|  | 163 | +            ); | 
|  | 164 | +        } | 
|  | 165 | +    } | 
|  | 166 | +} | 
0 commit comments