1#[cfg(not(target_os = "solana"))]
4use spl_token_confidential_transfer_proof_generation::errors::TokenProofGenerationError;
5use {
6 num_derive::FromPrimitive,
7 solana_program::{
8 decode_error::DecodeError,
9 msg,
10 program_error::{PrintProgramError, ProgramError},
11 },
12 spl_token_confidential_transfer_proof_extraction::errors::TokenProofExtractionError,
13 thiserror::Error,
14};
15
16#[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)]
18pub enum TokenError {
19 #[error("Lamport balance below rent-exempt threshold")]
22 NotRentExempt,
23 #[error("Insufficient funds")]
25 InsufficientFunds,
26 #[error("Invalid Mint")]
28 InvalidMint,
29 #[error("Account not associated with this Mint")]
31 MintMismatch,
32 #[error("Owner does not match")]
34 OwnerMismatch,
35
36 #[error("Fixed supply")]
39 FixedSupply,
40 #[error("Already in use")]
42 AlreadyInUse,
43 #[error("Invalid number of provided signers")]
45 InvalidNumberOfProvidedSigners,
46 #[error("Invalid number of required signers")]
48 InvalidNumberOfRequiredSigners,
49 #[error("State is uninitialized")]
51 UninitializedState,
52
53 #[error("Instruction does not support native tokens")]
56 NativeNotSupported,
57 #[error("Non-native account can only be closed if its balance is zero")]
59 NonNativeHasBalance,
60 #[error("Invalid instruction")]
62 InvalidInstruction,
63 #[error("State is invalid for requested operation")]
65 InvalidState,
66 #[error("Operation overflowed")]
68 Overflow,
69
70 #[error("Account does not support specified authority type")]
73 AuthorityTypeNotSupported,
74 #[error("This token mint cannot freeze accounts")]
76 MintCannotFreeze,
77 #[error("Account is frozen")]
79 AccountFrozen,
80 #[error("The provided decimals value different from the Mint decimals")]
82 MintDecimalsMismatch,
83 #[error("Instruction does not support non-native tokens")]
85 NonNativeNotSupported,
86
87 #[error("Extension type does not match already existing extensions")]
90 ExtensionTypeMismatch,
91 #[error("Extension does not match the base type provided")]
93 ExtensionBaseMismatch,
94 #[error("Extension already initialized on this account")]
96 ExtensionAlreadyInitialized,
97 #[error("An account can only be closed if its confidential balance is zero")]
99 ConfidentialTransferAccountHasBalance,
100 #[error("Account not approved for confidential transfers")]
102 ConfidentialTransferAccountNotApproved,
103
104 #[error("Account not accepting deposits or transfers")]
107 ConfidentialTransferDepositsAndTransfersDisabled,
108 #[error("ElGamal public key mismatch")]
110 ConfidentialTransferElGamalPubkeyMismatch,
111 #[error("Balance mismatch")]
113 ConfidentialTransferBalanceMismatch,
114 #[error("Mint has non-zero supply. Burn all tokens before closing the mint")]
116 MintHasSupply,
117 #[error("No authority exists to perform the desired operation")]
119 NoAuthorityExists,
120
121 #[error("Transfer fee exceeds maximum of 10,000 basis points")]
124 TransferFeeExceedsMaximum,
125 #[error("Mint required for this account to transfer tokens, use `transfer_checked` or `transfer_checked_with_fee`")]
128 MintRequiredForTransfer,
129 #[error("Calculated fee does not match expected fee")]
131 FeeMismatch,
132 #[error(
135 "Fee parameters associated with zero-knowledge proofs do not match fee parameters in mint"
136 )]
137 FeeParametersMismatch,
138 #[error("The owner authority cannot be changed")]
140 ImmutableOwner,
141
142 #[error("An account can only be closed if its withheld fee balance is zero, harvest fees to the mint and try again")]
146 AccountHasWithheldTransferFees,
147 #[error("No memo in previous instruction; required for recipient to receive a transfer")]
150 NoMemo,
151 #[error("Transfer is disabled for this mint")]
153 NonTransferable,
154 #[error("Non-transferable tokens can't be minted to an account without immutable ownership")]
157 NonTransferableNeedsImmutableOwnership,
158 #[error(
162 "The total number of `Deposit` and `Transfer` instructions to an account cannot exceed
163 the associated `maximum_pending_balance_credit_counter`"
164 )]
165 MaximumPendingBalanceCreditCounterExceeded,
166
167 #[error("Deposit amount exceeds maximum limit")]
171 MaximumDepositAmountExceeded,
172 #[error("CPI Guard cannot be enabled or disabled in CPI")]
174 CpiGuardSettingsLocked,
175 #[error("CPI Guard is enabled, and a program attempted to transfer user funds via CPI without using a delegate")]
178 CpiGuardTransferBlocked,
179 #[error(
182 "CPI Guard is enabled, and a program attempted to burn user funds via CPI without using a delegate"
183 )]
184 CpiGuardBurnBlocked,
185 #[error("CPI Guard is enabled, and a program attempted to close an account via CPI without returning lamports to owner")]
188 CpiGuardCloseAccountBlocked,
189
190 #[error("CPI Guard is enabled, and a program attempted to approve a delegate via CPI")]
193 CpiGuardApproveBlocked,
194 #[error(
197 "CPI Guard is enabled, and a program attempted to add or replace an authority via CPI"
198 )]
199 CpiGuardSetAuthorityBlocked,
200 #[error("Account ownership cannot be changed while CPI Guard is enabled")]
202 CpiGuardOwnerChangeBlocked,
203 #[error("Extension not found in account data")]
205 ExtensionNotFound,
206 #[error("Non-confidential transfers disabled")]
208 NonConfidentialTransfersDisabled,
209
210 #[error("An account can only be closed if the confidential withheld fee is zero")]
213 ConfidentialTransferFeeAccountHasWithheldFee,
214 #[error("A mint or an account is initialized to an invalid combination of extensions")]
217 InvalidExtensionCombination,
218 #[error("Extension allocation with overwrite must use the same length")]
220 InvalidLengthForAlloc,
221 #[error("Failed to decrypt a confidential transfer account")]
223 AccountDecryption,
224 #[error("Failed to generate proof")]
226 ProofGeneration,
227
228 #[error("An invalid proof instruction offset was provided")]
231 InvalidProofInstructionOffset,
232 #[error("Harvest of withheld tokens to mint is disabled")]
234 HarvestToMintDisabled,
235 #[error("Split proof context state accounts not supported for instruction")]
237 SplitProofContextStateAccountsNotSupported,
238 #[error("Not enough proof context state accounts provided")]
240 NotEnoughProofContextStateAccounts,
241 #[error("Ciphertext is malformed")]
243 MalformedCiphertext,
244
245 #[error("Ciphertext arithmetic failed")]
248 CiphertextArithmeticFailed,
249 #[error("Pedersen commitment mismatch")]
251 PedersenCommitmentMismatch,
252 #[error("Range proof length mismatch")]
254 RangeProofLengthMismatch,
255 #[error("Illegal transfer amount bit length")]
257 IllegalBitLength,
258 #[error("Fee calculation failed")]
260 FeeCalculation,
261
262 #[error("Withdraw / Deposit not allowed for confidential-mint-burn")]
265 IllegalMintBurnConversion,
266 #[error("Invalid scale for scaled ui amount")]
268 InvalidScale,
269 #[error("Transferring, minting, and burning is paused on this mint")]
271 MintPaused,
272}
273impl From<TokenError> for ProgramError {
274 fn from(e: TokenError) -> Self {
275 ProgramError::Custom(e as u32)
276 }
277}
278impl<T> DecodeError<T> for TokenError {
279 fn type_of() -> &'static str {
280 "TokenError"
281 }
282}
283
284impl PrintProgramError for TokenError {
285 fn print<E>(&self)
286 where
287 E: 'static + std::error::Error + DecodeError<E> + num_traits::FromPrimitive,
288 {
289 match self {
290 TokenError::NotRentExempt => msg!("Error: Lamport balance below rent-exempt threshold"),
291 TokenError::InsufficientFunds => msg!("Error: insufficient funds"),
292 TokenError::InvalidMint => msg!("Error: Invalid Mint"),
293 TokenError::MintMismatch => msg!("Error: Account not associated with this Mint"),
294 TokenError::OwnerMismatch => msg!("Error: owner does not match"),
295 TokenError::FixedSupply => msg!("Error: the total supply of this token is fixed"),
296 TokenError::AlreadyInUse => msg!("Error: account or token already in use"),
297 TokenError::InvalidNumberOfProvidedSigners => {
298 msg!("Error: Invalid number of provided signers")
299 }
300 TokenError::InvalidNumberOfRequiredSigners => {
301 msg!("Error: Invalid number of required signers")
302 }
303 TokenError::UninitializedState => msg!("Error: State is uninitialized"),
304 TokenError::NativeNotSupported => {
305 msg!("Error: Instruction does not support native tokens")
306 }
307 TokenError::NonNativeHasBalance => {
308 msg!("Error: Non-native account can only be closed if its balance is zero")
309 }
310 TokenError::InvalidInstruction => msg!("Error: Invalid instruction"),
311 TokenError::InvalidState => msg!("Error: Invalid account state for operation"),
312 TokenError::Overflow => msg!("Error: Operation overflowed"),
313 TokenError::AuthorityTypeNotSupported => {
314 msg!("Error: Account does not support specified authority type")
315 }
316 TokenError::MintCannotFreeze => msg!("Error: This token mint cannot freeze accounts"),
317 TokenError::AccountFrozen => msg!("Error: Account is frozen"),
318 TokenError::MintDecimalsMismatch => {
319 msg!("Error: decimals different from the Mint decimals")
320 }
321 TokenError::NonNativeNotSupported => {
322 msg!("Error: Instruction does not support non-native tokens")
323 }
324 TokenError::ExtensionTypeMismatch => {
325 msg!("Error: New extension type does not match already existing extensions")
326 }
327 TokenError::ExtensionBaseMismatch => {
328 msg!("Error: Extension does not match the base type provided")
329 }
330 TokenError::ExtensionAlreadyInitialized => {
331 msg!("Error: Extension already initialized on this account")
332 }
333 TokenError::ConfidentialTransferAccountHasBalance => {
334 msg!("Error: An account can only be closed if its confidential balance is zero")
335 }
336 TokenError::ConfidentialTransferAccountNotApproved => {
337 msg!("Error: Account not approved for confidential transfers")
338 }
339 TokenError::ConfidentialTransferDepositsAndTransfersDisabled => {
340 msg!("Error: Account not accepting deposits or transfers")
341 }
342 TokenError::ConfidentialTransferElGamalPubkeyMismatch => {
343 msg!("Error: ElGamal public key mismatch")
344 }
345 TokenError::ConfidentialTransferBalanceMismatch => {
346 msg!("Error: Balance mismatch")
347 }
348 TokenError::MintHasSupply => {
349 msg!("Error: Mint has non-zero supply. Burn all tokens before closing the mint")
350 }
351 TokenError::NoAuthorityExists => {
352 msg!("Error: No authority exists to perform the desired operation");
353 }
354 TokenError::TransferFeeExceedsMaximum => {
355 msg!("Error: Transfer fee exceeds maximum of 10,000 basis points");
356 }
357 TokenError::MintRequiredForTransfer => {
358 msg!("Mint required for this account to transfer tokens, use `transfer_checked` or `transfer_checked_with_fee`");
359 }
360 TokenError::FeeMismatch => {
361 msg!("Calculated fee does not match expected fee");
362 }
363 TokenError::FeeParametersMismatch => {
364 msg!("Fee parameters associated with zero-knowledge proofs do not match fee parameters in mint")
365 }
366 TokenError::ImmutableOwner => {
367 msg!("The owner authority cannot be changed");
368 }
369 TokenError::AccountHasWithheldTransferFees => {
370 msg!("Error: An account can only be closed if its withheld fee balance is zero, harvest fees to the mint and try again");
371 }
372 TokenError::NoMemo => {
373 msg!("Error: No memo in previous instruction; required for recipient to receive a transfer");
374 }
375 TokenError::NonTransferable => {
376 msg!("Transfer is disabled for this mint");
377 }
378 TokenError::NonTransferableNeedsImmutableOwnership => {
379 msg!("Non-transferable tokens can't be minted to an account without immutable ownership");
380 }
381 TokenError::MaximumPendingBalanceCreditCounterExceeded => {
382 msg!("The total number of `Deposit` and `Transfer` instructions to an account cannot exceed the associated `maximum_pending_balance_credit_counter`");
383 }
384 TokenError::MaximumDepositAmountExceeded => {
385 msg!("Deposit amount exceeds maximum limit")
386 }
387 TokenError::CpiGuardSettingsLocked => {
388 msg!("CPI Guard status cannot be changed in CPI")
389 }
390 TokenError::CpiGuardTransferBlocked => {
391 msg!("CPI Guard is enabled, and a program attempted to transfer user funds without using a delegate")
392 }
393 TokenError::CpiGuardBurnBlocked => {
394 msg!("CPI Guard is enabled, and a program attempted to burn user funds without using a delegate")
395 }
396 TokenError::CpiGuardCloseAccountBlocked => {
397 msg!("CPI Guard is enabled, and a program attempted to close an account without returning lamports to owner")
398 }
399 TokenError::CpiGuardApproveBlocked => {
400 msg!("CPI Guard is enabled, and a program attempted to approve a delegate")
401 }
402 TokenError::CpiGuardSetAuthorityBlocked => {
403 msg!("CPI Guard is enabled, and a program attempted to add or change an authority")
404 }
405 TokenError::CpiGuardOwnerChangeBlocked => {
406 msg!("Account ownership cannot be changed while CPI Guard is enabled")
407 }
408 TokenError::ExtensionNotFound => {
409 msg!("Extension not found in account data")
410 }
411 TokenError::NonConfidentialTransfersDisabled => {
412 msg!("Non-confidential transfers disabled")
413 }
414 TokenError::ConfidentialTransferFeeAccountHasWithheldFee => {
415 msg!("Account has non-zero confidential withheld fee")
416 }
417 TokenError::InvalidExtensionCombination => {
418 msg!("Mint or account is initialized to an invalid combination of extensions")
419 }
420 TokenError::InvalidLengthForAlloc => {
421 msg!("Extension allocation with overwrite must use the same length")
422 }
423 TokenError::AccountDecryption => {
424 msg!("Failed to decrypt a confidential transfer account")
425 }
426 TokenError::ProofGeneration => {
427 msg!("Failed to generate proof")
428 }
429 TokenError::InvalidProofInstructionOffset => {
430 msg!("An invalid proof instruction offset was provided")
431 }
432 TokenError::HarvestToMintDisabled => {
433 msg!("Harvest of withheld tokens to mint is disabled")
434 }
435 TokenError::SplitProofContextStateAccountsNotSupported => {
436 msg!("Split proof context state accounts not supported for instruction")
437 }
438 TokenError::NotEnoughProofContextStateAccounts => {
439 msg!("Not enough proof context state accounts provided")
440 }
441 TokenError::MalformedCiphertext => {
442 msg!("Ciphertext is malformed")
443 }
444 TokenError::CiphertextArithmeticFailed => {
445 msg!("Ciphertext arithmetic failed")
446 }
447 TokenError::PedersenCommitmentMismatch => {
448 msg!("Pedersen commitments did not match")
449 }
450 TokenError::RangeProofLengthMismatch => {
451 msg!("Range proof lengths did not match")
452 }
453 TokenError::IllegalBitLength => {
454 msg!("Illegal transfer amount bit length")
455 }
456 TokenError::FeeCalculation => {
457 msg!("Transfer fee calculation failed")
458 }
459 TokenError::IllegalMintBurnConversion => {
460 msg!("Conversions from normal to confidential token balance and vice versa are illegal if the confidential-mint-burn extension is enabled")
461 }
462 TokenError::InvalidScale => {
463 msg!("Invalid scale for scaled ui amount")
464 }
465 TokenError::MintPaused => {
466 msg!("Transferring, minting, and burning is paused on this mint")
467 }
468 }
469 }
470}
471
472#[cfg(not(target_os = "solana"))]
473impl From<TokenProofGenerationError> for TokenError {
474 fn from(e: TokenProofGenerationError) -> Self {
475 match e {
476 TokenProofGenerationError::ProofGeneration(_) => TokenError::ProofGeneration,
477 TokenProofGenerationError::NotEnoughFunds => TokenError::InsufficientFunds,
478 TokenProofGenerationError::IllegalAmountBitLength => TokenError::IllegalBitLength,
479 TokenProofGenerationError::FeeCalculation => TokenError::FeeCalculation,
480 TokenProofGenerationError::CiphertextExtraction => TokenError::MalformedCiphertext,
481 }
482 }
483}
484
485impl From<TokenProofExtractionError> for TokenError {
486 fn from(e: TokenProofExtractionError) -> Self {
487 match e {
488 TokenProofExtractionError::ElGamalPubkeyMismatch => {
489 TokenError::ConfidentialTransferElGamalPubkeyMismatch
490 }
491 TokenProofExtractionError::PedersenCommitmentMismatch => {
492 TokenError::PedersenCommitmentMismatch
493 }
494 TokenProofExtractionError::RangeProofLengthMismatch => {
495 TokenError::RangeProofLengthMismatch
496 }
497 TokenProofExtractionError::FeeParametersMismatch => TokenError::FeeParametersMismatch,
498 TokenProofExtractionError::CurveArithmetic => TokenError::CiphertextArithmeticFailed,
499 TokenProofExtractionError::CiphertextExtraction => TokenError::MalformedCiphertext,
500 }
501 }
502}