gorba_token/
processor.rs

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