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