spl_token_2022/
processor.rs

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