Skip to main content

spl_token_2022/
processor.rs

1//! Program state processor
2
3use {
4    crate::{
5        extension::{
6            confidential_mint_burn, confidential_transfer, confidential_transfer_fee,
7            cpi_guard::{self, in_cpi},
8            default_account_state, group_member_pointer, group_pointer, interest_bearing_mint,
9            memo_transfer::{self, check_previous_sibling_instruction_is_memo},
10            metadata_pointer, pausable, permissioned_burn, reallocate, scaled_ui_amount,
11            token_group, token_metadata, transfer_fee, transfer_hook,
12        },
13        pod_instruction::{
14            decode_instruction_data_with_coption_pubkey, decode_instruction_data_with_coption_u64,
15            AmountCheckedData, AmountData, InitializeMintData, InitializeMultisigData,
16            PodTokenInstruction, SetAuthorityData,
17        },
18    },
19    solana_account_info::{next_account_info, AccountInfo},
20    solana_address::Address,
21    solana_clock::Clock,
22    solana_cpi::{invoke, invoke_signed, set_return_data},
23    solana_msg::msg,
24    solana_program_error::{ProgramError, ProgramResult},
25    solana_program_pack::Pack,
26    solana_rent::Rent,
27    solana_sdk_ids::system_program,
28    solana_system_interface::instruction as system_instruction,
29    solana_sysvar::{Sysvar, SysvarSerialize},
30    solana_zero_copy::unaligned::U64,
31    spl_token_2022_interface::{
32        check_program_account,
33        error::TokenError,
34        extension::{
35            confidential_mint_burn::ConfidentialMintBurn,
36            confidential_transfer::{ConfidentialTransferAccount, ConfidentialTransferMint},
37            confidential_transfer_fee::{
38                ConfidentialTransferFeeAmount, ConfidentialTransferFeeConfig,
39            },
40            cpi_guard::CpiGuard,
41            default_account_state::DefaultAccountState,
42            group_member_pointer::GroupMemberPointer,
43            group_pointer::GroupPointer,
44            immutable_owner::ImmutableOwner,
45            interest_bearing_mint::InterestBearingConfig,
46            memo_transfer::memo_required,
47            metadata_pointer::MetadataPointer,
48            mint_close_authority::MintCloseAuthority,
49            non_transferable::{NonTransferable, NonTransferableAccount},
50            pausable::{PausableAccount, PausableConfig},
51            permanent_delegate::{get_permanent_delegate, PermanentDelegate},
52            permissioned_burn::PermissionedBurnConfig,
53            scaled_ui_amount::ScaledUiAmountConfig,
54            transfer_fee::{TransferFeeAmount, TransferFeeConfig},
55            transfer_hook::{TransferHook, TransferHookAccount},
56            AccountType, BaseStateWithExtensions, BaseStateWithExtensionsMut, ExtensionType,
57            PodStateWithExtensions, PodStateWithExtensionsMut,
58        },
59        inline_spl_token,
60        instruction::{
61            decode_instruction_data, decode_instruction_type, is_valid_signer_index, AuthorityType,
62            MAX_SIGNERS,
63        },
64        native_mint,
65        pod::{PodAccount, PodCOption, PodMint, PodMultisig},
66        state::{Account, AccountState, Mint, PackedSizeOf},
67    },
68    spl_token_group_interface::instruction::TokenGroupInstruction,
69    spl_token_metadata_interface::instruction::TokenMetadataInstruction,
70    std::convert::{TryFrom, TryInto},
71};
72
73pub(crate) enum TransferInstruction {
74    Unchecked,
75    Checked { decimals: u8 },
76    CheckedWithFee { decimals: u8, fee: u64 },
77}
78
79pub(crate) enum InstructionVariant {
80    Unchecked,
81    Checked { decimals: u8 },
82}
83
84/// Burn instruction variant. Standard variants must not be used with the
85/// permissioned burn extension.
86///
87/// Permissioned variants require the extra authority to sign.
88pub(crate) enum BurnInstructionVariant {
89    Standard,
90    Permissioned,
91}
92
93/// Program state handler.
94pub struct Processor {}
95impl Processor {
96    fn _process_initialize_mint(
97        accounts: &[AccountInfo],
98        decimals: u8,
99        mint_authority: &Address,
100        freeze_authority: PodCOption<Address>,
101        rent_sysvar_account: bool,
102    ) -> ProgramResult {
103        let account_info_iter = &mut accounts.iter();
104        let mint_info = next_account_info(account_info_iter)?;
105        let mint_data_len = mint_info.data_len();
106        let mut mint_data = mint_info.data.borrow_mut();
107
108        check_program_account(mint_info.owner)?;
109
110        let rent = if rent_sysvar_account {
111            Rent::from_account_info(next_account_info(account_info_iter)?)?
112        } else {
113            Rent::get()?
114        };
115
116        if !rent.is_exempt(mint_info.lamports(), mint_data_len) {
117            return Err(TokenError::NotRentExempt.into());
118        }
119
120        let mut mint = PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut mint_data)?;
121        let extension_types = mint.get_extension_types()?;
122        if ExtensionType::try_calculate_account_len::<Mint>(&extension_types)? != mint_data_len {
123            return Err(ProgramError::InvalidAccountData);
124        }
125        ExtensionType::check_for_invalid_mint_extension_combinations(&extension_types)?;
126
127        if let Ok(default_account_state) = mint.get_extension_mut::<DefaultAccountState>() {
128            let default_account_state = AccountState::try_from(default_account_state.state)
129                .or(Err(ProgramError::InvalidAccountData))?;
130            if default_account_state == AccountState::Frozen && freeze_authority.is_none() {
131                return Err(TokenError::MintCannotFreeze.into());
132            }
133        }
134
135        mint.base.mint_authority = PodCOption::some(*mint_authority);
136        mint.base.decimals = decimals;
137        mint.base.is_initialized = true.into();
138        mint.base.freeze_authority = freeze_authority;
139        mint.init_account_type()?;
140
141        Ok(())
142    }
143
144    /// Processes an [`InitializeMint`](enum.TokenInstruction.html) instruction.
145    pub fn process_initialize_mint(
146        accounts: &[AccountInfo],
147        decimals: u8,
148        mint_authority: &Address,
149        freeze_authority: PodCOption<Address>,
150    ) -> ProgramResult {
151        Self::_process_initialize_mint(accounts, decimals, mint_authority, freeze_authority, true)
152    }
153
154    /// Processes an [`InitializeMint2`](enum.TokenInstruction.html)
155    /// instruction.
156    pub fn process_initialize_mint2(
157        accounts: &[AccountInfo],
158        decimals: u8,
159        mint_authority: &Address,
160        freeze_authority: PodCOption<Address>,
161    ) -> ProgramResult {
162        Self::_process_initialize_mint(accounts, decimals, mint_authority, freeze_authority, false)
163    }
164
165    fn _process_initialize_account(
166        accounts: &[AccountInfo],
167        owner: Option<&Address>,
168        rent_sysvar_account: bool,
169    ) -> ProgramResult {
170        let account_info_iter = &mut accounts.iter();
171        let new_account_info = next_account_info(account_info_iter)?;
172        let mint_info = next_account_info(account_info_iter)?;
173
174        check_program_account(new_account_info.owner)?;
175        check_program_account(mint_info.owner)?;
176
177        let owner = if let Some(owner) = owner {
178            owner
179        } else {
180            next_account_info(account_info_iter)?.key
181        };
182        let new_account_info_data_len = new_account_info.data_len();
183        let rent = if rent_sysvar_account {
184            Rent::from_account_info(next_account_info(account_info_iter)?)?
185        } else {
186            Rent::get()?
187        };
188
189        let mut account_data = new_account_info.data.borrow_mut();
190        // unpack_uninitialized checks account.base.is_initialized() under the hood
191        let mut account =
192            PodStateWithExtensionsMut::<PodAccount>::unpack_uninitialized(&mut account_data)?;
193
194        if !rent.is_exempt(new_account_info.lamports(), new_account_info_data_len) {
195            return Err(TokenError::NotRentExempt.into());
196        }
197
198        // get_required_account_extensions checks mint validity
199        let mint_data = mint_info.data.borrow();
200        let mint = PodStateWithExtensions::<PodMint>::unpack(&mint_data)
201            .map_err(|_| Into::<ProgramError>::into(TokenError::InvalidMint))?;
202        if mint
203            .get_extension::<PermanentDelegate>()
204            .map(|e| Option::<Address>::from(e.delegate).is_some())
205            .unwrap_or(false)
206        {
207            msg!("Warning: Mint has a permanent delegate, so tokens in this account may be seized at any time");
208        }
209        let required_extensions =
210            Self::get_required_account_extensions_from_unpacked_mint(mint_info.owner, &mint)?;
211        if ExtensionType::try_calculate_account_len::<Account>(&required_extensions)?
212            > new_account_info_data_len
213        {
214            return Err(ProgramError::InvalidAccountData);
215        }
216        for extension in required_extensions {
217            account.init_account_extension_from_type(extension)?;
218        }
219
220        let starting_state =
221            if let Ok(default_account_state) = mint.get_extension::<DefaultAccountState>() {
222                AccountState::try_from(default_account_state.state)
223                    .or(Err(ProgramError::InvalidAccountData))?
224            } else {
225                AccountState::Initialized
226            };
227
228        account.base.mint = *mint_info.key;
229        account.base.owner = *owner;
230        account.base.close_authority = PodCOption::none();
231        account.base.delegate = PodCOption::none();
232        account.base.delegated_amount = 0.into();
233        account.base.state = starting_state.into();
234        if mint_info.key == &native_mint::id() {
235            let rent_exempt_reserve = rent.minimum_balance(new_account_info_data_len);
236            account.base.is_native = PodCOption::some(rent_exempt_reserve.into());
237            account.base.amount = new_account_info
238                .lamports()
239                .checked_sub(rent_exempt_reserve)
240                .ok_or(TokenError::Overflow)?
241                .into();
242        } else {
243            account.base.is_native = PodCOption::none();
244            account.base.amount = 0.into();
245        };
246
247        account.init_account_type()?;
248
249        Ok(())
250    }
251
252    /// Processes an [`InitializeAccount`](enum.TokenInstruction.html)
253    /// instruction.
254    pub fn process_initialize_account(accounts: &[AccountInfo]) -> ProgramResult {
255        Self::_process_initialize_account(accounts, None, true)
256    }
257
258    /// Processes an [`InitializeAccount2`](enum.TokenInstruction.html)
259    /// instruction.
260    pub fn process_initialize_account2(accounts: &[AccountInfo], owner: &Address) -> ProgramResult {
261        Self::_process_initialize_account(accounts, Some(owner), true)
262    }
263
264    /// Processes an [`InitializeAccount3`](enum.TokenInstruction.html)
265    /// instruction.
266    pub fn process_initialize_account3(accounts: &[AccountInfo], owner: &Address) -> ProgramResult {
267        Self::_process_initialize_account(accounts, Some(owner), false)
268    }
269
270    fn _process_initialize_multisig(
271        accounts: &[AccountInfo],
272        m: u8,
273        rent_sysvar_account: bool,
274    ) -> ProgramResult {
275        let account_info_iter = &mut accounts.iter();
276        let multisig_info = next_account_info(account_info_iter)?;
277
278        check_program_account(multisig_info.owner)?;
279
280        let multisig_info_data_len = multisig_info.data_len();
281        let rent = if rent_sysvar_account {
282            Rent::from_account_info(next_account_info(account_info_iter)?)?
283        } else {
284            Rent::get()?
285        };
286
287        let mut multisig_data = multisig_info.data.borrow_mut();
288        let multisig = bytemuck::try_from_bytes_mut::<PodMultisig>(&mut multisig_data)
289            .map_err(|_| ProgramError::InvalidArgument)?;
290        if bool::from(multisig.is_initialized) {
291            return Err(TokenError::AlreadyInUse.into());
292        }
293
294        if !rent.is_exempt(multisig_info.lamports(), multisig_info_data_len) {
295            return Err(TokenError::NotRentExempt.into());
296        }
297
298        let signer_infos = account_info_iter.as_slice();
299        multisig.m = m;
300        multisig.n = signer_infos.len() as u8;
301        if !is_valid_signer_index(multisig.n as usize) {
302            return Err(TokenError::InvalidNumberOfProvidedSigners.into());
303        }
304        if !is_valid_signer_index(multisig.m as usize) {
305            return Err(TokenError::InvalidNumberOfRequiredSigners.into());
306        }
307        for (i, signer_info) in signer_infos.iter().enumerate() {
308            multisig.signers[i] = *signer_info.key;
309        }
310        multisig.is_initialized = true.into();
311
312        Ok(())
313    }
314
315    /// Processes a [`InitializeMultisig`](enum.TokenInstruction.html)
316    /// instruction.
317    pub fn process_initialize_multisig(accounts: &[AccountInfo], m: u8) -> ProgramResult {
318        Self::_process_initialize_multisig(accounts, m, true)
319    }
320
321    /// Processes a [`InitializeMultisig2`](enum.TokenInstruction.html)
322    /// instruction.
323    pub fn process_initialize_multisig2(accounts: &[AccountInfo], m: u8) -> ProgramResult {
324        Self::_process_initialize_multisig(accounts, m, false)
325    }
326
327    /// Processes a [`Transfer`](enum.TokenInstruction.html) instruction.
328    pub(crate) fn process_transfer(
329        program_id: &Address,
330        accounts: &[AccountInfo],
331        amount: u64,
332        transfer_instruction: TransferInstruction,
333    ) -> ProgramResult {
334        let account_info_iter = &mut accounts.iter();
335
336        let source_account_info = next_account_info(account_info_iter)?;
337
338        let expected_mint_info = match transfer_instruction {
339            TransferInstruction::Unchecked => None,
340            TransferInstruction::Checked { decimals }
341            | TransferInstruction::CheckedWithFee { decimals, .. } => {
342                Some((next_account_info(account_info_iter)?, decimals))
343            }
344        };
345
346        let destination_account_info = next_account_info(account_info_iter)?;
347        let authority_info = next_account_info(account_info_iter)?;
348        let authority_info_data_len = authority_info.data_len();
349
350        check_program_account(source_account_info.owner)?;
351        check_program_account(destination_account_info.owner)?;
352
353        let mut source_account_data = source_account_info.data.borrow_mut();
354        let mut source_account =
355            PodStateWithExtensionsMut::<PodAccount>::unpack(&mut source_account_data)?;
356        if source_account.base.is_frozen() {
357            return Err(TokenError::AccountFrozen.into());
358        }
359        let source_amount = u64::from(source_account.base.amount);
360        if source_amount < amount {
361            return Err(TokenError::InsufficientFunds.into());
362        }
363        if source_account
364            .get_extension::<NonTransferableAccount>()
365            .is_ok()
366        {
367            return Err(TokenError::NonTransferable.into());
368        }
369
370        let (calculated_fee, maybe_permanent_delegate, maybe_transfer_hook_program_id) =
371            if let Some((mint_info, expected_decimals)) = expected_mint_info {
372                check_program_account(mint_info.owner)?;
373
374                if &source_account.base.mint != mint_info.key {
375                    return Err(TokenError::MintMismatch.into());
376                }
377
378                let mint_data = mint_info.try_borrow_data()?;
379                let mint = PodStateWithExtensions::<PodMint>::unpack(&mint_data)?;
380
381                if expected_decimals != mint.base.decimals {
382                    return Err(TokenError::MintDecimalsMismatch.into());
383                }
384
385                let fee = if let Ok(transfer_fee_config) = mint.get_extension::<TransferFeeConfig>()
386                {
387                    transfer_fee_config
388                        .calculate_epoch_fee(Clock::get()?.epoch, amount)
389                        .ok_or(TokenError::Overflow)?
390                } else {
391                    0
392                };
393
394                if let Ok(extension) = mint.get_extension::<PausableConfig>() {
395                    if extension.paused.into() {
396                        return Err(TokenError::MintPaused.into());
397                    }
398                }
399
400                let maybe_permanent_delegate = get_permanent_delegate(&mint);
401                let maybe_transfer_hook_program_id = transfer_hook::get_program_id(&mint);
402
403                (
404                    fee,
405                    maybe_permanent_delegate,
406                    maybe_transfer_hook_program_id,
407                )
408            } else {
409                // Transfer hook extension exists on the account, but no mint
410                // was provided to figure out required accounts, abort
411                if source_account
412                    .get_extension::<TransferHookAccount>()
413                    .is_ok()
414                {
415                    return Err(TokenError::MintRequiredForTransfer.into());
416                }
417
418                // Transfer fee amount extension exists on the account, but no mint
419                // was provided to calculate the fee, abort
420                if source_account
421                    .get_extension_mut::<TransferFeeAmount>()
422                    .is_ok()
423                {
424                    return Err(TokenError::MintRequiredForTransfer.into());
425                }
426
427                // Pausable extension exists on the account, but no mint
428                // was provided to see if it's paused, abort
429                if source_account.get_extension::<PausableAccount>().is_ok() {
430                    return Err(TokenError::MintRequiredForTransfer.into());
431                }
432
433                (0, None, None)
434            };
435        if let TransferInstruction::CheckedWithFee { fee, .. } = transfer_instruction {
436            if calculated_fee != fee {
437                msg!("Calculated fee {calculated_fee}, received {fee}");
438                return Err(TokenError::FeeMismatch.into());
439            }
440        }
441
442        let self_transfer = source_account_info.key == destination_account_info.key;
443        if let Ok(cpi_guard) = source_account.get_extension::<CpiGuard>() {
444            // Blocks all cases where the authority has signed if CPI Guard is
445            // enabled, including:
446            // * the account is delegated to the owner
447            // * the account owner is the permanent delegate
448            if *authority_info.key == source_account.base.owner
449                && cpi_guard.lock_cpi.into()
450                && in_cpi()
451            {
452                return Err(TokenError::CpiGuardTransferBlocked.into());
453            }
454        }
455        match (source_account.base.delegate, maybe_permanent_delegate) {
456            (_, Some(ref delegate)) if authority_info.key == delegate => Self::validate_owner(
457                program_id,
458                delegate,
459                authority_info,
460                authority_info_data_len,
461                account_info_iter.as_slice(),
462            )?,
463            (
464                PodCOption {
465                    option: PodCOption::<Address>::SOME,
466                    value: delegate,
467                },
468                _,
469            ) if authority_info.key == &delegate => {
470                Self::validate_owner(
471                    program_id,
472                    &delegate,
473                    authority_info,
474                    authority_info_data_len,
475                    account_info_iter.as_slice(),
476                )?;
477                let delegated_amount = u64::from(source_account.base.delegated_amount);
478                if delegated_amount < amount {
479                    return Err(TokenError::InsufficientFunds.into());
480                }
481                if !self_transfer {
482                    source_account.base.delegated_amount = delegated_amount
483                        .checked_sub(amount)
484                        .ok_or(TokenError::Overflow)?
485                        .into();
486                    if u64::from(source_account.base.delegated_amount) == 0 {
487                        source_account.base.delegate = PodCOption::none();
488                    }
489                }
490            }
491            _ => {
492                Self::validate_owner(
493                    program_id,
494                    &source_account.base.owner,
495                    authority_info,
496                    authority_info_data_len,
497                    account_info_iter.as_slice(),
498                )?;
499            }
500        }
501
502        // This check MUST occur just before the amounts are manipulated
503        // to ensure self-transfers are fully validated
504        if self_transfer {
505            if memo_required(&source_account) {
506                check_previous_sibling_instruction_is_memo()?;
507            }
508            return Ok(());
509        }
510
511        // self-transfer was dealt with earlier, so this *should* be safe
512        let mut destination_account_data = destination_account_info.data.borrow_mut();
513        let mut destination_account =
514            PodStateWithExtensionsMut::<PodAccount>::unpack(&mut destination_account_data)?;
515
516        if destination_account.base.is_frozen() {
517            return Err(TokenError::AccountFrozen.into());
518        }
519        if source_account.base.mint != destination_account.base.mint {
520            return Err(TokenError::MintMismatch.into());
521        }
522
523        if memo_required(&destination_account) {
524            check_previous_sibling_instruction_is_memo()?;
525        }
526
527        if let Ok(confidential_transfer_state) =
528            destination_account.get_extension::<ConfidentialTransferAccount>()
529        {
530            confidential_transfer_state.non_confidential_transfer_allowed()?
531        }
532
533        source_account.base.amount = source_amount
534            .checked_sub(amount)
535            .ok_or(TokenError::Overflow)?
536            .into();
537        let credited_amount = amount
538            .checked_sub(calculated_fee)
539            .ok_or(TokenError::Overflow)?;
540        destination_account.base.amount = u64::from(destination_account.base.amount)
541            .checked_add(credited_amount)
542            .ok_or(TokenError::Overflow)?
543            .into();
544        if calculated_fee > 0 {
545            if let Ok(extension) = destination_account.get_extension_mut::<TransferFeeAmount>() {
546                let new_withheld_amount = u64::from(extension.withheld_amount)
547                    .checked_add(calculated_fee)
548                    .ok_or(TokenError::Overflow)?;
549                extension.withheld_amount = new_withheld_amount.into();
550            } else {
551                // Use the generic error since this should never happen. If there's
552                // a fee, then the mint has a fee configured, which means all accounts
553                // must have the withholding.
554                return Err(TokenError::InvalidState.into());
555            }
556        }
557
558        if source_account.base.is_native() {
559            let source_starting_lamports = source_account_info.lamports();
560            **source_account_info.lamports.borrow_mut() = source_starting_lamports
561                .checked_sub(amount)
562                .ok_or(TokenError::Overflow)?;
563
564            let destination_starting_lamports = destination_account_info.lamports();
565            **destination_account_info.lamports.borrow_mut() = destination_starting_lamports
566                .checked_add(amount)
567                .ok_or(TokenError::Overflow)?;
568        }
569
570        if let Some(program_id) = maybe_transfer_hook_program_id {
571            if let Some((mint_info, _)) = expected_mint_info {
572                // set transferring flags
573                transfer_hook::set_transferring(&mut source_account)?;
574                transfer_hook::set_transferring(&mut destination_account)?;
575
576                // must drop these to avoid the double-borrow during CPI
577                drop(source_account_data);
578                drop(destination_account_data);
579                spl_transfer_hook_interface::onchain::invoke_execute(
580                    &program_id,
581                    source_account_info.clone(),
582                    mint_info.clone(),
583                    destination_account_info.clone(),
584                    authority_info.clone(),
585                    account_info_iter.as_slice(),
586                    amount,
587                )?;
588
589                // unset transferring flag
590                transfer_hook::unset_transferring(source_account_info)?;
591                transfer_hook::unset_transferring(destination_account_info)?;
592            } else {
593                return Err(TokenError::MintRequiredForTransfer.into());
594            }
595        }
596
597        Ok(())
598    }
599
600    /// Processes an [`Approve`](enum.TokenInstruction.html) instruction.
601    pub(crate) fn process_approve(
602        program_id: &Address,
603        accounts: &[AccountInfo],
604        amount: u64,
605        instruction_variant: InstructionVariant,
606    ) -> ProgramResult {
607        let account_info_iter = &mut accounts.iter();
608
609        let source_account_info = next_account_info(account_info_iter)?;
610
611        check_program_account(source_account_info.owner)?;
612
613        let expected_mint_info =
614            if let InstructionVariant::Checked { decimals } = instruction_variant {
615                Some((next_account_info(account_info_iter)?, decimals))
616            } else {
617                None
618            };
619        let delegate_info = next_account_info(account_info_iter)?;
620        let owner_info = next_account_info(account_info_iter)?;
621        let owner_info_data_len = owner_info.data_len();
622
623        let mut source_account_data = source_account_info.data.borrow_mut();
624        let source_account =
625            PodStateWithExtensionsMut::<PodAccount>::unpack(&mut source_account_data)?;
626
627        if source_account.base.is_frozen() {
628            return Err(TokenError::AccountFrozen.into());
629        }
630
631        if let Some((mint_info, expected_decimals)) = expected_mint_info {
632            check_program_account(mint_info.owner)?;
633
634            if &source_account.base.mint != mint_info.key {
635                return Err(TokenError::MintMismatch.into());
636            }
637
638            let mint_data = mint_info.data.borrow();
639            let mint = PodStateWithExtensions::<PodMint>::unpack(&mint_data)?;
640            if expected_decimals != mint.base.decimals {
641                return Err(TokenError::MintDecimalsMismatch.into());
642            }
643        }
644
645        Self::validate_owner(
646            program_id,
647            &source_account.base.owner,
648            owner_info,
649            owner_info_data_len,
650            account_info_iter.as_slice(),
651        )?;
652
653        if let Ok(cpi_guard) = source_account.get_extension::<CpiGuard>() {
654            if cpi_guard.lock_cpi.into() && in_cpi() {
655                return Err(TokenError::CpiGuardApproveBlocked.into());
656            }
657        }
658
659        source_account.base.delegate = PodCOption::some(*delegate_info.key);
660        source_account.base.delegated_amount = amount.into();
661
662        Ok(())
663    }
664
665    /// Processes an [`Revoke`](enum.TokenInstruction.html) instruction.
666    pub fn process_revoke(program_id: &Address, accounts: &[AccountInfo]) -> ProgramResult {
667        let account_info_iter = &mut accounts.iter();
668        let source_account_info = next_account_info(account_info_iter)?;
669        let authority_info = next_account_info(account_info_iter)?;
670        let authority_info_data_len = authority_info.data_len();
671
672        check_program_account(source_account_info.owner)?;
673
674        let mut source_account_data = source_account_info.data.borrow_mut();
675        let source_account =
676            PodStateWithExtensionsMut::<PodAccount>::unpack(&mut source_account_data)?;
677        if source_account.base.is_frozen() {
678            return Err(TokenError::AccountFrozen.into());
679        }
680
681        Self::validate_owner(
682            program_id,
683            match &source_account.base.delegate {
684                PodCOption {
685                    option: PodCOption::<Address>::SOME,
686                    value: delegate,
687                } if authority_info.key == delegate => delegate,
688                _ => &source_account.base.owner,
689            },
690            authority_info,
691            authority_info_data_len,
692            account_info_iter.as_slice(),
693        )?;
694
695        source_account.base.delegate = PodCOption::none();
696        source_account.base.delegated_amount = 0.into();
697
698        Ok(())
699    }
700
701    /// Processes a [`SetAuthority`](enum.TokenInstruction.html) instruction.
702    pub fn process_set_authority(
703        program_id: &Address,
704        accounts: &[AccountInfo],
705        authority_type: AuthorityType,
706        new_authority: PodCOption<Address>,
707    ) -> ProgramResult {
708        let account_info_iter = &mut accounts.iter();
709        let account_info = next_account_info(account_info_iter)?;
710        let authority_info = next_account_info(account_info_iter)?;
711        let authority_info_data_len = authority_info.data_len();
712
713        check_program_account(account_info.owner)?;
714
715        let mut account_data = account_info.data.borrow_mut();
716        if let Ok(mut account) = PodStateWithExtensionsMut::<PodAccount>::unpack(&mut account_data)
717        {
718            if account.base.is_frozen() {
719                return Err(TokenError::AccountFrozen.into());
720            }
721
722            match authority_type {
723                AuthorityType::AccountOwner => {
724                    Self::validate_owner(
725                        program_id,
726                        &account.base.owner,
727                        authority_info,
728                        authority_info_data_len,
729                        account_info_iter.as_slice(),
730                    )?;
731
732                    if account.get_extension_mut::<ImmutableOwner>().is_ok() {
733                        return Err(TokenError::ImmutableOwner.into());
734                    }
735
736                    if let Ok(cpi_guard) = account.get_extension::<CpiGuard>() {
737                        if cpi_guard.lock_cpi.into() && in_cpi() {
738                            return Err(TokenError::CpiGuardSetAuthorityBlocked.into());
739                        } else if cpi_guard.lock_cpi.into() {
740                            return Err(TokenError::CpiGuardOwnerChangeBlocked.into());
741                        }
742                    }
743
744                    if let PodCOption {
745                        option: PodCOption::<Address>::SOME,
746                        value: authority,
747                    } = new_authority
748                    {
749                        account.base.owner = authority;
750                    } else {
751                        return Err(TokenError::InvalidInstruction.into());
752                    }
753
754                    account.base.delegate = PodCOption::none();
755                    account.base.delegated_amount = 0.into();
756
757                    if account.base.is_native() {
758                        account.base.close_authority = PodCOption::none();
759                    }
760                }
761                AuthorityType::CloseAccount => {
762                    let authority = account.base.close_authority.unwrap_or(account.base.owner);
763                    Self::validate_owner(
764                        program_id,
765                        &authority,
766                        authority_info,
767                        authority_info_data_len,
768                        account_info_iter.as_slice(),
769                    )?;
770
771                    if let Ok(cpi_guard) = account.get_extension::<CpiGuard>() {
772                        if cpi_guard.lock_cpi.into() && in_cpi() && new_authority.is_some() {
773                            return Err(TokenError::CpiGuardSetAuthorityBlocked.into());
774                        }
775                    }
776
777                    account.base.close_authority = new_authority;
778                }
779                _ => {
780                    return Err(TokenError::AuthorityTypeNotSupported.into());
781                }
782            }
783        } else if let Ok(mut mint) = PodStateWithExtensionsMut::<PodMint>::unpack(&mut account_data)
784        {
785            match authority_type {
786                AuthorityType::MintTokens => {
787                    // Once a mint's supply is fixed, it cannot be undone by setting a new
788                    // mint_authority
789                    let mint_authority = mint
790                        .base
791                        .mint_authority
792                        .ok_or(Into::<ProgramError>::into(TokenError::FixedSupply))?;
793                    Self::validate_owner(
794                        program_id,
795                        &mint_authority,
796                        authority_info,
797                        authority_info_data_len,
798                        account_info_iter.as_slice(),
799                    )?;
800                    mint.base.mint_authority = new_authority;
801                }
802                AuthorityType::FreezeAccount => {
803                    // Once a mint's freeze authority is disabled, it cannot be re-enabled by
804                    // setting a new freeze_authority
805                    let freeze_authority = mint
806                        .base
807                        .freeze_authority
808                        .ok_or(Into::<ProgramError>::into(TokenError::MintCannotFreeze))?;
809                    Self::validate_owner(
810                        program_id,
811                        &freeze_authority,
812                        authority_info,
813                        authority_info_data_len,
814                        account_info_iter.as_slice(),
815                    )?;
816                    mint.base.freeze_authority = new_authority;
817                }
818                AuthorityType::CloseMint => {
819                    let extension = mint.get_extension_mut::<MintCloseAuthority>()?;
820                    let maybe_close_authority: Option<Address> = extension.close_authority.into();
821                    let close_authority =
822                        maybe_close_authority.ok_or(TokenError::AuthorityTypeNotSupported)?;
823                    Self::validate_owner(
824                        program_id,
825                        &close_authority,
826                        authority_info,
827                        authority_info_data_len,
828                        account_info_iter.as_slice(),
829                    )?;
830                    extension.close_authority = new_authority.try_into()?;
831                }
832                AuthorityType::TransferFeeConfig => {
833                    let extension = mint.get_extension_mut::<TransferFeeConfig>()?;
834                    let maybe_transfer_fee_config_authority: Option<Address> =
835                        extension.transfer_fee_config_authority.into();
836                    let transfer_fee_config_authority = maybe_transfer_fee_config_authority
837                        .ok_or(TokenError::AuthorityTypeNotSupported)?;
838                    Self::validate_owner(
839                        program_id,
840                        &transfer_fee_config_authority,
841                        authority_info,
842                        authority_info_data_len,
843                        account_info_iter.as_slice(),
844                    )?;
845                    extension.transfer_fee_config_authority = new_authority.try_into()?;
846                }
847                AuthorityType::WithheldWithdraw => {
848                    let extension = mint.get_extension_mut::<TransferFeeConfig>()?;
849                    let maybe_withdraw_withheld_authority: Option<Address> =
850                        extension.withdraw_withheld_authority.into();
851                    let withdraw_withheld_authority = maybe_withdraw_withheld_authority
852                        .ok_or(TokenError::AuthorityTypeNotSupported)?;
853                    Self::validate_owner(
854                        program_id,
855                        &withdraw_withheld_authority,
856                        authority_info,
857                        authority_info_data_len,
858                        account_info_iter.as_slice(),
859                    )?;
860                    extension.withdraw_withheld_authority = new_authority.try_into()?;
861                }
862                AuthorityType::InterestRate => {
863                    let extension = mint.get_extension_mut::<InterestBearingConfig>()?;
864                    let maybe_rate_authority: Option<Address> = extension.rate_authority.into();
865                    let rate_authority =
866                        maybe_rate_authority.ok_or(TokenError::AuthorityTypeNotSupported)?;
867                    Self::validate_owner(
868                        program_id,
869                        &rate_authority,
870                        authority_info,
871                        authority_info_data_len,
872                        account_info_iter.as_slice(),
873                    )?;
874                    extension.rate_authority = new_authority.try_into()?;
875                }
876                AuthorityType::PermanentDelegate => {
877                    let extension = mint.get_extension_mut::<PermanentDelegate>()?;
878                    let maybe_delegate: Option<Address> = extension.delegate.into();
879                    let delegate = maybe_delegate.ok_or(TokenError::AuthorityTypeNotSupported)?;
880                    Self::validate_owner(
881                        program_id,
882                        &delegate,
883                        authority_info,
884                        authority_info_data_len,
885                        account_info_iter.as_slice(),
886                    )?;
887                    extension.delegate = new_authority.try_into()?;
888                }
889                AuthorityType::ConfidentialTransferMint => {
890                    let extension = mint.get_extension_mut::<ConfidentialTransferMint>()?;
891                    let maybe_confidential_transfer_mint_authority: Option<Address> =
892                        extension.authority.into();
893                    let confidential_transfer_mint_authority =
894                        maybe_confidential_transfer_mint_authority
895                            .ok_or(TokenError::AuthorityTypeNotSupported)?;
896                    Self::validate_owner(
897                        program_id,
898                        &confidential_transfer_mint_authority,
899                        authority_info,
900                        authority_info_data_len,
901                        account_info_iter.as_slice(),
902                    )?;
903                    extension.authority = new_authority.try_into()?;
904                }
905                AuthorityType::TransferHookProgramId => {
906                    let extension = mint.get_extension_mut::<TransferHook>()?;
907                    let maybe_authority: Option<Address> = extension.authority.into();
908                    let authority = maybe_authority.ok_or(TokenError::AuthorityTypeNotSupported)?;
909                    Self::validate_owner(
910                        program_id,
911                        &authority,
912                        authority_info,
913                        authority_info_data_len,
914                        account_info_iter.as_slice(),
915                    )?;
916                    extension.authority = new_authority.try_into()?;
917                }
918                AuthorityType::ConfidentialTransferFeeConfig => {
919                    let extension = mint.get_extension_mut::<ConfidentialTransferFeeConfig>()?;
920                    let maybe_authority: Option<Address> = extension.authority.into();
921                    let authority = maybe_authority.ok_or(TokenError::AuthorityTypeNotSupported)?;
922                    Self::validate_owner(
923                        program_id,
924                        &authority,
925                        authority_info,
926                        authority_info_data_len,
927                        account_info_iter.as_slice(),
928                    )?;
929                    extension.authority = new_authority.try_into()?;
930                }
931                AuthorityType::MetadataPointer => {
932                    let extension = mint.get_extension_mut::<MetadataPointer>()?;
933                    let maybe_authority: Option<Address> = extension.authority.into();
934                    let authority = maybe_authority.ok_or(TokenError::AuthorityTypeNotSupported)?;
935                    Self::validate_owner(
936                        program_id,
937                        &authority,
938                        authority_info,
939                        authority_info_data_len,
940                        account_info_iter.as_slice(),
941                    )?;
942                    extension.authority = new_authority.try_into()?;
943                }
944                AuthorityType::GroupPointer => {
945                    let extension = mint.get_extension_mut::<GroupPointer>()?;
946                    let maybe_authority: Option<Address> = extension.authority.into();
947                    let authority = maybe_authority.ok_or(TokenError::AuthorityTypeNotSupported)?;
948                    Self::validate_owner(
949                        program_id,
950                        &authority,
951                        authority_info,
952                        authority_info_data_len,
953                        account_info_iter.as_slice(),
954                    )?;
955                    extension.authority = new_authority.try_into()?;
956                }
957                AuthorityType::GroupMemberPointer => {
958                    let extension = mint.get_extension_mut::<GroupMemberPointer>()?;
959                    let maybe_authority: Option<Address> = extension.authority.into();
960                    let authority = maybe_authority.ok_or(TokenError::AuthorityTypeNotSupported)?;
961                    Self::validate_owner(
962                        program_id,
963                        &authority,
964                        authority_info,
965                        authority_info_data_len,
966                        account_info_iter.as_slice(),
967                    )?;
968                    extension.authority = new_authority.try_into()?;
969                }
970                AuthorityType::ScaledUiAmount => {
971                    let extension = mint.get_extension_mut::<ScaledUiAmountConfig>()?;
972                    let maybe_authority: Option<Address> = extension.authority.into();
973                    let authority = maybe_authority.ok_or(TokenError::AuthorityTypeNotSupported)?;
974                    Self::validate_owner(
975                        program_id,
976                        &authority,
977                        authority_info,
978                        authority_info_data_len,
979                        account_info_iter.as_slice(),
980                    )?;
981                    extension.authority = new_authority.try_into()?;
982                }
983                AuthorityType::Pause => {
984                    let extension = mint.get_extension_mut::<PausableConfig>()?;
985                    let maybe_authority: Option<Address> = extension.authority.into();
986                    let authority = maybe_authority.ok_or(TokenError::AuthorityTypeNotSupported)?;
987                    Self::validate_owner(
988                        program_id,
989                        &authority,
990                        authority_info,
991                        authority_info_data_len,
992                        account_info_iter.as_slice(),
993                    )?;
994                    extension.authority = new_authority.try_into()?;
995                }
996                AuthorityType::PermissionedBurn => {
997                    let extension = mint.get_extension_mut::<PermissionedBurnConfig>()?;
998                    let maybe_authority: Option<Address> = extension.authority.into();
999                    let authority = maybe_authority.ok_or(TokenError::AuthorityTypeNotSupported)?;
1000                    Self::validate_owner(
1001                        program_id,
1002                        &authority,
1003                        authority_info,
1004                        authority_info_data_len,
1005                        account_info_iter.as_slice(),
1006                    )?;
1007                    extension.authority = new_authority.try_into()?;
1008                }
1009                _ => {
1010                    return Err(TokenError::AuthorityTypeNotSupported.into());
1011                }
1012            }
1013        } else {
1014            return Err(ProgramError::InvalidAccountData);
1015        }
1016
1017        Ok(())
1018    }
1019
1020    /// Processes a [`MintTo`](enum.TokenInstruction.html) instruction.
1021    pub(crate) fn process_mint_to(
1022        program_id: &Address,
1023        accounts: &[AccountInfo],
1024        amount: u64,
1025        instruction_variant: InstructionVariant,
1026    ) -> ProgramResult {
1027        let account_info_iter = &mut accounts.iter();
1028        let mint_info = next_account_info(account_info_iter)?;
1029        let destination_account_info = next_account_info(account_info_iter)?;
1030        let owner_info = next_account_info(account_info_iter)?;
1031        let owner_info_data_len = owner_info.data_len();
1032
1033        check_program_account(mint_info.owner)?;
1034        check_program_account(destination_account_info.owner)?;
1035
1036        let mut destination_account_data = destination_account_info.data.borrow_mut();
1037        let destination_account =
1038            PodStateWithExtensionsMut::<PodAccount>::unpack(&mut destination_account_data)?;
1039        if destination_account.base.is_frozen() {
1040            return Err(TokenError::AccountFrozen.into());
1041        }
1042
1043        if destination_account.base.is_native() {
1044            return Err(TokenError::NativeNotSupported.into());
1045        }
1046        if mint_info.key != &destination_account.base.mint {
1047            return Err(TokenError::MintMismatch.into());
1048        }
1049
1050        let mut mint_data = mint_info.data.borrow_mut();
1051        let mint = PodStateWithExtensionsMut::<PodMint>::unpack(&mut mint_data)?;
1052
1053        // If the mint if non-transferable, only allow minting to accounts
1054        // with immutable ownership and the non-transferable extension.
1055        if mint.get_extension::<NonTransferable>().is_ok()
1056            && (destination_account
1057                .get_extension::<ImmutableOwner>()
1058                .is_err()
1059                || destination_account
1060                    .get_extension::<NonTransferableAccount>()
1061                    .is_err())
1062        {
1063            // This error name isn't totally correct since we also require the
1064            // non-transferable account extension, but that case only happens in
1065            // the case of a mint recreated with the extension, which should be
1066            // very rare. We leave the error name as it was.
1067            return Err(TokenError::NonTransferableNeedsImmutableOwnership.into());
1068        }
1069
1070        if let Ok(extension) = mint.get_extension::<PausableConfig>() {
1071            if extension.paused.into() {
1072                return Err(TokenError::MintPaused.into());
1073            }
1074        }
1075
1076        if mint.get_extension::<ConfidentialMintBurn>().is_ok() {
1077            return Err(TokenError::IllegalMintBurnConversion.into());
1078        }
1079
1080        if let InstructionVariant::Checked { decimals } = instruction_variant {
1081            if decimals != mint.base.decimals {
1082                return Err(TokenError::MintDecimalsMismatch.into());
1083            }
1084        }
1085
1086        match &mint.base.mint_authority {
1087            PodCOption {
1088                option: PodCOption::<Address>::SOME,
1089                value: mint_authority,
1090            } => Self::validate_owner(
1091                program_id,
1092                mint_authority,
1093                owner_info,
1094                owner_info_data_len,
1095                account_info_iter.as_slice(),
1096            )?,
1097            _ => return Err(TokenError::FixedSupply.into()),
1098        }
1099
1100        destination_account.base.amount = u64::from(destination_account.base.amount)
1101            .checked_add(amount)
1102            .ok_or(TokenError::Overflow)?
1103            .into();
1104
1105        mint.base.supply = u64::from(mint.base.supply)
1106            .checked_add(amount)
1107            .ok_or(TokenError::Overflow)?
1108            .into();
1109
1110        Ok(())
1111    }
1112
1113    /// Processes a [`Burn`](enum.TokenInstruction.html) instruction.
1114    pub(crate) fn process_burn(
1115        program_id: &Address,
1116        accounts: &[AccountInfo],
1117        amount: u64,
1118        burn_variant: BurnInstructionVariant,
1119        instruction_variant: InstructionVariant,
1120    ) -> ProgramResult {
1121        let account_info_iter = &mut accounts.iter();
1122
1123        let source_account_info = next_account_info(account_info_iter)?;
1124        let mint_info = next_account_info(account_info_iter)?;
1125
1126        check_program_account(source_account_info.owner)?;
1127        check_program_account(mint_info.owner)?;
1128
1129        let (permissioned_burn_authority_info, authority_info) = match burn_variant {
1130            BurnInstructionVariant::Permissioned => {
1131                let permissioned_burn_authority_info = next_account_info(account_info_iter)?;
1132                let authority_info = next_account_info(account_info_iter)?;
1133                (Some(permissioned_burn_authority_info), authority_info)
1134            }
1135            BurnInstructionVariant::Standard => (None, next_account_info(account_info_iter)?),
1136        };
1137
1138        let authority_info_data_len = authority_info.data_len();
1139
1140        let mut mint_data = mint_info.data.borrow_mut();
1141        let mint = PodStateWithExtensionsMut::<PodMint>::unpack(&mut mint_data)?;
1142
1143        let permissioned_ext = mint.get_extension::<PermissionedBurnConfig>();
1144        let maybe_permissioned_burn_authority = permissioned_ext
1145            .as_ref()
1146            .ok()
1147            .and_then(|ext| Option::<Address>::from(ext.authority));
1148
1149        match burn_variant {
1150            BurnInstructionVariant::Standard => {
1151                // Standard burns cannot be used when the permissioned burn
1152                // extension is present.
1153                if maybe_permissioned_burn_authority.is_some() {
1154                    return Err(TokenError::InvalidInstruction.into());
1155                }
1156            }
1157            BurnInstructionVariant::Permissioned => {
1158                permissioned_ext.map_err(|_| TokenError::InvalidInstruction)?;
1159
1160                let expected_burn_authority =
1161                    maybe_permissioned_burn_authority.ok_or_else(|| {
1162                        msg!("Permissioned burn authority is None; use the standard burn");
1163                        TokenError::InvalidInstruction
1164                    })?;
1165
1166                // Pull the required extra signer from the accounts
1167                let approver_ai =
1168                    permissioned_burn_authority_info.ok_or(ProgramError::NotEnoughAccountKeys)?;
1169
1170                if !approver_ai.is_signer {
1171                    return Err(ProgramError::MissingRequiredSignature);
1172                }
1173
1174                if *approver_ai.key != expected_burn_authority {
1175                    return Err(ProgramError::InvalidAccountData);
1176                }
1177            }
1178        }
1179
1180        let mut source_account_data = source_account_info.data.borrow_mut();
1181        let source_account =
1182            PodStateWithExtensionsMut::<PodAccount>::unpack(&mut source_account_data)?;
1183
1184        if source_account.base.is_frozen() {
1185            return Err(TokenError::AccountFrozen.into());
1186        }
1187        if source_account.base.is_native() {
1188            return Err(TokenError::NativeNotSupported.into());
1189        }
1190        if u64::from(source_account.base.amount) < amount {
1191            return Err(TokenError::InsufficientFunds.into());
1192        }
1193        if mint_info.key != &source_account.base.mint {
1194            return Err(TokenError::MintMismatch.into());
1195        }
1196
1197        if let InstructionVariant::Checked { decimals } = instruction_variant {
1198            if decimals != mint.base.decimals {
1199                return Err(TokenError::MintDecimalsMismatch.into());
1200            }
1201        }
1202        if let Ok(extension) = mint.get_extension::<PausableConfig>() {
1203            if extension.paused.into() {
1204                return Err(TokenError::MintPaused.into());
1205            }
1206        }
1207
1208        if mint.get_extension::<ConfidentialMintBurn>().is_ok() {
1209            return Err(TokenError::IllegalMintBurnConversion.into());
1210        }
1211
1212        let maybe_permanent_delegate = get_permanent_delegate(&mint);
1213
1214        if let Ok(cpi_guard) = source_account.get_extension::<CpiGuard>() {
1215            // Blocks all cases where the authority has signed if CPI Guard is
1216            // enabled, including:
1217            // * the account is delegated to the owner
1218            // * the account owner is the permanent delegate
1219            if *authority_info.key == source_account.base.owner
1220                && cpi_guard.lock_cpi.into()
1221                && in_cpi()
1222            {
1223                return Err(TokenError::CpiGuardBurnBlocked.into());
1224            }
1225        }
1226
1227        if !source_account
1228            .base
1229            .is_owned_by_system_program_or_incinerator()
1230        {
1231            match (&source_account.base.delegate, maybe_permanent_delegate) {
1232                (_, Some(ref delegate)) if authority_info.key == delegate => Self::validate_owner(
1233                    program_id,
1234                    delegate,
1235                    authority_info,
1236                    authority_info_data_len,
1237                    account_info_iter.as_slice(),
1238                )?,
1239                (
1240                    PodCOption {
1241                        option: PodCOption::<Address>::SOME,
1242                        value: delegate,
1243                    },
1244                    _,
1245                ) if authority_info.key == delegate => {
1246                    Self::validate_owner(
1247                        program_id,
1248                        delegate,
1249                        authority_info,
1250                        authority_info_data_len,
1251                        account_info_iter.as_slice(),
1252                    )?;
1253
1254                    if u64::from(source_account.base.delegated_amount) < amount {
1255                        return Err(TokenError::InsufficientFunds.into());
1256                    }
1257                    source_account.base.delegated_amount =
1258                        u64::from(source_account.base.delegated_amount)
1259                            .checked_sub(amount)
1260                            .ok_or(TokenError::Overflow)?
1261                            .into();
1262                    if u64::from(source_account.base.delegated_amount) == 0 {
1263                        source_account.base.delegate = PodCOption::none();
1264                    }
1265                }
1266                _ => {
1267                    Self::validate_owner(
1268                        program_id,
1269                        &source_account.base.owner,
1270                        authority_info,
1271                        authority_info_data_len,
1272                        account_info_iter.as_slice(),
1273                    )?;
1274                }
1275            }
1276        }
1277
1278        source_account.base.amount = u64::from(source_account.base.amount)
1279            .checked_sub(amount)
1280            .ok_or(TokenError::Overflow)?
1281            .into();
1282        mint.base.supply = u64::from(mint.base.supply)
1283            .checked_sub(amount)
1284            .ok_or(TokenError::Overflow)?
1285            .into();
1286
1287        Ok(())
1288    }
1289
1290    /// Processes a [`CloseAccount`](enum.TokenInstruction.html) instruction.
1291    pub fn process_close_account(program_id: &Address, accounts: &[AccountInfo]) -> ProgramResult {
1292        let account_info_iter = &mut accounts.iter();
1293        let source_account_info = next_account_info(account_info_iter)?;
1294        let destination_account_info = next_account_info(account_info_iter)?;
1295        let authority_info = next_account_info(account_info_iter)?;
1296        let authority_info_data_len = authority_info.data_len();
1297
1298        check_program_account(source_account_info.owner)?;
1299
1300        if source_account_info.key == destination_account_info.key {
1301            return Err(ProgramError::InvalidAccountData);
1302        }
1303
1304        let source_account_data = source_account_info.data.borrow();
1305        if let Ok(source_account) =
1306            PodStateWithExtensions::<PodAccount>::unpack(&source_account_data)
1307        {
1308            if !source_account.base.is_native() && u64::from(source_account.base.amount) != 0 {
1309                return Err(TokenError::NonNativeHasBalance.into());
1310            }
1311
1312            let authority = source_account
1313                .base
1314                .close_authority
1315                .unwrap_or(source_account.base.owner);
1316
1317            if !source_account
1318                .base
1319                .is_owned_by_system_program_or_incinerator()
1320            {
1321                if let Ok(cpi_guard) = source_account.get_extension::<CpiGuard>() {
1322                    if cpi_guard.lock_cpi.into()
1323                        && in_cpi()
1324                        && destination_account_info.key != &source_account.base.owner
1325                    {
1326                        return Err(TokenError::CpiGuardCloseAccountBlocked.into());
1327                    }
1328                }
1329
1330                Self::validate_owner(
1331                    program_id,
1332                    &authority,
1333                    authority_info,
1334                    authority_info_data_len,
1335                    account_info_iter.as_slice(),
1336                )?;
1337            } else if !solana_sdk_ids::incinerator::check_id(destination_account_info.key) {
1338                return Err(ProgramError::InvalidAccountData);
1339            }
1340
1341            if let Ok(confidential_transfer_state) =
1342                source_account.get_extension::<ConfidentialTransferAccount>()
1343            {
1344                confidential_transfer_state.closable()?
1345            }
1346
1347            if let Ok(confidential_transfer_fee_state) =
1348                source_account.get_extension::<ConfidentialTransferFeeAmount>()
1349            {
1350                confidential_transfer_fee_state.closable()?
1351            }
1352
1353            if let Ok(transfer_fee_state) = source_account.get_extension::<TransferFeeAmount>() {
1354                transfer_fee_state.closable()?
1355            }
1356        } else if let Ok(mint) = PodStateWithExtensions::<PodMint>::unpack(&source_account_data) {
1357            let extension = mint.get_extension::<MintCloseAuthority>()?;
1358            let maybe_authority: Option<Address> = extension.close_authority.into();
1359            let authority = maybe_authority.ok_or(TokenError::AuthorityTypeNotSupported)?;
1360            Self::validate_owner(
1361                program_id,
1362                &authority,
1363                authority_info,
1364                authority_info_data_len,
1365                account_info_iter.as_slice(),
1366            )?;
1367
1368            if u64::from(mint.base.supply) != 0 {
1369                return Err(TokenError::MintHasSupply.into());
1370            }
1371
1372            if let Ok(confidential_mint_burn) = mint.get_extension::<ConfidentialMintBurn>() {
1373                confidential_mint_burn.closable()?;
1374            }
1375        } else {
1376            return Err(ProgramError::UninitializedAccount);
1377        }
1378
1379        let destination_starting_lamports = destination_account_info.lamports();
1380        **destination_account_info.lamports.borrow_mut() = destination_starting_lamports
1381            .checked_add(source_account_info.lamports())
1382            .ok_or(TokenError::Overflow)?;
1383
1384        **source_account_info.lamports.borrow_mut() = 0;
1385        drop(source_account_data);
1386        delete_account(source_account_info)?;
1387
1388        Ok(())
1389    }
1390
1391    /// Processes a [`FreezeAccount`](enum.TokenInstruction.html) or a
1392    /// [`ThawAccount`](enum.TokenInstruction.html) instruction.
1393    pub fn process_toggle_freeze_account(
1394        program_id: &Address,
1395        accounts: &[AccountInfo],
1396        freeze: bool,
1397    ) -> ProgramResult {
1398        let account_info_iter = &mut accounts.iter();
1399        let source_account_info = next_account_info(account_info_iter)?;
1400        let mint_info = next_account_info(account_info_iter)?;
1401        let authority_info = next_account_info(account_info_iter)?;
1402        let authority_info_data_len = authority_info.data_len();
1403
1404        check_program_account(source_account_info.owner)?;
1405        check_program_account(mint_info.owner)?;
1406
1407        let mut source_account_data = source_account_info.data.borrow_mut();
1408        let source_account =
1409            PodStateWithExtensionsMut::<PodAccount>::unpack(&mut source_account_data)?;
1410        if freeze && source_account.base.is_frozen() || !freeze && !source_account.base.is_frozen()
1411        {
1412            return Err(TokenError::InvalidState.into());
1413        }
1414        if source_account.base.is_native() {
1415            return Err(TokenError::NativeNotSupported.into());
1416        }
1417        if mint_info.key != &source_account.base.mint {
1418            return Err(TokenError::MintMismatch.into());
1419        }
1420
1421        let mint_data = mint_info.data.borrow();
1422        let mint = PodStateWithExtensions::<PodMint>::unpack(&mint_data)?;
1423        match &mint.base.freeze_authority {
1424            PodCOption {
1425                option: PodCOption::<Address>::SOME,
1426                value: authority,
1427            } => Self::validate_owner(
1428                program_id,
1429                authority,
1430                authority_info,
1431                authority_info_data_len,
1432                account_info_iter.as_slice(),
1433            ),
1434            _ => Err(TokenError::MintCannotFreeze.into()),
1435        }?;
1436
1437        source_account.base.state = if freeze {
1438            AccountState::Frozen.into()
1439        } else {
1440            AccountState::Initialized.into()
1441        };
1442
1443        Ok(())
1444    }
1445
1446    /// Processes a [`SyncNative`](enum.TokenInstruction.html) instruction
1447    pub fn process_sync_native(accounts: &[AccountInfo]) -> ProgramResult {
1448        let account_info_iter = &mut accounts.iter();
1449        let native_account_info = next_account_info(account_info_iter)?;
1450
1451        check_program_account(native_account_info.owner)?;
1452
1453        let rent_exempt_reserve = if let Ok(rent_sysvar_info) = next_account_info(account_info_iter)
1454        {
1455            let rent = Rent::from_account_info(rent_sysvar_info)?;
1456            rent.minimum_balance(native_account_info.data_len())
1457        } else {
1458            Rent::get()?.minimum_balance(native_account_info.data_len())
1459        };
1460
1461        let mut native_account_data = native_account_info.data.borrow_mut();
1462        let native_account =
1463            PodStateWithExtensionsMut::<PodAccount>::unpack(&mut native_account_data)?;
1464
1465        match native_account.base.is_native {
1466            PodCOption {
1467                option: PodCOption::<U64>::SOME,
1468                ..
1469            } => {
1470                let new_amount = native_account_info
1471                    .lamports()
1472                    .checked_sub(rent_exempt_reserve)
1473                    .ok_or(TokenError::Overflow)?;
1474                native_account.base.is_native = PodCOption::some(rent_exempt_reserve.into());
1475                native_account.base.amount = new_amount.into();
1476            }
1477            _ => return Err(TokenError::NonNativeNotSupported.into()),
1478        }
1479
1480        Ok(())
1481    }
1482
1483    /// Processes an
1484    /// [`InitializeMintCloseAuthority`](enum.TokenInstruction.html)
1485    /// instruction
1486    pub fn process_initialize_mint_close_authority(
1487        accounts: &[AccountInfo],
1488        close_authority: PodCOption<Address>,
1489    ) -> ProgramResult {
1490        let account_info_iter = &mut accounts.iter();
1491        let mint_account_info = next_account_info(account_info_iter)?;
1492
1493        check_program_account(mint_account_info.owner)?;
1494
1495        let mut mint_data = mint_account_info.data.borrow_mut();
1496        let mut mint = PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut mint_data)?;
1497        let extension = mint.init_extension::<MintCloseAuthority>(true)?;
1498        extension.close_authority = close_authority.try_into()?;
1499
1500        Ok(())
1501    }
1502
1503    /// Processes a [`GetAccountDataSize`](enum.TokenInstruction.html)
1504    /// instruction
1505    pub fn process_get_account_data_size(
1506        accounts: &[AccountInfo],
1507        new_extension_types: &[ExtensionType],
1508    ) -> ProgramResult {
1509        if new_extension_types
1510            .iter()
1511            .any(|&t| t.get_account_type() != AccountType::Account)
1512        {
1513            return Err(TokenError::ExtensionTypeMismatch.into());
1514        }
1515
1516        let account_info_iter = &mut accounts.iter();
1517        let mint_account_info = next_account_info(account_info_iter)?;
1518
1519        check_program_account(mint_account_info.owner)?;
1520
1521        let mut account_extensions = Self::get_required_account_extensions(mint_account_info)?;
1522        // ExtensionType::try_calculate_account_len() dedupes types, so just a dumb
1523        // concatenation is fine here
1524        account_extensions.extend_from_slice(new_extension_types);
1525
1526        let account_len = ExtensionType::try_calculate_account_len::<Account>(&account_extensions)?;
1527        set_return_data(&account_len.to_le_bytes());
1528
1529        Ok(())
1530    }
1531
1532    /// Processes an [`InitializeImmutableOwner`](enum.TokenInstruction.html)
1533    /// instruction
1534    pub fn process_initialize_immutable_owner(accounts: &[AccountInfo]) -> ProgramResult {
1535        let account_info_iter = &mut accounts.iter();
1536        let token_account_info = next_account_info(account_info_iter)?;
1537
1538        check_program_account(token_account_info.owner)?;
1539
1540        let token_account_data = &mut token_account_info.data.borrow_mut();
1541        let mut token_account =
1542            PodStateWithExtensionsMut::<PodAccount>::unpack_uninitialized(token_account_data)?;
1543        token_account
1544            .init_extension::<ImmutableOwner>(true)
1545            .map(|_| ())
1546    }
1547
1548    /// Processes an [`AmountToUiAmount`](enum.TokenInstruction.html)
1549    /// instruction
1550    pub fn process_amount_to_ui_amount(accounts: &[AccountInfo], amount: u64) -> ProgramResult {
1551        let account_info_iter = &mut accounts.iter();
1552        let mint_info = next_account_info(account_info_iter)?;
1553        check_program_account(mint_info.owner)?;
1554
1555        let mint_data = mint_info.data.borrow();
1556        let mint = PodStateWithExtensions::<PodMint>::unpack(&mint_data)
1557            .map_err(|_| Into::<ProgramError>::into(TokenError::InvalidMint))?;
1558        let ui_amount = if let Ok(extension) = mint.get_extension::<InterestBearingConfig>() {
1559            let unix_timestamp = Clock::get()?.unix_timestamp;
1560            extension
1561                .amount_to_ui_amount(amount, mint.base.decimals, unix_timestamp)
1562                .ok_or(ProgramError::InvalidArgument)?
1563        } else if let Ok(extension) = mint.get_extension::<ScaledUiAmountConfig>() {
1564            let unix_timestamp = Clock::get()?.unix_timestamp;
1565            extension
1566                .amount_to_ui_amount(amount, mint.base.decimals, unix_timestamp)
1567                .ok_or(ProgramError::InvalidArgument)?
1568        } else {
1569            crate::amount_to_ui_amount_string_trimmed(amount, mint.base.decimals)
1570        };
1571
1572        set_return_data(&ui_amount.into_bytes());
1573        Ok(())
1574    }
1575
1576    /// Processes an [`UiAmountToAmount`](enum.TokenInstruction.html)
1577    /// instruction
1578    pub fn process_ui_amount_to_amount(accounts: &[AccountInfo], ui_amount: &str) -> ProgramResult {
1579        let account_info_iter = &mut accounts.iter();
1580        let mint_info = next_account_info(account_info_iter)?;
1581        check_program_account(mint_info.owner)?;
1582
1583        let mint_data = mint_info.data.borrow();
1584        let mint = PodStateWithExtensions::<PodMint>::unpack(&mint_data)
1585            .map_err(|_| Into::<ProgramError>::into(TokenError::InvalidMint))?;
1586        let amount = if let Ok(extension) = mint.get_extension::<InterestBearingConfig>() {
1587            let unix_timestamp = Clock::get()?.unix_timestamp;
1588            extension.try_ui_amount_into_amount(ui_amount, mint.base.decimals, unix_timestamp)?
1589        } else if let Ok(extension) = mint.get_extension::<ScaledUiAmountConfig>() {
1590            let unix_timestamp = Clock::get()?.unix_timestamp;
1591            extension.try_ui_amount_into_amount(ui_amount, mint.base.decimals, unix_timestamp)?
1592        } else {
1593            crate::try_ui_amount_into_amount(ui_amount.to_string(), mint.base.decimals)?
1594        };
1595
1596        set_return_data(&amount.to_le_bytes());
1597        Ok(())
1598    }
1599
1600    /// Processes a [`CreateNativeMint`](enum.TokenInstruction.html) instruction
1601    pub fn process_create_native_mint(accounts: &[AccountInfo]) -> ProgramResult {
1602        let account_info_iter = &mut accounts.iter();
1603        let payer_info = next_account_info(account_info_iter)?;
1604        let native_mint_info = next_account_info(account_info_iter)?;
1605        let system_program_info = next_account_info(account_info_iter)?;
1606
1607        if *native_mint_info.key != native_mint::id() {
1608            return Err(TokenError::InvalidMint.into());
1609        }
1610
1611        let rent = Rent::get()?;
1612        let new_minimum_balance = rent.minimum_balance(Mint::get_packed_len());
1613        let lamports_diff = new_minimum_balance.saturating_sub(native_mint_info.lamports());
1614        invoke(
1615            &system_instruction::transfer(payer_info.key, native_mint_info.key, lamports_diff),
1616            &[
1617                payer_info.clone(),
1618                native_mint_info.clone(),
1619                system_program_info.clone(),
1620            ],
1621        )?;
1622
1623        invoke_signed(
1624            &system_instruction::allocate(native_mint_info.key, Mint::get_packed_len() as u64),
1625            &[native_mint_info.clone(), system_program_info.clone()],
1626            &[native_mint::PROGRAM_ADDRESS_SEEDS],
1627        )?;
1628
1629        invoke_signed(
1630            &system_instruction::assign(native_mint_info.key, &crate::id()),
1631            &[native_mint_info.clone(), system_program_info.clone()],
1632            &[native_mint::PROGRAM_ADDRESS_SEEDS],
1633        )?;
1634
1635        Mint::pack(
1636            Mint {
1637                decimals: native_mint::DECIMALS,
1638                is_initialized: true,
1639                ..Mint::default()
1640            },
1641            &mut native_mint_info.data.borrow_mut(),
1642        )
1643    }
1644
1645    /// Processes an
1646    /// [`InitializeNonTransferableMint`](enum.TokenInstruction.html)
1647    /// instruction
1648    pub fn process_initialize_non_transferable_mint(accounts: &[AccountInfo]) -> ProgramResult {
1649        let account_info_iter = &mut accounts.iter();
1650        let mint_account_info = next_account_info(account_info_iter)?;
1651        check_program_account(mint_account_info.owner)?;
1652
1653        let mut mint_data = mint_account_info.data.borrow_mut();
1654        let mut mint = PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut mint_data)?;
1655        mint.init_extension::<NonTransferable>(true)?;
1656
1657        Ok(())
1658    }
1659
1660    /// Processes an [`InitializePermanentDelegate`](enum.TokenInstruction.html)
1661    /// instruction
1662    pub fn process_initialize_permanent_delegate(
1663        accounts: &[AccountInfo],
1664        delegate: &Address,
1665    ) -> ProgramResult {
1666        let account_info_iter = &mut accounts.iter();
1667        let mint_account_info = next_account_info(account_info_iter)?;
1668        check_program_account(mint_account_info.owner)?;
1669
1670        let mut mint_data = mint_account_info.data.borrow_mut();
1671        let mut mint = PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut mint_data)?;
1672        let extension = mint.init_extension::<PermanentDelegate>(true)?;
1673        extension.delegate = Some(*delegate)
1674            .try_into()
1675            .map_err(|_| ProgramError::InvalidArgument)?;
1676
1677        Ok(())
1678    }
1679
1680    /// Withdraw Excess Lamports is used to recover Lamports transferred to any
1681    /// `TokenProgram` owned account by moving them to another account
1682    /// of the source account.
1683    pub fn process_withdraw_excess_lamports(
1684        program_id: &Address,
1685        accounts: &[AccountInfo],
1686    ) -> ProgramResult {
1687        let account_info_iter = &mut accounts.iter();
1688
1689        let source_info = next_account_info(account_info_iter)?;
1690        let destination_info = next_account_info(account_info_iter)?;
1691        let authority_info = next_account_info(account_info_iter)?;
1692
1693        check_program_account(source_info.owner)?;
1694
1695        let source_data = source_info.data.borrow();
1696
1697        if let Ok(account) = PodStateWithExtensions::<PodAccount>::unpack(&source_data) {
1698            if account.base.is_native() {
1699                return Err(TokenError::NativeNotSupported.into());
1700            }
1701            Self::validate_owner(
1702                program_id,
1703                &account.base.owner,
1704                authority_info,
1705                authority_info.data_len(),
1706                account_info_iter.as_slice(),
1707            )?;
1708        } else if let Ok(mint) = PodStateWithExtensions::<PodMint>::unpack(&source_data) {
1709            match &mint.base.mint_authority {
1710                PodCOption {
1711                    option: PodCOption::<Address>::SOME,
1712                    value: mint_authority,
1713                } => {
1714                    Self::validate_owner(
1715                        program_id,
1716                        mint_authority,
1717                        authority_info,
1718                        authority_info.data_len(),
1719                        account_info_iter.as_slice(),
1720                    )?;
1721                }
1722                PodCOption {
1723                    option: PodCOption::<Address>::NONE,
1724                    value: _,
1725                } if source_info.key == authority_info.key => {
1726                    // This is a special case where there is no mint authority set but the mint
1727                    // account is the same as the authority account and, therefore, needs to be
1728                    // a signer.
1729                    if !authority_info.is_signer {
1730                        return Err(ProgramError::MissingRequiredSignature);
1731                    }
1732                }
1733                _ => return Err(TokenError::AuthorityTypeNotSupported.into()),
1734            }
1735        } else if source_data.len() == PodMultisig::SIZE_OF {
1736            Self::validate_owner(
1737                program_id,
1738                source_info.key,
1739                authority_info,
1740                authority_info.data_len(),
1741                account_info_iter.as_slice(),
1742            )?;
1743        } else {
1744            return Err(TokenError::InvalidState.into());
1745        }
1746
1747        let source_rent_exempt_reserve = Rent::get()?.minimum_balance(source_info.data_len());
1748
1749        let transfer_amount = source_info
1750            .lamports()
1751            .checked_sub(source_rent_exempt_reserve)
1752            .ok_or(TokenError::NotRentExempt)?;
1753
1754        let source_starting_lamports = source_info.lamports();
1755        **source_info.lamports.borrow_mut() = source_starting_lamports
1756            .checked_sub(transfer_amount)
1757            .ok_or(TokenError::Overflow)?;
1758
1759        let destination_starting_lamports = destination_info.lamports();
1760        **destination_info.lamports.borrow_mut() = destination_starting_lamports
1761            .checked_add(transfer_amount)
1762            .ok_or(TokenError::Overflow)?;
1763
1764        Ok(())
1765    }
1766
1767    /// Processes a [`UnwrapLamports`](enum.TokenInstruction.html)
1768    /// instruction
1769    pub fn process_unwrap_lamports(
1770        program_id: &Address,
1771        accounts: &[AccountInfo],
1772        amount: PodCOption<u64>,
1773    ) -> ProgramResult {
1774        let account_info_iter = &mut accounts.iter();
1775        let source_account_info = next_account_info(account_info_iter)?;
1776        let destination_account_info = next_account_info(account_info_iter)?;
1777        let authority_info = next_account_info(account_info_iter)?;
1778        let authority_info_data_len = authority_info.data_len();
1779
1780        check_program_account(source_account_info.owner)?;
1781
1782        let mut source_account_data = source_account_info.data.borrow_mut();
1783        let source_account =
1784            PodStateWithExtensionsMut::<PodAccount>::unpack(&mut source_account_data)?;
1785
1786        let (amount, remaining_amount) = match amount {
1787            PodCOption {
1788                option: PodCOption::<u64>::SOME,
1789                value: amount,
1790            } => (
1791                amount,
1792                Into::<u64>::into(source_account.base.amount)
1793                    .checked_sub(amount)
1794                    .ok_or(TokenError::InsufficientFunds)?,
1795            ),
1796            PodCOption {
1797                option: PodCOption::<u64>::NONE,
1798                value: _,
1799            } => (source_account.base.amount.into(), 0),
1800            _ => return Err(ProgramError::InvalidInstructionData),
1801        };
1802
1803        if !source_account.base.is_native() {
1804            return Err(TokenError::NonNativeNotSupported.into());
1805        }
1806
1807        match source_account.base.delegate {
1808            PodCOption {
1809                option: PodCOption::<Address>::SOME,
1810                value: delegate,
1811            } if authority_info.key == &delegate => {
1812                Self::validate_owner(
1813                    program_id,
1814                    &delegate,
1815                    authority_info,
1816                    authority_info_data_len,
1817                    account_info_iter.as_slice(),
1818                )?;
1819
1820                let delegated_amount = u64::from(source_account.base.delegated_amount);
1821
1822                source_account.base.delegated_amount = delegated_amount
1823                    .checked_sub(amount)
1824                    .ok_or(TokenError::InsufficientFunds)?
1825                    .into();
1826
1827                if u64::from(source_account.base.delegated_amount) == 0 {
1828                    source_account.base.delegate = PodCOption::none();
1829                }
1830            }
1831            _ => {
1832                Self::validate_owner(
1833                    program_id,
1834                    &source_account.base.owner,
1835                    authority_info,
1836                    authority_info_data_len,
1837                    account_info_iter.as_slice(),
1838                )?;
1839            }
1840        }
1841
1842        if let Ok(cpi_guard) = source_account.get_extension::<CpiGuard>() {
1843            if cpi_guard.lock_cpi.into() && in_cpi() {
1844                return Err(TokenError::CpiGuardTransferBlocked.into());
1845            }
1846        }
1847
1848        if amount != 0 {
1849            source_account.base.amount = remaining_amount.into();
1850
1851            if source_account_info.key != destination_account_info.key {
1852                let source_starting_lamports = source_account_info.lamports();
1853                **source_account_info.lamports.borrow_mut() = source_starting_lamports
1854                    .checked_sub(amount)
1855                    .ok_or(TokenError::Overflow)?;
1856
1857                let destination_starting_lamports = destination_account_info.lamports();
1858                **destination_account_info.lamports.borrow_mut() = destination_starting_lamports
1859                    .checked_add(amount)
1860                    .ok_or(TokenError::Overflow)?;
1861            }
1862        }
1863
1864        Ok(())
1865    }
1866
1867    /// The size of the batch instruction header.
1868    ///
1869    /// The header of each instruction consists of two `u8` values:
1870    /// * number of the accounts
1871    /// * length of the instruction data
1872    const IX_HEADER_SIZE: usize = 2;
1873
1874    /// Processes an [`Batch`](enum.TokenInstruction.html)
1875    /// instruction
1876    pub fn process_batch(
1877        program_id: &Address,
1878        mut accounts: &[AccountInfo],
1879        mut data: &[u8],
1880    ) -> ProgramResult {
1881        loop {
1882            let header = data
1883                .get(..Self::IX_HEADER_SIZE)
1884                .ok_or(TokenError::InvalidInstruction)?;
1885
1886            let expected_accounts = header[0] as usize;
1887            let data_offset = Self::IX_HEADER_SIZE + header[1] as usize;
1888
1889            let ix_accounts = accounts
1890                .get(..expected_accounts)
1891                .ok_or(ProgramError::NotEnoughAccountKeys)?;
1892            let ix_data = data
1893                .get(Self::IX_HEADER_SIZE..data_offset)
1894                .ok_or(TokenError::InvalidInstruction)?;
1895
1896            Self::_process_inner(program_id, ix_accounts, ix_data)?;
1897
1898            if data_offset == data.len() {
1899                break;
1900            }
1901
1902            accounts = &accounts[expected_accounts..];
1903            data = &data[data_offset..];
1904        }
1905
1906        Ok(())
1907    }
1908
1909    /// Processes an [`Instruction`](enum.Instruction.html).
1910    pub fn process(program_id: &Address, accounts: &[AccountInfo], input: &[u8]) -> ProgramResult {
1911        if let Ok(PodTokenInstruction::Batch) = decode_instruction_type(input) {
1912            msg!("Instruction: Batch");
1913            Self::process_batch(program_id, accounts, &input[1..])
1914        } else {
1915            Self::_process_inner(program_id, accounts, input)
1916        }
1917    }
1918
1919    fn _process_inner(
1920        program_id: &Address,
1921        accounts: &[AccountInfo],
1922        input: &[u8],
1923    ) -> ProgramResult {
1924        if let Ok(instruction_type) = decode_instruction_type(input) {
1925            match instruction_type {
1926                PodTokenInstruction::InitializeMint => {
1927                    msg!("Instruction: InitializeMint");
1928                    let (data, freeze_authority) =
1929                        decode_instruction_data_with_coption_pubkey::<InitializeMintData>(input)?;
1930                    Self::process_initialize_mint(
1931                        accounts,
1932                        data.decimals,
1933                        &data.mint_authority,
1934                        freeze_authority,
1935                    )
1936                }
1937                PodTokenInstruction::InitializeMint2 => {
1938                    msg!("Instruction: InitializeMint2");
1939                    let (data, freeze_authority) =
1940                        decode_instruction_data_with_coption_pubkey::<InitializeMintData>(input)?;
1941                    Self::process_initialize_mint2(
1942                        accounts,
1943                        data.decimals,
1944                        &data.mint_authority,
1945                        freeze_authority,
1946                    )
1947                }
1948                PodTokenInstruction::InitializeAccount => {
1949                    msg!("Instruction: InitializeAccount");
1950                    Self::process_initialize_account(accounts)
1951                }
1952                PodTokenInstruction::InitializeAccount2 => {
1953                    msg!("Instruction: InitializeAccount2");
1954                    let owner = decode_instruction_data::<Address>(input)?;
1955                    Self::process_initialize_account2(accounts, owner)
1956                }
1957                PodTokenInstruction::InitializeAccount3 => {
1958                    msg!("Instruction: InitializeAccount3");
1959                    let owner = decode_instruction_data::<Address>(input)?;
1960                    Self::process_initialize_account3(accounts, owner)
1961                }
1962                PodTokenInstruction::InitializeMultisig => {
1963                    msg!("Instruction: InitializeMultisig");
1964                    let data = decode_instruction_data::<InitializeMultisigData>(input)?;
1965                    Self::process_initialize_multisig(accounts, data.m)
1966                }
1967                PodTokenInstruction::InitializeMultisig2 => {
1968                    msg!("Instruction: InitializeMultisig2");
1969                    let data = decode_instruction_data::<InitializeMultisigData>(input)?;
1970                    Self::process_initialize_multisig2(accounts, data.m)
1971                }
1972                #[allow(deprecated)]
1973                PodTokenInstruction::Transfer => {
1974                    msg!("Instruction: Transfer");
1975                    let data = decode_instruction_data::<AmountData>(input)?;
1976                    Self::process_transfer(
1977                        program_id,
1978                        accounts,
1979                        data.amount.into(),
1980                        TransferInstruction::Unchecked,
1981                    )
1982                }
1983                PodTokenInstruction::Approve => {
1984                    msg!("Instruction: Approve");
1985                    let data = decode_instruction_data::<AmountData>(input)?;
1986                    Self::process_approve(
1987                        program_id,
1988                        accounts,
1989                        data.amount.into(),
1990                        InstructionVariant::Unchecked,
1991                    )
1992                }
1993                PodTokenInstruction::Revoke => {
1994                    msg!("Instruction: Revoke");
1995                    Self::process_revoke(program_id, accounts)
1996                }
1997                PodTokenInstruction::SetAuthority => {
1998                    msg!("Instruction: SetAuthority");
1999                    let (data, new_authority) =
2000                        decode_instruction_data_with_coption_pubkey::<SetAuthorityData>(input)?;
2001                    Self::process_set_authority(
2002                        program_id,
2003                        accounts,
2004                        AuthorityType::from(data.authority_type)?,
2005                        new_authority,
2006                    )
2007                }
2008                PodTokenInstruction::MintTo => {
2009                    msg!("Instruction: MintTo");
2010                    let data = decode_instruction_data::<AmountData>(input)?;
2011                    Self::process_mint_to(
2012                        program_id,
2013                        accounts,
2014                        data.amount.into(),
2015                        InstructionVariant::Unchecked,
2016                    )
2017                }
2018                PodTokenInstruction::Burn => {
2019                    msg!("Instruction: Burn");
2020                    let data = decode_instruction_data::<AmountData>(input)?;
2021                    Self::process_burn(
2022                        program_id,
2023                        accounts,
2024                        data.amount.into(),
2025                        BurnInstructionVariant::Standard,
2026                        InstructionVariant::Unchecked,
2027                    )
2028                }
2029                PodTokenInstruction::CloseAccount => {
2030                    msg!("Instruction: CloseAccount");
2031                    Self::process_close_account(program_id, accounts)
2032                }
2033                PodTokenInstruction::FreezeAccount => {
2034                    msg!("Instruction: FreezeAccount");
2035                    Self::process_toggle_freeze_account(program_id, accounts, true)
2036                }
2037                PodTokenInstruction::ThawAccount => {
2038                    msg!("Instruction: ThawAccount");
2039                    Self::process_toggle_freeze_account(program_id, accounts, false)
2040                }
2041                PodTokenInstruction::TransferChecked => {
2042                    msg!("Instruction: TransferChecked");
2043                    let data = decode_instruction_data::<AmountCheckedData>(input)?;
2044                    Self::process_transfer(
2045                        program_id,
2046                        accounts,
2047                        data.amount.into(),
2048                        TransferInstruction::Checked {
2049                            decimals: data.decimals,
2050                        },
2051                    )
2052                }
2053                PodTokenInstruction::ApproveChecked => {
2054                    msg!("Instruction: ApproveChecked");
2055                    let data = decode_instruction_data::<AmountCheckedData>(input)?;
2056                    Self::process_approve(
2057                        program_id,
2058                        accounts,
2059                        data.amount.into(),
2060                        InstructionVariant::Checked {
2061                            decimals: data.decimals,
2062                        },
2063                    )
2064                }
2065                PodTokenInstruction::MintToChecked => {
2066                    msg!("Instruction: MintToChecked");
2067                    let data = decode_instruction_data::<AmountCheckedData>(input)?;
2068                    Self::process_mint_to(
2069                        program_id,
2070                        accounts,
2071                        data.amount.into(),
2072                        InstructionVariant::Checked {
2073                            decimals: data.decimals,
2074                        },
2075                    )
2076                }
2077                PodTokenInstruction::BurnChecked => {
2078                    msg!("Instruction: BurnChecked");
2079                    let data = decode_instruction_data::<AmountCheckedData>(input)?;
2080                    Self::process_burn(
2081                        program_id,
2082                        accounts,
2083                        data.amount.into(),
2084                        BurnInstructionVariant::Standard,
2085                        InstructionVariant::Checked {
2086                            decimals: data.decimals,
2087                        },
2088                    )
2089                }
2090                PodTokenInstruction::SyncNative => {
2091                    msg!("Instruction: SyncNative");
2092                    Self::process_sync_native(accounts)
2093                }
2094                PodTokenInstruction::GetAccountDataSize => {
2095                    msg!("Instruction: GetAccountDataSize");
2096                    let extension_types = input[1..]
2097                        .chunks(std::mem::size_of::<ExtensionType>())
2098                        .map(ExtensionType::try_from)
2099                        .collect::<Result<Vec<_>, _>>()?;
2100                    Self::process_get_account_data_size(accounts, &extension_types)
2101                }
2102                PodTokenInstruction::InitializeMintCloseAuthority => {
2103                    msg!("Instruction: InitializeMintCloseAuthority");
2104                    let (_, close_authority) =
2105                        decode_instruction_data_with_coption_pubkey::<()>(input)?;
2106                    Self::process_initialize_mint_close_authority(accounts, close_authority)
2107                }
2108                PodTokenInstruction::TransferFeeExtension => {
2109                    transfer_fee::processor::process_instruction(program_id, accounts, &input[1..])
2110                }
2111                PodTokenInstruction::ConfidentialTransferExtension => {
2112                    confidential_transfer::processor::process_instruction(
2113                        program_id,
2114                        accounts,
2115                        &input[1..],
2116                    )
2117                }
2118                PodTokenInstruction::DefaultAccountStateExtension => {
2119                    default_account_state::processor::process_instruction(
2120                        program_id,
2121                        accounts,
2122                        &input[1..],
2123                    )
2124                }
2125                PodTokenInstruction::InitializeImmutableOwner => {
2126                    msg!("Instruction: InitializeImmutableOwner");
2127                    Self::process_initialize_immutable_owner(accounts)
2128                }
2129                PodTokenInstruction::AmountToUiAmount => {
2130                    msg!("Instruction: AmountToUiAmount");
2131                    let data = decode_instruction_data::<AmountData>(input)?;
2132                    Self::process_amount_to_ui_amount(accounts, data.amount.into())
2133                }
2134                PodTokenInstruction::UiAmountToAmount => {
2135                    msg!("Instruction: UiAmountToAmount");
2136                    let ui_amount = std::str::from_utf8(&input[1..])
2137                        .map_err(|_| TokenError::InvalidInstruction)?;
2138                    Self::process_ui_amount_to_amount(accounts, ui_amount)
2139                }
2140                PodTokenInstruction::Reallocate => {
2141                    msg!("Instruction: Reallocate");
2142                    let extension_types = input[1..]
2143                        .chunks(std::mem::size_of::<ExtensionType>())
2144                        .map(ExtensionType::try_from)
2145                        .collect::<Result<Vec<_>, _>>()?;
2146                    reallocate::process_reallocate(program_id, accounts, extension_types)
2147                }
2148                PodTokenInstruction::MemoTransferExtension => {
2149                    memo_transfer::processor::process_instruction(program_id, accounts, &input[1..])
2150                }
2151                PodTokenInstruction::CreateNativeMint => {
2152                    msg!("Instruction: CreateNativeMint");
2153                    Self::process_create_native_mint(accounts)
2154                }
2155                PodTokenInstruction::InitializeNonTransferableMint => {
2156                    msg!("Instruction: InitializeNonTransferableMint");
2157                    Self::process_initialize_non_transferable_mint(accounts)
2158                }
2159                PodTokenInstruction::InterestBearingMintExtension => {
2160                    interest_bearing_mint::processor::process_instruction(
2161                        program_id,
2162                        accounts,
2163                        &input[1..],
2164                    )
2165                }
2166                PodTokenInstruction::CpiGuardExtension => {
2167                    cpi_guard::processor::process_instruction(program_id, accounts, &input[1..])
2168                }
2169                PodTokenInstruction::InitializePermanentDelegate => {
2170                    msg!("Instruction: InitializePermanentDelegate");
2171                    let delegate = decode_instruction_data::<Address>(input)?;
2172                    Self::process_initialize_permanent_delegate(accounts, delegate)
2173                }
2174                PodTokenInstruction::TransferHookExtension => {
2175                    transfer_hook::processor::process_instruction(program_id, accounts, &input[1..])
2176                }
2177                PodTokenInstruction::ConfidentialTransferFeeExtension => {
2178                    confidential_transfer_fee::processor::process_instruction(
2179                        program_id,
2180                        accounts,
2181                        &input[1..],
2182                    )
2183                }
2184                PodTokenInstruction::WithdrawExcessLamports => {
2185                    msg!("Instruction: WithdrawExcessLamports");
2186                    Self::process_withdraw_excess_lamports(program_id, accounts)
2187                }
2188                PodTokenInstruction::MetadataPointerExtension => {
2189                    metadata_pointer::processor::process_instruction(
2190                        program_id,
2191                        accounts,
2192                        &input[1..],
2193                    )
2194                }
2195                PodTokenInstruction::GroupPointerExtension => {
2196                    group_pointer::processor::process_instruction(program_id, accounts, &input[1..])
2197                }
2198                PodTokenInstruction::GroupMemberPointerExtension => {
2199                    group_member_pointer::processor::process_instruction(
2200                        program_id,
2201                        accounts,
2202                        &input[1..],
2203                    )
2204                }
2205                PodTokenInstruction::ConfidentialMintBurnExtension => {
2206                    msg!("Instruction: ConfidentialMintBurnExtension");
2207                    confidential_mint_burn::processor::process_instruction(
2208                        program_id,
2209                        accounts,
2210                        &input[1..],
2211                    )
2212                }
2213                PodTokenInstruction::ScaledUiAmountExtension => {
2214                    msg!("Instruction: ScaledUiAmountExtension");
2215                    scaled_ui_amount::processor::process_instruction(
2216                        program_id,
2217                        accounts,
2218                        &input[1..],
2219                    )
2220                }
2221                PodTokenInstruction::PausableExtension => {
2222                    msg!("Instruction: PausableExtension");
2223                    pausable::processor::process_instruction(program_id, accounts, &input[1..])
2224                }
2225                PodTokenInstruction::PermissionedBurnExtension => {
2226                    msg!("Instruction: PermissionedBurnExtension");
2227                    permissioned_burn::processor::process_instruction(
2228                        program_id,
2229                        accounts,
2230                        &input[1..],
2231                    )
2232                }
2233                PodTokenInstruction::UnwrapLamports => {
2234                    msg!("Instruction: UnwrapLamports");
2235                    let (_, amount) = decode_instruction_data_with_coption_u64::<()>(input)?;
2236                    Self::process_unwrap_lamports(program_id, accounts, amount)
2237                }
2238                PodTokenInstruction::Batch => Err(TokenError::InvalidInstruction.into()),
2239            }
2240        } else if let Ok(instruction) = TokenMetadataInstruction::unpack(input) {
2241            token_metadata::processor::process_instruction(program_id, accounts, instruction)
2242        } else if let Ok(instruction) = TokenGroupInstruction::unpack(input) {
2243            token_group::processor::process_instruction(program_id, accounts, instruction)
2244        } else {
2245            Err(TokenError::InvalidInstruction.into())
2246        }
2247    }
2248
2249    /// Validates owner(s) are present. Used for Mints and Accounts only.
2250    pub fn validate_owner(
2251        program_id: &Address,
2252        expected_owner: &Address,
2253        owner_account_info: &AccountInfo,
2254        owner_account_data_len: usize,
2255        signers: &[AccountInfo],
2256    ) -> ProgramResult {
2257        if expected_owner != owner_account_info.key {
2258            return Err(TokenError::OwnerMismatch.into());
2259        }
2260
2261        let owned_by_token_program = program_id == owner_account_info.owner
2262            || owner_account_info.owner == &inline_spl_token::id()
2263            || owner_account_info.owner == &spl_token_2022_interface::id();
2264        if owned_by_token_program && owner_account_data_len == PodMultisig::SIZE_OF {
2265            let multisig_data = &owner_account_info.data.borrow();
2266            let multisig = bytemuck::try_from_bytes::<PodMultisig>(multisig_data)
2267                .map_err(|_| ProgramError::InvalidArgument)?;
2268            if !bool::from(multisig.is_initialized) {
2269                return Err(ProgramError::UninitializedAccount);
2270            }
2271            let mut num_signers = 0;
2272            let mut matched = [false; MAX_SIGNERS];
2273            for signer in signers.iter() {
2274                for (position, key) in multisig.signers[0..multisig.n as usize].iter().enumerate() {
2275                    if key == signer.key && !matched[position] {
2276                        if !signer.is_signer {
2277                            return Err(ProgramError::MissingRequiredSignature);
2278                        }
2279                        matched[position] = true;
2280                        num_signers += 1;
2281                    }
2282                }
2283            }
2284            if num_signers < multisig.m {
2285                return Err(ProgramError::MissingRequiredSignature);
2286            }
2287            return Ok(());
2288        } else if !owner_account_info.is_signer {
2289            return Err(ProgramError::MissingRequiredSignature);
2290        }
2291        Ok(())
2292    }
2293
2294    fn get_required_account_extensions(
2295        mint_account_info: &AccountInfo,
2296    ) -> Result<Vec<ExtensionType>, ProgramError> {
2297        let mint_data = mint_account_info.data.borrow();
2298        let state = PodStateWithExtensions::<PodMint>::unpack(&mint_data)
2299            .map_err(|_| Into::<ProgramError>::into(TokenError::InvalidMint))?;
2300        Self::get_required_account_extensions_from_unpacked_mint(mint_account_info.owner, &state)
2301    }
2302
2303    fn get_required_account_extensions_from_unpacked_mint(
2304        token_program_id: &Address,
2305        state: &PodStateWithExtensions<PodMint>,
2306    ) -> Result<Vec<ExtensionType>, ProgramError> {
2307        check_program_account(token_program_id)?;
2308        let mint_extensions = state.get_extension_types()?;
2309        Ok(ExtensionType::get_required_init_account_extensions(
2310            &mint_extensions,
2311        ))
2312    }
2313}
2314
2315/// Helper function to mostly delete an account in a test environment.  We could
2316/// potentially muck around the bytes assuming that a vec is passed in, but that
2317/// would be more trouble than it's worth.
2318#[cfg(not(target_os = "solana"))]
2319fn delete_account(account_info: &AccountInfo) -> Result<(), ProgramError> {
2320    account_info.assign(&system_program::id());
2321    let mut account_data = account_info.data.borrow_mut();
2322    let data_len = account_data.len();
2323    unsafe {
2324        solana_program_memory::sol_memset(*account_data, 0, data_len);
2325    }
2326    Ok(())
2327}
2328
2329/// Helper function to totally delete an account on-chain
2330#[cfg(target_os = "solana")]
2331fn delete_account(account_info: &AccountInfo) -> Result<(), ProgramError> {
2332    account_info.assign(&system_program::id());
2333    account_info.resize(0)
2334}
2335
2336#[cfg(test)]
2337mod tests {
2338    use {
2339        super::*,
2340        serial_test::serial,
2341        solana_account::{
2342            create_account_for_test, create_is_signer_account_infos, Account as SolanaAccount,
2343            ReadableAccount,
2344        },
2345        solana_account_info::IntoAccountInfo,
2346        solana_clock::Clock,
2347        solana_instruction::{AccountMeta, Instruction},
2348        solana_program_option::COption,
2349        solana_sdk_ids::sysvar::rent,
2350        spl_token_2022_interface::{
2351            extension::{
2352                permissioned_burn, transfer_fee::instruction::initialize_transfer_fee_config,
2353                ExtensionType,
2354            },
2355            instruction::*,
2356            state::Multisig,
2357        },
2358        std::sync::{Arc, RwLock},
2359    };
2360
2361    lazy_static::lazy_static! {
2362        static ref EXPECTED_DATA: Arc<RwLock<Vec<u8>>> = Arc::new(RwLock::new(Vec::new()));
2363    }
2364
2365    fn set_expected_data(expected_data: Vec<u8>) {
2366        *EXPECTED_DATA.write().unwrap() = expected_data;
2367    }
2368
2369    struct SyscallStubs {}
2370    impl solana_sysvar::program_stubs::SyscallStubs for SyscallStubs {
2371        fn sol_log(&self, _message: &str) {}
2372
2373        fn sol_invoke_signed(
2374            &self,
2375            _instruction: &Instruction,
2376            _account_infos: &[AccountInfo],
2377            _signers_seeds: &[&[&[u8]]],
2378        ) -> ProgramResult {
2379            Err(ProgramError::Custom(42)) // Not supported
2380        }
2381
2382        fn sol_get_clock_sysvar(&self, var_addr: *mut u8) -> u64 {
2383            unsafe {
2384                *(var_addr as *mut _ as *mut Clock) = Clock::default();
2385            }
2386            solana_program_entrypoint::SUCCESS
2387        }
2388
2389        fn sol_get_epoch_schedule_sysvar(&self, _var_addr: *mut u8) -> u64 {
2390            solana_instruction::error::UNSUPPORTED_SYSVAR
2391        }
2392
2393        #[allow(deprecated)]
2394        fn sol_get_fees_sysvar(&self, _var_addr: *mut u8) -> u64 {
2395            solana_instruction::error::UNSUPPORTED_SYSVAR
2396        }
2397
2398        fn sol_get_rent_sysvar(&self, var_addr: *mut u8) -> u64 {
2399            unsafe {
2400                *(var_addr as *mut _ as *mut Rent) = Rent::default();
2401            }
2402            solana_program_entrypoint::SUCCESS
2403        }
2404
2405        fn sol_set_return_data(&self, data: &[u8]) {
2406            assert_eq!(&*EXPECTED_DATA.read().unwrap(), data)
2407        }
2408    }
2409
2410    fn do_process_instruction(
2411        instruction: Instruction,
2412        accounts: Vec<&mut SolanaAccount>,
2413    ) -> ProgramResult {
2414        {
2415            use std::sync::Once;
2416            static ONCE: Once = Once::new();
2417
2418            ONCE.call_once(|| {
2419                solana_sysvar::program_stubs::set_syscall_stubs(Box::new(SyscallStubs {}));
2420            });
2421        }
2422
2423        let mut meta = instruction
2424            .accounts
2425            .iter()
2426            .zip(accounts)
2427            .map(|(account_meta, account)| (&account_meta.pubkey, account_meta.is_signer, account))
2428            .collect::<Vec<_>>();
2429
2430        let account_infos = create_is_signer_account_infos(&mut meta);
2431        Processor::process(&instruction.program_id, &account_infos, &instruction.data)
2432    }
2433
2434    fn do_process_instruction_dups(
2435        instruction: Instruction,
2436        account_infos: Vec<AccountInfo>,
2437    ) -> ProgramResult {
2438        {
2439            use std::sync::Once;
2440            static ONCE: Once = Once::new();
2441
2442            ONCE.call_once(|| {
2443                solana_sysvar::program_stubs::set_syscall_stubs(Box::new(SyscallStubs {}));
2444            });
2445        }
2446
2447        Processor::process(&instruction.program_id, &account_infos, &instruction.data)
2448    }
2449
2450    fn return_token_error_as_program_error() -> ProgramError {
2451        TokenError::MintMismatch.into()
2452    }
2453
2454    fn rent_sysvar() -> SolanaAccount {
2455        create_account_for_test(&Rent::default())
2456    }
2457
2458    fn mint_minimum_balance() -> u64 {
2459        Rent::default().minimum_balance(Mint::get_packed_len())
2460    }
2461
2462    fn account_minimum_balance() -> u64 {
2463        Rent::default().minimum_balance(Account::get_packed_len())
2464    }
2465
2466    fn multisig_minimum_balance() -> u64 {
2467        Rent::default().minimum_balance(Multisig::get_packed_len())
2468    }
2469
2470    fn batch_instruction(instructions: &[&Instruction]) -> Result<Instruction, ProgramError> {
2471        // Create a `Vec` of ordered `AccountMeta`s
2472        let mut accounts: Vec<AccountMeta> = vec![];
2473        // Start with the batch discriminator
2474        let mut data: Vec<u8> = vec![0xff];
2475
2476        for instruction in instructions {
2477            // Error out on non-token IX.
2478            if instruction.program_id.ne(&crate::ID) {
2479                return Err(ProgramError::IncorrectProgramId);
2480            }
2481
2482            data.push(instruction.accounts.len() as u8);
2483            data.push(instruction.data.len() as u8);
2484
2485            data.extend_from_slice(&instruction.data);
2486            accounts.extend_from_slice(&instruction.accounts);
2487        }
2488
2489        Ok(Instruction {
2490            program_id: crate::ID,
2491            data,
2492            accounts,
2493        })
2494    }
2495
2496    fn native_mint() -> SolanaAccount {
2497        let mut rent_sysvar = rent_sysvar();
2498        let mut mint_account =
2499            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &crate::id());
2500        do_process_instruction(
2501            initialize_mint(
2502                &crate::id(),
2503                &crate::native_mint::id(),
2504                &Address::default(),
2505                None,
2506                crate::native_mint::DECIMALS,
2507            )
2508            .unwrap(),
2509            vec![&mut mint_account, &mut rent_sysvar],
2510        )
2511        .unwrap();
2512        mint_account
2513    }
2514
2515    fn native_mint_to(account: &AccountInfo, amount: u64) -> ProgramResult {
2516        let mut buffer = account.try_borrow_mut_data()?;
2517        let mut account_account = Account::unpack(&buffer)?;
2518
2519        if !account_account.is_native() {
2520            return Err(TokenError::NonNativeNotSupported.into());
2521        }
2522
2523        let mut lamports = account.try_borrow_mut_lamports()?;
2524        **lamports += amount;
2525
2526        account_account.amount += amount;
2527
2528        Account::pack(account_account, &mut buffer)?;
2529
2530        Ok(())
2531    }
2532
2533    #[test]
2534    fn test_error_as_custom() {
2535        assert_eq!(
2536            return_token_error_as_program_error(),
2537            ProgramError::Custom(3)
2538        );
2539    }
2540
2541    #[test]
2542    fn test_unique_account_sizes() {
2543        assert_ne!(Mint::get_packed_len(), 0);
2544        assert_ne!(Mint::get_packed_len(), Account::get_packed_len());
2545        assert_ne!(Mint::get_packed_len(), Multisig::get_packed_len());
2546        assert_ne!(Account::get_packed_len(), 0);
2547        assert_ne!(Account::get_packed_len(), Multisig::get_packed_len());
2548        assert_ne!(Multisig::get_packed_len(), 0);
2549    }
2550
2551    #[test]
2552    fn test_initialize_mint() {
2553        let program_id = crate::id();
2554        let owner_key = Address::new_unique();
2555        let mint_key = Address::new_unique();
2556        let mut mint_account = SolanaAccount::new(42, Mint::get_packed_len(), &program_id);
2557        let mint2_key = Address::new_unique();
2558        let mut mint2_account =
2559            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
2560        let mut rent_sysvar = rent_sysvar();
2561
2562        // mint is not rent exempt
2563        assert_eq!(
2564            Err(TokenError::NotRentExempt.into()),
2565            do_process_instruction(
2566                initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
2567                vec![&mut mint_account, &mut rent_sysvar]
2568            )
2569        );
2570
2571        mint_account.lamports = mint_minimum_balance();
2572
2573        // create new mint
2574        do_process_instruction(
2575            initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
2576            vec![&mut mint_account, &mut rent_sysvar],
2577        )
2578        .unwrap();
2579
2580        // create twice
2581        assert_eq!(
2582            Err(TokenError::AlreadyInUse.into()),
2583            do_process_instruction(
2584                initialize_mint(&program_id, &mint_key, &owner_key, None, 2,).unwrap(),
2585                vec![&mut mint_account, &mut rent_sysvar]
2586            )
2587        );
2588
2589        // create another mint that can freeze
2590        do_process_instruction(
2591            initialize_mint(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(),
2592            vec![&mut mint2_account, &mut rent_sysvar],
2593        )
2594        .unwrap();
2595        let mint = Mint::unpack_unchecked(&mint2_account.data).unwrap();
2596        assert_eq!(mint.freeze_authority, COption::Some(owner_key));
2597    }
2598
2599    #[test]
2600    fn test_initialize_mint2() {
2601        let program_id = crate::id();
2602        let owner_key = Address::new_unique();
2603        let mint_key = Address::new_unique();
2604        let mut mint_account = SolanaAccount::new(42, Mint::get_packed_len(), &program_id);
2605        let mint2_key = Address::new_unique();
2606        let mut mint2_account =
2607            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
2608
2609        // mint is not rent exempt
2610        assert_eq!(
2611            Err(TokenError::NotRentExempt.into()),
2612            do_process_instruction(
2613                initialize_mint2(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
2614                vec![&mut mint_account]
2615            )
2616        );
2617
2618        mint_account.lamports = mint_minimum_balance();
2619
2620        // create new mint
2621        do_process_instruction(
2622            initialize_mint2(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
2623            vec![&mut mint_account],
2624        )
2625        .unwrap();
2626
2627        // create twice
2628        assert_eq!(
2629            Err(TokenError::AlreadyInUse.into()),
2630            do_process_instruction(
2631                initialize_mint2(&program_id, &mint_key, &owner_key, None, 2,).unwrap(),
2632                vec![&mut mint_account]
2633            )
2634        );
2635
2636        // create another mint that can freeze
2637        do_process_instruction(
2638            initialize_mint2(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(),
2639            vec![&mut mint2_account],
2640        )
2641        .unwrap();
2642        let mint = Mint::unpack_unchecked(&mint2_account.data).unwrap();
2643        assert_eq!(mint.freeze_authority, COption::Some(owner_key));
2644    }
2645
2646    #[test]
2647    fn test_initialize_mint_account() {
2648        let program_id = crate::id();
2649        let account_key = Address::new_unique();
2650        let mut account_account = SolanaAccount::new(42, Account::get_packed_len(), &program_id);
2651        let owner_key = Address::new_unique();
2652        let mut owner_account = SolanaAccount::default();
2653        let mint_key = Address::new_unique();
2654        let mut mint_account =
2655            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
2656        let mut rent_sysvar = rent_sysvar();
2657
2658        // account is not rent exempt
2659        assert_eq!(
2660            Err(TokenError::NotRentExempt.into()),
2661            do_process_instruction(
2662                initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
2663                vec![
2664                    &mut account_account,
2665                    &mut mint_account,
2666                    &mut owner_account,
2667                    &mut rent_sysvar
2668                ],
2669            )
2670        );
2671
2672        account_account.lamports = account_minimum_balance();
2673
2674        // mint is not valid (not initialized)
2675        assert_eq!(
2676            Err(TokenError::InvalidMint.into()),
2677            do_process_instruction(
2678                initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
2679                vec![
2680                    &mut account_account,
2681                    &mut mint_account,
2682                    &mut owner_account,
2683                    &mut rent_sysvar
2684                ],
2685            )
2686        );
2687
2688        // create mint
2689        do_process_instruction(
2690            initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
2691            vec![&mut mint_account, &mut rent_sysvar],
2692        )
2693        .unwrap();
2694
2695        // mint not owned by program
2696        let not_program_id = Address::new_unique();
2697        mint_account.owner = not_program_id;
2698        assert_eq!(
2699            Err(ProgramError::IncorrectProgramId),
2700            do_process_instruction(
2701                initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
2702                vec![
2703                    &mut account_account,
2704                    &mut mint_account,
2705                    &mut owner_account,
2706                    &mut rent_sysvar
2707                ],
2708            )
2709        );
2710        mint_account.owner = program_id;
2711
2712        // create account
2713        do_process_instruction(
2714            initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
2715            vec![
2716                &mut account_account,
2717                &mut mint_account,
2718                &mut owner_account,
2719                &mut rent_sysvar,
2720            ],
2721        )
2722        .unwrap();
2723
2724        // create twice
2725        assert_eq!(
2726            Err(TokenError::AlreadyInUse.into()),
2727            do_process_instruction(
2728                initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
2729                vec![
2730                    &mut account_account,
2731                    &mut mint_account,
2732                    &mut owner_account,
2733                    &mut rent_sysvar
2734                ],
2735            )
2736        );
2737    }
2738
2739    #[test]
2740    fn test_transfer_dups() {
2741        let program_id = crate::id();
2742        let account1_key = Address::new_unique();
2743        let mut account1_account = SolanaAccount::new(
2744            account_minimum_balance(),
2745            Account::get_packed_len(),
2746            &program_id,
2747        );
2748        let mut account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into();
2749        let account2_key = Address::new_unique();
2750        let mut account2_account = SolanaAccount::new(
2751            account_minimum_balance(),
2752            Account::get_packed_len(),
2753            &program_id,
2754        );
2755        let mut account2_info: AccountInfo = (&account2_key, false, &mut account2_account).into();
2756        let account3_key = Address::new_unique();
2757        let mut account3_account = SolanaAccount::new(
2758            account_minimum_balance(),
2759            Account::get_packed_len(),
2760            &program_id,
2761        );
2762        let account3_info: AccountInfo = (&account3_key, false, &mut account3_account).into();
2763        let account4_key = Address::new_unique();
2764        let mut account4_account = SolanaAccount::new(
2765            account_minimum_balance(),
2766            Account::get_packed_len(),
2767            &program_id,
2768        );
2769        let account4_info: AccountInfo = (&account4_key, true, &mut account4_account).into();
2770        let multisig_key = Address::new_unique();
2771        let mut multisig_account = SolanaAccount::new(
2772            multisig_minimum_balance(),
2773            Multisig::get_packed_len(),
2774            &program_id,
2775        );
2776        let multisig_info: AccountInfo = (&multisig_key, true, &mut multisig_account).into();
2777        let owner_key = Address::new_unique();
2778        let mut owner_account = SolanaAccount::default();
2779        let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into();
2780        let mint_key = Address::new_unique();
2781        let mut mint_account =
2782            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
2783        let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into();
2784        let rent_key = rent::id();
2785        let mut rent_sysvar = rent_sysvar();
2786        let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into();
2787
2788        // create mint
2789        do_process_instruction_dups(
2790            initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
2791            vec![mint_info.clone(), rent_info.clone()],
2792        )
2793        .unwrap();
2794
2795        // create account
2796        do_process_instruction_dups(
2797            initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(),
2798            vec![
2799                account1_info.clone(),
2800                mint_info.clone(),
2801                account1_info.clone(),
2802                rent_info.clone(),
2803            ],
2804        )
2805        .unwrap();
2806
2807        // create another account
2808        do_process_instruction_dups(
2809            initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(),
2810            vec![
2811                account2_info.clone(),
2812                mint_info.clone(),
2813                owner_info.clone(),
2814                rent_info.clone(),
2815            ],
2816        )
2817        .unwrap();
2818
2819        // mint to account
2820        do_process_instruction_dups(
2821            mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(),
2822            vec![mint_info.clone(), account1_info.clone(), owner_info.clone()],
2823        )
2824        .unwrap();
2825
2826        // source-owner transfer
2827        do_process_instruction_dups(
2828            #[allow(deprecated)]
2829            transfer(
2830                &program_id,
2831                &account1_key,
2832                &account2_key,
2833                &account1_key,
2834                &[],
2835                500,
2836            )
2837            .unwrap(),
2838            vec![
2839                account1_info.clone(),
2840                account2_info.clone(),
2841                account1_info.clone(),
2842            ],
2843        )
2844        .unwrap();
2845
2846        // source-owner TransferChecked
2847        do_process_instruction_dups(
2848            transfer_checked(
2849                &program_id,
2850                &account1_key,
2851                &mint_key,
2852                &account2_key,
2853                &account1_key,
2854                &[],
2855                500,
2856                2,
2857            )
2858            .unwrap(),
2859            vec![
2860                account1_info.clone(),
2861                mint_info.clone(),
2862                account2_info.clone(),
2863                account1_info.clone(),
2864            ],
2865        )
2866        .unwrap();
2867
2868        // source-delegate transfer
2869        let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap();
2870        account.amount = 1000;
2871        account.delegated_amount = 1000;
2872        account.delegate = COption::Some(account1_key);
2873        account.owner = owner_key;
2874        Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap();
2875
2876        do_process_instruction_dups(
2877            #[allow(deprecated)]
2878            transfer(
2879                &program_id,
2880                &account1_key,
2881                &account2_key,
2882                &account1_key,
2883                &[],
2884                500,
2885            )
2886            .unwrap(),
2887            vec![
2888                account1_info.clone(),
2889                account2_info.clone(),
2890                account1_info.clone(),
2891            ],
2892        )
2893        .unwrap();
2894
2895        // source-delegate TransferChecked
2896        do_process_instruction_dups(
2897            transfer_checked(
2898                &program_id,
2899                &account1_key,
2900                &mint_key,
2901                &account2_key,
2902                &account1_key,
2903                &[],
2904                500,
2905                2,
2906            )
2907            .unwrap(),
2908            vec![
2909                account1_info.clone(),
2910                mint_info.clone(),
2911                account2_info.clone(),
2912                account1_info.clone(),
2913            ],
2914        )
2915        .unwrap();
2916
2917        // test destination-owner transfer
2918        do_process_instruction_dups(
2919            initialize_account(&program_id, &account3_key, &mint_key, &account2_key).unwrap(),
2920            vec![
2921                account3_info.clone(),
2922                mint_info.clone(),
2923                account2_info.clone(),
2924                rent_info.clone(),
2925            ],
2926        )
2927        .unwrap();
2928        do_process_instruction_dups(
2929            mint_to(&program_id, &mint_key, &account3_key, &owner_key, &[], 1000).unwrap(),
2930            vec![mint_info.clone(), account3_info.clone(), owner_info.clone()],
2931        )
2932        .unwrap();
2933
2934        account1_info.is_signer = false;
2935        account2_info.is_signer = true;
2936        do_process_instruction_dups(
2937            #[allow(deprecated)]
2938            transfer(
2939                &program_id,
2940                &account3_key,
2941                &account2_key,
2942                &account2_key,
2943                &[],
2944                500,
2945            )
2946            .unwrap(),
2947            vec![
2948                account3_info.clone(),
2949                account2_info.clone(),
2950                account2_info.clone(),
2951            ],
2952        )
2953        .unwrap();
2954
2955        // destination-owner TransferChecked
2956        do_process_instruction_dups(
2957            transfer_checked(
2958                &program_id,
2959                &account3_key,
2960                &mint_key,
2961                &account2_key,
2962                &account2_key,
2963                &[],
2964                500,
2965                2,
2966            )
2967            .unwrap(),
2968            vec![
2969                account3_info.clone(),
2970                mint_info.clone(),
2971                account2_info.clone(),
2972                account2_info.clone(),
2973            ],
2974        )
2975        .unwrap();
2976
2977        // test source-multisig signer
2978        do_process_instruction_dups(
2979            initialize_multisig(&program_id, &multisig_key, &[&account4_key], 1).unwrap(),
2980            vec![
2981                multisig_info.clone(),
2982                rent_info.clone(),
2983                account4_info.clone(),
2984            ],
2985        )
2986        .unwrap();
2987
2988        do_process_instruction_dups(
2989            initialize_account(&program_id, &account4_key, &mint_key, &multisig_key).unwrap(),
2990            vec![
2991                account4_info.clone(),
2992                mint_info.clone(),
2993                multisig_info.clone(),
2994                rent_info.clone(),
2995            ],
2996        )
2997        .unwrap();
2998
2999        do_process_instruction_dups(
3000            mint_to(&program_id, &mint_key, &account4_key, &owner_key, &[], 1000).unwrap(),
3001            vec![mint_info.clone(), account4_info.clone(), owner_info.clone()],
3002        )
3003        .unwrap();
3004
3005        // source-multisig-signer transfer
3006        do_process_instruction_dups(
3007            #[allow(deprecated)]
3008            transfer(
3009                &program_id,
3010                &account4_key,
3011                &account2_key,
3012                &multisig_key,
3013                &[&account4_key],
3014                500,
3015            )
3016            .unwrap(),
3017            vec![
3018                account4_info.clone(),
3019                account2_info.clone(),
3020                multisig_info.clone(),
3021                account4_info.clone(),
3022            ],
3023        )
3024        .unwrap();
3025
3026        // source-multisig-signer TransferChecked
3027        do_process_instruction_dups(
3028            transfer_checked(
3029                &program_id,
3030                &account4_key,
3031                &mint_key,
3032                &account2_key,
3033                &multisig_key,
3034                &[&account4_key],
3035                500,
3036                2,
3037            )
3038            .unwrap(),
3039            vec![
3040                account4_info.clone(),
3041                mint_info.clone(),
3042                account2_info.clone(),
3043                multisig_info.clone(),
3044                account4_info.clone(),
3045            ],
3046        )
3047        .unwrap();
3048    }
3049
3050    #[test]
3051    fn test_transfer() {
3052        let program_id = crate::id();
3053        let account_key = Address::new_unique();
3054        let mut account_account = SolanaAccount::new(
3055            account_minimum_balance(),
3056            Account::get_packed_len(),
3057            &program_id,
3058        );
3059        let account2_key = Address::new_unique();
3060        let mut account2_account = SolanaAccount::new(
3061            account_minimum_balance(),
3062            Account::get_packed_len(),
3063            &program_id,
3064        );
3065        let account3_key = Address::new_unique();
3066        let mut account3_account = SolanaAccount::new(
3067            account_minimum_balance(),
3068            Account::get_packed_len(),
3069            &program_id,
3070        );
3071        let delegate_key = Address::new_unique();
3072        let mut delegate_account = SolanaAccount::default();
3073        let mismatch_key = Address::new_unique();
3074        let mut mismatch_account = SolanaAccount::new(
3075            account_minimum_balance(),
3076            Account::get_packed_len(),
3077            &program_id,
3078        );
3079        let owner_key = Address::new_unique();
3080        let mut owner_account = SolanaAccount::default();
3081        let owner2_key = Address::new_unique();
3082        let mut owner2_account = SolanaAccount::default();
3083        let mint_key = Address::new_unique();
3084        let mut mint_account =
3085            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
3086        let mint2_key = Address::new_unique();
3087        let mut rent_sysvar = rent_sysvar();
3088
3089        // create mint
3090        do_process_instruction(
3091            initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
3092            vec![&mut mint_account, &mut rent_sysvar],
3093        )
3094        .unwrap();
3095
3096        // create account
3097        do_process_instruction(
3098            initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
3099            vec![
3100                &mut account_account,
3101                &mut mint_account,
3102                &mut owner_account,
3103                &mut rent_sysvar,
3104            ],
3105        )
3106        .unwrap();
3107
3108        // create another account
3109        do_process_instruction(
3110            initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(),
3111            vec![
3112                &mut account2_account,
3113                &mut mint_account,
3114                &mut owner_account,
3115                &mut rent_sysvar,
3116            ],
3117        )
3118        .unwrap();
3119
3120        // create another account
3121        do_process_instruction(
3122            initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(),
3123            vec![
3124                &mut account3_account,
3125                &mut mint_account,
3126                &mut owner_account,
3127                &mut rent_sysvar,
3128            ],
3129        )
3130        .unwrap();
3131
3132        // create mismatch account
3133        do_process_instruction(
3134            initialize_account(&program_id, &mismatch_key, &mint_key, &owner_key).unwrap(),
3135            vec![
3136                &mut mismatch_account,
3137                &mut mint_account,
3138                &mut owner_account,
3139                &mut rent_sysvar,
3140            ],
3141        )
3142        .unwrap();
3143        let mut account = Account::unpack_unchecked(&mismatch_account.data).unwrap();
3144        account.mint = mint2_key;
3145        Account::pack(account, &mut mismatch_account.data).unwrap();
3146
3147        // mint to account
3148        do_process_instruction(
3149            mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(),
3150            vec![&mut mint_account, &mut account_account, &mut owner_account],
3151        )
3152        .unwrap();
3153
3154        // missing signer
3155        #[allow(deprecated)]
3156        let mut instruction = transfer(
3157            &program_id,
3158            &account_key,
3159            &account2_key,
3160            &owner_key,
3161            &[],
3162            1000,
3163        )
3164        .unwrap();
3165        instruction.accounts[2].is_signer = false;
3166        assert_eq!(
3167            Err(ProgramError::MissingRequiredSignature),
3168            do_process_instruction(
3169                instruction,
3170                vec![
3171                    &mut account_account,
3172                    &mut account2_account,
3173                    &mut owner_account,
3174                ],
3175            )
3176        );
3177
3178        // mismatch mint
3179        assert_eq!(
3180            Err(TokenError::MintMismatch.into()),
3181            do_process_instruction(
3182                #[allow(deprecated)]
3183                transfer(
3184                    &program_id,
3185                    &account_key,
3186                    &mismatch_key,
3187                    &owner_key,
3188                    &[],
3189                    1000
3190                )
3191                .unwrap(),
3192                vec![
3193                    &mut account_account,
3194                    &mut mismatch_account,
3195                    &mut owner_account,
3196                ],
3197            )
3198        );
3199
3200        // missing owner
3201        assert_eq!(
3202            Err(TokenError::OwnerMismatch.into()),
3203            do_process_instruction(
3204                #[allow(deprecated)]
3205                transfer(
3206                    &program_id,
3207                    &account_key,
3208                    &account2_key,
3209                    &owner2_key,
3210                    &[],
3211                    1000
3212                )
3213                .unwrap(),
3214                vec![
3215                    &mut account_account,
3216                    &mut account2_account,
3217                    &mut owner2_account,
3218                ],
3219            )
3220        );
3221
3222        // account not owned by program
3223        let not_program_id = Address::new_unique();
3224        account_account.owner = not_program_id;
3225        assert_eq!(
3226            Err(ProgramError::IncorrectProgramId),
3227            do_process_instruction(
3228                #[allow(deprecated)]
3229                transfer(&program_id, &account_key, &account2_key, &owner_key, &[], 0,).unwrap(),
3230                vec![
3231                    &mut account_account,
3232                    &mut account2_account,
3233                    &mut owner2_account,
3234                ],
3235            )
3236        );
3237        account_account.owner = program_id;
3238
3239        // account 2 not owned by program
3240        let not_program_id = Address::new_unique();
3241        account2_account.owner = not_program_id;
3242        assert_eq!(
3243            Err(ProgramError::IncorrectProgramId),
3244            do_process_instruction(
3245                #[allow(deprecated)]
3246                transfer(&program_id, &account_key, &account2_key, &owner_key, &[], 0,).unwrap(),
3247                vec![
3248                    &mut account_account,
3249                    &mut account2_account,
3250                    &mut owner2_account,
3251                ],
3252            )
3253        );
3254        account2_account.owner = program_id;
3255
3256        // transfer
3257        do_process_instruction(
3258            #[allow(deprecated)]
3259            transfer(
3260                &program_id,
3261                &account_key,
3262                &account2_key,
3263                &owner_key,
3264                &[],
3265                1000,
3266            )
3267            .unwrap(),
3268            vec![
3269                &mut account_account,
3270                &mut account2_account,
3271                &mut owner_account,
3272            ],
3273        )
3274        .unwrap();
3275
3276        // insufficient funds
3277        assert_eq!(
3278            Err(TokenError::InsufficientFunds.into()),
3279            do_process_instruction(
3280                #[allow(deprecated)]
3281                transfer(&program_id, &account_key, &account2_key, &owner_key, &[], 1).unwrap(),
3282                vec![
3283                    &mut account_account,
3284                    &mut account2_account,
3285                    &mut owner_account,
3286                ],
3287            )
3288        );
3289
3290        // transfer half back
3291        do_process_instruction(
3292            #[allow(deprecated)]
3293            transfer(
3294                &program_id,
3295                &account2_key,
3296                &account_key,
3297                &owner_key,
3298                &[],
3299                500,
3300            )
3301            .unwrap(),
3302            vec![
3303                &mut account2_account,
3304                &mut account_account,
3305                &mut owner_account,
3306            ],
3307        )
3308        .unwrap();
3309
3310        // incorrect decimals
3311        assert_eq!(
3312            Err(TokenError::MintDecimalsMismatch.into()),
3313            do_process_instruction(
3314                transfer_checked(
3315                    &program_id,
3316                    &account2_key,
3317                    &mint_key,
3318                    &account_key,
3319                    &owner_key,
3320                    &[],
3321                    1,
3322                    10 // <-- incorrect decimals
3323                )
3324                .unwrap(),
3325                vec![
3326                    &mut account2_account,
3327                    &mut mint_account,
3328                    &mut account_account,
3329                    &mut owner_account,
3330                ],
3331            )
3332        );
3333
3334        // incorrect mint
3335        assert_eq!(
3336            Err(TokenError::MintMismatch.into()),
3337            do_process_instruction(
3338                transfer_checked(
3339                    &program_id,
3340                    &account2_key,
3341                    &account3_key, // <-- incorrect mint
3342                    &account_key,
3343                    &owner_key,
3344                    &[],
3345                    1,
3346                    2
3347                )
3348                .unwrap(),
3349                vec![
3350                    &mut account2_account,
3351                    &mut account3_account, // <-- incorrect mint
3352                    &mut account_account,
3353                    &mut owner_account,
3354                ],
3355            )
3356        );
3357        // transfer rest with explicit decimals
3358        do_process_instruction(
3359            transfer_checked(
3360                &program_id,
3361                &account2_key,
3362                &mint_key,
3363                &account_key,
3364                &owner_key,
3365                &[],
3366                500,
3367                2,
3368            )
3369            .unwrap(),
3370            vec![
3371                &mut account2_account,
3372                &mut mint_account,
3373                &mut account_account,
3374                &mut owner_account,
3375            ],
3376        )
3377        .unwrap();
3378
3379        // insufficient funds
3380        assert_eq!(
3381            Err(TokenError::InsufficientFunds.into()),
3382            do_process_instruction(
3383                #[allow(deprecated)]
3384                transfer(&program_id, &account2_key, &account_key, &owner_key, &[], 1).unwrap(),
3385                vec![
3386                    &mut account2_account,
3387                    &mut account_account,
3388                    &mut owner_account,
3389                ],
3390            )
3391        );
3392
3393        // approve delegate
3394        do_process_instruction(
3395            approve(
3396                &program_id,
3397                &account_key,
3398                &delegate_key,
3399                &owner_key,
3400                &[],
3401                100,
3402            )
3403            .unwrap(),
3404            vec![
3405                &mut account_account,
3406                &mut delegate_account,
3407                &mut owner_account,
3408            ],
3409        )
3410        .unwrap();
3411
3412        // not a delegate of source account
3413        assert_eq!(
3414            Err(TokenError::OwnerMismatch.into()),
3415            do_process_instruction(
3416                #[allow(deprecated)]
3417                transfer(
3418                    &program_id,
3419                    &account_key,
3420                    &account2_key,
3421                    &owner2_key, // <-- incorrect owner or delegate
3422                    &[],
3423                    1,
3424                )
3425                .unwrap(),
3426                vec![
3427                    &mut account_account,
3428                    &mut account2_account,
3429                    &mut owner2_account,
3430                ],
3431            )
3432        );
3433
3434        // insufficient funds approved via delegate
3435        assert_eq!(
3436            Err(TokenError::InsufficientFunds.into()),
3437            do_process_instruction(
3438                #[allow(deprecated)]
3439                transfer(
3440                    &program_id,
3441                    &account_key,
3442                    &account2_key,
3443                    &delegate_key,
3444                    &[],
3445                    101
3446                )
3447                .unwrap(),
3448                vec![
3449                    &mut account_account,
3450                    &mut account2_account,
3451                    &mut delegate_account,
3452                ],
3453            )
3454        );
3455
3456        // transfer via delegate
3457        do_process_instruction(
3458            #[allow(deprecated)]
3459            transfer(
3460                &program_id,
3461                &account_key,
3462                &account2_key,
3463                &delegate_key,
3464                &[],
3465                100,
3466            )
3467            .unwrap(),
3468            vec![
3469                &mut account_account,
3470                &mut account2_account,
3471                &mut delegate_account,
3472            ],
3473        )
3474        .unwrap();
3475
3476        // insufficient funds approved via delegate
3477        assert_eq!(
3478            Err(TokenError::OwnerMismatch.into()),
3479            do_process_instruction(
3480                #[allow(deprecated)]
3481                transfer(
3482                    &program_id,
3483                    &account_key,
3484                    &account2_key,
3485                    &delegate_key,
3486                    &[],
3487                    1
3488                )
3489                .unwrap(),
3490                vec![
3491                    &mut account_account,
3492                    &mut account2_account,
3493                    &mut delegate_account,
3494                ],
3495            )
3496        );
3497
3498        // transfer rest
3499        do_process_instruction(
3500            #[allow(deprecated)]
3501            transfer(
3502                &program_id,
3503                &account_key,
3504                &account2_key,
3505                &owner_key,
3506                &[],
3507                900,
3508            )
3509            .unwrap(),
3510            vec![
3511                &mut account_account,
3512                &mut account2_account,
3513                &mut owner_account,
3514            ],
3515        )
3516        .unwrap();
3517
3518        // approve delegate
3519        do_process_instruction(
3520            approve(
3521                &program_id,
3522                &account_key,
3523                &delegate_key,
3524                &owner_key,
3525                &[],
3526                100,
3527            )
3528            .unwrap(),
3529            vec![
3530                &mut account_account,
3531                &mut delegate_account,
3532                &mut owner_account,
3533            ],
3534        )
3535        .unwrap();
3536
3537        // insufficient funds in source account via delegate
3538        assert_eq!(
3539            Err(TokenError::InsufficientFunds.into()),
3540            do_process_instruction(
3541                #[allow(deprecated)]
3542                transfer(
3543                    &program_id,
3544                    &account_key,
3545                    &account2_key,
3546                    &delegate_key,
3547                    &[],
3548                    100
3549                )
3550                .unwrap(),
3551                vec![
3552                    &mut account_account,
3553                    &mut account2_account,
3554                    &mut delegate_account,
3555                ],
3556            )
3557        );
3558    }
3559
3560    #[test]
3561    fn test_self_transfer() {
3562        let program_id = crate::id();
3563        let account_key = Address::new_unique();
3564        let mut account_account = SolanaAccount::new(
3565            account_minimum_balance(),
3566            Account::get_packed_len(),
3567            &program_id,
3568        );
3569        let account2_key = Address::new_unique();
3570        let mut account2_account = SolanaAccount::new(
3571            account_minimum_balance(),
3572            Account::get_packed_len(),
3573            &program_id,
3574        );
3575        let account3_key = Address::new_unique();
3576        let mut account3_account = SolanaAccount::new(
3577            account_minimum_balance(),
3578            Account::get_packed_len(),
3579            &program_id,
3580        );
3581        let delegate_key = Address::new_unique();
3582        let mut delegate_account = SolanaAccount::default();
3583        let owner_key = Address::new_unique();
3584        let mut owner_account = SolanaAccount::default();
3585        let owner2_key = Address::new_unique();
3586        let mut owner2_account = SolanaAccount::default();
3587        let mint_key = Address::new_unique();
3588        let mut mint_account =
3589            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
3590        let mut rent_sysvar = rent_sysvar();
3591
3592        // create mint
3593        do_process_instruction(
3594            initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
3595            vec![&mut mint_account, &mut rent_sysvar],
3596        )
3597        .unwrap();
3598
3599        // create account
3600        do_process_instruction(
3601            initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
3602            vec![
3603                &mut account_account,
3604                &mut mint_account,
3605                &mut owner_account,
3606                &mut rent_sysvar,
3607            ],
3608        )
3609        .unwrap();
3610
3611        // create another account
3612        do_process_instruction(
3613            initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(),
3614            vec![
3615                &mut account2_account,
3616                &mut mint_account,
3617                &mut owner_account,
3618                &mut rent_sysvar,
3619            ],
3620        )
3621        .unwrap();
3622
3623        // create another account
3624        do_process_instruction(
3625            initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(),
3626            vec![
3627                &mut account3_account,
3628                &mut mint_account,
3629                &mut owner_account,
3630                &mut rent_sysvar,
3631            ],
3632        )
3633        .unwrap();
3634
3635        // mint to account
3636        do_process_instruction(
3637            mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(),
3638            vec![&mut mint_account, &mut account_account, &mut owner_account],
3639        )
3640        .unwrap();
3641
3642        let account_info = (&account_key, false, &mut account_account).into_account_info();
3643        let account3_info = (&account3_key, false, &mut account3_account).into_account_info();
3644        let delegate_info = (&delegate_key, true, &mut delegate_account).into_account_info();
3645        let owner_info = (&owner_key, true, &mut owner_account).into_account_info();
3646        let owner2_info = (&owner2_key, true, &mut owner2_account).into_account_info();
3647        let mint_info = (&mint_key, false, &mut mint_account).into_account_info();
3648
3649        // transfer
3650        #[allow(deprecated)]
3651        let instruction = transfer(
3652            &program_id,
3653            account_info.key,
3654            account_info.key,
3655            owner_info.key,
3656            &[],
3657            1000,
3658        )
3659        .unwrap();
3660        assert_eq!(
3661            Ok(()),
3662            Processor::process(
3663                &instruction.program_id,
3664                &[
3665                    account_info.clone(),
3666                    account_info.clone(),
3667                    owner_info.clone(),
3668                ],
3669                &instruction.data,
3670            )
3671        );
3672        // no balance change...
3673        let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap();
3674        assert_eq!(account.amount, 1000);
3675
3676        // transfer checked
3677        let instruction = transfer_checked(
3678            &program_id,
3679            account_info.key,
3680            mint_info.key,
3681            account_info.key,
3682            owner_info.key,
3683            &[],
3684            1000,
3685            2,
3686        )
3687        .unwrap();
3688        assert_eq!(
3689            Ok(()),
3690            Processor::process(
3691                &instruction.program_id,
3692                &[
3693                    account_info.clone(),
3694                    mint_info.clone(),
3695                    account_info.clone(),
3696                    owner_info.clone(),
3697                ],
3698                &instruction.data,
3699            )
3700        );
3701        // no balance change...
3702        let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap();
3703        assert_eq!(account.amount, 1000);
3704
3705        // missing signer
3706        let mut owner_no_sign_info = owner_info.clone();
3707        #[allow(deprecated)]
3708        let mut instruction = transfer(
3709            &program_id,
3710            account_info.key,
3711            account_info.key,
3712            owner_no_sign_info.key,
3713            &[],
3714            1000,
3715        )
3716        .unwrap();
3717        instruction.accounts[2].is_signer = false;
3718        owner_no_sign_info.is_signer = false;
3719        assert_eq!(
3720            Err(ProgramError::MissingRequiredSignature),
3721            Processor::process(
3722                &instruction.program_id,
3723                &[
3724                    account_info.clone(),
3725                    account_info.clone(),
3726                    owner_no_sign_info.clone(),
3727                ],
3728                &instruction.data,
3729            )
3730        );
3731
3732        // missing signer checked
3733        let mut instruction = transfer_checked(
3734            &program_id,
3735            account_info.key,
3736            mint_info.key,
3737            account_info.key,
3738            owner_no_sign_info.key,
3739            &[],
3740            1000,
3741            2,
3742        )
3743        .unwrap();
3744        instruction.accounts[3].is_signer = false;
3745        assert_eq!(
3746            Err(ProgramError::MissingRequiredSignature),
3747            Processor::process(
3748                &instruction.program_id,
3749                &[
3750                    account_info.clone(),
3751                    mint_info.clone(),
3752                    account_info.clone(),
3753                    owner_no_sign_info,
3754                ],
3755                &instruction.data,
3756            )
3757        );
3758
3759        // missing owner
3760        #[allow(deprecated)]
3761        let instruction = transfer(
3762            &program_id,
3763            account_info.key,
3764            account_info.key,
3765            owner2_info.key,
3766            &[],
3767            1000,
3768        )
3769        .unwrap();
3770        assert_eq!(
3771            Err(TokenError::OwnerMismatch.into()),
3772            Processor::process(
3773                &instruction.program_id,
3774                &[
3775                    account_info.clone(),
3776                    account_info.clone(),
3777                    owner2_info.clone(),
3778                ],
3779                &instruction.data,
3780            )
3781        );
3782
3783        // missing owner checked
3784        let instruction = transfer_checked(
3785            &program_id,
3786            account_info.key,
3787            mint_info.key,
3788            account_info.key,
3789            owner2_info.key,
3790            &[],
3791            1000,
3792            2,
3793        )
3794        .unwrap();
3795        assert_eq!(
3796            Err(TokenError::OwnerMismatch.into()),
3797            Processor::process(
3798                &instruction.program_id,
3799                &[
3800                    account_info.clone(),
3801                    mint_info.clone(),
3802                    account_info.clone(),
3803                    owner2_info.clone(),
3804                ],
3805                &instruction.data,
3806            )
3807        );
3808
3809        // insufficient funds
3810        #[allow(deprecated)]
3811        let instruction = transfer(
3812            &program_id,
3813            account_info.key,
3814            account_info.key,
3815            owner_info.key,
3816            &[],
3817            1001,
3818        )
3819        .unwrap();
3820        assert_eq!(
3821            Err(TokenError::InsufficientFunds.into()),
3822            Processor::process(
3823                &instruction.program_id,
3824                &[
3825                    account_info.clone(),
3826                    account_info.clone(),
3827                    owner_info.clone(),
3828                ],
3829                &instruction.data,
3830            )
3831        );
3832
3833        // insufficient funds checked
3834        let instruction = transfer_checked(
3835            &program_id,
3836            account_info.key,
3837            mint_info.key,
3838            account_info.key,
3839            owner_info.key,
3840            &[],
3841            1001,
3842            2,
3843        )
3844        .unwrap();
3845        assert_eq!(
3846            Err(TokenError::InsufficientFunds.into()),
3847            Processor::process(
3848                &instruction.program_id,
3849                &[
3850                    account_info.clone(),
3851                    mint_info.clone(),
3852                    account_info.clone(),
3853                    owner_info.clone(),
3854                ],
3855                &instruction.data,
3856            )
3857        );
3858
3859        // incorrect decimals
3860        let instruction = transfer_checked(
3861            &program_id,
3862            account_info.key,
3863            mint_info.key,
3864            account_info.key,
3865            owner_info.key,
3866            &[],
3867            1,
3868            10, // <-- incorrect decimals
3869        )
3870        .unwrap();
3871        assert_eq!(
3872            Err(TokenError::MintDecimalsMismatch.into()),
3873            Processor::process(
3874                &instruction.program_id,
3875                &[
3876                    account_info.clone(),
3877                    mint_info.clone(),
3878                    account_info.clone(),
3879                    owner_info.clone(),
3880                ],
3881                &instruction.data,
3882            )
3883        );
3884
3885        // incorrect mint
3886        let instruction = transfer_checked(
3887            &program_id,
3888            account_info.key,
3889            account3_info.key, // <-- incorrect mint
3890            account_info.key,
3891            owner_info.key,
3892            &[],
3893            1,
3894            2,
3895        )
3896        .unwrap();
3897        assert_eq!(
3898            Err(TokenError::MintMismatch.into()),
3899            Processor::process(
3900                &instruction.program_id,
3901                &[
3902                    account_info.clone(),
3903                    account3_info.clone(), // <-- incorrect mint
3904                    account_info.clone(),
3905                    owner_info.clone(),
3906                ],
3907                &instruction.data,
3908            )
3909        );
3910
3911        // approve delegate
3912        let instruction = approve(
3913            &program_id,
3914            account_info.key,
3915            delegate_info.key,
3916            owner_info.key,
3917            &[],
3918            100,
3919        )
3920        .unwrap();
3921        Processor::process(
3922            &instruction.program_id,
3923            &[
3924                account_info.clone(),
3925                delegate_info.clone(),
3926                owner_info.clone(),
3927            ],
3928            &instruction.data,
3929        )
3930        .unwrap();
3931
3932        // delegate transfer
3933        #[allow(deprecated)]
3934        let instruction = transfer(
3935            &program_id,
3936            account_info.key,
3937            account_info.key,
3938            delegate_info.key,
3939            &[],
3940            100,
3941        )
3942        .unwrap();
3943        assert_eq!(
3944            Ok(()),
3945            Processor::process(
3946                &instruction.program_id,
3947                &[
3948                    account_info.clone(),
3949                    account_info.clone(),
3950                    delegate_info.clone(),
3951                ],
3952                &instruction.data,
3953            )
3954        );
3955        // no balance change...
3956        let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap();
3957        assert_eq!(account.amount, 1000);
3958        assert_eq!(account.delegated_amount, 100);
3959
3960        // delegate transfer checked
3961        let instruction = transfer_checked(
3962            &program_id,
3963            account_info.key,
3964            mint_info.key,
3965            account_info.key,
3966            delegate_info.key,
3967            &[],
3968            100,
3969            2,
3970        )
3971        .unwrap();
3972        assert_eq!(
3973            Ok(()),
3974            Processor::process(
3975                &instruction.program_id,
3976                &[
3977                    account_info.clone(),
3978                    mint_info.clone(),
3979                    account_info.clone(),
3980                    delegate_info.clone(),
3981                ],
3982                &instruction.data,
3983            )
3984        );
3985        // no balance change...
3986        let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap();
3987        assert_eq!(account.amount, 1000);
3988        assert_eq!(account.delegated_amount, 100);
3989
3990        // delegate insufficient funds
3991        #[allow(deprecated)]
3992        let instruction = transfer(
3993            &program_id,
3994            account_info.key,
3995            account_info.key,
3996            delegate_info.key,
3997            &[],
3998            101,
3999        )
4000        .unwrap();
4001        assert_eq!(
4002            Err(TokenError::InsufficientFunds.into()),
4003            Processor::process(
4004                &instruction.program_id,
4005                &[
4006                    account_info.clone(),
4007                    account_info.clone(),
4008                    delegate_info.clone(),
4009                ],
4010                &instruction.data,
4011            )
4012        );
4013
4014        // delegate insufficient funds checked
4015        let instruction = transfer_checked(
4016            &program_id,
4017            account_info.key,
4018            mint_info.key,
4019            account_info.key,
4020            delegate_info.key,
4021            &[],
4022            101,
4023            2,
4024        )
4025        .unwrap();
4026        assert_eq!(
4027            Err(TokenError::InsufficientFunds.into()),
4028            Processor::process(
4029                &instruction.program_id,
4030                &[
4031                    account_info.clone(),
4032                    mint_info.clone(),
4033                    account_info.clone(),
4034                    delegate_info.clone(),
4035                ],
4036                &instruction.data,
4037            )
4038        );
4039
4040        // owner transfer with delegate assigned
4041        #[allow(deprecated)]
4042        let instruction = transfer(
4043            &program_id,
4044            account_info.key,
4045            account_info.key,
4046            owner_info.key,
4047            &[],
4048            1000,
4049        )
4050        .unwrap();
4051        assert_eq!(
4052            Ok(()),
4053            Processor::process(
4054                &instruction.program_id,
4055                &[
4056                    account_info.clone(),
4057                    account_info.clone(),
4058                    owner_info.clone(),
4059                ],
4060                &instruction.data,
4061            )
4062        );
4063        // no balance change...
4064        let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap();
4065        assert_eq!(account.amount, 1000);
4066
4067        // owner transfer with delegate assigned checked
4068        let instruction = transfer_checked(
4069            &program_id,
4070            account_info.key,
4071            mint_info.key,
4072            account_info.key,
4073            owner_info.key,
4074            &[],
4075            1000,
4076            2,
4077        )
4078        .unwrap();
4079        assert_eq!(
4080            Ok(()),
4081            Processor::process(
4082                &instruction.program_id,
4083                &[
4084                    account_info.clone(),
4085                    mint_info.clone(),
4086                    account_info.clone(),
4087                    owner_info.clone(),
4088                ],
4089                &instruction.data,
4090            )
4091        );
4092        // no balance change...
4093        let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap();
4094        assert_eq!(account.amount, 1000);
4095    }
4096
4097    #[test]
4098    fn test_unwrap_lamports_dups() {
4099        let program_id = crate::id();
4100        let account1_key = Address::new_unique();
4101        let mut account1_account = SolanaAccount::new(
4102            account_minimum_balance(),
4103            Account::get_packed_len(),
4104            &program_id,
4105        );
4106        let mut account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into();
4107        let account2_key = Address::new_unique();
4108        let mut account2_account = SolanaAccount::new(
4109            account_minimum_balance(),
4110            Account::get_packed_len(),
4111            &program_id,
4112        );
4113        let mut account2_info: AccountInfo = (&account2_key, false, &mut account2_account).into();
4114        let account3_key = Address::new_unique();
4115        let mut account3_account = SolanaAccount::new(
4116            account_minimum_balance(),
4117            Account::get_packed_len(),
4118            &program_id,
4119        );
4120        let account3_info: AccountInfo = (&account3_key, false, &mut account3_account).into();
4121        let account4_key = Address::new_unique();
4122        let mut account4_account = SolanaAccount::new(
4123            account_minimum_balance(),
4124            Account::get_packed_len(),
4125            &program_id,
4126        );
4127        let account4_info: AccountInfo = (&account4_key, true, &mut account4_account).into();
4128        let multisig_key = Address::new_unique();
4129        let mut multisig_account = SolanaAccount::new(
4130            multisig_minimum_balance(),
4131            Multisig::get_packed_len(),
4132            &program_id,
4133        );
4134        let multisig_info: AccountInfo = (&multisig_key, true, &mut multisig_account).into();
4135        let owner_key = Address::new_unique();
4136        let mut owner_account = SolanaAccount::default();
4137        let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into();
4138        let mint_key = native_mint::id();
4139        let mut mint_account = native_mint();
4140        let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into();
4141        let rent_key = rent::id();
4142        let mut rent_sysvar = rent_sysvar();
4143        let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into();
4144
4145        // create account
4146        do_process_instruction_dups(
4147            initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(),
4148            vec![
4149                account1_info.clone(),
4150                mint_info.clone(),
4151                account1_info.clone(),
4152                rent_info.clone(),
4153            ],
4154        )
4155        .unwrap();
4156
4157        // create another account
4158        do_process_instruction_dups(
4159            initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(),
4160            vec![
4161                account2_info.clone(),
4162                mint_info.clone(),
4163                owner_info.clone(),
4164                rent_info.clone(),
4165            ],
4166        )
4167        .unwrap();
4168
4169        // mint to account
4170        native_mint_to(&account1_info, 1000).unwrap();
4171
4172        // source-owner unwrap lamports
4173        do_process_instruction_dups(
4174            unwrap_lamports(
4175                &program_id,
4176                &account1_key,
4177                &account2_key,
4178                &account1_key,
4179                &[],
4180                Some(500),
4181            )
4182            .unwrap(),
4183            vec![
4184                account1_info.clone(),
4185                account2_info.clone(),
4186                account1_info.clone(),
4187            ],
4188        )
4189        .unwrap();
4190
4191        // test destination-owner unwrap lamports
4192        do_process_instruction_dups(
4193            initialize_account(&program_id, &account3_key, &mint_key, &account2_key).unwrap(),
4194            vec![
4195                account3_info.clone(),
4196                mint_info.clone(),
4197                account2_info.clone(),
4198                rent_info.clone(),
4199            ],
4200        )
4201        .unwrap();
4202        native_mint_to(&account3_info, 1000).unwrap();
4203
4204        account1_info.is_signer = false;
4205        account2_info.is_signer = true;
4206        do_process_instruction_dups(
4207            unwrap_lamports(
4208                &program_id,
4209                &account3_key,
4210                &account2_key,
4211                &account2_key,
4212                &[],
4213                Some(500),
4214            )
4215            .unwrap(),
4216            vec![
4217                account3_info.clone(),
4218                account2_info.clone(),
4219                account2_info.clone(),
4220            ],
4221        )
4222        .unwrap();
4223
4224        // test source-multisig signer
4225        do_process_instruction_dups(
4226            initialize_multisig(&program_id, &multisig_key, &[&account4_key], 1).unwrap(),
4227            vec![
4228                multisig_info.clone(),
4229                rent_info.clone(),
4230                account4_info.clone(),
4231            ],
4232        )
4233        .unwrap();
4234
4235        do_process_instruction_dups(
4236            initialize_account(&program_id, &account4_key, &mint_key, &multisig_key).unwrap(),
4237            vec![
4238                account4_info.clone(),
4239                mint_info.clone(),
4240                multisig_info.clone(),
4241                rent_info.clone(),
4242            ],
4243        )
4244        .unwrap();
4245        native_mint_to(&account4_info, 1000).unwrap();
4246
4247        // source-multisig-signer unwrap lamports
4248        do_process_instruction_dups(
4249            unwrap_lamports(
4250                &program_id,
4251                &account4_key,
4252                &account2_key,
4253                &multisig_key,
4254                &[&account4_key],
4255                Some(500),
4256            )
4257            .unwrap(),
4258            vec![
4259                account4_info.clone(),
4260                account2_info.clone(),
4261                multisig_info.clone(),
4262                account4_info.clone(),
4263            ],
4264        )
4265        .unwrap();
4266    }
4267
4268    #[test]
4269    fn test_unwrap_lamports() {
4270        let program_id = crate::id();
4271        let zero_space_rent_exempt_balance = Rent::default().minimum_balance(0);
4272        let account_key = Address::new_unique();
4273        let mut account_account = SolanaAccount::new(
4274            account_minimum_balance(),
4275            Account::get_packed_len(),
4276            &program_id,
4277        );
4278        let account2_key = Address::new_unique();
4279        let mut account2_account = SolanaAccount::new(
4280            zero_space_rent_exempt_balance,
4281            Account::get_packed_len(),
4282            &program_id,
4283        );
4284        let mismatch_account_key = Address::new_unique();
4285        let mut mismatch_account_account = SolanaAccount::new(
4286            account_minimum_balance(),
4287            Account::get_packed_len(),
4288            &program_id,
4289        );
4290        let owner_key = Address::new_unique();
4291        let mut owner_account = SolanaAccount::default();
4292        let owner2_key = Address::new_unique();
4293        let mut owner2_account = SolanaAccount::default();
4294        let mint_key = native_mint::id();
4295        let mut mint_account = native_mint();
4296        let mismatch_mint_key = Address::new_unique();
4297        let mut mismatch_mint_account =
4298            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
4299        let mut rent_sysvar = rent_sysvar();
4300
4301        // create mismatch mint
4302        do_process_instruction(
4303            initialize_mint(&program_id, &mismatch_mint_key, &owner_key, None, 2).unwrap(),
4304            vec![&mut mismatch_mint_account, &mut rent_sysvar],
4305        )
4306        .unwrap();
4307
4308        // create account
4309        do_process_instruction(
4310            initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
4311            vec![
4312                &mut account_account,
4313                &mut mint_account,
4314                &mut owner_account,
4315                &mut rent_sysvar,
4316            ],
4317        )
4318        .unwrap();
4319
4320        // create mismatch account
4321        do_process_instruction(
4322            initialize_account(
4323                &program_id,
4324                &mismatch_account_key,
4325                &mismatch_mint_key,
4326                &owner_key,
4327            )
4328            .unwrap(),
4329            vec![
4330                &mut mismatch_account_account,
4331                &mut mismatch_mint_account,
4332                &mut owner_account,
4333                &mut rent_sysvar,
4334            ],
4335        )
4336        .unwrap();
4337
4338        // mint to account
4339        let account_info = (&account_key, false, &mut account_account).into();
4340        native_mint_to(&account_info, 1000).unwrap();
4341
4342        // missing signer
4343        let mut instruction = unwrap_lamports(
4344            &program_id,
4345            &account_key,
4346            &account2_key,
4347            &owner_key,
4348            &[],
4349            Some(1000),
4350        )
4351        .unwrap();
4352        instruction.accounts[2].is_signer = false;
4353        assert_eq!(
4354            Err(ProgramError::MissingRequiredSignature),
4355            do_process_instruction(
4356                instruction,
4357                vec![
4358                    &mut account_account,
4359                    &mut account2_account,
4360                    &mut owner_account,
4361                ],
4362            )
4363        );
4364
4365        // non native mint
4366        assert_eq!(
4367            Err(TokenError::NonNativeNotSupported.into()),
4368            do_process_instruction(
4369                unwrap_lamports(
4370                    &program_id,
4371                    &mismatch_account_key,
4372                    &account_key,
4373                    &owner_key,
4374                    &[],
4375                    None
4376                )
4377                .unwrap(),
4378                vec![
4379                    &mut mismatch_account_account,
4380                    &mut account_account,
4381                    &mut owner_account,
4382                ],
4383            )
4384        );
4385
4386        // missing owner
4387        assert_eq!(
4388            Err(TokenError::OwnerMismatch.into()),
4389            do_process_instruction(
4390                unwrap_lamports(
4391                    &program_id,
4392                    &account_key,
4393                    &account2_key,
4394                    &owner2_key,
4395                    &[],
4396                    Some(1000)
4397                )
4398                .unwrap(),
4399                vec![
4400                    &mut account_account,
4401                    &mut account2_account,
4402                    &mut owner2_account,
4403                ],
4404            )
4405        );
4406
4407        // account not owned by program
4408        let not_program_id = Address::new_unique();
4409        account_account.owner = not_program_id;
4410        assert_eq!(
4411            Err(ProgramError::IncorrectProgramId),
4412            do_process_instruction(
4413                unwrap_lamports(
4414                    &program_id,
4415                    &account_key,
4416                    &account2_key,
4417                    &owner_key,
4418                    &[],
4419                    Some(0)
4420                )
4421                .unwrap(),
4422                vec![
4423                    &mut account_account,
4424                    &mut account2_account,
4425                    &mut owner2_account,
4426                ],
4427            )
4428        );
4429        account_account.owner = program_id;
4430
4431        // unwrap Some(500) lamports
4432        do_process_instruction(
4433            unwrap_lamports(
4434                &program_id,
4435                &account_key,
4436                &account2_key,
4437                &owner_key,
4438                &[],
4439                Some(500),
4440            )
4441            .unwrap(),
4442            vec![
4443                &mut account_account,
4444                &mut account2_account,
4445                &mut owner_account,
4446            ],
4447        )
4448        .unwrap();
4449        // 500 amount balance change...
4450        let account = Account::unpack_unchecked(&account_account.data).unwrap();
4451        assert_eq!(account.amount, 500);
4452        // 500 lamports balance change...
4453        assert_eq!(account_account.lamports(), 500 + account_minimum_balance());
4454        assert_eq!(
4455            account2_account.lamports(),
4456            zero_space_rent_exempt_balance + 500
4457        );
4458
4459        // insufficient funds
4460        assert_eq!(
4461            Err(TokenError::InsufficientFunds.into()),
4462            do_process_instruction(
4463                unwrap_lamports(
4464                    &program_id,
4465                    &account_key,
4466                    &account2_key,
4467                    &owner_key,
4468                    &[],
4469                    Some(501)
4470                )
4471                .unwrap(),
4472                vec![
4473                    &mut account_account,
4474                    &mut account2_account,
4475                    &mut owner_account,
4476                ],
4477            )
4478        );
4479
4480        // unwrap None lamports
4481        do_process_instruction(
4482            unwrap_lamports(
4483                &program_id,
4484                &account_key,
4485                &account2_key,
4486                &owner_key,
4487                &[],
4488                None,
4489            )
4490            .unwrap(),
4491            vec![
4492                &mut account_account,
4493                &mut account2_account,
4494                &mut owner_account,
4495            ],
4496        )
4497        .unwrap();
4498        // 500 amount balance change...
4499        let account = Account::unpack_unchecked(&account_account.data).unwrap();
4500        assert_eq!(account.amount, 0);
4501        // 500 lamports balance change...
4502        assert_eq!(account_account.lamports(), account_minimum_balance());
4503        assert_eq!(
4504            account2_account.lamports(),
4505            zero_space_rent_exempt_balance + 500 + 500
4506        );
4507    }
4508
4509    #[test]
4510    fn test_self_unwrap_lamports() {
4511        let program_id = crate::id();
4512        let account_key = Address::new_unique();
4513        let mut account_account = SolanaAccount::new(
4514            account_minimum_balance(),
4515            Account::get_packed_len(),
4516            &program_id,
4517        );
4518        let mismatch_account_key = Address::new_unique();
4519        let mut mismatch_account_account = SolanaAccount::new(
4520            account_minimum_balance(),
4521            Account::get_packed_len(),
4522            &program_id,
4523        );
4524        let owner_key = Address::new_unique();
4525        let mut owner_account = SolanaAccount::default();
4526        let owner2_key = Address::new_unique();
4527        let mut owner2_account = SolanaAccount::default();
4528        let mint_key = native_mint::id();
4529        let mut mint_account = native_mint();
4530        let mismatch_mint_key = Address::new_unique();
4531        let mut mismatch_mint_account =
4532            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
4533        let mut rent_sysvar = rent_sysvar();
4534
4535        // create mismatch mint
4536        do_process_instruction(
4537            initialize_mint(&program_id, &mismatch_mint_key, &owner_key, None, 2).unwrap(),
4538            vec![&mut mismatch_mint_account, &mut rent_sysvar],
4539        )
4540        .unwrap();
4541
4542        // create account
4543        do_process_instruction(
4544            initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
4545            vec![
4546                &mut account_account,
4547                &mut mint_account,
4548                &mut owner_account,
4549                &mut rent_sysvar,
4550            ],
4551        )
4552        .unwrap();
4553
4554        // create mismatch account
4555        do_process_instruction(
4556            initialize_account(
4557                &program_id,
4558                &mismatch_account_key,
4559                &mismatch_mint_key,
4560                &owner_key,
4561            )
4562            .unwrap(),
4563            vec![
4564                &mut mismatch_account_account,
4565                &mut mismatch_mint_account,
4566                &mut owner_account,
4567                &mut rent_sysvar,
4568            ],
4569        )
4570        .unwrap();
4571
4572        let account_info = (&account_key, false, &mut account_account).into_account_info();
4573        let mismatch_account_info =
4574            (&mismatch_account_key, false, &mut mismatch_account_account).into_account_info();
4575        let owner_info = (&owner_key, true, &mut owner_account).into_account_info();
4576        let owner2_info = (&owner2_key, true, &mut owner2_account).into_account_info();
4577
4578        // mint to account
4579        native_mint_to(&account_info, 1000).unwrap();
4580
4581        // unwrap Some(500) lamports
4582        let instruction = unwrap_lamports(
4583            &program_id,
4584            account_info.key,
4585            account_info.key,
4586            owner_info.key,
4587            &[],
4588            Some(500),
4589        )
4590        .unwrap();
4591        assert_eq!(
4592            Ok(()),
4593            Processor::process(
4594                &instruction.program_id,
4595                &[
4596                    account_info.clone(),
4597                    account_info.clone(),
4598                    owner_info.clone(),
4599                ],
4600                &instruction.data,
4601            )
4602        );
4603        // 500 amount balance change...
4604        let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap();
4605        assert_eq!(account.amount, 500);
4606        // no lamport balance change...
4607        assert_eq!(account_info.lamports(), 1000 + account_minimum_balance());
4608
4609        // insufficient funds
4610        let instruction = unwrap_lamports(
4611            &program_id,
4612            account_info.key,
4613            account_info.key,
4614            owner_info.key,
4615            &[],
4616            Some(501),
4617        )
4618        .unwrap();
4619        assert_eq!(
4620            Err(TokenError::InsufficientFunds.into()),
4621            Processor::process(
4622                &instruction.program_id,
4623                &[
4624                    account_info.clone(),
4625                    account_info.clone(),
4626                    owner_info.clone(),
4627                ],
4628                &instruction.data,
4629            )
4630        );
4631
4632        // missing signer
4633        let mut owner_no_sign_info = owner_info.clone();
4634        let mut instruction = unwrap_lamports(
4635            &program_id,
4636            account_info.key,
4637            account_info.key,
4638            owner_no_sign_info.key,
4639            &[],
4640            Some(500),
4641        )
4642        .unwrap();
4643        instruction.accounts[2].is_signer = false;
4644        owner_no_sign_info.is_signer = false;
4645        assert_eq!(
4646            Err(ProgramError::MissingRequiredSignature),
4647            Processor::process(
4648                &instruction.program_id,
4649                &[
4650                    account_info.clone(),
4651                    account_info.clone(),
4652                    owner_no_sign_info.clone(),
4653                ],
4654                &instruction.data,
4655            )
4656        );
4657
4658        // non native mint
4659        let instruction = unwrap_lamports(
4660            &program_id,
4661            mismatch_account_info.key,
4662            mismatch_account_info.key,
4663            owner_info.key,
4664            &[],
4665            None,
4666        )
4667        .unwrap();
4668        assert_eq!(
4669            Err(TokenError::NonNativeNotSupported.into()),
4670            Processor::process(
4671                &instruction.program_id,
4672                &[
4673                    mismatch_account_info.clone(),
4674                    mismatch_account_info.clone(),
4675                    owner_info.clone(),
4676                ],
4677                &instruction.data,
4678            )
4679        );
4680
4681        // missing owner
4682        let instruction = unwrap_lamports(
4683            &program_id,
4684            account_info.key,
4685            account_info.key,
4686            owner2_info.key,
4687            &[],
4688            Some(500),
4689        )
4690        .unwrap();
4691        assert_eq!(
4692            Err(TokenError::OwnerMismatch.into()),
4693            Processor::process(
4694                &instruction.program_id,
4695                &[
4696                    account_info.clone(),
4697                    account_info.clone(),
4698                    owner2_info.clone(),
4699                ],
4700                &instruction.data,
4701            )
4702        );
4703
4704        // unwrap None lamports
4705        let instruction = unwrap_lamports(
4706            &program_id,
4707            account_info.key,
4708            account_info.key,
4709            owner_info.key,
4710            &[],
4711            None,
4712        )
4713        .unwrap();
4714        assert_eq!(
4715            Ok(()),
4716            Processor::process(
4717                &instruction.program_id,
4718                &[
4719                    account_info.clone(),
4720                    account_info.clone(),
4721                    owner_info.clone(),
4722                ],
4723                &instruction.data,
4724            )
4725        );
4726        // 500 amount balance change...
4727        let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap();
4728        assert_eq!(account.amount, 0);
4729        // no lamport balance change...
4730        assert_eq!(account_info.lamports(), 1000 + account_minimum_balance());
4731    }
4732
4733    #[test]
4734    fn test_mintable_token_with_zero_supply() {
4735        let program_id = crate::id();
4736        let account_key = Address::new_unique();
4737        let mut account_account = SolanaAccount::new(
4738            account_minimum_balance(),
4739            Account::get_packed_len(),
4740            &program_id,
4741        );
4742        let owner_key = Address::new_unique();
4743        let mut owner_account = SolanaAccount::default();
4744        let mint_key = Address::new_unique();
4745        let mut mint_account =
4746            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
4747        let mut rent_sysvar = rent_sysvar();
4748
4749        // create mint-able token with zero supply
4750        let decimals = 2;
4751        do_process_instruction(
4752            initialize_mint(&program_id, &mint_key, &owner_key, None, decimals).unwrap(),
4753            vec![&mut mint_account, &mut rent_sysvar],
4754        )
4755        .unwrap();
4756        let mint = Mint::unpack_unchecked(&mint_account.data).unwrap();
4757        assert_eq!(
4758            mint,
4759            Mint {
4760                mint_authority: COption::Some(owner_key),
4761                supply: 0,
4762                decimals,
4763                is_initialized: true,
4764                freeze_authority: COption::None,
4765            }
4766        );
4767
4768        // create account
4769        do_process_instruction(
4770            initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
4771            vec![
4772                &mut account_account,
4773                &mut mint_account,
4774                &mut owner_account,
4775                &mut rent_sysvar,
4776            ],
4777        )
4778        .unwrap();
4779
4780        // mint to
4781        do_process_instruction(
4782            mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 42).unwrap(),
4783            vec![&mut mint_account, &mut account_account, &mut owner_account],
4784        )
4785        .unwrap();
4786        let _ = Mint::unpack(&mint_account.data).unwrap();
4787        let account = Account::unpack_unchecked(&account_account.data).unwrap();
4788        assert_eq!(account.amount, 42);
4789
4790        // mint to 2, with incorrect decimals
4791        assert_eq!(
4792            Err(TokenError::MintDecimalsMismatch.into()),
4793            do_process_instruction(
4794                mint_to_checked(
4795                    &program_id,
4796                    &mint_key,
4797                    &account_key,
4798                    &owner_key,
4799                    &[],
4800                    42,
4801                    decimals + 1
4802                )
4803                .unwrap(),
4804                vec![&mut mint_account, &mut account_account, &mut owner_account],
4805            )
4806        );
4807
4808        let _ = Mint::unpack(&mint_account.data).unwrap();
4809        let account = Account::unpack_unchecked(&account_account.data).unwrap();
4810        assert_eq!(account.amount, 42);
4811
4812        // mint to 2
4813        do_process_instruction(
4814            mint_to_checked(
4815                &program_id,
4816                &mint_key,
4817                &account_key,
4818                &owner_key,
4819                &[],
4820                42,
4821                decimals,
4822            )
4823            .unwrap(),
4824            vec![&mut mint_account, &mut account_account, &mut owner_account],
4825        )
4826        .unwrap();
4827        let _ = Mint::unpack(&mint_account.data).unwrap();
4828        let account = Account::unpack_unchecked(&account_account.data).unwrap();
4829        assert_eq!(account.amount, 84);
4830    }
4831
4832    #[test]
4833    fn test_approve_dups() {
4834        let program_id = crate::id();
4835        let account1_key = Address::new_unique();
4836        let mut account1_account = SolanaAccount::new(
4837            account_minimum_balance(),
4838            Account::get_packed_len(),
4839            &program_id,
4840        );
4841        let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into();
4842        let account2_key = Address::new_unique();
4843        let mut account2_account = SolanaAccount::new(
4844            account_minimum_balance(),
4845            Account::get_packed_len(),
4846            &program_id,
4847        );
4848        let account2_info: AccountInfo = (&account2_key, false, &mut account2_account).into();
4849        let account3_key = Address::new_unique();
4850        let mut account3_account = SolanaAccount::new(
4851            account_minimum_balance(),
4852            Account::get_packed_len(),
4853            &program_id,
4854        );
4855        let account3_info: AccountInfo = (&account3_key, true, &mut account3_account).into();
4856        let multisig_key = Address::new_unique();
4857        let mut multisig_account = SolanaAccount::new(
4858            multisig_minimum_balance(),
4859            Multisig::get_packed_len(),
4860            &program_id,
4861        );
4862        let multisig_info: AccountInfo = (&multisig_key, true, &mut multisig_account).into();
4863        let owner_key = Address::new_unique();
4864        let mut owner_account = SolanaAccount::default();
4865        let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into();
4866        let mint_key = Address::new_unique();
4867        let mut mint_account =
4868            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
4869        let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into();
4870        let rent_key = rent::id();
4871        let mut rent_sysvar = rent_sysvar();
4872        let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into();
4873
4874        // create mint
4875        do_process_instruction_dups(
4876            initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
4877            vec![mint_info.clone(), rent_info.clone()],
4878        )
4879        .unwrap();
4880
4881        // create account
4882        do_process_instruction_dups(
4883            initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(),
4884            vec![
4885                account1_info.clone(),
4886                mint_info.clone(),
4887                account1_info.clone(),
4888                rent_info.clone(),
4889            ],
4890        )
4891        .unwrap();
4892
4893        // create another account
4894        do_process_instruction_dups(
4895            initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(),
4896            vec![
4897                account2_info.clone(),
4898                mint_info.clone(),
4899                owner_info.clone(),
4900                rent_info.clone(),
4901            ],
4902        )
4903        .unwrap();
4904
4905        // mint to account
4906        do_process_instruction_dups(
4907            mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(),
4908            vec![mint_info.clone(), account1_info.clone(), owner_info.clone()],
4909        )
4910        .unwrap();
4911
4912        // source-owner approve
4913        do_process_instruction_dups(
4914            approve(
4915                &program_id,
4916                &account1_key,
4917                &account2_key,
4918                &account1_key,
4919                &[],
4920                500,
4921            )
4922            .unwrap(),
4923            vec![
4924                account1_info.clone(),
4925                account2_info.clone(),
4926                account1_info.clone(),
4927            ],
4928        )
4929        .unwrap();
4930
4931        // source-owner approve_checked
4932        do_process_instruction_dups(
4933            approve_checked(
4934                &program_id,
4935                &account1_key,
4936                &mint_key,
4937                &account2_key,
4938                &account1_key,
4939                &[],
4940                500,
4941                2,
4942            )
4943            .unwrap(),
4944            vec![
4945                account1_info.clone(),
4946                mint_info.clone(),
4947                account2_info.clone(),
4948                account1_info.clone(),
4949            ],
4950        )
4951        .unwrap();
4952
4953        // source-owner revoke
4954        do_process_instruction_dups(
4955            revoke(&program_id, &account1_key, &account1_key, &[]).unwrap(),
4956            vec![account1_info.clone(), account1_info.clone()],
4957        )
4958        .unwrap();
4959
4960        // test source-multisig signer
4961        do_process_instruction_dups(
4962            initialize_multisig(&program_id, &multisig_key, &[&account3_key], 1).unwrap(),
4963            vec![
4964                multisig_info.clone(),
4965                rent_info.clone(),
4966                account3_info.clone(),
4967            ],
4968        )
4969        .unwrap();
4970
4971        do_process_instruction_dups(
4972            initialize_account(&program_id, &account3_key, &mint_key, &multisig_key).unwrap(),
4973            vec![
4974                account3_info.clone(),
4975                mint_info.clone(),
4976                multisig_info.clone(),
4977                rent_info.clone(),
4978            ],
4979        )
4980        .unwrap();
4981
4982        do_process_instruction_dups(
4983            mint_to(&program_id, &mint_key, &account3_key, &owner_key, &[], 1000).unwrap(),
4984            vec![mint_info.clone(), account3_info.clone(), owner_info.clone()],
4985        )
4986        .unwrap();
4987
4988        // source-multisig-signer approve
4989        do_process_instruction_dups(
4990            approve(
4991                &program_id,
4992                &account3_key,
4993                &account2_key,
4994                &multisig_key,
4995                &[&account3_key],
4996                500,
4997            )
4998            .unwrap(),
4999            vec![
5000                account3_info.clone(),
5001                account2_info.clone(),
5002                multisig_info.clone(),
5003                account3_info.clone(),
5004            ],
5005        )
5006        .unwrap();
5007
5008        // source-multisig-signer approve_checked
5009        do_process_instruction_dups(
5010            approve_checked(
5011                &program_id,
5012                &account3_key,
5013                &mint_key,
5014                &account2_key,
5015                &multisig_key,
5016                &[&account3_key],
5017                500,
5018                2,
5019            )
5020            .unwrap(),
5021            vec![
5022                account3_info.clone(),
5023                mint_info.clone(),
5024                account2_info.clone(),
5025                multisig_info.clone(),
5026                account3_info.clone(),
5027            ],
5028        )
5029        .unwrap();
5030
5031        // source-owner multisig-signer
5032        do_process_instruction_dups(
5033            revoke(&program_id, &account3_key, &multisig_key, &[&account3_key]).unwrap(),
5034            vec![
5035                account3_info.clone(),
5036                multisig_info.clone(),
5037                account3_info.clone(),
5038            ],
5039        )
5040        .unwrap();
5041
5042        // approve to source
5043        do_process_instruction_dups(
5044            approve_checked(
5045                &program_id,
5046                &account2_key,
5047                &mint_key,
5048                &account2_key,
5049                &owner_key,
5050                &[],
5051                500,
5052                2,
5053            )
5054            .unwrap(),
5055            vec![
5056                account2_info.clone(),
5057                mint_info.clone(),
5058                account2_info.clone(),
5059                owner_info.clone(),
5060            ],
5061        )
5062        .unwrap();
5063
5064        // source-delegate revoke, force account2 to be a signer
5065        let account2_info: AccountInfo = (&account2_key, true, &mut account2_account).into();
5066        do_process_instruction_dups(
5067            revoke(&program_id, &account2_key, &account2_key, &[]).unwrap(),
5068            vec![account2_info.clone(), account2_info.clone()],
5069        )
5070        .unwrap();
5071    }
5072
5073    #[test]
5074    fn test_approve() {
5075        let program_id = crate::id();
5076        let account_key = Address::new_unique();
5077        let mut account_account = SolanaAccount::new(
5078            account_minimum_balance(),
5079            Account::get_packed_len(),
5080            &program_id,
5081        );
5082        let account2_key = Address::new_unique();
5083        let mut account2_account = SolanaAccount::new(
5084            account_minimum_balance(),
5085            Account::get_packed_len(),
5086            &program_id,
5087        );
5088        let delegate_key = Address::new_unique();
5089        let mut delegate_account = SolanaAccount::default();
5090        let owner_key = Address::new_unique();
5091        let mut owner_account = SolanaAccount::default();
5092        let owner2_key = Address::new_unique();
5093        let mut owner2_account = SolanaAccount::default();
5094        let mint_key = Address::new_unique();
5095        let mut mint_account =
5096            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
5097        let mut rent_sysvar = rent_sysvar();
5098
5099        // create mint
5100        do_process_instruction(
5101            initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
5102            vec![&mut mint_account, &mut rent_sysvar],
5103        )
5104        .unwrap();
5105
5106        // create account
5107        do_process_instruction(
5108            initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
5109            vec![
5110                &mut account_account,
5111                &mut mint_account,
5112                &mut owner_account,
5113                &mut rent_sysvar,
5114            ],
5115        )
5116        .unwrap();
5117
5118        // create another account
5119        do_process_instruction(
5120            initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(),
5121            vec![
5122                &mut account2_account,
5123                &mut mint_account,
5124                &mut owner_account,
5125                &mut rent_sysvar,
5126            ],
5127        )
5128        .unwrap();
5129
5130        // mint to account
5131        do_process_instruction(
5132            mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(),
5133            vec![&mut mint_account, &mut account_account, &mut owner_account],
5134        )
5135        .unwrap();
5136
5137        // missing signer
5138        let mut instruction = approve(
5139            &program_id,
5140            &account_key,
5141            &delegate_key,
5142            &owner_key,
5143            &[],
5144            100,
5145        )
5146        .unwrap();
5147        instruction.accounts[2].is_signer = false;
5148        assert_eq!(
5149            Err(ProgramError::MissingRequiredSignature),
5150            do_process_instruction(
5151                instruction,
5152                vec![
5153                    &mut account_account,
5154                    &mut delegate_account,
5155                    &mut owner_account,
5156                ],
5157            )
5158        );
5159
5160        // no owner
5161        assert_eq!(
5162            Err(TokenError::OwnerMismatch.into()),
5163            do_process_instruction(
5164                approve(
5165                    &program_id,
5166                    &account_key,
5167                    &delegate_key,
5168                    &owner2_key,
5169                    &[],
5170                    100
5171                )
5172                .unwrap(),
5173                vec![
5174                    &mut account_account,
5175                    &mut delegate_account,
5176                    &mut owner2_account,
5177                ],
5178            )
5179        );
5180
5181        // approve delegate
5182        do_process_instruction(
5183            approve(
5184                &program_id,
5185                &account_key,
5186                &delegate_key,
5187                &owner_key,
5188                &[],
5189                100,
5190            )
5191            .unwrap(),
5192            vec![
5193                &mut account_account,
5194                &mut delegate_account,
5195                &mut owner_account,
5196            ],
5197        )
5198        .unwrap();
5199
5200        // approve delegate 2, with incorrect decimals
5201        assert_eq!(
5202            Err(TokenError::MintDecimalsMismatch.into()),
5203            do_process_instruction(
5204                approve_checked(
5205                    &program_id,
5206                    &account_key,
5207                    &mint_key,
5208                    &delegate_key,
5209                    &owner_key,
5210                    &[],
5211                    100,
5212                    0 // <-- incorrect decimals
5213                )
5214                .unwrap(),
5215                vec![
5216                    &mut account_account,
5217                    &mut mint_account,
5218                    &mut delegate_account,
5219                    &mut owner_account,
5220                ],
5221            )
5222        );
5223
5224        // approve delegate 2, with incorrect mint
5225        assert_eq!(
5226            Err(TokenError::MintMismatch.into()),
5227            do_process_instruction(
5228                approve_checked(
5229                    &program_id,
5230                    &account_key,
5231                    &account2_key, // <-- bad mint
5232                    &delegate_key,
5233                    &owner_key,
5234                    &[],
5235                    100,
5236                    0
5237                )
5238                .unwrap(),
5239                vec![
5240                    &mut account_account,
5241                    &mut account2_account, // <-- bad mint
5242                    &mut delegate_account,
5243                    &mut owner_account,
5244                ],
5245            )
5246        );
5247
5248        // approve delegate 2
5249        do_process_instruction(
5250            approve_checked(
5251                &program_id,
5252                &account_key,
5253                &mint_key,
5254                &delegate_key,
5255                &owner_key,
5256                &[],
5257                100,
5258                2,
5259            )
5260            .unwrap(),
5261            vec![
5262                &mut account_account,
5263                &mut mint_account,
5264                &mut delegate_account,
5265                &mut owner_account,
5266            ],
5267        )
5268        .unwrap();
5269
5270        // revoke delegate
5271        do_process_instruction(
5272            revoke(&program_id, &account_key, &owner_key, &[]).unwrap(),
5273            vec![&mut account_account, &mut owner_account],
5274        )
5275        .unwrap();
5276
5277        // approve delegate 3
5278        do_process_instruction(
5279            approve_checked(
5280                &program_id,
5281                &account_key,
5282                &mint_key,
5283                &delegate_key,
5284                &owner_key,
5285                &[],
5286                100,
5287                2,
5288            )
5289            .unwrap(),
5290            vec![
5291                &mut account_account,
5292                &mut mint_account,
5293                &mut delegate_account,
5294                &mut owner_account,
5295            ],
5296        )
5297        .unwrap();
5298
5299        // revoke by delegate
5300        do_process_instruction(
5301            revoke(&program_id, &account_key, &delegate_key, &[]).unwrap(),
5302            vec![&mut account_account, &mut delegate_account],
5303        )
5304        .unwrap();
5305
5306        // fails the second time
5307        assert_eq!(
5308            Err(TokenError::OwnerMismatch.into()),
5309            do_process_instruction(
5310                revoke(&program_id, &account_key, &delegate_key, &[]).unwrap(),
5311                vec![&mut account_account, &mut delegate_account],
5312            )
5313        );
5314    }
5315
5316    #[test]
5317    fn test_set_authority_dups() {
5318        let program_id = crate::id();
5319        let account1_key = Address::new_unique();
5320        let mut account1_account = SolanaAccount::new(
5321            account_minimum_balance(),
5322            Account::get_packed_len(),
5323            &program_id,
5324        );
5325        let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into();
5326        let owner_key = Address::new_unique();
5327        let mint_key = Address::new_unique();
5328        let mut mint_account =
5329            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
5330        let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into();
5331        let rent_key = rent::id();
5332        let mut rent_sysvar = rent_sysvar();
5333        let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into();
5334
5335        // create mint
5336        do_process_instruction_dups(
5337            initialize_mint(&program_id, &mint_key, &mint_key, Some(&mint_key), 2).unwrap(),
5338            vec![mint_info.clone(), rent_info.clone()],
5339        )
5340        .unwrap();
5341
5342        // create account
5343        do_process_instruction_dups(
5344            initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(),
5345            vec![
5346                account1_info.clone(),
5347                mint_info.clone(),
5348                account1_info.clone(),
5349                rent_info.clone(),
5350            ],
5351        )
5352        .unwrap();
5353
5354        // set mint_authority when currently self
5355        do_process_instruction_dups(
5356            set_authority(
5357                &program_id,
5358                &mint_key,
5359                Some(&owner_key),
5360                AuthorityType::MintTokens,
5361                &mint_key,
5362                &[],
5363            )
5364            .unwrap(),
5365            vec![mint_info.clone(), mint_info.clone()],
5366        )
5367        .unwrap();
5368
5369        // set freeze_authority when currently self
5370        do_process_instruction_dups(
5371            set_authority(
5372                &program_id,
5373                &mint_key,
5374                Some(&owner_key),
5375                AuthorityType::FreezeAccount,
5376                &mint_key,
5377                &[],
5378            )
5379            .unwrap(),
5380            vec![mint_info.clone(), mint_info.clone()],
5381        )
5382        .unwrap();
5383
5384        // set account owner when currently self
5385        do_process_instruction_dups(
5386            set_authority(
5387                &program_id,
5388                &account1_key,
5389                Some(&owner_key),
5390                AuthorityType::AccountOwner,
5391                &account1_key,
5392                &[],
5393            )
5394            .unwrap(),
5395            vec![account1_info.clone(), account1_info.clone()],
5396        )
5397        .unwrap();
5398
5399        // set close_authority when currently self
5400        let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap();
5401        account.close_authority = COption::Some(account1_key);
5402        Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap();
5403
5404        do_process_instruction_dups(
5405            set_authority(
5406                &program_id,
5407                &account1_key,
5408                Some(&owner_key),
5409                AuthorityType::CloseAccount,
5410                &account1_key,
5411                &[],
5412            )
5413            .unwrap(),
5414            vec![account1_info.clone(), account1_info.clone()],
5415        )
5416        .unwrap();
5417    }
5418
5419    #[test]
5420    fn test_set_authority() {
5421        let program_id = crate::id();
5422        let account_key = Address::new_unique();
5423        let mut account_account = SolanaAccount::new(
5424            account_minimum_balance(),
5425            Account::get_packed_len(),
5426            &program_id,
5427        );
5428        let account2_key = Address::new_unique();
5429        let mut account2_account = SolanaAccount::new(
5430            account_minimum_balance(),
5431            Account::get_packed_len(),
5432            &program_id,
5433        );
5434        let owner_key = Address::new_unique();
5435        let mut owner_account = SolanaAccount::default();
5436        let owner2_key = Address::new_unique();
5437        let mut owner2_account = SolanaAccount::default();
5438        let owner3_key = Address::new_unique();
5439        let mut owner3_account = SolanaAccount::default();
5440        let mint_key = Address::new_unique();
5441        let mut mint_account =
5442            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
5443        let mint2_key = Address::new_unique();
5444        let mut mint2_account =
5445            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
5446        let mut rent_sysvar = rent_sysvar();
5447
5448        // create new mint with owner
5449        do_process_instruction(
5450            initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
5451            vec![&mut mint_account, &mut rent_sysvar],
5452        )
5453        .unwrap();
5454
5455        // create mint with owner and freeze_authority
5456        do_process_instruction(
5457            initialize_mint(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(),
5458            vec![&mut mint2_account, &mut rent_sysvar],
5459        )
5460        .unwrap();
5461
5462        // invalid account
5463        assert_eq!(
5464            Err(ProgramError::InvalidAccountData),
5465            do_process_instruction(
5466                set_authority(
5467                    &program_id,
5468                    &account_key,
5469                    Some(&owner2_key),
5470                    AuthorityType::AccountOwner,
5471                    &owner_key,
5472                    &[]
5473                )
5474                .unwrap(),
5475                vec![&mut account_account, &mut owner_account],
5476            )
5477        );
5478
5479        // create account
5480        do_process_instruction(
5481            initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
5482            vec![
5483                &mut account_account,
5484                &mut mint_account,
5485                &mut owner_account,
5486                &mut rent_sysvar,
5487            ],
5488        )
5489        .unwrap();
5490
5491        // create another account
5492        do_process_instruction(
5493            initialize_account(&program_id, &account2_key, &mint2_key, &owner_key).unwrap(),
5494            vec![
5495                &mut account2_account,
5496                &mut mint2_account,
5497                &mut owner_account,
5498                &mut rent_sysvar,
5499            ],
5500        )
5501        .unwrap();
5502
5503        // missing owner
5504        assert_eq!(
5505            Err(TokenError::OwnerMismatch.into()),
5506            do_process_instruction(
5507                set_authority(
5508                    &program_id,
5509                    &account_key,
5510                    Some(&owner_key),
5511                    AuthorityType::AccountOwner,
5512                    &owner2_key,
5513                    &[]
5514                )
5515                .unwrap(),
5516                vec![&mut account_account, &mut owner2_account],
5517            )
5518        );
5519
5520        // owner did not sign
5521        let mut instruction = set_authority(
5522            &program_id,
5523            &account_key,
5524            Some(&owner2_key),
5525            AuthorityType::AccountOwner,
5526            &owner_key,
5527            &[],
5528        )
5529        .unwrap();
5530        instruction.accounts[1].is_signer = false;
5531        assert_eq!(
5532            Err(ProgramError::MissingRequiredSignature),
5533            do_process_instruction(instruction, vec![&mut account_account, &mut owner_account,],)
5534        );
5535
5536        // wrong authority type
5537        assert_eq!(
5538            Err(TokenError::AuthorityTypeNotSupported.into()),
5539            do_process_instruction(
5540                set_authority(
5541                    &program_id,
5542                    &account_key,
5543                    Some(&owner2_key),
5544                    AuthorityType::FreezeAccount,
5545                    &owner_key,
5546                    &[],
5547                )
5548                .unwrap(),
5549                vec![&mut account_account, &mut owner_account],
5550            )
5551        );
5552
5553        // account owner may not be set to None
5554        assert_eq!(
5555            Err(TokenError::InvalidInstruction.into()),
5556            do_process_instruction(
5557                set_authority(
5558                    &program_id,
5559                    &account_key,
5560                    None,
5561                    AuthorityType::AccountOwner,
5562                    &owner_key,
5563                    &[],
5564                )
5565                .unwrap(),
5566                vec![&mut account_account, &mut owner_account],
5567            )
5568        );
5569
5570        // set delegate
5571        do_process_instruction(
5572            approve(
5573                &program_id,
5574                &account_key,
5575                &owner2_key,
5576                &owner_key,
5577                &[],
5578                u64::MAX,
5579            )
5580            .unwrap(),
5581            vec![
5582                &mut account_account,
5583                &mut owner2_account,
5584                &mut owner_account,
5585            ],
5586        )
5587        .unwrap();
5588        let account = Account::unpack_unchecked(&account_account.data).unwrap();
5589        assert_eq!(account.delegate, COption::Some(owner2_key));
5590        assert_eq!(account.delegated_amount, u64::MAX);
5591
5592        // set owner
5593        do_process_instruction(
5594            set_authority(
5595                &program_id,
5596                &account_key,
5597                Some(&owner3_key),
5598                AuthorityType::AccountOwner,
5599                &owner_key,
5600                &[],
5601            )
5602            .unwrap(),
5603            vec![&mut account_account, &mut owner_account],
5604        )
5605        .unwrap();
5606
5607        // check delegate cleared
5608        let account = Account::unpack_unchecked(&account_account.data).unwrap();
5609        assert_eq!(account.delegate, COption::None);
5610        assert_eq!(account.delegated_amount, 0);
5611
5612        // set owner without existing delegate
5613        do_process_instruction(
5614            set_authority(
5615                &program_id,
5616                &account_key,
5617                Some(&owner2_key),
5618                AuthorityType::AccountOwner,
5619                &owner3_key,
5620                &[],
5621            )
5622            .unwrap(),
5623            vec![&mut account_account, &mut owner3_account],
5624        )
5625        .unwrap();
5626
5627        // set close_authority
5628        do_process_instruction(
5629            set_authority(
5630                &program_id,
5631                &account_key,
5632                Some(&owner2_key),
5633                AuthorityType::CloseAccount,
5634                &owner2_key,
5635                &[],
5636            )
5637            .unwrap(),
5638            vec![&mut account_account, &mut owner2_account],
5639        )
5640        .unwrap();
5641
5642        // close_authority may be set to None
5643        do_process_instruction(
5644            set_authority(
5645                &program_id,
5646                &account_key,
5647                None,
5648                AuthorityType::CloseAccount,
5649                &owner2_key,
5650                &[],
5651            )
5652            .unwrap(),
5653            vec![&mut account_account, &mut owner2_account],
5654        )
5655        .unwrap();
5656
5657        // wrong owner
5658        assert_eq!(
5659            Err(TokenError::OwnerMismatch.into()),
5660            do_process_instruction(
5661                set_authority(
5662                    &program_id,
5663                    &mint_key,
5664                    Some(&owner3_key),
5665                    AuthorityType::MintTokens,
5666                    &owner2_key,
5667                    &[]
5668                )
5669                .unwrap(),
5670                vec![&mut mint_account, &mut owner2_account],
5671            )
5672        );
5673
5674        // owner did not sign
5675        let mut instruction = set_authority(
5676            &program_id,
5677            &mint_key,
5678            Some(&owner2_key),
5679            AuthorityType::MintTokens,
5680            &owner_key,
5681            &[],
5682        )
5683        .unwrap();
5684        instruction.accounts[1].is_signer = false;
5685        assert_eq!(
5686            Err(ProgramError::MissingRequiredSignature),
5687            do_process_instruction(instruction, vec![&mut mint_account, &mut owner_account],)
5688        );
5689
5690        // cannot freeze
5691        assert_eq!(
5692            Err(TokenError::MintCannotFreeze.into()),
5693            do_process_instruction(
5694                set_authority(
5695                    &program_id,
5696                    &mint_key,
5697                    Some(&owner2_key),
5698                    AuthorityType::FreezeAccount,
5699                    &owner_key,
5700                    &[],
5701                )
5702                .unwrap(),
5703                vec![&mut mint_account, &mut owner_account],
5704            )
5705        );
5706
5707        // set owner
5708        do_process_instruction(
5709            set_authority(
5710                &program_id,
5711                &mint_key,
5712                Some(&owner2_key),
5713                AuthorityType::MintTokens,
5714                &owner_key,
5715                &[],
5716            )
5717            .unwrap(),
5718            vec![&mut mint_account, &mut owner_account],
5719        )
5720        .unwrap();
5721
5722        // set owner to None
5723        do_process_instruction(
5724            set_authority(
5725                &program_id,
5726                &mint_key,
5727                None,
5728                AuthorityType::MintTokens,
5729                &owner2_key,
5730                &[],
5731            )
5732            .unwrap(),
5733            vec![&mut mint_account, &mut owner2_account],
5734        )
5735        .unwrap();
5736
5737        // test unsetting mint_authority is one-way operation
5738        assert_eq!(
5739            Err(TokenError::FixedSupply.into()),
5740            do_process_instruction(
5741                set_authority(
5742                    &program_id,
5743                    &mint2_key,
5744                    Some(&owner2_key),
5745                    AuthorityType::MintTokens,
5746                    &owner_key,
5747                    &[]
5748                )
5749                .unwrap(),
5750                vec![&mut mint_account, &mut owner_account],
5751            )
5752        );
5753
5754        // set freeze_authority
5755        do_process_instruction(
5756            set_authority(
5757                &program_id,
5758                &mint2_key,
5759                Some(&owner2_key),
5760                AuthorityType::FreezeAccount,
5761                &owner_key,
5762                &[],
5763            )
5764            .unwrap(),
5765            vec![&mut mint2_account, &mut owner_account],
5766        )
5767        .unwrap();
5768
5769        // test unsetting freeze_authority is one-way operation
5770        do_process_instruction(
5771            set_authority(
5772                &program_id,
5773                &mint2_key,
5774                None,
5775                AuthorityType::FreezeAccount,
5776                &owner2_key,
5777                &[],
5778            )
5779            .unwrap(),
5780            vec![&mut mint2_account, &mut owner2_account],
5781        )
5782        .unwrap();
5783
5784        assert_eq!(
5785            Err(TokenError::MintCannotFreeze.into()),
5786            do_process_instruction(
5787                set_authority(
5788                    &program_id,
5789                    &mint2_key,
5790                    Some(&owner2_key),
5791                    AuthorityType::FreezeAccount,
5792                    &owner_key,
5793                    &[],
5794                )
5795                .unwrap(),
5796                vec![&mut mint2_account, &mut owner2_account],
5797            )
5798        );
5799    }
5800
5801    #[test]
5802    fn test_set_authority_with_immutable_owner_extension() {
5803        let program_id = crate::id();
5804        let account_key = Address::new_unique();
5805
5806        let account_len =
5807            ExtensionType::try_calculate_account_len::<Account>(&[ExtensionType::ImmutableOwner])
5808                .unwrap();
5809        let mut account_account = SolanaAccount::new(
5810            Rent::default().minimum_balance(account_len),
5811            account_len,
5812            &program_id,
5813        );
5814        let owner_key = Address::new_unique();
5815        let mut owner_account = SolanaAccount::default();
5816        let owner2_key = Address::new_unique();
5817
5818        let mint_key = Address::new_unique();
5819        let mut mint_account =
5820            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
5821        let mut rent_sysvar = rent_sysvar();
5822
5823        // create mint
5824        assert_eq!(
5825            Ok(()),
5826            do_process_instruction(
5827                initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
5828                vec![&mut mint_account, &mut rent_sysvar],
5829            )
5830        );
5831
5832        // create account
5833        assert_eq!(
5834            Ok(()),
5835            do_process_instruction(
5836                initialize_immutable_owner(&program_id, &account_key).unwrap(),
5837                vec![&mut account_account],
5838            )
5839        );
5840        assert_eq!(
5841            Ok(()),
5842            do_process_instruction(
5843                initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
5844                vec![
5845                    &mut account_account,
5846                    &mut mint_account,
5847                    &mut owner_account,
5848                    &mut rent_sysvar,
5849                ],
5850            )
5851        );
5852
5853        // Immutable Owner extension blocks account owner authority changes
5854        assert_eq!(
5855            Err(TokenError::ImmutableOwner.into()),
5856            do_process_instruction(
5857                set_authority(
5858                    &program_id,
5859                    &account_key,
5860                    Some(&owner2_key),
5861                    AuthorityType::AccountOwner,
5862                    &owner_key,
5863                    &[],
5864                )
5865                .unwrap(),
5866                vec![&mut account_account, &mut owner_account],
5867            )
5868        );
5869    }
5870
5871    #[test]
5872    fn test_mint_to_dups() {
5873        let program_id = crate::id();
5874        let account1_key = Address::new_unique();
5875        let mut account1_account = SolanaAccount::new(
5876            account_minimum_balance(),
5877            Account::get_packed_len(),
5878            &program_id,
5879        );
5880        let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into();
5881        let owner_key = Address::new_unique();
5882        let mut owner_account = SolanaAccount::default();
5883        let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into();
5884        let mint_key = Address::new_unique();
5885        let mut mint_account =
5886            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
5887        let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into();
5888        let rent_key = rent::id();
5889        let mut rent_sysvar = rent_sysvar();
5890        let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into();
5891
5892        // create mint
5893        do_process_instruction_dups(
5894            initialize_mint(&program_id, &mint_key, &mint_key, None, 2).unwrap(),
5895            vec![mint_info.clone(), rent_info.clone()],
5896        )
5897        .unwrap();
5898
5899        // create account
5900        do_process_instruction_dups(
5901            initialize_account(&program_id, &account1_key, &mint_key, &owner_key).unwrap(),
5902            vec![
5903                account1_info.clone(),
5904                mint_info.clone(),
5905                owner_info.clone(),
5906                rent_info.clone(),
5907            ],
5908        )
5909        .unwrap();
5910
5911        // mint_to when mint_authority is self
5912        do_process_instruction_dups(
5913            mint_to(&program_id, &mint_key, &account1_key, &mint_key, &[], 42).unwrap(),
5914            vec![mint_info.clone(), account1_info.clone(), mint_info.clone()],
5915        )
5916        .unwrap();
5917
5918        // mint_to_checked when mint_authority is self
5919        do_process_instruction_dups(
5920            mint_to_checked(&program_id, &mint_key, &account1_key, &mint_key, &[], 42, 2).unwrap(),
5921            vec![mint_info.clone(), account1_info.clone(), mint_info.clone()],
5922        )
5923        .unwrap();
5924
5925        // mint_to when mint_authority is account owner
5926        let mut mint = Mint::unpack_unchecked(&mint_info.data.borrow()).unwrap();
5927        mint.mint_authority = COption::Some(account1_key);
5928        Mint::pack(mint, &mut mint_info.data.borrow_mut()).unwrap();
5929        do_process_instruction_dups(
5930            mint_to(
5931                &program_id,
5932                &mint_key,
5933                &account1_key,
5934                &account1_key,
5935                &[],
5936                42,
5937            )
5938            .unwrap(),
5939            vec![
5940                mint_info.clone(),
5941                account1_info.clone(),
5942                account1_info.clone(),
5943            ],
5944        )
5945        .unwrap();
5946
5947        // mint_to_checked when mint_authority is account owner
5948        do_process_instruction_dups(
5949            mint_to(
5950                &program_id,
5951                &mint_key,
5952                &account1_key,
5953                &account1_key,
5954                &[],
5955                42,
5956            )
5957            .unwrap(),
5958            vec![
5959                mint_info.clone(),
5960                account1_info.clone(),
5961                account1_info.clone(),
5962            ],
5963        )
5964        .unwrap();
5965    }
5966
5967    #[test]
5968    fn test_mint_to() {
5969        let program_id = crate::id();
5970        let account_key = Address::new_unique();
5971        let mut account_account = SolanaAccount::new(
5972            account_minimum_balance(),
5973            Account::get_packed_len(),
5974            &program_id,
5975        );
5976        let account2_key = Address::new_unique();
5977        let mut account2_account = SolanaAccount::new(
5978            account_minimum_balance(),
5979            Account::get_packed_len(),
5980            &program_id,
5981        );
5982        let account3_key = Address::new_unique();
5983        let mut account3_account = SolanaAccount::new(
5984            account_minimum_balance(),
5985            Account::get_packed_len(),
5986            &program_id,
5987        );
5988        let mismatch_key = Address::new_unique();
5989        let mut mismatch_account = SolanaAccount::new(
5990            account_minimum_balance(),
5991            Account::get_packed_len(),
5992            &program_id,
5993        );
5994        let owner_key = Address::new_unique();
5995        let mut owner_account = SolanaAccount::default();
5996        let owner2_key = Address::new_unique();
5997        let mut owner2_account = SolanaAccount::default();
5998        let mint_key = Address::new_unique();
5999        let mut mint_account =
6000            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
6001        let mint2_key = Address::new_unique();
6002        let uninitialized_key = Address::new_unique();
6003        let mut uninitialized_account = SolanaAccount::new(
6004            account_minimum_balance(),
6005            Account::get_packed_len(),
6006            &program_id,
6007        );
6008        let mut rent_sysvar = rent_sysvar();
6009
6010        // create new mint with owner
6011        do_process_instruction(
6012            initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
6013            vec![&mut mint_account, &mut rent_sysvar],
6014        )
6015        .unwrap();
6016
6017        // create account
6018        do_process_instruction(
6019            initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
6020            vec![
6021                &mut account_account,
6022                &mut mint_account,
6023                &mut owner_account,
6024                &mut rent_sysvar,
6025            ],
6026        )
6027        .unwrap();
6028
6029        // create another account
6030        do_process_instruction(
6031            initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(),
6032            vec![
6033                &mut account2_account,
6034                &mut mint_account,
6035                &mut owner_account,
6036                &mut rent_sysvar,
6037            ],
6038        )
6039        .unwrap();
6040
6041        // create another account
6042        do_process_instruction(
6043            initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(),
6044            vec![
6045                &mut account3_account,
6046                &mut mint_account,
6047                &mut owner_account,
6048                &mut rent_sysvar,
6049            ],
6050        )
6051        .unwrap();
6052
6053        // create mismatch account
6054        do_process_instruction(
6055            initialize_account(&program_id, &mismatch_key, &mint_key, &owner_key).unwrap(),
6056            vec![
6057                &mut mismatch_account,
6058                &mut mint_account,
6059                &mut owner_account,
6060                &mut rent_sysvar,
6061            ],
6062        )
6063        .unwrap();
6064        let mut account = Account::unpack_unchecked(&mismatch_account.data).unwrap();
6065        account.mint = mint2_key;
6066        Account::pack(account, &mut mismatch_account.data).unwrap();
6067
6068        // mint to
6069        do_process_instruction(
6070            mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 42).unwrap(),
6071            vec![&mut mint_account, &mut account_account, &mut owner_account],
6072        )
6073        .unwrap();
6074
6075        let mint = Mint::unpack_unchecked(&mint_account.data).unwrap();
6076        assert_eq!(mint.supply, 42);
6077        let account = Account::unpack_unchecked(&account_account.data).unwrap();
6078        assert_eq!(account.amount, 42);
6079
6080        // mint to another account to test supply accumulation
6081        do_process_instruction(
6082            mint_to(&program_id, &mint_key, &account2_key, &owner_key, &[], 42).unwrap(),
6083            vec![&mut mint_account, &mut account2_account, &mut owner_account],
6084        )
6085        .unwrap();
6086
6087        let mint = Mint::unpack_unchecked(&mint_account.data).unwrap();
6088        assert_eq!(mint.supply, 84);
6089        let account = Account::unpack_unchecked(&account2_account.data).unwrap();
6090        assert_eq!(account.amount, 42);
6091
6092        // missing signer
6093        let mut instruction =
6094            mint_to(&program_id, &mint_key, &account2_key, &owner_key, &[], 42).unwrap();
6095        instruction.accounts[2].is_signer = false;
6096        assert_eq!(
6097            Err(ProgramError::MissingRequiredSignature),
6098            do_process_instruction(
6099                instruction,
6100                vec![&mut mint_account, &mut account2_account, &mut owner_account],
6101            )
6102        );
6103
6104        // mismatch account
6105        assert_eq!(
6106            Err(TokenError::MintMismatch.into()),
6107            do_process_instruction(
6108                mint_to(&program_id, &mint_key, &mismatch_key, &owner_key, &[], 42).unwrap(),
6109                vec![&mut mint_account, &mut mismatch_account, &mut owner_account],
6110            )
6111        );
6112
6113        // missing owner
6114        assert_eq!(
6115            Err(TokenError::OwnerMismatch.into()),
6116            do_process_instruction(
6117                mint_to(&program_id, &mint_key, &account2_key, &owner2_key, &[], 42).unwrap(),
6118                vec![
6119                    &mut mint_account,
6120                    &mut account2_account,
6121                    &mut owner2_account,
6122                ],
6123            )
6124        );
6125
6126        // mint not owned by program
6127        let not_program_id = Address::new_unique();
6128        mint_account.owner = not_program_id;
6129        assert_eq!(
6130            Err(ProgramError::IncorrectProgramId),
6131            do_process_instruction(
6132                mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 0).unwrap(),
6133                vec![&mut mint_account, &mut account_account, &mut owner_account],
6134            )
6135        );
6136        mint_account.owner = program_id;
6137
6138        // account not owned by program
6139        let not_program_id = Address::new_unique();
6140        account_account.owner = not_program_id;
6141        assert_eq!(
6142            Err(ProgramError::IncorrectProgramId),
6143            do_process_instruction(
6144                mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 0).unwrap(),
6145                vec![&mut mint_account, &mut account_account, &mut owner_account],
6146            )
6147        );
6148        account_account.owner = program_id;
6149
6150        // uninitialized destination account
6151        assert_eq!(
6152            Err(ProgramError::UninitializedAccount),
6153            do_process_instruction(
6154                mint_to(
6155                    &program_id,
6156                    &mint_key,
6157                    &uninitialized_key,
6158                    &owner_key,
6159                    &[],
6160                    42
6161                )
6162                .unwrap(),
6163                vec![
6164                    &mut mint_account,
6165                    &mut uninitialized_account,
6166                    &mut owner_account,
6167                ],
6168            )
6169        );
6170
6171        // unset mint_authority and test minting fails
6172        do_process_instruction(
6173            set_authority(
6174                &program_id,
6175                &mint_key,
6176                None,
6177                AuthorityType::MintTokens,
6178                &owner_key,
6179                &[],
6180            )
6181            .unwrap(),
6182            vec![&mut mint_account, &mut owner_account],
6183        )
6184        .unwrap();
6185        assert_eq!(
6186            Err(TokenError::FixedSupply.into()),
6187            do_process_instruction(
6188                mint_to(&program_id, &mint_key, &account2_key, &owner_key, &[], 42).unwrap(),
6189                vec![&mut mint_account, &mut account2_account, &mut owner_account],
6190            )
6191        );
6192    }
6193
6194    #[test]
6195    fn test_batch_with_invalid_count() {
6196        let program_id = crate::id();
6197        let account_key = Address::new_unique();
6198        let mut account_account = SolanaAccount::new(
6199            account_minimum_balance(),
6200            Account::get_packed_len(),
6201            &program_id,
6202        );
6203        let mint_account_key = Address::new_unique();
6204        let mut mint_account =
6205            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
6206        let mint_owner = Address::new_unique();
6207        let account_owner = Address::new_unique();
6208        let mut account_owner_account = SolanaAccount::default();
6209        let rent_key = rent::id();
6210        let mut rent_sysvar = rent_sysvar();
6211        let account_info: AccountInfo = (&account_key, true, &mut account_account).into();
6212        let mint_account_info: AccountInfo = (&mint_account_key, true, &mut mint_account).into();
6213        let account_owner_info: AccountInfo =
6214            (&account_owner, true, &mut account_owner_account).into();
6215        let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into();
6216
6217        let initialize_mint_instruction =
6218            initialize_mint(&program_id, &mint_account_key, &mint_owner, None, 9).unwrap();
6219
6220        let initialize_account_instruction =
6221            initialize_account3(&program_id, &account_key, &mint_account_key, &account_owner)
6222                .unwrap();
6223
6224        let close_account_instruction = close_account(
6225            &program_id,
6226            &account_key,
6227            &account_owner,
6228            &account_owner,
6229            &[],
6230        )
6231        .unwrap();
6232
6233        let mut batch_instr = batch_instruction(&[
6234            &initialize_mint_instruction,
6235            &initialize_account_instruction,
6236            &close_account_instruction,
6237        ])
6238        .unwrap();
6239
6240        // clear the close discriminator
6241        batch_instr.data.pop();
6242
6243        let temp_mint_data = mint_account_info.data.borrow().to_vec();
6244        let temp_account_data = account_info.data.borrow().to_vec();
6245
6246        assert_eq!(
6247            Err(TokenError::InvalidInstruction.into()),
6248            do_process_instruction_dups(
6249                batch_instr,
6250                vec![
6251                    mint_account_info.clone(),
6252                    rent_info.clone(),
6253                    account_info.clone(),
6254                    mint_account_info.clone(),
6255                    account_info.clone(),
6256                    account_owner_info.clone(),
6257                    account_owner_info.clone(),
6258                ]
6259            )
6260        );
6261
6262        // reset the accounts
6263        mint_account_info
6264            .data
6265            .borrow_mut()
6266            .copy_from_slice(&temp_mint_data);
6267        account_info
6268            .data
6269            .borrow_mut()
6270            .copy_from_slice(&temp_account_data);
6271
6272        let batch_instr = batch_instruction(&[
6273            &initialize_mint_instruction,
6274            &initialize_account_instruction,
6275            &close_account_instruction,
6276        ])
6277        .unwrap();
6278
6279        assert_eq!(
6280            Err(ProgramError::NotEnoughAccountKeys),
6281            do_process_instruction_dups(
6282                batch_instr,
6283                vec![
6284                    mint_account_info.clone(),
6285                    rent_info.clone(),
6286                    account_info.clone(),
6287                ] // leave out the `initialize_account3` accounts and `close_account` accounts
6288            )
6289        );
6290
6291        // reset the accounts
6292        mint_account_info
6293            .data
6294            .borrow_mut()
6295            .copy_from_slice(&temp_mint_data);
6296        account_info
6297            .data
6298            .borrow_mut()
6299            .copy_from_slice(&temp_account_data);
6300
6301        let batch_instruction = batch_instruction(&[
6302            &initialize_mint_instruction,
6303            &initialize_account_instruction,
6304            &close_account_instruction,
6305        ])
6306        .unwrap();
6307
6308        do_process_instruction_dups(
6309            batch_instruction,
6310            vec![
6311                mint_account_info.clone(),
6312                rent_info.clone(),
6313                account_info.clone(),
6314                mint_account_info.clone(),
6315                account_info.clone(),
6316                account_owner_info.clone(),
6317                account_owner_info.clone(),
6318            ],
6319        )
6320        .unwrap();
6321    }
6322
6323    #[test]
6324    fn test_batch_in_batch() {
6325        let program_id = crate::id();
6326        let mint_account_key = Address::new_unique();
6327        let mut mint_account =
6328            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
6329        let mint_owner = Address::new_unique();
6330        let mut mint_owner_account = SolanaAccount::default();
6331        let rent_key = rent::id();
6332        let mut rent_sysvar = rent_sysvar();
6333
6334        let mint_account_info: AccountInfo = (&mint_account_key, true, &mut mint_account).into();
6335        let mint_owner_info: AccountInfo = (&mint_owner, true, &mut mint_owner_account).into();
6336        let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into();
6337
6338        let initialize_mint_instruction = initialize_mint(
6339            &program_id,
6340            &mint_account_key,
6341            &mint_owner,
6342            Some(&mint_owner),
6343            9,
6344        )
6345        .unwrap();
6346
6347        let set_authority_instruction = set_authority(
6348            &program_id,
6349            &mint_account_key,
6350            None,
6351            AuthorityType::FreezeAccount,
6352            &mint_owner,
6353            &[],
6354        )
6355        .unwrap();
6356
6357        let batch_instr = batch_instruction(&[&set_authority_instruction]).unwrap();
6358
6359        let batch_in_batch_instruction =
6360            batch_instruction(&[&batch_instr, &initialize_mint_instruction]).unwrap();
6361
6362        let temp_mint_account_data = mint_account_info.data.borrow().to_vec();
6363
6364        assert_eq!(
6365            Err(TokenError::InvalidInstruction.into()),
6366            do_process_instruction_dups(
6367                batch_in_batch_instruction,
6368                vec![
6369                    mint_account_info.clone(),
6370                    rent_info.clone(),
6371                    mint_account_info.clone(),
6372                    mint_owner_info.clone(),
6373                ]
6374            )
6375        );
6376
6377        // reset account
6378        mint_account_info
6379            .data
6380            .borrow_mut()
6381            .copy_from_slice(&temp_mint_account_data);
6382
6383        do_process_instruction_dups(
6384            initialize_mint_instruction,
6385            vec![mint_account_info.clone(), rent_info.clone()],
6386        )
6387        .unwrap();
6388
6389        do_process_instruction_dups(
6390            batch_instr,
6391            vec![mint_account_info.clone(), mint_owner_info.clone()],
6392        )
6393        .unwrap();
6394    }
6395
6396    #[test]
6397    #[allow(deprecated)]
6398    fn test_batch_initialize_mint_swap() {
6399        let program_id = crate::id();
6400        let account1_key = Address::new_unique();
6401        let mut account1_account = SolanaAccount::new(
6402            account_minimum_balance(),
6403            Account::get_packed_len(),
6404            &program_id,
6405        );
6406        let account2_key = Address::new_unique();
6407        let mut account2_account = SolanaAccount::new(
6408            account_minimum_balance(),
6409            Account::get_packed_len(),
6410            &program_id,
6411        );
6412        let account3_key = Address::new_unique();
6413        let mut account3_account = SolanaAccount::new(
6414            account_minimum_balance(),
6415            Account::get_packed_len(),
6416            &program_id,
6417        );
6418        let account4_key = Address::new_unique();
6419        let mut account4_account = SolanaAccount::new(
6420            account_minimum_balance(),
6421            Account::get_packed_len(),
6422            &program_id,
6423        );
6424        let mint_account1_key = Address::new_unique();
6425        let mut mint1_account =
6426            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
6427        let mint_account2_key = Address::new_unique();
6428        let mut mint2_account = SolanaAccount::new(
6429            mint_minimum_balance(),
6430            Mint::get_packed_len(),
6431            &Address::new_unique(),
6432        );
6433        let mint_owner = Address::new_unique();
6434        let mut mint_owner_account = SolanaAccount::default();
6435        let account_owner = Address::new_unique();
6436        let mut account_owner_account = SolanaAccount::default();
6437        let rent_key = rent::id();
6438        let mut rent_sysvar = rent_sysvar();
6439
6440        let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into();
6441        let account2_info: AccountInfo = (&account2_key, true, &mut account2_account).into();
6442        let account3_info: AccountInfo = (&account3_key, true, &mut account3_account).into();
6443        let account4_info: AccountInfo = (&account4_key, true, &mut account4_account).into();
6444        let mint_account1_info: AccountInfo = (&mint_account1_key, true, &mut mint1_account).into();
6445        let mint_account2_info: AccountInfo = (&mint_account2_key, true, &mut mint2_account).into();
6446        let mint_owner_info: AccountInfo = (&mint_owner, true, &mut mint_owner_account).into();
6447        let account_owner_info: AccountInfo =
6448            (&account_owner, true, &mut account_owner_account).into();
6449        let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into();
6450
6451        let initialize_mint_1_instruction =
6452            initialize_mint(&program_id, &mint_account1_key, &mint_owner, None, 9).unwrap();
6453        let initialize_mint_2_instruction =
6454            initialize_mint(&program_id, &mint_account2_key, &mint_owner, None, 9).unwrap();
6455
6456        let initialize_account_1_instruction = initialize_account3(
6457            &program_id,
6458            &account1_key,
6459            &mint_account1_key,
6460            &account_owner,
6461        )
6462        .unwrap();
6463        let initialize_account_2_instruction = initialize_account3(
6464            &program_id,
6465            &account2_key,
6466            &mint_account2_key,
6467            &account_owner,
6468        )
6469        .unwrap();
6470
6471        let initialize_account_3_instruction = initialize_account3(
6472            &program_id,
6473            &account3_key,
6474            &mint_account1_key,
6475            &account_owner,
6476        )
6477        .unwrap();
6478        let initialize_account_4_instruction = initialize_account3(
6479            &program_id,
6480            &account4_key,
6481            &mint_account2_key,
6482            &account_owner,
6483        )
6484        .unwrap();
6485
6486        let mint_to_1_instruction = mint_to(
6487            &program_id,
6488            &mint_account1_key,
6489            &account1_key,
6490            &mint_owner,
6491            &[],
6492            1000,
6493        )
6494        .unwrap();
6495        let mint_to_2_instruction = mint_to_checked(
6496            &program_id,
6497            &mint_account2_key,
6498            &account2_key,
6499            &mint_owner,
6500            &[],
6501            1000,
6502            9,
6503        )
6504        .unwrap();
6505        let mint_to_2_with_invalid_decimals = mint_to_checked(
6506            &program_id,
6507            &mint_account2_key,
6508            &account2_key,
6509            &mint_owner,
6510            &[],
6511            1000,
6512            8,
6513        )
6514        .unwrap();
6515
6516        let transfer_to_3_instruction = transfer(
6517            &program_id,
6518            &account1_key,
6519            &account3_key,
6520            &account_owner,
6521            &[],
6522            500,
6523        )
6524        .unwrap();
6525        let transfer_to_3_with_invalid_amount = transfer(
6526            &program_id,
6527            &account1_key,
6528            &account3_key,
6529            &account_owner,
6530            &[],
6531            501,
6532        )
6533        .unwrap();
6534        let transfer_4_instruction = transfer_checked(
6535            &program_id,
6536            &account2_key,
6537            &mint_account2_key,
6538            &account4_key,
6539            &account_owner,
6540            &[],
6541            500,
6542            9,
6543        )
6544        .unwrap();
6545
6546        let batch_1_instruction = batch_instruction(&[&initialize_mint_1_instruction]).unwrap();
6547
6548        do_process_instruction_dups(
6549            batch_1_instruction,
6550            vec![mint_account1_info.clone(), rent_info.clone()],
6551        )
6552        .unwrap();
6553
6554        let temp_mint1_data = mint_account1_info.data.borrow().to_vec();
6555        let temp_account1_data = account1_info.data.borrow().to_vec();
6556        let temp_account2_data = account2_info.data.borrow().to_vec();
6557
6558        // fails with incorrect program id(caused by `initialize_account_2_instr`)
6559        let batch_2_fail_instruction = batch_instruction(&[
6560            &initialize_mint_2_instruction,
6561            &initialize_account_1_instruction,
6562            &initialize_account_2_instruction,
6563            &initialize_account_3_instruction,
6564            &initialize_account_4_instruction,
6565        ])
6566        .unwrap();
6567
6568        assert_eq!(
6569            Err(ProgramError::IncorrectProgramId),
6570            do_process_instruction_dups(
6571                batch_2_fail_instruction,
6572                vec![
6573                    mint_account2_info.clone(),
6574                    rent_info.clone(),
6575                    account1_info.clone(),
6576                    mint_account1_info.clone(),
6577                    account2_info.clone(),
6578                    mint_account2_info.clone(),
6579                    account3_info.clone(),
6580                    mint_account1_info.clone(),
6581                    account4_info.clone(),
6582                    mint_account2_info.clone(),
6583                ],
6584            )
6585        );
6586
6587        // reset accounts
6588        mint_account1_info
6589            .data
6590            .borrow_mut()
6591            .copy_from_slice(&temp_mint1_data);
6592        account1_info
6593            .data
6594            .borrow_mut()
6595            .copy_from_slice(&temp_account1_data);
6596        account2_info
6597            .data
6598            .borrow_mut()
6599            .copy_from_slice(&temp_account2_data);
6600
6601        // correct the owner
6602        let mut mint2_account =
6603            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
6604        let mint_account2_info: AccountInfo = (&mint_account2_key, true, &mut mint2_account).into();
6605
6606        // with correct owner
6607        let batch_2_success_instruction = batch_instruction(&[
6608            &initialize_mint_2_instruction,
6609            &initialize_account_1_instruction,
6610            &initialize_account_2_instruction,
6611            &initialize_account_3_instruction,
6612            &initialize_account_4_instruction,
6613        ])
6614        .unwrap();
6615
6616        do_process_instruction_dups(
6617            batch_2_success_instruction,
6618            vec![
6619                mint_account2_info.clone(),
6620                rent_info.clone(),
6621                account1_info.clone(),
6622                mint_account1_info.clone(),
6623                account2_info.clone(),
6624                mint_account2_info.clone(),
6625                account3_info.clone(),
6626                mint_account1_info.clone(),
6627                account4_info.clone(),
6628                mint_account2_info.clone(),
6629            ],
6630        )
6631        .unwrap();
6632
6633        let temp_mint1_data = mint_account1_info.data.borrow().to_vec();
6634        let temp_account1_data = account1_info.data.borrow().to_vec();
6635        let temp_mint2_data = mint_account2_info.data.borrow().to_vec();
6636        let temp_account2_data = account2_info.data.borrow().to_vec();
6637
6638        // with decimals mismatch
6639        let batch_3_fail_instruction = batch_instruction(&[
6640            &mint_to_1_instruction,
6641            &mint_to_2_instruction,
6642            &mint_to_2_with_invalid_decimals,
6643        ])
6644        .unwrap();
6645
6646        assert_eq!(
6647            Err(TokenError::MintDecimalsMismatch.into()),
6648            do_process_instruction_dups(
6649                batch_3_fail_instruction,
6650                vec![
6651                    mint_account1_info.clone(),
6652                    account1_info.clone(),
6653                    mint_owner_info.clone(),
6654                    mint_account2_info.clone(),
6655                    account2_info.clone(),
6656                    mint_owner_info.clone(),
6657                    mint_account2_info.clone(),
6658                    account2_info.clone(),
6659                    mint_owner_info.clone(),
6660                ],
6661            )
6662        );
6663
6664        // reset accounts
6665        mint_account1_info
6666            .data
6667            .borrow_mut()
6668            .copy_from_slice(&temp_mint1_data);
6669        account1_info
6670            .data
6671            .borrow_mut()
6672            .copy_from_slice(&temp_account1_data);
6673        mint_account2_info
6674            .data
6675            .borrow_mut()
6676            .copy_from_slice(&temp_mint2_data);
6677        account2_info
6678            .data
6679            .borrow_mut()
6680            .copy_from_slice(&temp_account2_data);
6681
6682        // without the invalid decimals instruction
6683        let batch_3_success_instruction =
6684            batch_instruction(&[&mint_to_1_instruction, &mint_to_2_instruction]).unwrap();
6685
6686        do_process_instruction_dups(
6687            batch_3_success_instruction,
6688            vec![
6689                mint_account1_info.clone(),
6690                account1_info.clone(),
6691                mint_owner_info.clone(),
6692                mint_account2_info.clone(),
6693                account2_info.clone(),
6694                mint_owner_info.clone(),
6695            ],
6696        )
6697        .unwrap();
6698
6699        let temp_account1_data = account1_info.data.borrow().to_vec();
6700        let temp_account3_data = account3_info.data.borrow().to_vec();
6701        let temp_account2_data = account2_info.data.borrow().to_vec();
6702        let temp_account4_data = account4_info.data.borrow().to_vec();
6703
6704        let batch_4_fail_instruction = batch_instruction(&[
6705            &transfer_to_3_instruction,
6706            &transfer_to_3_with_invalid_amount,
6707            &transfer_4_instruction,
6708        ])
6709        .unwrap();
6710
6711        assert_eq!(
6712            Err(TokenError::InsufficientFunds.into()),
6713            do_process_instruction_dups(
6714                batch_4_fail_instruction,
6715                vec![
6716                    account1_info.clone(),
6717                    account3_info.clone(),
6718                    account_owner_info.clone(),
6719                    account1_info.clone(),
6720                    account3_info.clone(),
6721                    account_owner_info.clone(),
6722                    account2_info.clone(),
6723                    mint_account2_info.clone(),
6724                    account4_info.clone(),
6725                    account_owner_info.clone(),
6726                ],
6727            )
6728        );
6729
6730        // reset accounts
6731        account1_info
6732            .data
6733            .borrow_mut()
6734            .copy_from_slice(&temp_account1_data);
6735        account3_info
6736            .data
6737            .borrow_mut()
6738            .copy_from_slice(&temp_account3_data);
6739        account2_info
6740            .data
6741            .borrow_mut()
6742            .copy_from_slice(&temp_account2_data);
6743        account4_info
6744            .data
6745            .borrow_mut()
6746            .copy_from_slice(&temp_account4_data);
6747
6748        // with valid amount
6749        let batch_4_success_instruction =
6750            batch_instruction(&[&transfer_to_3_instruction, &transfer_4_instruction]).unwrap();
6751
6752        do_process_instruction_dups(
6753            batch_4_success_instruction,
6754            vec![
6755                account1_info.clone(),
6756                account3_info.clone(),
6757                account_owner_info.clone(),
6758                account2_info.clone(),
6759                mint_account2_info.clone(),
6760                account4_info.clone(),
6761                account_owner_info.clone(),
6762            ],
6763        )
6764        .unwrap();
6765    }
6766
6767    #[test]
6768    fn test_burn_dups() {
6769        let program_id = crate::id();
6770        let account1_key = Address::new_unique();
6771        let mut account1_account = SolanaAccount::new(
6772            account_minimum_balance(),
6773            Account::get_packed_len(),
6774            &program_id,
6775        );
6776        let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into();
6777        let owner_key = Address::new_unique();
6778        let mut owner_account = SolanaAccount::default();
6779        let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into();
6780        let mint_key = Address::new_unique();
6781        let mut mint_account =
6782            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
6783        let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into();
6784        let rent_key = rent::id();
6785        let mut rent_sysvar = rent_sysvar();
6786        let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into();
6787
6788        // create mint
6789        do_process_instruction_dups(
6790            initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
6791            vec![mint_info.clone(), rent_info.clone()],
6792        )
6793        .unwrap();
6794
6795        // create account
6796        do_process_instruction_dups(
6797            initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(),
6798            vec![
6799                account1_info.clone(),
6800                mint_info.clone(),
6801                account1_info.clone(),
6802                rent_info.clone(),
6803            ],
6804        )
6805        .unwrap();
6806
6807        // mint to account
6808        do_process_instruction_dups(
6809            mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(),
6810            vec![mint_info.clone(), account1_info.clone(), owner_info.clone()],
6811        )
6812        .unwrap();
6813
6814        // source-owner burn
6815        do_process_instruction_dups(
6816            burn(
6817                &program_id,
6818                &mint_key,
6819                &account1_key,
6820                &account1_key,
6821                &[],
6822                500,
6823            )
6824            .unwrap(),
6825            vec![
6826                account1_info.clone(),
6827                mint_info.clone(),
6828                account1_info.clone(),
6829            ],
6830        )
6831        .unwrap();
6832
6833        // source-owner burn_checked
6834        do_process_instruction_dups(
6835            burn_checked(
6836                &program_id,
6837                &account1_key,
6838                &mint_key,
6839                &account1_key,
6840                &[],
6841                500,
6842                2,
6843            )
6844            .unwrap(),
6845            vec![
6846                account1_info.clone(),
6847                mint_info.clone(),
6848                account1_info.clone(),
6849            ],
6850        )
6851        .unwrap();
6852
6853        // mint-owner burn
6854        do_process_instruction_dups(
6855            mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(),
6856            vec![mint_info.clone(), account1_info.clone(), owner_info.clone()],
6857        )
6858        .unwrap();
6859        let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap();
6860        account.owner = mint_key;
6861        Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap();
6862        do_process_instruction_dups(
6863            burn(&program_id, &account1_key, &mint_key, &mint_key, &[], 500).unwrap(),
6864            vec![account1_info.clone(), mint_info.clone(), mint_info.clone()],
6865        )
6866        .unwrap();
6867
6868        // mint-owner burn_checked
6869        do_process_instruction_dups(
6870            burn_checked(
6871                &program_id,
6872                &account1_key,
6873                &mint_key,
6874                &mint_key,
6875                &[],
6876                500,
6877                2,
6878            )
6879            .unwrap(),
6880            vec![account1_info.clone(), mint_info.clone(), mint_info.clone()],
6881        )
6882        .unwrap();
6883
6884        // source-delegate burn
6885        do_process_instruction_dups(
6886            mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(),
6887            vec![mint_info.clone(), account1_info.clone(), owner_info.clone()],
6888        )
6889        .unwrap();
6890        let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap();
6891        account.delegated_amount = 1000;
6892        account.delegate = COption::Some(account1_key);
6893        account.owner = owner_key;
6894        Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap();
6895        do_process_instruction_dups(
6896            burn(
6897                &program_id,
6898                &account1_key,
6899                &mint_key,
6900                &account1_key,
6901                &[],
6902                500,
6903            )
6904            .unwrap(),
6905            vec![
6906                account1_info.clone(),
6907                mint_info.clone(),
6908                account1_info.clone(),
6909            ],
6910        )
6911        .unwrap();
6912
6913        // source-delegate burn_checked
6914        do_process_instruction_dups(
6915            burn_checked(
6916                &program_id,
6917                &account1_key,
6918                &mint_key,
6919                &account1_key,
6920                &[],
6921                500,
6922                2,
6923            )
6924            .unwrap(),
6925            vec![
6926                account1_info.clone(),
6927                mint_info.clone(),
6928                account1_info.clone(),
6929            ],
6930        )
6931        .unwrap();
6932
6933        // mint-delegate burn
6934        do_process_instruction_dups(
6935            mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(),
6936            vec![mint_info.clone(), account1_info.clone(), owner_info.clone()],
6937        )
6938        .unwrap();
6939        let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap();
6940        account.delegated_amount = 1000;
6941        account.delegate = COption::Some(mint_key);
6942        account.owner = owner_key;
6943        Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap();
6944        do_process_instruction_dups(
6945            burn(&program_id, &account1_key, &mint_key, &mint_key, &[], 500).unwrap(),
6946            vec![account1_info.clone(), mint_info.clone(), mint_info.clone()],
6947        )
6948        .unwrap();
6949
6950        // mint-delegate burn_checked
6951        do_process_instruction_dups(
6952            burn_checked(
6953                &program_id,
6954                &account1_key,
6955                &mint_key,
6956                &mint_key,
6957                &[],
6958                500,
6959                2,
6960            )
6961            .unwrap(),
6962            vec![account1_info.clone(), mint_info.clone(), mint_info.clone()],
6963        )
6964        .unwrap();
6965    }
6966
6967    #[test]
6968    fn test_burn() {
6969        let program_id = crate::id();
6970        let account_key = Address::new_unique();
6971        let mut account_account = SolanaAccount::new(
6972            account_minimum_balance(),
6973            Account::get_packed_len(),
6974            &program_id,
6975        );
6976        let account2_key = Address::new_unique();
6977        let mut account2_account = SolanaAccount::new(
6978            account_minimum_balance(),
6979            Account::get_packed_len(),
6980            &program_id,
6981        );
6982        let account3_key = Address::new_unique();
6983        let mut account3_account = SolanaAccount::new(
6984            account_minimum_balance(),
6985            Account::get_packed_len(),
6986            &program_id,
6987        );
6988        let delegate_key = Address::new_unique();
6989        let mut delegate_account = SolanaAccount::default();
6990        let mismatch_key = Address::new_unique();
6991        let mut mismatch_account = SolanaAccount::new(
6992            account_minimum_balance(),
6993            Account::get_packed_len(),
6994            &program_id,
6995        );
6996        let owner_key = Address::new_unique();
6997        let mut owner_account = SolanaAccount::default();
6998        let owner2_key = Address::new_unique();
6999        let mut owner2_account = SolanaAccount::default();
7000        let mint_key = Address::new_unique();
7001        let mut mint_account =
7002            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
7003        let mint2_key = Address::new_unique();
7004        let mut rent_sysvar = rent_sysvar();
7005
7006        // create new mint
7007        do_process_instruction(
7008            initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
7009            vec![&mut mint_account, &mut rent_sysvar],
7010        )
7011        .unwrap();
7012
7013        // create account
7014        do_process_instruction(
7015            initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
7016            vec![
7017                &mut account_account,
7018                &mut mint_account,
7019                &mut owner_account,
7020                &mut rent_sysvar,
7021            ],
7022        )
7023        .unwrap();
7024
7025        // create another account
7026        do_process_instruction(
7027            initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(),
7028            vec![
7029                &mut account2_account,
7030                &mut mint_account,
7031                &mut owner_account,
7032                &mut rent_sysvar,
7033            ],
7034        )
7035        .unwrap();
7036
7037        // create another account
7038        do_process_instruction(
7039            initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(),
7040            vec![
7041                &mut account3_account,
7042                &mut mint_account,
7043                &mut owner_account,
7044                &mut rent_sysvar,
7045            ],
7046        )
7047        .unwrap();
7048
7049        // create mismatch account
7050        do_process_instruction(
7051            initialize_account(&program_id, &mismatch_key, &mint_key, &owner_key).unwrap(),
7052            vec![
7053                &mut mismatch_account,
7054                &mut mint_account,
7055                &mut owner_account,
7056                &mut rent_sysvar,
7057            ],
7058        )
7059        .unwrap();
7060
7061        // mint to account
7062        do_process_instruction(
7063            mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(),
7064            vec![&mut mint_account, &mut account_account, &mut owner_account],
7065        )
7066        .unwrap();
7067
7068        // mint to mismatch account and change mint key
7069        do_process_instruction(
7070            mint_to(&program_id, &mint_key, &mismatch_key, &owner_key, &[], 1000).unwrap(),
7071            vec![&mut mint_account, &mut mismatch_account, &mut owner_account],
7072        )
7073        .unwrap();
7074        let mut account = Account::unpack_unchecked(&mismatch_account.data).unwrap();
7075        account.mint = mint2_key;
7076        Account::pack(account, &mut mismatch_account.data).unwrap();
7077
7078        // missing signer
7079        let mut instruction =
7080            burn(&program_id, &account_key, &mint_key, &delegate_key, &[], 42).unwrap();
7081        instruction.accounts[1].is_signer = false;
7082        assert_eq!(
7083            Err(TokenError::OwnerMismatch.into()),
7084            do_process_instruction(
7085                instruction,
7086                vec![
7087                    &mut account_account,
7088                    &mut mint_account,
7089                    &mut delegate_account
7090                ],
7091            )
7092        );
7093
7094        // missing owner
7095        assert_eq!(
7096            Err(TokenError::OwnerMismatch.into()),
7097            do_process_instruction(
7098                burn(&program_id, &account_key, &mint_key, &owner2_key, &[], 42).unwrap(),
7099                vec![&mut account_account, &mut mint_account, &mut owner2_account],
7100            )
7101        );
7102
7103        // account not owned by program
7104        let not_program_id = Address::new_unique();
7105        account_account.owner = not_program_id;
7106        assert_eq!(
7107            Err(ProgramError::IncorrectProgramId),
7108            do_process_instruction(
7109                burn(&program_id, &account_key, &mint_key, &owner_key, &[], 0).unwrap(),
7110                vec![&mut account_account, &mut mint_account, &mut owner_account],
7111            )
7112        );
7113        account_account.owner = program_id;
7114
7115        // mint not owned by program
7116        let not_program_id = Address::new_unique();
7117        mint_account.owner = not_program_id;
7118        assert_eq!(
7119            Err(ProgramError::IncorrectProgramId),
7120            do_process_instruction(
7121                burn(&program_id, &account_key, &mint_key, &owner_key, &[], 0).unwrap(),
7122                vec![&mut account_account, &mut mint_account, &mut owner_account],
7123            )
7124        );
7125        mint_account.owner = program_id;
7126
7127        // mint mismatch
7128        assert_eq!(
7129            Err(TokenError::MintMismatch.into()),
7130            do_process_instruction(
7131                burn(&program_id, &mismatch_key, &mint_key, &owner_key, &[], 42).unwrap(),
7132                vec![&mut mismatch_account, &mut mint_account, &mut owner_account],
7133            )
7134        );
7135
7136        // burn
7137        do_process_instruction(
7138            burn(&program_id, &account_key, &mint_key, &owner_key, &[], 21).unwrap(),
7139            vec![&mut account_account, &mut mint_account, &mut owner_account],
7140        )
7141        .unwrap();
7142
7143        // burn_checked, with incorrect decimals
7144        assert_eq!(
7145            Err(TokenError::MintDecimalsMismatch.into()),
7146            do_process_instruction(
7147                burn_checked(&program_id, &account_key, &mint_key, &owner_key, &[], 21, 3).unwrap(),
7148                vec![&mut account_account, &mut mint_account, &mut owner_account],
7149            )
7150        );
7151
7152        // burn_checked
7153        do_process_instruction(
7154            burn_checked(&program_id, &account_key, &mint_key, &owner_key, &[], 21, 2).unwrap(),
7155            vec![&mut account_account, &mut mint_account, &mut owner_account],
7156        )
7157        .unwrap();
7158
7159        let mint = Mint::unpack_unchecked(&mint_account.data).unwrap();
7160        assert_eq!(mint.supply, 2000 - 42);
7161        let account = Account::unpack_unchecked(&account_account.data).unwrap();
7162        assert_eq!(account.amount, 1000 - 42);
7163
7164        // insufficient funds
7165        assert_eq!(
7166            Err(TokenError::InsufficientFunds.into()),
7167            do_process_instruction(
7168                burn(
7169                    &program_id,
7170                    &account_key,
7171                    &mint_key,
7172                    &owner_key,
7173                    &[],
7174                    100_000_000
7175                )
7176                .unwrap(),
7177                vec![&mut account_account, &mut mint_account, &mut owner_account],
7178            )
7179        );
7180
7181        // approve delegate
7182        do_process_instruction(
7183            approve(
7184                &program_id,
7185                &account_key,
7186                &delegate_key,
7187                &owner_key,
7188                &[],
7189                84,
7190            )
7191            .unwrap(),
7192            vec![
7193                &mut account_account,
7194                &mut delegate_account,
7195                &mut owner_account,
7196            ],
7197        )
7198        .unwrap();
7199
7200        // not a delegate of source account
7201        assert_eq!(
7202            Err(TokenError::OwnerMismatch.into()),
7203            do_process_instruction(
7204                burn(
7205                    &program_id,
7206                    &account_key,
7207                    &mint_key,
7208                    &owner2_key, // <-- incorrect owner or delegate
7209                    &[],
7210                    1,
7211                )
7212                .unwrap(),
7213                vec![&mut account_account, &mut mint_account, &mut owner2_account],
7214            )
7215        );
7216
7217        // insufficient funds approved via delegate
7218        assert_eq!(
7219            Err(TokenError::InsufficientFunds.into()),
7220            do_process_instruction(
7221                burn(&program_id, &account_key, &mint_key, &delegate_key, &[], 85).unwrap(),
7222                vec![
7223                    &mut account_account,
7224                    &mut mint_account,
7225                    &mut delegate_account
7226                ],
7227            )
7228        );
7229
7230        // burn via delegate
7231        do_process_instruction(
7232            burn(&program_id, &account_key, &mint_key, &delegate_key, &[], 84).unwrap(),
7233            vec![
7234                &mut account_account,
7235                &mut mint_account,
7236                &mut delegate_account,
7237            ],
7238        )
7239        .unwrap();
7240
7241        // match
7242        let mint = Mint::unpack_unchecked(&mint_account.data).unwrap();
7243        assert_eq!(mint.supply, 2000 - 42 - 84);
7244        let account = Account::unpack_unchecked(&account_account.data).unwrap();
7245        assert_eq!(account.amount, 1000 - 42 - 84);
7246
7247        // insufficient funds approved via delegate
7248        assert_eq!(
7249            Err(TokenError::OwnerMismatch.into()),
7250            do_process_instruction(
7251                burn(&program_id, &account_key, &mint_key, &delegate_key, &[], 1).unwrap(),
7252                vec![
7253                    &mut account_account,
7254                    &mut mint_account,
7255                    &mut delegate_account
7256                ],
7257            )
7258        );
7259    }
7260
7261    #[test]
7262    fn test_multisig() {
7263        let program_id = crate::id();
7264        let mint_key = Address::new_unique();
7265        let mut mint_account =
7266            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
7267        let account_key = Address::new_unique();
7268        let mut account = SolanaAccount::new(
7269            account_minimum_balance(),
7270            Account::get_packed_len(),
7271            &program_id,
7272        );
7273        let account2_key = Address::new_unique();
7274        let mut account2_account = SolanaAccount::new(
7275            account_minimum_balance(),
7276            Account::get_packed_len(),
7277            &program_id,
7278        );
7279        let owner_key = Address::new_unique();
7280        let mut owner_account = SolanaAccount::default();
7281        let multisig_key = Address::new_unique();
7282        let mut multisig_account = SolanaAccount::new(42, Multisig::get_packed_len(), &program_id);
7283        let mut empty_multisig_account =
7284            SolanaAccount::new(42, Multisig::get_packed_len(), &program_id);
7285        let multisig_delegate_key = Address::new_unique();
7286        let mut multisig_delegate_account = SolanaAccount::new(
7287            multisig_minimum_balance(),
7288            Multisig::get_packed_len(),
7289            &program_id,
7290        );
7291        let signer_keys = vec![Address::new_unique(); MAX_SIGNERS];
7292        let signer_key_refs: Vec<&Address> = signer_keys.iter().collect();
7293        let mut signer_accounts = vec![SolanaAccount::new(0, 0, &program_id); MAX_SIGNERS];
7294        let mut rent_sysvar = rent_sysvar();
7295
7296        // multisig is not rent exempt
7297        let account_info_iter = &mut signer_accounts.iter_mut();
7298        assert_eq!(
7299            Err(TokenError::NotRentExempt.into()),
7300            do_process_instruction(
7301                initialize_multisig(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(),
7302                vec![
7303                    &mut multisig_account,
7304                    &mut rent_sysvar,
7305                    account_info_iter.next().unwrap(),
7306                ],
7307            )
7308        );
7309
7310        multisig_account.lamports = multisig_minimum_balance();
7311        let mut multisig_account2 = multisig_account.clone();
7312
7313        // single signer
7314        let account_info_iter = &mut signer_accounts.iter_mut();
7315        do_process_instruction(
7316            initialize_multisig(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(),
7317            vec![
7318                &mut multisig_account,
7319                &mut rent_sysvar,
7320                account_info_iter.next().unwrap(),
7321            ],
7322        )
7323        .unwrap();
7324
7325        // single signer using `initialize_multisig2`
7326        let account_info_iter = &mut signer_accounts.iter_mut();
7327        do_process_instruction(
7328            initialize_multisig2(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(),
7329            vec![&mut multisig_account2, account_info_iter.next().unwrap()],
7330        )
7331        .unwrap();
7332
7333        // multiple signer
7334        let account_info_iter = &mut signer_accounts.iter_mut();
7335        do_process_instruction(
7336            initialize_multisig(
7337                &program_id,
7338                &multisig_delegate_key,
7339                &signer_key_refs,
7340                MAX_SIGNERS as u8,
7341            )
7342            .unwrap(),
7343            vec![
7344                &mut multisig_delegate_account,
7345                &mut rent_sysvar,
7346                account_info_iter.next().unwrap(),
7347                account_info_iter.next().unwrap(),
7348                account_info_iter.next().unwrap(),
7349                account_info_iter.next().unwrap(),
7350                account_info_iter.next().unwrap(),
7351                account_info_iter.next().unwrap(),
7352                account_info_iter.next().unwrap(),
7353                account_info_iter.next().unwrap(),
7354                account_info_iter.next().unwrap(),
7355                account_info_iter.next().unwrap(),
7356                account_info_iter.next().unwrap(),
7357            ],
7358        )
7359        .unwrap();
7360
7361        // create new mint with multisig owner
7362        do_process_instruction(
7363            initialize_mint(&program_id, &mint_key, &multisig_key, None, 2).unwrap(),
7364            vec![&mut mint_account, &mut rent_sysvar],
7365        )
7366        .unwrap();
7367
7368        // create account with multisig owner
7369        do_process_instruction(
7370            initialize_account(&program_id, &account_key, &mint_key, &multisig_key).unwrap(),
7371            vec![
7372                &mut account,
7373                &mut mint_account,
7374                &mut multisig_account,
7375                &mut rent_sysvar,
7376            ],
7377        )
7378        .unwrap();
7379
7380        // create another account with multisig owner
7381        do_process_instruction(
7382            initialize_account(
7383                &program_id,
7384                &account2_key,
7385                &mint_key,
7386                &multisig_delegate_key,
7387            )
7388            .unwrap(),
7389            vec![
7390                &mut account2_account,
7391                &mut mint_account,
7392                &mut multisig_account,
7393                &mut rent_sysvar,
7394            ],
7395        )
7396        .unwrap();
7397
7398        // mint to account
7399        let account_info_iter = &mut signer_accounts.iter_mut();
7400        do_process_instruction(
7401            mint_to(
7402                &program_id,
7403                &mint_key,
7404                &account_key,
7405                &multisig_key,
7406                &[&signer_keys[0]],
7407                1000,
7408            )
7409            .unwrap(),
7410            vec![
7411                &mut mint_account,
7412                &mut account,
7413                &mut multisig_account,
7414                account_info_iter.next().unwrap(),
7415            ],
7416        )
7417        .unwrap();
7418
7419        // fail with uninitialized multisig
7420        let account_info_iter = &mut signer_accounts.iter_mut();
7421        assert_eq!(
7422            ProgramError::UninitializedAccount,
7423            do_process_instruction(
7424                approve(
7425                    &program_id,
7426                    &account_key,
7427                    &multisig_delegate_key,
7428                    &multisig_key,
7429                    &[],
7430                    100,
7431                )
7432                .unwrap(),
7433                vec![
7434                    &mut account,
7435                    &mut multisig_delegate_account,
7436                    &mut empty_multisig_account,
7437                    account_info_iter.next().unwrap(),
7438                ],
7439            )
7440            .unwrap_err(),
7441        );
7442
7443        // approve
7444        let account_info_iter = &mut signer_accounts.iter_mut();
7445        do_process_instruction(
7446            approve(
7447                &program_id,
7448                &account_key,
7449                &multisig_delegate_key,
7450                &multisig_key,
7451                &[&signer_keys[0]],
7452                100,
7453            )
7454            .unwrap(),
7455            vec![
7456                &mut account,
7457                &mut multisig_delegate_account,
7458                &mut multisig_account,
7459                account_info_iter.next().unwrap(),
7460            ],
7461        )
7462        .unwrap();
7463
7464        // transfer
7465        let account_info_iter = &mut signer_accounts.iter_mut();
7466        do_process_instruction(
7467            #[allow(deprecated)]
7468            transfer(
7469                &program_id,
7470                &account_key,
7471                &account2_key,
7472                &multisig_key,
7473                &[&signer_keys[0]],
7474                42,
7475            )
7476            .unwrap(),
7477            vec![
7478                &mut account,
7479                &mut account2_account,
7480                &mut multisig_account,
7481                account_info_iter.next().unwrap(),
7482            ],
7483        )
7484        .unwrap();
7485
7486        // transfer via delegate
7487        let account_info_iter = &mut signer_accounts.iter_mut();
7488        do_process_instruction(
7489            #[allow(deprecated)]
7490            transfer(
7491                &program_id,
7492                &account_key,
7493                &account2_key,
7494                &multisig_delegate_key,
7495                &signer_key_refs,
7496                42,
7497            )
7498            .unwrap(),
7499            vec![
7500                &mut account,
7501                &mut account2_account,
7502                &mut multisig_delegate_account,
7503                account_info_iter.next().unwrap(),
7504                account_info_iter.next().unwrap(),
7505                account_info_iter.next().unwrap(),
7506                account_info_iter.next().unwrap(),
7507                account_info_iter.next().unwrap(),
7508                account_info_iter.next().unwrap(),
7509                account_info_iter.next().unwrap(),
7510                account_info_iter.next().unwrap(),
7511                account_info_iter.next().unwrap(),
7512                account_info_iter.next().unwrap(),
7513                account_info_iter.next().unwrap(),
7514            ],
7515        )
7516        .unwrap();
7517
7518        // mint to
7519        let account_info_iter = &mut signer_accounts.iter_mut();
7520        do_process_instruction(
7521            mint_to(
7522                &program_id,
7523                &mint_key,
7524                &account2_key,
7525                &multisig_key,
7526                &[&signer_keys[0]],
7527                42,
7528            )
7529            .unwrap(),
7530            vec![
7531                &mut mint_account,
7532                &mut account2_account,
7533                &mut multisig_account,
7534                account_info_iter.next().unwrap(),
7535            ],
7536        )
7537        .unwrap();
7538
7539        // burn
7540        let account_info_iter = &mut signer_accounts.iter_mut();
7541        do_process_instruction(
7542            burn(
7543                &program_id,
7544                &account_key,
7545                &mint_key,
7546                &multisig_key,
7547                &[&signer_keys[0]],
7548                42,
7549            )
7550            .unwrap(),
7551            vec![
7552                &mut account,
7553                &mut mint_account,
7554                &mut multisig_account,
7555                account_info_iter.next().unwrap(),
7556            ],
7557        )
7558        .unwrap();
7559
7560        // burn via delegate
7561        let account_info_iter = &mut signer_accounts.iter_mut();
7562        do_process_instruction(
7563            burn(
7564                &program_id,
7565                &account_key,
7566                &mint_key,
7567                &multisig_delegate_key,
7568                &signer_key_refs,
7569                42,
7570            )
7571            .unwrap(),
7572            vec![
7573                &mut account,
7574                &mut mint_account,
7575                &mut multisig_delegate_account,
7576                account_info_iter.next().unwrap(),
7577                account_info_iter.next().unwrap(),
7578                account_info_iter.next().unwrap(),
7579                account_info_iter.next().unwrap(),
7580                account_info_iter.next().unwrap(),
7581                account_info_iter.next().unwrap(),
7582                account_info_iter.next().unwrap(),
7583                account_info_iter.next().unwrap(),
7584                account_info_iter.next().unwrap(),
7585                account_info_iter.next().unwrap(),
7586                account_info_iter.next().unwrap(),
7587            ],
7588        )
7589        .unwrap();
7590
7591        // freeze account
7592        let account3_key = Address::new_unique();
7593        let mut account3_account = SolanaAccount::new(
7594            account_minimum_balance(),
7595            Account::get_packed_len(),
7596            &program_id,
7597        );
7598        let mint2_key = Address::new_unique();
7599        let mut mint2_account =
7600            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
7601        do_process_instruction(
7602            initialize_mint(
7603                &program_id,
7604                &mint2_key,
7605                &multisig_key,
7606                Some(&multisig_key),
7607                2,
7608            )
7609            .unwrap(),
7610            vec![&mut mint2_account, &mut rent_sysvar],
7611        )
7612        .unwrap();
7613        do_process_instruction(
7614            initialize_account(&program_id, &account3_key, &mint2_key, &owner_key).unwrap(),
7615            vec![
7616                &mut account3_account,
7617                &mut mint2_account,
7618                &mut owner_account,
7619                &mut rent_sysvar,
7620            ],
7621        )
7622        .unwrap();
7623        let account_info_iter = &mut signer_accounts.iter_mut();
7624        do_process_instruction(
7625            mint_to(
7626                &program_id,
7627                &mint2_key,
7628                &account3_key,
7629                &multisig_key,
7630                &[&signer_keys[0]],
7631                1000,
7632            )
7633            .unwrap(),
7634            vec![
7635                &mut mint2_account,
7636                &mut account3_account,
7637                &mut multisig_account,
7638                account_info_iter.next().unwrap(),
7639            ],
7640        )
7641        .unwrap();
7642        let account_info_iter = &mut signer_accounts.iter_mut();
7643        do_process_instruction(
7644            freeze_account(
7645                &program_id,
7646                &account3_key,
7647                &mint2_key,
7648                &multisig_key,
7649                &[&signer_keys[0]],
7650            )
7651            .unwrap(),
7652            vec![
7653                &mut account3_account,
7654                &mut mint2_account,
7655                &mut multisig_account,
7656                account_info_iter.next().unwrap(),
7657            ],
7658        )
7659        .unwrap();
7660
7661        // do SetAuthority on mint
7662        let account_info_iter = &mut signer_accounts.iter_mut();
7663        do_process_instruction(
7664            set_authority(
7665                &program_id,
7666                &mint_key,
7667                Some(&owner_key),
7668                AuthorityType::MintTokens,
7669                &multisig_key,
7670                &[&signer_keys[0]],
7671            )
7672            .unwrap(),
7673            vec![
7674                &mut mint_account,
7675                &mut multisig_account,
7676                account_info_iter.next().unwrap(),
7677            ],
7678        )
7679        .unwrap();
7680
7681        // do SetAuthority on account
7682        let account_info_iter = &mut signer_accounts.iter_mut();
7683        do_process_instruction(
7684            set_authority(
7685                &program_id,
7686                &account_key,
7687                Some(&owner_key),
7688                AuthorityType::AccountOwner,
7689                &multisig_key,
7690                &[&signer_keys[0]],
7691            )
7692            .unwrap(),
7693            vec![
7694                &mut account,
7695                &mut multisig_account,
7696                account_info_iter.next().unwrap(),
7697            ],
7698        )
7699        .unwrap();
7700    }
7701
7702    #[test]
7703    fn test_permissioned_burn_none_authority_errors() {
7704        let program_id = crate::id();
7705        let mint_key = Address::new_unique();
7706        let owner_key = Address::new_unique();
7707        let burn_authority_key = Address::new_unique();
7708        let account_key = Address::new_unique();
7709
7710        let mint_size =
7711            ExtensionType::try_calculate_account_len::<PodMint>(&[ExtensionType::PermissionedBurn])
7712                .unwrap();
7713
7714        let mut mint_account = SolanaAccount::new(
7715            Rent::default().minimum_balance(mint_size),
7716            mint_size,
7717            &program_id,
7718        );
7719        let mut account_account = SolanaAccount::new(
7720            account_minimum_balance(),
7721            Account::get_packed_len(),
7722            &program_id,
7723        );
7724        let mut owner_account = SolanaAccount::default();
7725        let mut burn_authority_account = SolanaAccount::default();
7726        let mut rent_sysvar = rent_sysvar();
7727
7728        do_process_instruction(
7729            permissioned_burn::instruction::initialize(&program_id, &mint_key, &burn_authority_key)
7730                .unwrap(),
7731            vec![&mut mint_account],
7732        )
7733        .unwrap();
7734        do_process_instruction(
7735            initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
7736            vec![&mut mint_account, &mut rent_sysvar],
7737        )
7738        .unwrap();
7739
7740        // Create account and mint some tokens.
7741        do_process_instruction(
7742            initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
7743            vec![
7744                &mut account_account,
7745                &mut mint_account,
7746                &mut owner_account,
7747                &mut rent_sysvar,
7748            ],
7749        )
7750        .unwrap();
7751        do_process_instruction(
7752            mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 10).unwrap(),
7753            vec![&mut mint_account, &mut account_account, &mut owner_account],
7754        )
7755        .unwrap();
7756
7757        // Clear the permissioned burn authority.
7758        do_process_instruction(
7759            set_authority(
7760                &program_id,
7761                &mint_key,
7762                None,
7763                AuthorityType::PermissionedBurn,
7764                &burn_authority_key,
7765                &[],
7766            )
7767            .unwrap(),
7768            vec![&mut mint_account, &mut burn_authority_account],
7769        )
7770        .unwrap();
7771
7772        // Attempt a permissioned burn should fail when authority is None.
7773        assert_eq!(
7774            Err(TokenError::InvalidInstruction.into()),
7775            do_process_instruction(
7776                permissioned_burn::instruction::burn(
7777                    &program_id,
7778                    &account_key,
7779                    &mint_key,
7780                    &burn_authority_key,
7781                    &owner_key,
7782                    &[],
7783                    1
7784                )
7785                .unwrap(),
7786                vec![
7787                    &mut account_account,
7788                    &mut mint_account,
7789                    &mut burn_authority_account,
7790                    &mut owner_account
7791                ],
7792            )
7793        );
7794
7795        // Standard burn should still succeed after authority is cleared.
7796        assert_eq!(
7797            Ok(()),
7798            do_process_instruction(
7799                burn(&program_id, &account_key, &mint_key, &owner_key, &[], 1).unwrap(),
7800                vec![&mut account_account, &mut mint_account, &mut owner_account],
7801            )
7802        );
7803    }
7804
7805    #[test]
7806    fn test_validate_owner() {
7807        let program_id = crate::id();
7808        let owner_key = Address::new_unique();
7809        let account_to_validate = Address::new_unique();
7810        let mut signer_keys = [Address::default(); MAX_SIGNERS];
7811        for signer_key in signer_keys.iter_mut().take(MAX_SIGNERS) {
7812            *signer_key = Address::new_unique();
7813        }
7814        let mut signer_lamports = 0;
7815        let mut signer_data = vec![];
7816        let mut signers = vec![
7817            AccountInfo::new(
7818                &owner_key,
7819                true,
7820                false,
7821                &mut signer_lamports,
7822                &mut signer_data,
7823                &program_id,
7824                false,
7825            );
7826            MAX_SIGNERS + 1
7827        ];
7828        for (signer, key) in signers.iter_mut().zip(&signer_keys) {
7829            signer.key = key;
7830        }
7831        let mut lamports = 0;
7832        let mut data = vec![0; Multisig::get_packed_len()];
7833        let mut multisig = Multisig::unpack_unchecked(&data).unwrap();
7834        multisig.m = MAX_SIGNERS as u8;
7835        multisig.n = MAX_SIGNERS as u8;
7836        multisig.signers = signer_keys;
7837        multisig.is_initialized = true;
7838        Multisig::pack(multisig, &mut data).unwrap();
7839        let owner_account_info = AccountInfo::new(
7840            &owner_key,
7841            false,
7842            false,
7843            &mut lamports,
7844            &mut data,
7845            &program_id,
7846            false,
7847        );
7848
7849        // no multisig, but the account is its own authority, and data is mutably
7850        // borrowed
7851        {
7852            let mut lamports = 0;
7853            let mut data = vec![0; Account::get_packed_len()];
7854            let mut account = Account::unpack_unchecked(&data).unwrap();
7855            account.owner = account_to_validate;
7856            Account::pack(account, &mut data).unwrap();
7857            let account_info = AccountInfo::new(
7858                &account_to_validate,
7859                true,
7860                false,
7861                &mut lamports,
7862                &mut data,
7863                &program_id,
7864                false,
7865            );
7866            let account_info_data_len = account_info.data_len();
7867            let mut borrowed_data = account_info.try_borrow_mut_data().unwrap();
7868            Processor::validate_owner(
7869                &program_id,
7870                &account_to_validate,
7871                &account_info,
7872                account_info_data_len,
7873                &[],
7874            )
7875            .unwrap();
7876            // modify the data to be sure that it wasn't silently dropped by the compiler
7877            borrowed_data[0] = 1;
7878        }
7879
7880        // full 11 of 11
7881        Processor::validate_owner(
7882            &program_id,
7883            &owner_key,
7884            &owner_account_info,
7885            owner_account_info.data_len(),
7886            &signers,
7887        )
7888        .unwrap();
7889
7890        // full 11 of 11, multisig owned by tokenkeg (legacy spl-token program)
7891        {
7892            let tokenkeg_id = inline_spl_token::id();
7893            let mut lamports = 0;
7894            let mut data = vec![0; Multisig::get_packed_len()];
7895            let mut multisig = Multisig::unpack_unchecked(&data).unwrap();
7896            multisig.m = MAX_SIGNERS as u8;
7897            multisig.n = MAX_SIGNERS as u8;
7898            multisig.signers = signer_keys;
7899            multisig.is_initialized = true;
7900            Multisig::pack(multisig, &mut data).unwrap();
7901            let tokenkeg_multisig_info = AccountInfo::new(
7902                &owner_key,
7903                false,
7904                false,
7905                &mut lamports,
7906                &mut data,
7907                &tokenkeg_id,
7908                false,
7909            );
7910            Processor::validate_owner(
7911                &program_id,
7912                &owner_key,
7913                &tokenkeg_multisig_info,
7914                tokenkeg_multisig_info.data_len(),
7915                &signers,
7916            )
7917            .unwrap();
7918        }
7919
7920        // 1 of 11
7921        {
7922            let mut multisig =
7923                Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap();
7924            multisig.m = 1;
7925            Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap();
7926        }
7927        Processor::validate_owner(
7928            &program_id,
7929            &owner_key,
7930            &owner_account_info,
7931            owner_account_info.data_len(),
7932            &signers,
7933        )
7934        .unwrap();
7935
7936        // 2:1
7937        {
7938            let mut multisig =
7939                Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap();
7940            multisig.m = 2;
7941            multisig.n = 1;
7942            Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap();
7943        }
7944        assert_eq!(
7945            Err(ProgramError::MissingRequiredSignature),
7946            Processor::validate_owner(
7947                &program_id,
7948                &owner_key,
7949                &owner_account_info,
7950                owner_account_info.data_len(),
7951                &signers
7952            )
7953        );
7954
7955        // 0:11
7956        {
7957            let mut multisig =
7958                Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap();
7959            multisig.m = 0;
7960            multisig.n = 11;
7961            Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap();
7962        }
7963        Processor::validate_owner(
7964            &program_id,
7965            &owner_key,
7966            &owner_account_info,
7967            owner_account_info.data_len(),
7968            &signers,
7969        )
7970        .unwrap();
7971
7972        // 2:11 but 0 provided
7973        {
7974            let mut multisig =
7975                Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap();
7976            multisig.m = 2;
7977            multisig.n = 11;
7978            Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap();
7979        }
7980        assert_eq!(
7981            Err(ProgramError::MissingRequiredSignature),
7982            Processor::validate_owner(
7983                &program_id,
7984                &owner_key,
7985                &owner_account_info,
7986                owner_account_info.data_len(),
7987                &[]
7988            )
7989        );
7990        // 2:11 but 1 provided
7991        {
7992            let mut multisig =
7993                Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap();
7994            multisig.m = 2;
7995            multisig.n = 11;
7996            Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap();
7997        }
7998        assert_eq!(
7999            Err(ProgramError::MissingRequiredSignature),
8000            Processor::validate_owner(
8001                &program_id,
8002                &owner_key,
8003                &owner_account_info,
8004                owner_account_info.data_len(),
8005                &signers[0..1]
8006            )
8007        );
8008
8009        // 2:11, 2 from middle provided
8010        {
8011            let mut multisig =
8012                Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap();
8013            multisig.m = 2;
8014            multisig.n = 11;
8015            Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap();
8016        }
8017        Processor::validate_owner(
8018            &program_id,
8019            &owner_key,
8020            &owner_account_info,
8021            owner_account_info.data_len(),
8022            &signers[5..7],
8023        )
8024        .unwrap();
8025
8026        // 11:11, one is not a signer
8027        {
8028            let mut multisig =
8029                Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap();
8030            multisig.m = 11;
8031            multisig.n = 11;
8032            Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap();
8033        }
8034        signers[5].is_signer = false;
8035        assert_eq!(
8036            Err(ProgramError::MissingRequiredSignature),
8037            Processor::validate_owner(
8038                &program_id,
8039                &owner_key,
8040                &owner_account_info,
8041                owner_account_info.data_len(),
8042                &signers
8043            )
8044        );
8045        signers[5].is_signer = true;
8046
8047        // 11:11, single signer signs multiple times
8048        {
8049            let mut signer_lamports = 0;
8050            let mut signer_data = vec![];
8051            let signers = vec![
8052                AccountInfo::new(
8053                    &signer_keys[5],
8054                    true,
8055                    false,
8056                    &mut signer_lamports,
8057                    &mut signer_data,
8058                    &program_id,
8059                    false,
8060                );
8061                MAX_SIGNERS + 1
8062            ];
8063            let mut multisig =
8064                Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap();
8065            multisig.m = 11;
8066            multisig.n = 11;
8067            Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap();
8068            assert_eq!(
8069                Err(ProgramError::MissingRequiredSignature),
8070                Processor::validate_owner(
8071                    &program_id,
8072                    &owner_key,
8073                    &owner_account_info,
8074                    owner_account_info.data_len(),
8075                    &signers
8076                )
8077            );
8078        }
8079    }
8080
8081    #[test]
8082    fn test_owner_close_account_dups() {
8083        let program_id = crate::id();
8084        let owner_key = Address::new_unique();
8085        let mint_key = Address::new_unique();
8086        let mut mint_account =
8087            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
8088        let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into();
8089        let rent_key = rent::id();
8090        let mut rent_sysvar = rent_sysvar();
8091        let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into();
8092
8093        // create mint
8094        do_process_instruction_dups(
8095            initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
8096            vec![mint_info.clone(), rent_info.clone()],
8097        )
8098        .unwrap();
8099
8100        let to_close_key = Address::new_unique();
8101        let mut to_close_account = SolanaAccount::new(
8102            account_minimum_balance(),
8103            Account::get_packed_len(),
8104            &program_id,
8105        );
8106        let to_close_account_info: AccountInfo =
8107            (&to_close_key, true, &mut to_close_account).into();
8108        let destination_account_key = Address::new_unique();
8109        let mut destination_account = SolanaAccount::new(
8110            account_minimum_balance(),
8111            Account::get_packed_len(),
8112            &program_id,
8113        );
8114        let destination_account_info: AccountInfo =
8115            (&destination_account_key, true, &mut destination_account).into();
8116        // create account
8117        do_process_instruction_dups(
8118            initialize_account(&program_id, &to_close_key, &mint_key, &to_close_key).unwrap(),
8119            vec![
8120                to_close_account_info.clone(),
8121                mint_info.clone(),
8122                to_close_account_info.clone(),
8123                rent_info.clone(),
8124            ],
8125        )
8126        .unwrap();
8127
8128        // source-owner close
8129        do_process_instruction_dups(
8130            close_account(
8131                &program_id,
8132                &to_close_key,
8133                &destination_account_key,
8134                &to_close_key,
8135                &[],
8136            )
8137            .unwrap(),
8138            vec![
8139                to_close_account_info.clone(),
8140                destination_account_info.clone(),
8141                to_close_account_info.clone(),
8142            ],
8143        )
8144        .unwrap();
8145        assert_eq!(*to_close_account_info.data.borrow(), &[0u8; Account::LEN]);
8146    }
8147
8148    #[test]
8149    fn test_close_authority_close_account_dups() {
8150        let program_id = crate::id();
8151        let owner_key = Address::new_unique();
8152        let mint_key = Address::new_unique();
8153        let mut mint_account =
8154            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
8155        let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into();
8156        let rent_key = rent::id();
8157        let mut rent_sysvar = rent_sysvar();
8158        let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into();
8159
8160        // create mint
8161        do_process_instruction_dups(
8162            initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
8163            vec![mint_info.clone(), rent_info.clone()],
8164        )
8165        .unwrap();
8166
8167        let to_close_key = Address::new_unique();
8168        let mut to_close_account = SolanaAccount::new(
8169            account_minimum_balance(),
8170            Account::get_packed_len(),
8171            &program_id,
8172        );
8173        let to_close_account_info: AccountInfo =
8174            (&to_close_key, true, &mut to_close_account).into();
8175        let destination_account_key = Address::new_unique();
8176        let mut destination_account = SolanaAccount::new(
8177            account_minimum_balance(),
8178            Account::get_packed_len(),
8179            &program_id,
8180        );
8181        let destination_account_info: AccountInfo =
8182            (&destination_account_key, true, &mut destination_account).into();
8183        // create account
8184        do_process_instruction_dups(
8185            initialize_account(&program_id, &to_close_key, &mint_key, &to_close_key).unwrap(),
8186            vec![
8187                to_close_account_info.clone(),
8188                mint_info.clone(),
8189                to_close_account_info.clone(),
8190                rent_info.clone(),
8191            ],
8192        )
8193        .unwrap();
8194        let mut account = Account::unpack_unchecked(&to_close_account_info.data.borrow()).unwrap();
8195        account.close_authority = COption::Some(to_close_key);
8196        account.owner = owner_key;
8197        Account::pack(account, &mut to_close_account_info.data.borrow_mut()).unwrap();
8198        do_process_instruction_dups(
8199            close_account(
8200                &program_id,
8201                &to_close_key,
8202                &destination_account_key,
8203                &to_close_key,
8204                &[],
8205            )
8206            .unwrap(),
8207            vec![
8208                to_close_account_info.clone(),
8209                destination_account_info.clone(),
8210                to_close_account_info.clone(),
8211            ],
8212        )
8213        .unwrap();
8214        assert_eq!(*to_close_account_info.data.borrow(), &[0u8; Account::LEN]);
8215    }
8216
8217    #[test]
8218    fn test_close_account() {
8219        let program_id = crate::id();
8220        let mint_key = Address::new_unique();
8221        let mut mint_account =
8222            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
8223        let account_key = Address::new_unique();
8224        let mut account_account = SolanaAccount::new(
8225            account_minimum_balance(),
8226            Account::get_packed_len(),
8227            &program_id,
8228        );
8229        let account2_key = Address::new_unique();
8230        let mut account2_account = SolanaAccount::new(
8231            account_minimum_balance() + 42,
8232            Account::get_packed_len(),
8233            &program_id,
8234        );
8235        let account3_key = Address::new_unique();
8236        let mut account3_account = SolanaAccount::new(
8237            account_minimum_balance(),
8238            Account::get_packed_len(),
8239            &program_id,
8240        );
8241        let owner_key = Address::new_unique();
8242        let mut owner_account = SolanaAccount::default();
8243        let owner2_key = Address::new_unique();
8244        let mut owner2_account = SolanaAccount::default();
8245        let mut rent_sysvar = rent_sysvar();
8246
8247        // uninitialized
8248        assert_eq!(
8249            Err(ProgramError::UninitializedAccount),
8250            do_process_instruction(
8251                close_account(&program_id, &account_key, &account3_key, &owner2_key, &[]).unwrap(),
8252                vec![
8253                    &mut account_account,
8254                    &mut account3_account,
8255                    &mut owner2_account,
8256                ],
8257            )
8258        );
8259
8260        // initialize and mint to non-native account
8261        do_process_instruction(
8262            initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
8263            vec![&mut mint_account, &mut rent_sysvar],
8264        )
8265        .unwrap();
8266        do_process_instruction(
8267            initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
8268            vec![
8269                &mut account_account,
8270                &mut mint_account,
8271                &mut owner_account,
8272                &mut rent_sysvar,
8273            ],
8274        )
8275        .unwrap();
8276        do_process_instruction(
8277            mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 42).unwrap(),
8278            vec![
8279                &mut mint_account,
8280                &mut account_account,
8281                &mut owner_account,
8282                &mut rent_sysvar,
8283            ],
8284        )
8285        .unwrap();
8286        let account = Account::unpack_unchecked(&account_account.data).unwrap();
8287        assert_eq!(account.amount, 42);
8288
8289        // initialize native account
8290        do_process_instruction(
8291            initialize_account(
8292                &program_id,
8293                &account2_key,
8294                &crate::native_mint::id(),
8295                &owner_key,
8296            )
8297            .unwrap(),
8298            vec![
8299                &mut account2_account,
8300                &mut mint_account,
8301                &mut owner_account,
8302                &mut rent_sysvar,
8303            ],
8304        )
8305        .unwrap();
8306        let account = Account::unpack_unchecked(&account2_account.data).unwrap();
8307        assert!(account.is_native());
8308        assert_eq!(account.amount, 42);
8309
8310        // close non-native account with balance
8311        assert_eq!(
8312            Err(TokenError::NonNativeHasBalance.into()),
8313            do_process_instruction(
8314                close_account(&program_id, &account_key, &account3_key, &owner_key, &[]).unwrap(),
8315                vec![
8316                    &mut account_account,
8317                    &mut account3_account,
8318                    &mut owner_account,
8319                ],
8320            )
8321        );
8322        assert_eq!(account_account.lamports, account_minimum_balance());
8323
8324        // empty account
8325        do_process_instruction(
8326            burn(&program_id, &account_key, &mint_key, &owner_key, &[], 42).unwrap(),
8327            vec![&mut account_account, &mut mint_account, &mut owner_account],
8328        )
8329        .unwrap();
8330
8331        // wrong owner
8332        assert_eq!(
8333            Err(TokenError::OwnerMismatch.into()),
8334            do_process_instruction(
8335                close_account(&program_id, &account_key, &account3_key, &owner2_key, &[]).unwrap(),
8336                vec![
8337                    &mut account_account,
8338                    &mut account3_account,
8339                    &mut owner2_account,
8340                ],
8341            )
8342        );
8343
8344        // close account
8345        do_process_instruction(
8346            close_account(&program_id, &account_key, &account3_key, &owner_key, &[]).unwrap(),
8347            vec![
8348                &mut account_account,
8349                &mut account3_account,
8350                &mut owner_account,
8351            ],
8352        )
8353        .unwrap();
8354        assert_eq!(account_account.lamports, 0);
8355        assert_eq!(account3_account.lamports, 2 * account_minimum_balance());
8356        let account = Account::unpack_unchecked(&account_account.data).unwrap();
8357        assert_eq!(account.amount, 0);
8358
8359        // fund and initialize new non-native account to test close authority
8360        let account_key = Address::new_unique();
8361        let mut account_account = SolanaAccount::new(
8362            account_minimum_balance(),
8363            Account::get_packed_len(),
8364            &program_id,
8365        );
8366        let owner2_key = Address::new_unique();
8367        let mut owner2_account = SolanaAccount::new(
8368            account_minimum_balance(),
8369            Account::get_packed_len(),
8370            &program_id,
8371        );
8372        do_process_instruction(
8373            initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
8374            vec![
8375                &mut account_account,
8376                &mut mint_account,
8377                &mut owner_account,
8378                &mut rent_sysvar,
8379            ],
8380        )
8381        .unwrap();
8382        account_account.lamports = 2;
8383
8384        do_process_instruction(
8385            set_authority(
8386                &program_id,
8387                &account_key,
8388                Some(&owner2_key),
8389                AuthorityType::CloseAccount,
8390                &owner_key,
8391                &[],
8392            )
8393            .unwrap(),
8394            vec![&mut account_account, &mut owner_account],
8395        )
8396        .unwrap();
8397
8398        // account owner cannot authorize close if close_authority is set
8399        assert_eq!(
8400            Err(TokenError::OwnerMismatch.into()),
8401            do_process_instruction(
8402                close_account(&program_id, &account_key, &account3_key, &owner_key, &[]).unwrap(),
8403                vec![
8404                    &mut account_account,
8405                    &mut account3_account,
8406                    &mut owner_account,
8407                ],
8408            )
8409        );
8410
8411        // close non-native account with close_authority
8412        do_process_instruction(
8413            close_account(&program_id, &account_key, &account3_key, &owner2_key, &[]).unwrap(),
8414            vec![
8415                &mut account_account,
8416                &mut account3_account,
8417                &mut owner2_account,
8418            ],
8419        )
8420        .unwrap();
8421        assert_eq!(account_account.lamports, 0);
8422        assert_eq!(account3_account.lamports, 2 * account_minimum_balance() + 2);
8423        let account = Account::unpack_unchecked(&account_account.data).unwrap();
8424        assert_eq!(account.amount, 0);
8425
8426        // close native account
8427        do_process_instruction(
8428            close_account(&program_id, &account2_key, &account3_key, &owner_key, &[]).unwrap(),
8429            vec![
8430                &mut account2_account,
8431                &mut account3_account,
8432                &mut owner_account,
8433            ],
8434        )
8435        .unwrap();
8436        assert_eq!(account2_account.data, [0u8; Account::LEN]);
8437        assert_eq!(
8438            account3_account.lamports,
8439            3 * account_minimum_balance() + 2 + 42
8440        );
8441    }
8442
8443    #[test]
8444    fn test_native_token() {
8445        let program_id = crate::id();
8446        let mut mint_account = native_mint();
8447        let account_key = Address::new_unique();
8448        let mut account_account = SolanaAccount::new(
8449            account_minimum_balance() + 40,
8450            Account::get_packed_len(),
8451            &program_id,
8452        );
8453        let account2_key = Address::new_unique();
8454        let mut account2_account = SolanaAccount::new(
8455            account_minimum_balance(),
8456            Account::get_packed_len(),
8457            &program_id,
8458        );
8459        let account3_key = Address::new_unique();
8460        let mut account3_account = SolanaAccount::new(account_minimum_balance(), 0, &program_id);
8461        let owner_key = Address::new_unique();
8462        let mut owner_account = SolanaAccount::default();
8463        let owner2_key = Address::new_unique();
8464        let mut owner2_account = SolanaAccount::default();
8465        let owner3_key = Address::new_unique();
8466        let mut rent_sysvar = rent_sysvar();
8467
8468        // initialize native account
8469        do_process_instruction(
8470            initialize_account(
8471                &program_id,
8472                &account_key,
8473                &crate::native_mint::id(),
8474                &owner_key,
8475            )
8476            .unwrap(),
8477            vec![
8478                &mut account_account,
8479                &mut mint_account,
8480                &mut owner_account,
8481                &mut rent_sysvar,
8482            ],
8483        )
8484        .unwrap();
8485        let account = Account::unpack_unchecked(&account_account.data).unwrap();
8486        assert!(account.is_native());
8487        assert_eq!(account.amount, 40);
8488
8489        // initialize native account
8490        do_process_instruction(
8491            initialize_account(
8492                &program_id,
8493                &account2_key,
8494                &crate::native_mint::id(),
8495                &owner_key,
8496            )
8497            .unwrap(),
8498            vec![
8499                &mut account2_account,
8500                &mut mint_account,
8501                &mut owner_account,
8502                &mut rent_sysvar,
8503            ],
8504        )
8505        .unwrap();
8506        let account = Account::unpack_unchecked(&account2_account.data).unwrap();
8507        assert!(account.is_native());
8508        assert_eq!(account.amount, 0);
8509
8510        // mint_to unsupported
8511        assert_eq!(
8512            Err(TokenError::NativeNotSupported.into()),
8513            do_process_instruction(
8514                mint_to(
8515                    &program_id,
8516                    &crate::native_mint::id(),
8517                    &account_key,
8518                    &owner_key,
8519                    &[],
8520                    42
8521                )
8522                .unwrap(),
8523                vec![&mut mint_account, &mut account_account, &mut owner_account],
8524            )
8525        );
8526
8527        // burn unsupported
8528        let bogus_mint_key = Address::new_unique();
8529        let mut bogus_mint_account =
8530            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
8531        do_process_instruction(
8532            initialize_mint(&program_id, &bogus_mint_key, &owner_key, None, 2).unwrap(),
8533            vec![&mut bogus_mint_account, &mut rent_sysvar],
8534        )
8535        .unwrap();
8536
8537        assert_eq!(
8538            Err(TokenError::NativeNotSupported.into()),
8539            do_process_instruction(
8540                burn(
8541                    &program_id,
8542                    &account_key,
8543                    &bogus_mint_key,
8544                    &owner_key,
8545                    &[],
8546                    42
8547                )
8548                .unwrap(),
8549                vec![
8550                    &mut account_account,
8551                    &mut bogus_mint_account,
8552                    &mut owner_account
8553                ],
8554            )
8555        );
8556
8557        // ensure can't transfer below rent-exempt reserve
8558        assert_eq!(
8559            Err(TokenError::InsufficientFunds.into()),
8560            do_process_instruction(
8561                #[allow(deprecated)]
8562                transfer(
8563                    &program_id,
8564                    &account_key,
8565                    &account2_key,
8566                    &owner_key,
8567                    &[],
8568                    50,
8569                )
8570                .unwrap(),
8571                vec![
8572                    &mut account_account,
8573                    &mut account2_account,
8574                    &mut owner_account,
8575                ],
8576            )
8577        );
8578
8579        // transfer between native accounts
8580        do_process_instruction(
8581            #[allow(deprecated)]
8582            transfer(
8583                &program_id,
8584                &account_key,
8585                &account2_key,
8586                &owner_key,
8587                &[],
8588                40,
8589            )
8590            .unwrap(),
8591            vec![
8592                &mut account_account,
8593                &mut account2_account,
8594                &mut owner_account,
8595            ],
8596        )
8597        .unwrap();
8598        assert_eq!(account_account.lamports, account_minimum_balance());
8599        let account = Account::unpack_unchecked(&account_account.data).unwrap();
8600        assert!(account.is_native());
8601        assert_eq!(account.amount, 0);
8602        assert_eq!(account2_account.lamports, account_minimum_balance() + 40);
8603        let account = Account::unpack_unchecked(&account2_account.data).unwrap();
8604        assert!(account.is_native());
8605        assert_eq!(account.amount, 40);
8606
8607        // set close authority
8608        do_process_instruction(
8609            set_authority(
8610                &program_id,
8611                &account_key,
8612                Some(&owner3_key),
8613                AuthorityType::CloseAccount,
8614                &owner_key,
8615                &[],
8616            )
8617            .unwrap(),
8618            vec![&mut account_account, &mut owner_account],
8619        )
8620        .unwrap();
8621        let account = Account::unpack_unchecked(&account_account.data).unwrap();
8622        assert_eq!(account.close_authority, COption::Some(owner3_key));
8623
8624        // set new account owner
8625        do_process_instruction(
8626            set_authority(
8627                &program_id,
8628                &account_key,
8629                Some(&owner2_key),
8630                AuthorityType::AccountOwner,
8631                &owner_key,
8632                &[],
8633            )
8634            .unwrap(),
8635            vec![&mut account_account, &mut owner_account],
8636        )
8637        .unwrap();
8638
8639        // close authority cleared
8640        let account = Account::unpack_unchecked(&account_account.data).unwrap();
8641        assert_eq!(account.close_authority, COption::None);
8642
8643        // close native account
8644        do_process_instruction(
8645            close_account(&program_id, &account_key, &account3_key, &owner2_key, &[]).unwrap(),
8646            vec![
8647                &mut account_account,
8648                &mut account3_account,
8649                &mut owner2_account,
8650            ],
8651        )
8652        .unwrap();
8653        assert_eq!(account_account.lamports, 0);
8654        assert_eq!(account3_account.lamports, 2 * account_minimum_balance());
8655        assert_eq!(account_account.data, [0u8; Account::LEN]);
8656    }
8657
8658    #[test]
8659    fn test_overflow() {
8660        let program_id = crate::id();
8661        let account_key = Address::new_unique();
8662        let mut account_account = SolanaAccount::new(
8663            account_minimum_balance(),
8664            Account::get_packed_len(),
8665            &program_id,
8666        );
8667        let account2_key = Address::new_unique();
8668        let mut account2_account = SolanaAccount::new(
8669            account_minimum_balance(),
8670            Account::get_packed_len(),
8671            &program_id,
8672        );
8673        let owner_key = Address::new_unique();
8674        let mut owner_account = SolanaAccount::default();
8675        let owner2_key = Address::new_unique();
8676        let mut owner2_account = SolanaAccount::default();
8677        let mint_owner_key = Address::new_unique();
8678        let mut mint_owner_account = SolanaAccount::default();
8679        let mint_key = Address::new_unique();
8680        let mut mint_account =
8681            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
8682        let mut rent_sysvar = rent_sysvar();
8683
8684        // create new mint with owner
8685        do_process_instruction(
8686            initialize_mint(&program_id, &mint_key, &mint_owner_key, None, 2).unwrap(),
8687            vec![&mut mint_account, &mut rent_sysvar],
8688        )
8689        .unwrap();
8690
8691        // create an account
8692        do_process_instruction(
8693            initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
8694            vec![
8695                &mut account_account,
8696                &mut mint_account,
8697                &mut owner_account,
8698                &mut rent_sysvar,
8699            ],
8700        )
8701        .unwrap();
8702
8703        // create another account
8704        do_process_instruction(
8705            initialize_account(&program_id, &account2_key, &mint_key, &owner2_key).unwrap(),
8706            vec![
8707                &mut account2_account,
8708                &mut mint_account,
8709                &mut owner2_account,
8710                &mut rent_sysvar,
8711            ],
8712        )
8713        .unwrap();
8714
8715        // mint the max to an account
8716        do_process_instruction(
8717            mint_to(
8718                &program_id,
8719                &mint_key,
8720                &account_key,
8721                &mint_owner_key,
8722                &[],
8723                u64::MAX,
8724            )
8725            .unwrap(),
8726            vec![
8727                &mut mint_account,
8728                &mut account_account,
8729                &mut mint_owner_account,
8730            ],
8731        )
8732        .unwrap();
8733        let account = Account::unpack_unchecked(&account_account.data).unwrap();
8734        assert_eq!(account.amount, u64::MAX);
8735
8736        // attempt to mint one more to account
8737        assert_eq!(
8738            Err(TokenError::Overflow.into()),
8739            do_process_instruction(
8740                mint_to(
8741                    &program_id,
8742                    &mint_key,
8743                    &account_key,
8744                    &mint_owner_key,
8745                    &[],
8746                    1,
8747                )
8748                .unwrap(),
8749                vec![
8750                    &mut mint_account,
8751                    &mut account_account,
8752                    &mut mint_owner_account,
8753                ],
8754            )
8755        );
8756        let account = Account::unpack_unchecked(&account_account.data).unwrap();
8757        assert_eq!(account.amount, u64::MAX);
8758
8759        // attempt to mint one more to the other account
8760        assert_eq!(
8761            Err(TokenError::Overflow.into()),
8762            do_process_instruction(
8763                mint_to(
8764                    &program_id,
8765                    &mint_key,
8766                    &account2_key,
8767                    &mint_owner_key,
8768                    &[],
8769                    1,
8770                )
8771                .unwrap(),
8772                vec![
8773                    &mut mint_account,
8774                    &mut account2_account,
8775                    &mut mint_owner_account,
8776                ],
8777            )
8778        );
8779
8780        // burn some of the supply
8781        do_process_instruction(
8782            burn(&program_id, &account_key, &mint_key, &owner_key, &[], 100).unwrap(),
8783            vec![&mut account_account, &mut mint_account, &mut owner_account],
8784        )
8785        .unwrap();
8786        let account = Account::unpack_unchecked(&account_account.data).unwrap();
8787        assert_eq!(account.amount, u64::MAX - 100);
8788
8789        do_process_instruction(
8790            mint_to(
8791                &program_id,
8792                &mint_key,
8793                &account_key,
8794                &mint_owner_key,
8795                &[],
8796                100,
8797            )
8798            .unwrap(),
8799            vec![
8800                &mut mint_account,
8801                &mut account_account,
8802                &mut mint_owner_account,
8803            ],
8804        )
8805        .unwrap();
8806        let account = Account::unpack_unchecked(&account_account.data).unwrap();
8807        assert_eq!(account.amount, u64::MAX);
8808
8809        // manipulate account balance to attempt overflow transfer
8810        let mut account = Account::unpack_unchecked(&account2_account.data).unwrap();
8811        account.amount = 1;
8812        Account::pack(account, &mut account2_account.data).unwrap();
8813
8814        assert_eq!(
8815            Err(TokenError::Overflow.into()),
8816            do_process_instruction(
8817                #[allow(deprecated)]
8818                transfer(
8819                    &program_id,
8820                    &account2_key,
8821                    &account_key,
8822                    &owner2_key,
8823                    &[],
8824                    1,
8825                )
8826                .unwrap(),
8827                vec![
8828                    &mut account2_account,
8829                    &mut account_account,
8830                    &mut owner2_account,
8831                ],
8832            )
8833        );
8834    }
8835
8836    #[test]
8837    fn test_frozen() {
8838        let program_id = crate::id();
8839        let account_key = Address::new_unique();
8840        let mut account_account = SolanaAccount::new(
8841            account_minimum_balance(),
8842            Account::get_packed_len(),
8843            &program_id,
8844        );
8845        let account2_key = Address::new_unique();
8846        let mut account2_account = SolanaAccount::new(
8847            account_minimum_balance(),
8848            Account::get_packed_len(),
8849            &program_id,
8850        );
8851        let owner_key = Address::new_unique();
8852        let mut owner_account = SolanaAccount::default();
8853        let mint_key = Address::new_unique();
8854        let mut mint_account =
8855            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
8856        let mut rent_sysvar = rent_sysvar();
8857
8858        // create new mint and fund first account
8859        do_process_instruction(
8860            initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
8861            vec![&mut mint_account, &mut rent_sysvar],
8862        )
8863        .unwrap();
8864
8865        // create account
8866        do_process_instruction(
8867            initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
8868            vec![
8869                &mut account_account,
8870                &mut mint_account,
8871                &mut owner_account,
8872                &mut rent_sysvar,
8873            ],
8874        )
8875        .unwrap();
8876
8877        // create another account
8878        do_process_instruction(
8879            initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(),
8880            vec![
8881                &mut account2_account,
8882                &mut mint_account,
8883                &mut owner_account,
8884                &mut rent_sysvar,
8885            ],
8886        )
8887        .unwrap();
8888
8889        // fund first account
8890        do_process_instruction(
8891            mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(),
8892            vec![&mut mint_account, &mut account_account, &mut owner_account],
8893        )
8894        .unwrap();
8895
8896        // no transfer if either account is frozen
8897        let mut account = Account::unpack_unchecked(&account2_account.data).unwrap();
8898        account.state = AccountState::Frozen;
8899        Account::pack(account, &mut account2_account.data).unwrap();
8900        assert_eq!(
8901            Err(TokenError::AccountFrozen.into()),
8902            do_process_instruction(
8903                #[allow(deprecated)]
8904                transfer(
8905                    &program_id,
8906                    &account_key,
8907                    &account2_key,
8908                    &owner_key,
8909                    &[],
8910                    500,
8911                )
8912                .unwrap(),
8913                vec![
8914                    &mut account_account,
8915                    &mut account2_account,
8916                    &mut owner_account,
8917                ],
8918            )
8919        );
8920
8921        let mut account = Account::unpack_unchecked(&account_account.data).unwrap();
8922        account.state = AccountState::Initialized;
8923        Account::pack(account, &mut account_account.data).unwrap();
8924        let mut account = Account::unpack_unchecked(&account2_account.data).unwrap();
8925        account.state = AccountState::Frozen;
8926        Account::pack(account, &mut account2_account.data).unwrap();
8927        assert_eq!(
8928            Err(TokenError::AccountFrozen.into()),
8929            do_process_instruction(
8930                #[allow(deprecated)]
8931                transfer(
8932                    &program_id,
8933                    &account_key,
8934                    &account2_key,
8935                    &owner_key,
8936                    &[],
8937                    500,
8938                )
8939                .unwrap(),
8940                vec![
8941                    &mut account_account,
8942                    &mut account2_account,
8943                    &mut owner_account,
8944                ],
8945            )
8946        );
8947
8948        // no approve if account is frozen
8949        let mut account = Account::unpack_unchecked(&account_account.data).unwrap();
8950        account.state = AccountState::Frozen;
8951        Account::pack(account, &mut account_account.data).unwrap();
8952        let delegate_key = Address::new_unique();
8953        let mut delegate_account = SolanaAccount::default();
8954        assert_eq!(
8955            Err(TokenError::AccountFrozen.into()),
8956            do_process_instruction(
8957                approve(
8958                    &program_id,
8959                    &account_key,
8960                    &delegate_key,
8961                    &owner_key,
8962                    &[],
8963                    100
8964                )
8965                .unwrap(),
8966                vec![
8967                    &mut account_account,
8968                    &mut delegate_account,
8969                    &mut owner_account,
8970                ],
8971            )
8972        );
8973
8974        // no revoke if account is frozen
8975        let mut account = Account::unpack_unchecked(&account_account.data).unwrap();
8976        account.delegate = COption::Some(delegate_key);
8977        account.delegated_amount = 100;
8978        Account::pack(account, &mut account_account.data).unwrap();
8979        assert_eq!(
8980            Err(TokenError::AccountFrozen.into()),
8981            do_process_instruction(
8982                revoke(&program_id, &account_key, &owner_key, &[]).unwrap(),
8983                vec![&mut account_account, &mut owner_account],
8984            )
8985        );
8986
8987        // no set authority if account is frozen
8988        let new_owner_key = Address::new_unique();
8989        assert_eq!(
8990            Err(TokenError::AccountFrozen.into()),
8991            do_process_instruction(
8992                set_authority(
8993                    &program_id,
8994                    &account_key,
8995                    Some(&new_owner_key),
8996                    AuthorityType::AccountOwner,
8997                    &owner_key,
8998                    &[]
8999                )
9000                .unwrap(),
9001                vec![&mut account_account, &mut owner_account,],
9002            )
9003        );
9004
9005        // no mint_to if destination account is frozen
9006        assert_eq!(
9007            Err(TokenError::AccountFrozen.into()),
9008            do_process_instruction(
9009                mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 100).unwrap(),
9010                vec![&mut mint_account, &mut account_account, &mut owner_account,],
9011            )
9012        );
9013
9014        // no burn if account is frozen
9015        assert_eq!(
9016            Err(TokenError::AccountFrozen.into()),
9017            do_process_instruction(
9018                burn(&program_id, &account_key, &mint_key, &owner_key, &[], 100).unwrap(),
9019                vec![&mut account_account, &mut mint_account, &mut owner_account],
9020            )
9021        );
9022    }
9023
9024    #[test]
9025    fn test_freeze_thaw_dups() {
9026        let program_id = crate::id();
9027        let account1_key = Address::new_unique();
9028        let mut account1_account = SolanaAccount::new(
9029            account_minimum_balance(),
9030            Account::get_packed_len(),
9031            &program_id,
9032        );
9033        let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into();
9034        let owner_key = Address::new_unique();
9035        let mint_key = Address::new_unique();
9036        let mut mint_account =
9037            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
9038        let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into();
9039        let rent_key = rent::id();
9040        let mut rent_sysvar = rent_sysvar();
9041        let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into();
9042
9043        // create mint
9044        do_process_instruction_dups(
9045            initialize_mint(&program_id, &mint_key, &owner_key, Some(&account1_key), 2).unwrap(),
9046            vec![mint_info.clone(), rent_info.clone()],
9047        )
9048        .unwrap();
9049
9050        // create account
9051        do_process_instruction_dups(
9052            initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(),
9053            vec![
9054                account1_info.clone(),
9055                mint_info.clone(),
9056                account1_info.clone(),
9057                rent_info.clone(),
9058            ],
9059        )
9060        .unwrap();
9061
9062        // freeze where mint freeze_authority is account
9063        do_process_instruction_dups(
9064            freeze_account(&program_id, &account1_key, &mint_key, &account1_key, &[]).unwrap(),
9065            vec![
9066                account1_info.clone(),
9067                mint_info.clone(),
9068                account1_info.clone(),
9069            ],
9070        )
9071        .unwrap();
9072
9073        // thaw where mint freeze_authority is account
9074        let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap();
9075        account.state = AccountState::Frozen;
9076        Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap();
9077        do_process_instruction_dups(
9078            thaw_account(&program_id, &account1_key, &mint_key, &account1_key, &[]).unwrap(),
9079            vec![
9080                account1_info.clone(),
9081                mint_info.clone(),
9082                account1_info.clone(),
9083            ],
9084        )
9085        .unwrap();
9086    }
9087
9088    #[test]
9089    fn test_freeze_account() {
9090        let program_id = crate::id();
9091        let account_key = Address::new_unique();
9092        let mut account_account = SolanaAccount::new(
9093            account_minimum_balance(),
9094            Account::get_packed_len(),
9095            &program_id,
9096        );
9097        let account_owner_key = Address::new_unique();
9098        let mut account_owner_account = SolanaAccount::default();
9099        let owner_key = Address::new_unique();
9100        let mut owner_account = SolanaAccount::default();
9101        let owner2_key = Address::new_unique();
9102        let mut owner2_account = SolanaAccount::default();
9103        let mint_key = Address::new_unique();
9104        let mut mint_account =
9105            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
9106        let mut rent_sysvar = rent_sysvar();
9107
9108        // create new mint with owner different from account owner
9109        do_process_instruction(
9110            initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
9111            vec![&mut mint_account, &mut rent_sysvar],
9112        )
9113        .unwrap();
9114
9115        // create account
9116        do_process_instruction(
9117            initialize_account(&program_id, &account_key, &mint_key, &account_owner_key).unwrap(),
9118            vec![
9119                &mut account_account,
9120                &mut mint_account,
9121                &mut account_owner_account,
9122                &mut rent_sysvar,
9123            ],
9124        )
9125        .unwrap();
9126
9127        // mint to account
9128        do_process_instruction(
9129            mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(),
9130            vec![&mut mint_account, &mut account_account, &mut owner_account],
9131        )
9132        .unwrap();
9133
9134        // mint cannot freeze
9135        assert_eq!(
9136            Err(TokenError::MintCannotFreeze.into()),
9137            do_process_instruction(
9138                freeze_account(&program_id, &account_key, &mint_key, &owner_key, &[]).unwrap(),
9139                vec![&mut account_account, &mut mint_account, &mut owner_account],
9140            )
9141        );
9142
9143        // missing freeze_authority
9144        let mut mint = Mint::unpack_unchecked(&mint_account.data).unwrap();
9145        mint.freeze_authority = COption::Some(owner_key);
9146        Mint::pack(mint, &mut mint_account.data).unwrap();
9147        assert_eq!(
9148            Err(TokenError::OwnerMismatch.into()),
9149            do_process_instruction(
9150                freeze_account(&program_id, &account_key, &mint_key, &owner2_key, &[]).unwrap(),
9151                vec![&mut account_account, &mut mint_account, &mut owner2_account],
9152            )
9153        );
9154
9155        // check explicit thaw
9156        assert_eq!(
9157            Err(TokenError::InvalidState.into()),
9158            do_process_instruction(
9159                thaw_account(&program_id, &account_key, &mint_key, &owner2_key, &[]).unwrap(),
9160                vec![&mut account_account, &mut mint_account, &mut owner2_account],
9161            )
9162        );
9163
9164        // freeze
9165        do_process_instruction(
9166            freeze_account(&program_id, &account_key, &mint_key, &owner_key, &[]).unwrap(),
9167            vec![&mut account_account, &mut mint_account, &mut owner_account],
9168        )
9169        .unwrap();
9170        let account = Account::unpack_unchecked(&account_account.data).unwrap();
9171        assert_eq!(account.state, AccountState::Frozen);
9172
9173        // check explicit freeze
9174        assert_eq!(
9175            Err(TokenError::InvalidState.into()),
9176            do_process_instruction(
9177                freeze_account(&program_id, &account_key, &mint_key, &owner_key, &[]).unwrap(),
9178                vec![&mut account_account, &mut mint_account, &mut owner_account],
9179            )
9180        );
9181
9182        // check thaw authority
9183        assert_eq!(
9184            Err(TokenError::OwnerMismatch.into()),
9185            do_process_instruction(
9186                thaw_account(&program_id, &account_key, &mint_key, &owner2_key, &[]).unwrap(),
9187                vec![&mut account_account, &mut mint_account, &mut owner2_account],
9188            )
9189        );
9190
9191        // thaw
9192        do_process_instruction(
9193            thaw_account(&program_id, &account_key, &mint_key, &owner_key, &[]).unwrap(),
9194            vec![&mut account_account, &mut mint_account, &mut owner_account],
9195        )
9196        .unwrap();
9197        let account = Account::unpack_unchecked(&account_account.data).unwrap();
9198        assert_eq!(account.state, AccountState::Initialized);
9199    }
9200
9201    #[test]
9202    fn test_initialize_account2_and_3() {
9203        let program_id = crate::id();
9204        let account_key = Address::new_unique();
9205        let mut account_account = SolanaAccount::new(
9206            account_minimum_balance(),
9207            Account::get_packed_len(),
9208            &program_id,
9209        );
9210        let mut account2_account = SolanaAccount::new(
9211            account_minimum_balance(),
9212            Account::get_packed_len(),
9213            &program_id,
9214        );
9215        let mut account3_account = SolanaAccount::new(
9216            account_minimum_balance(),
9217            Account::get_packed_len(),
9218            &program_id,
9219        );
9220        let owner_key = Address::new_unique();
9221        let mut owner_account = SolanaAccount::default();
9222        let mint_key = Address::new_unique();
9223        let mut mint_account =
9224            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
9225        let mut rent_sysvar = rent_sysvar();
9226
9227        // create mint
9228        do_process_instruction(
9229            initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
9230            vec![&mut mint_account, &mut rent_sysvar],
9231        )
9232        .unwrap();
9233
9234        do_process_instruction(
9235            initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
9236            vec![
9237                &mut account_account,
9238                &mut mint_account,
9239                &mut owner_account,
9240                &mut rent_sysvar,
9241            ],
9242        )
9243        .unwrap();
9244
9245        do_process_instruction(
9246            initialize_account2(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
9247            vec![&mut account2_account, &mut mint_account, &mut rent_sysvar],
9248        )
9249        .unwrap();
9250
9251        assert_eq!(account_account, account2_account);
9252
9253        do_process_instruction(
9254            initialize_account3(&program_id, &account_key, &mint_key, &owner_key).unwrap(),
9255            vec![&mut account3_account, &mut mint_account],
9256        )
9257        .unwrap();
9258
9259        assert_eq!(account_account, account3_account);
9260    }
9261
9262    #[test]
9263    fn initialize_account_on_non_transferable_mint() {
9264        let program_id = crate::id();
9265        let account = Address::new_unique();
9266        let account_len = ExtensionType::try_calculate_account_len::<Mint>(&[
9267            ExtensionType::NonTransferableAccount,
9268        ])
9269        .unwrap();
9270        let mut account_without_enough_length = SolanaAccount::new(
9271            Rent::default().minimum_balance(account_len),
9272            account_len,
9273            &program_id,
9274        );
9275
9276        let account2 = Address::new_unique();
9277        let account2_len = ExtensionType::try_calculate_account_len::<Mint>(&[
9278            ExtensionType::NonTransferableAccount,
9279            ExtensionType::ImmutableOwner,
9280        ])
9281        .unwrap();
9282        let mut account_with_enough_length = SolanaAccount::new(
9283            Rent::default().minimum_balance(account2_len),
9284            account2_len,
9285            &program_id,
9286        );
9287
9288        let owner_key = Address::new_unique();
9289        let mut owner_account = SolanaAccount::default();
9290        let mint_key = Address::new_unique();
9291        let mint_len =
9292            ExtensionType::try_calculate_account_len::<Mint>(&[ExtensionType::NonTransferable])
9293                .unwrap();
9294        let mut mint_account = SolanaAccount::new(
9295            Rent::default().minimum_balance(mint_len),
9296            mint_len,
9297            &program_id,
9298        );
9299        let mut rent_sysvar = rent_sysvar();
9300
9301        // create a non-transferable mint
9302        assert_eq!(
9303            Ok(()),
9304            do_process_instruction(
9305                initialize_non_transferable_mint(&program_id, &mint_key).unwrap(),
9306                vec![&mut mint_account],
9307            )
9308        );
9309        assert_eq!(
9310            Ok(()),
9311            do_process_instruction(
9312                initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
9313                vec![&mut mint_account, &mut rent_sysvar]
9314            )
9315        );
9316
9317        //fail when account space is not enough for adding the immutable ownership
9318        // extension
9319        assert_eq!(
9320            Err(ProgramError::InvalidAccountData),
9321            do_process_instruction(
9322                initialize_account(&program_id, &account, &mint_key, &owner_key).unwrap(),
9323                vec![
9324                    &mut account_without_enough_length,
9325                    &mut mint_account,
9326                    &mut owner_account,
9327                    &mut rent_sysvar,
9328                ]
9329            )
9330        );
9331
9332        //success to initialize an account with enough data space
9333        assert_eq!(
9334            Ok(()),
9335            do_process_instruction(
9336                initialize_account(&program_id, &account2, &mint_key, &owner_key).unwrap(),
9337                vec![
9338                    &mut account_with_enough_length,
9339                    &mut mint_account,
9340                    &mut owner_account,
9341                    &mut rent_sysvar,
9342                ]
9343            )
9344        );
9345    }
9346
9347    #[test]
9348    fn test_sync_native() {
9349        let program_id = crate::id();
9350        let mint_key = Address::new_unique();
9351        let mut mint_account =
9352            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
9353        let native_account_key = Address::new_unique();
9354        let lamports = 40;
9355        let mut native_account = SolanaAccount::new(
9356            account_minimum_balance() + lamports,
9357            Account::get_packed_len(),
9358            &program_id,
9359        );
9360        let non_native_account_key = Address::new_unique();
9361        let mut non_native_account = SolanaAccount::new(
9362            account_minimum_balance() + 50,
9363            Account::get_packed_len(),
9364            &program_id,
9365        );
9366
9367        let owner_key = Address::new_unique();
9368        let mut owner_account = SolanaAccount::default();
9369        let mut rent_sysvar = rent_sysvar();
9370
9371        // initialize non-native mint
9372        do_process_instruction(
9373            initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
9374            vec![&mut mint_account, &mut rent_sysvar],
9375        )
9376        .unwrap();
9377
9378        // initialize non-native account
9379        do_process_instruction(
9380            initialize_account(&program_id, &non_native_account_key, &mint_key, &owner_key)
9381                .unwrap(),
9382            vec![
9383                &mut non_native_account,
9384                &mut mint_account,
9385                &mut owner_account,
9386                &mut rent_sysvar,
9387            ],
9388        )
9389        .unwrap();
9390
9391        let account = Account::unpack_unchecked(&non_native_account.data).unwrap();
9392        assert!(!account.is_native());
9393        assert_eq!(account.amount, 0);
9394
9395        // fail sync non-native
9396        assert_eq!(
9397            Err(TokenError::NonNativeNotSupported.into()),
9398            do_process_instruction(
9399                sync_native(&program_id, &non_native_account_key,).unwrap(),
9400                vec![&mut non_native_account],
9401            )
9402        );
9403
9404        // fail sync uninitialized
9405        assert_eq!(
9406            Err(ProgramError::UninitializedAccount),
9407            do_process_instruction(
9408                sync_native(&program_id, &native_account_key,).unwrap(),
9409                vec![&mut native_account],
9410            )
9411        );
9412
9413        // wrap native account
9414        do_process_instruction(
9415            initialize_account(
9416                &program_id,
9417                &native_account_key,
9418                &crate::native_mint::id(),
9419                &owner_key,
9420            )
9421            .unwrap(),
9422            vec![
9423                &mut native_account,
9424                &mut mint_account,
9425                &mut owner_account,
9426                &mut rent_sysvar,
9427            ],
9428        )
9429        .unwrap();
9430
9431        // fail sync, not owned by program
9432        let not_program_id = Address::new_unique();
9433        native_account.owner = not_program_id;
9434        assert_eq!(
9435            Err(ProgramError::IncorrectProgramId),
9436            do_process_instruction(
9437                sync_native(&program_id, &native_account_key,).unwrap(),
9438                vec![&mut native_account],
9439            )
9440        );
9441        native_account.owner = program_id;
9442
9443        let account = Account::unpack_unchecked(&native_account.data).unwrap();
9444        assert!(account.is_native());
9445        assert_eq!(account.amount, lamports);
9446
9447        // sync, no change
9448        do_process_instruction(
9449            sync_native(&program_id, &native_account_key).unwrap(),
9450            vec![&mut native_account],
9451        )
9452        .unwrap();
9453        let account = Account::unpack_unchecked(&native_account.data).unwrap();
9454        assert_eq!(account.amount, lamports);
9455
9456        // transfer sol
9457        let new_lamports = lamports + 50;
9458        native_account.lamports = account_minimum_balance() + new_lamports;
9459
9460        // success sync
9461        do_process_instruction(
9462            sync_native(&program_id, &native_account_key).unwrap(),
9463            vec![&mut native_account],
9464        )
9465        .unwrap();
9466        let account = Account::unpack_unchecked(&native_account.data).unwrap();
9467        assert_eq!(account.amount, new_lamports);
9468
9469        // reduce sol
9470        native_account.lamports -= 1;
9471
9472        // succeed sync with reduced value
9473        do_process_instruction(
9474            sync_native(&program_id, &native_account_key).unwrap(),
9475            vec![&mut native_account],
9476        )
9477        .unwrap();
9478        let account = Account::unpack_unchecked(&native_account.data).unwrap();
9479        assert_eq!(account.amount, new_lamports - 1);
9480    }
9481
9482    #[test]
9483    #[serial]
9484    fn test_get_account_data_size() {
9485        // see integration tests for return-data validity
9486        let program_id = crate::id();
9487        let owner_key = Address::new_unique();
9488        let mut owner_account = SolanaAccount::default();
9489        let mut rent_sysvar = rent_sysvar();
9490
9491        // Base mint
9492        let mut mint_account =
9493            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
9494        let mint_key = Address::new_unique();
9495        do_process_instruction(
9496            initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
9497            vec![&mut mint_account, &mut rent_sysvar],
9498        )
9499        .unwrap();
9500
9501        set_expected_data(
9502            ExtensionType::try_calculate_account_len::<Account>(&[])
9503                .unwrap()
9504                .to_le_bytes()
9505                .to_vec(),
9506        );
9507        do_process_instruction(
9508            get_account_data_size(&program_id, &mint_key, &[]).unwrap(),
9509            vec![&mut mint_account],
9510        )
9511        .unwrap();
9512
9513        set_expected_data(
9514            ExtensionType::try_calculate_account_len::<Account>(&[
9515                ExtensionType::TransferFeeAmount,
9516            ])
9517            .unwrap()
9518            .to_le_bytes()
9519            .to_vec(),
9520        );
9521        do_process_instruction(
9522            get_account_data_size(
9523                &program_id,
9524                &mint_key,
9525                &[
9526                    ExtensionType::TransferFeeAmount,
9527                    ExtensionType::TransferFeeAmount, // Duplicate user input ignored...
9528                ],
9529            )
9530            .unwrap(),
9531            vec![&mut mint_account],
9532        )
9533        .unwrap();
9534
9535        // Native mint
9536        let mut mint_account = native_mint();
9537        set_expected_data(
9538            ExtensionType::try_calculate_account_len::<Account>(&[])
9539                .unwrap()
9540                .to_le_bytes()
9541                .to_vec(),
9542        );
9543        do_process_instruction(
9544            get_account_data_size(&program_id, &mint_key, &[]).unwrap(),
9545            vec![&mut mint_account],
9546        )
9547        .unwrap();
9548
9549        // Extended mint
9550        let mint_len =
9551            ExtensionType::try_calculate_account_len::<Mint>(&[ExtensionType::TransferFeeConfig])
9552                .unwrap();
9553        let mut extended_mint_account = SolanaAccount::new(
9554            Rent::default().minimum_balance(mint_len),
9555            mint_len,
9556            &program_id,
9557        );
9558        let extended_mint_key = Address::new_unique();
9559        do_process_instruction(
9560            initialize_transfer_fee_config(&program_id, &extended_mint_key, None, None, 10, 4242)
9561                .unwrap(),
9562            vec![&mut extended_mint_account],
9563        )
9564        .unwrap();
9565        do_process_instruction(
9566            initialize_mint(&program_id, &extended_mint_key, &owner_key, None, 2).unwrap(),
9567            vec![&mut extended_mint_account, &mut rent_sysvar],
9568        )
9569        .unwrap();
9570
9571        set_expected_data(
9572            ExtensionType::try_calculate_account_len::<Account>(&[
9573                ExtensionType::TransferFeeAmount,
9574            ])
9575            .unwrap()
9576            .to_le_bytes()
9577            .to_vec(),
9578        );
9579        do_process_instruction(
9580            get_account_data_size(&program_id, &mint_key, &[]).unwrap(),
9581            vec![&mut extended_mint_account],
9582        )
9583        .unwrap();
9584
9585        do_process_instruction(
9586            get_account_data_size(
9587                &program_id,
9588                &mint_key,
9589                // User extension that's also added by the mint ignored...
9590                &[ExtensionType::TransferFeeAmount],
9591            )
9592            .unwrap(),
9593            vec![&mut extended_mint_account],
9594        )
9595        .unwrap();
9596
9597        // Invalid mint
9598        let mut invalid_mint_account = SolanaAccount::new(
9599            account_minimum_balance(),
9600            Account::get_packed_len(),
9601            &program_id,
9602        );
9603        let invalid_mint_key = Address::new_unique();
9604        do_process_instruction(
9605            initialize_account(&program_id, &invalid_mint_key, &mint_key, &owner_key).unwrap(),
9606            vec![
9607                &mut invalid_mint_account,
9608                &mut mint_account,
9609                &mut owner_account,
9610                &mut rent_sysvar,
9611            ],
9612        )
9613        .unwrap();
9614
9615        assert_eq!(
9616            do_process_instruction(
9617                get_account_data_size(&program_id, &invalid_mint_key, &[]).unwrap(),
9618                vec![&mut invalid_mint_account],
9619            ),
9620            Err(TokenError::InvalidMint.into())
9621        );
9622
9623        // Invalid mint owner
9624        let invalid_program_id = Address::new_unique();
9625        let mut invalid_mint_account =
9626            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
9627        let invalid_mint_key = Address::new_unique();
9628        let mut instruction =
9629            initialize_mint(&program_id, &invalid_mint_key, &owner_key, None, 2).unwrap();
9630        instruction.program_id = invalid_program_id;
9631        do_process_instruction(
9632            instruction,
9633            vec![&mut invalid_mint_account, &mut rent_sysvar],
9634        )
9635        .unwrap();
9636
9637        invalid_mint_account.owner = invalid_program_id;
9638
9639        assert_eq!(
9640            do_process_instruction(
9641                get_account_data_size(&program_id, &invalid_mint_key, &[]).unwrap(),
9642                vec![&mut invalid_mint_account],
9643            ),
9644            Err(ProgramError::IncorrectProgramId)
9645        );
9646
9647        // Invalid Extension Type for mint and uninitialized account
9648        assert_eq!(
9649            do_process_instruction(
9650                get_account_data_size(&program_id, &mint_key, &[ExtensionType::Uninitialized])
9651                    .unwrap(),
9652                vec![&mut mint_account],
9653            ),
9654            Err(TokenError::ExtensionTypeMismatch.into())
9655        );
9656        assert_eq!(
9657            do_process_instruction(
9658                get_account_data_size(
9659                    &program_id,
9660                    &mint_key,
9661                    &[
9662                        ExtensionType::MemoTransfer,
9663                        ExtensionType::MintCloseAuthority
9664                    ]
9665                )
9666                .unwrap(),
9667                vec![&mut mint_account],
9668            ),
9669            Err(TokenError::ExtensionTypeMismatch.into())
9670        );
9671    }
9672
9673    #[test]
9674    #[serial]
9675    fn test_amount_to_ui_amount() {
9676        let program_id = crate::id();
9677        let owner_key = Address::new_unique();
9678        let mint_key = Address::new_unique();
9679        let mut mint_account =
9680            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
9681        let mut rent_sysvar = rent_sysvar();
9682
9683        // fail if an invalid mint is passed in
9684        assert_eq!(
9685            Err(TokenError::InvalidMint.into()),
9686            do_process_instruction(
9687                amount_to_ui_amount(&program_id, &mint_key, 110).unwrap(),
9688                vec![&mut mint_account],
9689            )
9690        );
9691
9692        // create mint
9693        do_process_instruction(
9694            initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
9695            vec![&mut mint_account, &mut rent_sysvar],
9696        )
9697        .unwrap();
9698
9699        set_expected_data("0.23".as_bytes().to_vec());
9700        do_process_instruction(
9701            amount_to_ui_amount(&program_id, &mint_key, 23).unwrap(),
9702            vec![&mut mint_account],
9703        )
9704        .unwrap();
9705
9706        set_expected_data("1.1".as_bytes().to_vec());
9707        do_process_instruction(
9708            amount_to_ui_amount(&program_id, &mint_key, 110).unwrap(),
9709            vec![&mut mint_account],
9710        )
9711        .unwrap();
9712
9713        set_expected_data("42".as_bytes().to_vec());
9714        do_process_instruction(
9715            amount_to_ui_amount(&program_id, &mint_key, 4200).unwrap(),
9716            vec![&mut mint_account],
9717        )
9718        .unwrap();
9719
9720        set_expected_data("0".as_bytes().to_vec());
9721        do_process_instruction(
9722            amount_to_ui_amount(&program_id, &mint_key, 0).unwrap(),
9723            vec![&mut mint_account],
9724        )
9725        .unwrap();
9726    }
9727
9728    #[test]
9729    #[serial]
9730    fn test_ui_amount_to_amount() {
9731        let program_id = crate::id();
9732        let owner_key = Address::new_unique();
9733        let mint_key = Address::new_unique();
9734        let mut mint_account =
9735            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
9736        let mut rent_sysvar = rent_sysvar();
9737
9738        // fail if an invalid mint is passed in
9739        assert_eq!(
9740            Err(TokenError::InvalidMint.into()),
9741            do_process_instruction(
9742                ui_amount_to_amount(&program_id, &mint_key, "1.1").unwrap(),
9743                vec![&mut mint_account],
9744            )
9745        );
9746
9747        // create mint
9748        do_process_instruction(
9749            initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
9750            vec![&mut mint_account, &mut rent_sysvar],
9751        )
9752        .unwrap();
9753
9754        set_expected_data(23u64.to_le_bytes().to_vec());
9755        do_process_instruction(
9756            ui_amount_to_amount(&program_id, &mint_key, "0.23").unwrap(),
9757            vec![&mut mint_account],
9758        )
9759        .unwrap();
9760
9761        set_expected_data(20u64.to_le_bytes().to_vec());
9762        do_process_instruction(
9763            ui_amount_to_amount(&program_id, &mint_key, "0.20").unwrap(),
9764            vec![&mut mint_account],
9765        )
9766        .unwrap();
9767
9768        set_expected_data(20u64.to_le_bytes().to_vec());
9769        do_process_instruction(
9770            ui_amount_to_amount(&program_id, &mint_key, "0.2000").unwrap(),
9771            vec![&mut mint_account],
9772        )
9773        .unwrap();
9774
9775        set_expected_data(20u64.to_le_bytes().to_vec());
9776        do_process_instruction(
9777            ui_amount_to_amount(&program_id, &mint_key, ".20").unwrap(),
9778            vec![&mut mint_account],
9779        )
9780        .unwrap();
9781
9782        set_expected_data(110u64.to_le_bytes().to_vec());
9783        do_process_instruction(
9784            ui_amount_to_amount(&program_id, &mint_key, "1.1").unwrap(),
9785            vec![&mut mint_account],
9786        )
9787        .unwrap();
9788
9789        set_expected_data(110u64.to_le_bytes().to_vec());
9790        do_process_instruction(
9791            ui_amount_to_amount(&program_id, &mint_key, "1.10").unwrap(),
9792            vec![&mut mint_account],
9793        )
9794        .unwrap();
9795
9796        set_expected_data(4200u64.to_le_bytes().to_vec());
9797        do_process_instruction(
9798            ui_amount_to_amount(&program_id, &mint_key, "42").unwrap(),
9799            vec![&mut mint_account],
9800        )
9801        .unwrap();
9802
9803        set_expected_data(4200u64.to_le_bytes().to_vec());
9804        do_process_instruction(
9805            ui_amount_to_amount(&program_id, &mint_key, "42.").unwrap(),
9806            vec![&mut mint_account],
9807        )
9808        .unwrap();
9809
9810        set_expected_data(0u64.to_le_bytes().to_vec());
9811        do_process_instruction(
9812            ui_amount_to_amount(&program_id, &mint_key, "0").unwrap(),
9813            vec![&mut mint_account],
9814        )
9815        .unwrap();
9816
9817        // fail if invalid ui_amount passed in
9818        assert_eq!(
9819            Err(ProgramError::InvalidArgument),
9820            do_process_instruction(
9821                ui_amount_to_amount(&program_id, &mint_key, "").unwrap(),
9822                vec![&mut mint_account],
9823            )
9824        );
9825        assert_eq!(
9826            Err(ProgramError::InvalidArgument),
9827            do_process_instruction(
9828                ui_amount_to_amount(&program_id, &mint_key, ".").unwrap(),
9829                vec![&mut mint_account],
9830            )
9831        );
9832        assert_eq!(
9833            Err(ProgramError::InvalidArgument),
9834            do_process_instruction(
9835                ui_amount_to_amount(&program_id, &mint_key, "0.111").unwrap(),
9836                vec![&mut mint_account],
9837            )
9838        );
9839        assert_eq!(
9840            Err(ProgramError::InvalidArgument),
9841            do_process_instruction(
9842                ui_amount_to_amount(&program_id, &mint_key, "0.t").unwrap(),
9843                vec![&mut mint_account],
9844            )
9845        );
9846    }
9847
9848    #[test]
9849    #[serial]
9850    fn test_withdraw_excess_lamports_from_multisig() {
9851        {
9852            use std::sync::Once;
9853            static ONCE: Once = Once::new();
9854
9855            ONCE.call_once(|| {
9856                solana_sysvar::program_stubs::set_syscall_stubs(Box::new(SyscallStubs {}));
9857            });
9858        }
9859        let program_id = crate::id();
9860
9861        let mut lamports = 0;
9862        let mut destination_data = vec![];
9863        let system_program_id = system_program::id();
9864        let destination_key = Address::new_unique();
9865        let destination_info = AccountInfo::new(
9866            &destination_key,
9867            true,
9868            false,
9869            &mut lamports,
9870            &mut destination_data,
9871            &system_program_id,
9872            false,
9873        );
9874
9875        let multisig_key = Address::new_unique();
9876        let mut multisig_account = SolanaAccount::new(0, Multisig::get_packed_len(), &program_id);
9877        let excess_lamports = 4_000_000_000_000;
9878        multisig_account.lamports = excess_lamports + multisig_minimum_balance();
9879        let mut signer_keys = [Address::default(); MAX_SIGNERS];
9880
9881        for signer_key in signer_keys.iter_mut().take(MAX_SIGNERS) {
9882            *signer_key = Address::new_unique();
9883        }
9884        let signer_refs: Vec<&Address> = signer_keys.iter().collect();
9885        let mut signer_lamports = 0;
9886        let mut signer_data = vec![];
9887        let mut signers: Vec<AccountInfo<'_>> = vec![
9888            AccountInfo::new(
9889                &destination_key,
9890                true,
9891                false,
9892                &mut signer_lamports,
9893                &mut signer_data,
9894                &program_id,
9895                false,
9896            );
9897            MAX_SIGNERS + 1
9898        ];
9899        for (signer, key) in signers.iter_mut().zip(&signer_keys) {
9900            signer.key = key;
9901        }
9902
9903        let mut multisig =
9904            Multisig::unpack_unchecked(&vec![0; Multisig::get_packed_len()]).unwrap();
9905        multisig.m = MAX_SIGNERS as u8;
9906        multisig.n = MAX_SIGNERS as u8;
9907        multisig.signers = signer_keys;
9908        multisig.is_initialized = true;
9909        Multisig::pack(multisig, &mut multisig_account.data).unwrap();
9910
9911        let multisig_info: AccountInfo = (&multisig_key, true, &mut multisig_account).into();
9912
9913        let mut signers_infos = vec![
9914            multisig_info.clone(),
9915            destination_info.clone(),
9916            multisig_info.clone(),
9917        ];
9918        signers_infos.extend(signers);
9919        do_process_instruction_dups(
9920            withdraw_excess_lamports(
9921                &program_id,
9922                &multisig_key,
9923                &destination_key,
9924                &multisig_key,
9925                &signer_refs,
9926            )
9927            .unwrap(),
9928            signers_infos,
9929        )
9930        .unwrap();
9931
9932        assert_eq!(destination_info.lamports(), excess_lamports);
9933    }
9934
9935    #[test]
9936    #[serial]
9937    fn test_withdraw_excess_lamports_from_account() {
9938        let excess_lamports = 4_000_000_000_000;
9939
9940        let program_id = crate::id();
9941        let account_key = Address::new_unique();
9942        let mut account_account = SolanaAccount::new(
9943            excess_lamports + account_minimum_balance(),
9944            Account::get_packed_len(),
9945            &program_id,
9946        );
9947
9948        let system_program_id = system_program::id();
9949        let owner_key = Address::new_unique();
9950
9951        let mut destination_lamports = 0;
9952        let mut destination_data = vec![];
9953        let destination_key = Address::new_unique();
9954        let destination_info = AccountInfo::new(
9955            &destination_key,
9956            true,
9957            false,
9958            &mut destination_lamports,
9959            &mut destination_data,
9960            &system_program_id,
9961            false,
9962        );
9963        let mint_key = Address::new_unique();
9964        let mut mint_account =
9965            SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
9966
9967        let mut rent_sysvar = rent_sysvar();
9968        do_process_instruction(
9969            initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
9970            vec![&mut mint_account, &mut rent_sysvar],
9971        )
9972        .unwrap();
9973
9974        let mint_info = AccountInfo::new(
9975            &mint_key,
9976            true,
9977            false,
9978            &mut mint_account.lamports,
9979            &mut mint_account.data,
9980            &program_id,
9981            false,
9982        );
9983
9984        let account_info: AccountInfo = (&account_key, true, &mut account_account).into();
9985
9986        do_process_instruction_dups(
9987            initialize_account3(&program_id, &account_key, &mint_key, &account_key).unwrap(),
9988            vec![account_info.clone(), mint_info.clone()],
9989        )
9990        .unwrap();
9991
9992        do_process_instruction_dups(
9993            withdraw_excess_lamports(
9994                &program_id,
9995                &account_key,
9996                &destination_key,
9997                &account_key,
9998                &[],
9999            )
10000            .unwrap(),
10001            vec![
10002                account_info.clone(),
10003                destination_info.clone(),
10004                account_info.clone(),
10005            ],
10006        )
10007        .unwrap();
10008
10009        assert_eq!(destination_info.lamports(), excess_lamports);
10010    }
10011
10012    #[test]
10013    #[serial]
10014    fn test_withdraw_excess_lamports_from_mint() {
10015        let excess_lamports = 4_000_000_000_000;
10016
10017        let program_id = crate::id();
10018        let system_program_id = system_program::id();
10019
10020        let mut destination_lamports = 0;
10021        let mut destination_data = vec![];
10022        let destination_key = Address::new_unique();
10023        let destination_info = AccountInfo::new(
10024            &destination_key,
10025            true,
10026            false,
10027            &mut destination_lamports,
10028            &mut destination_data,
10029            &system_program_id,
10030            false,
10031        );
10032        let mint_key = Address::new_unique();
10033        let mut mint_account = SolanaAccount::new(
10034            excess_lamports + mint_minimum_balance(),
10035            Mint::get_packed_len(),
10036            &program_id,
10037        );
10038        let mut rent_sysvar = rent_sysvar();
10039
10040        do_process_instruction(
10041            initialize_mint(&program_id, &mint_key, &mint_key, None, 2).unwrap(),
10042            vec![&mut mint_account, &mut rent_sysvar],
10043        )
10044        .unwrap();
10045
10046        let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into();
10047
10048        do_process_instruction_dups(
10049            withdraw_excess_lamports(&program_id, &mint_key, &destination_key, &mint_key, &[])
10050                .unwrap(),
10051            vec![
10052                mint_info.clone(),
10053                destination_info.clone(),
10054                mint_info.clone(),
10055            ],
10056        )
10057        .unwrap();
10058
10059        assert_eq!(destination_info.lamports(), excess_lamports);
10060    }
10061
10062    #[test]
10063    #[serial]
10064    fn test_withdraw_excess_lamports_from_mint_with_no_mint_authority() {
10065        let excess_lamports = 4_000_000_000_000;
10066
10067        let program_id = crate::id();
10068        let system_program_id = system_program::id();
10069
10070        let mut destination_lamports = 0;
10071        let mut destination_data = vec![];
10072        let destination_key = Address::new_unique();
10073        let destination_info = AccountInfo::new(
10074            &destination_key,
10075            true,
10076            false,
10077            &mut destination_lamports,
10078            &mut destination_data,
10079            &system_program_id,
10080            false,
10081        );
10082        let mint_key = Address::new_unique();
10083        let mut mint_account = SolanaAccount::new(
10084            excess_lamports + mint_minimum_balance(),
10085            Mint::get_packed_len(),
10086            &program_id,
10087        );
10088        let mut mint_authority_lamports = 0;
10089        let mut mint_authority_data = vec![];
10090        let mint_authority_key = Address::new_unique();
10091        let mint_authority_info = AccountInfo::new(
10092            &mint_authority_key,
10093            true,
10094            false,
10095            &mut mint_authority_lamports,
10096            &mut mint_authority_data,
10097            &system_program_id,
10098            false,
10099        );
10100        let mut rent_sysvar = rent_sysvar();
10101
10102        do_process_instruction(
10103            initialize_mint(&program_id, &mint_key, &mint_authority_key, None, 2).unwrap(),
10104            vec![&mut mint_account, &mut rent_sysvar],
10105        )
10106        .unwrap();
10107
10108        let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into();
10109
10110        // fail when withdrawing with the mint as authority when there is
10111        // a mint authority set
10112        assert_eq!(
10113            Err(TokenError::OwnerMismatch.into()),
10114            do_process_instruction_dups(
10115                withdraw_excess_lamports(&program_id, &mint_key, &destination_key, &mint_key, &[])
10116                    .unwrap(),
10117                vec![
10118                    mint_info.clone(),
10119                    destination_info.clone(),
10120                    mint_info.clone(),
10121                ],
10122            )
10123        );
10124
10125        do_process_instruction_dups(
10126            set_authority(
10127                &program_id,
10128                &mint_key,
10129                None,
10130                AuthorityType::MintTokens,
10131                &mint_authority_key,
10132                &[],
10133            )
10134            .unwrap(),
10135            vec![mint_info.clone(), mint_authority_info.clone()],
10136        )
10137        .unwrap();
10138
10139        // fail when withdrawing with the previous mint authority
10140        assert_eq!(
10141            Err(TokenError::AuthorityTypeNotSupported.into()),
10142            do_process_instruction_dups(
10143                withdraw_excess_lamports(
10144                    &program_id,
10145                    &mint_key,
10146                    &destination_key,
10147                    &mint_authority_key,
10148                    &[]
10149                )
10150                .unwrap(),
10151                vec![
10152                    mint_info.clone(),
10153                    destination_info.clone(),
10154                    mint_authority_info.clone(),
10155                ],
10156            )
10157        );
10158
10159        do_process_instruction_dups(
10160            withdraw_excess_lamports(&program_id, &mint_key, &destination_key, &mint_key, &[])
10161                .unwrap(),
10162            vec![
10163                mint_info.clone(),
10164                destination_info.clone(),
10165                mint_info.clone(),
10166            ],
10167        )
10168        .unwrap();
10169
10170        assert_eq!(destination_info.lamports(), excess_lamports);
10171    }
10172}