1use std::convert::{TryFrom, TryInto};
6
7use rialo_s_account_info::{next_account_info, AccountInfo};
8use rialo_s_clock::Clock;
9use rialo_s_cpi::{invoke, invoke_signed, set_return_data};
10use rialo_s_msg::msg;
11use rialo_s_program_error::{ProgramError, ProgramResult};
12use rialo_s_program_option::COption;
13use rialo_s_program_pack::Pack;
14use rialo_s_pubkey::Pubkey;
15use rialo_s_rent::Rent;
16use rialo_s_sdk_ids::system_program;
17use rialo_s_spl_pod::{
18 bytemuck::{pod_from_bytes, pod_from_bytes_mut},
19 primitives::{PodBool, PodU64},
20};
21use rialo_s_spl_token_group_interface::instruction::TokenGroupInstruction;
22use rialo_s_spl_token_metadata_interface::instruction::TokenMetadataInstruction;
23use rialo_s_system_interface::instruction as system_instruction;
24use rialo_s_sysvar::Sysvar;
25use rialo_spl_token_2022_interface::{
26 check_program_account,
27 error::TokenError,
28 extension::{
29 confidential_mint_burn::ConfidentialMintBurn,
30 confidential_transfer::{ConfidentialTransferAccount, ConfidentialTransferMint},
31 confidential_transfer_fee::{ConfidentialTransferFeeAmount, ConfidentialTransferFeeConfig},
32 cpi_guard::CpiGuard,
33 default_account_state::DefaultAccountState,
34 group_member_pointer::GroupMemberPointer,
35 group_pointer::GroupPointer,
36 immutable_owner::ImmutableOwner,
37 interest_bearing_mint::InterestBearingConfig,
38 memo_transfer::memo_required,
39 metadata_pointer::MetadataPointer,
40 mint_close_authority::MintCloseAuthority,
41 non_transferable::{NonTransferable, NonTransferableAccount},
42 pausable::{PausableAccount, PausableConfig},
43 permanent_delegate::{get_permanent_delegate, PermanentDelegate},
44 scaled_ui_amount::ScaledUiAmountConfig,
45 transfer_fee::{TransferFeeAmount, TransferFeeConfig},
46 transfer_hook::{TransferHook, TransferHookAccount},
47 AccountType, BaseStateWithExtensions, BaseStateWithExtensionsMut, ExtensionType,
48 PodStateWithExtensions, PodStateWithExtensionsMut,
49 },
50 instruction::{
51 decode_instruction_data, decode_instruction_type, derive_tombstone_pda,
52 is_valid_signer_index, AuthorityType, MAX_SIGNERS, TOMBSTONE_LEN, TOMBSTONE_SEED,
53 },
54 native_mint,
55 pod::{PodAccount, PodCOption, PodMint, PodMultisig},
56 state::{Account, AccountState, Mint, MintTombstone, PackedSizeOf},
57};
58
59use crate::{
60 extension::{
61 confidential_mint_burn, confidential_transfer, confidential_transfer_fee,
62 cpi_guard::{self, in_cpi},
63 default_account_state, group_member_pointer, group_pointer, interest_bearing_mint,
64 memo_transfer::{self, check_previous_sibling_instruction_is_memo},
65 metadata_pointer, pausable, reallocate, scaled_ui_amount, token_group, token_metadata,
66 transfer_fee, transfer_hook,
67 },
68 pod_instruction::{
69 decode_instruction_data_with_coption_pubkey, AmountCheckedData, AmountData,
70 InitializeMintData, InitializeMultisigData, PodTokenInstruction, SetAuthorityData,
71 },
72};
73
74pub(crate) enum TransferInstruction {
75 Unchecked,
76 Checked { decimals: u8 },
77 CheckedWithFee { decimals: u8, fee: u64 },
78}
79
80pub(crate) enum InstructionVariant {
81 Unchecked,
82 Checked { decimals: u8 },
83}
84pub struct Processor {}
86impl Processor {
87 fn _process_initialize_mint(
88 accounts: &[AccountInfo<'_>],
89 decimals: u8,
90 mint_authority: &Pubkey,
91 freeze_authority: PodCOption<Pubkey>,
92 rent_sysvar_account: bool,
93 ) -> ProgramResult {
94 let account_info_iter = &mut accounts.iter();
95 let mint_info = next_account_info(account_info_iter)?;
96 let mint_data_len = mint_info.data_len();
97 let mut mint_data = mint_info.data.borrow_mut();
98
99 let rent = if rent_sysvar_account {
103 let rent_info = next_account_info(account_info_iter)?;
105 Rent::from_account_info(rent_info)?
106 } else {
107 let tomb_info = next_account_info(account_info_iter)?;
109
110 let (expected_pda, _bump) = derive_tombstone_pda(&crate::id(), mint_info.key);
111 if tomb_info.key != &expected_pda {
112 return Err(TokenError::TombstoneAddressMismatch.into());
113 }
114
115 if tomb_info.kelvins() > 0 {
117 return Err(TokenError::MintRetired.into());
118 }
119
120 Rent::get()?
121 };
122
123 if !rent.is_exempt(mint_info.kelvins(), mint_data_len) {
124 return Err(TokenError::NotRentExempt.into());
125 }
126
127 let mut mint = PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut mint_data)?;
128 let extension_types = mint.get_extension_types()?;
129 if ExtensionType::try_calculate_account_len::<Mint>(&extension_types)? != mint_data_len {
130 return Err(ProgramError::InvalidAccountData);
131 }
132 ExtensionType::check_for_invalid_mint_extension_combinations(&extension_types)?;
133
134 if let Ok(default_account_state) = mint.get_extension_mut::<DefaultAccountState>() {
135 let default_account_state = AccountState::try_from(default_account_state.state)
136 .or(Err(ProgramError::InvalidAccountData))?;
137 if default_account_state == AccountState::Frozen && freeze_authority.is_none() {
138 return Err(TokenError::MintCannotFreeze.into());
139 }
140 }
141
142 mint.base.mint_authority = PodCOption::some(*mint_authority);
143 mint.base.decimals = decimals;
144 mint.base.is_initialized = PodBool::from_bool(true);
145 mint.base.freeze_authority = freeze_authority;
146 mint.init_account_type()?;
147
148 Ok(())
149 }
150
151 pub fn process_initialize_mint(
153 accounts: &[AccountInfo<'_>],
154 decimals: u8,
155 mint_authority: &Pubkey,
156 freeze_authority: PodCOption<Pubkey>,
157 ) -> ProgramResult {
158 Self::_process_initialize_mint(accounts, decimals, mint_authority, freeze_authority, true)
159 }
160
161 pub fn process_initialize_mint2(
164 accounts: &[AccountInfo<'_>],
165 decimals: u8,
166 mint_authority: &Pubkey,
167 freeze_authority: PodCOption<Pubkey>,
168 ) -> ProgramResult {
169 Self::_process_initialize_mint(accounts, decimals, mint_authority, freeze_authority, false)
170 }
171
172 fn _process_initialize_account(
173 accounts: &[AccountInfo<'_>],
174 owner: Option<&Pubkey>,
175 rent_sysvar_account: bool,
176 ) -> ProgramResult {
177 let account_info_iter = &mut accounts.iter();
178 let new_account_info = next_account_info(account_info_iter)?;
179 let mint_info = next_account_info(account_info_iter)?;
180 let owner = if let Some(owner) = owner {
181 owner
182 } else {
183 next_account_info(account_info_iter)?.key
184 };
185 let new_account_info_data_len = new_account_info.data_len();
186 let rent = if rent_sysvar_account {
187 Rent::from_account_info(next_account_info(account_info_iter)?)?
188 } else {
189 Rent::get()?
190 };
191
192 let mut account_data = new_account_info.data.borrow_mut();
193 let mut account =
195 PodStateWithExtensionsMut::<PodAccount>::unpack_uninitialized(&mut account_data)?;
196
197 if !rent.is_exempt(new_account_info.kelvins(), new_account_info_data_len) {
198 return Err(TokenError::NotRentExempt.into());
199 }
200
201 let mint_data = mint_info.data.borrow();
203 let mint = PodStateWithExtensions::<PodMint>::unpack(&mint_data)
204 .map_err(|_| Into::<ProgramError>::into(TokenError::InvalidMint))?;
205 if mint
206 .get_extension::<PermanentDelegate>()
207 .map(|e| Option::<Pubkey>::from(e.delegate).is_some())
208 .unwrap_or(false)
209 {
210 msg!("Warning: Mint has a permanent delegate, so tokens in this account may be seized at any time");
211 }
212 let required_extensions =
213 Self::get_required_account_extensions_from_unpacked_mint(mint_info.owner, &mint)?;
214 if ExtensionType::try_calculate_account_len::<Account>(&required_extensions)?
215 > new_account_info_data_len
216 {
217 return Err(ProgramError::InvalidAccountData);
218 }
219 for extension in required_extensions {
220 account.init_account_extension_from_type(extension)?;
221 }
222
223 let starting_state =
224 if let Ok(default_account_state) = mint.get_extension::<DefaultAccountState>() {
225 AccountState::try_from(default_account_state.state)
226 .or(Err(ProgramError::InvalidAccountData))?
227 } else {
228 AccountState::Initialized
229 };
230
231 account.base.mint = *mint_info.key;
232 account.base.owner = *owner;
233 account.base.close_authority = PodCOption::none();
234 account.base.delegate = PodCOption::none();
235 account.base.delegated_amount = 0.into();
236 account.base.state = starting_state.into();
237 if mint_info.key == &native_mint::id() {
238 let rent_exempt_reserve = rent.minimum_balance(new_account_info_data_len);
239 account.base.is_native = PodCOption::some(rent_exempt_reserve.into());
240 account.base.amount = new_account_info
241 .kelvins()
242 .checked_sub(rent_exempt_reserve)
243 .ok_or(TokenError::Overflow)?
244 .into();
245 } else {
246 account.base.is_native = PodCOption::none();
247 account.base.amount = 0.into();
248 };
249
250 account.init_account_type()?;
251
252 Ok(())
253 }
254
255 pub fn process_initialize_account(accounts: &[AccountInfo<'_>]) -> ProgramResult {
258 Self::_process_initialize_account(accounts, None, true)
259 }
260
261 pub fn process_initialize_account2(
264 accounts: &[AccountInfo<'_>],
265 owner: &Pubkey,
266 ) -> ProgramResult {
267 Self::_process_initialize_account(accounts, Some(owner), true)
268 }
269
270 pub fn process_initialize_account3(
273 accounts: &[AccountInfo<'_>],
274 owner: &Pubkey,
275 ) -> ProgramResult {
276 Self::_process_initialize_account(accounts, Some(owner), false)
277 }
278
279 fn _process_initialize_multisig(
280 accounts: &[AccountInfo<'_>],
281 m: u8,
282 rent_sysvar_account: bool,
283 ) -> ProgramResult {
284 let account_info_iter = &mut accounts.iter();
285 let multisig_info = next_account_info(account_info_iter)?;
286 let multisig_info_data_len = multisig_info.data_len();
287 let rent = if rent_sysvar_account {
288 Rent::from_account_info(next_account_info(account_info_iter)?)?
289 } else {
290 Rent::get()?
291 };
292
293 let mut multisig_data = multisig_info.data.borrow_mut();
294 let multisig = pod_from_bytes_mut::<PodMultisig>(&mut multisig_data)?;
295 if bool::from(multisig.is_initialized) {
296 return Err(TokenError::AlreadyInUse.into());
297 }
298
299 if !rent.is_exempt(multisig_info.kelvins(), multisig_info_data_len) {
300 return Err(TokenError::NotRentExempt.into());
301 }
302
303 let signer_infos = account_info_iter.as_slice();
304 multisig.m = m;
305 multisig.n = signer_infos.len() as u8;
306 if !is_valid_signer_index(multisig.n as usize) {
307 return Err(TokenError::InvalidNumberOfProvidedSigners.into());
308 }
309 if !is_valid_signer_index(multisig.m as usize) {
310 return Err(TokenError::InvalidNumberOfRequiredSigners.into());
311 }
312 for (i, signer_info) in signer_infos.iter().enumerate() {
313 multisig.signers[i] = *signer_info.key;
314 }
315 multisig.is_initialized = true.into();
316
317 Ok(())
318 }
319
320 pub fn process_initialize_multisig(accounts: &[AccountInfo<'_>], m: u8) -> ProgramResult {
323 Self::_process_initialize_multisig(accounts, m, true)
324 }
325
326 pub fn process_initialize_multisig2(accounts: &[AccountInfo<'_>], m: u8) -> ProgramResult {
329 Self::_process_initialize_multisig(accounts, m, false)
330 }
331
332 pub(crate) fn process_transfer(
334 program_id: &Pubkey,
335 accounts: &[AccountInfo<'_>],
336 amount: u64,
337 transfer_instruction: TransferInstruction,
338 ) -> ProgramResult {
339 let account_info_iter = &mut accounts.iter();
340
341 let source_account_info = next_account_info(account_info_iter)?;
342
343 let expected_mint_info = match transfer_instruction {
344 TransferInstruction::Unchecked => None,
345 TransferInstruction::Checked { decimals }
346 | TransferInstruction::CheckedWithFee { decimals, .. } => {
347 Some((next_account_info(account_info_iter)?, decimals))
348 }
349 };
350
351 let destination_account_info = next_account_info(account_info_iter)?;
352 let authority_info = next_account_info(account_info_iter)?;
353 let authority_info_data_len = authority_info.data_len();
354
355 let mut source_account_data = source_account_info.data.borrow_mut();
356 let mut source_account =
357 PodStateWithExtensionsMut::<PodAccount>::unpack(&mut source_account_data)?;
358 if source_account.base.is_frozen() {
359 return Err(TokenError::AccountFrozen.into());
360 }
361 let source_amount = u64::from(source_account.base.amount);
362 if source_amount < amount {
363 return Err(TokenError::InsufficientFunds.into());
364 }
365 if source_account
366 .get_extension::<NonTransferableAccount>()
367 .is_ok()
368 {
369 return Err(TokenError::NonTransferable.into());
370 }
371
372 let (calculated_fee, maybe_permanent_delegate, maybe_transfer_hook_program_id) =
373 if let Some((mint_info, expected_decimals)) = expected_mint_info {
374 if &source_account.base.mint != mint_info.key {
375 return Err(TokenError::MintMismatch.into());
376 }
377
378 let mint_data = mint_info.try_borrow_data()?;
379 let mint = PodStateWithExtensions::<PodMint>::unpack(&mint_data)?;
380
381 if expected_decimals != mint.base.decimals {
382 return Err(TokenError::MintDecimalsMismatch.into());
383 }
384
385 let fee = if let Ok(transfer_fee_config) = mint.get_extension::<TransferFeeConfig>()
386 {
387 transfer_fee_config
388 .calculate_fee(Clock::get()?.unix_timestamp as u64, amount)
389 .ok_or(TokenError::Overflow)?
390 } else {
391 0
392 };
393
394 if let Ok(extension) = mint.get_extension::<PausableConfig>() {
395 if extension.paused.into() {
396 return Err(TokenError::MintPaused.into());
397 }
398 }
399
400 let maybe_permanent_delegate = get_permanent_delegate(&mint);
401 let maybe_transfer_hook_program_id = transfer_hook::get_program_id(&mint);
402
403 (
404 fee,
405 maybe_permanent_delegate,
406 maybe_transfer_hook_program_id,
407 )
408 } else {
409 if source_account
412 .get_extension::<TransferHookAccount>()
413 .is_ok()
414 {
415 return Err(TokenError::MintRequiredForTransfer.into());
416 }
417
418 if source_account
421 .get_extension_mut::<TransferFeeAmount>()
422 .is_ok()
423 {
424 return Err(TokenError::MintRequiredForTransfer.into());
425 }
426
427 if source_account.get_extension::<PausableAccount>().is_ok() {
430 return Err(TokenError::MintRequiredForTransfer.into());
431 }
432
433 (0, None, None)
434 };
435 if let TransferInstruction::CheckedWithFee { fee, .. } = transfer_instruction {
436 if calculated_fee != fee {
437 msg!("Calculated fee {}, received {}", calculated_fee, fee);
438 return Err(TokenError::FeeMismatch.into());
439 }
440 }
441
442 let self_transfer = source_account_info.key == destination_account_info.key;
443 if let Ok(cpi_guard) = source_account.get_extension::<CpiGuard>() {
444 if *authority_info.key == source_account.base.owner
449 && cpi_guard.lock_cpi.into()
450 && in_cpi()
451 {
452 return Err(TokenError::CpiGuardTransferBlocked.into());
453 }
454 }
455 match (source_account.base.delegate, maybe_permanent_delegate) {
456 (_, Some(ref delegate)) if authority_info.key == delegate => Self::validate_owner(
457 program_id,
458 delegate,
459 authority_info,
460 authority_info_data_len,
461 account_info_iter.as_slice(),
462 )?,
463 (
464 PodCOption {
465 option: PodCOption::<Pubkey>::SOME,
466 value: delegate,
467 },
468 _,
469 ) if authority_info.key == &delegate => {
470 Self::validate_owner(
471 program_id,
472 &delegate,
473 authority_info,
474 authority_info_data_len,
475 account_info_iter.as_slice(),
476 )?;
477 let delegated_amount = u64::from(source_account.base.delegated_amount);
478 if delegated_amount < amount {
479 return Err(TokenError::InsufficientFunds.into());
480 }
481 if !self_transfer {
482 source_account.base.delegated_amount = delegated_amount
483 .checked_sub(amount)
484 .ok_or(TokenError::Overflow)?
485 .into();
486 if u64::from(source_account.base.delegated_amount) == 0 {
487 source_account.base.delegate = PodCOption::none();
488 }
489 }
490 }
491 _ => {
492 Self::validate_owner(
493 program_id,
494 &source_account.base.owner,
495 authority_info,
496 authority_info_data_len,
497 account_info_iter.as_slice(),
498 )?;
499 }
500 }
501
502 check_program_account(source_account_info.owner)?;
506 check_program_account(destination_account_info.owner)?;
507
508 if self_transfer {
511 if memo_required(&source_account) {
512 check_previous_sibling_instruction_is_memo()?;
513 }
514 return Ok(());
515 }
516
517 let mut destination_account_data = destination_account_info.data.borrow_mut();
519 let mut destination_account =
520 PodStateWithExtensionsMut::<PodAccount>::unpack(&mut destination_account_data)?;
521
522 if destination_account.base.is_frozen() {
523 return Err(TokenError::AccountFrozen.into());
524 }
525 if source_account.base.mint != destination_account.base.mint {
526 return Err(TokenError::MintMismatch.into());
527 }
528
529 if memo_required(&destination_account) {
530 check_previous_sibling_instruction_is_memo()?;
531 }
532
533 if let Ok(confidential_transfer_state) =
534 destination_account.get_extension::<ConfidentialTransferAccount>()
535 {
536 confidential_transfer_state.non_confidential_transfer_allowed()?
537 }
538
539 source_account.base.amount = source_amount
540 .checked_sub(amount)
541 .ok_or(TokenError::Overflow)?
542 .into();
543 let credited_amount = amount
544 .checked_sub(calculated_fee)
545 .ok_or(TokenError::Overflow)?;
546 destination_account.base.amount = u64::from(destination_account.base.amount)
547 .checked_add(credited_amount)
548 .ok_or(TokenError::Overflow)?
549 .into();
550 if calculated_fee > 0 {
551 if let Ok(extension) = destination_account.get_extension_mut::<TransferFeeAmount>() {
552 let new_withheld_amount = u64::from(extension.withheld_amount)
553 .checked_add(calculated_fee)
554 .ok_or(TokenError::Overflow)?;
555 extension.withheld_amount = new_withheld_amount.into();
556 } else {
557 return Err(TokenError::InvalidState.into());
561 }
562 }
563
564 if source_account.base.is_native() {
565 let source_starting_kelvins = source_account_info.kelvins();
566 **source_account_info.kelvins.borrow_mut() = source_starting_kelvins
567 .checked_sub(amount)
568 .ok_or(TokenError::Overflow)?;
569
570 let destination_starting_kelvins = destination_account_info.kelvins();
571 **destination_account_info.kelvins.borrow_mut() = destination_starting_kelvins
572 .checked_add(amount)
573 .ok_or(TokenError::Overflow)?;
574 }
575
576 if let Some(program_id) = maybe_transfer_hook_program_id {
577 if let Some((mint_info, _)) = expected_mint_info {
578 transfer_hook::set_transferring(&mut source_account)?;
580 transfer_hook::set_transferring(&mut destination_account)?;
581
582 drop(source_account_data);
584 drop(destination_account_data);
585 rialo_s_spl_transfer_hook_interface::onchain::invoke_execute(
586 &program_id,
587 source_account_info.clone(),
588 mint_info.clone(),
589 destination_account_info.clone(),
590 authority_info.clone(),
591 account_info_iter.as_slice(),
592 amount,
593 )?;
594
595 transfer_hook::unset_transferring(source_account_info)?;
597 transfer_hook::unset_transferring(destination_account_info)?;
598 } else {
599 return Err(TokenError::MintRequiredForTransfer.into());
600 }
601 }
602
603 Ok(())
604 }
605
606 pub(crate) fn process_approve(
608 program_id: &Pubkey,
609 accounts: &[AccountInfo<'_>],
610 amount: u64,
611 instruction_variant: InstructionVariant,
612 ) -> ProgramResult {
613 let account_info_iter = &mut accounts.iter();
614
615 let source_account_info = next_account_info(account_info_iter)?;
616
617 let expected_mint_info =
618 if let InstructionVariant::Checked { decimals } = instruction_variant {
619 Some((next_account_info(account_info_iter)?, decimals))
620 } else {
621 None
622 };
623 let delegate_info = next_account_info(account_info_iter)?;
624 let owner_info = next_account_info(account_info_iter)?;
625 let owner_info_data_len = owner_info.data_len();
626
627 let mut source_account_data = source_account_info.data.borrow_mut();
628 let source_account =
629 PodStateWithExtensionsMut::<PodAccount>::unpack(&mut source_account_data)?;
630
631 if source_account.base.is_frozen() {
632 return Err(TokenError::AccountFrozen.into());
633 }
634
635 if let Some((mint_info, expected_decimals)) = expected_mint_info {
636 if &source_account.base.mint != mint_info.key {
637 return Err(TokenError::MintMismatch.into());
638 }
639
640 let mint_data = mint_info.data.borrow();
641 let mint = PodStateWithExtensions::<PodMint>::unpack(&mint_data)?;
642 if expected_decimals != mint.base.decimals {
643 return Err(TokenError::MintDecimalsMismatch.into());
644 }
645 }
646
647 Self::validate_owner(
648 program_id,
649 &source_account.base.owner,
650 owner_info,
651 owner_info_data_len,
652 account_info_iter.as_slice(),
653 )?;
654
655 if let Ok(cpi_guard) = source_account.get_extension::<CpiGuard>() {
656 if cpi_guard.lock_cpi.into() && in_cpi() {
657 return Err(TokenError::CpiGuardApproveBlocked.into());
658 }
659 }
660
661 source_account.base.delegate = PodCOption::some(*delegate_info.key);
662 source_account.base.delegated_amount = amount.into();
663
664 Ok(())
665 }
666
667 pub fn process_revoke(program_id: &Pubkey, accounts: &[AccountInfo<'_>]) -> ProgramResult {
669 let account_info_iter = &mut accounts.iter();
670 let source_account_info = next_account_info(account_info_iter)?;
671 let authority_info = next_account_info(account_info_iter)?;
672 let authority_info_data_len = authority_info.data_len();
673
674 let mut source_account_data = source_account_info.data.borrow_mut();
675 let source_account =
676 PodStateWithExtensionsMut::<PodAccount>::unpack(&mut source_account_data)?;
677 if source_account.base.is_frozen() {
678 return Err(TokenError::AccountFrozen.into());
679 }
680
681 Self::validate_owner(
682 program_id,
683 match &source_account.base.delegate {
684 PodCOption {
685 option: PodCOption::<Pubkey>::SOME,
686 value: delegate,
687 } if authority_info.key == delegate => delegate,
688 _ => &source_account.base.owner,
689 },
690 authority_info,
691 authority_info_data_len,
692 account_info_iter.as_slice(),
693 )?;
694
695 source_account.base.delegate = PodCOption::none();
696 source_account.base.delegated_amount = 0.into();
697
698 Ok(())
699 }
700
701 pub fn process_set_authority(
703 program_id: &Pubkey,
704 accounts: &[AccountInfo<'_>],
705 authority_type: AuthorityType,
706 new_authority: PodCOption<Pubkey>,
707 ) -> ProgramResult {
708 let account_info_iter = &mut accounts.iter();
709 let account_info = next_account_info(account_info_iter)?;
710 let authority_info = next_account_info(account_info_iter)?;
711 let authority_info_data_len = authority_info.data_len();
712
713 let mut account_data = account_info.data.borrow_mut();
714 if let Ok(mut account) = PodStateWithExtensionsMut::<PodAccount>::unpack(&mut account_data)
715 {
716 if account.base.is_frozen() {
717 return Err(TokenError::AccountFrozen.into());
718 }
719
720 match authority_type {
721 AuthorityType::AccountOwner => {
722 Self::validate_owner(
723 program_id,
724 &account.base.owner,
725 authority_info,
726 authority_info_data_len,
727 account_info_iter.as_slice(),
728 )?;
729
730 if account.get_extension_mut::<ImmutableOwner>().is_ok() {
731 return Err(TokenError::ImmutableOwner.into());
732 }
733
734 if let Ok(cpi_guard) = account.get_extension::<CpiGuard>() {
735 if cpi_guard.lock_cpi.into() && in_cpi() {
736 return Err(TokenError::CpiGuardSetAuthorityBlocked.into());
737 } else if cpi_guard.lock_cpi.into() {
738 return Err(TokenError::CpiGuardOwnerChangeBlocked.into());
739 }
740 }
741
742 if let PodCOption {
743 option: PodCOption::<Pubkey>::SOME,
744 value: authority,
745 } = new_authority
746 {
747 account.base.owner = authority;
748 } else {
749 return Err(TokenError::InvalidInstruction.into());
750 }
751
752 account.base.delegate = PodCOption::none();
753 account.base.delegated_amount = 0.into();
754
755 if account.base.is_native() {
756 account.base.close_authority = PodCOption::none();
757 }
758 }
759 AuthorityType::CloseAccount => {
760 let authority = account.base.close_authority.unwrap_or(account.base.owner);
761 Self::validate_owner(
762 program_id,
763 &authority,
764 authority_info,
765 authority_info_data_len,
766 account_info_iter.as_slice(),
767 )?;
768
769 if let Ok(cpi_guard) = account.get_extension::<CpiGuard>() {
770 if cpi_guard.lock_cpi.into() && in_cpi() && new_authority.is_some() {
771 return Err(TokenError::CpiGuardSetAuthorityBlocked.into());
772 }
773 }
774
775 account.base.close_authority = new_authority;
776 }
777 _ => {
778 return Err(TokenError::AuthorityTypeNotSupported.into());
779 }
780 }
781 } else if let Ok(mut mint) = PodStateWithExtensionsMut::<PodMint>::unpack(&mut account_data)
782 {
783 match authority_type {
784 AuthorityType::MintTokens => {
785 let mint_authority = mint
788 .base
789 .mint_authority
790 .ok_or(Into::<ProgramError>::into(TokenError::FixedSupply))?;
791 Self::validate_owner(
792 program_id,
793 &mint_authority,
794 authority_info,
795 authority_info_data_len,
796 account_info_iter.as_slice(),
797 )?;
798 mint.base.mint_authority = new_authority;
799 }
800 AuthorityType::FreezeAccount => {
801 let freeze_authority = mint
804 .base
805 .freeze_authority
806 .ok_or(Into::<ProgramError>::into(TokenError::MintCannotFreeze))?;
807 Self::validate_owner(
808 program_id,
809 &freeze_authority,
810 authority_info,
811 authority_info_data_len,
812 account_info_iter.as_slice(),
813 )?;
814 mint.base.freeze_authority = new_authority;
815 }
816 AuthorityType::CloseMint => {
817 let extension = mint.get_extension_mut::<MintCloseAuthority>()?;
818 let maybe_close_authority: Option<Pubkey> = extension.close_authority.into();
819 let close_authority =
820 maybe_close_authority.ok_or(TokenError::AuthorityTypeNotSupported)?;
821 Self::validate_owner(
822 program_id,
823 &close_authority,
824 authority_info,
825 authority_info_data_len,
826 account_info_iter.as_slice(),
827 )?;
828 extension.close_authority = new_authority.try_into()?;
829 }
830 AuthorityType::TransferFeeConfig => {
831 let extension = mint.get_extension_mut::<TransferFeeConfig>()?;
832 let maybe_transfer_fee_config_authority: Option<Pubkey> =
833 extension.transfer_fee_config_authority.into();
834 let transfer_fee_config_authority = maybe_transfer_fee_config_authority
835 .ok_or(TokenError::AuthorityTypeNotSupported)?;
836 Self::validate_owner(
837 program_id,
838 &transfer_fee_config_authority,
839 authority_info,
840 authority_info_data_len,
841 account_info_iter.as_slice(),
842 )?;
843 extension.transfer_fee_config_authority = new_authority.try_into()?;
844 }
845 AuthorityType::WithheldWithdraw => {
846 let extension = mint.get_extension_mut::<TransferFeeConfig>()?;
847 let maybe_withdraw_withheld_authority: Option<Pubkey> =
848 extension.withdraw_withheld_authority.into();
849 let withdraw_withheld_authority = maybe_withdraw_withheld_authority
850 .ok_or(TokenError::AuthorityTypeNotSupported)?;
851 Self::validate_owner(
852 program_id,
853 &withdraw_withheld_authority,
854 authority_info,
855 authority_info_data_len,
856 account_info_iter.as_slice(),
857 )?;
858 extension.withdraw_withheld_authority = new_authority.try_into()?;
859 }
860 AuthorityType::InterestRate => {
861 let extension = mint.get_extension_mut::<InterestBearingConfig>()?;
862 let maybe_rate_authority: Option<Pubkey> = extension.rate_authority.into();
863 let rate_authority =
864 maybe_rate_authority.ok_or(TokenError::AuthorityTypeNotSupported)?;
865 Self::validate_owner(
866 program_id,
867 &rate_authority,
868 authority_info,
869 authority_info_data_len,
870 account_info_iter.as_slice(),
871 )?;
872 extension.rate_authority = new_authority.try_into()?;
873 }
874 AuthorityType::PermanentDelegate => {
875 let extension = mint.get_extension_mut::<PermanentDelegate>()?;
876 let maybe_delegate: Option<Pubkey> = extension.delegate.into();
877 let delegate = maybe_delegate.ok_or(TokenError::AuthorityTypeNotSupported)?;
878 Self::validate_owner(
879 program_id,
880 &delegate,
881 authority_info,
882 authority_info_data_len,
883 account_info_iter.as_slice(),
884 )?;
885 extension.delegate = new_authority.try_into()?;
886 }
887 AuthorityType::ConfidentialTransferMint => {
888 let extension = mint.get_extension_mut::<ConfidentialTransferMint>()?;
889 let maybe_confidential_transfer_mint_authority: Option<Pubkey> =
890 extension.authority.into();
891 let confidential_transfer_mint_authority =
892 maybe_confidential_transfer_mint_authority
893 .ok_or(TokenError::AuthorityTypeNotSupported)?;
894 Self::validate_owner(
895 program_id,
896 &confidential_transfer_mint_authority,
897 authority_info,
898 authority_info_data_len,
899 account_info_iter.as_slice(),
900 )?;
901 extension.authority = new_authority.try_into()?;
902 }
903 AuthorityType::TransferHookProgramId => {
904 let extension = mint.get_extension_mut::<TransferHook>()?;
905 let maybe_authority: Option<Pubkey> = extension.authority.into();
906 let authority = maybe_authority.ok_or(TokenError::AuthorityTypeNotSupported)?;
907 Self::validate_owner(
908 program_id,
909 &authority,
910 authority_info,
911 authority_info_data_len,
912 account_info_iter.as_slice(),
913 )?;
914 extension.authority = new_authority.try_into()?;
915 }
916 AuthorityType::ConfidentialTransferFeeConfig => {
917 let extension = mint.get_extension_mut::<ConfidentialTransferFeeConfig>()?;
918 let maybe_authority: Option<Pubkey> = extension.authority.into();
919 let authority = maybe_authority.ok_or(TokenError::AuthorityTypeNotSupported)?;
920 Self::validate_owner(
921 program_id,
922 &authority,
923 authority_info,
924 authority_info_data_len,
925 account_info_iter.as_slice(),
926 )?;
927 extension.authority = new_authority.try_into()?;
928 }
929 AuthorityType::MetadataPointer => {
930 let extension = mint.get_extension_mut::<MetadataPointer>()?;
931 let maybe_authority: Option<Pubkey> = extension.authority.into();
932 let authority = maybe_authority.ok_or(TokenError::AuthorityTypeNotSupported)?;
933 Self::validate_owner(
934 program_id,
935 &authority,
936 authority_info,
937 authority_info_data_len,
938 account_info_iter.as_slice(),
939 )?;
940 extension.authority = new_authority.try_into()?;
941 }
942 AuthorityType::GroupPointer => {
943 let extension = mint.get_extension_mut::<GroupPointer>()?;
944 let maybe_authority: Option<Pubkey> = extension.authority.into();
945 let authority = maybe_authority.ok_or(TokenError::AuthorityTypeNotSupported)?;
946 Self::validate_owner(
947 program_id,
948 &authority,
949 authority_info,
950 authority_info_data_len,
951 account_info_iter.as_slice(),
952 )?;
953 extension.authority = new_authority.try_into()?;
954 }
955 AuthorityType::GroupMemberPointer => {
956 let extension = mint.get_extension_mut::<GroupMemberPointer>()?;
957 let maybe_authority: Option<Pubkey> = extension.authority.into();
958 let authority = maybe_authority.ok_or(TokenError::AuthorityTypeNotSupported)?;
959 Self::validate_owner(
960 program_id,
961 &authority,
962 authority_info,
963 authority_info_data_len,
964 account_info_iter.as_slice(),
965 )?;
966 extension.authority = new_authority.try_into()?;
967 }
968 AuthorityType::ScaledUiAmount => {
969 let extension = mint.get_extension_mut::<ScaledUiAmountConfig>()?;
970 let maybe_authority: Option<Pubkey> = extension.authority.into();
971 let authority = maybe_authority.ok_or(TokenError::AuthorityTypeNotSupported)?;
972 Self::validate_owner(
973 program_id,
974 &authority,
975 authority_info,
976 authority_info_data_len,
977 account_info_iter.as_slice(),
978 )?;
979 extension.authority = new_authority.try_into()?;
980 }
981 AuthorityType::Pause => {
982 let extension = mint.get_extension_mut::<PausableConfig>()?;
983 let maybe_authority: Option<Pubkey> = extension.authority.into();
984 let authority = maybe_authority.ok_or(TokenError::AuthorityTypeNotSupported)?;
985 Self::validate_owner(
986 program_id,
987 &authority,
988 authority_info,
989 authority_info_data_len,
990 account_info_iter.as_slice(),
991 )?;
992 extension.authority = new_authority.try_into()?;
993 }
994 _ => {
995 return Err(TokenError::AuthorityTypeNotSupported.into());
996 }
997 }
998 } else {
999 return Err(ProgramError::InvalidAccountData);
1000 }
1001
1002 Ok(())
1003 }
1004
1005 pub(crate) fn process_mint_to(
1007 program_id: &Pubkey,
1008 accounts: &[AccountInfo<'_>],
1009 amount: u64,
1010 instruction_variant: InstructionVariant,
1011 ) -> ProgramResult {
1012 let account_info_iter = &mut accounts.iter();
1013 let mint_info = next_account_info(account_info_iter)?;
1014 let destination_account_info = next_account_info(account_info_iter)?;
1015 let owner_info = next_account_info(account_info_iter)?;
1016 let owner_info_data_len = owner_info.data_len();
1017
1018 let mut destination_account_data = destination_account_info.data.borrow_mut();
1019 let destination_account =
1020 PodStateWithExtensionsMut::<PodAccount>::unpack(&mut destination_account_data)?;
1021 if destination_account.base.is_frozen() {
1022 return Err(TokenError::AccountFrozen.into());
1023 }
1024
1025 if destination_account.base.is_native() {
1026 return Err(TokenError::NativeNotSupported.into());
1027 }
1028 if mint_info.key != &destination_account.base.mint {
1029 return Err(TokenError::MintMismatch.into());
1030 }
1031
1032 let mut mint_data = mint_info.data.borrow_mut();
1033 let mint = PodStateWithExtensionsMut::<PodMint>::unpack(&mut mint_data)?;
1034
1035 if mint.get_extension::<NonTransferable>().is_ok()
1038 && destination_account
1039 .get_extension::<ImmutableOwner>()
1040 .is_err()
1041 {
1042 return Err(TokenError::NonTransferableNeedsImmutableOwnership.into());
1043 }
1044
1045 if let Ok(extension) = mint.get_extension::<PausableConfig>() {
1046 if extension.paused.into() {
1047 return Err(TokenError::MintPaused.into());
1048 }
1049 }
1050
1051 if mint.get_extension::<ConfidentialMintBurn>().is_ok() {
1052 return Err(TokenError::IllegalMintBurnConversion.into());
1053 }
1054
1055 if let InstructionVariant::Checked { decimals } = instruction_variant {
1056 if decimals != mint.base.decimals {
1057 return Err(TokenError::MintDecimalsMismatch.into());
1058 }
1059 }
1060
1061 match &mint.base.mint_authority {
1062 PodCOption {
1063 option: PodCOption::<Pubkey>::SOME,
1064 value: mint_authority,
1065 } => Self::validate_owner(
1066 program_id,
1067 mint_authority,
1068 owner_info,
1069 owner_info_data_len,
1070 account_info_iter.as_slice(),
1071 )?,
1072 _ => return Err(TokenError::FixedSupply.into()),
1073 }
1074
1075 check_program_account(mint_info.owner)?;
1079 check_program_account(destination_account_info.owner)?;
1080
1081 destination_account.base.amount = u64::from(destination_account.base.amount)
1082 .checked_add(amount)
1083 .ok_or(TokenError::Overflow)?
1084 .into();
1085
1086 mint.base.supply = u64::from(mint.base.supply)
1087 .checked_add(amount)
1088 .ok_or(TokenError::Overflow)?
1089 .into();
1090
1091 Ok(())
1092 }
1093
1094 pub(crate) fn process_burn(
1096 program_id: &Pubkey,
1097 accounts: &[AccountInfo<'_>],
1098 amount: u64,
1099 instruction_variant: InstructionVariant,
1100 ) -> ProgramResult {
1101 let account_info_iter = &mut accounts.iter();
1102
1103 let source_account_info = next_account_info(account_info_iter)?;
1104 let mint_info = next_account_info(account_info_iter)?;
1105 let authority_info = next_account_info(account_info_iter)?;
1106 let authority_info_data_len = authority_info.data_len();
1107
1108 let mut source_account_data = source_account_info.data.borrow_mut();
1109 let source_account =
1110 PodStateWithExtensionsMut::<PodAccount>::unpack(&mut source_account_data)?;
1111 let mut mint_data = mint_info.data.borrow_mut();
1112 let mint = PodStateWithExtensionsMut::<PodMint>::unpack(&mut mint_data)?;
1113
1114 if source_account.base.is_frozen() {
1115 return Err(TokenError::AccountFrozen.into());
1116 }
1117 if source_account.base.is_native() {
1118 return Err(TokenError::NativeNotSupported.into());
1119 }
1120 if u64::from(source_account.base.amount) < amount {
1121 return Err(TokenError::InsufficientFunds.into());
1122 }
1123 if mint_info.key != &source_account.base.mint {
1124 return Err(TokenError::MintMismatch.into());
1125 }
1126
1127 if let InstructionVariant::Checked { decimals } = instruction_variant {
1128 if decimals != mint.base.decimals {
1129 return Err(TokenError::MintDecimalsMismatch.into());
1130 }
1131 }
1132 if let Ok(extension) = mint.get_extension::<PausableConfig>() {
1133 if extension.paused.into() {
1134 return Err(TokenError::MintPaused.into());
1135 }
1136 }
1137 let maybe_permanent_delegate = get_permanent_delegate(&mint);
1138
1139 if let Ok(cpi_guard) = source_account.get_extension::<CpiGuard>() {
1140 if *authority_info.key == source_account.base.owner
1145 && cpi_guard.lock_cpi.into()
1146 && in_cpi()
1147 {
1148 return Err(TokenError::CpiGuardBurnBlocked.into());
1149 }
1150 }
1151
1152 if !source_account
1153 .base
1154 .is_owned_by_system_program_or_incinerator()
1155 {
1156 match (&source_account.base.delegate, maybe_permanent_delegate) {
1157 (_, Some(ref delegate)) if authority_info.key == delegate => Self::validate_owner(
1158 program_id,
1159 delegate,
1160 authority_info,
1161 authority_info_data_len,
1162 account_info_iter.as_slice(),
1163 )?,
1164 (
1165 PodCOption {
1166 option: PodCOption::<Pubkey>::SOME,
1167 value: delegate,
1168 },
1169 _,
1170 ) if authority_info.key == delegate => {
1171 Self::validate_owner(
1172 program_id,
1173 delegate,
1174 authority_info,
1175 authority_info_data_len,
1176 account_info_iter.as_slice(),
1177 )?;
1178
1179 if u64::from(source_account.base.delegated_amount) < amount {
1180 return Err(TokenError::InsufficientFunds.into());
1181 }
1182 source_account.base.delegated_amount =
1183 u64::from(source_account.base.delegated_amount)
1184 .checked_sub(amount)
1185 .ok_or(TokenError::Overflow)?
1186 .into();
1187 if u64::from(source_account.base.delegated_amount) == 0 {
1188 source_account.base.delegate = PodCOption::none();
1189 }
1190 }
1191 _ => {
1192 Self::validate_owner(
1193 program_id,
1194 &source_account.base.owner,
1195 authority_info,
1196 authority_info_data_len,
1197 account_info_iter.as_slice(),
1198 )?;
1199 }
1200 }
1201 }
1202
1203 check_program_account(source_account_info.owner)?;
1207 check_program_account(mint_info.owner)?;
1208
1209 source_account.base.amount = u64::from(source_account.base.amount)
1210 .checked_sub(amount)
1211 .ok_or(TokenError::Overflow)?
1212 .into();
1213 mint.base.supply = u64::from(mint.base.supply)
1214 .checked_sub(amount)
1215 .ok_or(TokenError::Overflow)?
1216 .into();
1217
1218 Ok(())
1219 }
1220
1221 pub fn process_close_account(
1223 program_id: &Pubkey,
1224 accounts: &[AccountInfo<'_>],
1225 ) -> ProgramResult {
1226 let account_info_iter = &mut accounts.iter();
1227 let source_account_info = next_account_info(account_info_iter)?;
1228 let destination_account_info = next_account_info(account_info_iter)?;
1229 let authority_info = next_account_info(account_info_iter)?;
1230 let authority_info_data_len = authority_info.data_len();
1231
1232 if source_account_info.key == destination_account_info.key {
1233 return Err(ProgramError::InvalidAccountData);
1234 }
1235
1236 let source_account_data = source_account_info.data.borrow();
1237
1238 if let Ok(source_account) =
1240 PodStateWithExtensions::<PodAccount>::unpack(&source_account_data)
1241 {
1242 if !source_account.base.is_native() && u64::from(source_account.base.amount) != 0 {
1243 return Err(TokenError::NonNativeHasBalance.into());
1244 }
1245
1246 let authority = source_account
1247 .base
1248 .close_authority
1249 .unwrap_or(source_account.base.owner);
1250
1251 if !source_account
1252 .base
1253 .is_owned_by_system_program_or_incinerator()
1254 {
1255 if let Ok(cpi_guard) = source_account.get_extension::<CpiGuard>() {
1256 if cpi_guard.lock_cpi.into()
1257 && in_cpi()
1258 && destination_account_info.key != &source_account.base.owner
1259 {
1260 return Err(TokenError::CpiGuardCloseAccountBlocked.into());
1261 }
1262 }
1263
1264 Self::validate_owner(
1265 program_id,
1266 &authority,
1267 authority_info,
1268 authority_info_data_len,
1269 account_info_iter.as_slice(),
1270 )?;
1271 } else if !rialo_s_sdk_ids::incinerator::check_id(destination_account_info.key) {
1272 return Err(ProgramError::InvalidAccountData);
1273 }
1274
1275 if let Ok(confidential_transfer_state) =
1276 source_account.get_extension::<ConfidentialTransferAccount>()
1277 {
1278 confidential_transfer_state.closable()?
1279 }
1280
1281 if let Ok(confidential_transfer_fee_state) =
1282 source_account.get_extension::<ConfidentialTransferFeeAmount>()
1283 {
1284 confidential_transfer_fee_state.closable()?
1285 }
1286
1287 if let Ok(transfer_fee_state) = source_account.get_extension::<TransferFeeAmount>() {
1288 transfer_fee_state.closable()?
1289 }
1290 }
1291 else if let Ok(mint) = PodStateWithExtensions::<PodMint>::unpack(&source_account_data) {
1293 let extension = mint.get_extension::<MintCloseAuthority>()?;
1294 let maybe_authority: Option<Pubkey> = extension.close_authority.into();
1295 let authority = maybe_authority.ok_or(TokenError::AuthorityTypeNotSupported)?;
1296 Self::validate_owner(
1297 program_id,
1298 &authority,
1299 authority_info,
1300 authority_info_data_len,
1301 account_info_iter.as_slice(),
1302 )?;
1303
1304 if u64::from(mint.base.supply) != 0 {
1305 return Err(TokenError::MintHasSupply.into());
1306 }
1307
1308 if accounts.len() < 6 {
1312 return Err(ProgramError::NotEnoughAccountKeys);
1313 }
1314
1315 let tombstone_index = accounts.len() - 3;
1316 let payer_index = accounts.len() - 2;
1317 let system_index = accounts.len() - 1;
1318
1319 let tombstone_account_info = &accounts[tombstone_index];
1320 let payer_account_info = &accounts[payer_index];
1321 let system_program_info = &accounts[system_index];
1322
1323 let (expected_pda, bump) = derive_tombstone_pda(program_id, source_account_info.key);
1325 if tombstone_account_info.key != &expected_pda {
1326 return Err(TokenError::TombstoneAddressMismatch.into());
1327 }
1328
1329 if tombstone_account_info.kelvins() > 0 {
1331 return Err(TokenError::TombstoneAlreadyExists.into());
1332 }
1333
1334 let rent = Rent::get()?;
1336 let kelvins_needed = rent.minimum_balance(TOMBSTONE_LEN);
1337
1338 let create_ix = system_instruction::create_account(
1339 payer_account_info.key,
1340 tombstone_account_info.key,
1341 kelvins_needed,
1342 TOMBSTONE_LEN as u64,
1343 program_id,
1344 );
1345
1346 let signer_seeds: &[&[u8]] =
1347 &[TOMBSTONE_SEED, source_account_info.key.as_ref(), &[bump]];
1348
1349 invoke_signed(
1350 &create_ix,
1351 &[
1352 payer_account_info.clone(),
1353 tombstone_account_info.clone(),
1354 system_program_info.clone(),
1355 ],
1356 &[signer_seeds],
1357 )?;
1358
1359 let tomb = MintTombstone {
1361 closed_at_slot: Clock::get()?.slot,
1362 closed_by: *authority_info.key,
1363 successor: COption::None,
1364 policy_hash16: [0u8; 16],
1365 };
1366
1367 {
1368 let mut data = tombstone_account_info.data.borrow_mut();
1369 MintTombstone::pack_into_slice(&tomb, &mut data[..MintTombstone::LEN]);
1370 }
1371 }
1372 else {
1374 return Err(ProgramError::UninitializedAccount);
1375 }
1376
1377 let destination_starting_kelvins = destination_account_info.kelvins();
1378 **destination_account_info.kelvins.borrow_mut() = destination_starting_kelvins
1379 .checked_add(source_account_info.kelvins())
1380 .ok_or(TokenError::Overflow)?;
1381
1382 **source_account_info.kelvins.borrow_mut() = 0;
1383 drop(source_account_data);
1384 delete_account(source_account_info)?;
1385
1386 Ok(())
1387 }
1388
1389 pub fn process_toggle_freeze_account(
1392 program_id: &Pubkey,
1393 accounts: &[AccountInfo<'_>],
1394 freeze: bool,
1395 ) -> ProgramResult {
1396 let account_info_iter = &mut accounts.iter();
1397 let source_account_info = next_account_info(account_info_iter)?;
1398 let mint_info = next_account_info(account_info_iter)?;
1399 let authority_info = next_account_info(account_info_iter)?;
1400 let authority_info_data_len = authority_info.data_len();
1401
1402 let mut source_account_data = source_account_info.data.borrow_mut();
1403 let source_account =
1404 PodStateWithExtensionsMut::<PodAccount>::unpack(&mut source_account_data)?;
1405 if freeze && source_account.base.is_frozen() || !freeze && !source_account.base.is_frozen()
1406 {
1407 return Err(TokenError::InvalidState.into());
1408 }
1409 if source_account.base.is_native() {
1410 return Err(TokenError::NativeNotSupported.into());
1411 }
1412 if mint_info.key != &source_account.base.mint {
1413 return Err(TokenError::MintMismatch.into());
1414 }
1415
1416 let mint_data = mint_info.data.borrow();
1417 let mint = PodStateWithExtensions::<PodMint>::unpack(&mint_data)?;
1418 match &mint.base.freeze_authority {
1419 PodCOption {
1420 option: PodCOption::<Pubkey>::SOME,
1421 value: authority,
1422 } => Self::validate_owner(
1423 program_id,
1424 authority,
1425 authority_info,
1426 authority_info_data_len,
1427 account_info_iter.as_slice(),
1428 ),
1429 _ => Err(TokenError::MintCannotFreeze.into()),
1430 }?;
1431
1432 source_account.base.state = if freeze {
1433 AccountState::Frozen.into()
1434 } else {
1435 AccountState::Initialized.into()
1436 };
1437
1438 Ok(())
1439 }
1440
1441 pub fn process_sync_native(accounts: &[AccountInfo<'_>]) -> ProgramResult {
1443 let account_info_iter = &mut accounts.iter();
1444 let native_account_info = next_account_info(account_info_iter)?;
1445
1446 check_program_account(native_account_info.owner)?;
1447 let mut native_account_data = native_account_info.data.borrow_mut();
1448 let native_account =
1449 PodStateWithExtensionsMut::<PodAccount>::unpack(&mut native_account_data)?;
1450
1451 match native_account.base.is_native {
1452 PodCOption {
1453 option: PodCOption::<PodU64>::SOME,
1454 value: amount,
1455 } => {
1456 let new_amount = native_account_info
1457 .kelvins()
1458 .checked_sub(u64::from(amount))
1459 .ok_or(TokenError::Overflow)?;
1460 if new_amount < u64::from(native_account.base.amount) {
1461 return Err(TokenError::InvalidState.into());
1462 }
1463 native_account.base.amount = new_amount.into();
1464 }
1465 _ => return Err(TokenError::NonNativeNotSupported.into()),
1466 }
1467
1468 Ok(())
1469 }
1470
1471 pub fn process_initialize_mint_close_authority(
1475 accounts: &[AccountInfo<'_>],
1476 close_authority: PodCOption<Pubkey>,
1477 ) -> ProgramResult {
1478 let account_info_iter = &mut accounts.iter();
1479 let mint_account_info = next_account_info(account_info_iter)?;
1480
1481 let mut mint_data = mint_account_info.data.borrow_mut();
1482 let mut mint = PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut mint_data)?;
1483 let extension = mint.init_extension::<MintCloseAuthority>(true)?;
1484 extension.close_authority = close_authority.try_into()?;
1485
1486 Ok(())
1487 }
1488
1489 pub fn process_get_account_data_size(
1492 accounts: &[AccountInfo<'_>],
1493 new_extension_types: &[ExtensionType],
1494 ) -> ProgramResult {
1495 if new_extension_types
1496 .iter()
1497 .any(|&t| t.get_account_type() != AccountType::Account)
1498 {
1499 return Err(TokenError::ExtensionTypeMismatch.into());
1500 }
1501
1502 let account_info_iter = &mut accounts.iter();
1503 let mint_account_info = next_account_info(account_info_iter)?;
1504
1505 let mut account_extensions = Self::get_required_account_extensions(mint_account_info)?;
1506 account_extensions.extend_from_slice(new_extension_types);
1509
1510 let account_len = ExtensionType::try_calculate_account_len::<Account>(&account_extensions)?;
1511 set_return_data(&account_len.to_le_bytes());
1512
1513 Ok(())
1514 }
1515
1516 pub fn process_initialize_immutable_owner(accounts: &[AccountInfo<'_>]) -> ProgramResult {
1519 let account_info_iter = &mut accounts.iter();
1520 let token_account_info = next_account_info(account_info_iter)?;
1521 let token_account_data = &mut token_account_info.data.borrow_mut();
1522 let mut token_account =
1523 PodStateWithExtensionsMut::<PodAccount>::unpack_uninitialized(token_account_data)?;
1524 token_account
1525 .init_extension::<ImmutableOwner>(true)
1526 .map(|_| ())
1527 }
1528
1529 pub fn process_amount_to_ui_amount(accounts: &[AccountInfo<'_>], amount: u64) -> ProgramResult {
1532 let account_info_iter = &mut accounts.iter();
1533 let mint_info = next_account_info(account_info_iter)?;
1534 check_program_account(mint_info.owner)?;
1535
1536 let mint_data = mint_info.data.borrow();
1537 let mint = PodStateWithExtensions::<PodMint>::unpack(&mint_data)
1538 .map_err(|_| Into::<ProgramError>::into(TokenError::InvalidMint))?;
1539 let ui_amount = if let Ok(extension) = mint.get_extension::<InterestBearingConfig>() {
1540 let unix_timestamp = Clock::get()?.unix_timestamp;
1541 extension
1542 .amount_to_ui_amount(amount, mint.base.decimals, unix_timestamp)
1543 .ok_or(ProgramError::InvalidArgument)?
1544 } else if let Ok(extension) = mint.get_extension::<ScaledUiAmountConfig>() {
1545 let unix_timestamp = Clock::get()?.unix_timestamp;
1546 extension
1547 .amount_to_ui_amount(amount, mint.base.decimals, unix_timestamp)
1548 .ok_or(ProgramError::InvalidArgument)?
1549 } else {
1550 crate::amount_to_ui_amount_string_trimmed(amount, mint.base.decimals)
1551 };
1552
1553 set_return_data(&ui_amount.into_bytes());
1554 Ok(())
1555 }
1556
1557 pub fn process_ui_amount_to_amount(
1560 accounts: &[AccountInfo<'_>],
1561 ui_amount: &str,
1562 ) -> ProgramResult {
1563 let account_info_iter = &mut accounts.iter();
1564 let mint_info = next_account_info(account_info_iter)?;
1565 check_program_account(mint_info.owner)?;
1566
1567 let mint_data = mint_info.data.borrow();
1568 let mint = PodStateWithExtensions::<PodMint>::unpack(&mint_data)
1569 .map_err(|_| Into::<ProgramError>::into(TokenError::InvalidMint))?;
1570 let amount = if let Ok(extension) = mint.get_extension::<InterestBearingConfig>() {
1571 let unix_timestamp = Clock::get()?.unix_timestamp;
1572 extension.try_ui_amount_into_amount(ui_amount, mint.base.decimals, unix_timestamp)?
1573 } else if let Ok(extension) = mint.get_extension::<ScaledUiAmountConfig>() {
1574 let unix_timestamp = Clock::get()?.unix_timestamp;
1575 extension.try_ui_amount_into_amount(ui_amount, mint.base.decimals, unix_timestamp)?
1576 } else {
1577 crate::try_ui_amount_into_amount(ui_amount.to_string(), mint.base.decimals)?
1578 };
1579
1580 set_return_data(&amount.to_le_bytes());
1581 Ok(())
1582 }
1583
1584 pub fn process_create_native_mint(accounts: &[AccountInfo<'_>]) -> ProgramResult {
1586 let account_info_iter = &mut accounts.iter();
1587 let payer_info = next_account_info(account_info_iter)?;
1588 let native_mint_info = next_account_info(account_info_iter)?;
1589 let system_program_info = next_account_info(account_info_iter)?;
1590
1591 if *native_mint_info.key != native_mint::id() {
1592 return Err(TokenError::InvalidMint.into());
1593 }
1594
1595 let rent = Rent::get()?;
1596 let new_minimum_balance = rent.minimum_balance(Mint::get_packed_len());
1597 let kelvins_diff = new_minimum_balance.saturating_sub(native_mint_info.kelvins());
1598 invoke(
1599 &system_instruction::transfer(payer_info.key, native_mint_info.key, kelvins_diff),
1600 &[
1601 payer_info.clone(),
1602 native_mint_info.clone(),
1603 system_program_info.clone(),
1604 ],
1605 )?;
1606
1607 invoke_signed(
1608 &system_instruction::allocate(native_mint_info.key, Mint::get_packed_len() as u64),
1609 &[native_mint_info.clone(), system_program_info.clone()],
1610 &[native_mint::PROGRAM_ADDRESS_SEEDS],
1611 )?;
1612
1613 invoke_signed(
1614 &system_instruction::assign(native_mint_info.key, &crate::id()),
1615 &[native_mint_info.clone(), system_program_info.clone()],
1616 &[native_mint::PROGRAM_ADDRESS_SEEDS],
1617 )?;
1618
1619 Mint::pack(
1620 Mint {
1621 decimals: native_mint::DECIMALS,
1622 is_initialized: true,
1623 ..Mint::default()
1624 },
1625 &mut native_mint_info.data.borrow_mut(),
1626 )
1627 }
1628
1629 pub fn process_initialize_non_transferable_mint(accounts: &[AccountInfo<'_>]) -> ProgramResult {
1633 let account_info_iter = &mut accounts.iter();
1634 let mint_account_info = next_account_info(account_info_iter)?;
1635
1636 let mut mint_data = mint_account_info.data.borrow_mut();
1637 let mut mint = PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut mint_data)?;
1638 mint.init_extension::<NonTransferable>(true)?;
1639
1640 Ok(())
1641 }
1642
1643 pub fn process_initialize_permanent_delegate(
1646 accounts: &[AccountInfo<'_>],
1647 delegate: &Pubkey,
1648 ) -> ProgramResult {
1649 let account_info_iter = &mut accounts.iter();
1650 let mint_account_info = next_account_info(account_info_iter)?;
1651
1652 let mut mint_data = mint_account_info.data.borrow_mut();
1653 let mut mint = PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut mint_data)?;
1654 let extension = mint.init_extension::<PermanentDelegate>(true)?;
1655 extension.delegate = Some(*delegate).try_into()?;
1656
1657 Ok(())
1658 }
1659
1660 pub fn process_withdraw_excess_kelvins(
1664 program_id: &Pubkey,
1665 accounts: &[AccountInfo<'_>],
1666 ) -> ProgramResult {
1667 let account_info_iter = &mut accounts.iter();
1668
1669 let source_info = next_account_info(account_info_iter)?;
1670 let destination_info = next_account_info(account_info_iter)?;
1671 let authority_info = next_account_info(account_info_iter)?;
1672
1673 let source_data = source_info.data.borrow();
1674
1675 if let Ok(account) = PodStateWithExtensions::<PodAccount>::unpack(&source_data) {
1676 if account.base.is_native() {
1677 return Err(TokenError::NativeNotSupported.into());
1678 }
1679 Self::validate_owner(
1680 program_id,
1681 &account.base.owner,
1682 authority_info,
1683 authority_info.data_len(),
1684 account_info_iter.as_slice(),
1685 )?;
1686 } else if let Ok(mint) = PodStateWithExtensions::<PodMint>::unpack(&source_data) {
1687 match &mint.base.mint_authority {
1688 PodCOption {
1689 option: PodCOption::<Pubkey>::SOME,
1690 value: mint_authority,
1691 } => {
1692 Self::validate_owner(
1693 program_id,
1694 mint_authority,
1695 authority_info,
1696 authority_info.data_len(),
1697 account_info_iter.as_slice(),
1698 )?;
1699 }
1700 PodCOption {
1701 option: PodCOption::<Pubkey>::NONE,
1702 value: _,
1703 } if source_info.key == authority_info.key => {
1704 if !authority_info.is_signer {
1708 return Err(ProgramError::MissingRequiredSignature);
1709 }
1710 }
1711 _ => return Err(TokenError::AuthorityTypeNotSupported.into()),
1712 }
1713 } else if source_data.len() == PodMultisig::SIZE_OF {
1714 Self::validate_owner(
1715 program_id,
1716 source_info.key,
1717 authority_info,
1718 authority_info.data_len(),
1719 account_info_iter.as_slice(),
1720 )?;
1721 } else {
1722 return Err(TokenError::InvalidState.into());
1723 }
1724
1725 let source_rent_exempt_reserve = Rent::get()?.minimum_balance(source_info.data_len());
1726
1727 let transfer_amount = source_info
1728 .kelvins()
1729 .checked_sub(source_rent_exempt_reserve)
1730 .ok_or(TokenError::NotRentExempt)?;
1731
1732 let source_starting_kelvins = source_info.kelvins();
1733 **source_info.kelvins.borrow_mut() = source_starting_kelvins
1734 .checked_sub(transfer_amount)
1735 .ok_or(TokenError::Overflow)?;
1736
1737 let destination_starting_kelvins = destination_info.kelvins();
1738 **destination_info.kelvins.borrow_mut() = destination_starting_kelvins
1739 .checked_add(transfer_amount)
1740 .ok_or(TokenError::Overflow)?;
1741
1742 Ok(())
1743 }
1744
1745 pub fn process(
1747 program_id: &Pubkey,
1748 accounts: &[AccountInfo<'_>],
1749 input: &[u8],
1750 ) -> ProgramResult {
1751 if let Ok(instruction_type) = decode_instruction_type(input) {
1752 match instruction_type {
1753 PodTokenInstruction::InitializeMint => {
1754 msg!("Instruction: InitializeMint");
1755 let (data, freeze_authority) =
1756 decode_instruction_data_with_coption_pubkey::<InitializeMintData>(input)?;
1757 Self::process_initialize_mint(
1758 accounts,
1759 data.decimals,
1760 &data.mint_authority,
1761 freeze_authority,
1762 )
1763 }
1764 PodTokenInstruction::InitializeMint2 => {
1765 msg!("Instruction: InitializeMint2");
1766 let (data, freeze_authority) =
1767 decode_instruction_data_with_coption_pubkey::<InitializeMintData>(input)?;
1768 Self::process_initialize_mint2(
1769 accounts,
1770 data.decimals,
1771 &data.mint_authority,
1772 freeze_authority,
1773 )
1774 }
1775 PodTokenInstruction::InitializeAccount => {
1776 msg!("Instruction: InitializeAccount");
1777 Self::process_initialize_account(accounts)
1778 }
1779 PodTokenInstruction::InitializeAccount2 => {
1780 msg!("Instruction: InitializeAccount2");
1781 let owner = decode_instruction_data::<Pubkey>(input)?;
1782 Self::process_initialize_account2(accounts, owner)
1783 }
1784 PodTokenInstruction::InitializeAccount3 => {
1785 msg!("Instruction: InitializeAccount3");
1786 let owner = decode_instruction_data::<Pubkey>(input)?;
1787 Self::process_initialize_account3(accounts, owner)
1788 }
1789 PodTokenInstruction::InitializeMultisig => {
1790 msg!("Instruction: InitializeMultisig");
1791 let data = decode_instruction_data::<InitializeMultisigData>(input)?;
1792 Self::process_initialize_multisig(accounts, data.m)
1793 }
1794 PodTokenInstruction::InitializeMultisig2 => {
1795 msg!("Instruction: InitializeMultisig2");
1796 let data = decode_instruction_data::<InitializeMultisigData>(input)?;
1797 Self::process_initialize_multisig2(accounts, data.m)
1798 }
1799 #[allow(deprecated)]
1800 PodTokenInstruction::Transfer => {
1801 msg!("Instruction: Transfer");
1802 let data = decode_instruction_data::<AmountData>(input)?;
1803 Self::process_transfer(
1804 program_id,
1805 accounts,
1806 data.amount.into(),
1807 TransferInstruction::Unchecked,
1808 )
1809 }
1810 PodTokenInstruction::Approve => {
1811 msg!("Instruction: Approve");
1812 let data = decode_instruction_data::<AmountData>(input)?;
1813 Self::process_approve(
1814 program_id,
1815 accounts,
1816 data.amount.into(),
1817 InstructionVariant::Unchecked,
1818 )
1819 }
1820 PodTokenInstruction::Revoke => {
1821 msg!("Instruction: Revoke");
1822 Self::process_revoke(program_id, accounts)
1823 }
1824 PodTokenInstruction::SetAuthority => {
1825 msg!("Instruction: SetAuthority");
1826 let (data, new_authority) =
1827 decode_instruction_data_with_coption_pubkey::<SetAuthorityData>(input)?;
1828 Self::process_set_authority(
1829 program_id,
1830 accounts,
1831 AuthorityType::from(data.authority_type)?,
1832 new_authority,
1833 )
1834 }
1835 PodTokenInstruction::MintTo => {
1836 msg!("Instruction: MintTo");
1837 let data = decode_instruction_data::<AmountData>(input)?;
1838 Self::process_mint_to(
1839 program_id,
1840 accounts,
1841 data.amount.into(),
1842 InstructionVariant::Unchecked,
1843 )
1844 }
1845 PodTokenInstruction::Burn => {
1846 msg!("Instruction: Burn");
1847 let data = decode_instruction_data::<AmountData>(input)?;
1848 Self::process_burn(
1849 program_id,
1850 accounts,
1851 data.amount.into(),
1852 InstructionVariant::Unchecked,
1853 )
1854 }
1855 PodTokenInstruction::CloseAccount => {
1856 msg!("Instruction: CloseAccount");
1857 Self::process_close_account(program_id, accounts)
1858 }
1859 PodTokenInstruction::FreezeAccount => {
1860 msg!("Instruction: FreezeAccount");
1861 Self::process_toggle_freeze_account(program_id, accounts, true)
1862 }
1863 PodTokenInstruction::ThawAccount => {
1864 msg!("Instruction: ThawAccount");
1865 Self::process_toggle_freeze_account(program_id, accounts, false)
1866 }
1867 PodTokenInstruction::TransferChecked => {
1868 msg!("Instruction: TransferChecked");
1869 let data = decode_instruction_data::<AmountCheckedData>(input)?;
1870 Self::process_transfer(
1871 program_id,
1872 accounts,
1873 data.amount.into(),
1874 TransferInstruction::Checked {
1875 decimals: data.decimals,
1876 },
1877 )
1878 }
1879 PodTokenInstruction::ApproveChecked => {
1880 msg!("Instruction: ApproveChecked");
1881 let data = decode_instruction_data::<AmountCheckedData>(input)?;
1882 Self::process_approve(
1883 program_id,
1884 accounts,
1885 data.amount.into(),
1886 InstructionVariant::Checked {
1887 decimals: data.decimals,
1888 },
1889 )
1890 }
1891 PodTokenInstruction::MintToChecked => {
1892 msg!("Instruction: MintToChecked");
1893 let data = decode_instruction_data::<AmountCheckedData>(input)?;
1894 Self::process_mint_to(
1895 program_id,
1896 accounts,
1897 data.amount.into(),
1898 InstructionVariant::Checked {
1899 decimals: data.decimals,
1900 },
1901 )
1902 }
1903 PodTokenInstruction::BurnChecked => {
1904 msg!("Instruction: BurnChecked");
1905 let data = decode_instruction_data::<AmountCheckedData>(input)?;
1906 Self::process_burn(
1907 program_id,
1908 accounts,
1909 data.amount.into(),
1910 InstructionVariant::Checked {
1911 decimals: data.decimals,
1912 },
1913 )
1914 }
1915 PodTokenInstruction::SyncNative => {
1916 msg!("Instruction: SyncNative");
1917 Self::process_sync_native(accounts)
1918 }
1919 PodTokenInstruction::GetAccountDataSize => {
1920 msg!("Instruction: GetAccountDataSize");
1921 let extension_types = input[1..]
1922 .chunks(std::mem::size_of::<ExtensionType>())
1923 .map(ExtensionType::try_from)
1924 .collect::<Result<Vec<_>, _>>()?;
1925 Self::process_get_account_data_size(accounts, &extension_types)
1926 }
1927 PodTokenInstruction::InitializeMintCloseAuthority => {
1928 msg!("Instruction: InitializeMintCloseAuthority");
1929 let (_, close_authority) =
1930 decode_instruction_data_with_coption_pubkey::<()>(input)?;
1931 Self::process_initialize_mint_close_authority(accounts, close_authority)
1932 }
1933 PodTokenInstruction::TransferFeeExtension => {
1934 transfer_fee::processor::process_instruction(program_id, accounts, &input[1..])
1935 }
1936 PodTokenInstruction::ConfidentialTransferExtension => {
1937 confidential_transfer::processor::process_instruction(
1938 program_id,
1939 accounts,
1940 &input[1..],
1941 )
1942 }
1943 PodTokenInstruction::DefaultAccountStateExtension => {
1944 default_account_state::processor::process_instruction(
1945 program_id,
1946 accounts,
1947 &input[1..],
1948 )
1949 }
1950 PodTokenInstruction::InitializeImmutableOwner => {
1951 msg!("Instruction: InitializeImmutableOwner");
1952 Self::process_initialize_immutable_owner(accounts)
1953 }
1954 PodTokenInstruction::AmountToUiAmount => {
1955 msg!("Instruction: AmountToUiAmount");
1956 let data = decode_instruction_data::<AmountData>(input)?;
1957 Self::process_amount_to_ui_amount(accounts, data.amount.into())
1958 }
1959 PodTokenInstruction::UiAmountToAmount => {
1960 msg!("Instruction: UiAmountToAmount");
1961 let ui_amount = std::str::from_utf8(&input[1..])
1962 .map_err(|_| TokenError::InvalidInstruction)?;
1963 Self::process_ui_amount_to_amount(accounts, ui_amount)
1964 }
1965 PodTokenInstruction::Reallocate => {
1966 msg!("Instruction: Reallocate");
1967 let extension_types = input[1..]
1968 .chunks(std::mem::size_of::<ExtensionType>())
1969 .map(ExtensionType::try_from)
1970 .collect::<Result<Vec<_>, _>>()?;
1971 reallocate::process_reallocate(program_id, accounts, extension_types)
1972 }
1973 PodTokenInstruction::MemoTransferExtension => {
1974 memo_transfer::processor::process_instruction(program_id, accounts, &input[1..])
1975 }
1976 PodTokenInstruction::CreateNativeMint => {
1977 msg!("Instruction: CreateNativeMint");
1978 Self::process_create_native_mint(accounts)
1979 }
1980 PodTokenInstruction::InitializeNonTransferableMint => {
1981 msg!("Instruction: InitializeNonTransferableMint");
1982 Self::process_initialize_non_transferable_mint(accounts)
1983 }
1984 PodTokenInstruction::InterestBearingMintExtension => {
1985 interest_bearing_mint::processor::process_instruction(
1986 program_id,
1987 accounts,
1988 &input[1..],
1989 )
1990 }
1991 PodTokenInstruction::CpiGuardExtension => {
1992 cpi_guard::processor::process_instruction(program_id, accounts, &input[1..])
1993 }
1994 PodTokenInstruction::InitializePermanentDelegate => {
1995 msg!("Instruction: InitializePermanentDelegate");
1996 let delegate = decode_instruction_data::<Pubkey>(input)?;
1997 Self::process_initialize_permanent_delegate(accounts, delegate)
1998 }
1999 PodTokenInstruction::TransferHookExtension => {
2000 transfer_hook::processor::process_instruction(program_id, accounts, &input[1..])
2001 }
2002 PodTokenInstruction::ConfidentialTransferFeeExtension => {
2003 confidential_transfer_fee::processor::process_instruction(
2004 program_id,
2005 accounts,
2006 &input[1..],
2007 )
2008 }
2009 PodTokenInstruction::WithdrawExcessKelvins => {
2010 msg!("Instruction: WithdrawExcessKelvins");
2011 Self::process_withdraw_excess_kelvins(program_id, accounts)
2012 }
2013 PodTokenInstruction::MetadataPointerExtension => {
2014 metadata_pointer::processor::process_instruction(
2015 program_id,
2016 accounts,
2017 &input[1..],
2018 )
2019 }
2020 PodTokenInstruction::GroupPointerExtension => {
2021 group_pointer::processor::process_instruction(program_id, accounts, &input[1..])
2022 }
2023 PodTokenInstruction::GroupMemberPointerExtension => {
2024 group_member_pointer::processor::process_instruction(
2025 program_id,
2026 accounts,
2027 &input[1..],
2028 )
2029 }
2030 PodTokenInstruction::ConfidentialMintBurnExtension => {
2031 msg!("Instruction: ConfidentialMintBurnExtension");
2032 confidential_mint_burn::processor::process_instruction(
2033 program_id,
2034 accounts,
2035 &input[1..],
2036 )
2037 }
2038 PodTokenInstruction::ScaledUiAmountExtension => {
2039 msg!("Instruction: ScaledUiAmountExtension");
2040 scaled_ui_amount::processor::process_instruction(
2041 program_id,
2042 accounts,
2043 &input[1..],
2044 )
2045 }
2046 PodTokenInstruction::PausableExtension => {
2047 msg!("Instruction: PausableExtension");
2048 pausable::processor::process_instruction(program_id, accounts, &input[1..])
2049 }
2050 }
2051 } else if let Ok(instruction) = TokenMetadataInstruction::unpack(input) {
2052 token_metadata::processor::process_instruction(program_id, accounts, instruction)
2053 } else if let Ok(instruction) = TokenGroupInstruction::unpack(input) {
2054 token_group::processor::process_instruction(program_id, accounts, instruction)
2055 } else {
2056 Err(TokenError::InvalidInstruction.into())
2057 }
2058 }
2059
2060 pub fn validate_owner(
2062 program_id: &Pubkey,
2063 expected_owner: &Pubkey,
2064 owner_account_info: &AccountInfo<'_>,
2065 owner_account_data_len: usize,
2066 signers: &[AccountInfo<'_>],
2067 ) -> ProgramResult {
2068 if expected_owner != owner_account_info.key {
2069 return Err(TokenError::OwnerMismatch.into());
2070 }
2071
2072 if program_id == owner_account_info.owner && owner_account_data_len == PodMultisig::SIZE_OF
2073 {
2074 let multisig_data = &owner_account_info.data.borrow();
2075 let multisig = pod_from_bytes::<PodMultisig>(multisig_data)?;
2076 let mut num_signers = 0;
2077 let mut matched = [false; MAX_SIGNERS];
2078 for signer in signers.iter() {
2079 for (position, key) in multisig.signers[0..multisig.n as usize].iter().enumerate() {
2080 if key == signer.key && !matched[position] {
2081 if !signer.is_signer {
2082 return Err(ProgramError::MissingRequiredSignature);
2083 }
2084 matched[position] = true;
2085 num_signers += 1;
2086 }
2087 }
2088 }
2089 if num_signers < multisig.m {
2090 return Err(ProgramError::MissingRequiredSignature);
2091 }
2092 return Ok(());
2093 } else if !owner_account_info.is_signer {
2094 return Err(ProgramError::MissingRequiredSignature);
2095 }
2096 Ok(())
2097 }
2098
2099 fn get_required_account_extensions(
2100 mint_account_info: &AccountInfo<'_>,
2101 ) -> Result<Vec<ExtensionType>, ProgramError> {
2102 let mint_data = mint_account_info.data.borrow();
2103 let state = PodStateWithExtensions::<PodMint>::unpack(&mint_data)
2104 .map_err(|_| Into::<ProgramError>::into(TokenError::InvalidMint))?;
2105 Self::get_required_account_extensions_from_unpacked_mint(mint_account_info.owner, &state)
2106 }
2107
2108 fn get_required_account_extensions_from_unpacked_mint(
2109 token_program_id: &Pubkey,
2110 state: &PodStateWithExtensions<'_, PodMint>,
2111 ) -> Result<Vec<ExtensionType>, ProgramError> {
2112 check_program_account(token_program_id)?;
2113 let mint_extensions = state.get_extension_types()?;
2114 Ok(ExtensionType::get_required_init_account_extensions(
2115 &mint_extensions,
2116 ))
2117 }
2118}
2119
2120#[cfg(not(target_os = "solana"))]
2124fn delete_account(account_info: &AccountInfo<'_>) -> Result<(), ProgramError> {
2125 account_info.assign(&system_program::id());
2126 let mut account_data = account_info.data.borrow_mut();
2127 let data_len = account_data.len();
2128 rialo_s_program_memory::rlo_memset(*account_data, 0, data_len);
2129 Ok(())
2130}
2131
2132#[cfg(target_os = "solana")]
2134fn delete_account(account_info: &AccountInfo<'_>) -> Result<(), ProgramError> {
2135 account_info.assign(&system_program::id());
2136 account_info.realloc(0, true)
2137}
2138
2139#[cfg(test)]
2140mod tests {
2141 use std::sync::{Arc, RwLock};
2142
2143 use once_cell::sync::Lazy;
2144 use rialo_s_account::{
2145 create_account_for_test, create_is_signer_account_infos, Account as SolanaAccount,
2146 };
2147 use rialo_s_account_info::IntoAccountInfo;
2148 use rialo_s_clock::{Clock, Epoch};
2149 use rialo_s_instruction::Instruction;
2150 use rialo_s_program_error::PrintProgramError;
2151 use rialo_s_program_option::COption;
2152 use rialo_s_sdk_ids::sysvar::rent;
2153 use rialo_spl_token_2022_interface::{
2154 extension::transfer_fee::instruction::initialize_transfer_fee_config, instruction::*,
2155 state::Multisig,
2156 };
2157 use serial_test::serial;
2158
2159 use super::*;
2160
2161 static EXPECTED_DATA: Lazy<Arc<RwLock<Vec<u8>>>> =
2162 Lazy::new(|| Arc::new(RwLock::new(Vec::new())));
2163
2164 fn set_expected_data(expected_data: Vec<u8>) {
2165 *EXPECTED_DATA.write().unwrap() = expected_data;
2166 }
2167
2168 struct SyscallStubs {}
2169 impl rialo_s_sysvar::program_stubs::SyscallStubs for SyscallStubs {
2170 fn rlo_log(&self, _message: &str) {}
2171
2172 fn rlo_invoke_signed(
2173 &self,
2174 _instruction: &Instruction,
2175 _account_infos: &[AccountInfo<'_>],
2176 _signers_seeds: &[&[&[u8]]],
2177 ) -> ProgramResult {
2178 Err(ProgramError::Custom(42)) }
2180
2181 #[allow(unsafe_code)]
2182 fn rlo_get_clock_sysvar(&self, var_addr: *mut u8) -> u64 {
2183 unsafe {
2184 *var_addr.cast::<Clock>() = Clock::default();
2185 }
2186 rialo_s_program_entrypoint::SUCCESS
2187 }
2188
2189 fn rlo_get_epoch_schedule_sysvar(&self, _var_addr: *mut u8) -> u64 {
2190 rialo_s_instruction::error::UNSUPPORTED_SYSVAR
2191 }
2192
2193 #[allow(deprecated)]
2194 fn rlo_get_fees_sysvar(&self, _var_addr: *mut u8) -> u64 {
2195 rialo_s_instruction::error::UNSUPPORTED_SYSVAR
2196 }
2197
2198 #[allow(unsafe_code)]
2199 fn rlo_get_rent_sysvar(&self, var_addr: *mut u8) -> u64 {
2200 unsafe {
2201 *var_addr.cast::<Rent>() = Rent::default();
2202 }
2203 rialo_s_program_entrypoint::SUCCESS
2204 }
2205
2206 fn rlo_set_return_data(&self, data: &[u8]) {
2207 assert_eq!(&*EXPECTED_DATA.read().unwrap(), data)
2208 }
2209 }
2210
2211 fn do_process_instruction(
2212 instruction: Instruction,
2213 accounts: Vec<&mut SolanaAccount>,
2214 ) -> ProgramResult {
2215 {
2216 use std::sync::Once;
2217 static ONCE: Once = Once::new();
2218
2219 ONCE.call_once(|| {
2220 rialo_s_sysvar::program_stubs::set_syscall_stubs(Box::new(SyscallStubs {}));
2221 });
2222 }
2223
2224 let mut meta = instruction
2225 .accounts
2226 .iter()
2227 .zip(accounts)
2228 .map(|(account_meta, account)| (&account_meta.pubkey, account_meta.is_signer, account))
2229 .collect::<Vec<_>>();
2230
2231 let account_infos = create_is_signer_account_infos(&mut meta);
2232 Processor::process(&instruction.program_id, &account_infos, &instruction.data)
2233 }
2234
2235 fn do_process_instruction_dups(
2236 instruction: Instruction,
2237 account_infos: Vec<AccountInfo<'_>>,
2238 ) -> ProgramResult {
2239 Processor::process(&instruction.program_id, &account_infos, &instruction.data)
2240 }
2241
2242 fn return_token_error_as_program_error() -> ProgramError {
2243 TokenError::MintMismatch.into()
2244 }
2245
2246 fn rent_sysvar() -> SolanaAccount {
2247 create_account_for_test(&Rent::default())
2248 }
2249
2250 fn mint_minimum_balance() -> u64 {
2251 Rent::default().minimum_balance(Mint::get_packed_len())
2252 }
2253
2254 fn account_minimum_balance() -> u64 {
2255 Rent::default().minimum_balance(Account::get_packed_len())
2256 }
2257
2258 fn multisig_minimum_balance() -> u64 {
2259 Rent::default().minimum_balance(Multisig::get_packed_len())
2260 }
2261
2262 fn native_mint() -> SolanaAccount {
2263 let mut rent_sysvar = rent_sysvar();
2264 let mut mint_account =
2265 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &crate::id());
2266 do_process_instruction(
2267 initialize_mint(
2268 &crate::id(),
2269 &crate::native_mint::id(),
2270 &Pubkey::default(),
2271 None,
2272 crate::native_mint::DECIMALS,
2273 )
2274 .unwrap(),
2275 vec![&mut mint_account, &mut rent_sysvar],
2276 )
2277 .unwrap();
2278 mint_account
2279 }
2280
2281 #[test]
2282 fn test_print_error() {
2283 let error = return_token_error_as_program_error();
2284 error.print::<TokenError>();
2285 }
2286
2287 #[test]
2288 fn test_error_as_custom() {
2289 assert_eq!(
2290 return_token_error_as_program_error(),
2291 ProgramError::Custom(3)
2292 );
2293 }
2294
2295 #[test]
2296 fn test_unique_account_sizes() {
2297 assert_ne!(Mint::get_packed_len(), 0);
2298 assert_ne!(Mint::get_packed_len(), Account::get_packed_len());
2299 assert_ne!(Mint::get_packed_len(), Multisig::get_packed_len());
2300 assert_ne!(Account::get_packed_len(), 0);
2301 assert_ne!(Account::get_packed_len(), Multisig::get_packed_len());
2302 assert_ne!(Multisig::get_packed_len(), 0);
2303 }
2304
2305 #[test]
2306 fn test_initialize_mint() {
2307 let program_id = crate::id();
2308 let owner_key = Pubkey::new_unique();
2309 let mint_key = Pubkey::new_unique();
2310 let mut mint_account = SolanaAccount::new(42, Mint::get_packed_len(), &program_id);
2311 let mint2_key = Pubkey::new_unique();
2312 let mut mint2_account =
2313 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
2314 let mut rent_sysvar = rent_sysvar();
2315
2316 assert_eq!(
2318 Err(TokenError::NotRentExempt.into()),
2319 do_process_instruction(
2320 initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
2321 vec![&mut mint_account, &mut rent_sysvar]
2322 )
2323 );
2324
2325 mint_account.kelvins = mint_minimum_balance();
2326
2327 do_process_instruction(
2329 initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
2330 vec![&mut mint_account, &mut rent_sysvar],
2331 )
2332 .unwrap();
2333
2334 assert_eq!(
2336 Err(TokenError::AlreadyInUse.into()),
2337 do_process_instruction(
2338 initialize_mint(&program_id, &mint_key, &owner_key, None, 2,).unwrap(),
2339 vec![&mut mint_account, &mut rent_sysvar]
2340 )
2341 );
2342
2343 do_process_instruction(
2345 initialize_mint(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(),
2346 vec![&mut mint2_account, &mut rent_sysvar],
2347 )
2348 .unwrap();
2349 let mint = Mint::unpack_unchecked(&mint2_account.data).unwrap();
2350 assert_eq!(mint.freeze_authority, COption::Some(owner_key));
2351 }
2352
2353 #[test]
2354 fn test_initialize_mint2() {
2355 let program_id = crate::id();
2356 let owner_key = Pubkey::new_unique();
2357 let mint_key = Pubkey::new_unique();
2358 let mut mint_account = SolanaAccount::new(42, Mint::get_packed_len(), &program_id);
2359 let mut mint_tombstone_account = SolanaAccount::new(0, 0, &program_id);
2360 let mint2_key = Pubkey::new_unique();
2361 let mut mint2_account =
2362 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
2363 let mut mint2_tombstone_account = SolanaAccount::new(0, 0, &program_id);
2364
2365 assert_eq!(
2367 Err(TokenError::NotRentExempt.into()),
2368 do_process_instruction(
2369 initialize_mint2(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
2370 vec![&mut mint_account, &mut mint_tombstone_account],
2371 )
2372 );
2373
2374 mint_account.kelvins = mint_minimum_balance();
2375
2376 do_process_instruction(
2378 initialize_mint2(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
2379 vec![&mut mint_account, &mut mint_tombstone_account],
2380 )
2381 .unwrap();
2382
2383 assert_eq!(
2385 Err(TokenError::AlreadyInUse.into()),
2386 do_process_instruction(
2387 initialize_mint2(&program_id, &mint_key, &owner_key, None, 2,).unwrap(),
2388 vec![&mut mint_account, &mut mint_tombstone_account],
2389 )
2390 );
2391
2392 do_process_instruction(
2394 initialize_mint2(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(),
2395 vec![&mut mint2_account, &mut mint2_tombstone_account],
2396 )
2397 .unwrap();
2398 let mint = Mint::unpack_unchecked(&mint2_account.data).unwrap();
2399 assert_eq!(mint.freeze_authority, COption::Some(owner_key));
2400 }
2401
2402 #[test]
2403 fn test_initialize_mint_account() {
2404 let program_id = crate::id();
2405 let account_key = Pubkey::new_unique();
2406 let mut account_account = SolanaAccount::new(42, Account::get_packed_len(), &program_id);
2407 let owner_key = Pubkey::new_unique();
2408 let mut owner_account = SolanaAccount::default();
2409 let mint_key = Pubkey::new_unique();
2410 let mut mint_account =
2411 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
2412 let mut rent_sysvar = rent_sysvar();
2413
2414 assert_eq!(
2416 Err(TokenError::NotRentExempt.into()),
2417 do_process_instruction(
2418 initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
2419 vec![
2420 &mut account_account,
2421 &mut mint_account,
2422 &mut owner_account,
2423 &mut rent_sysvar
2424 ],
2425 )
2426 );
2427
2428 account_account.kelvins = account_minimum_balance();
2429
2430 assert_eq!(
2432 Err(TokenError::InvalidMint.into()),
2433 do_process_instruction(
2434 initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
2435 vec![
2436 &mut account_account,
2437 &mut mint_account,
2438 &mut owner_account,
2439 &mut rent_sysvar
2440 ],
2441 )
2442 );
2443
2444 do_process_instruction(
2446 initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
2447 vec![&mut mint_account, &mut rent_sysvar],
2448 )
2449 .unwrap();
2450
2451 let not_program_id = Pubkey::new_unique();
2453 mint_account.owner = not_program_id;
2454 assert_eq!(
2455 Err(ProgramError::IncorrectProgramId),
2456 do_process_instruction(
2457 initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
2458 vec![
2459 &mut account_account,
2460 &mut mint_account,
2461 &mut owner_account,
2462 &mut rent_sysvar
2463 ],
2464 )
2465 );
2466 mint_account.owner = program_id;
2467
2468 do_process_instruction(
2470 initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
2471 vec![
2472 &mut account_account,
2473 &mut mint_account,
2474 &mut owner_account,
2475 &mut rent_sysvar,
2476 ],
2477 )
2478 .unwrap();
2479
2480 assert_eq!(
2482 Err(TokenError::AlreadyInUse.into()),
2483 do_process_instruction(
2484 initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
2485 vec![
2486 &mut account_account,
2487 &mut mint_account,
2488 &mut owner_account,
2489 &mut rent_sysvar
2490 ],
2491 )
2492 );
2493 }
2494
2495 #[test]
2496 fn test_transfer_dups() {
2497 let program_id = crate::id();
2498 let account1_key = Pubkey::new_unique();
2499 let mut account1_account = SolanaAccount::new(
2500 account_minimum_balance(),
2501 Account::get_packed_len(),
2502 &program_id,
2503 );
2504 let mut account1_info: AccountInfo<'_> =
2505 (&account1_key, true, &mut account1_account).into();
2506 let account2_key = Pubkey::new_unique();
2507 let mut account2_account = SolanaAccount::new(
2508 account_minimum_balance(),
2509 Account::get_packed_len(),
2510 &program_id,
2511 );
2512 let mut account2_info: AccountInfo<'_> =
2513 (&account2_key, false, &mut account2_account).into();
2514 let account3_key = Pubkey::new_unique();
2515 let mut account3_account = SolanaAccount::new(
2516 account_minimum_balance(),
2517 Account::get_packed_len(),
2518 &program_id,
2519 );
2520 let account3_info: AccountInfo<'_> = (&account3_key, false, &mut account3_account).into();
2521 let account4_key = Pubkey::new_unique();
2522 let mut account4_account = SolanaAccount::new(
2523 account_minimum_balance(),
2524 Account::get_packed_len(),
2525 &program_id,
2526 );
2527 let account4_info: AccountInfo<'_> = (&account4_key, true, &mut account4_account).into();
2528 let multisig_key = Pubkey::new_unique();
2529 let mut multisig_account = SolanaAccount::new(
2530 multisig_minimum_balance(),
2531 Multisig::get_packed_len(),
2532 &program_id,
2533 );
2534 let multisig_info: AccountInfo<'_> = (&multisig_key, true, &mut multisig_account).into();
2535 let owner_key = Pubkey::new_unique();
2536 let mut owner_account = SolanaAccount::default();
2537 let owner_info: AccountInfo<'_> = (&owner_key, true, &mut owner_account).into();
2538 let mint_key = Pubkey::new_unique();
2539 let mut mint_account =
2540 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
2541 let mint_info: AccountInfo<'_> = (&mint_key, false, &mut mint_account).into();
2542 let rent_key = rent::id();
2543 let mut rent_sysvar = rent_sysvar();
2544 let rent_info: AccountInfo<'_> = (&rent_key, false, &mut rent_sysvar).into();
2545
2546 do_process_instruction_dups(
2548 initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
2549 vec![mint_info.clone(), rent_info.clone()],
2550 )
2551 .unwrap();
2552
2553 do_process_instruction_dups(
2555 initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(),
2556 vec![
2557 account1_info.clone(),
2558 mint_info.clone(),
2559 account1_info.clone(),
2560 rent_info.clone(),
2561 ],
2562 )
2563 .unwrap();
2564
2565 do_process_instruction_dups(
2567 initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(),
2568 vec![
2569 account2_info.clone(),
2570 mint_info.clone(),
2571 owner_info.clone(),
2572 rent_info.clone(),
2573 ],
2574 )
2575 .unwrap();
2576
2577 do_process_instruction_dups(
2579 mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(),
2580 vec![mint_info.clone(), account1_info.clone(), owner_info.clone()],
2581 )
2582 .unwrap();
2583
2584 do_process_instruction_dups(
2586 #[allow(deprecated)]
2587 transfer(
2588 &program_id,
2589 &account1_key,
2590 &account2_key,
2591 &account1_key,
2592 &[],
2593 500,
2594 )
2595 .unwrap(),
2596 vec![
2597 account1_info.clone(),
2598 account2_info.clone(),
2599 account1_info.clone(),
2600 ],
2601 )
2602 .unwrap();
2603
2604 do_process_instruction_dups(
2606 transfer_checked(
2607 &program_id,
2608 &account1_key,
2609 &mint_key,
2610 &account2_key,
2611 &account1_key,
2612 &[],
2613 500,
2614 2,
2615 )
2616 .unwrap(),
2617 vec![
2618 account1_info.clone(),
2619 mint_info.clone(),
2620 account2_info.clone(),
2621 account1_info.clone(),
2622 ],
2623 )
2624 .unwrap();
2625
2626 let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap();
2628 account.amount = 1000;
2629 account.delegated_amount = 1000;
2630 account.delegate = COption::Some(account1_key);
2631 account.owner = owner_key;
2632 Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap();
2633
2634 do_process_instruction_dups(
2635 #[allow(deprecated)]
2636 transfer(
2637 &program_id,
2638 &account1_key,
2639 &account2_key,
2640 &account1_key,
2641 &[],
2642 500,
2643 )
2644 .unwrap(),
2645 vec![
2646 account1_info.clone(),
2647 account2_info.clone(),
2648 account1_info.clone(),
2649 ],
2650 )
2651 .unwrap();
2652
2653 do_process_instruction_dups(
2655 transfer_checked(
2656 &program_id,
2657 &account1_key,
2658 &mint_key,
2659 &account2_key,
2660 &account1_key,
2661 &[],
2662 500,
2663 2,
2664 )
2665 .unwrap(),
2666 vec![
2667 account1_info.clone(),
2668 mint_info.clone(),
2669 account2_info.clone(),
2670 account1_info.clone(),
2671 ],
2672 )
2673 .unwrap();
2674
2675 do_process_instruction_dups(
2677 initialize_account(&program_id, &account3_key, &mint_key, &account2_key).unwrap(),
2678 vec![
2679 account3_info.clone(),
2680 mint_info.clone(),
2681 account2_info.clone(),
2682 rent_info.clone(),
2683 ],
2684 )
2685 .unwrap();
2686 do_process_instruction_dups(
2687 mint_to(&program_id, &mint_key, &account3_key, &owner_key, &[], 1000).unwrap(),
2688 vec![mint_info.clone(), account3_info.clone(), owner_info.clone()],
2689 )
2690 .unwrap();
2691
2692 account1_info.is_signer = false;
2693 account2_info.is_signer = true;
2694 do_process_instruction_dups(
2695 #[allow(deprecated)]
2696 transfer(
2697 &program_id,
2698 &account3_key,
2699 &account2_key,
2700 &account2_key,
2701 &[],
2702 500,
2703 )
2704 .unwrap(),
2705 vec![
2706 account3_info.clone(),
2707 account2_info.clone(),
2708 account2_info.clone(),
2709 ],
2710 )
2711 .unwrap();
2712
2713 do_process_instruction_dups(
2715 transfer_checked(
2716 &program_id,
2717 &account3_key,
2718 &mint_key,
2719 &account2_key,
2720 &account2_key,
2721 &[],
2722 500,
2723 2,
2724 )
2725 .unwrap(),
2726 vec![
2727 account3_info.clone(),
2728 mint_info.clone(),
2729 account2_info.clone(),
2730 account2_info.clone(),
2731 ],
2732 )
2733 .unwrap();
2734
2735 do_process_instruction_dups(
2737 initialize_multisig(&program_id, &multisig_key, &[&account4_key], 1).unwrap(),
2738 vec![
2739 multisig_info.clone(),
2740 rent_info.clone(),
2741 account4_info.clone(),
2742 ],
2743 )
2744 .unwrap();
2745
2746 do_process_instruction_dups(
2747 initialize_account(&program_id, &account4_key, &mint_key, &multisig_key).unwrap(),
2748 vec![
2749 account4_info.clone(),
2750 mint_info.clone(),
2751 multisig_info.clone(),
2752 rent_info.clone(),
2753 ],
2754 )
2755 .unwrap();
2756
2757 do_process_instruction_dups(
2758 mint_to(&program_id, &mint_key, &account4_key, &owner_key, &[], 1000).unwrap(),
2759 vec![mint_info.clone(), account4_info.clone(), owner_info.clone()],
2760 )
2761 .unwrap();
2762
2763 do_process_instruction_dups(
2765 #[allow(deprecated)]
2766 transfer(
2767 &program_id,
2768 &account4_key,
2769 &account2_key,
2770 &multisig_key,
2771 &[&account4_key],
2772 500,
2773 )
2774 .unwrap(),
2775 vec![
2776 account4_info.clone(),
2777 account2_info.clone(),
2778 multisig_info.clone(),
2779 account4_info.clone(),
2780 ],
2781 )
2782 .unwrap();
2783
2784 do_process_instruction_dups(
2786 transfer_checked(
2787 &program_id,
2788 &account4_key,
2789 &mint_key,
2790 &account2_key,
2791 &multisig_key,
2792 &[&account4_key],
2793 500,
2794 2,
2795 )
2796 .unwrap(),
2797 vec![
2798 account4_info.clone(),
2799 mint_info.clone(),
2800 account2_info.clone(),
2801 multisig_info.clone(),
2802 account4_info.clone(),
2803 ],
2804 )
2805 .unwrap();
2806 }
2807
2808 #[test]
2809 fn test_transfer() {
2810 let program_id = crate::id();
2811 let account_key = Pubkey::new_unique();
2812 let mut account_account = SolanaAccount::new(
2813 account_minimum_balance(),
2814 Account::get_packed_len(),
2815 &program_id,
2816 );
2817 let account2_key = Pubkey::new_unique();
2818 let mut account2_account = SolanaAccount::new(
2819 account_minimum_balance(),
2820 Account::get_packed_len(),
2821 &program_id,
2822 );
2823 let account3_key = Pubkey::new_unique();
2824 let mut account3_account = SolanaAccount::new(
2825 account_minimum_balance(),
2826 Account::get_packed_len(),
2827 &program_id,
2828 );
2829 let delegate_key = Pubkey::new_unique();
2830 let mut delegate_account = SolanaAccount::default();
2831 let mismatch_key = Pubkey::new_unique();
2832 let mut mismatch_account = SolanaAccount::new(
2833 account_minimum_balance(),
2834 Account::get_packed_len(),
2835 &program_id,
2836 );
2837 let owner_key = Pubkey::new_unique();
2838 let mut owner_account = SolanaAccount::default();
2839 let owner2_key = Pubkey::new_unique();
2840 let mut owner2_account = SolanaAccount::default();
2841 let mint_key = Pubkey::new_unique();
2842 let mut mint_account =
2843 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
2844 let mint2_key = Pubkey::new_unique();
2845 let mut rent_sysvar = rent_sysvar();
2846
2847 do_process_instruction(
2849 initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
2850 vec![&mut mint_account, &mut rent_sysvar],
2851 )
2852 .unwrap();
2853
2854 do_process_instruction(
2856 initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
2857 vec![
2858 &mut account_account,
2859 &mut mint_account,
2860 &mut owner_account,
2861 &mut rent_sysvar,
2862 ],
2863 )
2864 .unwrap();
2865
2866 do_process_instruction(
2868 initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(),
2869 vec![
2870 &mut account2_account,
2871 &mut mint_account,
2872 &mut owner_account,
2873 &mut rent_sysvar,
2874 ],
2875 )
2876 .unwrap();
2877
2878 do_process_instruction(
2880 initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(),
2881 vec![
2882 &mut account3_account,
2883 &mut mint_account,
2884 &mut owner_account,
2885 &mut rent_sysvar,
2886 ],
2887 )
2888 .unwrap();
2889
2890 do_process_instruction(
2892 initialize_account(&program_id, &mismatch_key, &mint_key, &owner_key).unwrap(),
2893 vec![
2894 &mut mismatch_account,
2895 &mut mint_account,
2896 &mut owner_account,
2897 &mut rent_sysvar,
2898 ],
2899 )
2900 .unwrap();
2901 let mut account = Account::unpack_unchecked(&mismatch_account.data).unwrap();
2902 account.mint = mint2_key;
2903 Account::pack(account, &mut mismatch_account.data).unwrap();
2904
2905 do_process_instruction(
2907 mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(),
2908 vec![&mut mint_account, &mut account_account, &mut owner_account],
2909 )
2910 .unwrap();
2911
2912 #[allow(deprecated)]
2914 let mut instruction = transfer(
2915 &program_id,
2916 &account_key,
2917 &account2_key,
2918 &owner_key,
2919 &[],
2920 1000,
2921 )
2922 .unwrap();
2923 instruction.accounts[2].is_signer = false;
2924 assert_eq!(
2925 Err(ProgramError::MissingRequiredSignature),
2926 do_process_instruction(
2927 instruction,
2928 vec![
2929 &mut account_account,
2930 &mut account2_account,
2931 &mut owner_account,
2932 ],
2933 )
2934 );
2935
2936 assert_eq!(
2938 Err(TokenError::MintMismatch.into()),
2939 do_process_instruction(
2940 #[allow(deprecated)]
2941 transfer(
2942 &program_id,
2943 &account_key,
2944 &mismatch_key,
2945 &owner_key,
2946 &[],
2947 1000
2948 )
2949 .unwrap(),
2950 vec![
2951 &mut account_account,
2952 &mut mismatch_account,
2953 &mut owner_account,
2954 ],
2955 )
2956 );
2957
2958 assert_eq!(
2960 Err(TokenError::OwnerMismatch.into()),
2961 do_process_instruction(
2962 #[allow(deprecated)]
2963 transfer(
2964 &program_id,
2965 &account_key,
2966 &account2_key,
2967 &owner2_key,
2968 &[],
2969 1000
2970 )
2971 .unwrap(),
2972 vec![
2973 &mut account_account,
2974 &mut account2_account,
2975 &mut owner2_account,
2976 ],
2977 )
2978 );
2979
2980 let not_program_id = Pubkey::new_unique();
2982 account_account.owner = not_program_id;
2983 assert_eq!(
2984 Err(ProgramError::IncorrectProgramId),
2985 do_process_instruction(
2986 #[allow(deprecated)]
2987 transfer(&program_id, &account_key, &account2_key, &owner_key, &[], 0,).unwrap(),
2988 vec![
2989 &mut account_account,
2990 &mut account2_account,
2991 &mut owner2_account,
2992 ],
2993 )
2994 );
2995 account_account.owner = program_id;
2996
2997 let not_program_id = Pubkey::new_unique();
2999 account2_account.owner = not_program_id;
3000 assert_eq!(
3001 Err(ProgramError::IncorrectProgramId),
3002 do_process_instruction(
3003 #[allow(deprecated)]
3004 transfer(&program_id, &account_key, &account2_key, &owner_key, &[], 0,).unwrap(),
3005 vec![
3006 &mut account_account,
3007 &mut account2_account,
3008 &mut owner2_account,
3009 ],
3010 )
3011 );
3012 account2_account.owner = program_id;
3013
3014 do_process_instruction(
3016 #[allow(deprecated)]
3017 transfer(
3018 &program_id,
3019 &account_key,
3020 &account2_key,
3021 &owner_key,
3022 &[],
3023 1000,
3024 )
3025 .unwrap(),
3026 vec![
3027 &mut account_account,
3028 &mut account2_account,
3029 &mut owner_account,
3030 ],
3031 )
3032 .unwrap();
3033
3034 assert_eq!(
3036 Err(TokenError::InsufficientFunds.into()),
3037 do_process_instruction(
3038 #[allow(deprecated)]
3039 transfer(&program_id, &account_key, &account2_key, &owner_key, &[], 1).unwrap(),
3040 vec![
3041 &mut account_account,
3042 &mut account2_account,
3043 &mut owner_account,
3044 ],
3045 )
3046 );
3047
3048 do_process_instruction(
3050 #[allow(deprecated)]
3051 transfer(
3052 &program_id,
3053 &account2_key,
3054 &account_key,
3055 &owner_key,
3056 &[],
3057 500,
3058 )
3059 .unwrap(),
3060 vec![
3061 &mut account2_account,
3062 &mut account_account,
3063 &mut owner_account,
3064 ],
3065 )
3066 .unwrap();
3067
3068 assert_eq!(
3070 Err(TokenError::MintDecimalsMismatch.into()),
3071 do_process_instruction(
3072 transfer_checked(
3073 &program_id,
3074 &account2_key,
3075 &mint_key,
3076 &account_key,
3077 &owner_key,
3078 &[],
3079 1,
3080 10 )
3082 .unwrap(),
3083 vec![
3084 &mut account2_account,
3085 &mut mint_account,
3086 &mut account_account,
3087 &mut owner_account,
3088 ],
3089 )
3090 );
3091
3092 assert_eq!(
3094 Err(TokenError::MintMismatch.into()),
3095 do_process_instruction(
3096 transfer_checked(
3097 &program_id,
3098 &account2_key,
3099 &account3_key, &account_key,
3101 &owner_key,
3102 &[],
3103 1,
3104 2
3105 )
3106 .unwrap(),
3107 vec![
3108 &mut account2_account,
3109 &mut account3_account, &mut account_account,
3111 &mut owner_account,
3112 ],
3113 )
3114 );
3115 do_process_instruction(
3117 transfer_checked(
3118 &program_id,
3119 &account2_key,
3120 &mint_key,
3121 &account_key,
3122 &owner_key,
3123 &[],
3124 500,
3125 2,
3126 )
3127 .unwrap(),
3128 vec![
3129 &mut account2_account,
3130 &mut mint_account,
3131 &mut account_account,
3132 &mut owner_account,
3133 ],
3134 )
3135 .unwrap();
3136
3137 assert_eq!(
3139 Err(TokenError::InsufficientFunds.into()),
3140 do_process_instruction(
3141 #[allow(deprecated)]
3142 transfer(&program_id, &account2_key, &account_key, &owner_key, &[], 1).unwrap(),
3143 vec![
3144 &mut account2_account,
3145 &mut account_account,
3146 &mut owner_account,
3147 ],
3148 )
3149 );
3150
3151 do_process_instruction(
3153 approve(
3154 &program_id,
3155 &account_key,
3156 &delegate_key,
3157 &owner_key,
3158 &[],
3159 100,
3160 )
3161 .unwrap(),
3162 vec![
3163 &mut account_account,
3164 &mut delegate_account,
3165 &mut owner_account,
3166 ],
3167 )
3168 .unwrap();
3169
3170 assert_eq!(
3172 Err(TokenError::OwnerMismatch.into()),
3173 do_process_instruction(
3174 #[allow(deprecated)]
3175 transfer(
3176 &program_id,
3177 &account_key,
3178 &account2_key,
3179 &owner2_key, &[],
3181 1,
3182 )
3183 .unwrap(),
3184 vec![
3185 &mut account_account,
3186 &mut account2_account,
3187 &mut owner2_account,
3188 ],
3189 )
3190 );
3191
3192 assert_eq!(
3194 Err(TokenError::InsufficientFunds.into()),
3195 do_process_instruction(
3196 #[allow(deprecated)]
3197 transfer(
3198 &program_id,
3199 &account_key,
3200 &account2_key,
3201 &delegate_key,
3202 &[],
3203 101
3204 )
3205 .unwrap(),
3206 vec![
3207 &mut account_account,
3208 &mut account2_account,
3209 &mut delegate_account,
3210 ],
3211 )
3212 );
3213
3214 do_process_instruction(
3216 #[allow(deprecated)]
3217 transfer(
3218 &program_id,
3219 &account_key,
3220 &account2_key,
3221 &delegate_key,
3222 &[],
3223 100,
3224 )
3225 .unwrap(),
3226 vec![
3227 &mut account_account,
3228 &mut account2_account,
3229 &mut delegate_account,
3230 ],
3231 )
3232 .unwrap();
3233
3234 assert_eq!(
3236 Err(TokenError::OwnerMismatch.into()),
3237 do_process_instruction(
3238 #[allow(deprecated)]
3239 transfer(
3240 &program_id,
3241 &account_key,
3242 &account2_key,
3243 &delegate_key,
3244 &[],
3245 1
3246 )
3247 .unwrap(),
3248 vec![
3249 &mut account_account,
3250 &mut account2_account,
3251 &mut delegate_account,
3252 ],
3253 )
3254 );
3255
3256 do_process_instruction(
3258 #[allow(deprecated)]
3259 transfer(
3260 &program_id,
3261 &account_key,
3262 &account2_key,
3263 &owner_key,
3264 &[],
3265 900,
3266 )
3267 .unwrap(),
3268 vec![
3269 &mut account_account,
3270 &mut account2_account,
3271 &mut owner_account,
3272 ],
3273 )
3274 .unwrap();
3275
3276 do_process_instruction(
3278 approve(
3279 &program_id,
3280 &account_key,
3281 &delegate_key,
3282 &owner_key,
3283 &[],
3284 100,
3285 )
3286 .unwrap(),
3287 vec![
3288 &mut account_account,
3289 &mut delegate_account,
3290 &mut owner_account,
3291 ],
3292 )
3293 .unwrap();
3294
3295 assert_eq!(
3297 Err(TokenError::InsufficientFunds.into()),
3298 do_process_instruction(
3299 #[allow(deprecated)]
3300 transfer(
3301 &program_id,
3302 &account_key,
3303 &account2_key,
3304 &delegate_key,
3305 &[],
3306 100
3307 )
3308 .unwrap(),
3309 vec![
3310 &mut account_account,
3311 &mut account2_account,
3312 &mut delegate_account,
3313 ],
3314 )
3315 );
3316 }
3317
3318 #[test]
3319 fn test_self_transfer() {
3320 let program_id = crate::id();
3321 let account_key = Pubkey::new_unique();
3322 let mut account_account = SolanaAccount::new(
3323 account_minimum_balance(),
3324 Account::get_packed_len(),
3325 &program_id,
3326 );
3327 let account2_key = Pubkey::new_unique();
3328 let mut account2_account = SolanaAccount::new(
3329 account_minimum_balance(),
3330 Account::get_packed_len(),
3331 &program_id,
3332 );
3333 let account3_key = Pubkey::new_unique();
3334 let mut account3_account = SolanaAccount::new(
3335 account_minimum_balance(),
3336 Account::get_packed_len(),
3337 &program_id,
3338 );
3339 let delegate_key = Pubkey::new_unique();
3340 let mut delegate_account = SolanaAccount::default();
3341 let owner_key = Pubkey::new_unique();
3342 let mut owner_account = SolanaAccount::default();
3343 let owner2_key = Pubkey::new_unique();
3344 let mut owner2_account = SolanaAccount::default();
3345 let mint_key = Pubkey::new_unique();
3346 let mut mint_account =
3347 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
3348 let mut rent_sysvar = rent_sysvar();
3349
3350 do_process_instruction(
3352 initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
3353 vec![&mut mint_account, &mut rent_sysvar],
3354 )
3355 .unwrap();
3356
3357 do_process_instruction(
3359 initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
3360 vec![
3361 &mut account_account,
3362 &mut mint_account,
3363 &mut owner_account,
3364 &mut rent_sysvar,
3365 ],
3366 )
3367 .unwrap();
3368
3369 do_process_instruction(
3371 initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(),
3372 vec![
3373 &mut account2_account,
3374 &mut mint_account,
3375 &mut owner_account,
3376 &mut rent_sysvar,
3377 ],
3378 )
3379 .unwrap();
3380
3381 do_process_instruction(
3383 initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(),
3384 vec![
3385 &mut account3_account,
3386 &mut mint_account,
3387 &mut owner_account,
3388 &mut rent_sysvar,
3389 ],
3390 )
3391 .unwrap();
3392
3393 do_process_instruction(
3395 mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(),
3396 vec![&mut mint_account, &mut account_account, &mut owner_account],
3397 )
3398 .unwrap();
3399
3400 let account_info = (&account_key, false, &mut account_account).into_account_info();
3401 let account3_info = (&account3_key, false, &mut account3_account).into_account_info();
3402 let delegate_info = (&delegate_key, true, &mut delegate_account).into_account_info();
3403 let owner_info = (&owner_key, true, &mut owner_account).into_account_info();
3404 let owner2_info = (&owner2_key, true, &mut owner2_account).into_account_info();
3405 let mint_info = (&mint_key, false, &mut mint_account).into_account_info();
3406
3407 #[allow(deprecated)]
3409 let instruction = transfer(
3410 &program_id,
3411 account_info.key,
3412 account_info.key,
3413 owner_info.key,
3414 &[],
3415 1000,
3416 )
3417 .unwrap();
3418 assert_eq!(
3419 Ok(()),
3420 Processor::process(
3421 &instruction.program_id,
3422 &[
3423 account_info.clone(),
3424 account_info.clone(),
3425 owner_info.clone(),
3426 ],
3427 &instruction.data,
3428 )
3429 );
3430 let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap();
3432 assert_eq!(account.amount, 1000);
3433
3434 let instruction = transfer_checked(
3436 &program_id,
3437 account_info.key,
3438 mint_info.key,
3439 account_info.key,
3440 owner_info.key,
3441 &[],
3442 1000,
3443 2,
3444 )
3445 .unwrap();
3446 assert_eq!(
3447 Ok(()),
3448 Processor::process(
3449 &instruction.program_id,
3450 &[
3451 account_info.clone(),
3452 mint_info.clone(),
3453 account_info.clone(),
3454 owner_info.clone(),
3455 ],
3456 &instruction.data,
3457 )
3458 );
3459 let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap();
3461 assert_eq!(account.amount, 1000);
3462
3463 let mut owner_no_sign_info = owner_info.clone();
3465 #[allow(deprecated)]
3466 let mut instruction = transfer(
3467 &program_id,
3468 account_info.key,
3469 account_info.key,
3470 owner_no_sign_info.key,
3471 &[],
3472 1000,
3473 )
3474 .unwrap();
3475 instruction.accounts[2].is_signer = false;
3476 owner_no_sign_info.is_signer = false;
3477 assert_eq!(
3478 Err(ProgramError::MissingRequiredSignature),
3479 Processor::process(
3480 &instruction.program_id,
3481 &[
3482 account_info.clone(),
3483 account_info.clone(),
3484 owner_no_sign_info.clone(),
3485 ],
3486 &instruction.data,
3487 )
3488 );
3489
3490 let mut instruction = transfer_checked(
3492 &program_id,
3493 account_info.key,
3494 mint_info.key,
3495 account_info.key,
3496 owner_no_sign_info.key,
3497 &[],
3498 1000,
3499 2,
3500 )
3501 .unwrap();
3502 instruction.accounts[3].is_signer = false;
3503 assert_eq!(
3504 Err(ProgramError::MissingRequiredSignature),
3505 Processor::process(
3506 &instruction.program_id,
3507 &[
3508 account_info.clone(),
3509 mint_info.clone(),
3510 account_info.clone(),
3511 owner_no_sign_info,
3512 ],
3513 &instruction.data,
3514 )
3515 );
3516
3517 #[allow(deprecated)]
3519 let instruction = transfer(
3520 &program_id,
3521 account_info.key,
3522 account_info.key,
3523 owner2_info.key,
3524 &[],
3525 1000,
3526 )
3527 .unwrap();
3528 assert_eq!(
3529 Err(TokenError::OwnerMismatch.into()),
3530 Processor::process(
3531 &instruction.program_id,
3532 &[
3533 account_info.clone(),
3534 account_info.clone(),
3535 owner2_info.clone(),
3536 ],
3537 &instruction.data,
3538 )
3539 );
3540
3541 let instruction = transfer_checked(
3543 &program_id,
3544 account_info.key,
3545 mint_info.key,
3546 account_info.key,
3547 owner2_info.key,
3548 &[],
3549 1000,
3550 2,
3551 )
3552 .unwrap();
3553 assert_eq!(
3554 Err(TokenError::OwnerMismatch.into()),
3555 Processor::process(
3556 &instruction.program_id,
3557 &[
3558 account_info.clone(),
3559 mint_info.clone(),
3560 account_info.clone(),
3561 owner2_info.clone(),
3562 ],
3563 &instruction.data,
3564 )
3565 );
3566
3567 #[allow(deprecated)]
3569 let instruction = transfer(
3570 &program_id,
3571 account_info.key,
3572 account_info.key,
3573 owner_info.key,
3574 &[],
3575 1001,
3576 )
3577 .unwrap();
3578 assert_eq!(
3579 Err(TokenError::InsufficientFunds.into()),
3580 Processor::process(
3581 &instruction.program_id,
3582 &[
3583 account_info.clone(),
3584 account_info.clone(),
3585 owner_info.clone(),
3586 ],
3587 &instruction.data,
3588 )
3589 );
3590
3591 let instruction = transfer_checked(
3593 &program_id,
3594 account_info.key,
3595 mint_info.key,
3596 account_info.key,
3597 owner_info.key,
3598 &[],
3599 1001,
3600 2,
3601 )
3602 .unwrap();
3603 assert_eq!(
3604 Err(TokenError::InsufficientFunds.into()),
3605 Processor::process(
3606 &instruction.program_id,
3607 &[
3608 account_info.clone(),
3609 mint_info.clone(),
3610 account_info.clone(),
3611 owner_info.clone(),
3612 ],
3613 &instruction.data,
3614 )
3615 );
3616
3617 let instruction = transfer_checked(
3619 &program_id,
3620 account_info.key,
3621 mint_info.key,
3622 account_info.key,
3623 owner_info.key,
3624 &[],
3625 1,
3626 10, )
3628 .unwrap();
3629 assert_eq!(
3630 Err(TokenError::MintDecimalsMismatch.into()),
3631 Processor::process(
3632 &instruction.program_id,
3633 &[
3634 account_info.clone(),
3635 mint_info.clone(),
3636 account_info.clone(),
3637 owner_info.clone(),
3638 ],
3639 &instruction.data,
3640 )
3641 );
3642
3643 let instruction = transfer_checked(
3645 &program_id,
3646 account_info.key,
3647 account3_info.key, account_info.key,
3649 owner_info.key,
3650 &[],
3651 1,
3652 2,
3653 )
3654 .unwrap();
3655 assert_eq!(
3656 Err(TokenError::MintMismatch.into()),
3657 Processor::process(
3658 &instruction.program_id,
3659 &[
3660 account_info.clone(),
3661 account3_info.clone(), account_info.clone(),
3663 owner_info.clone(),
3664 ],
3665 &instruction.data,
3666 )
3667 );
3668
3669 let instruction = approve(
3671 &program_id,
3672 account_info.key,
3673 delegate_info.key,
3674 owner_info.key,
3675 &[],
3676 100,
3677 )
3678 .unwrap();
3679 Processor::process(
3680 &instruction.program_id,
3681 &[
3682 account_info.clone(),
3683 delegate_info.clone(),
3684 owner_info.clone(),
3685 ],
3686 &instruction.data,
3687 )
3688 .unwrap();
3689
3690 #[allow(deprecated)]
3692 let instruction = transfer(
3693 &program_id,
3694 account_info.key,
3695 account_info.key,
3696 delegate_info.key,
3697 &[],
3698 100,
3699 )
3700 .unwrap();
3701 assert_eq!(
3702 Ok(()),
3703 Processor::process(
3704 &instruction.program_id,
3705 &[
3706 account_info.clone(),
3707 account_info.clone(),
3708 delegate_info.clone(),
3709 ],
3710 &instruction.data,
3711 )
3712 );
3713 let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap();
3715 assert_eq!(account.amount, 1000);
3716 assert_eq!(account.delegated_amount, 100);
3717
3718 let instruction = transfer_checked(
3720 &program_id,
3721 account_info.key,
3722 mint_info.key,
3723 account_info.key,
3724 delegate_info.key,
3725 &[],
3726 100,
3727 2,
3728 )
3729 .unwrap();
3730 assert_eq!(
3731 Ok(()),
3732 Processor::process(
3733 &instruction.program_id,
3734 &[
3735 account_info.clone(),
3736 mint_info.clone(),
3737 account_info.clone(),
3738 delegate_info.clone(),
3739 ],
3740 &instruction.data,
3741 )
3742 );
3743 let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap();
3745 assert_eq!(account.amount, 1000);
3746 assert_eq!(account.delegated_amount, 100);
3747
3748 #[allow(deprecated)]
3750 let instruction = transfer(
3751 &program_id,
3752 account_info.key,
3753 account_info.key,
3754 delegate_info.key,
3755 &[],
3756 101,
3757 )
3758 .unwrap();
3759 assert_eq!(
3760 Err(TokenError::InsufficientFunds.into()),
3761 Processor::process(
3762 &instruction.program_id,
3763 &[
3764 account_info.clone(),
3765 account_info.clone(),
3766 delegate_info.clone(),
3767 ],
3768 &instruction.data,
3769 )
3770 );
3771
3772 let instruction = transfer_checked(
3774 &program_id,
3775 account_info.key,
3776 mint_info.key,
3777 account_info.key,
3778 delegate_info.key,
3779 &[],
3780 101,
3781 2,
3782 )
3783 .unwrap();
3784 assert_eq!(
3785 Err(TokenError::InsufficientFunds.into()),
3786 Processor::process(
3787 &instruction.program_id,
3788 &[
3789 account_info.clone(),
3790 mint_info.clone(),
3791 account_info.clone(),
3792 delegate_info.clone(),
3793 ],
3794 &instruction.data,
3795 )
3796 );
3797
3798 #[allow(deprecated)]
3800 let instruction = transfer(
3801 &program_id,
3802 account_info.key,
3803 account_info.key,
3804 owner_info.key,
3805 &[],
3806 1000,
3807 )
3808 .unwrap();
3809 assert_eq!(
3810 Ok(()),
3811 Processor::process(
3812 &instruction.program_id,
3813 &[
3814 account_info.clone(),
3815 account_info.clone(),
3816 owner_info.clone(),
3817 ],
3818 &instruction.data,
3819 )
3820 );
3821 let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap();
3823 assert_eq!(account.amount, 1000);
3824
3825 let instruction = transfer_checked(
3827 &program_id,
3828 account_info.key,
3829 mint_info.key,
3830 account_info.key,
3831 owner_info.key,
3832 &[],
3833 1000,
3834 2,
3835 )
3836 .unwrap();
3837 assert_eq!(
3838 Ok(()),
3839 Processor::process(
3840 &instruction.program_id,
3841 &[
3842 account_info.clone(),
3843 mint_info.clone(),
3844 account_info.clone(),
3845 owner_info.clone(),
3846 ],
3847 &instruction.data,
3848 )
3849 );
3850 let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap();
3852 assert_eq!(account.amount, 1000);
3853 }
3854
3855 #[test]
3856 fn test_mintable_token_with_zero_supply() {
3857 let program_id = crate::id();
3858 let account_key = Pubkey::new_unique();
3859 let mut account_account = SolanaAccount::new(
3860 account_minimum_balance(),
3861 Account::get_packed_len(),
3862 &program_id,
3863 );
3864 let owner_key = Pubkey::new_unique();
3865 let mut owner_account = SolanaAccount::default();
3866 let mint_key = Pubkey::new_unique();
3867 let mut mint_account =
3868 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
3869 let mut rent_sysvar = rent_sysvar();
3870
3871 let decimals = 2;
3873 do_process_instruction(
3874 initialize_mint(&program_id, &mint_key, &owner_key, None, decimals).unwrap(),
3875 vec![&mut mint_account, &mut rent_sysvar],
3876 )
3877 .unwrap();
3878 let mint = Mint::unpack_unchecked(&mint_account.data).unwrap();
3879 assert_eq!(
3880 mint,
3881 Mint {
3882 mint_authority: COption::Some(owner_key),
3883 supply: 0,
3884 decimals,
3885 is_initialized: true,
3886 freeze_authority: COption::None,
3887 }
3888 );
3889
3890 do_process_instruction(
3892 initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
3893 vec![
3894 &mut account_account,
3895 &mut mint_account,
3896 &mut owner_account,
3897 &mut rent_sysvar,
3898 ],
3899 )
3900 .unwrap();
3901
3902 do_process_instruction(
3904 mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 42).unwrap(),
3905 vec![&mut mint_account, &mut account_account, &mut owner_account],
3906 )
3907 .unwrap();
3908 let _ = Mint::unpack(&mint_account.data).unwrap();
3909 let account = Account::unpack_unchecked(&account_account.data).unwrap();
3910 assert_eq!(account.amount, 42);
3911
3912 assert_eq!(
3914 Err(TokenError::MintDecimalsMismatch.into()),
3915 do_process_instruction(
3916 mint_to_checked(
3917 &program_id,
3918 &mint_key,
3919 &account_key,
3920 &owner_key,
3921 &[],
3922 42,
3923 decimals + 1
3924 )
3925 .unwrap(),
3926 vec![&mut mint_account, &mut account_account, &mut owner_account],
3927 )
3928 );
3929
3930 let _ = Mint::unpack(&mint_account.data).unwrap();
3931 let account = Account::unpack_unchecked(&account_account.data).unwrap();
3932 assert_eq!(account.amount, 42);
3933
3934 do_process_instruction(
3936 mint_to_checked(
3937 &program_id,
3938 &mint_key,
3939 &account_key,
3940 &owner_key,
3941 &[],
3942 42,
3943 decimals,
3944 )
3945 .unwrap(),
3946 vec![&mut mint_account, &mut account_account, &mut owner_account],
3947 )
3948 .unwrap();
3949 let _ = Mint::unpack(&mint_account.data).unwrap();
3950 let account = Account::unpack_unchecked(&account_account.data).unwrap();
3951 assert_eq!(account.amount, 84);
3952 }
3953
3954 #[test]
3955 fn test_approve_dups() {
3956 let program_id = crate::id();
3957 let account1_key = Pubkey::new_unique();
3958 let mut account1_account = SolanaAccount::new(
3959 account_minimum_balance(),
3960 Account::get_packed_len(),
3961 &program_id,
3962 );
3963 let account1_info: AccountInfo<'_> = (&account1_key, true, &mut account1_account).into();
3964 let account2_key = Pubkey::new_unique();
3965 let mut account2_account = SolanaAccount::new(
3966 account_minimum_balance(),
3967 Account::get_packed_len(),
3968 &program_id,
3969 );
3970 let account2_info: AccountInfo<'_> = (&account2_key, false, &mut account2_account).into();
3971 let account3_key = Pubkey::new_unique();
3972 let mut account3_account = SolanaAccount::new(
3973 account_minimum_balance(),
3974 Account::get_packed_len(),
3975 &program_id,
3976 );
3977 let account3_info: AccountInfo<'_> = (&account3_key, true, &mut account3_account).into();
3978 let multisig_key = Pubkey::new_unique();
3979 let mut multisig_account = SolanaAccount::new(
3980 multisig_minimum_balance(),
3981 Multisig::get_packed_len(),
3982 &program_id,
3983 );
3984 let multisig_info: AccountInfo<'_> = (&multisig_key, true, &mut multisig_account).into();
3985 let owner_key = Pubkey::new_unique();
3986 let mut owner_account = SolanaAccount::default();
3987 let owner_info: AccountInfo<'_> = (&owner_key, true, &mut owner_account).into();
3988 let mint_key = Pubkey::new_unique();
3989 let mut mint_account =
3990 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
3991 let mint_info: AccountInfo<'_> = (&mint_key, false, &mut mint_account).into();
3992 let rent_key = rent::id();
3993 let mut rent_sysvar = rent_sysvar();
3994 let rent_info: AccountInfo<'_> = (&rent_key, false, &mut rent_sysvar).into();
3995
3996 do_process_instruction_dups(
3998 initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
3999 vec![mint_info.clone(), rent_info.clone()],
4000 )
4001 .unwrap();
4002
4003 do_process_instruction_dups(
4005 initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(),
4006 vec![
4007 account1_info.clone(),
4008 mint_info.clone(),
4009 account1_info.clone(),
4010 rent_info.clone(),
4011 ],
4012 )
4013 .unwrap();
4014
4015 do_process_instruction_dups(
4017 initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(),
4018 vec![
4019 account2_info.clone(),
4020 mint_info.clone(),
4021 owner_info.clone(),
4022 rent_info.clone(),
4023 ],
4024 )
4025 .unwrap();
4026
4027 do_process_instruction_dups(
4029 mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(),
4030 vec![mint_info.clone(), account1_info.clone(), owner_info.clone()],
4031 )
4032 .unwrap();
4033
4034 do_process_instruction_dups(
4036 approve(
4037 &program_id,
4038 &account1_key,
4039 &account2_key,
4040 &account1_key,
4041 &[],
4042 500,
4043 )
4044 .unwrap(),
4045 vec![
4046 account1_info.clone(),
4047 account2_info.clone(),
4048 account1_info.clone(),
4049 ],
4050 )
4051 .unwrap();
4052
4053 do_process_instruction_dups(
4055 approve_checked(
4056 &program_id,
4057 &account1_key,
4058 &mint_key,
4059 &account2_key,
4060 &account1_key,
4061 &[],
4062 500,
4063 2,
4064 )
4065 .unwrap(),
4066 vec![
4067 account1_info.clone(),
4068 mint_info.clone(),
4069 account2_info.clone(),
4070 account1_info.clone(),
4071 ],
4072 )
4073 .unwrap();
4074
4075 do_process_instruction_dups(
4077 revoke(&program_id, &account1_key, &account1_key, &[]).unwrap(),
4078 vec![account1_info.clone(), account1_info.clone()],
4079 )
4080 .unwrap();
4081
4082 do_process_instruction_dups(
4084 initialize_multisig(&program_id, &multisig_key, &[&account3_key], 1).unwrap(),
4085 vec![
4086 multisig_info.clone(),
4087 rent_info.clone(),
4088 account3_info.clone(),
4089 ],
4090 )
4091 .unwrap();
4092
4093 do_process_instruction_dups(
4094 initialize_account(&program_id, &account3_key, &mint_key, &multisig_key).unwrap(),
4095 vec![
4096 account3_info.clone(),
4097 mint_info.clone(),
4098 multisig_info.clone(),
4099 rent_info.clone(),
4100 ],
4101 )
4102 .unwrap();
4103
4104 do_process_instruction_dups(
4105 mint_to(&program_id, &mint_key, &account3_key, &owner_key, &[], 1000).unwrap(),
4106 vec![mint_info.clone(), account3_info.clone(), owner_info.clone()],
4107 )
4108 .unwrap();
4109
4110 do_process_instruction_dups(
4112 approve(
4113 &program_id,
4114 &account3_key,
4115 &account2_key,
4116 &multisig_key,
4117 &[&account3_key],
4118 500,
4119 )
4120 .unwrap(),
4121 vec![
4122 account3_info.clone(),
4123 account2_info.clone(),
4124 multisig_info.clone(),
4125 account3_info.clone(),
4126 ],
4127 )
4128 .unwrap();
4129
4130 do_process_instruction_dups(
4132 approve_checked(
4133 &program_id,
4134 &account3_key,
4135 &mint_key,
4136 &account2_key,
4137 &multisig_key,
4138 &[&account3_key],
4139 500,
4140 2,
4141 )
4142 .unwrap(),
4143 vec![
4144 account3_info.clone(),
4145 mint_info.clone(),
4146 account2_info.clone(),
4147 multisig_info.clone(),
4148 account3_info.clone(),
4149 ],
4150 )
4151 .unwrap();
4152
4153 do_process_instruction_dups(
4155 revoke(&program_id, &account3_key, &multisig_key, &[&account3_key]).unwrap(),
4156 vec![
4157 account3_info.clone(),
4158 multisig_info.clone(),
4159 account3_info.clone(),
4160 ],
4161 )
4162 .unwrap();
4163
4164 do_process_instruction_dups(
4166 approve_checked(
4167 &program_id,
4168 &account2_key,
4169 &mint_key,
4170 &account2_key,
4171 &owner_key,
4172 &[],
4173 500,
4174 2,
4175 )
4176 .unwrap(),
4177 vec![
4178 account2_info.clone(),
4179 mint_info.clone(),
4180 account2_info.clone(),
4181 owner_info.clone(),
4182 ],
4183 )
4184 .unwrap();
4185
4186 let account2_info: AccountInfo<'_> = (&account2_key, true, &mut account2_account).into();
4188 do_process_instruction_dups(
4189 revoke(&program_id, &account2_key, &account2_key, &[]).unwrap(),
4190 vec![account2_info.clone(), account2_info.clone()],
4191 )
4192 .unwrap();
4193 }
4194
4195 #[test]
4196 fn test_approve() {
4197 let program_id = crate::id();
4198 let account_key = Pubkey::new_unique();
4199 let mut account_account = SolanaAccount::new(
4200 account_minimum_balance(),
4201 Account::get_packed_len(),
4202 &program_id,
4203 );
4204 let account2_key = Pubkey::new_unique();
4205 let mut account2_account = SolanaAccount::new(
4206 account_minimum_balance(),
4207 Account::get_packed_len(),
4208 &program_id,
4209 );
4210 let delegate_key = Pubkey::new_unique();
4211 let mut delegate_account = SolanaAccount::default();
4212 let owner_key = Pubkey::new_unique();
4213 let mut owner_account = SolanaAccount::default();
4214 let owner2_key = Pubkey::new_unique();
4215 let mut owner2_account = SolanaAccount::default();
4216 let mint_key = Pubkey::new_unique();
4217 let mut mint_account =
4218 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
4219 let mut rent_sysvar = rent_sysvar();
4220
4221 do_process_instruction(
4223 initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
4224 vec![&mut mint_account, &mut rent_sysvar],
4225 )
4226 .unwrap();
4227
4228 do_process_instruction(
4230 initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
4231 vec![
4232 &mut account_account,
4233 &mut mint_account,
4234 &mut owner_account,
4235 &mut rent_sysvar,
4236 ],
4237 )
4238 .unwrap();
4239
4240 do_process_instruction(
4242 initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(),
4243 vec![
4244 &mut account2_account,
4245 &mut mint_account,
4246 &mut owner_account,
4247 &mut rent_sysvar,
4248 ],
4249 )
4250 .unwrap();
4251
4252 do_process_instruction(
4254 mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(),
4255 vec![&mut mint_account, &mut account_account, &mut owner_account],
4256 )
4257 .unwrap();
4258
4259 let mut instruction = approve(
4261 &program_id,
4262 &account_key,
4263 &delegate_key,
4264 &owner_key,
4265 &[],
4266 100,
4267 )
4268 .unwrap();
4269 instruction.accounts[2].is_signer = false;
4270 assert_eq!(
4271 Err(ProgramError::MissingRequiredSignature),
4272 do_process_instruction(
4273 instruction,
4274 vec![
4275 &mut account_account,
4276 &mut delegate_account,
4277 &mut owner_account,
4278 ],
4279 )
4280 );
4281
4282 assert_eq!(
4284 Err(TokenError::OwnerMismatch.into()),
4285 do_process_instruction(
4286 approve(
4287 &program_id,
4288 &account_key,
4289 &delegate_key,
4290 &owner2_key,
4291 &[],
4292 100
4293 )
4294 .unwrap(),
4295 vec![
4296 &mut account_account,
4297 &mut delegate_account,
4298 &mut owner2_account,
4299 ],
4300 )
4301 );
4302
4303 do_process_instruction(
4305 approve(
4306 &program_id,
4307 &account_key,
4308 &delegate_key,
4309 &owner_key,
4310 &[],
4311 100,
4312 )
4313 .unwrap(),
4314 vec![
4315 &mut account_account,
4316 &mut delegate_account,
4317 &mut owner_account,
4318 ],
4319 )
4320 .unwrap();
4321
4322 assert_eq!(
4324 Err(TokenError::MintDecimalsMismatch.into()),
4325 do_process_instruction(
4326 approve_checked(
4327 &program_id,
4328 &account_key,
4329 &mint_key,
4330 &delegate_key,
4331 &owner_key,
4332 &[],
4333 100,
4334 0 )
4336 .unwrap(),
4337 vec![
4338 &mut account_account,
4339 &mut mint_account,
4340 &mut delegate_account,
4341 &mut owner_account,
4342 ],
4343 )
4344 );
4345
4346 assert_eq!(
4348 Err(TokenError::MintMismatch.into()),
4349 do_process_instruction(
4350 approve_checked(
4351 &program_id,
4352 &account_key,
4353 &account2_key, &delegate_key,
4355 &owner_key,
4356 &[],
4357 100,
4358 0
4359 )
4360 .unwrap(),
4361 vec![
4362 &mut account_account,
4363 &mut account2_account, &mut delegate_account,
4365 &mut owner_account,
4366 ],
4367 )
4368 );
4369
4370 do_process_instruction(
4372 approve_checked(
4373 &program_id,
4374 &account_key,
4375 &mint_key,
4376 &delegate_key,
4377 &owner_key,
4378 &[],
4379 100,
4380 2,
4381 )
4382 .unwrap(),
4383 vec![
4384 &mut account_account,
4385 &mut mint_account,
4386 &mut delegate_account,
4387 &mut owner_account,
4388 ],
4389 )
4390 .unwrap();
4391
4392 do_process_instruction(
4394 revoke(&program_id, &account_key, &owner_key, &[]).unwrap(),
4395 vec![&mut account_account, &mut owner_account],
4396 )
4397 .unwrap();
4398
4399 do_process_instruction(
4401 approve_checked(
4402 &program_id,
4403 &account_key,
4404 &mint_key,
4405 &delegate_key,
4406 &owner_key,
4407 &[],
4408 100,
4409 2,
4410 )
4411 .unwrap(),
4412 vec![
4413 &mut account_account,
4414 &mut mint_account,
4415 &mut delegate_account,
4416 &mut owner_account,
4417 ],
4418 )
4419 .unwrap();
4420
4421 do_process_instruction(
4423 revoke(&program_id, &account_key, &delegate_key, &[]).unwrap(),
4424 vec![&mut account_account, &mut delegate_account],
4425 )
4426 .unwrap();
4427
4428 assert_eq!(
4430 Err(TokenError::OwnerMismatch.into()),
4431 do_process_instruction(
4432 revoke(&program_id, &account_key, &delegate_key, &[]).unwrap(),
4433 vec![&mut account_account, &mut delegate_account],
4434 )
4435 );
4436 }
4437
4438 #[test]
4439 fn test_set_authority_dups() {
4440 let program_id = crate::id();
4441 let account1_key = Pubkey::new_unique();
4442 let mut account1_account = SolanaAccount::new(
4443 account_minimum_balance(),
4444 Account::get_packed_len(),
4445 &program_id,
4446 );
4447 let account1_info: AccountInfo<'_> = (&account1_key, true, &mut account1_account).into();
4448 let owner_key = Pubkey::new_unique();
4449 let mint_key = Pubkey::new_unique();
4450 let mut mint_account =
4451 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
4452 let mint_info: AccountInfo<'_> = (&mint_key, true, &mut mint_account).into();
4453 let rent_key = rent::id();
4454 let mut rent_sysvar = rent_sysvar();
4455 let rent_info: AccountInfo<'_> = (&rent_key, false, &mut rent_sysvar).into();
4456
4457 do_process_instruction_dups(
4459 initialize_mint(&program_id, &mint_key, &mint_key, Some(&mint_key), 2).unwrap(),
4460 vec![mint_info.clone(), rent_info.clone()],
4461 )
4462 .unwrap();
4463
4464 do_process_instruction_dups(
4466 initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(),
4467 vec![
4468 account1_info.clone(),
4469 mint_info.clone(),
4470 account1_info.clone(),
4471 rent_info.clone(),
4472 ],
4473 )
4474 .unwrap();
4475
4476 do_process_instruction_dups(
4478 set_authority(
4479 &program_id,
4480 &mint_key,
4481 Some(&owner_key),
4482 AuthorityType::MintTokens,
4483 &mint_key,
4484 &[],
4485 )
4486 .unwrap(),
4487 vec![mint_info.clone(), mint_info.clone()],
4488 )
4489 .unwrap();
4490
4491 do_process_instruction_dups(
4493 set_authority(
4494 &program_id,
4495 &mint_key,
4496 Some(&owner_key),
4497 AuthorityType::FreezeAccount,
4498 &mint_key,
4499 &[],
4500 )
4501 .unwrap(),
4502 vec![mint_info.clone(), mint_info.clone()],
4503 )
4504 .unwrap();
4505
4506 do_process_instruction_dups(
4508 set_authority(
4509 &program_id,
4510 &account1_key,
4511 Some(&owner_key),
4512 AuthorityType::AccountOwner,
4513 &account1_key,
4514 &[],
4515 )
4516 .unwrap(),
4517 vec![account1_info.clone(), account1_info.clone()],
4518 )
4519 .unwrap();
4520
4521 let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap();
4523 account.close_authority = COption::Some(account1_key);
4524 Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap();
4525
4526 do_process_instruction_dups(
4527 set_authority(
4528 &program_id,
4529 &account1_key,
4530 Some(&owner_key),
4531 AuthorityType::CloseAccount,
4532 &account1_key,
4533 &[],
4534 )
4535 .unwrap(),
4536 vec![account1_info.clone(), account1_info.clone()],
4537 )
4538 .unwrap();
4539 }
4540
4541 #[test]
4542 fn test_set_authority() {
4543 let program_id = crate::id();
4544 let account_key = Pubkey::new_unique();
4545 let mut account_account = SolanaAccount::new(
4546 account_minimum_balance(),
4547 Account::get_packed_len(),
4548 &program_id,
4549 );
4550 let account2_key = Pubkey::new_unique();
4551 let mut account2_account = SolanaAccount::new(
4552 account_minimum_balance(),
4553 Account::get_packed_len(),
4554 &program_id,
4555 );
4556 let owner_key = Pubkey::new_unique();
4557 let mut owner_account = SolanaAccount::default();
4558 let owner2_key = Pubkey::new_unique();
4559 let mut owner2_account = SolanaAccount::default();
4560 let owner3_key = Pubkey::new_unique();
4561 let mut owner3_account = SolanaAccount::default();
4562 let mint_key = Pubkey::new_unique();
4563 let mut mint_account =
4564 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
4565 let mint2_key = Pubkey::new_unique();
4566 let mut mint2_account =
4567 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
4568 let mut rent_sysvar = rent_sysvar();
4569
4570 do_process_instruction(
4572 initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
4573 vec![&mut mint_account, &mut rent_sysvar],
4574 )
4575 .unwrap();
4576
4577 do_process_instruction(
4579 initialize_mint(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(),
4580 vec![&mut mint2_account, &mut rent_sysvar],
4581 )
4582 .unwrap();
4583
4584 assert_eq!(
4586 Err(ProgramError::InvalidAccountData),
4587 do_process_instruction(
4588 set_authority(
4589 &program_id,
4590 &account_key,
4591 Some(&owner2_key),
4592 AuthorityType::AccountOwner,
4593 &owner_key,
4594 &[]
4595 )
4596 .unwrap(),
4597 vec![&mut account_account, &mut owner_account],
4598 )
4599 );
4600
4601 do_process_instruction(
4603 initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
4604 vec![
4605 &mut account_account,
4606 &mut mint_account,
4607 &mut owner_account,
4608 &mut rent_sysvar,
4609 ],
4610 )
4611 .unwrap();
4612
4613 do_process_instruction(
4615 initialize_account(&program_id, &account2_key, &mint2_key, &owner_key).unwrap(),
4616 vec![
4617 &mut account2_account,
4618 &mut mint2_account,
4619 &mut owner_account,
4620 &mut rent_sysvar,
4621 ],
4622 )
4623 .unwrap();
4624
4625 assert_eq!(
4627 Err(TokenError::OwnerMismatch.into()),
4628 do_process_instruction(
4629 set_authority(
4630 &program_id,
4631 &account_key,
4632 Some(&owner_key),
4633 AuthorityType::AccountOwner,
4634 &owner2_key,
4635 &[]
4636 )
4637 .unwrap(),
4638 vec![&mut account_account, &mut owner2_account],
4639 )
4640 );
4641
4642 let mut instruction = set_authority(
4644 &program_id,
4645 &account_key,
4646 Some(&owner2_key),
4647 AuthorityType::AccountOwner,
4648 &owner_key,
4649 &[],
4650 )
4651 .unwrap();
4652 instruction.accounts[1].is_signer = false;
4653 assert_eq!(
4654 Err(ProgramError::MissingRequiredSignature),
4655 do_process_instruction(instruction, vec![&mut account_account, &mut owner_account,],)
4656 );
4657
4658 assert_eq!(
4660 Err(TokenError::AuthorityTypeNotSupported.into()),
4661 do_process_instruction(
4662 set_authority(
4663 &program_id,
4664 &account_key,
4665 Some(&owner2_key),
4666 AuthorityType::FreezeAccount,
4667 &owner_key,
4668 &[],
4669 )
4670 .unwrap(),
4671 vec![&mut account_account, &mut owner_account],
4672 )
4673 );
4674
4675 assert_eq!(
4677 Err(TokenError::InvalidInstruction.into()),
4678 do_process_instruction(
4679 set_authority(
4680 &program_id,
4681 &account_key,
4682 None,
4683 AuthorityType::AccountOwner,
4684 &owner_key,
4685 &[],
4686 )
4687 .unwrap(),
4688 vec![&mut account_account, &mut owner_account],
4689 )
4690 );
4691
4692 do_process_instruction(
4694 approve(
4695 &program_id,
4696 &account_key,
4697 &owner2_key,
4698 &owner_key,
4699 &[],
4700 u64::MAX,
4701 )
4702 .unwrap(),
4703 vec![
4704 &mut account_account,
4705 &mut owner2_account,
4706 &mut owner_account,
4707 ],
4708 )
4709 .unwrap();
4710 let account = Account::unpack_unchecked(&account_account.data).unwrap();
4711 assert_eq!(account.delegate, COption::Some(owner2_key));
4712 assert_eq!(account.delegated_amount, u64::MAX);
4713
4714 do_process_instruction(
4716 set_authority(
4717 &program_id,
4718 &account_key,
4719 Some(&owner3_key),
4720 AuthorityType::AccountOwner,
4721 &owner_key,
4722 &[],
4723 )
4724 .unwrap(),
4725 vec![&mut account_account, &mut owner_account],
4726 )
4727 .unwrap();
4728
4729 let account = Account::unpack_unchecked(&account_account.data).unwrap();
4731 assert_eq!(account.delegate, COption::None);
4732 assert_eq!(account.delegated_amount, 0);
4733
4734 do_process_instruction(
4736 set_authority(
4737 &program_id,
4738 &account_key,
4739 Some(&owner2_key),
4740 AuthorityType::AccountOwner,
4741 &owner3_key,
4742 &[],
4743 )
4744 .unwrap(),
4745 vec![&mut account_account, &mut owner3_account],
4746 )
4747 .unwrap();
4748
4749 do_process_instruction(
4751 set_authority(
4752 &program_id,
4753 &account_key,
4754 Some(&owner2_key),
4755 AuthorityType::CloseAccount,
4756 &owner2_key,
4757 &[],
4758 )
4759 .unwrap(),
4760 vec![&mut account_account, &mut owner2_account],
4761 )
4762 .unwrap();
4763
4764 do_process_instruction(
4766 set_authority(
4767 &program_id,
4768 &account_key,
4769 None,
4770 AuthorityType::CloseAccount,
4771 &owner2_key,
4772 &[],
4773 )
4774 .unwrap(),
4775 vec![&mut account_account, &mut owner2_account],
4776 )
4777 .unwrap();
4778
4779 assert_eq!(
4781 Err(TokenError::OwnerMismatch.into()),
4782 do_process_instruction(
4783 set_authority(
4784 &program_id,
4785 &mint_key,
4786 Some(&owner3_key),
4787 AuthorityType::MintTokens,
4788 &owner2_key,
4789 &[]
4790 )
4791 .unwrap(),
4792 vec![&mut mint_account, &mut owner2_account],
4793 )
4794 );
4795
4796 let mut instruction = set_authority(
4798 &program_id,
4799 &mint_key,
4800 Some(&owner2_key),
4801 AuthorityType::MintTokens,
4802 &owner_key,
4803 &[],
4804 )
4805 .unwrap();
4806 instruction.accounts[1].is_signer = false;
4807 assert_eq!(
4808 Err(ProgramError::MissingRequiredSignature),
4809 do_process_instruction(instruction, vec![&mut mint_account, &mut owner_account],)
4810 );
4811
4812 assert_eq!(
4814 Err(TokenError::MintCannotFreeze.into()),
4815 do_process_instruction(
4816 set_authority(
4817 &program_id,
4818 &mint_key,
4819 Some(&owner2_key),
4820 AuthorityType::FreezeAccount,
4821 &owner_key,
4822 &[],
4823 )
4824 .unwrap(),
4825 vec![&mut mint_account, &mut owner_account],
4826 )
4827 );
4828
4829 do_process_instruction(
4831 set_authority(
4832 &program_id,
4833 &mint_key,
4834 Some(&owner2_key),
4835 AuthorityType::MintTokens,
4836 &owner_key,
4837 &[],
4838 )
4839 .unwrap(),
4840 vec![&mut mint_account, &mut owner_account],
4841 )
4842 .unwrap();
4843
4844 do_process_instruction(
4846 set_authority(
4847 &program_id,
4848 &mint_key,
4849 None,
4850 AuthorityType::MintTokens,
4851 &owner2_key,
4852 &[],
4853 )
4854 .unwrap(),
4855 vec![&mut mint_account, &mut owner2_account],
4856 )
4857 .unwrap();
4858
4859 assert_eq!(
4861 Err(TokenError::FixedSupply.into()),
4862 do_process_instruction(
4863 set_authority(
4864 &program_id,
4865 &mint2_key,
4866 Some(&owner2_key),
4867 AuthorityType::MintTokens,
4868 &owner_key,
4869 &[]
4870 )
4871 .unwrap(),
4872 vec![&mut mint_account, &mut owner_account],
4873 )
4874 );
4875
4876 do_process_instruction(
4878 set_authority(
4879 &program_id,
4880 &mint2_key,
4881 Some(&owner2_key),
4882 AuthorityType::FreezeAccount,
4883 &owner_key,
4884 &[],
4885 )
4886 .unwrap(),
4887 vec![&mut mint2_account, &mut owner_account],
4888 )
4889 .unwrap();
4890
4891 do_process_instruction(
4893 set_authority(
4894 &program_id,
4895 &mint2_key,
4896 None,
4897 AuthorityType::FreezeAccount,
4898 &owner2_key,
4899 &[],
4900 )
4901 .unwrap(),
4902 vec![&mut mint2_account, &mut owner2_account],
4903 )
4904 .unwrap();
4905
4906 assert_eq!(
4907 Err(TokenError::MintCannotFreeze.into()),
4908 do_process_instruction(
4909 set_authority(
4910 &program_id,
4911 &mint2_key,
4912 Some(&owner2_key),
4913 AuthorityType::FreezeAccount,
4914 &owner_key,
4915 &[],
4916 )
4917 .unwrap(),
4918 vec![&mut mint2_account, &mut owner2_account],
4919 )
4920 );
4921 }
4922
4923 #[test]
4924 fn test_set_authority_with_immutable_owner_extension() {
4925 let program_id = crate::id();
4926 let account_key = Pubkey::new_unique();
4927
4928 let account_len =
4929 ExtensionType::try_calculate_account_len::<Account>(&[ExtensionType::ImmutableOwner])
4930 .unwrap();
4931 let mut account_account = SolanaAccount::new(
4932 Rent::default().minimum_balance(account_len),
4933 account_len,
4934 &program_id,
4935 );
4936 let owner_key = Pubkey::new_unique();
4937 let mut owner_account = SolanaAccount::default();
4938 let owner2_key = Pubkey::new_unique();
4939
4940 let mint_key = Pubkey::new_unique();
4941 let mut mint_account =
4942 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
4943 let mut rent_sysvar = rent_sysvar();
4944
4945 assert_eq!(
4947 Ok(()),
4948 do_process_instruction(
4949 initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
4950 vec![&mut mint_account, &mut rent_sysvar],
4951 )
4952 );
4953
4954 assert_eq!(
4956 Ok(()),
4957 do_process_instruction(
4958 initialize_immutable_owner(&program_id, &account_key).unwrap(),
4959 vec![&mut account_account],
4960 )
4961 );
4962 assert_eq!(
4963 Ok(()),
4964 do_process_instruction(
4965 initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
4966 vec![
4967 &mut account_account,
4968 &mut mint_account,
4969 &mut owner_account,
4970 &mut rent_sysvar,
4971 ],
4972 )
4973 );
4974
4975 assert_eq!(
4977 Err(TokenError::ImmutableOwner.into()),
4978 do_process_instruction(
4979 set_authority(
4980 &program_id,
4981 &account_key,
4982 Some(&owner2_key),
4983 AuthorityType::AccountOwner,
4984 &owner_key,
4985 &[],
4986 )
4987 .unwrap(),
4988 vec![&mut account_account, &mut owner_account],
4989 )
4990 );
4991 }
4992
4993 #[test]
4994 fn test_mint_to_dups() {
4995 let program_id = crate::id();
4996 let account1_key = Pubkey::new_unique();
4997 let mut account1_account = SolanaAccount::new(
4998 account_minimum_balance(),
4999 Account::get_packed_len(),
5000 &program_id,
5001 );
5002 let account1_info: AccountInfo<'_> = (&account1_key, true, &mut account1_account).into();
5003 let owner_key = Pubkey::new_unique();
5004 let mut owner_account = SolanaAccount::default();
5005 let owner_info: AccountInfo<'_> = (&owner_key, true, &mut owner_account).into();
5006 let mint_key = Pubkey::new_unique();
5007 let mut mint_account =
5008 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
5009 let mint_info: AccountInfo<'_> = (&mint_key, true, &mut mint_account).into();
5010 let rent_key = rent::id();
5011 let mut rent_sysvar = rent_sysvar();
5012 let rent_info: AccountInfo<'_> = (&rent_key, false, &mut rent_sysvar).into();
5013
5014 do_process_instruction_dups(
5016 initialize_mint(&program_id, &mint_key, &mint_key, None, 2).unwrap(),
5017 vec![mint_info.clone(), rent_info.clone()],
5018 )
5019 .unwrap();
5020
5021 do_process_instruction_dups(
5023 initialize_account(&program_id, &account1_key, &mint_key, &owner_key).unwrap(),
5024 vec![
5025 account1_info.clone(),
5026 mint_info.clone(),
5027 owner_info.clone(),
5028 rent_info.clone(),
5029 ],
5030 )
5031 .unwrap();
5032
5033 do_process_instruction_dups(
5035 mint_to(&program_id, &mint_key, &account1_key, &mint_key, &[], 42).unwrap(),
5036 vec![mint_info.clone(), account1_info.clone(), mint_info.clone()],
5037 )
5038 .unwrap();
5039
5040 do_process_instruction_dups(
5042 mint_to_checked(&program_id, &mint_key, &account1_key, &mint_key, &[], 42, 2).unwrap(),
5043 vec![mint_info.clone(), account1_info.clone(), mint_info.clone()],
5044 )
5045 .unwrap();
5046
5047 let mut mint = Mint::unpack_unchecked(&mint_info.data.borrow()).unwrap();
5049 mint.mint_authority = COption::Some(account1_key);
5050 Mint::pack(mint, &mut mint_info.data.borrow_mut()).unwrap();
5051 do_process_instruction_dups(
5052 mint_to(
5053 &program_id,
5054 &mint_key,
5055 &account1_key,
5056 &account1_key,
5057 &[],
5058 42,
5059 )
5060 .unwrap(),
5061 vec![
5062 mint_info.clone(),
5063 account1_info.clone(),
5064 account1_info.clone(),
5065 ],
5066 )
5067 .unwrap();
5068
5069 do_process_instruction_dups(
5071 mint_to(
5072 &program_id,
5073 &mint_key,
5074 &account1_key,
5075 &account1_key,
5076 &[],
5077 42,
5078 )
5079 .unwrap(),
5080 vec![
5081 mint_info.clone(),
5082 account1_info.clone(),
5083 account1_info.clone(),
5084 ],
5085 )
5086 .unwrap();
5087 }
5088
5089 #[test]
5090 fn test_mint_to() {
5091 let program_id = crate::id();
5092 let account_key = Pubkey::new_unique();
5093 let mut account_account = SolanaAccount::new(
5094 account_minimum_balance(),
5095 Account::get_packed_len(),
5096 &program_id,
5097 );
5098 let account2_key = Pubkey::new_unique();
5099 let mut account2_account = SolanaAccount::new(
5100 account_minimum_balance(),
5101 Account::get_packed_len(),
5102 &program_id,
5103 );
5104 let account3_key = Pubkey::new_unique();
5105 let mut account3_account = SolanaAccount::new(
5106 account_minimum_balance(),
5107 Account::get_packed_len(),
5108 &program_id,
5109 );
5110 let mismatch_key = Pubkey::new_unique();
5111 let mut mismatch_account = SolanaAccount::new(
5112 account_minimum_balance(),
5113 Account::get_packed_len(),
5114 &program_id,
5115 );
5116 let owner_key = Pubkey::new_unique();
5117 let mut owner_account = SolanaAccount::default();
5118 let owner2_key = Pubkey::new_unique();
5119 let mut owner2_account = SolanaAccount::default();
5120 let mint_key = Pubkey::new_unique();
5121 let mut mint_account =
5122 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
5123 let mint2_key = Pubkey::new_unique();
5124 let uninitialized_key = Pubkey::new_unique();
5125 let mut uninitialized_account = SolanaAccount::new(
5126 account_minimum_balance(),
5127 Account::get_packed_len(),
5128 &program_id,
5129 );
5130 let mut rent_sysvar = rent_sysvar();
5131
5132 do_process_instruction(
5134 initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
5135 vec![&mut mint_account, &mut rent_sysvar],
5136 )
5137 .unwrap();
5138
5139 do_process_instruction(
5141 initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
5142 vec![
5143 &mut account_account,
5144 &mut mint_account,
5145 &mut owner_account,
5146 &mut rent_sysvar,
5147 ],
5148 )
5149 .unwrap();
5150
5151 do_process_instruction(
5153 initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(),
5154 vec![
5155 &mut account2_account,
5156 &mut mint_account,
5157 &mut owner_account,
5158 &mut rent_sysvar,
5159 ],
5160 )
5161 .unwrap();
5162
5163 do_process_instruction(
5165 initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(),
5166 vec![
5167 &mut account3_account,
5168 &mut mint_account,
5169 &mut owner_account,
5170 &mut rent_sysvar,
5171 ],
5172 )
5173 .unwrap();
5174
5175 do_process_instruction(
5177 initialize_account(&program_id, &mismatch_key, &mint_key, &owner_key).unwrap(),
5178 vec![
5179 &mut mismatch_account,
5180 &mut mint_account,
5181 &mut owner_account,
5182 &mut rent_sysvar,
5183 ],
5184 )
5185 .unwrap();
5186 let mut account = Account::unpack_unchecked(&mismatch_account.data).unwrap();
5187 account.mint = mint2_key;
5188 Account::pack(account, &mut mismatch_account.data).unwrap();
5189
5190 do_process_instruction(
5192 mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 42).unwrap(),
5193 vec![&mut mint_account, &mut account_account, &mut owner_account],
5194 )
5195 .unwrap();
5196
5197 let mint = Mint::unpack_unchecked(&mint_account.data).unwrap();
5198 assert_eq!(mint.supply, 42);
5199 let account = Account::unpack_unchecked(&account_account.data).unwrap();
5200 assert_eq!(account.amount, 42);
5201
5202 do_process_instruction(
5204 mint_to(&program_id, &mint_key, &account2_key, &owner_key, &[], 42).unwrap(),
5205 vec![&mut mint_account, &mut account2_account, &mut owner_account],
5206 )
5207 .unwrap();
5208
5209 let mint = Mint::unpack_unchecked(&mint_account.data).unwrap();
5210 assert_eq!(mint.supply, 84);
5211 let account = Account::unpack_unchecked(&account2_account.data).unwrap();
5212 assert_eq!(account.amount, 42);
5213
5214 let mut instruction =
5216 mint_to(&program_id, &mint_key, &account2_key, &owner_key, &[], 42).unwrap();
5217 instruction.accounts[2].is_signer = false;
5218 assert_eq!(
5219 Err(ProgramError::MissingRequiredSignature),
5220 do_process_instruction(
5221 instruction,
5222 vec![&mut mint_account, &mut account2_account, &mut owner_account],
5223 )
5224 );
5225
5226 assert_eq!(
5228 Err(TokenError::MintMismatch.into()),
5229 do_process_instruction(
5230 mint_to(&program_id, &mint_key, &mismatch_key, &owner_key, &[], 42).unwrap(),
5231 vec![&mut mint_account, &mut mismatch_account, &mut owner_account],
5232 )
5233 );
5234
5235 assert_eq!(
5237 Err(TokenError::OwnerMismatch.into()),
5238 do_process_instruction(
5239 mint_to(&program_id, &mint_key, &account2_key, &owner2_key, &[], 42).unwrap(),
5240 vec![
5241 &mut mint_account,
5242 &mut account2_account,
5243 &mut owner2_account,
5244 ],
5245 )
5246 );
5247
5248 let not_program_id = Pubkey::new_unique();
5250 mint_account.owner = not_program_id;
5251 assert_eq!(
5252 Err(ProgramError::IncorrectProgramId),
5253 do_process_instruction(
5254 mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 0).unwrap(),
5255 vec![&mut mint_account, &mut account_account, &mut owner_account],
5256 )
5257 );
5258 mint_account.owner = program_id;
5259
5260 let not_program_id = Pubkey::new_unique();
5262 account_account.owner = not_program_id;
5263 assert_eq!(
5264 Err(ProgramError::IncorrectProgramId),
5265 do_process_instruction(
5266 mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 0).unwrap(),
5267 vec![&mut mint_account, &mut account_account, &mut owner_account],
5268 )
5269 );
5270 account_account.owner = program_id;
5271
5272 assert_eq!(
5274 Err(ProgramError::UninitializedAccount),
5275 do_process_instruction(
5276 mint_to(
5277 &program_id,
5278 &mint_key,
5279 &uninitialized_key,
5280 &owner_key,
5281 &[],
5282 42
5283 )
5284 .unwrap(),
5285 vec![
5286 &mut mint_account,
5287 &mut uninitialized_account,
5288 &mut owner_account,
5289 ],
5290 )
5291 );
5292
5293 do_process_instruction(
5295 set_authority(
5296 &program_id,
5297 &mint_key,
5298 None,
5299 AuthorityType::MintTokens,
5300 &owner_key,
5301 &[],
5302 )
5303 .unwrap(),
5304 vec![&mut mint_account, &mut owner_account],
5305 )
5306 .unwrap();
5307 assert_eq!(
5308 Err(TokenError::FixedSupply.into()),
5309 do_process_instruction(
5310 mint_to(&program_id, &mint_key, &account2_key, &owner_key, &[], 42).unwrap(),
5311 vec![&mut mint_account, &mut account2_account, &mut owner_account],
5312 )
5313 );
5314 }
5315
5316 #[test]
5317 fn test_burn_dups() {
5318 let program_id = crate::id();
5319 let account1_key = Pubkey::new_unique();
5320 let mut account1_account = SolanaAccount::new(
5321 account_minimum_balance(),
5322 Account::get_packed_len(),
5323 &program_id,
5324 );
5325 let account1_info: AccountInfo<'_> = (&account1_key, true, &mut account1_account).into();
5326 let owner_key = Pubkey::new_unique();
5327 let mut owner_account = SolanaAccount::default();
5328 let owner_info: AccountInfo<'_> = (&owner_key, true, &mut owner_account).into();
5329 let mint_key = Pubkey::new_unique();
5330 let mut mint_account =
5331 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
5332 let mint_info: AccountInfo<'_> = (&mint_key, true, &mut mint_account).into();
5333 let rent_key = rent::id();
5334 let mut rent_sysvar = rent_sysvar();
5335 let rent_info: AccountInfo<'_> = (&rent_key, false, &mut rent_sysvar).into();
5336
5337 do_process_instruction_dups(
5339 initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
5340 vec![mint_info.clone(), rent_info.clone()],
5341 )
5342 .unwrap();
5343
5344 do_process_instruction_dups(
5346 initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(),
5347 vec![
5348 account1_info.clone(),
5349 mint_info.clone(),
5350 account1_info.clone(),
5351 rent_info.clone(),
5352 ],
5353 )
5354 .unwrap();
5355
5356 do_process_instruction_dups(
5358 mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(),
5359 vec![mint_info.clone(), account1_info.clone(), owner_info.clone()],
5360 )
5361 .unwrap();
5362
5363 do_process_instruction_dups(
5365 burn(
5366 &program_id,
5367 &mint_key,
5368 &account1_key,
5369 &account1_key,
5370 &[],
5371 500,
5372 )
5373 .unwrap(),
5374 vec![
5375 account1_info.clone(),
5376 mint_info.clone(),
5377 account1_info.clone(),
5378 ],
5379 )
5380 .unwrap();
5381
5382 do_process_instruction_dups(
5384 burn_checked(
5385 &program_id,
5386 &account1_key,
5387 &mint_key,
5388 &account1_key,
5389 &[],
5390 500,
5391 2,
5392 )
5393 .unwrap(),
5394 vec![
5395 account1_info.clone(),
5396 mint_info.clone(),
5397 account1_info.clone(),
5398 ],
5399 )
5400 .unwrap();
5401
5402 do_process_instruction_dups(
5404 mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(),
5405 vec![mint_info.clone(), account1_info.clone(), owner_info.clone()],
5406 )
5407 .unwrap();
5408 let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap();
5409 account.owner = mint_key;
5410 Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap();
5411 do_process_instruction_dups(
5412 burn(&program_id, &account1_key, &mint_key, &mint_key, &[], 500).unwrap(),
5413 vec![account1_info.clone(), mint_info.clone(), mint_info.clone()],
5414 )
5415 .unwrap();
5416
5417 do_process_instruction_dups(
5419 burn_checked(
5420 &program_id,
5421 &account1_key,
5422 &mint_key,
5423 &mint_key,
5424 &[],
5425 500,
5426 2,
5427 )
5428 .unwrap(),
5429 vec![account1_info.clone(), mint_info.clone(), mint_info.clone()],
5430 )
5431 .unwrap();
5432
5433 do_process_instruction_dups(
5435 mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(),
5436 vec![mint_info.clone(), account1_info.clone(), owner_info.clone()],
5437 )
5438 .unwrap();
5439 let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap();
5440 account.delegated_amount = 1000;
5441 account.delegate = COption::Some(account1_key);
5442 account.owner = owner_key;
5443 Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap();
5444 do_process_instruction_dups(
5445 burn(
5446 &program_id,
5447 &account1_key,
5448 &mint_key,
5449 &account1_key,
5450 &[],
5451 500,
5452 )
5453 .unwrap(),
5454 vec![
5455 account1_info.clone(),
5456 mint_info.clone(),
5457 account1_info.clone(),
5458 ],
5459 )
5460 .unwrap();
5461
5462 do_process_instruction_dups(
5464 burn_checked(
5465 &program_id,
5466 &account1_key,
5467 &mint_key,
5468 &account1_key,
5469 &[],
5470 500,
5471 2,
5472 )
5473 .unwrap(),
5474 vec![
5475 account1_info.clone(),
5476 mint_info.clone(),
5477 account1_info.clone(),
5478 ],
5479 )
5480 .unwrap();
5481
5482 do_process_instruction_dups(
5484 mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(),
5485 vec![mint_info.clone(), account1_info.clone(), owner_info.clone()],
5486 )
5487 .unwrap();
5488 let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap();
5489 account.delegated_amount = 1000;
5490 account.delegate = COption::Some(mint_key);
5491 account.owner = owner_key;
5492 Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap();
5493 do_process_instruction_dups(
5494 burn(&program_id, &account1_key, &mint_key, &mint_key, &[], 500).unwrap(),
5495 vec![account1_info.clone(), mint_info.clone(), mint_info.clone()],
5496 )
5497 .unwrap();
5498
5499 do_process_instruction_dups(
5501 burn_checked(
5502 &program_id,
5503 &account1_key,
5504 &mint_key,
5505 &mint_key,
5506 &[],
5507 500,
5508 2,
5509 )
5510 .unwrap(),
5511 vec![account1_info.clone(), mint_info.clone(), mint_info.clone()],
5512 )
5513 .unwrap();
5514 }
5515
5516 #[test]
5517 fn test_burn() {
5518 let program_id = crate::id();
5519 let account_key = Pubkey::new_unique();
5520 let mut account_account = SolanaAccount::new(
5521 account_minimum_balance(),
5522 Account::get_packed_len(),
5523 &program_id,
5524 );
5525 let account2_key = Pubkey::new_unique();
5526 let mut account2_account = SolanaAccount::new(
5527 account_minimum_balance(),
5528 Account::get_packed_len(),
5529 &program_id,
5530 );
5531 let account3_key = Pubkey::new_unique();
5532 let mut account3_account = SolanaAccount::new(
5533 account_minimum_balance(),
5534 Account::get_packed_len(),
5535 &program_id,
5536 );
5537 let delegate_key = Pubkey::new_unique();
5538 let mut delegate_account = SolanaAccount::default();
5539 let mismatch_key = Pubkey::new_unique();
5540 let mut mismatch_account = SolanaAccount::new(
5541 account_minimum_balance(),
5542 Account::get_packed_len(),
5543 &program_id,
5544 );
5545 let owner_key = Pubkey::new_unique();
5546 let mut owner_account = SolanaAccount::default();
5547 let owner2_key = Pubkey::new_unique();
5548 let mut owner2_account = SolanaAccount::default();
5549 let mint_key = Pubkey::new_unique();
5550 let mut mint_account =
5551 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
5552 let mint2_key = Pubkey::new_unique();
5553 let mut rent_sysvar = rent_sysvar();
5554
5555 do_process_instruction(
5557 initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
5558 vec![&mut mint_account, &mut rent_sysvar],
5559 )
5560 .unwrap();
5561
5562 do_process_instruction(
5564 initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
5565 vec![
5566 &mut account_account,
5567 &mut mint_account,
5568 &mut owner_account,
5569 &mut rent_sysvar,
5570 ],
5571 )
5572 .unwrap();
5573
5574 do_process_instruction(
5576 initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(),
5577 vec![
5578 &mut account2_account,
5579 &mut mint_account,
5580 &mut owner_account,
5581 &mut rent_sysvar,
5582 ],
5583 )
5584 .unwrap();
5585
5586 do_process_instruction(
5588 initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(),
5589 vec![
5590 &mut account3_account,
5591 &mut mint_account,
5592 &mut owner_account,
5593 &mut rent_sysvar,
5594 ],
5595 )
5596 .unwrap();
5597
5598 do_process_instruction(
5600 initialize_account(&program_id, &mismatch_key, &mint_key, &owner_key).unwrap(),
5601 vec![
5602 &mut mismatch_account,
5603 &mut mint_account,
5604 &mut owner_account,
5605 &mut rent_sysvar,
5606 ],
5607 )
5608 .unwrap();
5609
5610 do_process_instruction(
5612 mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(),
5613 vec![&mut mint_account, &mut account_account, &mut owner_account],
5614 )
5615 .unwrap();
5616
5617 do_process_instruction(
5619 mint_to(&program_id, &mint_key, &mismatch_key, &owner_key, &[], 1000).unwrap(),
5620 vec![&mut mint_account, &mut mismatch_account, &mut owner_account],
5621 )
5622 .unwrap();
5623 let mut account = Account::unpack_unchecked(&mismatch_account.data).unwrap();
5624 account.mint = mint2_key;
5625 Account::pack(account, &mut mismatch_account.data).unwrap();
5626
5627 let mut instruction =
5629 burn(&program_id, &account_key, &mint_key, &delegate_key, &[], 42).unwrap();
5630 instruction.accounts[1].is_signer = false;
5631 assert_eq!(
5632 Err(TokenError::OwnerMismatch.into()),
5633 do_process_instruction(
5634 instruction,
5635 vec![
5636 &mut account_account,
5637 &mut mint_account,
5638 &mut delegate_account
5639 ],
5640 )
5641 );
5642
5643 assert_eq!(
5645 Err(TokenError::OwnerMismatch.into()),
5646 do_process_instruction(
5647 burn(&program_id, &account_key, &mint_key, &owner2_key, &[], 42).unwrap(),
5648 vec![&mut account_account, &mut mint_account, &mut owner2_account],
5649 )
5650 );
5651
5652 let not_program_id = Pubkey::new_unique();
5654 account_account.owner = not_program_id;
5655 assert_eq!(
5656 Err(ProgramError::IncorrectProgramId),
5657 do_process_instruction(
5658 burn(&program_id, &account_key, &mint_key, &owner_key, &[], 0).unwrap(),
5659 vec![&mut account_account, &mut mint_account, &mut owner_account],
5660 )
5661 );
5662 account_account.owner = program_id;
5663
5664 let not_program_id = Pubkey::new_unique();
5666 mint_account.owner = not_program_id;
5667 assert_eq!(
5668 Err(ProgramError::IncorrectProgramId),
5669 do_process_instruction(
5670 burn(&program_id, &account_key, &mint_key, &owner_key, &[], 0).unwrap(),
5671 vec![&mut account_account, &mut mint_account, &mut owner_account],
5672 )
5673 );
5674 mint_account.owner = program_id;
5675
5676 assert_eq!(
5678 Err(TokenError::MintMismatch.into()),
5679 do_process_instruction(
5680 burn(&program_id, &mismatch_key, &mint_key, &owner_key, &[], 42).unwrap(),
5681 vec![&mut mismatch_account, &mut mint_account, &mut owner_account],
5682 )
5683 );
5684
5685 do_process_instruction(
5687 burn(&program_id, &account_key, &mint_key, &owner_key, &[], 21).unwrap(),
5688 vec![&mut account_account, &mut mint_account, &mut owner_account],
5689 )
5690 .unwrap();
5691
5692 assert_eq!(
5694 Err(TokenError::MintDecimalsMismatch.into()),
5695 do_process_instruction(
5696 burn_checked(&program_id, &account_key, &mint_key, &owner_key, &[], 21, 3).unwrap(),
5697 vec![&mut account_account, &mut mint_account, &mut owner_account],
5698 )
5699 );
5700
5701 do_process_instruction(
5703 burn_checked(&program_id, &account_key, &mint_key, &owner_key, &[], 21, 2).unwrap(),
5704 vec![&mut account_account, &mut mint_account, &mut owner_account],
5705 )
5706 .unwrap();
5707
5708 let mint = Mint::unpack_unchecked(&mint_account.data).unwrap();
5709 assert_eq!(mint.supply, 2000 - 42);
5710 let account = Account::unpack_unchecked(&account_account.data).unwrap();
5711 assert_eq!(account.amount, 1000 - 42);
5712
5713 assert_eq!(
5715 Err(TokenError::InsufficientFunds.into()),
5716 do_process_instruction(
5717 burn(
5718 &program_id,
5719 &account_key,
5720 &mint_key,
5721 &owner_key,
5722 &[],
5723 100_000_000
5724 )
5725 .unwrap(),
5726 vec![&mut account_account, &mut mint_account, &mut owner_account],
5727 )
5728 );
5729
5730 do_process_instruction(
5732 approve(
5733 &program_id,
5734 &account_key,
5735 &delegate_key,
5736 &owner_key,
5737 &[],
5738 84,
5739 )
5740 .unwrap(),
5741 vec![
5742 &mut account_account,
5743 &mut delegate_account,
5744 &mut owner_account,
5745 ],
5746 )
5747 .unwrap();
5748
5749 assert_eq!(
5751 Err(TokenError::OwnerMismatch.into()),
5752 do_process_instruction(
5753 burn(
5754 &program_id,
5755 &account_key,
5756 &mint_key,
5757 &owner2_key, &[],
5759 1,
5760 )
5761 .unwrap(),
5762 vec![&mut account_account, &mut mint_account, &mut owner2_account],
5763 )
5764 );
5765
5766 assert_eq!(
5768 Err(TokenError::InsufficientFunds.into()),
5769 do_process_instruction(
5770 burn(&program_id, &account_key, &mint_key, &delegate_key, &[], 85).unwrap(),
5771 vec![
5772 &mut account_account,
5773 &mut mint_account,
5774 &mut delegate_account
5775 ],
5776 )
5777 );
5778
5779 do_process_instruction(
5781 burn(&program_id, &account_key, &mint_key, &delegate_key, &[], 84).unwrap(),
5782 vec![
5783 &mut account_account,
5784 &mut mint_account,
5785 &mut delegate_account,
5786 ],
5787 )
5788 .unwrap();
5789
5790 let mint = Mint::unpack_unchecked(&mint_account.data).unwrap();
5792 assert_eq!(mint.supply, 2000 - 42 - 84);
5793 let account = Account::unpack_unchecked(&account_account.data).unwrap();
5794 assert_eq!(account.amount, 1000 - 42 - 84);
5795
5796 assert_eq!(
5798 Err(TokenError::OwnerMismatch.into()),
5799 do_process_instruction(
5800 burn(&program_id, &account_key, &mint_key, &delegate_key, &[], 1).unwrap(),
5801 vec![
5802 &mut account_account,
5803 &mut mint_account,
5804 &mut delegate_account
5805 ],
5806 )
5807 );
5808 }
5809
5810 #[test]
5811 fn test_multisig() {
5812 let program_id = crate::id();
5813 let mint_key = Pubkey::new_unique();
5814 let mut mint_account =
5815 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
5816 let account_key = Pubkey::new_unique();
5817 let mut account = SolanaAccount::new(
5818 account_minimum_balance(),
5819 Account::get_packed_len(),
5820 &program_id,
5821 );
5822 let account2_key = Pubkey::new_unique();
5823 let mut account2_account = SolanaAccount::new(
5824 account_minimum_balance(),
5825 Account::get_packed_len(),
5826 &program_id,
5827 );
5828 let owner_key = Pubkey::new_unique();
5829 let mut owner_account = SolanaAccount::default();
5830 let multisig_key = Pubkey::new_unique();
5831 let mut multisig_account = SolanaAccount::new(42, Multisig::get_packed_len(), &program_id);
5832 let multisig_delegate_key = Pubkey::new_unique();
5833 let mut multisig_delegate_account = SolanaAccount::new(
5834 multisig_minimum_balance(),
5835 Multisig::get_packed_len(),
5836 &program_id,
5837 );
5838 let signer_keys = vec![Pubkey::new_unique(); MAX_SIGNERS];
5839 let signer_key_refs: Vec<&Pubkey> = signer_keys.iter().collect();
5840 let mut signer_accounts = vec![SolanaAccount::new(0, 0, &program_id); MAX_SIGNERS];
5841 let mut rent_sysvar = rent_sysvar();
5842
5843 let account_info_iter = &mut signer_accounts.iter_mut();
5845 assert_eq!(
5846 Err(TokenError::NotRentExempt.into()),
5847 do_process_instruction(
5848 initialize_multisig(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(),
5849 vec![
5850 &mut multisig_account,
5851 &mut rent_sysvar,
5852 account_info_iter.next().unwrap(),
5853 ],
5854 )
5855 );
5856
5857 multisig_account.kelvins = multisig_minimum_balance();
5858 let mut multisig_account2 = multisig_account.clone();
5859
5860 let account_info_iter = &mut signer_accounts.iter_mut();
5862 do_process_instruction(
5863 initialize_multisig(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(),
5864 vec![
5865 &mut multisig_account,
5866 &mut rent_sysvar,
5867 account_info_iter.next().unwrap(),
5868 ],
5869 )
5870 .unwrap();
5871
5872 let account_info_iter = &mut signer_accounts.iter_mut();
5874 do_process_instruction(
5875 initialize_multisig2(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(),
5876 vec![&mut multisig_account2, account_info_iter.next().unwrap()],
5877 )
5878 .unwrap();
5879
5880 let account_info_iter = &mut signer_accounts.iter_mut();
5882 do_process_instruction(
5883 initialize_multisig(
5884 &program_id,
5885 &multisig_delegate_key,
5886 &signer_key_refs,
5887 MAX_SIGNERS as u8,
5888 )
5889 .unwrap(),
5890 vec![
5891 &mut multisig_delegate_account,
5892 &mut rent_sysvar,
5893 account_info_iter.next().unwrap(),
5894 account_info_iter.next().unwrap(),
5895 account_info_iter.next().unwrap(),
5896 account_info_iter.next().unwrap(),
5897 account_info_iter.next().unwrap(),
5898 account_info_iter.next().unwrap(),
5899 account_info_iter.next().unwrap(),
5900 account_info_iter.next().unwrap(),
5901 account_info_iter.next().unwrap(),
5902 account_info_iter.next().unwrap(),
5903 account_info_iter.next().unwrap(),
5904 ],
5905 )
5906 .unwrap();
5907
5908 do_process_instruction(
5910 initialize_mint(&program_id, &mint_key, &multisig_key, None, 2).unwrap(),
5911 vec![&mut mint_account, &mut rent_sysvar],
5912 )
5913 .unwrap();
5914
5915 do_process_instruction(
5917 initialize_account(&program_id, &account_key, &mint_key, &multisig_key).unwrap(),
5918 vec![
5919 &mut account,
5920 &mut mint_account,
5921 &mut multisig_account,
5922 &mut rent_sysvar,
5923 ],
5924 )
5925 .unwrap();
5926
5927 do_process_instruction(
5929 initialize_account(
5930 &program_id,
5931 &account2_key,
5932 &mint_key,
5933 &multisig_delegate_key,
5934 )
5935 .unwrap(),
5936 vec![
5937 &mut account2_account,
5938 &mut mint_account,
5939 &mut multisig_account,
5940 &mut rent_sysvar,
5941 ],
5942 )
5943 .unwrap();
5944
5945 let account_info_iter = &mut signer_accounts.iter_mut();
5947 do_process_instruction(
5948 mint_to(
5949 &program_id,
5950 &mint_key,
5951 &account_key,
5952 &multisig_key,
5953 &[&signer_keys[0]],
5954 1000,
5955 )
5956 .unwrap(),
5957 vec![
5958 &mut mint_account,
5959 &mut account,
5960 &mut multisig_account,
5961 account_info_iter.next().unwrap(),
5962 ],
5963 )
5964 .unwrap();
5965
5966 let account_info_iter = &mut signer_accounts.iter_mut();
5968 do_process_instruction(
5969 approve(
5970 &program_id,
5971 &account_key,
5972 &multisig_delegate_key,
5973 &multisig_key,
5974 &[&signer_keys[0]],
5975 100,
5976 )
5977 .unwrap(),
5978 vec![
5979 &mut account,
5980 &mut multisig_delegate_account,
5981 &mut multisig_account,
5982 account_info_iter.next().unwrap(),
5983 ],
5984 )
5985 .unwrap();
5986
5987 let account_info_iter = &mut signer_accounts.iter_mut();
5989 do_process_instruction(
5990 #[allow(deprecated)]
5991 transfer(
5992 &program_id,
5993 &account_key,
5994 &account2_key,
5995 &multisig_key,
5996 &[&signer_keys[0]],
5997 42,
5998 )
5999 .unwrap(),
6000 vec![
6001 &mut account,
6002 &mut account2_account,
6003 &mut multisig_account,
6004 account_info_iter.next().unwrap(),
6005 ],
6006 )
6007 .unwrap();
6008
6009 let account_info_iter = &mut signer_accounts.iter_mut();
6011 do_process_instruction(
6012 #[allow(deprecated)]
6013 transfer(
6014 &program_id,
6015 &account_key,
6016 &account2_key,
6017 &multisig_delegate_key,
6018 &signer_key_refs,
6019 42,
6020 )
6021 .unwrap(),
6022 vec![
6023 &mut account,
6024 &mut account2_account,
6025 &mut multisig_delegate_account,
6026 account_info_iter.next().unwrap(),
6027 account_info_iter.next().unwrap(),
6028 account_info_iter.next().unwrap(),
6029 account_info_iter.next().unwrap(),
6030 account_info_iter.next().unwrap(),
6031 account_info_iter.next().unwrap(),
6032 account_info_iter.next().unwrap(),
6033 account_info_iter.next().unwrap(),
6034 account_info_iter.next().unwrap(),
6035 account_info_iter.next().unwrap(),
6036 account_info_iter.next().unwrap(),
6037 ],
6038 )
6039 .unwrap();
6040
6041 let account_info_iter = &mut signer_accounts.iter_mut();
6043 do_process_instruction(
6044 mint_to(
6045 &program_id,
6046 &mint_key,
6047 &account2_key,
6048 &multisig_key,
6049 &[&signer_keys[0]],
6050 42,
6051 )
6052 .unwrap(),
6053 vec![
6054 &mut mint_account,
6055 &mut account2_account,
6056 &mut multisig_account,
6057 account_info_iter.next().unwrap(),
6058 ],
6059 )
6060 .unwrap();
6061
6062 let account_info_iter = &mut signer_accounts.iter_mut();
6064 do_process_instruction(
6065 burn(
6066 &program_id,
6067 &account_key,
6068 &mint_key,
6069 &multisig_key,
6070 &[&signer_keys[0]],
6071 42,
6072 )
6073 .unwrap(),
6074 vec![
6075 &mut account,
6076 &mut mint_account,
6077 &mut multisig_account,
6078 account_info_iter.next().unwrap(),
6079 ],
6080 )
6081 .unwrap();
6082
6083 let account_info_iter = &mut signer_accounts.iter_mut();
6085 do_process_instruction(
6086 burn(
6087 &program_id,
6088 &account_key,
6089 &mint_key,
6090 &multisig_delegate_key,
6091 &signer_key_refs,
6092 42,
6093 )
6094 .unwrap(),
6095 vec![
6096 &mut account,
6097 &mut mint_account,
6098 &mut multisig_delegate_account,
6099 account_info_iter.next().unwrap(),
6100 account_info_iter.next().unwrap(),
6101 account_info_iter.next().unwrap(),
6102 account_info_iter.next().unwrap(),
6103 account_info_iter.next().unwrap(),
6104 account_info_iter.next().unwrap(),
6105 account_info_iter.next().unwrap(),
6106 account_info_iter.next().unwrap(),
6107 account_info_iter.next().unwrap(),
6108 account_info_iter.next().unwrap(),
6109 account_info_iter.next().unwrap(),
6110 ],
6111 )
6112 .unwrap();
6113
6114 let account3_key = Pubkey::new_unique();
6116 let mut account3_account = SolanaAccount::new(
6117 account_minimum_balance(),
6118 Account::get_packed_len(),
6119 &program_id,
6120 );
6121 let mint2_key = Pubkey::new_unique();
6122 let mut mint2_account =
6123 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
6124 do_process_instruction(
6125 initialize_mint(
6126 &program_id,
6127 &mint2_key,
6128 &multisig_key,
6129 Some(&multisig_key),
6130 2,
6131 )
6132 .unwrap(),
6133 vec![&mut mint2_account, &mut rent_sysvar],
6134 )
6135 .unwrap();
6136 do_process_instruction(
6137 initialize_account(&program_id, &account3_key, &mint2_key, &owner_key).unwrap(),
6138 vec![
6139 &mut account3_account,
6140 &mut mint2_account,
6141 &mut owner_account,
6142 &mut rent_sysvar,
6143 ],
6144 )
6145 .unwrap();
6146 let account_info_iter = &mut signer_accounts.iter_mut();
6147 do_process_instruction(
6148 mint_to(
6149 &program_id,
6150 &mint2_key,
6151 &account3_key,
6152 &multisig_key,
6153 &[&signer_keys[0]],
6154 1000,
6155 )
6156 .unwrap(),
6157 vec![
6158 &mut mint2_account,
6159 &mut account3_account,
6160 &mut multisig_account,
6161 account_info_iter.next().unwrap(),
6162 ],
6163 )
6164 .unwrap();
6165 let account_info_iter = &mut signer_accounts.iter_mut();
6166 do_process_instruction(
6167 freeze_account(
6168 &program_id,
6169 &account3_key,
6170 &mint2_key,
6171 &multisig_key,
6172 &[&signer_keys[0]],
6173 )
6174 .unwrap(),
6175 vec![
6176 &mut account3_account,
6177 &mut mint2_account,
6178 &mut multisig_account,
6179 account_info_iter.next().unwrap(),
6180 ],
6181 )
6182 .unwrap();
6183
6184 let account_info_iter = &mut signer_accounts.iter_mut();
6186 do_process_instruction(
6187 set_authority(
6188 &program_id,
6189 &mint_key,
6190 Some(&owner_key),
6191 AuthorityType::MintTokens,
6192 &multisig_key,
6193 &[&signer_keys[0]],
6194 )
6195 .unwrap(),
6196 vec![
6197 &mut mint_account,
6198 &mut multisig_account,
6199 account_info_iter.next().unwrap(),
6200 ],
6201 )
6202 .unwrap();
6203
6204 let account_info_iter = &mut signer_accounts.iter_mut();
6206 do_process_instruction(
6207 set_authority(
6208 &program_id,
6209 &account_key,
6210 Some(&owner_key),
6211 AuthorityType::AccountOwner,
6212 &multisig_key,
6213 &[&signer_keys[0]],
6214 )
6215 .unwrap(),
6216 vec![
6217 &mut account,
6218 &mut multisig_account,
6219 account_info_iter.next().unwrap(),
6220 ],
6221 )
6222 .unwrap();
6223 }
6224
6225 #[test]
6226 fn test_validate_owner() {
6227 let program_id = crate::id();
6228 let owner_key = Pubkey::new_unique();
6229 let account_to_validate = Pubkey::new_unique();
6230 let mut signer_keys = [Pubkey::default(); MAX_SIGNERS];
6231 for signer_key in signer_keys.iter_mut().take(MAX_SIGNERS) {
6232 *signer_key = Pubkey::new_unique();
6233 }
6234 let mut signer_kelvins = 0;
6235 let mut signer_data = vec![];
6236 let mut signers = vec![
6237 AccountInfo::new(
6238 &owner_key,
6239 true,
6240 false,
6241 &mut signer_kelvins,
6242 &mut signer_data,
6243 &program_id,
6244 false,
6245 Epoch::default(),
6246 );
6247 MAX_SIGNERS + 1
6248 ];
6249 for (signer, key) in signers.iter_mut().zip(&signer_keys) {
6250 signer.key = key;
6251 }
6252 let mut kelvins = 0;
6253 let mut data = vec![0; Multisig::get_packed_len()];
6254 let mut multisig = Multisig::unpack_unchecked(&data).unwrap();
6255 multisig.m = MAX_SIGNERS as u8;
6256 multisig.n = MAX_SIGNERS as u8;
6257 multisig.signers = signer_keys;
6258 multisig.is_initialized = true;
6259 Multisig::pack(multisig, &mut data).unwrap();
6260 let owner_account_info = AccountInfo::new(
6261 &owner_key,
6262 false,
6263 false,
6264 &mut kelvins,
6265 &mut data,
6266 &program_id,
6267 false,
6268 Epoch::default(),
6269 );
6270
6271 {
6274 let mut kelvins = 0;
6275 let mut data = vec![0; Account::get_packed_len()];
6276 let mut account = Account::unpack_unchecked(&data).unwrap();
6277 account.owner = account_to_validate;
6278 Account::pack(account, &mut data).unwrap();
6279 let account_info = AccountInfo::new(
6280 &account_to_validate,
6281 true,
6282 false,
6283 &mut kelvins,
6284 &mut data,
6285 &program_id,
6286 false,
6287 Epoch::default(),
6288 );
6289 let account_info_data_len = account_info.data_len();
6290 let mut borrowed_data = account_info.try_borrow_mut_data().unwrap();
6291 Processor::validate_owner(
6292 &program_id,
6293 &account_to_validate,
6294 &account_info,
6295 account_info_data_len,
6296 &[],
6297 )
6298 .unwrap();
6299 borrowed_data[0] = 1;
6301 }
6302
6303 Processor::validate_owner(
6305 &program_id,
6306 &owner_key,
6307 &owner_account_info,
6308 owner_account_info.data_len(),
6309 &signers,
6310 )
6311 .unwrap();
6312
6313 {
6315 let mut multisig =
6316 Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap();
6317 multisig.m = 1;
6318 Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap();
6319 }
6320 Processor::validate_owner(
6321 &program_id,
6322 &owner_key,
6323 &owner_account_info,
6324 owner_account_info.data_len(),
6325 &signers,
6326 )
6327 .unwrap();
6328
6329 {
6331 let mut multisig =
6332 Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap();
6333 multisig.m = 2;
6334 multisig.n = 1;
6335 Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap();
6336 }
6337 assert_eq!(
6338 Err(ProgramError::MissingRequiredSignature),
6339 Processor::validate_owner(
6340 &program_id,
6341 &owner_key,
6342 &owner_account_info,
6343 owner_account_info.data_len(),
6344 &signers
6345 )
6346 );
6347
6348 {
6350 let mut multisig =
6351 Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap();
6352 multisig.m = 0;
6353 multisig.n = 11;
6354 Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap();
6355 }
6356 Processor::validate_owner(
6357 &program_id,
6358 &owner_key,
6359 &owner_account_info,
6360 owner_account_info.data_len(),
6361 &signers,
6362 )
6363 .unwrap();
6364
6365 {
6367 let mut multisig =
6368 Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap();
6369 multisig.m = 2;
6370 multisig.n = 11;
6371 Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap();
6372 }
6373 assert_eq!(
6374 Err(ProgramError::MissingRequiredSignature),
6375 Processor::validate_owner(
6376 &program_id,
6377 &owner_key,
6378 &owner_account_info,
6379 owner_account_info.data_len(),
6380 &[]
6381 )
6382 );
6383 {
6385 let mut multisig =
6386 Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap();
6387 multisig.m = 2;
6388 multisig.n = 11;
6389 Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap();
6390 }
6391 assert_eq!(
6392 Err(ProgramError::MissingRequiredSignature),
6393 Processor::validate_owner(
6394 &program_id,
6395 &owner_key,
6396 &owner_account_info,
6397 owner_account_info.data_len(),
6398 &signers[0..1]
6399 )
6400 );
6401
6402 {
6404 let mut multisig =
6405 Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap();
6406 multisig.m = 2;
6407 multisig.n = 11;
6408 Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap();
6409 }
6410 Processor::validate_owner(
6411 &program_id,
6412 &owner_key,
6413 &owner_account_info,
6414 owner_account_info.data_len(),
6415 &signers[5..7],
6416 )
6417 .unwrap();
6418
6419 {
6421 let mut multisig =
6422 Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap();
6423 multisig.m = 11;
6424 multisig.n = 11;
6425 Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap();
6426 }
6427 signers[5].is_signer = false;
6428 assert_eq!(
6429 Err(ProgramError::MissingRequiredSignature),
6430 Processor::validate_owner(
6431 &program_id,
6432 &owner_key,
6433 &owner_account_info,
6434 owner_account_info.data_len(),
6435 &signers
6436 )
6437 );
6438 signers[5].is_signer = true;
6439
6440 {
6442 let mut signer_kelvins = 0;
6443 let mut signer_data = vec![];
6444 let signers = vec![
6445 AccountInfo::new(
6446 &signer_keys[5],
6447 true,
6448 false,
6449 &mut signer_kelvins,
6450 &mut signer_data,
6451 &program_id,
6452 false,
6453 Epoch::default(),
6454 );
6455 MAX_SIGNERS + 1
6456 ];
6457 let mut multisig =
6458 Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap();
6459 multisig.m = 11;
6460 multisig.n = 11;
6461 Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap();
6462 assert_eq!(
6463 Err(ProgramError::MissingRequiredSignature),
6464 Processor::validate_owner(
6465 &program_id,
6466 &owner_key,
6467 &owner_account_info,
6468 owner_account_info.data_len(),
6469 &signers
6470 )
6471 );
6472 }
6473 }
6474
6475 #[test]
6476 fn test_owner_close_account_dups() {
6477 let program_id = crate::id();
6478 let owner_key = Pubkey::new_unique();
6479 let mint_key = Pubkey::new_unique();
6480 let mut mint_account =
6481 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
6482 let mint_info: AccountInfo<'_> = (&mint_key, false, &mut mint_account).into();
6483 let rent_key = rent::id();
6484 let mut rent_sysvar = rent_sysvar();
6485 let rent_info: AccountInfo<'_> = (&rent_key, false, &mut rent_sysvar).into();
6486
6487 do_process_instruction_dups(
6489 initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
6490 vec![mint_info.clone(), rent_info.clone()],
6491 )
6492 .unwrap();
6493
6494 let to_close_key = Pubkey::new_unique();
6495 let mut to_close_account = SolanaAccount::new(
6496 account_minimum_balance(),
6497 Account::get_packed_len(),
6498 &program_id,
6499 );
6500 let to_close_account_info: AccountInfo<'_> =
6501 (&to_close_key, true, &mut to_close_account).into();
6502 let destination_account_key = Pubkey::new_unique();
6503 let mut destination_account = SolanaAccount::new(
6504 account_minimum_balance(),
6505 Account::get_packed_len(),
6506 &program_id,
6507 );
6508 let destination_account_info: AccountInfo<'_> =
6509 (&destination_account_key, true, &mut destination_account).into();
6510 do_process_instruction_dups(
6512 initialize_account(&program_id, &to_close_key, &mint_key, &to_close_key).unwrap(),
6513 vec![
6514 to_close_account_info.clone(),
6515 mint_info.clone(),
6516 to_close_account_info.clone(),
6517 rent_info.clone(),
6518 ],
6519 )
6520 .unwrap();
6521
6522 do_process_instruction_dups(
6524 close_account(
6525 &program_id,
6526 &to_close_key,
6527 &destination_account_key,
6528 &to_close_key,
6529 &[],
6530 )
6531 .unwrap(),
6532 vec![
6533 to_close_account_info.clone(),
6534 destination_account_info.clone(),
6535 to_close_account_info.clone(),
6536 ],
6537 )
6538 .unwrap();
6539 assert_eq!(*to_close_account_info.data.borrow(), &[0u8; Account::LEN]);
6540 }
6541
6542 #[test]
6543 fn test_close_authority_close_account_dups() {
6544 let program_id = crate::id();
6545 let owner_key = Pubkey::new_unique();
6546 let mint_key = Pubkey::new_unique();
6547 let mut mint_account =
6548 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
6549 let mint_info: AccountInfo<'_> = (&mint_key, false, &mut mint_account).into();
6550 let rent_key = rent::id();
6551 let mut rent_sysvar = rent_sysvar();
6552 let rent_info: AccountInfo<'_> = (&rent_key, false, &mut rent_sysvar).into();
6553
6554 do_process_instruction_dups(
6556 initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
6557 vec![mint_info.clone(), rent_info.clone()],
6558 )
6559 .unwrap();
6560
6561 let to_close_key = Pubkey::new_unique();
6562 let mut to_close_account = SolanaAccount::new(
6563 account_minimum_balance(),
6564 Account::get_packed_len(),
6565 &program_id,
6566 );
6567 let to_close_account_info: AccountInfo<'_> =
6568 (&to_close_key, true, &mut to_close_account).into();
6569 let destination_account_key = Pubkey::new_unique();
6570 let mut destination_account = SolanaAccount::new(
6571 account_minimum_balance(),
6572 Account::get_packed_len(),
6573 &program_id,
6574 );
6575 let destination_account_info: AccountInfo<'_> =
6576 (&destination_account_key, true, &mut destination_account).into();
6577 do_process_instruction_dups(
6579 initialize_account(&program_id, &to_close_key, &mint_key, &to_close_key).unwrap(),
6580 vec![
6581 to_close_account_info.clone(),
6582 mint_info.clone(),
6583 to_close_account_info.clone(),
6584 rent_info.clone(),
6585 ],
6586 )
6587 .unwrap();
6588 let mut account = Account::unpack_unchecked(&to_close_account_info.data.borrow()).unwrap();
6589 account.close_authority = COption::Some(to_close_key);
6590 account.owner = owner_key;
6591 Account::pack(account, &mut to_close_account_info.data.borrow_mut()).unwrap();
6592 do_process_instruction_dups(
6593 close_account(
6594 &program_id,
6595 &to_close_key,
6596 &destination_account_key,
6597 &to_close_key,
6598 &[],
6599 )
6600 .unwrap(),
6601 vec![
6602 to_close_account_info.clone(),
6603 destination_account_info.clone(),
6604 to_close_account_info.clone(),
6605 ],
6606 )
6607 .unwrap();
6608 assert_eq!(*to_close_account_info.data.borrow(), &[0u8; Account::LEN]);
6609 }
6610
6611 #[test]
6612 fn test_close_account() {
6613 let program_id = crate::id();
6614 let mint_key = Pubkey::new_unique();
6615 let mut mint_account =
6616 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
6617 let account_key = Pubkey::new_unique();
6618 let mut account_account = SolanaAccount::new(
6619 account_minimum_balance(),
6620 Account::get_packed_len(),
6621 &program_id,
6622 );
6623 let account2_key = Pubkey::new_unique();
6624 let mut account2_account = SolanaAccount::new(
6625 account_minimum_balance() + 42,
6626 Account::get_packed_len(),
6627 &program_id,
6628 );
6629 let account3_key = Pubkey::new_unique();
6630 let mut account3_account = SolanaAccount::new(
6631 account_minimum_balance(),
6632 Account::get_packed_len(),
6633 &program_id,
6634 );
6635 let owner_key = Pubkey::new_unique();
6636 let mut owner_account = SolanaAccount::default();
6637 let owner2_key = Pubkey::new_unique();
6638 let mut owner2_account = SolanaAccount::default();
6639 let mut rent_sysvar = rent_sysvar();
6640
6641 assert_eq!(
6643 Err(ProgramError::UninitializedAccount),
6644 do_process_instruction(
6645 close_account(&program_id, &account_key, &account3_key, &owner2_key, &[]).unwrap(),
6646 vec![
6647 &mut account_account,
6648 &mut account3_account,
6649 &mut owner2_account,
6650 ],
6651 )
6652 );
6653
6654 do_process_instruction(
6656 initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
6657 vec![&mut mint_account, &mut rent_sysvar],
6658 )
6659 .unwrap();
6660 do_process_instruction(
6661 initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
6662 vec![
6663 &mut account_account,
6664 &mut mint_account,
6665 &mut owner_account,
6666 &mut rent_sysvar,
6667 ],
6668 )
6669 .unwrap();
6670 do_process_instruction(
6671 mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 42).unwrap(),
6672 vec![
6673 &mut mint_account,
6674 &mut account_account,
6675 &mut owner_account,
6676 &mut rent_sysvar,
6677 ],
6678 )
6679 .unwrap();
6680 let account = Account::unpack_unchecked(&account_account.data).unwrap();
6681 assert_eq!(account.amount, 42);
6682
6683 do_process_instruction(
6685 initialize_account(
6686 &program_id,
6687 &account2_key,
6688 &crate::native_mint::id(),
6689 &owner_key,
6690 )
6691 .unwrap(),
6692 vec![
6693 &mut account2_account,
6694 &mut mint_account,
6695 &mut owner_account,
6696 &mut rent_sysvar,
6697 ],
6698 )
6699 .unwrap();
6700 let account = Account::unpack_unchecked(&account2_account.data).unwrap();
6701 assert!(account.is_native());
6702 assert_eq!(account.amount, 42);
6703
6704 assert_eq!(
6706 Err(TokenError::NonNativeHasBalance.into()),
6707 do_process_instruction(
6708 close_account(&program_id, &account_key, &account3_key, &owner_key, &[]).unwrap(),
6709 vec![
6710 &mut account_account,
6711 &mut account3_account,
6712 &mut owner_account,
6713 ],
6714 )
6715 );
6716 assert_eq!(account_account.kelvins, account_minimum_balance());
6717
6718 do_process_instruction(
6720 burn(&program_id, &account_key, &mint_key, &owner_key, &[], 42).unwrap(),
6721 vec![&mut account_account, &mut mint_account, &mut owner_account],
6722 )
6723 .unwrap();
6724
6725 assert_eq!(
6727 Err(TokenError::OwnerMismatch.into()),
6728 do_process_instruction(
6729 close_account(&program_id, &account_key, &account3_key, &owner2_key, &[]).unwrap(),
6730 vec![
6731 &mut account_account,
6732 &mut account3_account,
6733 &mut owner2_account,
6734 ],
6735 )
6736 );
6737
6738 do_process_instruction(
6740 close_account(&program_id, &account_key, &account3_key, &owner_key, &[]).unwrap(),
6741 vec![
6742 &mut account_account,
6743 &mut account3_account,
6744 &mut owner_account,
6745 ],
6746 )
6747 .unwrap();
6748 assert_eq!(account_account.kelvins, 0);
6749 assert_eq!(account3_account.kelvins, 2 * account_minimum_balance());
6750 let account = Account::unpack_unchecked(&account_account.data).unwrap();
6751 assert_eq!(account.amount, 0);
6752
6753 let account_key = Pubkey::new_unique();
6755 let mut account_account = SolanaAccount::new(
6756 account_minimum_balance(),
6757 Account::get_packed_len(),
6758 &program_id,
6759 );
6760 let owner2_key = Pubkey::new_unique();
6761 let mut owner2_account = SolanaAccount::new(
6762 account_minimum_balance(),
6763 Account::get_packed_len(),
6764 &program_id,
6765 );
6766 do_process_instruction(
6767 initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
6768 vec![
6769 &mut account_account,
6770 &mut mint_account,
6771 &mut owner_account,
6772 &mut rent_sysvar,
6773 ],
6774 )
6775 .unwrap();
6776 account_account.kelvins = 2;
6777
6778 do_process_instruction(
6779 set_authority(
6780 &program_id,
6781 &account_key,
6782 Some(&owner2_key),
6783 AuthorityType::CloseAccount,
6784 &owner_key,
6785 &[],
6786 )
6787 .unwrap(),
6788 vec![&mut account_account, &mut owner_account],
6789 )
6790 .unwrap();
6791
6792 assert_eq!(
6794 Err(TokenError::OwnerMismatch.into()),
6795 do_process_instruction(
6796 close_account(&program_id, &account_key, &account3_key, &owner_key, &[]).unwrap(),
6797 vec![
6798 &mut account_account,
6799 &mut account3_account,
6800 &mut owner_account,
6801 ],
6802 )
6803 );
6804
6805 do_process_instruction(
6807 close_account(&program_id, &account_key, &account3_key, &owner2_key, &[]).unwrap(),
6808 vec![
6809 &mut account_account,
6810 &mut account3_account,
6811 &mut owner2_account,
6812 ],
6813 )
6814 .unwrap();
6815 assert_eq!(account_account.kelvins, 0);
6816 assert_eq!(account3_account.kelvins, 2 * account_minimum_balance() + 2);
6817 let account = Account::unpack_unchecked(&account_account.data).unwrap();
6818 assert_eq!(account.amount, 0);
6819
6820 do_process_instruction(
6822 close_account(&program_id, &account2_key, &account3_key, &owner_key, &[]).unwrap(),
6823 vec![
6824 &mut account2_account,
6825 &mut account3_account,
6826 &mut owner_account,
6827 ],
6828 )
6829 .unwrap();
6830 assert_eq!(account2_account.data, [0u8; Account::LEN]);
6831 assert_eq!(
6832 account3_account.kelvins,
6833 3 * account_minimum_balance() + 2 + 42
6834 );
6835 }
6836
6837 #[test]
6838 fn test_native_token() {
6839 let program_id = crate::id();
6840 let mut mint_account = native_mint();
6841 let account_key = Pubkey::new_unique();
6842 let mut account_account = SolanaAccount::new(
6843 account_minimum_balance() + 40,
6844 Account::get_packed_len(),
6845 &program_id,
6846 );
6847 let account2_key = Pubkey::new_unique();
6848 let mut account2_account = SolanaAccount::new(
6849 account_minimum_balance(),
6850 Account::get_packed_len(),
6851 &program_id,
6852 );
6853 let account3_key = Pubkey::new_unique();
6854 let mut account3_account = SolanaAccount::new(account_minimum_balance(), 0, &program_id);
6855 let owner_key = Pubkey::new_unique();
6856 let mut owner_account = SolanaAccount::default();
6857 let owner2_key = Pubkey::new_unique();
6858 let mut owner2_account = SolanaAccount::default();
6859 let owner3_key = Pubkey::new_unique();
6860 let mut rent_sysvar = rent_sysvar();
6861
6862 do_process_instruction(
6864 initialize_account(
6865 &program_id,
6866 &account_key,
6867 &crate::native_mint::id(),
6868 &owner_key,
6869 )
6870 .unwrap(),
6871 vec![
6872 &mut account_account,
6873 &mut mint_account,
6874 &mut owner_account,
6875 &mut rent_sysvar,
6876 ],
6877 )
6878 .unwrap();
6879 let account = Account::unpack_unchecked(&account_account.data).unwrap();
6880 assert!(account.is_native());
6881 assert_eq!(account.amount, 40);
6882
6883 do_process_instruction(
6885 initialize_account(
6886 &program_id,
6887 &account2_key,
6888 &crate::native_mint::id(),
6889 &owner_key,
6890 )
6891 .unwrap(),
6892 vec![
6893 &mut account2_account,
6894 &mut mint_account,
6895 &mut owner_account,
6896 &mut rent_sysvar,
6897 ],
6898 )
6899 .unwrap();
6900 let account = Account::unpack_unchecked(&account2_account.data).unwrap();
6901 assert!(account.is_native());
6902 assert_eq!(account.amount, 0);
6903
6904 assert_eq!(
6906 Err(TokenError::NativeNotSupported.into()),
6907 do_process_instruction(
6908 mint_to(
6909 &program_id,
6910 &crate::native_mint::id(),
6911 &account_key,
6912 &owner_key,
6913 &[],
6914 42
6915 )
6916 .unwrap(),
6917 vec![&mut mint_account, &mut account_account, &mut owner_account],
6918 )
6919 );
6920
6921 let bogus_mint_key = Pubkey::new_unique();
6923 let mut bogus_mint_account =
6924 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
6925 do_process_instruction(
6926 initialize_mint(&program_id, &bogus_mint_key, &owner_key, None, 2).unwrap(),
6927 vec![&mut bogus_mint_account, &mut rent_sysvar],
6928 )
6929 .unwrap();
6930
6931 assert_eq!(
6932 Err(TokenError::NativeNotSupported.into()),
6933 do_process_instruction(
6934 burn(
6935 &program_id,
6936 &account_key,
6937 &bogus_mint_key,
6938 &owner_key,
6939 &[],
6940 42
6941 )
6942 .unwrap(),
6943 vec![
6944 &mut account_account,
6945 &mut bogus_mint_account,
6946 &mut owner_account
6947 ],
6948 )
6949 );
6950
6951 assert_eq!(
6953 Err(TokenError::InsufficientFunds.into()),
6954 do_process_instruction(
6955 #[allow(deprecated)]
6956 transfer(
6957 &program_id,
6958 &account_key,
6959 &account2_key,
6960 &owner_key,
6961 &[],
6962 50,
6963 )
6964 .unwrap(),
6965 vec![
6966 &mut account_account,
6967 &mut account2_account,
6968 &mut owner_account,
6969 ],
6970 )
6971 );
6972
6973 do_process_instruction(
6975 #[allow(deprecated)]
6976 transfer(
6977 &program_id,
6978 &account_key,
6979 &account2_key,
6980 &owner_key,
6981 &[],
6982 40,
6983 )
6984 .unwrap(),
6985 vec![
6986 &mut account_account,
6987 &mut account2_account,
6988 &mut owner_account,
6989 ],
6990 )
6991 .unwrap();
6992 assert_eq!(account_account.kelvins, account_minimum_balance());
6993 let account = Account::unpack_unchecked(&account_account.data).unwrap();
6994 assert!(account.is_native());
6995 assert_eq!(account.amount, 0);
6996 assert_eq!(account2_account.kelvins, account_minimum_balance() + 40);
6997 let account = Account::unpack_unchecked(&account2_account.data).unwrap();
6998 assert!(account.is_native());
6999 assert_eq!(account.amount, 40);
7000
7001 do_process_instruction(
7003 set_authority(
7004 &program_id,
7005 &account_key,
7006 Some(&owner3_key),
7007 AuthorityType::CloseAccount,
7008 &owner_key,
7009 &[],
7010 )
7011 .unwrap(),
7012 vec![&mut account_account, &mut owner_account],
7013 )
7014 .unwrap();
7015 let account = Account::unpack_unchecked(&account_account.data).unwrap();
7016 assert_eq!(account.close_authority, COption::Some(owner3_key));
7017
7018 do_process_instruction(
7020 set_authority(
7021 &program_id,
7022 &account_key,
7023 Some(&owner2_key),
7024 AuthorityType::AccountOwner,
7025 &owner_key,
7026 &[],
7027 )
7028 .unwrap(),
7029 vec![&mut account_account, &mut owner_account],
7030 )
7031 .unwrap();
7032
7033 let account = Account::unpack_unchecked(&account_account.data).unwrap();
7035 assert_eq!(account.close_authority, COption::None);
7036
7037 do_process_instruction(
7039 close_account(&program_id, &account_key, &account3_key, &owner2_key, &[]).unwrap(),
7040 vec![
7041 &mut account_account,
7042 &mut account3_account,
7043 &mut owner2_account,
7044 ],
7045 )
7046 .unwrap();
7047 assert_eq!(account_account.kelvins, 0);
7048 assert_eq!(account3_account.kelvins, 2 * account_minimum_balance());
7049 assert_eq!(account_account.data, [0u8; Account::LEN]);
7050 }
7051
7052 #[test]
7053 fn test_overflow() {
7054 let program_id = crate::id();
7055 let account_key = Pubkey::new_unique();
7056 let mut account_account = SolanaAccount::new(
7057 account_minimum_balance(),
7058 Account::get_packed_len(),
7059 &program_id,
7060 );
7061 let account2_key = Pubkey::new_unique();
7062 let mut account2_account = SolanaAccount::new(
7063 account_minimum_balance(),
7064 Account::get_packed_len(),
7065 &program_id,
7066 );
7067 let owner_key = Pubkey::new_unique();
7068 let mut owner_account = SolanaAccount::default();
7069 let owner2_key = Pubkey::new_unique();
7070 let mut owner2_account = SolanaAccount::default();
7071 let mint_owner_key = Pubkey::new_unique();
7072 let mut mint_owner_account = SolanaAccount::default();
7073 let mint_key = Pubkey::new_unique();
7074 let mut mint_account =
7075 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
7076 let mut rent_sysvar = rent_sysvar();
7077
7078 do_process_instruction(
7080 initialize_mint(&program_id, &mint_key, &mint_owner_key, None, 2).unwrap(),
7081 vec![&mut mint_account, &mut rent_sysvar],
7082 )
7083 .unwrap();
7084
7085 do_process_instruction(
7087 initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
7088 vec![
7089 &mut account_account,
7090 &mut mint_account,
7091 &mut owner_account,
7092 &mut rent_sysvar,
7093 ],
7094 )
7095 .unwrap();
7096
7097 do_process_instruction(
7099 initialize_account(&program_id, &account2_key, &mint_key, &owner2_key).unwrap(),
7100 vec![
7101 &mut account2_account,
7102 &mut mint_account,
7103 &mut owner2_account,
7104 &mut rent_sysvar,
7105 ],
7106 )
7107 .unwrap();
7108
7109 do_process_instruction(
7111 mint_to(
7112 &program_id,
7113 &mint_key,
7114 &account_key,
7115 &mint_owner_key,
7116 &[],
7117 u64::MAX,
7118 )
7119 .unwrap(),
7120 vec![
7121 &mut mint_account,
7122 &mut account_account,
7123 &mut mint_owner_account,
7124 ],
7125 )
7126 .unwrap();
7127 let account = Account::unpack_unchecked(&account_account.data).unwrap();
7128 assert_eq!(account.amount, u64::MAX);
7129
7130 assert_eq!(
7132 Err(TokenError::Overflow.into()),
7133 do_process_instruction(
7134 mint_to(
7135 &program_id,
7136 &mint_key,
7137 &account_key,
7138 &mint_owner_key,
7139 &[],
7140 1,
7141 )
7142 .unwrap(),
7143 vec![
7144 &mut mint_account,
7145 &mut account_account,
7146 &mut mint_owner_account,
7147 ],
7148 )
7149 );
7150 let account = Account::unpack_unchecked(&account_account.data).unwrap();
7151 assert_eq!(account.amount, u64::MAX);
7152
7153 assert_eq!(
7155 Err(TokenError::Overflow.into()),
7156 do_process_instruction(
7157 mint_to(
7158 &program_id,
7159 &mint_key,
7160 &account2_key,
7161 &mint_owner_key,
7162 &[],
7163 1,
7164 )
7165 .unwrap(),
7166 vec![
7167 &mut mint_account,
7168 &mut account2_account,
7169 &mut mint_owner_account,
7170 ],
7171 )
7172 );
7173
7174 do_process_instruction(
7176 burn(&program_id, &account_key, &mint_key, &owner_key, &[], 100).unwrap(),
7177 vec![&mut account_account, &mut mint_account, &mut owner_account],
7178 )
7179 .unwrap();
7180 let account = Account::unpack_unchecked(&account_account.data).unwrap();
7181 assert_eq!(account.amount, u64::MAX - 100);
7182
7183 do_process_instruction(
7184 mint_to(
7185 &program_id,
7186 &mint_key,
7187 &account_key,
7188 &mint_owner_key,
7189 &[],
7190 100,
7191 )
7192 .unwrap(),
7193 vec![
7194 &mut mint_account,
7195 &mut account_account,
7196 &mut mint_owner_account,
7197 ],
7198 )
7199 .unwrap();
7200 let account = Account::unpack_unchecked(&account_account.data).unwrap();
7201 assert_eq!(account.amount, u64::MAX);
7202
7203 let mut account = Account::unpack_unchecked(&account2_account.data).unwrap();
7205 account.amount = 1;
7206 Account::pack(account, &mut account2_account.data).unwrap();
7207
7208 assert_eq!(
7209 Err(TokenError::Overflow.into()),
7210 do_process_instruction(
7211 #[allow(deprecated)]
7212 transfer(
7213 &program_id,
7214 &account2_key,
7215 &account_key,
7216 &owner2_key,
7217 &[],
7218 1,
7219 )
7220 .unwrap(),
7221 vec![
7222 &mut account2_account,
7223 &mut account_account,
7224 &mut owner2_account,
7225 ],
7226 )
7227 );
7228 }
7229
7230 #[test]
7231 fn test_frozen() {
7232 let program_id = crate::id();
7233 let account_key = Pubkey::new_unique();
7234 let mut account_account = SolanaAccount::new(
7235 account_minimum_balance(),
7236 Account::get_packed_len(),
7237 &program_id,
7238 );
7239 let account2_key = Pubkey::new_unique();
7240 let mut account2_account = SolanaAccount::new(
7241 account_minimum_balance(),
7242 Account::get_packed_len(),
7243 &program_id,
7244 );
7245 let owner_key = Pubkey::new_unique();
7246 let mut owner_account = SolanaAccount::default();
7247 let mint_key = Pubkey::new_unique();
7248 let mut mint_account =
7249 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
7250 let mut rent_sysvar = rent_sysvar();
7251
7252 do_process_instruction(
7254 initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
7255 vec![&mut mint_account, &mut rent_sysvar],
7256 )
7257 .unwrap();
7258
7259 do_process_instruction(
7261 initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
7262 vec![
7263 &mut account_account,
7264 &mut mint_account,
7265 &mut owner_account,
7266 &mut rent_sysvar,
7267 ],
7268 )
7269 .unwrap();
7270
7271 do_process_instruction(
7273 initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(),
7274 vec![
7275 &mut account2_account,
7276 &mut mint_account,
7277 &mut owner_account,
7278 &mut rent_sysvar,
7279 ],
7280 )
7281 .unwrap();
7282
7283 do_process_instruction(
7285 mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(),
7286 vec![&mut mint_account, &mut account_account, &mut owner_account],
7287 )
7288 .unwrap();
7289
7290 let mut account = Account::unpack_unchecked(&account2_account.data).unwrap();
7292 account.state = AccountState::Frozen;
7293 Account::pack(account, &mut account2_account.data).unwrap();
7294 assert_eq!(
7295 Err(TokenError::AccountFrozen.into()),
7296 do_process_instruction(
7297 #[allow(deprecated)]
7298 transfer(
7299 &program_id,
7300 &account_key,
7301 &account2_key,
7302 &owner_key,
7303 &[],
7304 500,
7305 )
7306 .unwrap(),
7307 vec![
7308 &mut account_account,
7309 &mut account2_account,
7310 &mut owner_account,
7311 ],
7312 )
7313 );
7314
7315 let mut account = Account::unpack_unchecked(&account_account.data).unwrap();
7316 account.state = AccountState::Initialized;
7317 Account::pack(account, &mut account_account.data).unwrap();
7318 let mut account = Account::unpack_unchecked(&account2_account.data).unwrap();
7319 account.state = AccountState::Frozen;
7320 Account::pack(account, &mut account2_account.data).unwrap();
7321 assert_eq!(
7322 Err(TokenError::AccountFrozen.into()),
7323 do_process_instruction(
7324 #[allow(deprecated)]
7325 transfer(
7326 &program_id,
7327 &account_key,
7328 &account2_key,
7329 &owner_key,
7330 &[],
7331 500,
7332 )
7333 .unwrap(),
7334 vec![
7335 &mut account_account,
7336 &mut account2_account,
7337 &mut owner_account,
7338 ],
7339 )
7340 );
7341
7342 let mut account = Account::unpack_unchecked(&account_account.data).unwrap();
7344 account.state = AccountState::Frozen;
7345 Account::pack(account, &mut account_account.data).unwrap();
7346 let delegate_key = Pubkey::new_unique();
7347 let mut delegate_account = SolanaAccount::default();
7348 assert_eq!(
7349 Err(TokenError::AccountFrozen.into()),
7350 do_process_instruction(
7351 approve(
7352 &program_id,
7353 &account_key,
7354 &delegate_key,
7355 &owner_key,
7356 &[],
7357 100
7358 )
7359 .unwrap(),
7360 vec![
7361 &mut account_account,
7362 &mut delegate_account,
7363 &mut owner_account,
7364 ],
7365 )
7366 );
7367
7368 let mut account = Account::unpack_unchecked(&account_account.data).unwrap();
7370 account.delegate = COption::Some(delegate_key);
7371 account.delegated_amount = 100;
7372 Account::pack(account, &mut account_account.data).unwrap();
7373 assert_eq!(
7374 Err(TokenError::AccountFrozen.into()),
7375 do_process_instruction(
7376 revoke(&program_id, &account_key, &owner_key, &[]).unwrap(),
7377 vec![&mut account_account, &mut owner_account],
7378 )
7379 );
7380
7381 let new_owner_key = Pubkey::new_unique();
7383 assert_eq!(
7384 Err(TokenError::AccountFrozen.into()),
7385 do_process_instruction(
7386 set_authority(
7387 &program_id,
7388 &account_key,
7389 Some(&new_owner_key),
7390 AuthorityType::AccountOwner,
7391 &owner_key,
7392 &[]
7393 )
7394 .unwrap(),
7395 vec![&mut account_account, &mut owner_account,],
7396 )
7397 );
7398
7399 assert_eq!(
7401 Err(TokenError::AccountFrozen.into()),
7402 do_process_instruction(
7403 mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 100).unwrap(),
7404 vec![&mut mint_account, &mut account_account, &mut owner_account,],
7405 )
7406 );
7407
7408 assert_eq!(
7410 Err(TokenError::AccountFrozen.into()),
7411 do_process_instruction(
7412 burn(&program_id, &account_key, &mint_key, &owner_key, &[], 100).unwrap(),
7413 vec![&mut account_account, &mut mint_account, &mut owner_account],
7414 )
7415 );
7416 }
7417
7418 #[test]
7419 fn test_freeze_thaw_dups() {
7420 let program_id = crate::id();
7421 let account1_key = Pubkey::new_unique();
7422 let mut account1_account = SolanaAccount::new(
7423 account_minimum_balance(),
7424 Account::get_packed_len(),
7425 &program_id,
7426 );
7427 let account1_info: AccountInfo<'_> = (&account1_key, true, &mut account1_account).into();
7428 let owner_key = Pubkey::new_unique();
7429 let mint_key = Pubkey::new_unique();
7430 let mut mint_account =
7431 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
7432 let mint_info: AccountInfo<'_> = (&mint_key, true, &mut mint_account).into();
7433 let rent_key = rent::id();
7434 let mut rent_sysvar = rent_sysvar();
7435 let rent_info: AccountInfo<'_> = (&rent_key, false, &mut rent_sysvar).into();
7436
7437 do_process_instruction_dups(
7439 initialize_mint(&program_id, &mint_key, &owner_key, Some(&account1_key), 2).unwrap(),
7440 vec![mint_info.clone(), rent_info.clone()],
7441 )
7442 .unwrap();
7443
7444 do_process_instruction_dups(
7446 initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(),
7447 vec![
7448 account1_info.clone(),
7449 mint_info.clone(),
7450 account1_info.clone(),
7451 rent_info.clone(),
7452 ],
7453 )
7454 .unwrap();
7455
7456 do_process_instruction_dups(
7458 freeze_account(&program_id, &account1_key, &mint_key, &account1_key, &[]).unwrap(),
7459 vec![
7460 account1_info.clone(),
7461 mint_info.clone(),
7462 account1_info.clone(),
7463 ],
7464 )
7465 .unwrap();
7466
7467 let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap();
7469 account.state = AccountState::Frozen;
7470 Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap();
7471 do_process_instruction_dups(
7472 thaw_account(&program_id, &account1_key, &mint_key, &account1_key, &[]).unwrap(),
7473 vec![
7474 account1_info.clone(),
7475 mint_info.clone(),
7476 account1_info.clone(),
7477 ],
7478 )
7479 .unwrap();
7480 }
7481
7482 #[test]
7483 fn test_freeze_account() {
7484 let program_id = crate::id();
7485 let account_key = Pubkey::new_unique();
7486 let mut account_account = SolanaAccount::new(
7487 account_minimum_balance(),
7488 Account::get_packed_len(),
7489 &program_id,
7490 );
7491 let account_owner_key = Pubkey::new_unique();
7492 let mut account_owner_account = SolanaAccount::default();
7493 let owner_key = Pubkey::new_unique();
7494 let mut owner_account = SolanaAccount::default();
7495 let owner2_key = Pubkey::new_unique();
7496 let mut owner2_account = SolanaAccount::default();
7497 let mint_key = Pubkey::new_unique();
7498 let mut mint_account =
7499 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
7500 let mut rent_sysvar = rent_sysvar();
7501
7502 do_process_instruction(
7504 initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
7505 vec![&mut mint_account, &mut rent_sysvar],
7506 )
7507 .unwrap();
7508
7509 do_process_instruction(
7511 initialize_account(&program_id, &account_key, &mint_key, &account_owner_key).unwrap(),
7512 vec![
7513 &mut account_account,
7514 &mut mint_account,
7515 &mut account_owner_account,
7516 &mut rent_sysvar,
7517 ],
7518 )
7519 .unwrap();
7520
7521 do_process_instruction(
7523 mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(),
7524 vec![&mut mint_account, &mut account_account, &mut owner_account],
7525 )
7526 .unwrap();
7527
7528 assert_eq!(
7530 Err(TokenError::MintCannotFreeze.into()),
7531 do_process_instruction(
7532 freeze_account(&program_id, &account_key, &mint_key, &owner_key, &[]).unwrap(),
7533 vec![&mut account_account, &mut mint_account, &mut owner_account],
7534 )
7535 );
7536
7537 let mut mint = Mint::unpack_unchecked(&mint_account.data).unwrap();
7539 mint.freeze_authority = COption::Some(owner_key);
7540 Mint::pack(mint, &mut mint_account.data).unwrap();
7541 assert_eq!(
7542 Err(TokenError::OwnerMismatch.into()),
7543 do_process_instruction(
7544 freeze_account(&program_id, &account_key, &mint_key, &owner2_key, &[]).unwrap(),
7545 vec![&mut account_account, &mut mint_account, &mut owner2_account],
7546 )
7547 );
7548
7549 assert_eq!(
7551 Err(TokenError::InvalidState.into()),
7552 do_process_instruction(
7553 thaw_account(&program_id, &account_key, &mint_key, &owner2_key, &[]).unwrap(),
7554 vec![&mut account_account, &mut mint_account, &mut owner2_account],
7555 )
7556 );
7557
7558 do_process_instruction(
7560 freeze_account(&program_id, &account_key, &mint_key, &owner_key, &[]).unwrap(),
7561 vec![&mut account_account, &mut mint_account, &mut owner_account],
7562 )
7563 .unwrap();
7564 let account = Account::unpack_unchecked(&account_account.data).unwrap();
7565 assert_eq!(account.state, AccountState::Frozen);
7566
7567 assert_eq!(
7569 Err(TokenError::InvalidState.into()),
7570 do_process_instruction(
7571 freeze_account(&program_id, &account_key, &mint_key, &owner_key, &[]).unwrap(),
7572 vec![&mut account_account, &mut mint_account, &mut owner_account],
7573 )
7574 );
7575
7576 assert_eq!(
7578 Err(TokenError::OwnerMismatch.into()),
7579 do_process_instruction(
7580 thaw_account(&program_id, &account_key, &mint_key, &owner2_key, &[]).unwrap(),
7581 vec![&mut account_account, &mut mint_account, &mut owner2_account],
7582 )
7583 );
7584
7585 do_process_instruction(
7587 thaw_account(&program_id, &account_key, &mint_key, &owner_key, &[]).unwrap(),
7588 vec![&mut account_account, &mut mint_account, &mut owner_account],
7589 )
7590 .unwrap();
7591 let account = Account::unpack_unchecked(&account_account.data).unwrap();
7592 assert_eq!(account.state, AccountState::Initialized);
7593 }
7594
7595 #[test]
7596 fn test_initialize_account2_and_3() {
7597 let program_id = crate::id();
7598 let account_key = Pubkey::new_unique();
7599 let mut account_account = SolanaAccount::new(
7600 account_minimum_balance(),
7601 Account::get_packed_len(),
7602 &program_id,
7603 );
7604 let mut account2_account = SolanaAccount::new(
7605 account_minimum_balance(),
7606 Account::get_packed_len(),
7607 &program_id,
7608 );
7609 let mut account3_account = SolanaAccount::new(
7610 account_minimum_balance(),
7611 Account::get_packed_len(),
7612 &program_id,
7613 );
7614 let owner_key = Pubkey::new_unique();
7615 let mut owner_account = SolanaAccount::default();
7616 let mint_key = Pubkey::new_unique();
7617 let mut mint_account =
7618 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
7619 let mut rent_sysvar = rent_sysvar();
7620
7621 do_process_instruction(
7623 initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
7624 vec![&mut mint_account, &mut rent_sysvar],
7625 )
7626 .unwrap();
7627
7628 do_process_instruction(
7629 initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
7630 vec![
7631 &mut account_account,
7632 &mut mint_account,
7633 &mut owner_account,
7634 &mut rent_sysvar,
7635 ],
7636 )
7637 .unwrap();
7638
7639 do_process_instruction(
7640 initialize_account2(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
7641 vec![&mut account2_account, &mut mint_account, &mut rent_sysvar],
7642 )
7643 .unwrap();
7644
7645 assert_eq!(account_account, account2_account);
7646
7647 do_process_instruction(
7648 initialize_account3(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
7649 vec![&mut account3_account, &mut mint_account],
7650 )
7651 .unwrap();
7652
7653 assert_eq!(account_account, account3_account);
7654 }
7655
7656 #[test]
7657 fn initialize_account_on_non_transferable_mint() {
7658 let program_id = crate::id();
7659 let account = Pubkey::new_unique();
7660 let account_len = ExtensionType::try_calculate_account_len::<Mint>(&[
7661 ExtensionType::NonTransferableAccount,
7662 ])
7663 .unwrap();
7664 let mut account_without_enough_length = SolanaAccount::new(
7665 Rent::default().minimum_balance(account_len),
7666 account_len,
7667 &program_id,
7668 );
7669
7670 let account2 = Pubkey::new_unique();
7671 let account2_len = ExtensionType::try_calculate_account_len::<Mint>(&[
7672 ExtensionType::NonTransferableAccount,
7673 ExtensionType::ImmutableOwner,
7674 ])
7675 .unwrap();
7676 let mut account_with_enough_length = SolanaAccount::new(
7677 Rent::default().minimum_balance(account2_len),
7678 account2_len,
7679 &program_id,
7680 );
7681
7682 let owner_key = Pubkey::new_unique();
7683 let mut owner_account = SolanaAccount::default();
7684 let mint_key = Pubkey::new_unique();
7685 let mint_len =
7686 ExtensionType::try_calculate_account_len::<Mint>(&[ExtensionType::NonTransferable])
7687 .unwrap();
7688 let mut mint_account = SolanaAccount::new(
7689 Rent::default().minimum_balance(mint_len),
7690 mint_len,
7691 &program_id,
7692 );
7693 let mut rent_sysvar = rent_sysvar();
7694
7695 assert_eq!(
7697 Ok(()),
7698 do_process_instruction(
7699 initialize_non_transferable_mint(&program_id, &mint_key).unwrap(),
7700 vec![&mut mint_account],
7701 )
7702 );
7703 assert_eq!(
7704 Ok(()),
7705 do_process_instruction(
7706 initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
7707 vec![&mut mint_account, &mut rent_sysvar]
7708 )
7709 );
7710
7711 assert_eq!(
7714 Err(ProgramError::InvalidAccountData),
7715 do_process_instruction(
7716 initialize_account(&program_id, &account, &mint_key, &owner_key).unwrap(),
7717 vec![
7718 &mut account_without_enough_length,
7719 &mut mint_account,
7720 &mut owner_account,
7721 &mut rent_sysvar,
7722 ]
7723 )
7724 );
7725
7726 assert_eq!(
7728 Ok(()),
7729 do_process_instruction(
7730 initialize_account(&program_id, &account2, &mint_key, &owner_key).unwrap(),
7731 vec![
7732 &mut account_with_enough_length,
7733 &mut mint_account,
7734 &mut owner_account,
7735 &mut rent_sysvar,
7736 ]
7737 )
7738 );
7739 }
7740
7741 #[test]
7742 fn test_sync_native() {
7743 let program_id = crate::id();
7744 let mint_key = Pubkey::new_unique();
7745 let mut mint_account =
7746 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
7747 let native_account_key = Pubkey::new_unique();
7748 let kelvins = 40;
7749 let mut native_account = SolanaAccount::new(
7750 account_minimum_balance() + kelvins,
7751 Account::get_packed_len(),
7752 &program_id,
7753 );
7754 let non_native_account_key = Pubkey::new_unique();
7755 let mut non_native_account = SolanaAccount::new(
7756 account_minimum_balance() + 50,
7757 Account::get_packed_len(),
7758 &program_id,
7759 );
7760
7761 let owner_key = Pubkey::new_unique();
7762 let mut owner_account = SolanaAccount::default();
7763 let mut rent_sysvar = rent_sysvar();
7764
7765 do_process_instruction(
7767 initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
7768 vec![&mut mint_account, &mut rent_sysvar],
7769 )
7770 .unwrap();
7771
7772 do_process_instruction(
7774 initialize_account(&program_id, &non_native_account_key, &mint_key, &owner_key)
7775 .unwrap(),
7776 vec![
7777 &mut non_native_account,
7778 &mut mint_account,
7779 &mut owner_account,
7780 &mut rent_sysvar,
7781 ],
7782 )
7783 .unwrap();
7784
7785 let account = Account::unpack_unchecked(&non_native_account.data).unwrap();
7786 assert!(!account.is_native());
7787 assert_eq!(account.amount, 0);
7788
7789 assert_eq!(
7791 Err(TokenError::NonNativeNotSupported.into()),
7792 do_process_instruction(
7793 sync_native(&program_id, &non_native_account_key,).unwrap(),
7794 vec![&mut non_native_account],
7795 )
7796 );
7797
7798 assert_eq!(
7800 Err(ProgramError::UninitializedAccount),
7801 do_process_instruction(
7802 sync_native(&program_id, &native_account_key,).unwrap(),
7803 vec![&mut native_account],
7804 )
7805 );
7806
7807 do_process_instruction(
7809 initialize_account(
7810 &program_id,
7811 &native_account_key,
7812 &crate::native_mint::id(),
7813 &owner_key,
7814 )
7815 .unwrap(),
7816 vec![
7817 &mut native_account,
7818 &mut mint_account,
7819 &mut owner_account,
7820 &mut rent_sysvar,
7821 ],
7822 )
7823 .unwrap();
7824
7825 let not_program_id = Pubkey::new_unique();
7827 native_account.owner = not_program_id;
7828 assert_eq!(
7829 Err(ProgramError::IncorrectProgramId),
7830 do_process_instruction(
7831 sync_native(&program_id, &native_account_key,).unwrap(),
7832 vec![&mut native_account],
7833 )
7834 );
7835 native_account.owner = program_id;
7836
7837 let account = Account::unpack_unchecked(&native_account.data).unwrap();
7838 assert!(account.is_native());
7839 assert_eq!(account.amount, kelvins);
7840
7841 do_process_instruction(
7843 sync_native(&program_id, &native_account_key).unwrap(),
7844 vec![&mut native_account],
7845 )
7846 .unwrap();
7847 let account = Account::unpack_unchecked(&native_account.data).unwrap();
7848 assert_eq!(account.amount, kelvins);
7849
7850 let new_kelvins = kelvins + 50;
7852 native_account.kelvins = account_minimum_balance() + new_kelvins;
7853
7854 do_process_instruction(
7856 sync_native(&program_id, &native_account_key).unwrap(),
7857 vec![&mut native_account],
7858 )
7859 .unwrap();
7860 let account = Account::unpack_unchecked(&native_account.data).unwrap();
7861 assert_eq!(account.amount, new_kelvins);
7862
7863 native_account.kelvins -= 1;
7865
7866 assert_eq!(
7868 Err(TokenError::InvalidState.into()),
7869 do_process_instruction(
7870 sync_native(&program_id, &native_account_key,).unwrap(),
7871 vec![&mut native_account],
7872 )
7873 );
7874 }
7875
7876 #[test]
7877 #[serial]
7878 fn test_get_account_data_size() {
7879 let program_id = crate::id();
7881 let owner_key = Pubkey::new_unique();
7882 let mut owner_account = SolanaAccount::default();
7883 let mut rent_sysvar = rent_sysvar();
7884
7885 let mut mint_account =
7887 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
7888 let mint_key = Pubkey::new_unique();
7889 do_process_instruction(
7890 initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
7891 vec![&mut mint_account, &mut rent_sysvar],
7892 )
7893 .unwrap();
7894
7895 set_expected_data(
7896 ExtensionType::try_calculate_account_len::<Account>(&[])
7897 .unwrap()
7898 .to_le_bytes()
7899 .to_vec(),
7900 );
7901 do_process_instruction(
7902 get_account_data_size(&program_id, &mint_key, &[]).unwrap(),
7903 vec![&mut mint_account],
7904 )
7905 .unwrap();
7906
7907 set_expected_data(
7908 ExtensionType::try_calculate_account_len::<Account>(&[
7909 ExtensionType::TransferFeeAmount,
7910 ])
7911 .unwrap()
7912 .to_le_bytes()
7913 .to_vec(),
7914 );
7915 do_process_instruction(
7916 get_account_data_size(
7917 &program_id,
7918 &mint_key,
7919 &[
7920 ExtensionType::TransferFeeAmount,
7921 ExtensionType::TransferFeeAmount, ],
7923 )
7924 .unwrap(),
7925 vec![&mut mint_account],
7926 )
7927 .unwrap();
7928
7929 let mut mint_account = native_mint();
7931 set_expected_data(
7932 ExtensionType::try_calculate_account_len::<Account>(&[])
7933 .unwrap()
7934 .to_le_bytes()
7935 .to_vec(),
7936 );
7937 do_process_instruction(
7938 get_account_data_size(&program_id, &mint_key, &[]).unwrap(),
7939 vec![&mut mint_account],
7940 )
7941 .unwrap();
7942
7943 let mint_len =
7945 ExtensionType::try_calculate_account_len::<Mint>(&[ExtensionType::TransferFeeConfig])
7946 .unwrap();
7947 let mut extended_mint_account = SolanaAccount::new(
7948 Rent::default().minimum_balance(mint_len),
7949 mint_len,
7950 &program_id,
7951 );
7952 let extended_mint_key = Pubkey::new_unique();
7953 do_process_instruction(
7954 initialize_transfer_fee_config(&program_id, &extended_mint_key, None, None, 10, 4242)
7955 .unwrap(),
7956 vec![&mut extended_mint_account],
7957 )
7958 .unwrap();
7959 do_process_instruction(
7960 initialize_mint(&program_id, &extended_mint_key, &owner_key, None, 2).unwrap(),
7961 vec![&mut extended_mint_account, &mut rent_sysvar],
7962 )
7963 .unwrap();
7964
7965 set_expected_data(
7966 ExtensionType::try_calculate_account_len::<Account>(&[
7967 ExtensionType::TransferFeeAmount,
7968 ])
7969 .unwrap()
7970 .to_le_bytes()
7971 .to_vec(),
7972 );
7973 do_process_instruction(
7974 get_account_data_size(&program_id, &mint_key, &[]).unwrap(),
7975 vec![&mut extended_mint_account],
7976 )
7977 .unwrap();
7978
7979 do_process_instruction(
7980 get_account_data_size(
7981 &program_id,
7982 &mint_key,
7983 &[ExtensionType::TransferFeeAmount],
7985 )
7986 .unwrap(),
7987 vec![&mut extended_mint_account],
7988 )
7989 .unwrap();
7990
7991 let mut invalid_mint_account = SolanaAccount::new(
7993 account_minimum_balance(),
7994 Account::get_packed_len(),
7995 &program_id,
7996 );
7997 let invalid_mint_key = Pubkey::new_unique();
7998 do_process_instruction(
7999 initialize_account(&program_id, &invalid_mint_key, &mint_key, &owner_key).unwrap(),
8000 vec![
8001 &mut invalid_mint_account,
8002 &mut mint_account,
8003 &mut owner_account,
8004 &mut rent_sysvar,
8005 ],
8006 )
8007 .unwrap();
8008
8009 assert_eq!(
8010 do_process_instruction(
8011 get_account_data_size(&program_id, &invalid_mint_key, &[]).unwrap(),
8012 vec![&mut invalid_mint_account],
8013 ),
8014 Err(TokenError::InvalidMint.into())
8015 );
8016
8017 let invalid_program_id = Pubkey::new_unique();
8019 let mut invalid_mint_account = SolanaAccount::new(
8020 mint_minimum_balance(),
8021 Mint::get_packed_len(),
8022 &invalid_program_id,
8023 );
8024 let invalid_mint_key = Pubkey::new_unique();
8025 let mut instruction =
8026 initialize_mint(&program_id, &invalid_mint_key, &owner_key, None, 2).unwrap();
8027 instruction.program_id = invalid_program_id;
8028 do_process_instruction(
8029 instruction,
8030 vec![&mut invalid_mint_account, &mut rent_sysvar],
8031 )
8032 .unwrap();
8033
8034 assert_eq!(
8035 do_process_instruction(
8036 get_account_data_size(&program_id, &invalid_mint_key, &[]).unwrap(),
8037 vec![&mut invalid_mint_account],
8038 ),
8039 Err(ProgramError::IncorrectProgramId)
8040 );
8041
8042 assert_eq!(
8044 do_process_instruction(
8045 get_account_data_size(&program_id, &mint_key, &[ExtensionType::Uninitialized])
8046 .unwrap(),
8047 vec![&mut mint_account],
8048 ),
8049 Err(TokenError::ExtensionTypeMismatch.into())
8050 );
8051 assert_eq!(
8052 do_process_instruction(
8053 get_account_data_size(
8054 &program_id,
8055 &mint_key,
8056 &[
8057 ExtensionType::MemoTransfer,
8058 ExtensionType::MintCloseAuthority
8059 ]
8060 )
8061 .unwrap(),
8062 vec![&mut mint_account],
8063 ),
8064 Err(TokenError::ExtensionTypeMismatch.into())
8065 );
8066 }
8067
8068 #[test]
8069 #[serial]
8070 fn test_amount_to_ui_amount() {
8071 let program_id = crate::id();
8072 let owner_key = Pubkey::new_unique();
8073 let mint_key = Pubkey::new_unique();
8074 let mut mint_account =
8075 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
8076 let mut rent_sysvar = rent_sysvar();
8077
8078 assert_eq!(
8080 Err(TokenError::InvalidMint.into()),
8081 do_process_instruction(
8082 amount_to_ui_amount(&program_id, &mint_key, 110).unwrap(),
8083 vec![&mut mint_account],
8084 )
8085 );
8086
8087 do_process_instruction(
8089 initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
8090 vec![&mut mint_account, &mut rent_sysvar],
8091 )
8092 .unwrap();
8093
8094 set_expected_data("0.23".as_bytes().to_vec());
8095 do_process_instruction(
8096 amount_to_ui_amount(&program_id, &mint_key, 23).unwrap(),
8097 vec![&mut mint_account],
8098 )
8099 .unwrap();
8100
8101 set_expected_data("1.1".as_bytes().to_vec());
8102 do_process_instruction(
8103 amount_to_ui_amount(&program_id, &mint_key, 110).unwrap(),
8104 vec![&mut mint_account],
8105 )
8106 .unwrap();
8107
8108 set_expected_data("42".as_bytes().to_vec());
8109 do_process_instruction(
8110 amount_to_ui_amount(&program_id, &mint_key, 4200).unwrap(),
8111 vec![&mut mint_account],
8112 )
8113 .unwrap();
8114
8115 set_expected_data("0".as_bytes().to_vec());
8116 do_process_instruction(
8117 amount_to_ui_amount(&program_id, &mint_key, 0).unwrap(),
8118 vec![&mut mint_account],
8119 )
8120 .unwrap();
8121 }
8122
8123 #[test]
8124 #[serial]
8125 fn test_ui_amount_to_amount() {
8126 let program_id = crate::id();
8127 let owner_key = Pubkey::new_unique();
8128 let mint_key = Pubkey::new_unique();
8129 let mut mint_account =
8130 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
8131 let mut rent_sysvar = rent_sysvar();
8132
8133 assert_eq!(
8135 Err(TokenError::InvalidMint.into()),
8136 do_process_instruction(
8137 ui_amount_to_amount(&program_id, &mint_key, "1.1").unwrap(),
8138 vec![&mut mint_account],
8139 )
8140 );
8141
8142 do_process_instruction(
8144 initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
8145 vec![&mut mint_account, &mut rent_sysvar],
8146 )
8147 .unwrap();
8148
8149 set_expected_data(23u64.to_le_bytes().to_vec());
8150 do_process_instruction(
8151 ui_amount_to_amount(&program_id, &mint_key, "0.23").unwrap(),
8152 vec![&mut mint_account],
8153 )
8154 .unwrap();
8155
8156 set_expected_data(20u64.to_le_bytes().to_vec());
8157 do_process_instruction(
8158 ui_amount_to_amount(&program_id, &mint_key, "0.20").unwrap(),
8159 vec![&mut mint_account],
8160 )
8161 .unwrap();
8162
8163 set_expected_data(20u64.to_le_bytes().to_vec());
8164 do_process_instruction(
8165 ui_amount_to_amount(&program_id, &mint_key, "0.2000").unwrap(),
8166 vec![&mut mint_account],
8167 )
8168 .unwrap();
8169
8170 set_expected_data(20u64.to_le_bytes().to_vec());
8171 do_process_instruction(
8172 ui_amount_to_amount(&program_id, &mint_key, ".20").unwrap(),
8173 vec![&mut mint_account],
8174 )
8175 .unwrap();
8176
8177 set_expected_data(110u64.to_le_bytes().to_vec());
8178 do_process_instruction(
8179 ui_amount_to_amount(&program_id, &mint_key, "1.1").unwrap(),
8180 vec![&mut mint_account],
8181 )
8182 .unwrap();
8183
8184 set_expected_data(110u64.to_le_bytes().to_vec());
8185 do_process_instruction(
8186 ui_amount_to_amount(&program_id, &mint_key, "1.10").unwrap(),
8187 vec![&mut mint_account],
8188 )
8189 .unwrap();
8190
8191 set_expected_data(4200u64.to_le_bytes().to_vec());
8192 do_process_instruction(
8193 ui_amount_to_amount(&program_id, &mint_key, "42").unwrap(),
8194 vec![&mut mint_account],
8195 )
8196 .unwrap();
8197
8198 set_expected_data(4200u64.to_le_bytes().to_vec());
8199 do_process_instruction(
8200 ui_amount_to_amount(&program_id, &mint_key, "42.").unwrap(),
8201 vec![&mut mint_account],
8202 )
8203 .unwrap();
8204
8205 set_expected_data(0u64.to_le_bytes().to_vec());
8206 do_process_instruction(
8207 ui_amount_to_amount(&program_id, &mint_key, "0").unwrap(),
8208 vec![&mut mint_account],
8209 )
8210 .unwrap();
8211
8212 assert_eq!(
8214 Err(ProgramError::InvalidArgument),
8215 do_process_instruction(
8216 ui_amount_to_amount(&program_id, &mint_key, "").unwrap(),
8217 vec![&mut mint_account],
8218 )
8219 );
8220 assert_eq!(
8221 Err(ProgramError::InvalidArgument),
8222 do_process_instruction(
8223 ui_amount_to_amount(&program_id, &mint_key, ".").unwrap(),
8224 vec![&mut mint_account],
8225 )
8226 );
8227 assert_eq!(
8228 Err(ProgramError::InvalidArgument),
8229 do_process_instruction(
8230 ui_amount_to_amount(&program_id, &mint_key, "0.111").unwrap(),
8231 vec![&mut mint_account],
8232 )
8233 );
8234 assert_eq!(
8235 Err(ProgramError::InvalidArgument),
8236 do_process_instruction(
8237 ui_amount_to_amount(&program_id, &mint_key, "0.t").unwrap(),
8238 vec![&mut mint_account],
8239 )
8240 );
8241 }
8242
8243 #[test]
8244 #[serial]
8245 fn test_withdraw_excess_kelvins_from_multisig() {
8246 {
8247 use std::sync::Once;
8248 static ONCE: Once = Once::new();
8249
8250 ONCE.call_once(|| {
8251 rialo_s_sysvar::program_stubs::set_syscall_stubs(Box::new(SyscallStubs {}));
8252 });
8253 }
8254 let program_id = crate::id();
8255
8256 let mut kelvins = 0;
8257 let mut destination_data = vec![];
8258 let system_program_id = system_program::id();
8259 let destination_key = Pubkey::new_unique();
8260 let destination_info = AccountInfo::new(
8261 &destination_key,
8262 true,
8263 false,
8264 &mut kelvins,
8265 &mut destination_data,
8266 &system_program_id,
8267 false,
8268 Epoch::default(),
8269 );
8270
8271 let multisig_key = Pubkey::new_unique();
8272 let mut multisig_account = SolanaAccount::new(0, Multisig::get_packed_len(), &program_id);
8273 let excess_kelvins = 4_000_000_000_000;
8274 multisig_account.kelvins = excess_kelvins + multisig_minimum_balance();
8275 let mut signer_keys = [Pubkey::default(); MAX_SIGNERS];
8276
8277 for signer_key in signer_keys.iter_mut().take(MAX_SIGNERS) {
8278 *signer_key = Pubkey::new_unique();
8279 }
8280 let signer_refs: Vec<&Pubkey> = signer_keys.iter().collect();
8281 let mut signer_kelvins = 0;
8282 let mut signer_data = vec![];
8283 let mut signers: Vec<AccountInfo<'_>> = vec![
8284 AccountInfo::new(
8285 &destination_key,
8286 true,
8287 false,
8288 &mut signer_kelvins,
8289 &mut signer_data,
8290 &program_id,
8291 false,
8292 Epoch::default(),
8293 );
8294 MAX_SIGNERS + 1
8295 ];
8296 for (signer, key) in signers.iter_mut().zip(&signer_keys) {
8297 signer.key = key;
8298 }
8299
8300 let mut multisig =
8301 Multisig::unpack_unchecked(&vec![0; Multisig::get_packed_len()]).unwrap();
8302 multisig.m = MAX_SIGNERS as u8;
8303 multisig.n = MAX_SIGNERS as u8;
8304 multisig.signers = signer_keys;
8305 multisig.is_initialized = true;
8306 Multisig::pack(multisig, &mut multisig_account.data).unwrap();
8307
8308 let multisig_info: AccountInfo<'_> = (&multisig_key, true, &mut multisig_account).into();
8309
8310 let mut signers_infos = vec![
8311 multisig_info.clone(),
8312 destination_info.clone(),
8313 multisig_info.clone(),
8314 ];
8315 signers_infos.extend(signers);
8316 do_process_instruction_dups(
8317 withdraw_excess_kelvins(
8318 &program_id,
8319 &multisig_key,
8320 &destination_key,
8321 &multisig_key,
8322 &signer_refs,
8323 )
8324 .unwrap(),
8325 signers_infos,
8326 )
8327 .unwrap();
8328
8329 assert_eq!(destination_info.kelvins(), excess_kelvins);
8330 }
8331
8332 #[test]
8333 #[serial]
8334 fn test_withdraw_excess_kelvins_from_account() {
8335 let excess_kelvins = 4_000_000_000_000;
8336
8337 let program_id = crate::id();
8338 let account_key = Pubkey::new_unique();
8339 let mut account_account = SolanaAccount::new(
8340 excess_kelvins + account_minimum_balance(),
8341 Account::get_packed_len(),
8342 &program_id,
8343 );
8344
8345 let system_program_id = system_program::id();
8346 let owner_key = Pubkey::new_unique();
8347
8348 let mut destination_kelvins = 0;
8349 let mut destination_data = vec![];
8350 let destination_key = Pubkey::new_unique();
8351 let destination_info = AccountInfo::new(
8352 &destination_key,
8353 true,
8354 false,
8355 &mut destination_kelvins,
8356 &mut destination_data,
8357 &system_program_id,
8358 false,
8359 Epoch::default(),
8360 );
8361 let mint_key = Pubkey::new_unique();
8362 let mut mint_account =
8363 SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
8364
8365 let mut rent_sysvar = rent_sysvar();
8366 do_process_instruction(
8367 initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
8368 vec![&mut mint_account, &mut rent_sysvar],
8369 )
8370 .unwrap();
8371
8372 let mint_info = AccountInfo::new(
8373 &mint_key,
8374 true,
8375 false,
8376 &mut mint_account.kelvins,
8377 &mut mint_account.data,
8378 &program_id,
8379 false,
8380 Epoch::default(),
8381 );
8382
8383 let account_info: AccountInfo<'_> = (&account_key, true, &mut account_account).into();
8384
8385 do_process_instruction_dups(
8386 initialize_account3(&program_id, &account_key, &mint_key, &account_key).unwrap(),
8387 vec![account_info.clone(), mint_info.clone()],
8388 )
8389 .unwrap();
8390
8391 do_process_instruction_dups(
8392 withdraw_excess_kelvins(
8393 &program_id,
8394 &account_key,
8395 &destination_key,
8396 &account_key,
8397 &[],
8398 )
8399 .unwrap(),
8400 vec![
8401 account_info.clone(),
8402 destination_info.clone(),
8403 account_info.clone(),
8404 ],
8405 )
8406 .unwrap();
8407
8408 assert_eq!(destination_info.kelvins(), excess_kelvins);
8409 }
8410
8411 #[test]
8412 #[serial]
8413 fn test_withdraw_excess_kelvins_from_mint() {
8414 let excess_kelvins = 4_000_000_000_000;
8415
8416 let program_id = crate::id();
8417 let system_program_id = system_program::id();
8418
8419 let mut destination_kelvins = 0;
8420 let mut destination_data = vec![];
8421 let destination_key = Pubkey::new_unique();
8422 let destination_info = AccountInfo::new(
8423 &destination_key,
8424 true,
8425 false,
8426 &mut destination_kelvins,
8427 &mut destination_data,
8428 &system_program_id,
8429 false,
8430 Epoch::default(),
8431 );
8432 let mint_key = Pubkey::new_unique();
8433 let mut mint_account = SolanaAccount::new(
8434 excess_kelvins + mint_minimum_balance(),
8435 Mint::get_packed_len(),
8436 &program_id,
8437 );
8438 let mut rent_sysvar = rent_sysvar();
8439
8440 do_process_instruction(
8441 initialize_mint(&program_id, &mint_key, &mint_key, None, 2).unwrap(),
8442 vec![&mut mint_account, &mut rent_sysvar],
8443 )
8444 .unwrap();
8445
8446 let mint_info: AccountInfo<'_> = (&mint_key, true, &mut mint_account).into();
8447
8448 do_process_instruction_dups(
8449 withdraw_excess_kelvins(&program_id, &mint_key, &destination_key, &mint_key, &[])
8450 .unwrap(),
8451 vec![
8452 mint_info.clone(),
8453 destination_info.clone(),
8454 mint_info.clone(),
8455 ],
8456 )
8457 .unwrap();
8458
8459 assert_eq!(destination_info.kelvins(), excess_kelvins);
8460 }
8461
8462 #[test]
8463 #[serial]
8464 fn test_withdraw_excess_kelvins_from_mint_with_no_mint_authority() {
8465 let excess_kelvins = 4_000_000_000_000;
8466
8467 let program_id = crate::id();
8468 let system_program_id = system_program::id();
8469
8470 let mut destination_kelvins = 0;
8471 let mut destination_data = vec![];
8472 let destination_key = Pubkey::new_unique();
8473 let destination_info = AccountInfo::new(
8474 &destination_key,
8475 true,
8476 false,
8477 &mut destination_kelvins,
8478 &mut destination_data,
8479 &system_program_id,
8480 false,
8481 Epoch::default(),
8482 );
8483 let mint_key = Pubkey::new_unique();
8484 let mut mint_account = SolanaAccount::new(
8485 excess_kelvins + mint_minimum_balance(),
8486 Mint::get_packed_len(),
8487 &program_id,
8488 );
8489 let mut mint_authority_kelvins = 0;
8490 let mut mint_authority_data = vec![];
8491 let mint_authority_key = Pubkey::new_unique();
8492 let mint_authority_info = AccountInfo::new(
8493 &mint_authority_key,
8494 true,
8495 false,
8496 &mut mint_authority_kelvins,
8497 &mut mint_authority_data,
8498 &system_program_id,
8499 false,
8500 Epoch::default(),
8501 );
8502 let mut rent_sysvar = rent_sysvar();
8503
8504 do_process_instruction(
8505 initialize_mint(&program_id, &mint_key, &mint_authority_key, None, 2).unwrap(),
8506 vec![&mut mint_account, &mut rent_sysvar],
8507 )
8508 .unwrap();
8509
8510 let mint_info: AccountInfo<'_> = (&mint_key, true, &mut mint_account).into();
8511
8512 assert_eq!(
8515 Err(TokenError::OwnerMismatch.into()),
8516 do_process_instruction_dups(
8517 withdraw_excess_kelvins(&program_id, &mint_key, &destination_key, &mint_key, &[])
8518 .unwrap(),
8519 vec![
8520 mint_info.clone(),
8521 destination_info.clone(),
8522 mint_info.clone(),
8523 ],
8524 )
8525 );
8526
8527 do_process_instruction_dups(
8528 set_authority(
8529 &program_id,
8530 &mint_key,
8531 None,
8532 AuthorityType::MintTokens,
8533 &mint_authority_key,
8534 &[],
8535 )
8536 .unwrap(),
8537 vec![mint_info.clone(), mint_authority_info.clone()],
8538 )
8539 .unwrap();
8540
8541 assert_eq!(
8543 Err(TokenError::AuthorityTypeNotSupported.into()),
8544 do_process_instruction_dups(
8545 withdraw_excess_kelvins(
8546 &program_id,
8547 &mint_key,
8548 &destination_key,
8549 &mint_authority_key,
8550 &[]
8551 )
8552 .unwrap(),
8553 vec![
8554 mint_info.clone(),
8555 destination_info.clone(),
8556 mint_authority_info.clone(),
8557 ],
8558 )
8559 );
8560
8561 do_process_instruction_dups(
8562 withdraw_excess_kelvins(&program_id, &mint_key, &destination_key, &mint_key, &[])
8563 .unwrap(),
8564 vec![
8565 mint_info.clone(),
8566 destination_info.clone(),
8567 mint_info.clone(),
8568 ],
8569 )
8570 .unwrap();
8571
8572 assert_eq!(destination_info.kelvins(), excess_kelvins);
8573 }
8574}