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