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