1use {
4 num_derive::FromPrimitive,
5 solana_program::{
6 decode_error::DecodeError,
7 msg,
8 program_error::{PrintProgramError, ProgramError},
9 },
10 thiserror::Error,
11};
12
13#[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)]
15pub enum TokenError {
16 #[error("Lamport balance below rent-exempt threshold")]
19 NotRentExempt,
20 #[error("Insufficient funds")]
22 InsufficientFunds,
23 #[error("Invalid Mint")]
25 InvalidMint,
26 #[error("Account not associated with this Mint")]
28 MintMismatch,
29 #[error("Owner does not match")]
31 OwnerMismatch,
32
33 #[error("Fixed supply")]
36 FixedSupply,
37 #[error("Already in use")]
39 AlreadyInUse,
40 #[error("Invalid number of provided signers")]
42 InvalidNumberOfProvidedSigners,
43 #[error("Invalid number of required signers")]
45 InvalidNumberOfRequiredSigners,
46 #[error("State is uninitialized")]
48 UninitializedState,
49
50 #[error("Instruction does not support native tokens")]
53 NativeNotSupported,
54 #[error("Non-native account can only be closed if its balance is zero")]
56 NonNativeHasBalance,
57 #[error("Invalid instruction")]
59 InvalidInstruction,
60 #[error("State is invalid for requested operation")]
62 InvalidState,
63 #[error("Operation overflowed")]
65 Overflow,
66
67 #[error("Account does not support specified authority type")]
70 AuthorityTypeNotSupported,
71 #[error("This token mint cannot freeze accounts")]
73 MintCannotFreeze,
74 #[error("Account is frozen")]
76 AccountFrozen,
77 #[error("The provided decimals value different from the Mint decimals")]
79 MintDecimalsMismatch,
80 #[error("Instruction does not support non-native tokens")]
82 NonNativeNotSupported,
83
84 #[error("Extension type does not match already existing extensions")]
87 ExtensionTypeMismatch,
88 #[error("Extension does not match the base type provided")]
90 ExtensionBaseMismatch,
91 #[error("Extension already initialized on this account")]
93 ExtensionAlreadyInitialized,
94 #[error("An account can only be closed if its confidential balance is zero")]
96 ConfidentialTransferAccountHasBalance,
97 #[error("Account not approved for confidential transfers")]
99 ConfidentialTransferAccountNotApproved,
100
101 #[error("Account not accepting deposits or transfers")]
104 ConfidentialTransferDepositsAndTransfersDisabled,
105 #[error("ElGamal public key mismatch")]
107 ConfidentialTransferElGamalPubkeyMismatch,
108 #[error("Balance mismatch")]
110 ConfidentialTransferBalanceMismatch,
111 #[error("Mint has non-zero supply. Burn all tokens before closing the mint")]
113 MintHasSupply,
114 #[error("No authority exists to perform the desired operation")]
116 NoAuthorityExists,
117
118 #[error("Transfer fee exceeds maximum of 10,000 basis points")]
121 TransferFeeExceedsMaximum,
122 #[error("Mint required for this account to transfer tokens, use `transfer_checked` or `transfer_checked_with_fee`")]
124 MintRequiredForTransfer,
125 #[error("Calculated fee does not match expected fee")]
127 FeeMismatch,
128 #[error(
130 "Fee parameters associated with zero-knowledge proofs do not match fee parameters in mint"
131 )]
132 FeeParametersMismatch,
133 #[error("The owner authority cannot be changed")]
135 ImmutableOwner,
136
137 #[error("An account can only be closed if its withheld fee balance is zero, harvest fees to the mint and try again")]
141 AccountHasWithheldTransferFees,
142 #[error("No memo in previous instruction; required for recipient to receive a transfer")]
144 NoMemo,
145 #[error("Transfer is disabled for this mint")]
147 NonTransferable,
148 #[error("Non-transferable tokens can't be minted to an account without immutable ownership")]
150 NonTransferableNeedsImmutableOwnership,
151 #[error(
154 "The total number of `Deposit` and `Transfer` instructions to an account cannot exceed
155 the associated `maximum_pending_balance_credit_counter`"
156 )]
157 MaximumPendingBalanceCreditCounterExceeded,
158
159 #[error("Deposit amount exceeds maximum limit")]
162 MaximumDepositAmountExceeded,
163 #[error("CPI Guard cannot be enabled or disabled in CPI")]
165 CpiGuardSettingsLocked,
166 #[error("CPI Guard is enabled, and a program attempted to transfer user funds via CPI without using a delegate")]
168 CpiGuardTransferBlocked,
169 #[error(
171 "CPI Guard is enabled, and a program attempted to burn user funds via CPI without using a delegate"
172 )]
173 CpiGuardBurnBlocked,
174 #[error("CPI Guard is enabled, and a program attempted to close an account via CPI without returning lamports to owner")]
176 CpiGuardCloseAccountBlocked,
177
178 #[error("CPI Guard is enabled, and a program attempted to approve a delegate via CPI")]
181 CpiGuardApproveBlocked,
182 #[error(
184 "CPI Guard is enabled, and a program attempted to add or replace an authority via CPI"
185 )]
186 CpiGuardSetAuthorityBlocked,
187 #[error("Account ownership cannot be changed while CPI Guard is enabled")]
189 CpiGuardOwnerChangeBlocked,
190 #[error("Extension not found in account data")]
192 ExtensionNotFound,
193 #[error("Non-confidential transfers disabled")]
195 NonConfidentialTransfersDisabled,
196}
197impl From<TokenError> for ProgramError {
198 fn from(e: TokenError) -> Self {
199 ProgramError::Custom(e as u32)
200 }
201}
202impl<T> DecodeError<T> for TokenError {
203 fn type_of() -> &'static str {
204 "TokenError"
205 }
206}
207
208impl PrintProgramError for TokenError {
209 fn print<E>(&self)
210 where
211 E: 'static + std::error::Error + DecodeError<E> + num_traits::FromPrimitive,
212 {
213 match self {
214 TokenError::NotRentExempt => msg!("Error: Lamport balance below rent-exempt threshold"),
215 TokenError::InsufficientFunds => msg!("Error: insufficient funds"),
216 TokenError::InvalidMint => msg!("Error: Invalid Mint"),
217 TokenError::MintMismatch => msg!("Error: Account not associated with this Mint"),
218 TokenError::OwnerMismatch => msg!("Error: owner does not match"),
219 TokenError::FixedSupply => msg!("Error: the total supply of this token is fixed"),
220 TokenError::AlreadyInUse => msg!("Error: account or token already in use"),
221 TokenError::InvalidNumberOfProvidedSigners => {
222 msg!("Error: Invalid number of provided signers")
223 }
224 TokenError::InvalidNumberOfRequiredSigners => {
225 msg!("Error: Invalid number of required signers")
226 }
227 TokenError::UninitializedState => msg!("Error: State is uninitialized"),
228 TokenError::NativeNotSupported => {
229 msg!("Error: Instruction does not support native tokens")
230 }
231 TokenError::NonNativeHasBalance => {
232 msg!("Error: Non-native account can only be closed if its balance is zero")
233 }
234 TokenError::InvalidInstruction => msg!("Error: Invalid instruction"),
235 TokenError::InvalidState => msg!("Error: Invalid account state for operation"),
236 TokenError::Overflow => msg!("Error: Operation overflowed"),
237 TokenError::AuthorityTypeNotSupported => {
238 msg!("Error: Account does not support specified authority type")
239 }
240 TokenError::MintCannotFreeze => msg!("Error: This token mint cannot freeze accounts"),
241 TokenError::AccountFrozen => msg!("Error: Account is frozen"),
242 TokenError::MintDecimalsMismatch => {
243 msg!("Error: decimals different from the Mint decimals")
244 }
245 TokenError::NonNativeNotSupported => {
246 msg!("Error: Instruction does not support non-native tokens")
247 }
248 TokenError::ExtensionTypeMismatch => {
249 msg!("Error: New extension type does not match already existing extensions")
250 }
251 TokenError::ExtensionBaseMismatch => {
252 msg!("Error: Extension does not match the base type provided")
253 }
254 TokenError::ExtensionAlreadyInitialized => {
255 msg!("Error: Extension already initialized on this account")
256 }
257 TokenError::ConfidentialTransferAccountHasBalance => {
258 msg!("Error: An account can only be closed if its confidential balance is zero")
259 }
260 TokenError::ConfidentialTransferAccountNotApproved => {
261 msg!("Error: Account not approved for confidential transfers")
262 }
263 TokenError::ConfidentialTransferDepositsAndTransfersDisabled => {
264 msg!("Error: Account not accepting deposits or transfers")
265 }
266 TokenError::ConfidentialTransferElGamalPubkeyMismatch => {
267 msg!("Error: ElGamal public key mismatch")
268 }
269 TokenError::ConfidentialTransferBalanceMismatch => {
270 msg!("Error: Balance mismatch")
271 }
272 TokenError::MintHasSupply => {
273 msg!("Error: Mint has non-zero supply. Burn all tokens before closing the mint")
274 }
275 TokenError::NoAuthorityExists => {
276 msg!("Error: No authority exists to perform the desired operation");
277 }
278 TokenError::TransferFeeExceedsMaximum => {
279 msg!("Error: Transfer fee exceeds maximum of 10,000 basis points");
280 }
281 TokenError::MintRequiredForTransfer => {
282 msg!("Mint required for this account to transfer tokens, use `transfer_checked` or `transfer_checked_with_fee`");
283 }
284 TokenError::FeeMismatch => {
285 msg!("Calculated fee does not match expected fee");
286 }
287 TokenError::FeeParametersMismatch => {
288 msg!("Fee parameters associated with zero-knowledge proofs do not match fee parameters in mint")
289 }
290 TokenError::ImmutableOwner => {
291 msg!("The owner authority cannot be changed");
292 }
293 TokenError::AccountHasWithheldTransferFees => {
294 msg!("Error: An account can only be closed if its withheld fee balance is zero, harvest fees to the mint and try again");
295 }
296 TokenError::NoMemo => {
297 msg!("Error: No memo in previous instruction; required for recipient to receive a transfer");
298 }
299 TokenError::NonTransferable => {
300 msg!("Transfer is disabled for this mint");
301 }
302 TokenError::NonTransferableNeedsImmutableOwnership => {
303 msg!("Non-transferable tokens can't be minted to an account without immutable ownership");
304 }
305 TokenError::MaximumPendingBalanceCreditCounterExceeded => {
306 msg!("The total number of `Deposit` and `Transfer` instructions to an account cannot exceed the associated `maximum_pending_balance_credit_counter`");
307 }
308 TokenError::MaximumDepositAmountExceeded => {
309 msg!("Deposit amount exceeds maximum limit")
310 }
311 TokenError::CpiGuardSettingsLocked => {
312 msg!("CPI Guard status cannot be changed in CPI")
313 }
314 TokenError::CpiGuardTransferBlocked => {
315 msg!("CPI Guard is enabled, and a program attempted to transfer user funds without using a delegate")
316 }
317 TokenError::CpiGuardBurnBlocked => {
318 msg!("CPI Guard is enabled, and a program attempted to burn user funds without using a delegate")
319 }
320 TokenError::CpiGuardCloseAccountBlocked => {
321 msg!("CPI Guard is enabled, and a program attempted to close an account without returning lamports to owner")
322 }
323 TokenError::CpiGuardApproveBlocked => {
324 msg!("CPI Guard is enabled, and a program attempted to approve a delegate")
325 }
326 TokenError::CpiGuardSetAuthorityBlocked => {
327 msg!("CPI Guard is enabled, and a program attempted to add or change an authority")
328 }
329 TokenError::CpiGuardOwnerChangeBlocked => {
330 msg!("Account ownership cannot be changed while CPI Guard is enabled")
331 }
332 TokenError::ExtensionNotFound => {
333 msg!("Extension not found in account data")
334 }
335 TokenError::NonConfidentialTransfersDisabled => {
336 msg!("Non-confidential transfers disabled")
337 }
338 }
339 }
340}