safe_token/
processor.rs

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