gpl_token/
processor.rs

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