safe_token_2022/
processor.rs

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