spl_token_2022_interface/
error.rs

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