1use light_zero_copy::errors::ZeroCopyError;
2use thiserror::Error;
3
4#[derive(Debug, PartialEq, Error)]
5pub enum TokenError {
6 #[error("Invalid instruction data provided")]
7 InvalidInstructionData,
8
9 #[error("Invalid account data format")]
10 InvalidAccountData,
11
12 #[error("Arithmetic operation resulted in overflow")]
13 ArithmeticOverflow,
14
15 #[error("Failed to compute hash for data")]
16 HashComputationError,
17
18 #[error("Invalid or malformed extension data")]
19 InvalidExtensionData,
20
21 #[error("Missing required mint authority")]
22 MissingMintAuthority,
23
24 #[error("Missing required freeze authority")]
25 MissingFreezeAuthority,
26
27 #[error("Invalid metadata pointer configuration")]
28 InvalidMetadataPointer,
29
30 #[error("Token metadata validation failed")]
31 InvalidTokenMetadata,
32
33 #[error("Insufficient token supply for operation")]
34 InsufficientSupply,
35
36 #[error("Token account is frozen and cannot be modified")]
37 AccountFrozen,
38
39 #[error("Invalid compressed proof provided")]
40 InvalidProof,
41
42 #[error("Address derivation failed")]
43 AddressDerivationFailed,
44
45 #[error("Extension type not supported")]
46 UnsupportedExtension,
47
48 #[error("Maximum number of extensions exceeded")]
49 TooManyExtensions,
50
51 #[error("Invalid merkle tree root index")]
52 InvalidRootIndex,
53
54 #[error("Compressed account data size exceeds limit")]
55 DataSizeExceeded,
56
57 #[error("Invalid compression mode")]
58 InvalidCompressionMode,
59
60 #[error("Insufficient funds for compression.")]
61 CompressInsufficientFunds,
62
63 #[error("Failed to access sysvar")]
64 SysvarAccessError,
65
66 #[error("Compressed token account TLV is unimplemented.")]
67 CompressedTokenAccountTlvUnimplemented,
68
69 #[error("Input accounts lamports length mismatch")]
70 InputAccountsLamportsLengthMismatch,
71
72 #[error("Output accounts lamports length mismatch")]
73 OutputAccountsLamportsLengthMismatch,
74
75 #[error("Invalid token data version")]
76 InvalidTokenDataVersion,
77
78 #[error("Instruction data expected mint authority")]
79 InstructionDataExpectedMintAuthority,
80
81 #[error("Zero-copy expected mint authority")]
82 ZeroCopyExpectedMintAuthority,
83
84 #[error("Instruction data expected freeze authority")]
85 InstructionDataExpectedFreezeAuthority,
86
87 #[error("Zero-copy expected mint authority")]
88 ZeroCopyExpectedFreezeAuthority,
89
90 #[error("Invalid authority type provided")]
91 InvalidAuthorityType,
92
93 #[error("Expected mint signer account")]
94 ExpectedMintSignerAccount,
95
96 #[error("Light hasher error: {0}")]
97 HasherError(#[from] light_hasher::HasherError),
98
99 #[error("Light zero copy error: {0}")]
100 ZeroCopyError(#[from] ZeroCopyError),
101
102 #[error("Light compressed account error: {0}")]
103 CompressedAccountError(#[from] light_compressed_account::CompressedAccountError),
104
105 #[error("Invalid token metadata version")]
106 InvalidTokenMetadataVersion,
107 #[error("InvalidExtensionConfig")]
108 InvalidExtensionConfig,
109 #[error("InstructionDataExpectedDelegate")]
110 InstructionDataExpectedDelegate,
111 #[error("ZeroCopyExpectedDelegate")]
112 ZeroCopyExpectedDelegate,
113 #[error("Unsupported TLV extension type - only CompressedOnly is currently implemented")]
114 UnsupportedTlvExtensionType,
115 #[error("InvalidAccountState")]
116 InvalidAccountState,
117 #[error("BorshFailed")]
118 BorshFailed,
119 #[error(
120 "Too many input compressed accounts. Maximum 8 input accounts allowed per instruction"
121 )]
122 TooManyInputAccounts,
123
124 #[error("Too many additional metadata elements. Maximum 20 allowed")]
125 TooManyAdditionalMetadata,
126
127 #[error("Duplicate metadata key found in additional metadata")]
128 DuplicateMetadataKey,
129
130 #[error("Too many PDA seeds. Maximum {0} seeds allowed")]
131 TooManySeeds(usize),
132
133 #[error("write_top_up exceeds max_top_up from RentConfig")]
134 WriteTopUpExceedsMaximum,
135
136 #[error("Calculated top-up exceeds sender's max_top_up limit")]
137 MaxTopUpExceeded,
138
139 #[error("Mint account has invalid owner")]
140 InvalidMintOwner,
141
142 #[error("Mint account is not initialized")]
143 MintNotInitialized,
144
145 #[error("Failed to borrow Mint account data")]
146 MintBorrowFailed,
147
148 #[error("Failed to deserialize Mint account data")]
149 MintDeserializationFailed,
150
151 #[error("CompressedOnly tokens cannot have compressed outputs - must decompress only")]
152 CompressedOnlyBlocksTransfer,
153
154 #[error("Output TLV data count must match number of compressed outputs")]
155 OutTlvOutputCountMismatch,
156
157 #[error("in_lamports field is not yet implemented")]
158 InLamportsUnimplemented,
159
160 #[error("out_lamports field is not yet implemented")]
161 OutLamportsUnimplemented,
162
163 #[error("TLV extension length mismatch - exactly one extension required")]
164 TlvExtensionLengthMismatch,
165
166 #[error("InvalidAccountType")]
167 InvalidAccountType,
168
169 #[error("Duplicate compression_index found in input TLV data")]
170 DuplicateCompressionIndex,
171
172 #[error("Decompress destination Token is not a fresh account")]
173 DecompressDestinationNotFresh,
174
175 #[error("Token account missing required Compressible extension")]
176 MissingCompressibleExtension,
177
178 #[error("Decompress destination doesn't match source account")]
179 DecompressDestinationMismatch,
180
181 #[error("Token account mint does not match expected mint")]
182 MintMismatch,
183
184 #[error("Decompress has delegated_amount but no delegate pubkey provided")]
185 DecompressDelegatedAmountWithoutDelegate,
186
187 #[error(
188 "Decompress has withheld_transfer_fee but destination lacks TransferFeeAccount extension"
189 )]
190 DecompressWithheldFeeWithoutExtension,
191
192 #[error("Missing required payer account")]
193 MissingPayer,
194
195 #[error("Failed to borrow account data")]
196 BorrowFailed,
197
198 #[error("Token account has invalid owner")]
199 InvalidTokenOwner,
200
201 #[error("Decompress amount mismatch between compression instruction and input token data")]
202 DecompressAmountMismatch,
203
204 #[error("Compression index exceeds maximum allowed value")]
205 CompressionIndexOutOfBounds,
206
207 #[error("ATA derivation failed or mismatched for is_ata compressed token")]
208 InvalidAtaDerivation,
209}
210
211impl From<TokenError> for u32 {
212 fn from(e: TokenError) -> u32 {
213 match e {
214 TokenError::InvalidInstructionData => 18001,
215 TokenError::InvalidAccountData => 18002,
216 TokenError::ArithmeticOverflow => 18003,
217 TokenError::HashComputationError => 18004,
218 TokenError::InvalidExtensionData => 18005,
219 TokenError::MissingMintAuthority => 18006,
220 TokenError::MissingFreezeAuthority => 18007,
221 TokenError::InvalidMetadataPointer => 18008,
222 TokenError::InvalidTokenMetadata => 18009,
223 TokenError::InsufficientSupply => 18010,
224 TokenError::AccountFrozen => 18011,
225 TokenError::InvalidProof => 18012,
226 TokenError::AddressDerivationFailed => 18013,
227 TokenError::UnsupportedExtension => 18014,
228 TokenError::TooManyExtensions => 18015,
229 TokenError::InvalidRootIndex => 18016,
230 TokenError::DataSizeExceeded => 18017,
231 TokenError::InvalidCompressionMode => 18018,
232 TokenError::CompressInsufficientFunds => 18019,
233 TokenError::SysvarAccessError => 18020,
234 TokenError::CompressedTokenAccountTlvUnimplemented => 18021,
235 TokenError::InputAccountsLamportsLengthMismatch => 18022,
236 TokenError::OutputAccountsLamportsLengthMismatch => 18023,
237 TokenError::InvalidTokenDataVersion => 18028,
238 TokenError::InstructionDataExpectedMintAuthority => 18024,
239 TokenError::ZeroCopyExpectedMintAuthority => 18025,
240 TokenError::InstructionDataExpectedFreezeAuthority => 18026,
241 TokenError::ZeroCopyExpectedFreezeAuthority => 18027,
242 TokenError::InvalidAuthorityType => 18029,
243 TokenError::ExpectedMintSignerAccount => 18030,
244 TokenError::InvalidTokenMetadataVersion => 18031,
245 TokenError::InvalidExtensionConfig => 18032,
246 TokenError::InstructionDataExpectedDelegate => 18033,
247 TokenError::ZeroCopyExpectedDelegate => 18034,
248 TokenError::UnsupportedTlvExtensionType => 18035,
249 TokenError::InvalidAccountState => 18036,
250 TokenError::BorshFailed => 18037,
251 TokenError::TooManyInputAccounts => 18038,
252 TokenError::TooManyAdditionalMetadata => 18039,
253 TokenError::DuplicateMetadataKey => 18040,
254 TokenError::TooManySeeds(_) => 18041,
255 TokenError::WriteTopUpExceedsMaximum => 18042,
256 TokenError::MaxTopUpExceeded => 18043,
257 TokenError::InvalidMintOwner => 18044,
258 TokenError::MintNotInitialized => 18045,
259 TokenError::MintBorrowFailed => 18046,
260 TokenError::MintDeserializationFailed => 18047,
261 TokenError::CompressedOnlyBlocksTransfer => 18048,
262 TokenError::OutTlvOutputCountMismatch => 18049,
263 TokenError::InLamportsUnimplemented => 18050,
264 TokenError::OutLamportsUnimplemented => 18051,
265 TokenError::TlvExtensionLengthMismatch => 18052,
266 TokenError::InvalidAccountType => 18053,
267 TokenError::DuplicateCompressionIndex => 18054,
268 TokenError::DecompressDestinationNotFresh => 18055,
269 TokenError::MissingCompressibleExtension => 18056,
270 TokenError::DecompressDestinationMismatch => 18057,
271 TokenError::MintMismatch => 18058,
272 TokenError::DecompressDelegatedAmountWithoutDelegate => 18059,
273 TokenError::DecompressWithheldFeeWithoutExtension => 18060,
274 TokenError::MissingPayer => 18061,
275 TokenError::BorrowFailed => 18062,
276 TokenError::InvalidTokenOwner => 18063,
277 TokenError::DecompressAmountMismatch => 18064,
278 TokenError::CompressionIndexOutOfBounds => 18065,
279 TokenError::InvalidAtaDerivation => 18066,
280 TokenError::HasherError(e) => u32::from(e),
281 TokenError::ZeroCopyError(e) => u32::from(e),
282 TokenError::CompressedAccountError(e) => u32::from(e),
283 }
284 }
285}
286
287#[cfg(all(feature = "solana", not(feature = "anchor")))]
288impl From<TokenError> for solana_program_error::ProgramError {
289 fn from(e: TokenError) -> Self {
290 solana_program_error::ProgramError::Custom(e.into())
291 }
292}
293
294impl From<TokenError> for pinocchio::program_error::ProgramError {
295 fn from(e: TokenError) -> Self {
296 pinocchio::program_error::ProgramError::Custom(e.into())
297 }
298}
299
300#[cfg(feature = "anchor")]
301impl From<TokenError> for anchor_lang::prelude::ProgramError {
302 fn from(e: TokenError) -> Self {
303 anchor_lang::prelude::ProgramError::Custom(e.into())
304 }
305}