1use {
4 crate::program::spl_token_2022::{
5 amount_to_ui_amount_string_trimmed, check_program_account, cmp_pubkeys,
6 error::TokenError,
7 extension::{
8 default_account_state::{self, DefaultAccountState},
11 immutable_owner::ImmutableOwner,
12 interest_bearing_mint::{self, InterestBearingConfig},
13 memo_transfer::{self, check_previous_sibling_instruction_is_memo, memo_required},
14 mint_close_authority::MintCloseAuthority,
15 non_transferable::NonTransferable,
16 reallocate,
17 transfer_fee::{self, TransferFeeAmount, TransferFeeConfig},
18 ExtensionType,
19 StateWithExtensions,
20 StateWithExtensionsMut,
21 },
22 instruction::{is_valid_signer_index, AuthorityType, TokenInstruction, MAX_SIGNERS},
23 native_mint,
24 state::{Account, AccountState, Mint, Multisig},
25 try_ui_amount_into_amount,
26 },
27 num_traits::FromPrimitive,
28 solana_sdk::{
29 account_info::{next_account_info, AccountInfo},
30 clock::Clock,
31 decode_error::DecodeError,
32 entrypoint::ProgramResult,
33 msg,
34 program::{invoke, invoke_signed, set_return_data},
35 program_error::{PrintProgramError, ProgramError},
36 program_memory::sol_memset,
37 program_option::COption,
38 program_pack::Pack,
39 pubkey::Pubkey,
40 system_instruction,
41 sysvar::{rent::Rent, Sysvar},
42 },
43 std::convert::{TryFrom, TryInto},
44};
45
46pub struct Processor {}
48impl Processor {
49 fn _process_initialize_mint(
50 accounts: &[AccountInfo],
51 decimals: u8,
52 mint_authority: Pubkey,
53 freeze_authority: COption<Pubkey>,
54 rent_sysvar_account: bool,
55 ) -> ProgramResult {
56 let account_info_iter = &mut accounts.iter();
57 let mint_info = next_account_info(account_info_iter)?;
58 let mint_data_len = mint_info.data_len();
59 let mut mint_data = mint_info.data.borrow_mut();
60 let rent = if rent_sysvar_account {
61 Rent::from_account_info(next_account_info(account_info_iter)?)?
62 } else {
63 Rent::get()?
64 };
65
66 if !rent.is_exempt(mint_info.lamports(), mint_data_len) {
67 return Err(TokenError::NotRentExempt.into());
68 }
69
70 let mut mint = StateWithExtensionsMut::<Mint>::unpack_uninitialized(&mut mint_data)?;
71 if mint.base.is_initialized {
72 return Err(TokenError::AlreadyInUse.into());
73 }
74
75 let extension_types = mint.get_extension_types()?;
76 if ExtensionType::get_account_len::<Mint>(&extension_types) != mint_data_len {
77 return Err(ProgramError::InvalidAccountData);
78 }
79
80 if let Ok(default_account_state) = mint.get_extension_mut::<DefaultAccountState>() {
81 let default_account_state = AccountState::try_from(default_account_state.state)
82 .or(Err(ProgramError::InvalidAccountData))?;
83 if default_account_state == AccountState::Frozen && freeze_authority.is_none() {
84 return Err(TokenError::MintCannotFreeze.into());
85 }
86 }
87
88 mint.base.mint_authority = COption::Some(mint_authority);
89 mint.base.decimals = decimals;
90 mint.base.is_initialized = true;
91 mint.base.freeze_authority = freeze_authority;
92 mint.pack_base();
93 mint.init_account_type()?;
94
95 Ok(())
96 }
97
98 pub fn process_initialize_mint(
100 accounts: &[AccountInfo],
101 decimals: u8,
102 mint_authority: Pubkey,
103 freeze_authority: COption<Pubkey>,
104 ) -> ProgramResult {
105 Self::_process_initialize_mint(accounts, decimals, mint_authority, freeze_authority, true)
106 }
107
108 pub fn process_initialize_mint2(
110 accounts: &[AccountInfo],
111 decimals: u8,
112 mint_authority: Pubkey,
113 freeze_authority: COption<Pubkey>,
114 ) -> ProgramResult {
115 Self::_process_initialize_mint(accounts, decimals, mint_authority, freeze_authority, false)
116 }
117
118 fn _process_initialize_account(
119 accounts: &[AccountInfo],
120 owner: Option<&Pubkey>,
121 rent_sysvar_account: bool,
122 ) -> ProgramResult {
123 let account_info_iter = &mut accounts.iter();
124 let new_account_info = next_account_info(account_info_iter)?;
125 let mint_info = next_account_info(account_info_iter)?;
126 let owner = if let Some(owner) = owner {
127 owner
128 } else {
129 next_account_info(account_info_iter)?.key
130 };
131 let new_account_info_data_len = new_account_info.data_len();
132 let rent = if rent_sysvar_account {
133 Rent::from_account_info(next_account_info(account_info_iter)?)?
134 } else {
135 Rent::get()?
136 };
137
138 let mut account_data = new_account_info.data.borrow_mut();
139 let mut account =
141 StateWithExtensionsMut::<Account>::unpack_uninitialized(&mut account_data)?;
142
143 if !rent.is_exempt(new_account_info.lamports(), new_account_info_data_len) {
144 return Err(TokenError::NotRentExempt.into());
145 }
146
147 let mint_data = mint_info.data.borrow();
149 let mint = StateWithExtensions::<Mint>::unpack(&mint_data)
150 .map_err(|_| Into::<ProgramError>::into(TokenError::InvalidMint))?;
151 let required_extensions =
152 Self::get_required_account_extensions_from_unpacked_mint(mint_info.owner, &mint)?;
153 if ExtensionType::get_account_len::<Account>(&required_extensions)
154 > new_account_info_data_len
155 {
156 return Err(ProgramError::InvalidAccountData);
157 }
158 for extension in required_extensions {
159 account.init_account_extension_from_type(extension)?;
160 }
161
162 let starting_state =
163 if let Ok(default_account_state) = mint.get_extension::<DefaultAccountState>() {
164 AccountState::try_from(default_account_state.state)
165 .or(Err(ProgramError::InvalidAccountData))?
166 } else {
167 AccountState::Initialized
168 };
169
170 account.base.mint = *mint_info.key;
171 account.base.owner = *owner;
172 account.base.close_authority = COption::None;
173 account.base.delegate = COption::None;
174 account.base.delegated_amount = 0;
175 account.base.state = starting_state;
176 if cmp_pubkeys(mint_info.key, &native_mint::id()) {
177 let rent_exempt_reserve = rent.minimum_balance(new_account_info_data_len);
178 account.base.is_native = COption::Some(rent_exempt_reserve);
179 account.base.amount = new_account_info
180 .lamports()
181 .checked_sub(rent_exempt_reserve)
182 .ok_or(TokenError::Overflow)?;
183 } else {
184 account.base.is_native = COption::None;
185 account.base.amount = 0;
186 };
187
188 account.pack_base();
189 account.init_account_type()?;
190
191 Ok(())
192 }
193
194 pub fn process_initialize_account(accounts: &[AccountInfo]) -> ProgramResult {
196 Self::_process_initialize_account(accounts, None, true)
197 }
198
199 pub fn process_initialize_account2(accounts: &[AccountInfo], owner: Pubkey) -> ProgramResult {
201 Self::_process_initialize_account(accounts, Some(&owner), true)
202 }
203
204 pub fn process_initialize_account3(accounts: &[AccountInfo], owner: Pubkey) -> ProgramResult {
206 Self::_process_initialize_account(accounts, Some(&owner), false)
207 }
208
209 fn _process_initialize_multisig(
210 accounts: &[AccountInfo],
211 m: u8,
212 rent_sysvar_account: bool,
213 ) -> ProgramResult {
214 let account_info_iter = &mut accounts.iter();
215 let multisig_info = next_account_info(account_info_iter)?;
216 let multisig_info_data_len = multisig_info.data_len();
217 let rent = if rent_sysvar_account {
218 Rent::from_account_info(next_account_info(account_info_iter)?)?
219 } else {
220 Rent::get()?
221 };
222
223 let mut multisig = Multisig::unpack_unchecked(&multisig_info.data.borrow())?;
224 if multisig.is_initialized {
225 return Err(TokenError::AlreadyInUse.into());
226 }
227
228 if !rent.is_exempt(multisig_info.lamports(), multisig_info_data_len) {
229 return Err(TokenError::NotRentExempt.into());
230 }
231
232 let signer_infos = account_info_iter.as_slice();
233 multisig.m = m;
234 multisig.n = signer_infos.len() as u8;
235 if !is_valid_signer_index(multisig.n as usize) {
236 return Err(TokenError::InvalidNumberOfProvidedSigners.into());
237 }
238 if !is_valid_signer_index(multisig.m as usize) {
239 return Err(TokenError::InvalidNumberOfRequiredSigners.into());
240 }
241 for (i, signer_info) in signer_infos.iter().enumerate() {
242 multisig.signers[i] = *signer_info.key;
243 }
244 multisig.is_initialized = true;
245
246 Multisig::pack(multisig, &mut multisig_info.data.borrow_mut())?;
247
248 Ok(())
249 }
250
251 pub fn process_initialize_multisig(accounts: &[AccountInfo], m: u8) -> ProgramResult {
253 Self::_process_initialize_multisig(accounts, m, true)
254 }
255
256 pub fn process_initialize_multisig2(accounts: &[AccountInfo], m: u8) -> ProgramResult {
258 Self::_process_initialize_multisig(accounts, m, false)
259 }
260
261 pub fn process_transfer(
263 program_id: &Pubkey,
264 accounts: &[AccountInfo],
265 amount: u64,
266 expected_decimals: Option<u8>,
267 expected_fee: Option<u64>,
268 ) -> ProgramResult {
269 let account_info_iter = &mut accounts.iter();
270
271 let source_account_info = next_account_info(account_info_iter)?;
272
273 let expected_mint_info = if let Some(expected_decimals) = expected_decimals {
274 Some((next_account_info(account_info_iter)?, expected_decimals))
275 } else {
276 None
277 };
278
279 let destination_account_info = next_account_info(account_info_iter)?;
280 let authority_info = next_account_info(account_info_iter)?;
281 let authority_info_data_len = authority_info.data_len();
282
283 let mut source_account_data = source_account_info.data.borrow_mut();
284 let mut source_account =
285 StateWithExtensionsMut::<Account>::unpack(&mut source_account_data)?;
286 if source_account.base.is_frozen() {
287 return Err(TokenError::AccountFrozen.into());
288 }
289 if source_account.base.amount < amount {
290 return Err(TokenError::InsufficientFunds.into());
291 }
292 let fee = if let Some((mint_info, expected_decimals)) = expected_mint_info {
293 if !cmp_pubkeys(&source_account.base.mint, mint_info.key) {
294 return Err(TokenError::MintMismatch.into());
295 }
296
297 let mint_data = mint_info.try_borrow_data()?;
298 let mint = StateWithExtensions::<Mint>::unpack(&mint_data)?;
299
300 if mint.get_extension::<NonTransferable>().is_ok() {
301 return Err(TokenError::NonTransferable.into());
302 }
303
304 if expected_decimals != mint.base.decimals {
305 return Err(TokenError::MintDecimalsMismatch.into());
306 }
307
308 if let Ok(transfer_fee_config) = mint.get_extension::<TransferFeeConfig>() {
309 transfer_fee_config
310 .calculate_epoch_fee(Clock::get()?.epoch, amount)
311 .ok_or(TokenError::Overflow)?
312 } else {
313 0
314 }
315 } else {
316 if source_account
319 .get_extension_mut::<TransferFeeAmount>()
320 .is_ok()
321 {
322 return Err(TokenError::MintRequiredForTransfer.into());
323 } else {
324 0
325 }
326 };
327 if let Some(expected_fee) = expected_fee {
328 if expected_fee != fee {
329 msg!("Calculated fee {}, received {}", fee, expected_fee);
330 return Err(TokenError::FeeMismatch.into());
331 }
332 }
333
334 let self_transfer = cmp_pubkeys(source_account_info.key, destination_account_info.key);
335 match source_account.base.delegate {
336 COption::Some(ref delegate) if cmp_pubkeys(authority_info.key, delegate) => {
337 Self::validate_owner(
338 program_id,
339 delegate,
340 authority_info,
341 authority_info_data_len,
342 account_info_iter.as_slice(),
343 )?;
344 if source_account.base.delegated_amount < amount {
345 return Err(TokenError::InsufficientFunds.into());
346 }
347 if !self_transfer {
348 source_account.base.delegated_amount = source_account
349 .base
350 .delegated_amount
351 .checked_sub(amount)
352 .ok_or(TokenError::Overflow)?;
353 if source_account.base.delegated_amount == 0 {
354 source_account.base.delegate = COption::None;
355 }
356 }
357 }
358 _ => Self::validate_owner(
359 program_id,
360 &source_account.base.owner,
361 authority_info,
362 authority_info_data_len,
363 account_info_iter.as_slice(),
364 )?,
365 };
366
367 check_program_account(source_account_info.owner)?;
371 check_program_account(destination_account_info.owner)?;
372
373 if self_transfer {
376 return Ok(());
377 }
378
379 let mut destination_account_data = destination_account_info.data.borrow_mut();
381 let mut destination_account =
382 StateWithExtensionsMut::<Account>::unpack(&mut destination_account_data)?;
383
384 if destination_account.base.is_frozen() {
385 return Err(TokenError::AccountFrozen.into());
386 }
387 if !cmp_pubkeys(&source_account.base.mint, &destination_account.base.mint) {
388 return Err(TokenError::MintMismatch.into());
389 }
390
391 if memo_required(&destination_account) {
392 check_previous_sibling_instruction_is_memo()?;
393 }
394
395 source_account.base.amount = source_account
396 .base
397 .amount
398 .checked_sub(amount)
399 .ok_or(TokenError::Overflow)?;
400 let credited_amount = amount.checked_sub(fee).ok_or(TokenError::Overflow)?;
401 destination_account.base.amount = destination_account
402 .base
403 .amount
404 .checked_add(credited_amount)
405 .ok_or(TokenError::Overflow)?;
406 if fee > 0 {
407 if let Ok(extension) = destination_account.get_extension_mut::<TransferFeeAmount>() {
408 let new_withheld_amount = u64::from(extension.withheld_amount)
409 .checked_add(fee)
410 .ok_or(TokenError::Overflow)?;
411 extension.withheld_amount = new_withheld_amount.into();
412 } else {
413 return Err(TokenError::InvalidState.into());
417 }
418 }
419
420 if source_account.base.is_native() {
421 let source_starting_lamports = source_account_info.lamports();
422 **source_account_info.lamports.borrow_mut() = source_starting_lamports
423 .checked_sub(amount)
424 .ok_or(TokenError::Overflow)?;
425
426 let destination_starting_lamports = destination_account_info.lamports();
427 **destination_account_info.lamports.borrow_mut() = destination_starting_lamports
428 .checked_add(amount)
429 .ok_or(TokenError::Overflow)?;
430 }
431
432 source_account.pack_base();
433 destination_account.pack_base();
434
435 Ok(())
436 }
437
438 pub fn process_approve(
440 program_id: &Pubkey,
441 accounts: &[AccountInfo],
442 amount: u64,
443 expected_decimals: Option<u8>,
444 ) -> ProgramResult {
445 let account_info_iter = &mut accounts.iter();
446
447 let source_account_info = next_account_info(account_info_iter)?;
448
449 let expected_mint_info = if let Some(expected_decimals) = expected_decimals {
450 Some((next_account_info(account_info_iter)?, expected_decimals))
451 } else {
452 None
453 };
454 let delegate_info = next_account_info(account_info_iter)?;
455 let owner_info = next_account_info(account_info_iter)?;
456 let owner_info_data_len = owner_info.data_len();
457
458 let mut source_account_data = source_account_info.data.borrow_mut();
459 let mut source_account =
460 StateWithExtensionsMut::<Account>::unpack(&mut source_account_data)?;
461
462 if source_account.base.is_frozen() {
463 return Err(TokenError::AccountFrozen.into());
464 }
465
466 if let Some((mint_info, expected_decimals)) = expected_mint_info {
467 if !cmp_pubkeys(&source_account.base.mint, mint_info.key) {
468 return Err(TokenError::MintMismatch.into());
469 }
470
471 let mint_data = mint_info.data.borrow();
472 let mint = StateWithExtensions::<Mint>::unpack(&mint_data)?;
473 if expected_decimals != mint.base.decimals {
474 return Err(TokenError::MintDecimalsMismatch.into());
475 }
476 }
477
478 Self::validate_owner(
479 program_id,
480 &source_account.base.owner,
481 owner_info,
482 owner_info_data_len,
483 account_info_iter.as_slice(),
484 )?;
485
486 source_account.base.delegate = COption::Some(*delegate_info.key);
487 source_account.base.delegated_amount = amount;
488 source_account.pack_base();
489
490 Ok(())
491 }
492
493 pub fn process_revoke(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult {
495 let account_info_iter = &mut accounts.iter();
496 let source_account_info = next_account_info(account_info_iter)?;
497 let authority_info = next_account_info(account_info_iter)?;
498 let authority_info_data_len = authority_info.data_len();
499
500 let mut source_account_data = source_account_info.data.borrow_mut();
501 let mut source_account =
502 StateWithExtensionsMut::<Account>::unpack(&mut source_account_data)?;
503 if source_account.base.is_frozen() {
504 return Err(TokenError::AccountFrozen.into());
505 }
506
507 Self::validate_owner(
508 program_id,
509 match source_account.base.delegate {
510 COption::Some(ref delegate) if cmp_pubkeys(authority_info.key, delegate) => {
511 delegate
512 }
513 _ => &source_account.base.owner,
514 },
515 authority_info,
516 authority_info_data_len,
517 account_info_iter.as_slice(),
518 )?;
519
520 source_account.base.delegate = COption::None;
521 source_account.base.delegated_amount = 0;
522 source_account.pack_base();
523
524 Ok(())
525 }
526
527 pub fn process_set_authority(
529 program_id: &Pubkey,
530 accounts: &[AccountInfo],
531 authority_type: AuthorityType,
532 new_authority: COption<Pubkey>,
533 ) -> ProgramResult {
534 let account_info_iter = &mut accounts.iter();
535 let account_info = next_account_info(account_info_iter)?;
536 let authority_info = next_account_info(account_info_iter)?;
537 let authority_info_data_len = authority_info.data_len();
538
539 let mut account_data = account_info.data.borrow_mut();
540 if let Ok(mut account) = StateWithExtensionsMut::<Account>::unpack(&mut account_data) {
541 if account.base.is_frozen() {
542 return Err(TokenError::AccountFrozen.into());
543 }
544
545 match authority_type {
546 AuthorityType::AccountOwner => {
547 Self::validate_owner(
548 program_id,
549 &account.base.owner,
550 authority_info,
551 authority_info_data_len,
552 account_info_iter.as_slice(),
553 )?;
554
555 if account.get_extension_mut::<ImmutableOwner>().is_ok() {
556 return Err(TokenError::ImmutableOwner.into());
557 }
558
559 if let COption::Some(authority) = new_authority {
560 account.base.owner = authority;
561 } else {
562 return Err(TokenError::InvalidInstruction.into());
563 }
564
565 account.base.delegate = COption::None;
566 account.base.delegated_amount = 0;
567
568 if account.base.is_native() {
569 account.base.close_authority = COption::None;
570 }
571 }
572 AuthorityType::CloseAccount => {
573 let authority = account.base.close_authority.unwrap_or(account.base.owner);
574 Self::validate_owner(
575 program_id,
576 &authority,
577 authority_info,
578 authority_info_data_len,
579 account_info_iter.as_slice(),
580 )?;
581 account.base.close_authority = new_authority;
582 }
583 _ => {
584 return Err(TokenError::AuthorityTypeNotSupported.into());
585 }
586 }
587 account.pack_base();
588 } else if let Ok(mut mint) = StateWithExtensionsMut::<Mint>::unpack(&mut account_data) {
589 match authority_type {
590 AuthorityType::MintTokens => {
591 let mint_authority = mint
594 .base
595 .mint_authority
596 .ok_or(Into::<ProgramError>::into(TokenError::FixedSupply))?;
597 Self::validate_owner(
598 program_id,
599 &mint_authority,
600 authority_info,
601 authority_info_data_len,
602 account_info_iter.as_slice(),
603 )?;
604 mint.base.mint_authority = new_authority;
605 mint.pack_base();
606 }
607 AuthorityType::FreezeAccount => {
608 let freeze_authority = mint
611 .base
612 .freeze_authority
613 .ok_or(Into::<ProgramError>::into(TokenError::MintCannotFreeze))?;
614 Self::validate_owner(
615 program_id,
616 &freeze_authority,
617 authority_info,
618 authority_info_data_len,
619 account_info_iter.as_slice(),
620 )?;
621 mint.base.freeze_authority = new_authority;
622 mint.pack_base();
623 }
624 AuthorityType::CloseMint => {
625 let extension = mint.get_extension_mut::<MintCloseAuthority>()?;
626 let maybe_close_authority: Option<Pubkey> = extension.close_authority.into();
627 let close_authority =
628 maybe_close_authority.ok_or(TokenError::AuthorityTypeNotSupported)?;
629 Self::validate_owner(
630 program_id,
631 &close_authority,
632 authority_info,
633 authority_info_data_len,
634 account_info_iter.as_slice(),
635 )?;
636 extension.close_authority = new_authority.try_into()?;
637 }
638 AuthorityType::TransferFeeConfig => {
639 let extension = mint.get_extension_mut::<TransferFeeConfig>()?;
640 let maybe_transfer_fee_config_authority: Option<Pubkey> =
641 extension.transfer_fee_config_authority.into();
642 let transfer_fee_config_authority = maybe_transfer_fee_config_authority
643 .ok_or(TokenError::AuthorityTypeNotSupported)?;
644 Self::validate_owner(
645 program_id,
646 &transfer_fee_config_authority,
647 authority_info,
648 authority_info_data_len,
649 account_info_iter.as_slice(),
650 )?;
651 extension.transfer_fee_config_authority = new_authority.try_into()?;
652 }
653 AuthorityType::WithheldWithdraw => {
654 let extension = mint.get_extension_mut::<TransferFeeConfig>()?;
655 let maybe_withdraw_withheld_authority: Option<Pubkey> =
656 extension.withdraw_withheld_authority.into();
657 let withdraw_withheld_authority = maybe_withdraw_withheld_authority
658 .ok_or(TokenError::AuthorityTypeNotSupported)?;
659 Self::validate_owner(
660 program_id,
661 &withdraw_withheld_authority,
662 authority_info,
663 authority_info_data_len,
664 account_info_iter.as_slice(),
665 )?;
666 extension.withdraw_withheld_authority = new_authority.try_into()?;
667 }
668 AuthorityType::InterestRate => {
669 let extension = mint.get_extension_mut::<InterestBearingConfig>()?;
670 let maybe_rate_authority: Option<Pubkey> = extension.rate_authority.into();
671 let rate_authority =
672 maybe_rate_authority.ok_or(TokenError::AuthorityTypeNotSupported)?;
673 Self::validate_owner(
674 program_id,
675 &rate_authority,
676 authority_info,
677 authority_info_data_len,
678 account_info_iter.as_slice(),
679 )?;
680 extension.rate_authority = new_authority.try_into()?;
681 }
682 _ => {
683 return Err(TokenError::AuthorityTypeNotSupported.into());
684 }
685 }
686 } else {
687 return Err(ProgramError::InvalidAccountData);
688 }
689
690 Ok(())
691 }
692
693 pub fn process_mint_to(
695 program_id: &Pubkey,
696 accounts: &[AccountInfo],
697 amount: u64,
698 expected_decimals: Option<u8>,
699 ) -> ProgramResult {
700 let account_info_iter = &mut accounts.iter();
701 let mint_info = next_account_info(account_info_iter)?;
702 let destination_account_info = next_account_info(account_info_iter)?;
703 let owner_info = next_account_info(account_info_iter)?;
704 let owner_info_data_len = owner_info.data_len();
705
706 let mut destination_account_data = destination_account_info.data.borrow_mut();
707 let mut destination_account =
708 StateWithExtensionsMut::<Account>::unpack(&mut destination_account_data)?;
709 if destination_account.base.is_frozen() {
710 return Err(TokenError::AccountFrozen.into());
711 }
712
713 if destination_account.base.is_native() {
714 return Err(TokenError::NativeNotSupported.into());
715 }
716 if !cmp_pubkeys(mint_info.key, &destination_account.base.mint) {
717 return Err(TokenError::MintMismatch.into());
718 }
719
720 let mut mint_data = mint_info.data.borrow_mut();
721 let mut mint = StateWithExtensionsMut::<Mint>::unpack(&mut mint_data)?;
722
723 if mint.get_extension::<NonTransferable>().is_ok()
726 && destination_account
727 .get_extension::<ImmutableOwner>()
728 .is_err()
729 {
730 return Err(TokenError::NonTransferableNeedsImmutableOwnership.into());
731 }
732
733 if let Some(expected_decimals) = expected_decimals {
734 if expected_decimals != mint.base.decimals {
735 return Err(TokenError::MintDecimalsMismatch.into());
736 }
737 }
738
739 match mint.base.mint_authority {
740 COption::Some(mint_authority) => Self::validate_owner(
741 program_id,
742 &mint_authority,
743 owner_info,
744 owner_info_data_len,
745 account_info_iter.as_slice(),
746 )?,
747 COption::None => return Err(TokenError::FixedSupply.into()),
748 }
749
750 check_program_account(mint_info.owner)?;
754 check_program_account(destination_account_info.owner)?;
755
756 destination_account.base.amount = destination_account
757 .base
758 .amount
759 .checked_add(amount)
760 .ok_or(TokenError::Overflow)?;
761
762 mint.base.supply = mint
763 .base
764 .supply
765 .checked_add(amount)
766 .ok_or(TokenError::Overflow)?;
767
768 mint.pack_base();
769 destination_account.pack_base();
770
771 Ok(())
772 }
773
774 pub fn process_burn(
776 program_id: &Pubkey,
777 accounts: &[AccountInfo],
778 amount: u64,
779 expected_decimals: Option<u8>,
780 ) -> ProgramResult {
781 let account_info_iter = &mut accounts.iter();
782
783 let source_account_info = next_account_info(account_info_iter)?;
784 let mint_info = next_account_info(account_info_iter)?;
785 let authority_info = next_account_info(account_info_iter)?;
786 let authority_info_data_len = authority_info.data_len();
787
788 let mut source_account_data = source_account_info.data.borrow_mut();
789 let mut source_account =
790 StateWithExtensionsMut::<Account>::unpack(&mut source_account_data)?;
791 let mut mint_data = mint_info.data.borrow_mut();
792 let mut mint = StateWithExtensionsMut::<Mint>::unpack(&mut mint_data)?;
793
794 if source_account.base.is_frozen() {
795 return Err(TokenError::AccountFrozen.into());
796 }
797 if source_account.base.is_native() {
798 return Err(TokenError::NativeNotSupported.into());
799 }
800 if source_account.base.amount < amount {
801 return Err(TokenError::InsufficientFunds.into());
802 }
803 if mint_info.key != &source_account.base.mint {
804 return Err(TokenError::MintMismatch.into());
805 }
806
807 if let Some(expected_decimals) = expected_decimals {
808 if expected_decimals != mint.base.decimals {
809 return Err(TokenError::MintDecimalsMismatch.into());
810 }
811 }
812
813 if !source_account
814 .base
815 .is_owned_by_system_program_or_incinerator()
816 {
817 match source_account.base.delegate {
818 COption::Some(ref delegate) if cmp_pubkeys(authority_info.key, delegate) => {
819 Self::validate_owner(
820 program_id,
821 delegate,
822 authority_info,
823 authority_info_data_len,
824 account_info_iter.as_slice(),
825 )?;
826
827 if source_account.base.delegated_amount < amount {
828 return Err(TokenError::InsufficientFunds.into());
829 }
830 source_account.base.delegated_amount = source_account
831 .base
832 .delegated_amount
833 .checked_sub(amount)
834 .ok_or(TokenError::Overflow)?;
835 if source_account.base.delegated_amount == 0 {
836 source_account.base.delegate = COption::None;
837 }
838 }
839 _ => Self::validate_owner(
840 program_id,
841 &source_account.base.owner,
842 authority_info,
843 authority_info_data_len,
844 account_info_iter.as_slice(),
845 )?,
846 }
847 }
848
849 check_program_account(source_account_info.owner)?;
853 check_program_account(mint_info.owner)?;
854
855 source_account.base.amount = source_account
856 .base
857 .amount
858 .checked_sub(amount)
859 .ok_or(TokenError::Overflow)?;
860 mint.base.supply = mint
861 .base
862 .supply
863 .checked_sub(amount)
864 .ok_or(TokenError::Overflow)?;
865
866 source_account.pack_base();
867 mint.pack_base();
868
869 Ok(())
870 }
871
872 pub fn process_close_account(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult {
874 let account_info_iter = &mut accounts.iter();
875 let source_account_info = next_account_info(account_info_iter)?;
876 let destination_account_info = next_account_info(account_info_iter)?;
877 let authority_info = next_account_info(account_info_iter)?;
878 let authority_info_data_len = authority_info.data_len();
879
880 if cmp_pubkeys(source_account_info.key, destination_account_info.key) {
881 return Err(ProgramError::InvalidAccountData);
882 }
883
884 let mut source_account_data = source_account_info.data.borrow_mut();
885 if let Ok(source_account) = StateWithExtensions::<Account>::unpack(&source_account_data) {
886 if !source_account.base.is_native() && source_account.base.amount != 0 {
887 return Err(TokenError::NonNativeHasBalance.into());
888 }
889
890 let authority = source_account
891 .base
892 .close_authority
893 .unwrap_or(source_account.base.owner);
894
895 if !source_account
896 .base
897 .is_owned_by_system_program_or_incinerator()
898 {
899 Self::validate_owner(
900 program_id,
901 &authority,
902 authority_info,
903 authority_info_data_len,
904 account_info_iter.as_slice(),
905 )?;
906 } else if !solana_sdk::incinerator::check_id(destination_account_info.key) {
907 return Err(ProgramError::InvalidAccountData);
908 }
909
910 if let Ok(transfer_fee_state) = source_account.get_extension::<TransferFeeAmount>() {
918 transfer_fee_state.closable()?
919 }
920 } else if let Ok(mint) = StateWithExtensions::<Mint>::unpack(&source_account_data) {
921 let extension = mint.get_extension::<MintCloseAuthority>()?;
922 let maybe_authority: Option<Pubkey> = extension.close_authority.into();
923 let authority = maybe_authority.ok_or(TokenError::AuthorityTypeNotSupported)?;
924 Self::validate_owner(
925 program_id,
926 &authority,
927 authority_info,
928 authority_info_data_len,
929 account_info_iter.as_slice(),
930 )?;
931
932 if mint.base.supply != 0 {
933 return Err(TokenError::MintHasSupply.into());
934 }
935 } else {
936 return Err(ProgramError::UninitializedAccount);
937 }
938
939 let destination_starting_lamports = destination_account_info.lamports();
940 **destination_account_info.lamports.borrow_mut() = destination_starting_lamports
941 .checked_add(source_account_info.lamports())
942 .ok_or(TokenError::Overflow)?;
943
944 **source_account_info.lamports.borrow_mut() = 0;
945 let data_len = source_account_data.len();
946 sol_memset(*source_account_data, 0, data_len);
947
948 Ok(())
949 }
950
951 pub fn process_toggle_freeze_account(
954 program_id: &Pubkey,
955 accounts: &[AccountInfo],
956 freeze: bool,
957 ) -> ProgramResult {
958 let account_info_iter = &mut accounts.iter();
959 let source_account_info = next_account_info(account_info_iter)?;
960 let mint_info = next_account_info(account_info_iter)?;
961 let authority_info = next_account_info(account_info_iter)?;
962 let authority_info_data_len = authority_info.data_len();
963
964 let mut source_account_data = source_account_info.data.borrow_mut();
965 let mut source_account =
966 StateWithExtensionsMut::<Account>::unpack(&mut source_account_data)?;
967 if freeze && source_account.base.is_frozen() || !freeze && !source_account.base.is_frozen()
968 {
969 return Err(TokenError::InvalidState.into());
970 }
971 if source_account.base.is_native() {
972 return Err(TokenError::NativeNotSupported.into());
973 }
974 if !cmp_pubkeys(mint_info.key, &source_account.base.mint) {
975 return Err(TokenError::MintMismatch.into());
976 }
977
978 let mint_data = mint_info.data.borrow();
979 let mint = StateWithExtensions::<Mint>::unpack(&mint_data)?;
980 match mint.base.freeze_authority {
981 COption::Some(authority) => Self::validate_owner(
982 program_id,
983 &authority,
984 authority_info,
985 authority_info_data_len,
986 account_info_iter.as_slice(),
987 ),
988 COption::None => Err(TokenError::MintCannotFreeze.into()),
989 }?;
990
991 source_account.base.state = if freeze {
992 AccountState::Frozen
993 } else {
994 AccountState::Initialized
995 };
996
997 source_account.pack_base();
998
999 Ok(())
1000 }
1001
1002 pub fn process_sync_native(accounts: &[AccountInfo]) -> ProgramResult {
1004 let account_info_iter = &mut accounts.iter();
1005 let native_account_info = next_account_info(account_info_iter)?;
1006
1007 check_program_account(native_account_info.owner)?;
1008 let mut native_account_data = native_account_info.data.borrow_mut();
1009 let mut native_account =
1010 StateWithExtensionsMut::<Account>::unpack(&mut native_account_data)?;
1011
1012 if let COption::Some(rent_exempt_reserve) = native_account.base.is_native {
1013 let new_amount = native_account_info
1014 .lamports()
1015 .checked_sub(rent_exempt_reserve)
1016 .ok_or(TokenError::Overflow)?;
1017 if new_amount < native_account.base.amount {
1018 return Err(TokenError::InvalidState.into());
1019 }
1020 native_account.base.amount = new_amount;
1021 } else {
1022 return Err(TokenError::NonNativeNotSupported.into());
1023 }
1024
1025 native_account.pack_base();
1026 Ok(())
1027 }
1028
1029 pub fn process_initialize_mint_close_authority(
1031 accounts: &[AccountInfo],
1032 close_authority: COption<Pubkey>,
1033 ) -> ProgramResult {
1034 let account_info_iter = &mut accounts.iter();
1035 let mint_account_info = next_account_info(account_info_iter)?;
1036
1037 let mut mint_data = mint_account_info.data.borrow_mut();
1038 let mut mint = StateWithExtensionsMut::<Mint>::unpack_uninitialized(&mut mint_data)?;
1039 let extension = mint.init_extension::<MintCloseAuthority>(true)?;
1040 extension.close_authority = close_authority.try_into()?;
1041
1042 Ok(())
1043 }
1044
1045 pub fn process_get_account_data_size(
1047 accounts: &[AccountInfo],
1048 new_extension_types: Vec<ExtensionType>,
1049 ) -> ProgramResult {
1050 let account_info_iter = &mut accounts.iter();
1051 let mint_account_info = next_account_info(account_info_iter)?;
1052
1053 let mut account_extensions = Self::get_required_account_extensions(mint_account_info)?;
1054 account_extensions.extend_from_slice(&new_extension_types);
1057
1058 let account_len = ExtensionType::get_account_len::<Account>(&account_extensions);
1059 set_return_data(&account_len.to_le_bytes());
1060
1061 Ok(())
1062 }
1063
1064 pub fn process_initialize_immutable_owner(accounts: &[AccountInfo]) -> ProgramResult {
1066 let account_info_iter = &mut accounts.iter();
1067 let token_account_info = next_account_info(account_info_iter)?;
1068 let token_account_data = &mut token_account_info.data.borrow_mut();
1069 let mut token_account =
1070 StateWithExtensionsMut::<Account>::unpack_uninitialized(token_account_data)?;
1071 token_account
1072 .init_extension::<ImmutableOwner>(true)
1073 .map(|_| ())
1074 }
1075
1076 pub fn process_amount_to_ui_amount(accounts: &[AccountInfo], amount: u64) -> ProgramResult {
1078 let account_info_iter = &mut accounts.iter();
1079 let mint_info = next_account_info(account_info_iter)?;
1080 check_program_account(mint_info.owner)?;
1081
1082 let mint_data = mint_info.data.borrow();
1083 let mint = StateWithExtensions::<Mint>::unpack(&mint_data)
1084 .map_err(|_| Into::<ProgramError>::into(TokenError::InvalidMint))?;
1085 let ui_amount = if let Ok(extension) = mint.get_extension::<InterestBearingConfig>() {
1086 let unix_timestamp = Clock::get()?.unix_timestamp;
1087 extension
1088 .amount_to_ui_amount(amount, mint.base.decimals, unix_timestamp)
1089 .ok_or(ProgramError::InvalidArgument)?
1090 } else {
1091 amount_to_ui_amount_string_trimmed(amount, mint.base.decimals)
1092 };
1093
1094 set_return_data(&ui_amount.into_bytes());
1095 Ok(())
1096 }
1097
1098 pub fn process_ui_amount_to_amount(accounts: &[AccountInfo], ui_amount: &str) -> ProgramResult {
1100 let account_info_iter = &mut accounts.iter();
1101 let mint_info = next_account_info(account_info_iter)?;
1102 check_program_account(mint_info.owner)?;
1103
1104 let mint_data = mint_info.data.borrow();
1105 let mint = StateWithExtensions::<Mint>::unpack(&mint_data)
1106 .map_err(|_| Into::<ProgramError>::into(TokenError::InvalidMint))?;
1107 let amount = if let Ok(extension) = mint.get_extension::<InterestBearingConfig>() {
1108 let unix_timestamp = Clock::get()?.unix_timestamp;
1109 extension.try_ui_amount_into_amount(ui_amount, mint.base.decimals, unix_timestamp)?
1110 } else {
1111 try_ui_amount_into_amount(ui_amount.to_string(), mint.base.decimals)?
1112 };
1113
1114 set_return_data(&amount.to_le_bytes());
1115 Ok(())
1116 }
1117
1118 pub fn process_create_native_mint(accounts: &[AccountInfo]) -> ProgramResult {
1120 let account_info_iter = &mut accounts.iter();
1121 let payer_info = next_account_info(account_info_iter)?;
1122 let native_mint_info = next_account_info(account_info_iter)?;
1123 let system_program_info = next_account_info(account_info_iter)?;
1124
1125 if *native_mint_info.key != native_mint::id() {
1126 return Err(TokenError::InvalidMint.into());
1127 }
1128
1129 let rent = Rent::get()?;
1130 let new_minimum_balance = rent.minimum_balance(Mint::get_packed_len());
1131 let lamports_diff = new_minimum_balance.saturating_sub(native_mint_info.lamports());
1132 invoke(
1133 &system_instruction::transfer(payer_info.key, native_mint_info.key, lamports_diff),
1134 &[
1135 payer_info.clone(),
1136 native_mint_info.clone(),
1137 system_program_info.clone(),
1138 ],
1139 )?;
1140
1141 invoke_signed(
1142 &system_instruction::allocate(native_mint_info.key, Mint::get_packed_len() as u64),
1143 &[native_mint_info.clone(), system_program_info.clone()],
1144 &[native_mint::PROGRAM_ADDRESS_SEEDS],
1145 )?;
1146
1147 invoke_signed(
1148 &system_instruction::assign(
1149 native_mint_info.key,
1150 &crate::program::spl_token_2022::id(),
1151 ),
1152 &[native_mint_info.clone(), system_program_info.clone()],
1153 &[native_mint::PROGRAM_ADDRESS_SEEDS],
1154 )?;
1155
1156 Mint::pack(
1157 Mint {
1158 decimals: native_mint::DECIMALS,
1159 is_initialized: true,
1160 ..Mint::default()
1161 },
1162 &mut native_mint_info.data.borrow_mut(),
1163 )
1164 }
1165
1166 pub fn process_initialize_non_transferable_mint(accounts: &[AccountInfo]) -> ProgramResult {
1168 let account_info_iter = &mut accounts.iter();
1169 let mint_account_info = next_account_info(account_info_iter)?;
1170
1171 let mut mint_data = mint_account_info.data.borrow_mut();
1172 let mut mint = StateWithExtensionsMut::<Mint>::unpack_uninitialized(&mut mint_data)?;
1173 mint.init_extension::<NonTransferable>(true)?;
1174
1175 Ok(())
1176 }
1177
1178 pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], input: &[u8]) -> ProgramResult {
1180 let instruction = TokenInstruction::unpack(input)?;
1181
1182 match instruction {
1183 TokenInstruction::InitializeMint {
1184 decimals,
1185 mint_authority,
1186 freeze_authority,
1187 } => {
1188 msg!("Instruction: InitializeMint");
1189 Self::process_initialize_mint(accounts, decimals, mint_authority, freeze_authority)
1190 }
1191 TokenInstruction::InitializeMint2 {
1192 decimals,
1193 mint_authority,
1194 freeze_authority,
1195 } => {
1196 msg!("Instruction: InitializeMint2");
1197 Self::process_initialize_mint2(accounts, decimals, mint_authority, freeze_authority)
1198 }
1199 TokenInstruction::InitializeAccount => {
1200 msg!("Instruction: InitializeAccount");
1201 Self::process_initialize_account(accounts)
1202 }
1203 TokenInstruction::InitializeAccount2 { owner } => {
1204 msg!("Instruction: InitializeAccount2");
1205 Self::process_initialize_account2(accounts, owner)
1206 }
1207 TokenInstruction::InitializeAccount3 { owner } => {
1208 msg!("Instruction: InitializeAccount3");
1209 Self::process_initialize_account3(accounts, owner)
1210 }
1211 TokenInstruction::InitializeMultisig { m } => {
1212 msg!("Instruction: InitializeMultisig");
1213 Self::process_initialize_multisig(accounts, m)
1214 }
1215 TokenInstruction::InitializeMultisig2 { m } => {
1216 msg!("Instruction: InitializeMultisig2");
1217 Self::process_initialize_multisig2(accounts, m)
1218 }
1219 #[allow(deprecated)]
1220 TokenInstruction::Transfer { amount } => {
1221 msg!("Instruction: Transfer");
1222 Self::process_transfer(program_id, accounts, amount, None, None)
1223 }
1224 TokenInstruction::Approve { amount } => {
1225 msg!("Instruction: Approve");
1226 Self::process_approve(program_id, accounts, amount, None)
1227 }
1228 TokenInstruction::Revoke => {
1229 msg!("Instruction: Revoke");
1230 Self::process_revoke(program_id, accounts)
1231 }
1232 TokenInstruction::SetAuthority {
1233 authority_type,
1234 new_authority,
1235 } => {
1236 msg!("Instruction: SetAuthority");
1237 Self::process_set_authority(program_id, accounts, authority_type, new_authority)
1238 }
1239 TokenInstruction::MintTo { amount } => {
1240 msg!("Instruction: MintTo");
1241 Self::process_mint_to(program_id, accounts, amount, None)
1242 }
1243 TokenInstruction::Burn { amount } => {
1244 msg!("Instruction: Burn");
1245 Self::process_burn(program_id, accounts, amount, None)
1246 }
1247 TokenInstruction::CloseAccount => {
1248 msg!("Instruction: CloseAccount");
1249 Self::process_close_account(program_id, accounts)
1250 }
1251 TokenInstruction::FreezeAccount => {
1252 msg!("Instruction: FreezeAccount");
1253 Self::process_toggle_freeze_account(program_id, accounts, true)
1254 }
1255 TokenInstruction::ThawAccount => {
1256 msg!("Instruction: ThawAccount");
1257 Self::process_toggle_freeze_account(program_id, accounts, false)
1258 }
1259 TokenInstruction::TransferChecked { amount, decimals } => {
1260 msg!("Instruction: TransferChecked");
1261 Self::process_transfer(program_id, accounts, amount, Some(decimals), None)
1262 }
1263 TokenInstruction::ApproveChecked { amount, decimals } => {
1264 msg!("Instruction: ApproveChecked");
1265 Self::process_approve(program_id, accounts, amount, Some(decimals))
1266 }
1267 TokenInstruction::MintToChecked { amount, decimals } => {
1268 msg!("Instruction: MintToChecked");
1269 Self::process_mint_to(program_id, accounts, amount, Some(decimals))
1270 }
1271 TokenInstruction::BurnChecked { amount, decimals } => {
1272 msg!("Instruction: BurnChecked");
1273 Self::process_burn(program_id, accounts, amount, Some(decimals))
1274 }
1275 TokenInstruction::SyncNative => {
1276 msg!("Instruction: SyncNative");
1277 Self::process_sync_native(accounts)
1278 }
1279 TokenInstruction::GetAccountDataSize { extension_types } => {
1280 msg!("Instruction: GetAccountDataSize");
1281 Self::process_get_account_data_size(accounts, extension_types)
1282 }
1283 TokenInstruction::InitializeMintCloseAuthority { close_authority } => {
1284 msg!("Instruction: InitializeMintCloseAuthority");
1285 Self::process_initialize_mint_close_authority(accounts, close_authority)
1286 }
1287 TokenInstruction::TransferFeeExtension(instruction) => {
1288 transfer_fee::processor::process_instruction(program_id, accounts, instruction)
1289 }
1290 TokenInstruction::ConfidentialTransferExtension => {
1292 Err(ProgramError::InvalidArgument)
1293 }
1299 TokenInstruction::DefaultAccountStateExtension => {
1300 default_account_state::processor::process_instruction(
1301 program_id,
1302 accounts,
1303 &input[1..],
1304 )
1305 }
1306 TokenInstruction::InitializeImmutableOwner => {
1307 msg!("Instruction: InitializeImmutableOwner");
1308 Self::process_initialize_immutable_owner(accounts)
1309 }
1310 TokenInstruction::AmountToUiAmount { amount } => {
1311 msg!("Instruction: AmountToUiAmount");
1312 Self::process_amount_to_ui_amount(accounts, amount)
1313 }
1314 TokenInstruction::UiAmountToAmount { ui_amount } => {
1315 msg!("Instruction: UiAmountToAmount");
1316 Self::process_ui_amount_to_amount(accounts, ui_amount)
1317 }
1318 TokenInstruction::Reallocate { extension_types } => {
1319 msg!("Instruction: Reallocate");
1320 reallocate::process_reallocate(program_id, accounts, extension_types)
1321 }
1322 TokenInstruction::MemoTransferExtension => {
1323 memo_transfer::processor::process_instruction(program_id, accounts, &input[1..])
1324 }
1325 TokenInstruction::CreateNativeMint => {
1326 msg!("Instruction: CreateNativeMint");
1327 Self::process_create_native_mint(accounts)
1328 }
1329 TokenInstruction::InitializeNonTransferableMint => {
1330 msg!("Instruction: InitializeNonTransferableMint");
1331 Self::process_initialize_non_transferable_mint(accounts)
1332 }
1333 TokenInstruction::InterestBearingMintExtension => {
1334 interest_bearing_mint::processor::process_instruction(
1335 program_id,
1336 accounts,
1337 &input[1..],
1338 )
1339 }
1340 }
1341 }
1342
1343 pub fn validate_owner(
1345 program_id: &Pubkey,
1346 expected_owner: &Pubkey,
1347 owner_account_info: &AccountInfo,
1348 owner_account_data_len: usize,
1349 signers: &[AccountInfo],
1350 ) -> ProgramResult {
1351 if !cmp_pubkeys(expected_owner, owner_account_info.key) {
1352 return Err(TokenError::OwnerMismatch.into());
1353 }
1354
1355 if cmp_pubkeys(program_id, owner_account_info.owner)
1356 && owner_account_data_len == Multisig::get_packed_len()
1357 {
1358 let multisig = Multisig::unpack(&owner_account_info.data.borrow())?;
1359 let mut num_signers = 0;
1360 let mut matched = [false; MAX_SIGNERS];
1361 for signer in signers.iter() {
1362 for (position, key) in multisig.signers[0..multisig.n as usize].iter().enumerate() {
1363 if cmp_pubkeys(key, signer.key) && !matched[position] {
1364 if !signer.is_signer {
1365 return Err(ProgramError::MissingRequiredSignature);
1366 }
1367 matched[position] = true;
1368 num_signers += 1;
1369 }
1370 }
1371 }
1372 if num_signers < multisig.m {
1373 return Err(ProgramError::MissingRequiredSignature);
1374 }
1375 return Ok(());
1376 } else if !owner_account_info.is_signer {
1377 return Err(ProgramError::MissingRequiredSignature);
1378 }
1379 Ok(())
1380 }
1381
1382 fn get_required_account_extensions(
1383 mint_account_info: &AccountInfo,
1384 ) -> Result<Vec<ExtensionType>, ProgramError> {
1385 let mint_data = mint_account_info.data.borrow();
1386 let state = StateWithExtensions::<Mint>::unpack(&mint_data)
1387 .map_err(|_| Into::<ProgramError>::into(TokenError::InvalidMint))?;
1388 Self::get_required_account_extensions_from_unpacked_mint(mint_account_info.owner, &state)
1389 }
1390
1391 fn get_required_account_extensions_from_unpacked_mint(
1392 token_program_id: &Pubkey,
1393 state: &StateWithExtensions<Mint>,
1394 ) -> Result<Vec<ExtensionType>, ProgramError> {
1395 check_program_account(token_program_id)?;
1396 let mint_extensions: Vec<ExtensionType> = state.get_extension_types()?;
1397 Ok(ExtensionType::get_required_init_account_extensions(
1398 &mint_extensions,
1399 ))
1400 }
1401}
1402
1403impl PrintProgramError for TokenError {
1404 fn print<E>(&self)
1405 where
1406 E: 'static + std::error::Error + DecodeError<E> + PrintProgramError + FromPrimitive,
1407 {
1408 match self {
1409 TokenError::NotRentExempt => msg!("Error: Lamport balance below rent-exempt threshold"),
1410 TokenError::InsufficientFunds => msg!("Error: insufficient funds"),
1411 TokenError::InvalidMint => msg!("Error: Invalid Mint"),
1412 TokenError::MintMismatch => msg!("Error: Account not associated with this Mint"),
1413 TokenError::OwnerMismatch => msg!("Error: owner does not match"),
1414 TokenError::FixedSupply => msg!("Error: the total supply of this token is fixed"),
1415 TokenError::AlreadyInUse => msg!("Error: account or token already in use"),
1416 TokenError::InvalidNumberOfProvidedSigners => {
1417 msg!("Error: Invalid number of provided signers")
1418 }
1419 TokenError::InvalidNumberOfRequiredSigners => {
1420 msg!("Error: Invalid number of required signers")
1421 }
1422 TokenError::UninitializedState => msg!("Error: State is uninitialized"),
1423 TokenError::NativeNotSupported => {
1424 msg!("Error: Instruction does not support native tokens")
1425 }
1426 TokenError::NonNativeHasBalance => {
1427 msg!("Error: Non-native account can only be closed if its balance is zero")
1428 }
1429 TokenError::InvalidInstruction => msg!("Error: Invalid instruction"),
1430 TokenError::InvalidState => msg!("Error: Invalid account state for operation"),
1431 TokenError::Overflow => msg!("Error: Operation overflowed"),
1432 TokenError::AuthorityTypeNotSupported => {
1433 msg!("Error: Account does not support specified authority type")
1434 }
1435 TokenError::MintCannotFreeze => msg!("Error: This token mint cannot freeze accounts"),
1436 TokenError::AccountFrozen => msg!("Error: Account is frozen"),
1437 TokenError::MintDecimalsMismatch => {
1438 msg!("Error: decimals different from the Mint decimals")
1439 }
1440 TokenError::NonNativeNotSupported => {
1441 msg!("Error: Instruction does not support non-native tokens")
1442 }
1443 TokenError::ExtensionTypeMismatch => {
1444 msg!("Error: New extension type does not match already existing extensions")
1445 }
1446 TokenError::ExtensionBaseMismatch => {
1447 msg!("Error: Extension does not match the base type provided")
1448 }
1449 TokenError::ExtensionAlreadyInitialized => {
1450 msg!("Error: Extension already initialized on this account")
1451 }
1452 TokenError::ConfidentialTransferAccountHasBalance => {
1453 msg!("Error: An account can only be closed if its confidential balance is zero")
1454 }
1455 TokenError::ConfidentialTransferAccountNotApproved => {
1456 msg!("Error: Account not approved for confidential transfers")
1457 }
1458 TokenError::ConfidentialTransferDepositsAndTransfersDisabled => {
1459 msg!("Error: Account not accepting deposits or transfers")
1460 }
1461 TokenError::ConfidentialTransferElGamalPubkeyMismatch => {
1462 msg!("Error: ElGamal public key mismatch")
1463 }
1464 TokenError::ConfidentialTransferBalanceMismatch => {
1465 msg!("Error: Balance mismatch")
1466 }
1467 TokenError::MintHasSupply => {
1468 msg!("Error: Mint has non-zero supply. Burn all tokens before closing the mint")
1469 }
1470 TokenError::NoAuthorityExists => {
1471 msg!("Error: No authority exists to perform the desired operation");
1472 }
1473 TokenError::TransferFeeExceedsMaximum => {
1474 msg!("Error: Transfer fee exceeds maximum of 10,000 basis points");
1475 }
1476 TokenError::MintRequiredForTransfer => {
1477 msg!("Mint required for this account to transfer tokens, use `transfer_checked` or `transfer_checked_with_fee`");
1478 }
1479 TokenError::FeeMismatch => {
1480 msg!("Calculated fee does not match expected fee");
1481 }
1482 TokenError::FeeParametersMismatch => {
1483 msg!("Fee parameters associated with zero-knowledge proofs do not match fee parameters in mint")
1484 }
1485 TokenError::ImmutableOwner => {
1486 msg!("The owner authority cannot be changed");
1487 }
1488 TokenError::AccountHasWithheldTransferFees => {
1489 msg!("Error: An account can only be closed if its withheld fee balance is zero, harvest fees to the mint and try again");
1490 }
1491 TokenError::NoMemo => {
1492 msg!("Error: No memo in previous instruction; required for recipient to receive a transfer");
1493 }
1494 TokenError::NonTransferable => {
1495 msg!("Transfer is disabled for this mint");
1496 }
1497 TokenError::NonTransferableNeedsImmutableOwnership => {
1498 msg!("Non-transferable tokens can't be minted to an account without immutable ownership");
1499 }
1500 TokenError::MaximumPendingBalanceCreditCounterExceeded => {
1501 msg!("The total number of `Deposit` and `Transfer` instructions to an account cannot exceed the associated `maximum_pending_balance_credit_counter`");
1502 }
1503 }
1504 }
1505}