From 0a64761435d4584386848dde4efdb5c12b876e9d Mon Sep 17 00:00:00 2001 From: febo Date: Fri, 20 Dec 2024 23:24:21 +0000 Subject: [PATCH 01/11] [wip]: Switch processor tests to mollusk --- Cargo.lock | 9 +-- program/Cargo.toml | 2 +- program/tests/processor.rs | 146 +++++++++++++++++++++++++++++++++++++ 3 files changed, 150 insertions(+), 7 deletions(-) create mode 100644 program/tests/processor.rs diff --git a/Cargo.lock b/Cargo.lock index 48b0c964..37fea2dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1559,8 +1559,7 @@ dependencies = [ [[package]] name = "mollusk-svm" version = "0.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fceaf67fe3f95a9478f4f5b0d71e77c073eee7a795a74d6143317a22454c289" +source = "git+https://github.com/febo/mollusk.git?branch=data-slice-check#ab5d8157fd4d1dc2bd66c23fe516e3b6e7d8d6cd" dependencies = [ "bincode", "mollusk-svm-error", @@ -1577,8 +1576,7 @@ dependencies = [ [[package]] name = "mollusk-svm-error" version = "0.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8738bc85a52d123012209a573f17faffa1db440493396ae2e1f64fbb8f3579bf" +source = "git+https://github.com/febo/mollusk.git?branch=data-slice-check#ab5d8157fd4d1dc2bd66c23fe516e3b6e7d8d6cd" dependencies = [ "solana-sdk", "thiserror 1.0.69", @@ -1587,8 +1585,7 @@ dependencies = [ [[package]] name = "mollusk-svm-keys" version = "0.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a7656d86d743de0a9788ce4c0e9ff63028a42e350131ebe67c476cdde6ac9f" +source = "git+https://github.com/febo/mollusk.git?branch=data-slice-check#ab5d8157fd4d1dc2bd66c23fe516e3b6e7d8d6cd" dependencies = [ "mollusk-svm-error", "solana-sdk", diff --git a/program/Cargo.toml b/program/Cargo.toml index 21b18ad6..f648045d 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -22,7 +22,7 @@ thiserror = "2.0" [dev-dependencies] lazy_static = "1.5.0" -mollusk-svm = "0.0.13" +mollusk-svm = { version = "0.0.13", git = "https://github.com/febo/mollusk.git", branch = "data-slice-check" } proptest = "1.5" serial_test = "3.2.0" solana-sdk = "2.1.0" diff --git a/program/tests/processor.rs b/program/tests/processor.rs new file mode 100644 index 00000000..9fca2b84 --- /dev/null +++ b/program/tests/processor.rs @@ -0,0 +1,146 @@ +#![cfg(feature = "test-sbf")] + +//! Program state processor tests + +use std::collections::HashSet; + +use mollusk_svm::{ + result::{Check, InstructionResult}, + Mollusk, +}; +use solana_sdk::{ + account::{create_account_for_test, Account as SolanaAccount, AccountSharedData}, + instruction::Instruction, + program_pack::Pack, + pubkey::Pubkey, + rent::Rent, +}; +use spl_token::{error::TokenError, instruction::initialize_mint, state::Mint}; + +type InstructionPack<'a> = (Instruction, Vec<&'a SolanaAccount>); + +fn do_process_instruction( + instruction: Instruction, + accounts: Vec<&SolanaAccount>, + checks: &[Check], +) -> InstructionResult { + let accounts = instruction + .accounts + .iter() + .zip(accounts) + .map(|(account_meta, account)| { + ( + account_meta.pubkey, + AccountSharedData::from(account.clone()), + ) + }) + .collect::>(); + + let mollusk = Mollusk::new(&spl_token::id(), "spl_token"); + mollusk.process_and_validate_instruction(&instruction, accounts.as_slice(), checks) +} + +fn do_process_instructions( + instructions: &[InstructionPack], + checks: &[Check], +) -> InstructionResult { + let mut present = HashSet::new(); + let mut tx_instructions = Vec::new(); + let mut tx_accounts = Vec::new(); + + instructions.iter().for_each(|(instruction, accounts)| { + instruction + .accounts + .iter() + .zip(accounts) + .map(|(account_meta, account)| { + ( + account_meta.pubkey, + AccountSharedData::from((*account).clone()), + ) + }) + .for_each(|(pubkey, account)| { + if !present.contains(&pubkey) { + present.insert(pubkey); + tx_accounts.push((pubkey, account)); + } + }); + tx_instructions.push(instruction.clone()); + }); + + let mollusk = Mollusk::new(&spl_token::id(), "spl_token"); + mollusk.process_and_validate_instruction_chain( + tx_instructions.as_slice(), + tx_accounts.as_slice(), + checks, + ) +} + +fn mint_minimum_balance() -> u64 { + Rent::default().minimum_balance(Mint::get_packed_len()) +} + +fn rent_sysvar() -> SolanaAccount { + create_account_for_test(&Rent::default()) +} + +#[test] +fn test_initialize_mint() { + let program_id = spl_token::id(); + let owner_key = Pubkey::new_unique(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = SolanaAccount::new(42, Mint::get_packed_len(), &program_id); + let mint2_key = Pubkey::new_unique(); + let mint2_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let rent_sysvar = rent_sysvar(); + + // mint is not rent exempt + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mint_account, &rent_sysvar], + &[Check::err(TokenError::NotRentExempt.into())], + ); + + mint_account.lamports = mint_minimum_balance(); + + // create new mint + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mint_account, &rent_sysvar], + &[Check::success()], + ); + + // create twice + do_process_instructions( + &[ + ( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mint_account, &rent_sysvar], + ), + ( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mint_account, &rent_sysvar], + ), + ], + &[Check::err(TokenError::AlreadyInUse.into())], + ); + + // create another mint that can freeze + do_process_instruction( + initialize_mint(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(), + vec![&mint2_account, &rent_sysvar], + &[ + // Account successfully re-initialized. + Check::success(), + // mint authority is set + Check::account(&mint2_key) + .data_slice(46, &[1, 0, 0, 0]) + .build(), + // mint authority matches owner + Check::account(&mint2_key) + .data_slice(50, owner_key.as_ref()) + .build(), + ], + ); +} From 93e163631eca8758d040917cd7004917cdda8096 Mon Sep 17 00:00:00 2001 From: febo Date: Fri, 20 Dec 2024 23:42:41 +0000 Subject: [PATCH 02/11] Tidy up --- program/tests/processor.rs | 72 +++++++++++++++----------------------- 1 file changed, 29 insertions(+), 43 deletions(-) diff --git a/program/tests/processor.rs b/program/tests/processor.rs index 9fca2b84..f0473a22 100644 --- a/program/tests/processor.rs +++ b/program/tests/processor.rs @@ -2,44 +2,24 @@ //! Program state processor tests -use std::collections::HashSet; - -use mollusk_svm::{ - result::{Check, InstructionResult}, - Mollusk, -}; -use solana_sdk::{ - account::{create_account_for_test, Account as SolanaAccount, AccountSharedData}, - instruction::Instruction, - program_pack::Pack, - pubkey::Pubkey, - rent::Rent, +use { + mollusk_svm::{ + result::{Check, InstructionResult}, + Mollusk, + }, + solana_sdk::{ + account::{create_account_for_test, Account as SolanaAccount, AccountSharedData}, + instruction::Instruction, + program_pack::Pack, + pubkey::Pubkey, + rent::Rent, + }, + spl_token::{error::TokenError, instruction::initialize_mint, state::Mint}, + std::collections::HashSet, }; -use spl_token::{error::TokenError, instruction::initialize_mint, state::Mint}; type InstructionPack<'a> = (Instruction, Vec<&'a SolanaAccount>); -fn do_process_instruction( - instruction: Instruction, - accounts: Vec<&SolanaAccount>, - checks: &[Check], -) -> InstructionResult { - let accounts = instruction - .accounts - .iter() - .zip(accounts) - .map(|(account_meta, account)| { - ( - account_meta.pubkey, - AccountSharedData::from(account.clone()), - ) - }) - .collect::>(); - - let mollusk = Mollusk::new(&spl_token::id(), "spl_token"); - mollusk.process_and_validate_instruction(&instruction, accounts.as_slice(), checks) -} - fn do_process_instructions( instructions: &[InstructionPack], checks: &[Check], @@ -96,18 +76,22 @@ fn test_initialize_mint() { let rent_sysvar = rent_sysvar(); // mint is not rent exempt - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mint_account, &rent_sysvar], + do_process_instructions( + &[( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mint_account, &rent_sysvar], + )], &[Check::err(TokenError::NotRentExempt.into())], ); mint_account.lamports = mint_minimum_balance(); // create new mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mint_account, &rent_sysvar], + do_process_instructions( + &[( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mint_account, &rent_sysvar], + )], &[Check::success()], ); @@ -127,9 +111,11 @@ fn test_initialize_mint() { ); // create another mint that can freeze - do_process_instruction( - initialize_mint(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(), - vec![&mint2_account, &rent_sysvar], + do_process_instructions( + &[( + initialize_mint(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(), + vec![&mint2_account, &rent_sysvar], + )], &[ // Account successfully re-initialized. Check::success(), From 4d9b9489f33603d04cd720e1fe26fe96b08b2cba Mon Sep 17 00:00:00 2001 From: febo Date: Sat, 21 Dec 2024 02:33:47 +0000 Subject: [PATCH 03/11] [wip]: More tests --- program/tests/processor.rs | 197 ++++++++++++++++++++++++++++++++++++- 1 file changed, 196 insertions(+), 1 deletion(-) diff --git a/program/tests/processor.rs b/program/tests/processor.rs index f0473a22..a21a423f 100644 --- a/program/tests/processor.rs +++ b/program/tests/processor.rs @@ -10,11 +10,16 @@ use { solana_sdk::{ account::{create_account_for_test, Account as SolanaAccount, AccountSharedData}, instruction::Instruction, + program_error::ProgramError, program_pack::Pack, pubkey::Pubkey, rent::Rent, }, - spl_token::{error::TokenError, instruction::initialize_mint, state::Mint}, + spl_token::{ + error::TokenError, + instruction::{initialize_account, initialize_mint, initialize_mint2}, + state::{Account, Mint}, + }, std::collections::HashSet, }; @@ -56,6 +61,10 @@ fn do_process_instructions( ) } +fn account_minimum_balance() -> u64 { + Rent::default().minimum_balance(Account::get_packed_len()) +} + fn mint_minimum_balance() -> u64 { Rent::default().minimum_balance(Mint::get_packed_len()) } @@ -130,3 +139,189 @@ fn test_initialize_mint() { ], ); } + +#[test] +fn test_initialize_mint2() { + let program_id = spl_token::id(); + let owner_key = Pubkey::new_unique(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = SolanaAccount::new(42, Mint::get_packed_len(), &program_id); + let mint2_key = Pubkey::new_unique(); + let mut mint2_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + + // mint is not rent exempt + do_process_instructions( + &[( + initialize_mint2(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mint_account], + )], + &[Check::err(TokenError::NotRentExempt.into())], + ); + + mint_account.lamports = mint_minimum_balance(); + + // create new mint + do_process_instructions( + &[( + initialize_mint2(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mint_account], + )], + &[Check::success()], + ); + + // create twice + do_process_instructions( + &[ + ( + initialize_mint2(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mint_account], + ), + ( + initialize_mint2(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mint_account], + ), + ], + &[Check::err(TokenError::AlreadyInUse.into())], + ); + + // create another mint that can freeze + do_process_instructions( + &[( + initialize_mint2(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(), + vec![&mut mint2_account], + )], + &[ + // Account successfully re-initialized. + Check::success(), + // mint authority is set + Check::account(&mint2_key) + .data_slice(46, &[1, 0, 0, 0]) + .build(), + // mint authority matches owner + Check::account(&mint2_key) + .data_slice(50, owner_key.as_ref()) + .build(), + ], + ); +} + +#[test] +fn test_initialize_mint_account() { + let program_id = spl_token::id(); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new(42, Account::get_packed_len(), &program_id); + let owner_key = Pubkey::new_unique(); + let owner_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let rent_sysvar = rent_sysvar(); + + // account is not rent exempt + do_process_instructions( + &[( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &account_account, + &mint_account, + &owner_account, + &rent_sysvar, + ], + )], + &[Check::err(TokenError::NotRentExempt.into())], + ); + + account_account.lamports = account_minimum_balance(); + + // mint is not valid (not initialized) + do_process_instructions( + &[( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &account_account, + &mint_account, + &owner_account, + &rent_sysvar, + ], + )], + &[Check::err(TokenError::InvalidMint.into())], + ); + + // create mint + do_process_instructions( + &[( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mint_account, &rent_sysvar], + )], + &[Check::success()], + ); + + // mint not owned by program + let not_program_id = Pubkey::new_unique(); + mint_account.owner = not_program_id; + + do_process_instructions( + &[( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &account_account, + &mint_account, + &owner_account, + &rent_sysvar, + ], + )], + &[Check::err(ProgramError::IncorrectProgramId)], + ); + + mint_account.owner = program_id; + + // create account + do_process_instructions( + &[ + ( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mint_account, &rent_sysvar], + ), + ( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &account_account, + &mint_account, + &owner_account, + &rent_sysvar, + ], + ), + ], + &[Check::success()], + ); + + // create twice + do_process_instructions( + &[ + ( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mint_account, &rent_sysvar], + ), + ( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &account_account, + &mint_account, + &owner_account, + &rent_sysvar, + ], + ), + ( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &account_account, + &mint_account, + &owner_account, + &rent_sysvar, + ], + ), + ], + &[Check::err(TokenError::AlreadyInUse.into())], + ); +} From 86a076826581c81d5e7d50e0f494d99fff3cf45c Mon Sep 17 00:00:00 2001 From: febo Date: Sun, 29 Dec 2024 13:24:52 +0000 Subject: [PATCH 04/11] [wip]: Yet more tests --- program/tests/processor.rs | 5835 +++++++++++++++++++++++++++++++++++- 1 file changed, 5806 insertions(+), 29 deletions(-) diff --git a/program/tests/processor.rs b/program/tests/processor.rs index a21a423f..bad60b7d 100644 --- a/program/tests/processor.rs +++ b/program/tests/processor.rs @@ -11,28 +11,87 @@ use { account::{create_account_for_test, Account as SolanaAccount, AccountSharedData}, instruction::Instruction, program_error::ProgramError, + program_option::COption, program_pack::Pack, pubkey::Pubkey, rent::Rent, }, spl_token::{ error::TokenError, - instruction::{initialize_account, initialize_mint, initialize_mint2}, - state::{Account, Mint}, + instruction::{ + initialize_account, initialize_mint, initialize_mint2, initialize_multisig, mint_to, + transfer, transfer_checked, + }, + state::{Account, AccountState, Mint, Multisig}, }, std::collections::HashSet, }; +/// The name of the token program `.so` file. +const TOKEN_PROGRAM_NAME: &str = "spl_token"; + +/// The ID of the token program used in the instruction constructors. +/// +/// In general this should be the same as the `spl_token::id()` constant, since +/// the instruction construction functions are designed to work with the `spl_token`. +/// This value then is replaced by [`TARGET_TOKEN_PROGRAM_ID`] when the instruction +/// is processed by `mollusk`. +const TOKEN_PROGRAM_ID: Pubkey = spl_token::id(); + +/// The ID of the token program that will execute the instruction. +const TARGET_TOKEN_PROGRAM_ID: Pubkey = spl_token::id(); + +/// A tuple of an instruction and the accounts it references. type InstructionPack<'a> = (Instruction, Vec<&'a SolanaAccount>); +/// Process a list of instructions using mollusk. fn do_process_instructions( instructions: &[InstructionPack], checks: &[Check], ) -> InstructionResult { - let mut present = HashSet::new(); + do_process_instructions_with_pre_instructions(None, instructions, checks) +} + +/// Process a list of instructions using mollusk with a pre-defined set of +/// "setup" instructions. +fn do_process_instructions_with_pre_instructions( + pre_instructions: Option<&[InstructionPack]>, + instructions: &[InstructionPack], + checks: &[Check], +) -> InstructionResult { + // Track the accounts that have been set up. + let mut cached_accounts = HashSet::new(); + // List of instructions to process. let mut tx_instructions = Vec::new(); + // List of accounts to process. let mut tx_accounts = Vec::new(); + // Process pre-instructions. + if let Some(pre_instructions) = pre_instructions { + pre_instructions.iter().for_each(|(instruction, accounts)| { + instruction + .accounts + .iter() + .zip(accounts) + .map(|(account_meta, account)| { + ( + account_meta.pubkey, + AccountSharedData::from((*account).clone()), + ) + }) + .for_each(|(pubkey, account)| { + if !cached_accounts.contains(&pubkey) { + cached_accounts.insert(pubkey); + tx_accounts.push((pubkey, account)); + } + }); + let mut ix = instruction.clone(); + ix.program_id = TARGET_TOKEN_PROGRAM_ID; + tx_instructions.push(ix); + }); + } + + // Process instructions. instructions.iter().for_each(|(instruction, accounts)| { instruction .accounts @@ -45,15 +104,17 @@ fn do_process_instructions( ) }) .for_each(|(pubkey, account)| { - if !present.contains(&pubkey) { - present.insert(pubkey); + if !cached_accounts.contains(&pubkey) { + cached_accounts.insert(pubkey); tx_accounts.push((pubkey, account)); } }); - tx_instructions.push(instruction.clone()); + let mut ix = instruction.clone(); + ix.program_id = TARGET_TOKEN_PROGRAM_ID; + tx_instructions.push(ix); }); - let mollusk = Mollusk::new(&spl_token::id(), "spl_token"); + let mollusk = Mollusk::new(&TARGET_TOKEN_PROGRAM_ID, TOKEN_PROGRAM_NAME); mollusk.process_and_validate_instruction_chain( tx_instructions.as_slice(), tx_accounts.as_slice(), @@ -69,13 +130,17 @@ fn mint_minimum_balance() -> u64 { Rent::default().minimum_balance(Mint::get_packed_len()) } +fn multisig_minimum_balance() -> u64 { + Rent::default().minimum_balance(Multisig::get_packed_len()) +} + fn rent_sysvar() -> SolanaAccount { create_account_for_test(&Rent::default()) } #[test] fn test_initialize_mint() { - let program_id = spl_token::id(); + let program_id = TARGET_TOKEN_PROGRAM_ID; let owner_key = Pubkey::new_unique(); let mint_key = Pubkey::new_unique(); let mut mint_account = SolanaAccount::new(42, Mint::get_packed_len(), &program_id); @@ -87,7 +152,7 @@ fn test_initialize_mint() { // mint is not rent exempt do_process_instructions( &[( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), vec![&mint_account, &rent_sysvar], )], &[Check::err(TokenError::NotRentExempt.into())], @@ -98,7 +163,7 @@ fn test_initialize_mint() { // create new mint do_process_instructions( &[( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), vec![&mint_account, &rent_sysvar], )], &[Check::success()], @@ -108,11 +173,11 @@ fn test_initialize_mint() { do_process_instructions( &[ ( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), vec![&mint_account, &rent_sysvar], ), ( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), vec![&mint_account, &rent_sysvar], ), ], @@ -122,7 +187,14 @@ fn test_initialize_mint() { // create another mint that can freeze do_process_instructions( &[( - initialize_mint(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(), + initialize_mint( + &TOKEN_PROGRAM_ID, + &mint2_key, + &owner_key, + Some(&owner_key), + 2, + ) + .unwrap(), vec![&mint2_account, &rent_sysvar], )], &[ @@ -142,7 +214,7 @@ fn test_initialize_mint() { #[test] fn test_initialize_mint2() { - let program_id = spl_token::id(); + let program_id = TARGET_TOKEN_PROGRAM_ID; let owner_key = Pubkey::new_unique(); let mint_key = Pubkey::new_unique(); let mut mint_account = SolanaAccount::new(42, Mint::get_packed_len(), &program_id); @@ -153,7 +225,7 @@ fn test_initialize_mint2() { // mint is not rent exempt do_process_instructions( &[( - initialize_mint2(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + initialize_mint2(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), vec![&mint_account], )], &[Check::err(TokenError::NotRentExempt.into())], @@ -164,7 +236,7 @@ fn test_initialize_mint2() { // create new mint do_process_instructions( &[( - initialize_mint2(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + initialize_mint2(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), vec![&mint_account], )], &[Check::success()], @@ -174,11 +246,11 @@ fn test_initialize_mint2() { do_process_instructions( &[ ( - initialize_mint2(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + initialize_mint2(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), vec![&mint_account], ), ( - initialize_mint2(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + initialize_mint2(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), vec![&mint_account], ), ], @@ -188,7 +260,14 @@ fn test_initialize_mint2() { // create another mint that can freeze do_process_instructions( &[( - initialize_mint2(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(), + initialize_mint2( + &TOKEN_PROGRAM_ID, + &mint2_key, + &owner_key, + Some(&owner_key), + 2, + ) + .unwrap(), vec![&mut mint2_account], )], &[ @@ -208,7 +287,7 @@ fn test_initialize_mint2() { #[test] fn test_initialize_mint_account() { - let program_id = spl_token::id(); + let program_id = TARGET_TOKEN_PROGRAM_ID; let account_key = Pubkey::new_unique(); let mut account_account = SolanaAccount::new(42, Account::get_packed_len(), &program_id); let owner_key = Pubkey::new_unique(); @@ -221,7 +300,7 @@ fn test_initialize_mint_account() { // account is not rent exempt do_process_instructions( &[( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + initialize_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), vec![ &account_account, &mint_account, @@ -237,7 +316,7 @@ fn test_initialize_mint_account() { // mint is not valid (not initialized) do_process_instructions( &[( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + initialize_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), vec![ &account_account, &mint_account, @@ -251,7 +330,7 @@ fn test_initialize_mint_account() { // create mint do_process_instructions( &[( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), vec![&mint_account, &rent_sysvar], )], &[Check::success()], @@ -263,7 +342,7 @@ fn test_initialize_mint_account() { do_process_instructions( &[( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + initialize_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), vec![ &account_account, &mint_account, @@ -280,11 +359,11 @@ fn test_initialize_mint_account() { do_process_instructions( &[ ( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), vec![&mint_account, &rent_sysvar], ), ( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + initialize_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), vec![ &account_account, &mint_account, @@ -300,11 +379,11 @@ fn test_initialize_mint_account() { do_process_instructions( &[ ( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), vec![&mint_account, &rent_sysvar], ), ( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + initialize_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), vec![ &account_account, &mint_account, @@ -313,7 +392,7 @@ fn test_initialize_mint_account() { ], ), ( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + initialize_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), vec![ &account_account, &mint_account, @@ -325,3 +404,5701 @@ fn test_initialize_mint_account() { &[Check::err(TokenError::AlreadyInUse.into())], ); } + +#[test] +fn test_transfer_dups() { + let program_id = TARGET_TOKEN_PROGRAM_ID; + let account1_key = Pubkey::new_unique(); + let account1_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + //let mut account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); + let account2_key = Pubkey::new_unique(); + let account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + //let mut account2_info: AccountInfo = (&account2_key, false, &mut account2_account).into(); + let account3_key = Pubkey::new_unique(); + let account3_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + //let account3_info: AccountInfo = (&account3_key, false, &mut account3_account).into(); + let account4_key = Pubkey::new_unique(); + let account4_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + //let account4_info: AccountInfo = (&account4_key, true, &mut account4_account).into(); + let multisig_key = Pubkey::new_unique(); + let multisig_account = SolanaAccount::new( + multisig_minimum_balance(), + Multisig::get_packed_len(), + &program_id, + ); + //let multisig_info: AccountInfo = (&multisig_key, true, &mut multisig_account).into(); + let owner_key = Pubkey::new_unique(); + let owner_account = SolanaAccount::default(); + //let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into(); + let mint_key = Pubkey::new_unique(); + let mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + //let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into(); + //let rent_key = solana_sdk::sysvar::rent::id(); + let rent_sysvar = rent_sysvar(); + //let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); + + let setup_instructions = vec![ + // create mint + ( + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mint_account, &rent_sysvar], + ), + // create account + ( + initialize_account(&TOKEN_PROGRAM_ID, &account1_key, &mint_key, &account1_key).unwrap(), + vec![ + &account1_account, + &mint_account, + &account1_account, + &rent_sysvar, + ], + ), + // create another account + ( + initialize_account(&TOKEN_PROGRAM_ID, &account2_key, &mint_key, &owner_key).unwrap(), + vec![ + &account2_account, + &mint_account, + &owner_account, + &rent_sysvar, + ], + ), + // mint to account + ( + mint_to( + &TOKEN_PROGRAM_ID, + &mint_key, + &account1_key, + &owner_key, + &[], + 1000, + ) + .unwrap(), + vec![&mint_account, &account1_account, &owner_account], + ), + ]; + + // source-owner transfer + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + transfer( + &program_id, + &account1_key, + &account2_key, + &account1_key, + &[], + 500, + ) + .unwrap(), + vec![&account1_account, &account2_account, &account1_account], + )], + &[Check::success()], + ); + + // source-owner TransferChecked + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + transfer_checked( + &program_id, + &account1_key, + &mint_key, + &account2_key, + &account1_key, + &[], + 500, + 2, + ) + .unwrap(), + vec![ + &account1_account, + &mint_account, + &account2_account, + &account1_account, + ], + )], + &[Check::success()], + ); + + // source-delegate transfer + let delegate_key = Pubkey::new_unique(); + let delegate_account = SolanaAccount::default(); + + let mut account = Account::unpack_unchecked(&account1_account.data).unwrap(); + account.state = AccountState::Initialized; + account.mint = mint_key; + account.amount = 1000; + account.delegated_amount = 1000; + account.delegate = COption::Some(delegate_key); + account.owner = owner_key; + let delegated_account_key = Pubkey::new_unique(); + let mut delegated_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + Account::pack(account, &mut delegated_account.data).unwrap(); + + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + transfer( + &program_id, + &delegated_account_key, + &account2_key, + &delegate_key, + &[], + 500, + ) + .unwrap(), + vec![&delegated_account, &account2_account, &delegate_account], + )], + &[Check::success()], + ); + + // source-delegate TransferChecked + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + transfer_checked( + &program_id, + &delegated_account_key, + &mint_key, + &account2_key, + &delegate_key, + &[], + 500, + 2, + ) + .unwrap(), + vec![ + &delegated_account, + &mint_account, + &account2_account, + &delegate_account, + ], + )], + &[Check::success()], + ); + + // test destination-owner transfer + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[ + ( + initialize_account(&TOKEN_PROGRAM_ID, &account3_key, &mint_key, &account2_key) + .unwrap(), + vec![ + &account3_account, + &mint_account, + &account2_account, + &rent_sysvar, + ], + ), + ( + mint_to( + &TOKEN_PROGRAM_ID, + &mint_key, + &account3_key, + &owner_key, + &[], + 1000, + ) + .unwrap(), + vec![&mint_account, &account3_account, &owner_account], + ), + ( + transfer( + &program_id, + &account3_key, + &account2_key, + &account2_key, + &[], + 500, + ) + .unwrap(), + vec![&account3_account, &account2_account, &account2_account], + ), + ], + &[Check::success()], + ); + + // destination-owner TransferChecked + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[ + ( + initialize_account(&TOKEN_PROGRAM_ID, &account3_key, &mint_key, &account2_key) + .unwrap(), + vec![ + &account3_account, + &mint_account, + &account2_account, + &rent_sysvar, + ], + ), + ( + mint_to( + &TOKEN_PROGRAM_ID, + &mint_key, + &account3_key, + &owner_key, + &[], + 1000, + ) + .unwrap(), + vec![&mint_account, &account3_account, &owner_account], + ), + ( + transfer_checked( + &program_id, + &account3_key, + &mint_key, + &account2_key, + &account2_key, + &[], + 500, + 2, + ) + .unwrap(), + vec![ + &account3_account, + &mint_account, + &account2_account, + &account2_account, + ], + ), + ], + &[Check::success()], + ); + + // test source-multisig signer + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[ + ( + initialize_multisig(&TOKEN_PROGRAM_ID, &multisig_key, &[&account4_key], 1).unwrap(), + vec![&multisig_account, &rent_sysvar, &account4_account], + ), + ( + initialize_account(&TOKEN_PROGRAM_ID, &account4_key, &mint_key, &multisig_key) + .unwrap(), + vec![ + &account4_account, + &mint_account, + &multisig_account, + &rent_sysvar, + ], + ), + ( + mint_to( + &TOKEN_PROGRAM_ID, + &mint_key, + &account4_key, + &owner_key, + &[], + 1000, + ) + .unwrap(), + vec![&mint_account, &account4_account, &owner_account], + ), + ], + &[Check::success()], + ); + + // source-multisig-signer transfer + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[ + ( + initialize_multisig(&TOKEN_PROGRAM_ID, &multisig_key, &[&account4_key], 1).unwrap(), + vec![&multisig_account, &rent_sysvar, &account4_account], + ), + ( + initialize_account(&TOKEN_PROGRAM_ID, &account4_key, &mint_key, &multisig_key) + .unwrap(), + vec![ + &account4_account, + &mint_account, + &multisig_account, + &rent_sysvar, + ], + ), + ( + mint_to( + &TOKEN_PROGRAM_ID, + &mint_key, + &account4_key, + &owner_key, + &[], + 1000, + ) + .unwrap(), + vec![&mint_account, &account4_account, &owner_account], + ), + ( + transfer( + &program_id, + &account4_key, + &account2_key, + &multisig_key, + &[&account4_key], + 500, + ) + .unwrap(), + vec![ + &account4_account, + &account2_account, + &multisig_account, + &account4_account, + ], + ), + ], + &[Check::success()], + ); + + // source-multisig-signer TransferChecked + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[ + ( + initialize_multisig(&TOKEN_PROGRAM_ID, &multisig_key, &[&account4_key], 1).unwrap(), + vec![&multisig_account, &rent_sysvar, &account4_account], + ), + ( + initialize_account(&TOKEN_PROGRAM_ID, &account4_key, &mint_key, &multisig_key) + .unwrap(), + vec![ + &account4_account, + &mint_account, + &multisig_account, + &rent_sysvar, + ], + ), + ( + mint_to( + &TOKEN_PROGRAM_ID, + &mint_key, + &account4_key, + &owner_key, + &[], + 1000, + ) + .unwrap(), + vec![&mint_account, &account4_account, &owner_account], + ), + ( + transfer_checked( + &program_id, + &account4_key, + &mint_key, + &account2_key, + &multisig_key, + &[&account4_key], + 500, + 2, + ) + .unwrap(), + vec![ + &account4_account, + &mint_account, + &account2_account, + &multisig_account, + &account4_account, + ], + ), + ], + &[Check::success()], + ); +} +/* +#[test] +fn test_transfer() { + let program_id = TARGET_TOKEN_PROGRAM_ID; + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account2_key = Pubkey::new_unique(); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account3_key = Pubkey::new_unique(); + let mut account3_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let delegate_key = Pubkey::new_unique(); + let mut delegate_account = SolanaAccount::default(); + let mismatch_key = Pubkey::new_unique(); + let mut mismatch_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = Pubkey::new_unique(); + let mut owner2_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint2_key = Pubkey::new_unique(); + let mut mint2_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mut rent_sysvar = rent_sysvar(); + + let setup_instructions = vec![ + // create mint + ( + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mint_account, &rent_sysvar], + ), + // create account + ( + initialize_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &account_account, + &mint_account, + &owner_account, + &rent_sysvar, + ], + ), + // create another account + ( + initialize_account(&TOKEN_PROGRAM_ID, &account2_key, &mint_key, &owner_key).unwrap(), + vec![ + &account2_account, + &mint_account, + &owner_account, + &rent_sysvar, + ], + ), + // create another account + ( + initialize_account(&TOKEN_PROGRAM_ID, &account3_key, &mint_key, &owner_key).unwrap(), + vec![ + &account3_account, + &mint_account, + &owner_account, + &rent_sysvar, + ], + ), + // mint to account + ( + mint_to( + &TOKEN_PROGRAM_ID, + &mint_key, + &account_key, + &owner_key, + &[], + 1000, + ) + .unwrap(), + vec![&mint_account, &account_account, &owner_account], + ), + // create a second mint + ( + initialize_mint(&TOKEN_PROGRAM_ID, &mint2_key, &owner_key, None, 2).unwrap(), + vec![&mint2_account, &rent_sysvar], + ), + // create mismatch account using mint2 + ( + initialize_account(&TOKEN_PROGRAM_ID, &mismatch_key, &mint2_key, &owner_key).unwrap(), + vec![ + &mismatch_account, + &mint2_account, + &owner_account, + &rent_sysvar, + ], + ), + ]; + + // missing signer + let mut instruction = transfer( + &TOKEN_PROGRAM_ID, + &account_key, + &account2_key, + &owner_key, + &[], + 1000, + ) + .unwrap(); + instruction.accounts[2].is_signer = false; + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + instruction, + vec![&account_account, &account2_account, &owner_account], + )], + &[Check::err(ProgramError::MissingRequiredSignature)], + ); + + // mismatch mint + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + transfer( + &TOKEN_PROGRAM_ID, + &account_key, + &mismatch_key, + &owner_key, + &[], + 1000, + ) + .unwrap(), + vec![&account_account, &mismatch_account, &owner_account], + )], + &[Check::err(TokenError::MintMismatch.into())], + ); + + // missing owner + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + transfer( + &TOKEN_PROGRAM_ID, + &account_key, + &account2_key, + &owner2_key, + &[], + 1000, + ) + .unwrap(), + vec![&account_account, &account2_account, &owner2_account], + )], + &[Check::err(TokenError::OwnerMismatch.into())], + ); + + // account not owned by program + let not_program_id = Pubkey::new_unique(); + let mut not_program_id_account = account_account.clone(); + not_program_id_account.owner = not_program_id; + + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + transfer( + &TOKEN_PROGRAM_ID, + ¬_program_id, + &account2_key, + &owner_key, + &[], + 0, + ) + .unwrap(), + vec![¬_program_id_account, &account2_account, &owner2_account], + )], + &[Check::err(ProgramError::IncorrectProgramId)], + ); + //account_account.owner = program_id; + + // account 2 not owned by program + let not_program_id = Pubkey::new_unique(); + account2_account.owner = not_program_id; + assert_eq!( + Err(ProgramError::IncorrectProgramId), + do_process_instruction( + transfer( + &TOKEN_PROGRAM_ID, + &account_key, + &account2_key, + &owner_key, + &[], + 0, + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner2_account, + ], + ) + ); + account2_account.owner = program_id; + + // transfer + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &owner_key, + &[], + 1000, + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner_account, + ], + ) + .unwrap(); + + // insufficient funds + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + do_process_instruction( + transfer( + &TOKEN_PROGRAM_ID, + &account_key, + &account2_key, + &owner_key, + &[], + 1 + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner_account, + ], + ) + ); + + // transfer half back + do_process_instruction( + transfer( + &program_id, + &account2_key, + &account_key, + &owner_key, + &[], + 500, + ) + .unwrap(), + vec![ + &mut account2_account, + &mut account_account, + &mut owner_account, + ], + ) + .unwrap(); + + // incorrect decimals + assert_eq!( + Err(TokenError::MintDecimalsMismatch.into()), + do_process_instruction( + transfer_checked( + &program_id, + &account2_key, + &mint_key, + &account_key, + &owner_key, + &[], + 1, + 10 // <-- incorrect decimals + ) + .unwrap(), + vec![ + &mut account2_account, + &mut mint_account, + &mut account_account, + &mut owner_account, + ], + ) + ); + + // incorrect mint + assert_eq!( + Err(TokenError::MintMismatch.into()), + do_process_instruction( + transfer_checked( + &program_id, + &account2_key, + &account3_key, // <-- incorrect mint + &account_key, + &owner_key, + &[], + 1, + 2 + ) + .unwrap(), + vec![ + &mut account2_account, + &mut account3_account, // <-- incorrect mint + &mut account_account, + &mut owner_account, + ], + ) + ); + // transfer rest with explicit decimals + do_process_instruction( + transfer_checked( + &program_id, + &account2_key, + &mint_key, + &account_key, + &owner_key, + &[], + 500, + 2, + ) + .unwrap(), + vec![ + &mut account2_account, + &mut mint_account, + &mut account_account, + &mut owner_account, + ], + ) + .unwrap(); + + // insufficient funds + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + do_process_instruction( + transfer( + &TOKEN_PROGRAM_ID, + &account2_key, + &account_key, + &owner_key, + &[], + 1 + ) + .unwrap(), + vec![ + &mut account2_account, + &mut account_account, + &mut owner_account, + ], + ) + ); + + // approve delegate + do_process_instruction( + approve( + &program_id, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, + ) + .unwrap(), + vec![ + &mut account_account, + &mut delegate_account, + &mut owner_account, + ], + ) + .unwrap(); + + // not a delegate of source account + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &owner2_key, // <-- incorrect owner or delegate + &[], + 1, + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner2_account, + ], + ) + ); + + // insufficient funds approved via delegate + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &delegate_key, + &[], + 101 + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut delegate_account, + ], + ) + ); + + // transfer via delegate + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &delegate_key, + &[], + 100, + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut delegate_account, + ], + ) + .unwrap(); + + // insufficient funds approved via delegate + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &delegate_key, + &[], + 1 + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut delegate_account, + ], + ) + ); + + // transfer rest + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &owner_key, + &[], + 900, + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner_account, + ], + ) + .unwrap(); + + // approve delegate + do_process_instruction( + approve( + &program_id, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, + ) + .unwrap(), + vec![ + &mut account_account, + &mut delegate_account, + &mut owner_account, + ], + ) + .unwrap(); + + // insufficient funds in source account via delegate + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &delegate_key, + &[], + 100 + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut delegate_account, + ], + ) + ); + +} + + #[test] + fn test_self_transfer() { + let program_id = crate::id(); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account2_key = Pubkey::new_unique(); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account3_key = Pubkey::new_unique(); + let mut account3_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let delegate_key = Pubkey::new_unique(); + let mut delegate_account = SolanaAccount::default(); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = Pubkey::new_unique(); + let mut owner2_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mut rent_sysvar = rent_sysvar(); + + // create mint + do_process_instruction( + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + // create account + do_process_instruction( + initialize_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&TOKEN_PROGRAM_ID, &account2_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account2_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&TOKEN_PROGRAM_ID, &account3_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account3_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // mint to account + do_process_instruction( + mint_to(&TOKEN_PROGRAM_ID, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + + let account_info = (&account_key, false, &mut account_account).into_account_info(); + let account3_info = (&account3_key, false, &mut account3_account).into_account_info(); + let delegate_info = (&delegate_key, true, &mut delegate_account).into_account_info(); + let owner_info = (&owner_key, true, &mut owner_account).into_account_info(); + let owner2_info = (&owner2_key, true, &mut owner2_account).into_account_info(); + let mint_info = (&mint_key, false, &mut mint_account).into_account_info(); + + // transfer + let instruction = transfer( + &program_id, + account_info.key, + account_info.key, + owner_info.key, + &[], + 1000, + ) + .unwrap(); + assert_eq!( + Ok(()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + account_info.clone(), + owner_info.clone(), + ], + &instruction.data, + ) + ); + // no balance change... + let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); + assert_eq!(account.amount, 1000); + + // transfer checked + let instruction = transfer_checked( + &program_id, + account_info.key, + mint_info.key, + account_info.key, + owner_info.key, + &[], + 1000, + 2, + ) + .unwrap(); + assert_eq!( + Ok(()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + mint_info.clone(), + account_info.clone(), + owner_info.clone(), + ], + &instruction.data, + ) + ); + // no balance change... + let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); + assert_eq!(account.amount, 1000); + + // missing signer + let mut owner_no_sign_info = owner_info.clone(); + let mut instruction = transfer( + &program_id, + account_info.key, + account_info.key, + owner_no_sign_info.key, + &[], + 1000, + ) + .unwrap(); + instruction.accounts[2].is_signer = false; + owner_no_sign_info.is_signer = false; + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + account_info.clone(), + owner_no_sign_info.clone(), + ], + &instruction.data, + ) + ); + + // missing signer checked + let mut instruction = transfer_checked( + &program_id, + account_info.key, + mint_info.key, + account_info.key, + owner_no_sign_info.key, + &[], + 1000, + 2, + ) + .unwrap(); + instruction.accounts[3].is_signer = false; + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + mint_info.clone(), + account_info.clone(), + owner_no_sign_info, + ], + &instruction.data, + ) + ); + + // missing owner + let instruction = transfer( + &program_id, + account_info.key, + account_info.key, + owner2_info.key, + &[], + 1000, + ) + .unwrap(); + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + account_info.clone(), + owner2_info.clone(), + ], + &instruction.data, + ) + ); + + // missing owner checked + let instruction = transfer_checked( + &program_id, + account_info.key, + mint_info.key, + account_info.key, + owner2_info.key, + &[], + 1000, + 2, + ) + .unwrap(); + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + mint_info.clone(), + account_info.clone(), + owner2_info.clone(), + ], + &instruction.data, + ) + ); + + // insufficient funds + let instruction = transfer( + &program_id, + account_info.key, + account_info.key, + owner_info.key, + &[], + 1001, + ) + .unwrap(); + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + account_info.clone(), + owner_info.clone(), + ], + &instruction.data, + ) + ); + + // insufficient funds checked + let instruction = transfer_checked( + &program_id, + account_info.key, + mint_info.key, + account_info.key, + owner_info.key, + &[], + 1001, + 2, + ) + .unwrap(); + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + mint_info.clone(), + account_info.clone(), + owner_info.clone(), + ], + &instruction.data, + ) + ); + + // incorrect decimals + let instruction = transfer_checked( + &program_id, + account_info.key, + mint_info.key, + account_info.key, + owner_info.key, + &[], + 1, + 10, // <-- incorrect decimals + ) + .unwrap(); + assert_eq!( + Err(TokenError::MintDecimalsMismatch.into()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + mint_info.clone(), + account_info.clone(), + owner_info.clone(), + ], + &instruction.data, + ) + ); + + // incorrect mint + let instruction = transfer_checked( + &program_id, + account_info.key, + account3_info.key, // <-- incorrect mint + account_info.key, + owner_info.key, + &[], + 1, + 2, + ) + .unwrap(); + assert_eq!( + Err(TokenError::MintMismatch.into()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + account3_info.clone(), // <-- incorrect mint + account_info.clone(), + owner_info.clone(), + ], + &instruction.data, + ) + ); + + // approve delegate + let instruction = approve( + &program_id, + account_info.key, + delegate_info.key, + owner_info.key, + &[], + 100, + ) + .unwrap(); + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + delegate_info.clone(), + owner_info.clone(), + ], + &instruction.data, + ) + .unwrap(); + + // delegate transfer + let instruction = transfer( + &program_id, + account_info.key, + account_info.key, + delegate_info.key, + &[], + 100, + ) + .unwrap(); + assert_eq!( + Ok(()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + account_info.clone(), + delegate_info.clone(), + ], + &instruction.data, + ) + ); + // no balance change... + let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); + assert_eq!(account.amount, 1000); + assert_eq!(account.delegated_amount, 100); + + // delegate transfer checked + let instruction = transfer_checked( + &program_id, + account_info.key, + mint_info.key, + account_info.key, + delegate_info.key, + &[], + 100, + 2, + ) + .unwrap(); + assert_eq!( + Ok(()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + mint_info.clone(), + account_info.clone(), + delegate_info.clone(), + ], + &instruction.data, + ) + ); + // no balance change... + let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); + assert_eq!(account.amount, 1000); + assert_eq!(account.delegated_amount, 100); + + // delegate insufficient funds + let instruction = transfer( + &program_id, + account_info.key, + account_info.key, + delegate_info.key, + &[], + 101, + ) + .unwrap(); + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + account_info.clone(), + delegate_info.clone(), + ], + &instruction.data, + ) + ); + + // delegate insufficient funds checked + let instruction = transfer_checked( + &program_id, + account_info.key, + mint_info.key, + account_info.key, + delegate_info.key, + &[], + 101, + 2, + ) + .unwrap(); + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + mint_info.clone(), + account_info.clone(), + delegate_info.clone(), + ], + &instruction.data, + ) + ); + + // owner transfer with delegate assigned + let instruction = transfer( + &program_id, + account_info.key, + account_info.key, + owner_info.key, + &[], + 1000, + ) + .unwrap(); + assert_eq!( + Ok(()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + account_info.clone(), + owner_info.clone(), + ], + &instruction.data, + ) + ); + // no balance change... + let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); + assert_eq!(account.amount, 1000); + + // owner transfer with delegate assigned checked + let instruction = transfer_checked( + &program_id, + account_info.key, + mint_info.key, + account_info.key, + owner_info.key, + &[], + 1000, + 2, + ) + .unwrap(); + assert_eq!( + Ok(()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + mint_info.clone(), + account_info.clone(), + owner_info.clone(), + ], + &instruction.data, + ) + ); + // no balance change... + let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); + assert_eq!(account.amount, 1000); + } + + #[test] + fn test_mintable_token_with_zero_supply() { + let program_id = crate::id(); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mut rent_sysvar = rent_sysvar(); + + // create mint-able token with zero supply + let decimals = 2; + do_process_instruction( + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, decimals).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); + assert_eq!( + mint, + Mint { + mint_authority: COption::Some(owner_key), + supply: 0, + decimals, + is_initialized: true, + freeze_authority: COption::None, + } + ); + + // create account + do_process_instruction( + initialize_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // mint to + do_process_instruction( + mint_to(&TOKEN_PROGRAM_ID, &mint_key, &account_key, &owner_key, &[], 42).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + let _ = Mint::unpack(&mint_account.data).unwrap(); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.amount, 42); + + // mint to 2, with incorrect decimals + assert_eq!( + Err(TokenError::MintDecimalsMismatch.into()), + do_process_instruction( + mint_to_checked( + &program_id, + &mint_key, + &account_key, + &owner_key, + &[], + 42, + decimals + 1 + ) + .unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + ); + + let _ = Mint::unpack(&mint_account.data).unwrap(); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.amount, 42); + + // mint to 2 + do_process_instruction( + mint_to_checked( + &program_id, + &mint_key, + &account_key, + &owner_key, + &[], + 42, + decimals, + ) + .unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + let _ = Mint::unpack(&mint_account.data).unwrap(); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.amount, 84); + } + + #[test] + fn test_approve_dups() { + let program_id = crate::id(); + let account1_key = Pubkey::new_unique(); + let mut account1_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); + let account2_key = Pubkey::new_unique(); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account2_info: AccountInfo = (&account2_key, false, &mut account2_account).into(); + let account3_key = Pubkey::new_unique(); + let mut account3_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account3_info: AccountInfo = (&account3_key, true, &mut account3_account).into(); + let multisig_key = Pubkey::new_unique(); + let mut multisig_account = SolanaAccount::new( + multisig_minimum_balance(), + Multisig::get_packed_len(), + &program_id, + ); + let multisig_info: AccountInfo = (&multisig_key, true, &mut multisig_account).into(); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into(); + let rent_key = rent::id(); + let mut rent_sysvar = rent_sysvar(); + let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); + + // create mint + do_process_instruction_dups( + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + vec![mint_info.clone(), rent_info.clone()], + ) + .unwrap(); + + // create account + do_process_instruction_dups( + initialize_account(&TOKEN_PROGRAM_ID, &account1_key, &mint_key, &account1_key).unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + + // create another account + do_process_instruction_dups( + initialize_account(&TOKEN_PROGRAM_ID, &account2_key, &mint_key, &owner_key).unwrap(), + vec![ + account2_info.clone(), + mint_info.clone(), + owner_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + + // mint to account + do_process_instruction_dups( + mint_to(&TOKEN_PROGRAM_ID, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), + vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], + ) + .unwrap(); + + // source-owner approve + do_process_instruction_dups( + approve( + &program_id, + &account1_key, + &account2_key, + &account1_key, + &[], + 500, + ) + .unwrap(), + vec![ + account1_info.clone(), + account2_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // source-owner approve_checked + do_process_instruction_dups( + approve_checked( + &program_id, + &account1_key, + &mint_key, + &account2_key, + &account1_key, + &[], + 500, + 2, + ) + .unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account2_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // source-owner revoke + do_process_instruction_dups( + revoke(&TOKEN_PROGRAM_ID, &account1_key, &account1_key, &[]).unwrap(), + vec![account1_info.clone(), account1_info.clone()], + ) + .unwrap(); + + // test source-multisig signer + do_process_instruction_dups( + initialize_multisig(&TOKEN_PROGRAM_ID, &multisig_key, &[&account3_key], 1).unwrap(), + vec![ + multisig_info.clone(), + rent_info.clone(), + account3_info.clone(), + ], + ) + .unwrap(); + + do_process_instruction_dups( + initialize_account(&TOKEN_PROGRAM_ID, &account3_key, &mint_key, &multisig_key).unwrap(), + vec![ + account3_info.clone(), + mint_info.clone(), + multisig_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + + do_process_instruction_dups( + mint_to(&TOKEN_PROGRAM_ID, &mint_key, &account3_key, &owner_key, &[], 1000).unwrap(), + vec![mint_info.clone(), account3_info.clone(), owner_info.clone()], + ) + .unwrap(); + + // source-multisig-signer approve + do_process_instruction_dups( + approve( + &program_id, + &account3_key, + &account2_key, + &multisig_key, + &[&account3_key], + 500, + ) + .unwrap(), + vec![ + account3_info.clone(), + account2_info.clone(), + multisig_info.clone(), + account3_info.clone(), + ], + ) + .unwrap(); + + // source-multisig-signer approve_checked + do_process_instruction_dups( + approve_checked( + &program_id, + &account3_key, + &mint_key, + &account2_key, + &multisig_key, + &[&account3_key], + 500, + 2, + ) + .unwrap(), + vec![ + account3_info.clone(), + mint_info.clone(), + account2_info.clone(), + multisig_info.clone(), + account3_info.clone(), + ], + ) + .unwrap(); + + // source-owner multisig-signer + do_process_instruction_dups( + revoke(&TOKEN_PROGRAM_ID, &account3_key, &multisig_key, &[&account3_key]).unwrap(), + vec![ + account3_info.clone(), + multisig_info.clone(), + account3_info.clone(), + ], + ) + .unwrap(); + } + + #[test] + fn test_approve() { + let program_id = crate::id(); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account2_key = Pubkey::new_unique(); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let delegate_key = Pubkey::new_unique(); + let mut delegate_account = SolanaAccount::default(); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = Pubkey::new_unique(); + let mut owner2_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mut rent_sysvar = rent_sysvar(); + + // create mint + do_process_instruction( + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + // create account + do_process_instruction( + initialize_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&TOKEN_PROGRAM_ID, &account2_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account2_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // mint to account + do_process_instruction( + mint_to(&TOKEN_PROGRAM_ID, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + + // missing signer + let mut instruction = approve( + &program_id, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, + ) + .unwrap(); + instruction.accounts[2].is_signer = false; + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + do_process_instruction( + instruction, + vec![ + &mut account_account, + &mut delegate_account, + &mut owner_account, + ], + ) + ); + + // no owner + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + approve( + &program_id, + &account_key, + &delegate_key, + &owner2_key, + &[], + 100 + ) + .unwrap(), + vec![ + &mut account_account, + &mut delegate_account, + &mut owner2_account, + ], + ) + ); + + // approve delegate + do_process_instruction( + approve( + &program_id, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, + ) + .unwrap(), + vec![ + &mut account_account, + &mut delegate_account, + &mut owner_account, + ], + ) + .unwrap(); + + // approve delegate 2, with incorrect decimals + assert_eq!( + Err(TokenError::MintDecimalsMismatch.into()), + do_process_instruction( + approve_checked( + &program_id, + &account_key, + &mint_key, + &delegate_key, + &owner_key, + &[], + 100, + 0 // <-- incorrect decimals + ) + .unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut delegate_account, + &mut owner_account, + ], + ) + ); + + // approve delegate 2, with incorrect mint + assert_eq!( + Err(TokenError::MintMismatch.into()), + do_process_instruction( + approve_checked( + &program_id, + &account_key, + &account2_key, // <-- bad mint + &delegate_key, + &owner_key, + &[], + 100, + 0 + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, // <-- bad mint + &mut delegate_account, + &mut owner_account, + ], + ) + ); + + // approve delegate 2 + do_process_instruction( + approve_checked( + &program_id, + &account_key, + &mint_key, + &delegate_key, + &owner_key, + &[], + 100, + 2, + ) + .unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut delegate_account, + &mut owner_account, + ], + ) + .unwrap(); + + // revoke delegate + do_process_instruction( + revoke(&TOKEN_PROGRAM_ID, &account_key, &owner_key, &[]).unwrap(), + vec![&mut account_account, &mut owner_account], + ) + .unwrap(); + } + + #[test] + fn test_set_authority_dups() { + let program_id = crate::id(); + let account1_key = Pubkey::new_unique(); + let mut account1_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); + let owner_key = Pubkey::new_unique(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into(); + let rent_key = rent::id(); + let mut rent_sysvar = rent_sysvar(); + let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); + + // create mint + do_process_instruction_dups( + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &mint_key, Some(&mint_key), 2).unwrap(), + vec![mint_info.clone(), rent_info.clone()], + ) + .unwrap(); + + // create account + do_process_instruction_dups( + initialize_account(&TOKEN_PROGRAM_ID, &account1_key, &mint_key, &account1_key).unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + + // set mint_authority when currently self + do_process_instruction_dups( + set_authority( + &program_id, + &mint_key, + Some(&owner_key), + AuthorityType::MintTokens, + &mint_key, + &[], + ) + .unwrap(), + vec![mint_info.clone(), mint_info.clone()], + ) + .unwrap(); + + // set freeze_authority when currently self + do_process_instruction_dups( + set_authority( + &program_id, + &mint_key, + Some(&owner_key), + AuthorityType::FreezeAccount, + &mint_key, + &[], + ) + .unwrap(), + vec![mint_info.clone(), mint_info.clone()], + ) + .unwrap(); + + // set account owner when currently self + do_process_instruction_dups( + set_authority( + &program_id, + &account1_key, + Some(&owner_key), + AuthorityType::AccountOwner, + &account1_key, + &[], + ) + .unwrap(), + vec![account1_info.clone(), account1_info.clone()], + ) + .unwrap(); + + // set close_authority when currently self + let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); + account.close_authority = COption::Some(account1_key); + Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); + + do_process_instruction_dups( + set_authority( + &program_id, + &account1_key, + Some(&owner_key), + AuthorityType::CloseAccount, + &account1_key, + &[], + ) + .unwrap(), + vec![account1_info.clone(), account1_info.clone()], + ) + .unwrap(); + } + + #[test] + fn test_set_authority() { + let program_id = crate::id(); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account2_key = Pubkey::new_unique(); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = Pubkey::new_unique(); + let mut owner2_account = SolanaAccount::default(); + let owner3_key = Pubkey::new_unique(); + let mut owner3_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint2_key = Pubkey::new_unique(); + let mut mint2_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mut rent_sysvar = rent_sysvar(); + + // create new mint with owner + do_process_instruction( + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + // create mint with owner and freeze_authority + do_process_instruction( + initialize_mint(&TOKEN_PROGRAM_ID, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(), + vec![&mut mint2_account, &mut rent_sysvar], + ) + .unwrap(); + + // invalid account + assert_eq!( + Err(ProgramError::UninitializedAccount), + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&owner2_key), + AuthorityType::AccountOwner, + &owner_key, + &[] + ) + .unwrap(), + vec![&mut account_account, &mut owner_account], + ) + ); + + // create account + do_process_instruction( + initialize_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&TOKEN_PROGRAM_ID, &account2_key, &mint2_key, &owner_key).unwrap(), + vec![ + &mut account2_account, + &mut mint2_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // missing owner + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&owner_key), + AuthorityType::AccountOwner, + &owner2_key, + &[] + ) + .unwrap(), + vec![&mut account_account, &mut owner2_account], + ) + ); + + // owner did not sign + let mut instruction = set_authority( + &program_id, + &account_key, + Some(&owner2_key), + AuthorityType::AccountOwner, + &owner_key, + &[], + ) + .unwrap(); + instruction.accounts[1].is_signer = false; + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + do_process_instruction(instruction, vec![&mut account_account, &mut owner_account,],) + ); + + // wrong authority type + assert_eq!( + Err(TokenError::AuthorityTypeNotSupported.into()), + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&owner2_key), + AuthorityType::FreezeAccount, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut account_account, &mut owner_account], + ) + ); + + // account owner may not be set to None + assert_eq!( + Err(TokenError::InvalidInstruction.into()), + do_process_instruction( + set_authority( + &program_id, + &account_key, + None, + AuthorityType::AccountOwner, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut account_account, &mut owner_account], + ) + ); + + // set delegate + do_process_instruction( + approve( + &program_id, + &account_key, + &owner2_key, + &owner_key, + &[], + u64::MAX, + ) + .unwrap(), + vec![ + &mut account_account, + &mut owner2_account, + &mut owner_account, + ], + ) + .unwrap(); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.delegate, COption::Some(owner2_key)); + assert_eq!(account.delegated_amount, u64::MAX); + + // set owner + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&owner3_key), + AuthorityType::AccountOwner, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut account_account, &mut owner_account], + ) + .unwrap(); + + // check delegate cleared + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.delegate, COption::None); + assert_eq!(account.delegated_amount, 0); + + // set owner without existing delegate + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&owner2_key), + AuthorityType::AccountOwner, + &owner3_key, + &[], + ) + .unwrap(), + vec![&mut account_account, &mut owner3_account], + ) + .unwrap(); + + // set close_authority + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&owner2_key), + AuthorityType::CloseAccount, + &owner2_key, + &[], + ) + .unwrap(), + vec![&mut account_account, &mut owner2_account], + ) + .unwrap(); + + // close_authority may be set to None + do_process_instruction( + set_authority( + &program_id, + &account_key, + None, + AuthorityType::CloseAccount, + &owner2_key, + &[], + ) + .unwrap(), + vec![&mut account_account, &mut owner2_account], + ) + .unwrap(); + + // wrong owner + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + set_authority( + &program_id, + &mint_key, + Some(&owner3_key), + AuthorityType::MintTokens, + &owner2_key, + &[] + ) + .unwrap(), + vec![&mut mint_account, &mut owner2_account], + ) + ); + + // owner did not sign + let mut instruction = set_authority( + &program_id, + &mint_key, + Some(&owner2_key), + AuthorityType::MintTokens, + &owner_key, + &[], + ) + .unwrap(); + instruction.accounts[1].is_signer = false; + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + do_process_instruction(instruction, vec![&mut mint_account, &mut owner_account],) + ); + + // cannot freeze + assert_eq!( + Err(TokenError::MintCannotFreeze.into()), + do_process_instruction( + set_authority( + &program_id, + &mint_key, + Some(&owner2_key), + AuthorityType::FreezeAccount, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut mint_account, &mut owner_account], + ) + ); + + // set owner + do_process_instruction( + set_authority( + &program_id, + &mint_key, + Some(&owner2_key), + AuthorityType::MintTokens, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut mint_account, &mut owner_account], + ) + .unwrap(); + + // set owner to None + do_process_instruction( + set_authority( + &program_id, + &mint_key, + None, + AuthorityType::MintTokens, + &owner2_key, + &[], + ) + .unwrap(), + vec![&mut mint_account, &mut owner2_account], + ) + .unwrap(); + + // test unsetting mint_authority is one-way operation + assert_eq!( + Err(TokenError::FixedSupply.into()), + do_process_instruction( + set_authority( + &program_id, + &mint2_key, + Some(&owner2_key), + AuthorityType::MintTokens, + &owner_key, + &[] + ) + .unwrap(), + vec![&mut mint_account, &mut owner_account], + ) + ); + + // set freeze_authority + do_process_instruction( + set_authority( + &program_id, + &mint2_key, + Some(&owner2_key), + AuthorityType::FreezeAccount, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut mint2_account, &mut owner_account], + ) + .unwrap(); + + // test unsetting freeze_authority is one-way operation + do_process_instruction( + set_authority( + &program_id, + &mint2_key, + None, + AuthorityType::FreezeAccount, + &owner2_key, + &[], + ) + .unwrap(), + vec![&mut mint2_account, &mut owner2_account], + ) + .unwrap(); + + assert_eq!( + Err(TokenError::MintCannotFreeze.into()), + do_process_instruction( + set_authority( + &program_id, + &mint2_key, + Some(&owner2_key), + AuthorityType::FreezeAccount, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut mint2_account, &mut owner2_account], + ) + ); + } + + #[test] + fn test_mint_to_dups() { + let program_id = crate::id(); + let account1_key = Pubkey::new_unique(); + let mut account1_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into(); + let rent_key = rent::id(); + let mut rent_sysvar = rent_sysvar(); + let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); + + // create mint + do_process_instruction_dups( + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &mint_key, None, 2).unwrap(), + vec![mint_info.clone(), rent_info.clone()], + ) + .unwrap(); + + // create account + do_process_instruction_dups( + initialize_account(&TOKEN_PROGRAM_ID, &account1_key, &mint_key, &owner_key).unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + owner_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + + // mint_to when mint_authority is self + do_process_instruction_dups( + mint_to(&TOKEN_PROGRAM_ID, &mint_key, &account1_key, &mint_key, &[], 42).unwrap(), + vec![mint_info.clone(), account1_info.clone(), mint_info.clone()], + ) + .unwrap(); + + // mint_to_checked when mint_authority is self + do_process_instruction_dups( + mint_to_checked(&TOKEN_PROGRAM_ID, &mint_key, &account1_key, &mint_key, &[], 42, 2).unwrap(), + vec![mint_info.clone(), account1_info.clone(), mint_info.clone()], + ) + .unwrap(); + + // mint_to when mint_authority is account owner + let mut mint = Mint::unpack_unchecked(&mint_info.data.borrow()).unwrap(); + mint.mint_authority = COption::Some(account1_key); + Mint::pack(mint, &mut mint_info.data.borrow_mut()).unwrap(); + do_process_instruction_dups( + mint_to( + &program_id, + &mint_key, + &account1_key, + &account1_key, + &[], + 42, + ) + .unwrap(), + vec![ + mint_info.clone(), + account1_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // mint_to_checked when mint_authority is account owner + do_process_instruction_dups( + mint_to( + &program_id, + &mint_key, + &account1_key, + &account1_key, + &[], + 42, + ) + .unwrap(), + vec![ + mint_info.clone(), + account1_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + } + + #[test] + fn test_mint_to() { + let program_id = crate::id(); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account2_key = Pubkey::new_unique(); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account3_key = Pubkey::new_unique(); + let mut account3_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let mismatch_key = Pubkey::new_unique(); + let mut mismatch_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = Pubkey::new_unique(); + let mut owner2_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint2_key = Pubkey::new_unique(); + let uninitialized_key = Pubkey::new_unique(); + let mut uninitialized_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let mut rent_sysvar = rent_sysvar(); + + // create new mint with owner + do_process_instruction( + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + // create account + do_process_instruction( + initialize_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&TOKEN_PROGRAM_ID, &account2_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account2_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&TOKEN_PROGRAM_ID, &account3_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account3_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // create mismatch account + do_process_instruction( + initialize_account(&TOKEN_PROGRAM_ID, &mismatch_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut mismatch_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + let mut account = Account::unpack_unchecked(&mismatch_account.data).unwrap(); + account.mint = mint2_key; + Account::pack(account, &mut mismatch_account.data).unwrap(); + + // mint to + do_process_instruction( + mint_to(&TOKEN_PROGRAM_ID, &mint_key, &account_key, &owner_key, &[], 42).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + + let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); + assert_eq!(mint.supply, 42); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.amount, 42); + + // mint to another account to test supply accumulation + do_process_instruction( + mint_to(&TOKEN_PROGRAM_ID, &mint_key, &account2_key, &owner_key, &[], 42).unwrap(), + vec![&mut mint_account, &mut account2_account, &mut owner_account], + ) + .unwrap(); + + let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); + assert_eq!(mint.supply, 84); + let account = Account::unpack_unchecked(&account2_account.data).unwrap(); + assert_eq!(account.amount, 42); + + // missing signer + let mut instruction = + mint_to(&TOKEN_PROGRAM_ID, &mint_key, &account2_key, &owner_key, &[], 42).unwrap(); + instruction.accounts[2].is_signer = false; + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + do_process_instruction( + instruction, + vec![&mut mint_account, &mut account2_account, &mut owner_account], + ) + ); + + // mismatch account + assert_eq!( + Err(TokenError::MintMismatch.into()), + do_process_instruction( + mint_to(&TOKEN_PROGRAM_ID, &mint_key, &mismatch_key, &owner_key, &[], 42).unwrap(), + vec![&mut mint_account, &mut mismatch_account, &mut owner_account], + ) + ); + + // missing owner + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + mint_to(&TOKEN_PROGRAM_ID, &mint_key, &account2_key, &owner2_key, &[], 42).unwrap(), + vec![ + &mut mint_account, + &mut account2_account, + &mut owner2_account, + ], + ) + ); + + // mint not owned by program + let not_program_id = Pubkey::new_unique(); + mint_account.owner = not_program_id; + assert_eq!( + Err(ProgramError::IncorrectProgramId), + do_process_instruction( + mint_to(&TOKEN_PROGRAM_ID, &mint_key, &account_key, &owner_key, &[], 0).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + ); + mint_account.owner = program_id; + + // account not owned by program + let not_program_id = Pubkey::new_unique(); + account_account.owner = not_program_id; + assert_eq!( + Err(ProgramError::IncorrectProgramId), + do_process_instruction( + mint_to(&TOKEN_PROGRAM_ID, &mint_key, &account_key, &owner_key, &[], 0).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + ); + account_account.owner = program_id; + + // uninitialized destination account + assert_eq!( + Err(ProgramError::UninitializedAccount), + do_process_instruction( + mint_to( + &program_id, + &mint_key, + &uninitialized_key, + &owner_key, + &[], + 42 + ) + .unwrap(), + vec![ + &mut mint_account, + &mut uninitialized_account, + &mut owner_account, + ], + ) + ); + + // unset mint_authority and test minting fails + do_process_instruction( + set_authority( + &program_id, + &mint_key, + None, + AuthorityType::MintTokens, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut mint_account, &mut owner_account], + ) + .unwrap(); + assert_eq!( + Err(TokenError::FixedSupply.into()), + do_process_instruction( + mint_to(&TOKEN_PROGRAM_ID, &mint_key, &account2_key, &owner_key, &[], 42).unwrap(), + vec![&mut mint_account, &mut account2_account, &mut owner_account], + ) + ); + } + + #[test] + fn test_burn_dups() { + let program_id = crate::id(); + let account1_key = Pubkey::new_unique(); + let mut account1_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into(); + let rent_key = rent::id(); + let mut rent_sysvar = rent_sysvar(); + let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); + + // create mint + do_process_instruction_dups( + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + vec![mint_info.clone(), rent_info.clone()], + ) + .unwrap(); + + // create account + do_process_instruction_dups( + initialize_account(&TOKEN_PROGRAM_ID, &account1_key, &mint_key, &account1_key).unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + + // mint to account + do_process_instruction_dups( + mint_to(&TOKEN_PROGRAM_ID, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), + vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], + ) + .unwrap(); + + // source-owner burn + do_process_instruction_dups( + burn( + &program_id, + &mint_key, + &account1_key, + &account1_key, + &[], + 500, + ) + .unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // source-owner burn_checked + do_process_instruction_dups( + burn_checked( + &program_id, + &account1_key, + &mint_key, + &account1_key, + &[], + 500, + 2, + ) + .unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // mint-owner burn + do_process_instruction_dups( + mint_to(&TOKEN_PROGRAM_ID, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), + vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], + ) + .unwrap(); + let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); + account.owner = mint_key; + Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); + do_process_instruction_dups( + burn(&TOKEN_PROGRAM_ID, &account1_key, &mint_key, &mint_key, &[], 500).unwrap(), + vec![account1_info.clone(), mint_info.clone(), mint_info.clone()], + ) + .unwrap(); + + // mint-owner burn_checked + do_process_instruction_dups( + burn_checked( + &program_id, + &account1_key, + &mint_key, + &mint_key, + &[], + 500, + 2, + ) + .unwrap(), + vec![account1_info.clone(), mint_info.clone(), mint_info.clone()], + ) + .unwrap(); + + // source-delegate burn + do_process_instruction_dups( + mint_to(&TOKEN_PROGRAM_ID, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), + vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], + ) + .unwrap(); + let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); + account.delegated_amount = 1000; + account.delegate = COption::Some(account1_key); + account.owner = owner_key; + Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); + do_process_instruction_dups( + burn( + &program_id, + &account1_key, + &mint_key, + &account1_key, + &[], + 500, + ) + .unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // source-delegate burn_checked + do_process_instruction_dups( + burn_checked( + &program_id, + &account1_key, + &mint_key, + &account1_key, + &[], + 500, + 2, + ) + .unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // mint-delegate burn + do_process_instruction_dups( + mint_to(&TOKEN_PROGRAM_ID, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), + vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], + ) + .unwrap(); + let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); + account.delegated_amount = 1000; + account.delegate = COption::Some(mint_key); + account.owner = owner_key; + Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); + do_process_instruction_dups( + burn(&TOKEN_PROGRAM_ID, &account1_key, &mint_key, &mint_key, &[], 500).unwrap(), + vec![account1_info.clone(), mint_info.clone(), mint_info.clone()], + ) + .unwrap(); + + // mint-delegate burn_checked + do_process_instruction_dups( + burn_checked( + &program_id, + &account1_key, + &mint_key, + &mint_key, + &[], + 500, + 2, + ) + .unwrap(), + vec![account1_info.clone(), mint_info.clone(), mint_info.clone()], + ) + .unwrap(); + } + + #[test] + fn test_burn() { + let program_id = crate::id(); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account2_key = Pubkey::new_unique(); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account3_key = Pubkey::new_unique(); + let mut account3_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let delegate_key = Pubkey::new_unique(); + let mut delegate_account = SolanaAccount::default(); + let mismatch_key = Pubkey::new_unique(); + let mut mismatch_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = Pubkey::new_unique(); + let mut owner2_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint2_key = Pubkey::new_unique(); + let mut rent_sysvar = rent_sysvar(); + + // create new mint + do_process_instruction( + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + // create account + do_process_instruction( + initialize_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&TOKEN_PROGRAM_ID, &account2_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account2_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&TOKEN_PROGRAM_ID, &account3_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account3_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // create mismatch account + do_process_instruction( + initialize_account(&TOKEN_PROGRAM_ID, &mismatch_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut mismatch_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // mint to account + do_process_instruction( + mint_to(&TOKEN_PROGRAM_ID, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + + // mint to mismatch account and change mint key + do_process_instruction( + mint_to(&TOKEN_PROGRAM_ID, &mint_key, &mismatch_key, &owner_key, &[], 1000).unwrap(), + vec![&mut mint_account, &mut mismatch_account, &mut owner_account], + ) + .unwrap(); + let mut account = Account::unpack_unchecked(&mismatch_account.data).unwrap(); + account.mint = mint2_key; + Account::pack(account, &mut mismatch_account.data).unwrap(); + + // missing signer + let mut instruction = + burn(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &delegate_key, &[], 42).unwrap(); + instruction.accounts[1].is_signer = false; + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + instruction, + vec![ + &mut account_account, + &mut mint_account, + &mut delegate_account + ], + ) + ); + + // missing owner + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + burn(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner2_key, &[], 42).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner2_account], + ) + ); + + // account not owned by program + let not_program_id = Pubkey::new_unique(); + account_account.owner = not_program_id; + assert_eq!( + Err(ProgramError::IncorrectProgramId), + do_process_instruction( + burn(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key, &[], 0).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + ); + account_account.owner = program_id; + + // mint not owned by program + let not_program_id = Pubkey::new_unique(); + mint_account.owner = not_program_id; + assert_eq!( + Err(ProgramError::IncorrectProgramId), + do_process_instruction( + burn(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key, &[], 0).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + ); + mint_account.owner = program_id; + + // mint mismatch + assert_eq!( + Err(TokenError::MintMismatch.into()), + do_process_instruction( + burn(&TOKEN_PROGRAM_ID, &mismatch_key, &mint_key, &owner_key, &[], 42).unwrap(), + vec![&mut mismatch_account, &mut mint_account, &mut owner_account], + ) + ); + + // burn + do_process_instruction( + burn(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key, &[], 21).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + // burn_checked, with incorrect decimals + assert_eq!( + Err(TokenError::MintDecimalsMismatch.into()), + do_process_instruction( + burn_checked(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key, &[], 21, 3).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + ); + + // burn_checked + do_process_instruction( + burn_checked(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key, &[], 21, 2).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); + assert_eq!(mint.supply, 2000 - 42); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.amount, 1000 - 42); + + // insufficient funds + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + do_process_instruction( + burn( + &program_id, + &account_key, + &mint_key, + &owner_key, + &[], + 100_000_000 + ) + .unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + ); + + // approve delegate + do_process_instruction( + approve( + &program_id, + &account_key, + &delegate_key, + &owner_key, + &[], + 84, + ) + .unwrap(), + vec![ + &mut account_account, + &mut delegate_account, + &mut owner_account, + ], + ) + .unwrap(); + + // not a delegate of source account + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + burn( + &program_id, + &account_key, + &mint_key, + &owner2_key, // <-- incorrect owner or delegate + &[], + 1, + ) + .unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner2_account], + ) + ); + + // insufficient funds approved via delegate + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + do_process_instruction( + burn(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &delegate_key, &[], 85).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut delegate_account + ], + ) + ); + + // burn via delegate + do_process_instruction( + burn(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &delegate_key, &[], 84).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut delegate_account, + ], + ) + .unwrap(); + + // match + let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); + assert_eq!(mint.supply, 2000 - 42 - 84); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.amount, 1000 - 42 - 84); + + // insufficient funds approved via delegate + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + burn(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &delegate_key, &[], 1).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut delegate_account + ], + ) + ); + } + + #[test] + fn test_burn_and_close_system_and_incinerator_tokens() { + let program_id = crate::id(); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let incinerator_account_key = Pubkey::new_unique(); + let mut incinerator_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let system_account_key = Pubkey::new_unique(); + let mut system_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let recipient_key = Pubkey::new_unique(); + let mut recipient_account = SolanaAccount::default(); + let mut mock_incinerator_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + + // create new mint + do_process_instruction( + initialize_mint2(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + // create account + do_process_instruction( + initialize_account3(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), + vec![&mut account_account, &mut mint_account], + ) + .unwrap(); + + // create incinerator- and system-owned accounts + do_process_instruction( + initialize_account3( + &program_id, + &incinerator_account_key, + &mint_key, + &solana_program::incinerator::id(), + ) + .unwrap(), + vec![&mut incinerator_account, &mut mint_account], + ) + .unwrap(); + do_process_instruction( + initialize_account3( + &program_id, + &system_account_key, + &mint_key, + &solana_program::system_program::id(), + ) + .unwrap(), + vec![&mut system_account, &mut mint_account], + ) + .unwrap(); + + // mint to account + do_process_instruction( + mint_to(&TOKEN_PROGRAM_ID, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + + // transfer half to incinerator, half to system program + do_process_instruction( + transfer( + &program_id, + &account_key, + &incinerator_account_key, + &owner_key, + &[], + 500, + ) + .unwrap(), + vec![ + &mut account_account, + &mut incinerator_account, + &mut owner_account, + ], + ) + .unwrap(); + do_process_instruction( + transfer( + &program_id, + &account_key, + &system_account_key, + &owner_key, + &[], + 500, + ) + .unwrap(), + vec![ + &mut account_account, + &mut system_account, + &mut owner_account, + ], + ) + .unwrap(); + + // close with balance fails + assert_eq!( + Err(TokenError::NonNativeHasBalance.into()), + do_process_instruction( + close_account( + &program_id, + &incinerator_account_key, + &solana_program::incinerator::id(), + &owner_key, + &[] + ) + .unwrap(), + vec![ + &mut incinerator_account, + &mut mock_incinerator_account, + &mut owner_account, + ], + ) + ); + assert_eq!( + Err(TokenError::NonNativeHasBalance.into()), + do_process_instruction( + close_account( + &program_id, + &system_account_key, + &solana_program::incinerator::id(), + &owner_key, + &[] + ) + .unwrap(), + vec![ + &mut system_account, + &mut mock_incinerator_account, + &mut owner_account, + ], + ) + ); + + // anyone can burn + do_process_instruction( + burn( + &program_id, + &incinerator_account_key, + &mint_key, + &recipient_key, + &[], + 500, + ) + .unwrap(), + vec![ + &mut incinerator_account, + &mut mint_account, + &mut recipient_account, + ], + ) + .unwrap(); + do_process_instruction( + burn( + &program_id, + &system_account_key, + &mint_key, + &recipient_key, + &[], + 500, + ) + .unwrap(), + vec![ + &mut system_account, + &mut mint_account, + &mut recipient_account, + ], + ) + .unwrap(); + + // closing fails if destination is not the incinerator + assert_eq!( + Err(ProgramError::InvalidAccountData), + do_process_instruction( + close_account( + &program_id, + &incinerator_account_key, + &recipient_key, + &owner_key, + &[] + ) + .unwrap(), + vec![ + &mut incinerator_account, + &mut recipient_account, + &mut owner_account, + ], + ) + ); + assert_eq!( + Err(ProgramError::InvalidAccountData), + do_process_instruction( + close_account( + &program_id, + &system_account_key, + &recipient_key, + &owner_key, + &[] + ) + .unwrap(), + vec![ + &mut system_account, + &mut recipient_account, + &mut owner_account, + ], + ) + ); + + // closing succeeds with incinerator recipient + do_process_instruction( + close_account( + &program_id, + &incinerator_account_key, + &solana_program::incinerator::id(), + &owner_key, + &[], + ) + .unwrap(), + vec![ + &mut incinerator_account, + &mut mock_incinerator_account, + &mut owner_account, + ], + ) + .unwrap(); + + do_process_instruction( + close_account( + &program_id, + &system_account_key, + &solana_program::incinerator::id(), + &owner_key, + &[], + ) + .unwrap(), + vec![ + &mut system_account, + &mut mock_incinerator_account, + &mut owner_account, + ], + ) + .unwrap(); + } + + #[test] + fn test_multisig() { + let program_id = crate::id(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let account_key = Pubkey::new_unique(); + let mut account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account2_key = Pubkey::new_unique(); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let multisig_key = Pubkey::new_unique(); + let mut multisig_account = SolanaAccount::new(42, Multisig::get_packed_len(), &program_id); + let multisig_delegate_key = Pubkey::new_unique(); + let mut multisig_delegate_account = SolanaAccount::new( + multisig_minimum_balance(), + Multisig::get_packed_len(), + &program_id, + ); + let signer_keys = vec![Pubkey::new_unique(); MAX_SIGNERS]; + let signer_key_refs: Vec<&Pubkey> = signer_keys.iter().collect(); + let mut signer_accounts = vec![SolanaAccount::new(0, 0, &program_id); MAX_SIGNERS]; + let mut rent_sysvar = rent_sysvar(); + + // multisig is not rent exempt + let account_info_iter = &mut signer_accounts.iter_mut(); + assert_eq!( + Err(TokenError::NotRentExempt.into()), + do_process_instruction( + initialize_multisig(&TOKEN_PROGRAM_ID, &multisig_key, &[&signer_keys[0]], 1).unwrap(), + vec![ + &mut multisig_account, + &mut rent_sysvar, + account_info_iter.next().unwrap(), + ], + ) + ); + + multisig_account.lamports = multisig_minimum_balance(); + let mut multisig_account2 = multisig_account.clone(); + + // single signer + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + initialize_multisig(&TOKEN_PROGRAM_ID, &multisig_key, &[&signer_keys[0]], 1).unwrap(), + vec![ + &mut multisig_account, + &mut rent_sysvar, + account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // single signer using `initialize_multisig2` + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + initialize_multisig2(&TOKEN_PROGRAM_ID, &multisig_key, &[&signer_keys[0]], 1).unwrap(), + vec![&mut multisig_account2, account_info_iter.next().unwrap()], + ) + .unwrap(); + + // multiple signer + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + initialize_multisig( + &program_id, + &multisig_delegate_key, + &signer_key_refs, + MAX_SIGNERS as u8, + ) + .unwrap(), + vec![ + &mut multisig_delegate_account, + &mut rent_sysvar, + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // create new mint with multisig owner + do_process_instruction( + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &multisig_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + // create account with multisig owner + do_process_instruction( + initialize_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &multisig_key).unwrap(), + vec![ + &mut account, + &mut mint_account, + &mut multisig_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // create another account with multisig owner + do_process_instruction( + initialize_account( + &program_id, + &account2_key, + &mint_key, + &multisig_delegate_key, + ) + .unwrap(), + vec![ + &mut account2_account, + &mut mint_account, + &mut multisig_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // mint to account + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + mint_to( + &program_id, + &mint_key, + &account_key, + &multisig_key, + &[&signer_keys[0]], + 1000, + ) + .unwrap(), + vec![ + &mut mint_account, + &mut account, + &mut multisig_account, + account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // approve + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + approve( + &program_id, + &account_key, + &multisig_delegate_key, + &multisig_key, + &[&signer_keys[0]], + 100, + ) + .unwrap(), + vec![ + &mut account, + &mut multisig_delegate_account, + &mut multisig_account, + account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // transfer + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &multisig_key, + &[&signer_keys[0]], + 42, + ) + .unwrap(), + vec![ + &mut account, + &mut account2_account, + &mut multisig_account, + account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // transfer via delegate + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &multisig_delegate_key, + &signer_key_refs, + 42, + ) + .unwrap(), + vec![ + &mut account, + &mut account2_account, + &mut multisig_delegate_account, + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // mint to + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + mint_to( + &program_id, + &mint_key, + &account2_key, + &multisig_key, + &[&signer_keys[0]], + 42, + ) + .unwrap(), + vec![ + &mut mint_account, + &mut account2_account, + &mut multisig_account, + account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // burn + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + burn( + &program_id, + &account_key, + &mint_key, + &multisig_key, + &[&signer_keys[0]], + 42, + ) + .unwrap(), + vec![ + &mut account, + &mut mint_account, + &mut multisig_account, + account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // burn via delegate + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + burn( + &program_id, + &account_key, + &mint_key, + &multisig_delegate_key, + &signer_key_refs, + 42, + ) + .unwrap(), + vec![ + &mut account, + &mut mint_account, + &mut multisig_delegate_account, + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // freeze account + let account3_key = Pubkey::new_unique(); + let mut account3_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let mint2_key = Pubkey::new_unique(); + let mut mint2_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + do_process_instruction( + initialize_mint( + &program_id, + &mint2_key, + &multisig_key, + Some(&multisig_key), + 2, + ) + .unwrap(), + vec![&mut mint2_account, &mut rent_sysvar], + ) + .unwrap(); + do_process_instruction( + initialize_account(&TOKEN_PROGRAM_ID, &account3_key, &mint2_key, &owner_key).unwrap(), + vec![ + &mut account3_account, + &mut mint2_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + mint_to( + &program_id, + &mint2_key, + &account3_key, + &multisig_key, + &[&signer_keys[0]], + 1000, + ) + .unwrap(), + vec![ + &mut mint2_account, + &mut account3_account, + &mut multisig_account, + account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + freeze_account( + &program_id, + &account3_key, + &mint2_key, + &multisig_key, + &[&signer_keys[0]], + ) + .unwrap(), + vec![ + &mut account3_account, + &mut mint2_account, + &mut multisig_account, + account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // do SetAuthority on mint + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + set_authority( + &program_id, + &mint_key, + Some(&owner_key), + AuthorityType::MintTokens, + &multisig_key, + &[&signer_keys[0]], + ) + .unwrap(), + vec![ + &mut mint_account, + &mut multisig_account, + account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // do SetAuthority on account + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&owner_key), + AuthorityType::AccountOwner, + &multisig_key, + &[&signer_keys[0]], + ) + .unwrap(), + vec![ + &mut account, + &mut multisig_account, + account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + } + + #[test] + fn test_validate_owner() { + let program_id = crate::id(); + let owner_key = Pubkey::new_unique(); + let mut signer_keys = [Pubkey::default(); MAX_SIGNERS]; + for signer_key in signer_keys.iter_mut().take(MAX_SIGNERS) { + *signer_key = Pubkey::new_unique(); + } + let mut signer_lamports = 0; + let mut signer_data = vec![]; + let mut signers = vec![ + AccountInfo::new( + &owner_key, + true, + false, + &mut signer_lamports, + &mut signer_data, + &program_id, + false, + Epoch::default(), + ); + MAX_SIGNERS + 1 + ]; + for (signer, key) in signers.iter_mut().zip(&signer_keys) { + signer.key = key; + } + let mut lamports = 0; + let mut data = vec![0; Multisig::get_packed_len()]; + let mut multisig = Multisig::unpack_unchecked(&data).unwrap(); + multisig.m = MAX_SIGNERS as u8; + multisig.n = MAX_SIGNERS as u8; + multisig.signers = signer_keys; + multisig.is_initialized = true; + Multisig::pack(multisig, &mut data).unwrap(); + let owner_account_info = AccountInfo::new( + &owner_key, + false, + false, + &mut lamports, + &mut data, + &program_id, + false, + Epoch::default(), + ); + + // full 11 of 11 + Processor::validate_owner(&TOKEN_PROGRAM_ID, &owner_key, &owner_account_info, &signers).unwrap(); + + // 1 of 11 + { + let mut multisig = + Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); + multisig.m = 1; + Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); + } + Processor::validate_owner(&TOKEN_PROGRAM_ID, &owner_key, &owner_account_info, &signers).unwrap(); + + // 2:1 + { + let mut multisig = + Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); + multisig.m = 2; + multisig.n = 1; + Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); + } + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + Processor::validate_owner(&TOKEN_PROGRAM_ID, &owner_key, &owner_account_info, &signers) + ); + + // 0:11 + { + let mut multisig = + Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); + multisig.m = 0; + multisig.n = 11; + Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); + } + Processor::validate_owner(&TOKEN_PROGRAM_ID, &owner_key, &owner_account_info, &signers).unwrap(); + + // 2:11 but 0 provided + { + let mut multisig = + Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); + multisig.m = 2; + multisig.n = 11; + Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); + } + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + Processor::validate_owner(&TOKEN_PROGRAM_ID, &owner_key, &owner_account_info, &[]) + ); + // 2:11 but 1 provided + { + let mut multisig = + Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); + multisig.m = 2; + multisig.n = 11; + Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); + } + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + Processor::validate_owner(&TOKEN_PROGRAM_ID, &owner_key, &owner_account_info, &signers[0..1]) + ); + + // 2:11, 2 from middle provided + { + let mut multisig = + Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); + multisig.m = 2; + multisig.n = 11; + Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); + } + Processor::validate_owner(&TOKEN_PROGRAM_ID, &owner_key, &owner_account_info, &signers[5..7]) + .unwrap(); + + // 11:11, one is not a signer + { + let mut multisig = + Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); + multisig.m = 11; + multisig.n = 11; + Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); + } + signers[5].is_signer = false; + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + Processor::validate_owner(&TOKEN_PROGRAM_ID, &owner_key, &owner_account_info, &signers) + ); + signers[5].is_signer = true; + + // 11:11, single signer signs multiple times + { + let mut signer_lamports = 0; + let mut signer_data = vec![]; + let signers = vec![ + AccountInfo::new( + &signer_keys[5], + true, + false, + &mut signer_lamports, + &mut signer_data, + &program_id, + false, + Epoch::default(), + ); + MAX_SIGNERS + 1 + ]; + let mut multisig = + Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); + multisig.m = 11; + multisig.n = 11; + Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + Processor::validate_owner(&TOKEN_PROGRAM_ID, &owner_key, &owner_account_info, &signers) + ); + } + } + + #[test] + fn test_owner_close_account_dups() { + let program_id = crate::id(); + let owner_key = Pubkey::new_unique(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into(); + let rent_key = rent::id(); + let mut rent_sysvar = rent_sysvar(); + let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); + + // create mint + do_process_instruction_dups( + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + vec![mint_info.clone(), rent_info.clone()], + ) + .unwrap(); + + let to_close_key = Pubkey::new_unique(); + let mut to_close_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let to_close_account_info: AccountInfo = + (&to_close_key, true, &mut to_close_account).into(); + let destination_account_key = Pubkey::new_unique(); + let mut destination_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let destination_account_info: AccountInfo = + (&destination_account_key, true, &mut destination_account).into(); + // create account + do_process_instruction_dups( + initialize_account(&TOKEN_PROGRAM_ID, &to_close_key, &mint_key, &to_close_key).unwrap(), + vec![ + to_close_account_info.clone(), + mint_info.clone(), + to_close_account_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + + // source-owner close + do_process_instruction_dups( + close_account( + &program_id, + &to_close_key, + &destination_account_key, + &to_close_key, + &[], + ) + .unwrap(), + vec![ + to_close_account_info.clone(), + destination_account_info.clone(), + to_close_account_info.clone(), + ], + ) + .unwrap(); + assert_eq!(*to_close_account_info.data.borrow(), &[0u8; Account::LEN]); + } + + #[test] + fn test_close_authority_close_account_dups() { + let program_id = crate::id(); + let owner_key = Pubkey::new_unique(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into(); + let rent_key = rent::id(); + let mut rent_sysvar = rent_sysvar(); + let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); + + // create mint + do_process_instruction_dups( + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + vec![mint_info.clone(), rent_info.clone()], + ) + .unwrap(); + + let to_close_key = Pubkey::new_unique(); + let mut to_close_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let to_close_account_info: AccountInfo = + (&to_close_key, true, &mut to_close_account).into(); + let destination_account_key = Pubkey::new_unique(); + let mut destination_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let destination_account_info: AccountInfo = + (&destination_account_key, true, &mut destination_account).into(); + // create account + do_process_instruction_dups( + initialize_account(&TOKEN_PROGRAM_ID, &to_close_key, &mint_key, &to_close_key).unwrap(), + vec![ + to_close_account_info.clone(), + mint_info.clone(), + to_close_account_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + let mut account = Account::unpack_unchecked(&to_close_account_info.data.borrow()).unwrap(); + account.close_authority = COption::Some(to_close_key); + account.owner = owner_key; + Account::pack(account, &mut to_close_account_info.data.borrow_mut()).unwrap(); + do_process_instruction_dups( + close_account( + &program_id, + &to_close_key, + &destination_account_key, + &to_close_key, + &[], + ) + .unwrap(), + vec![ + to_close_account_info.clone(), + destination_account_info.clone(), + to_close_account_info.clone(), + ], + ) + .unwrap(); + assert_eq!(*to_close_account_info.data.borrow(), &[0u8; Account::LEN]); + } + + #[test] + fn test_close_account() { + let program_id = crate::id(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account2_key = Pubkey::new_unique(); + let mut account2_account = SolanaAccount::new( + account_minimum_balance() + 42, + Account::get_packed_len(), + &program_id, + ); + let account3_key = Pubkey::new_unique(); + let mut account3_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = Pubkey::new_unique(); + let mut owner2_account = SolanaAccount::default(); + let mut rent_sysvar = rent_sysvar(); + + // uninitialized + assert_eq!( + Err(ProgramError::UninitializedAccount), + do_process_instruction( + close_account(&TOKEN_PROGRAM_ID, &account_key, &account3_key, &owner2_key, &[]).unwrap(), + vec![ + &mut account_account, + &mut account3_account, + &mut owner2_account, + ], + ) + ); + + // initialize and mint to non-native account + do_process_instruction( + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + do_process_instruction( + initialize_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + do_process_instruction( + mint_to(&TOKEN_PROGRAM_ID, &mint_key, &account_key, &owner_key, &[], 42).unwrap(), + vec![ + &mut mint_account, + &mut account_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.amount, 42); + + // initialize native account + do_process_instruction( + initialize_account( + &program_id, + &account2_key, + &crate::native_mint::id(), + &owner_key, + ) + .unwrap(), + vec![ + &mut account2_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + let account = Account::unpack_unchecked(&account2_account.data).unwrap(); + assert!(account.is_native()); + assert_eq!(account.amount, 42); + + // close non-native account with balance + assert_eq!( + Err(TokenError::NonNativeHasBalance.into()), + do_process_instruction( + close_account(&TOKEN_PROGRAM_ID, &account_key, &account3_key, &owner_key, &[]).unwrap(), + vec![ + &mut account_account, + &mut account3_account, + &mut owner_account, + ], + ) + ); + assert_eq!(account_account.lamports, account_minimum_balance()); + + // empty account + do_process_instruction( + burn(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key, &[], 42).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + // wrong owner + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + close_account(&TOKEN_PROGRAM_ID, &account_key, &account3_key, &owner2_key, &[]).unwrap(), + vec![ + &mut account_account, + &mut account3_account, + &mut owner2_account, + ], + ) + ); + + // close account + do_process_instruction( + close_account(&TOKEN_PROGRAM_ID, &account_key, &account3_key, &owner_key, &[]).unwrap(), + vec![ + &mut account_account, + &mut account3_account, + &mut owner_account, + ], + ) + .unwrap(); + assert_eq!(account_account.lamports, 0); + assert_eq!(account3_account.lamports, 2 * account_minimum_balance()); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.amount, 0); + + // fund and initialize new non-native account to test close authority + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let owner2_key = Pubkey::new_unique(); + let mut owner2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + do_process_instruction( + initialize_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + account_account.lamports = 2; + + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&owner2_key), + AuthorityType::CloseAccount, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut account_account, &mut owner_account], + ) + .unwrap(); + + // account owner cannot authorize close if close_authority is set + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + close_account(&TOKEN_PROGRAM_ID, &account_key, &account3_key, &owner_key, &[]).unwrap(), + vec![ + &mut account_account, + &mut account3_account, + &mut owner_account, + ], + ) + ); + + // close non-native account with close_authority + do_process_instruction( + close_account(&TOKEN_PROGRAM_ID, &account_key, &account3_key, &owner2_key, &[]).unwrap(), + vec![ + &mut account_account, + &mut account3_account, + &mut owner2_account, + ], + ) + .unwrap(); + assert_eq!(account_account.lamports, 0); + assert_eq!(account3_account.lamports, 2 * account_minimum_balance() + 2); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.amount, 0); + + // close native account + do_process_instruction( + close_account(&TOKEN_PROGRAM_ID, &account2_key, &account3_key, &owner_key, &[]).unwrap(), + vec![ + &mut account2_account, + &mut account3_account, + &mut owner_account, + ], + ) + .unwrap(); + assert_eq!(account2_account.data, [0u8; Account::LEN]); + assert_eq!( + account3_account.lamports, + 3 * account_minimum_balance() + 2 + 42 + ); + } + + #[test] + fn test_native_token() { + let program_id = crate::id(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance() + 40, + Account::get_packed_len(), + &program_id, + ); + let account2_key = Pubkey::new_unique(); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account3_key = Pubkey::new_unique(); + let mut account3_account = SolanaAccount::new(account_minimum_balance(), 0, &program_id); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = Pubkey::new_unique(); + let mut owner2_account = SolanaAccount::default(); + let owner3_key = Pubkey::new_unique(); + let mut rent_sysvar = rent_sysvar(); + + // initialize native account + do_process_instruction( + initialize_account( + &program_id, + &account_key, + &crate::native_mint::id(), + &owner_key, + ) + .unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert!(account.is_native()); + assert_eq!(account.amount, 40); + + // initialize native account + do_process_instruction( + initialize_account( + &program_id, + &account2_key, + &crate::native_mint::id(), + &owner_key, + ) + .unwrap(), + vec![ + &mut account2_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + let account = Account::unpack_unchecked(&account2_account.data).unwrap(); + assert!(account.is_native()); + assert_eq!(account.amount, 0); + + // mint_to unsupported + assert_eq!( + Err(TokenError::NativeNotSupported.into()), + do_process_instruction( + mint_to( + &program_id, + &crate::native_mint::id(), + &account_key, + &owner_key, + &[], + 42 + ) + .unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + ); + + // burn unsupported + let bogus_mint_key = Pubkey::new_unique(); + let mut bogus_mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + do_process_instruction( + initialize_mint(&TOKEN_PROGRAM_ID, &bogus_mint_key, &owner_key, None, 2).unwrap(), + vec![&mut bogus_mint_account, &mut rent_sysvar], + ) + .unwrap(); + + assert_eq!( + Err(TokenError::NativeNotSupported.into()), + do_process_instruction( + burn( + &program_id, + &account_key, + &bogus_mint_key, + &owner_key, + &[], + 42 + ) + .unwrap(), + vec![ + &mut account_account, + &mut bogus_mint_account, + &mut owner_account + ], + ) + ); + + // ensure can't transfer below rent-exempt reserve + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &owner_key, + &[], + 50, + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner_account, + ], + ) + ); + + // transfer between native accounts + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &owner_key, + &[], + 40, + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner_account, + ], + ) + .unwrap(); + assert_eq!(account_account.lamports, account_minimum_balance()); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert!(account.is_native()); + assert_eq!(account.amount, 0); + assert_eq!(account2_account.lamports, account_minimum_balance() + 40); + let account = Account::unpack_unchecked(&account2_account.data).unwrap(); + assert!(account.is_native()); + assert_eq!(account.amount, 40); + + // set close authority + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&owner3_key), + AuthorityType::CloseAccount, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut account_account, &mut owner_account], + ) + .unwrap(); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.close_authority, COption::Some(owner3_key)); + + // set new account owner + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&owner2_key), + AuthorityType::AccountOwner, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut account_account, &mut owner_account], + ) + .unwrap(); + + // close authority cleared + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.close_authority, COption::None); + + // close native account + do_process_instruction( + close_account(&TOKEN_PROGRAM_ID, &account_key, &account3_key, &owner2_key, &[]).unwrap(), + vec![ + &mut account_account, + &mut account3_account, + &mut owner2_account, + ], + ) + .unwrap(); + assert_eq!(account_account.lamports, 0); + assert_eq!(account3_account.lamports, 2 * account_minimum_balance()); + assert_eq!(account_account.data, [0u8; Account::LEN]); + } + + #[test] + fn test_overflow() { + let program_id = crate::id(); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account2_key = Pubkey::new_unique(); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = Pubkey::new_unique(); + let mut owner2_account = SolanaAccount::default(); + let mint_owner_key = Pubkey::new_unique(); + let mut mint_owner_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mut rent_sysvar = rent_sysvar(); + + // create new mint with owner + do_process_instruction( + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &mint_owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + // create an account + do_process_instruction( + initialize_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&TOKEN_PROGRAM_ID, &account2_key, &mint_key, &owner2_key).unwrap(), + vec![ + &mut account2_account, + &mut mint_account, + &mut owner2_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // mint the max to an account + do_process_instruction( + mint_to( + &program_id, + &mint_key, + &account_key, + &mint_owner_key, + &[], + u64::MAX, + ) + .unwrap(), + vec![ + &mut mint_account, + &mut account_account, + &mut mint_owner_account, + ], + ) + .unwrap(); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.amount, u64::MAX); + + // attempt to mint one more to account + assert_eq!( + Err(TokenError::Overflow.into()), + do_process_instruction( + mint_to( + &program_id, + &mint_key, + &account_key, + &mint_owner_key, + &[], + 1, + ) + .unwrap(), + vec![ + &mut mint_account, + &mut account_account, + &mut mint_owner_account, + ], + ) + ); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.amount, u64::MAX); + + // attempt to mint one more to the other account + assert_eq!( + Err(TokenError::Overflow.into()), + do_process_instruction( + mint_to( + &program_id, + &mint_key, + &account2_key, + &mint_owner_key, + &[], + 1, + ) + .unwrap(), + vec![ + &mut mint_account, + &mut account2_account, + &mut mint_owner_account, + ], + ) + ); + + // burn some of the supply + do_process_instruction( + burn(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key, &[], 100).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.amount, u64::MAX - 100); + + do_process_instruction( + mint_to( + &program_id, + &mint_key, + &account_key, + &mint_owner_key, + &[], + 100, + ) + .unwrap(), + vec![ + &mut mint_account, + &mut account_account, + &mut mint_owner_account, + ], + ) + .unwrap(); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.amount, u64::MAX); + + // manipulate account balance to attempt overflow transfer + let mut account = Account::unpack_unchecked(&account2_account.data).unwrap(); + account.amount = 1; + Account::pack(account, &mut account2_account.data).unwrap(); + + assert_eq!( + Err(TokenError::Overflow.into()), + do_process_instruction( + transfer( + &program_id, + &account2_key, + &account_key, + &owner2_key, + &[], + 1, + ) + .unwrap(), + vec![ + &mut account2_account, + &mut account_account, + &mut owner2_account, + ], + ) + ); + } + + #[test] + fn test_frozen() { + let program_id = crate::id(); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account2_key = Pubkey::new_unique(); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mut rent_sysvar = rent_sysvar(); + + // create new mint and fund first account + do_process_instruction( + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + // create account + do_process_instruction( + initialize_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&TOKEN_PROGRAM_ID, &account2_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account2_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // fund first account + do_process_instruction( + mint_to(&TOKEN_PROGRAM_ID, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + + // no transfer if either account is frozen + let mut account = Account::unpack_unchecked(&account2_account.data).unwrap(); + account.state = AccountState::Frozen; + Account::pack(account, &mut account2_account.data).unwrap(); + assert_eq!( + Err(TokenError::AccountFrozen.into()), + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &owner_key, + &[], + 500, + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner_account, + ], + ) + ); + + let mut account = Account::unpack_unchecked(&account_account.data).unwrap(); + account.state = AccountState::Initialized; + Account::pack(account, &mut account_account.data).unwrap(); + let mut account = Account::unpack_unchecked(&account2_account.data).unwrap(); + account.state = AccountState::Frozen; + Account::pack(account, &mut account2_account.data).unwrap(); + assert_eq!( + Err(TokenError::AccountFrozen.into()), + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &owner_key, + &[], + 500, + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner_account, + ], + ) + ); + + // no approve if account is frozen + let mut account = Account::unpack_unchecked(&account_account.data).unwrap(); + account.state = AccountState::Frozen; + Account::pack(account, &mut account_account.data).unwrap(); + let delegate_key = Pubkey::new_unique(); + let mut delegate_account = SolanaAccount::default(); + assert_eq!( + Err(TokenError::AccountFrozen.into()), + do_process_instruction( + approve( + &program_id, + &account_key, + &delegate_key, + &owner_key, + &[], + 100 + ) + .unwrap(), + vec![ + &mut account_account, + &mut delegate_account, + &mut owner_account, + ], + ) + ); + + // no revoke if account is frozen + let mut account = Account::unpack_unchecked(&account_account.data).unwrap(); + account.delegate = COption::Some(delegate_key); + account.delegated_amount = 100; + Account::pack(account, &mut account_account.data).unwrap(); + assert_eq!( + Err(TokenError::AccountFrozen.into()), + do_process_instruction( + revoke(&TOKEN_PROGRAM_ID, &account_key, &owner_key, &[]).unwrap(), + vec![&mut account_account, &mut owner_account], + ) + ); + + // no set authority if account is frozen + let new_owner_key = Pubkey::new_unique(); + assert_eq!( + Err(TokenError::AccountFrozen.into()), + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&new_owner_key), + AuthorityType::AccountOwner, + &owner_key, + &[] + ) + .unwrap(), + vec![&mut account_account, &mut owner_account,], + ) + ); + + // no mint_to if destination account is frozen + assert_eq!( + Err(TokenError::AccountFrozen.into()), + do_process_instruction( + mint_to(&TOKEN_PROGRAM_ID, &mint_key, &account_key, &owner_key, &[], 100).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account,], + ) + ); + + // no burn if account is frozen + assert_eq!( + Err(TokenError::AccountFrozen.into()), + do_process_instruction( + burn(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key, &[], 100).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + ); + } + + #[test] + fn test_freeze_thaw_dups() { + let program_id = crate::id(); + let account1_key = Pubkey::new_unique(); + let mut account1_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); + let owner_key = Pubkey::new_unique(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into(); + let rent_key = rent::id(); + let mut rent_sysvar = rent_sysvar(); + let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); + + // create mint + do_process_instruction_dups( + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, Some(&account1_key), 2).unwrap(), + vec![mint_info.clone(), rent_info.clone()], + ) + .unwrap(); + + // create account + do_process_instruction_dups( + initialize_account(&TOKEN_PROGRAM_ID, &account1_key, &mint_key, &account1_key).unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + + // freeze where mint freeze_authority is account + do_process_instruction_dups( + freeze_account(&TOKEN_PROGRAM_ID, &account1_key, &mint_key, &account1_key, &[]).unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // thaw where mint freeze_authority is account + let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); + account.state = AccountState::Frozen; + Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); + do_process_instruction_dups( + thaw_account(&TOKEN_PROGRAM_ID, &account1_key, &mint_key, &account1_key, &[]).unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + } + + #[test] + fn test_freeze_account() { + let program_id = crate::id(); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account_owner_key = Pubkey::new_unique(); + let mut account_owner_account = SolanaAccount::default(); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = Pubkey::new_unique(); + let mut owner2_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mut rent_sysvar = rent_sysvar(); + + // create new mint with owner different from account owner + do_process_instruction( + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + // create account + do_process_instruction( + initialize_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &account_owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut account_owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // mint to account + do_process_instruction( + mint_to(&TOKEN_PROGRAM_ID, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + + // mint cannot freeze + assert_eq!( + Err(TokenError::MintCannotFreeze.into()), + do_process_instruction( + freeze_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key, &[]).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + ); + + // missing freeze_authority + let mut mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); + mint.freeze_authority = COption::Some(owner_key); + Mint::pack(mint, &mut mint_account.data).unwrap(); + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + freeze_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner2_key, &[]).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner2_account], + ) + ); + + // check explicit thaw + assert_eq!( + Err(TokenError::InvalidState.into()), + do_process_instruction( + thaw_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner2_key, &[]).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner2_account], + ) + ); + + // freeze + do_process_instruction( + freeze_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key, &[]).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.state, AccountState::Frozen); + + // check explicit freeze + assert_eq!( + Err(TokenError::InvalidState.into()), + do_process_instruction( + freeze_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key, &[]).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + ); + + // check thaw authority + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + thaw_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner2_key, &[]).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner2_account], + ) + ); + + // thaw + do_process_instruction( + thaw_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key, &[]).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.state, AccountState::Initialized); + } + + #[test] + fn test_initialize_account2_and_3() { + let program_id = crate::id(); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let mut account3_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mut rent_sysvar = rent_sysvar(); + + // create mint + do_process_instruction( + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + do_process_instruction( + initialize_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + do_process_instruction( + initialize_account2(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), + vec![&mut account2_account, &mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + assert_eq!(account_account, account2_account); + + do_process_instruction( + initialize_account3(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), + vec![&mut account3_account, &mut mint_account], + ) + .unwrap(); + + assert_eq!(account_account, account3_account); + } + + #[test] + fn test_sync_native() { + let program_id = crate::id(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let native_account_key = Pubkey::new_unique(); + let lamports = 40; + let mut native_account = SolanaAccount::new( + account_minimum_balance() + lamports, + Account::get_packed_len(), + &program_id, + ); + let non_native_account_key = Pubkey::new_unique(); + let mut non_native_account = SolanaAccount::new( + account_minimum_balance() + 50, + Account::get_packed_len(), + &program_id, + ); + + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let mut rent_sysvar = rent_sysvar(); + + // initialize non-native mint + do_process_instruction( + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + // initialize non-native account + do_process_instruction( + initialize_account(&TOKEN_PROGRAM_ID, &non_native_account_key, &mint_key, &owner_key) + .unwrap(), + vec![ + &mut non_native_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + let account = Account::unpack_unchecked(&non_native_account.data).unwrap(); + assert!(!account.is_native()); + assert_eq!(account.amount, 0); + + // fail sync non-native + assert_eq!( + Err(TokenError::NonNativeNotSupported.into()), + do_process_instruction( + sync_native(&TOKEN_PROGRAM_ID, &non_native_account_key,).unwrap(), + vec![&mut non_native_account], + ) + ); + + // fail sync uninitialized + assert_eq!( + Err(ProgramError::UninitializedAccount), + do_process_instruction( + sync_native(&TOKEN_PROGRAM_ID, &native_account_key,).unwrap(), + vec![&mut native_account], + ) + ); + + // wrap native account + do_process_instruction( + initialize_account( + &program_id, + &native_account_key, + &crate::native_mint::id(), + &owner_key, + ) + .unwrap(), + vec![ + &mut native_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // fail sync, not owned by program + let not_program_id = Pubkey::new_unique(); + native_account.owner = not_program_id; + assert_eq!( + Err(ProgramError::IncorrectProgramId), + do_process_instruction( + sync_native(&TOKEN_PROGRAM_ID, &native_account_key,).unwrap(), + vec![&mut native_account], + ) + ); + native_account.owner = program_id; + + let account = Account::unpack_unchecked(&native_account.data).unwrap(); + assert!(account.is_native()); + assert_eq!(account.amount, lamports); + + // sync, no change + do_process_instruction( + sync_native(&TOKEN_PROGRAM_ID, &native_account_key).unwrap(), + vec![&mut native_account], + ) + .unwrap(); + let account = Account::unpack_unchecked(&native_account.data).unwrap(); + assert_eq!(account.amount, lamports); + + // transfer sol + let new_lamports = lamports + 50; + native_account.lamports = account_minimum_balance() + new_lamports; + + // success sync + do_process_instruction( + sync_native(&TOKEN_PROGRAM_ID, &native_account_key).unwrap(), + vec![&mut native_account], + ) + .unwrap(); + let account = Account::unpack_unchecked(&native_account.data).unwrap(); + assert_eq!(account.amount, new_lamports); + + // reduce sol + native_account.lamports -= 1; + + // fail sync + assert_eq!( + Err(TokenError::InvalidState.into()), + do_process_instruction( + sync_native(&TOKEN_PROGRAM_ID, &native_account_key,).unwrap(), + vec![&mut native_account], + ) + ); + } + + #[test] + #[serial] + fn test_get_account_data_size() { + // see integration tests for return-data validity + let program_id = crate::id(); + let owner_key = Pubkey::new_unique(); + let mut rent_sysvar = rent_sysvar(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint_key = Pubkey::new_unique(); + // fail if an invalid mint is passed in + assert_eq!( + Err(TokenError::InvalidMint.into()), + do_process_instruction( + get_account_data_size(&TOKEN_PROGRAM_ID, &mint_key).unwrap(), + vec![&mut mint_account], + ) + ); + + do_process_instruction( + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + set_expected_data(Account::LEN.to_le_bytes().to_vec()); + do_process_instruction( + get_account_data_size(&TOKEN_PROGRAM_ID, &mint_key).unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + } + + #[test] + fn test_initialize_immutable_owner() { + let program_id = crate::id(); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mut rent_sysvar = rent_sysvar(); + + // create mint + do_process_instruction( + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + // success initialize immutable + do_process_instruction( + initialize_immutable_owner(&TOKEN_PROGRAM_ID, &account_key).unwrap(), + vec![&mut account_account], + ) + .unwrap(); + + // create account + do_process_instruction( + initialize_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // fail post-init + assert_eq!( + Err(TokenError::AlreadyInUse.into()), + do_process_instruction( + initialize_immutable_owner(&TOKEN_PROGRAM_ID, &account_key).unwrap(), + vec![&mut account_account], + ) + ); + } + + #[test] + #[serial] + fn test_amount_to_ui_amount() { + let program_id = crate::id(); + let owner_key = Pubkey::new_unique(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mut rent_sysvar = rent_sysvar(); + + // fail if an invalid mint is passed in + assert_eq!( + Err(TokenError::InvalidMint.into()), + do_process_instruction( + amount_to_ui_amount(&TOKEN_PROGRAM_ID, &mint_key, 110).unwrap(), + vec![&mut mint_account], + ) + ); + + // create mint + do_process_instruction( + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + set_expected_data("0.23".as_bytes().to_vec()); + do_process_instruction( + amount_to_ui_amount(&TOKEN_PROGRAM_ID, &mint_key, 23).unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data("1.1".as_bytes().to_vec()); + do_process_instruction( + amount_to_ui_amount(&TOKEN_PROGRAM_ID, &mint_key, 110).unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data("42".as_bytes().to_vec()); + do_process_instruction( + amount_to_ui_amount(&TOKEN_PROGRAM_ID, &mint_key, 4200).unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data("0".as_bytes().to_vec()); + do_process_instruction( + amount_to_ui_amount(&TOKEN_PROGRAM_ID, &mint_key, 0).unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + } + + #[test] + #[serial] + fn test_ui_amount_to_amount() { + let program_id = crate::id(); + let owner_key = Pubkey::new_unique(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mut rent_sysvar = rent_sysvar(); + + // fail if an invalid mint is passed in + assert_eq!( + Err(TokenError::InvalidMint.into()), + do_process_instruction( + ui_amount_to_amount(&TOKEN_PROGRAM_ID, &mint_key, "1.1").unwrap(), + vec![&mut mint_account], + ) + ); + + // create mint + do_process_instruction( + initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + set_expected_data(23u64.to_le_bytes().to_vec()); + do_process_instruction( + ui_amount_to_amount(&TOKEN_PROGRAM_ID, &mint_key, "0.23").unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data(20u64.to_le_bytes().to_vec()); + do_process_instruction( + ui_amount_to_amount(&TOKEN_PROGRAM_ID, &mint_key, "0.20").unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data(20u64.to_le_bytes().to_vec()); + do_process_instruction( + ui_amount_to_amount(&TOKEN_PROGRAM_ID, &mint_key, "0.2000").unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data(20u64.to_le_bytes().to_vec()); + do_process_instruction( + ui_amount_to_amount(&TOKEN_PROGRAM_ID, &mint_key, ".20").unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data(110u64.to_le_bytes().to_vec()); + do_process_instruction( + ui_amount_to_amount(&TOKEN_PROGRAM_ID, &mint_key, "1.1").unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data(110u64.to_le_bytes().to_vec()); + do_process_instruction( + ui_amount_to_amount(&TOKEN_PROGRAM_ID, &mint_key, "1.10").unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data(4200u64.to_le_bytes().to_vec()); + do_process_instruction( + ui_amount_to_amount(&TOKEN_PROGRAM_ID, &mint_key, "42").unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data(4200u64.to_le_bytes().to_vec()); + do_process_instruction( + ui_amount_to_amount(&TOKEN_PROGRAM_ID, &mint_key, "42.").unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data(0u64.to_le_bytes().to_vec()); + do_process_instruction( + ui_amount_to_amount(&TOKEN_PROGRAM_ID, &mint_key, "0").unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + // fail if invalid ui_amount passed in + assert_eq!( + Err(ProgramError::InvalidArgument), + do_process_instruction( + ui_amount_to_amount(&TOKEN_PROGRAM_ID, &mint_key, "").unwrap(), + vec![&mut mint_account], + ) + ); + assert_eq!( + Err(ProgramError::InvalidArgument), + do_process_instruction( + ui_amount_to_amount(&TOKEN_PROGRAM_ID, &mint_key, ".").unwrap(), + vec![&mut mint_account], + ) + ); + assert_eq!( + Err(ProgramError::InvalidArgument), + do_process_instruction( + ui_amount_to_amount(&TOKEN_PROGRAM_ID, &mint_key, "0.111").unwrap(), + vec![&mut mint_account], + ) + ); + assert_eq!( + Err(ProgramError::InvalidArgument), + do_process_instruction( + ui_amount_to_amount(&TOKEN_PROGRAM_ID, &mint_key, "0.t").unwrap(), + vec![&mut mint_account], + ) + ); + } +*/ From 5b92af3c98c2a1da65c72c6c8f7868a9881f4953 Mon Sep 17 00:00:00 2001 From: febo Date: Sun, 29 Dec 2024 16:15:53 +0000 Subject: [PATCH 05/11] [wip]: Rename constant --- program/tests/processor.rs | 280 ++++++++++++++++++++++++++++++------- 1 file changed, 230 insertions(+), 50 deletions(-) diff --git a/program/tests/processor.rs b/program/tests/processor.rs index bad60b7d..feec2e23 100644 --- a/program/tests/processor.rs +++ b/program/tests/processor.rs @@ -33,10 +33,10 @@ const TOKEN_PROGRAM_NAME: &str = "spl_token"; /// The ID of the token program used in the instruction constructors. /// /// In general this should be the same as the `spl_token::id()` constant, since -/// the instruction construction functions are designed to work with the `spl_token`. -/// This value then is replaced by [`TARGET_TOKEN_PROGRAM_ID`] when the instruction -/// is processed by `mollusk`. -const TOKEN_PROGRAM_ID: Pubkey = spl_token::id(); +/// the instruction construction functions are designed to work with the +/// `spl_token`. This value then is replaced by [`TARGET_TOKEN_PROGRAM_ID`] when +/// the instruction is processed by `mollusk` helper. +const INSTRUCTION_TOKEN_PROGRAM_ID: Pubkey = spl_token::id(); /// The ID of the token program that will execute the instruction. const TARGET_TOKEN_PROGRAM_ID: Pubkey = spl_token::id(); @@ -152,7 +152,14 @@ fn test_initialize_mint() { // mint is not rent exempt do_process_instructions( &[( - initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + initialize_mint( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint_key, + &owner_key, + None, + 2, + ) + .unwrap(), vec![&mint_account, &rent_sysvar], )], &[Check::err(TokenError::NotRentExempt.into())], @@ -163,7 +170,14 @@ fn test_initialize_mint() { // create new mint do_process_instructions( &[( - initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + initialize_mint( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint_key, + &owner_key, + None, + 2, + ) + .unwrap(), vec![&mint_account, &rent_sysvar], )], &[Check::success()], @@ -173,11 +187,25 @@ fn test_initialize_mint() { do_process_instructions( &[ ( - initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + initialize_mint( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint_key, + &owner_key, + None, + 2, + ) + .unwrap(), vec![&mint_account, &rent_sysvar], ), ( - initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + initialize_mint( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint_key, + &owner_key, + None, + 2, + ) + .unwrap(), vec![&mint_account, &rent_sysvar], ), ], @@ -188,7 +216,7 @@ fn test_initialize_mint() { do_process_instructions( &[( initialize_mint( - &TOKEN_PROGRAM_ID, + &INSTRUCTION_TOKEN_PROGRAM_ID, &mint2_key, &owner_key, Some(&owner_key), @@ -225,7 +253,14 @@ fn test_initialize_mint2() { // mint is not rent exempt do_process_instructions( &[( - initialize_mint2(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + initialize_mint2( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint_key, + &owner_key, + None, + 2, + ) + .unwrap(), vec![&mint_account], )], &[Check::err(TokenError::NotRentExempt.into())], @@ -236,7 +271,14 @@ fn test_initialize_mint2() { // create new mint do_process_instructions( &[( - initialize_mint2(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + initialize_mint2( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint_key, + &owner_key, + None, + 2, + ) + .unwrap(), vec![&mint_account], )], &[Check::success()], @@ -246,11 +288,25 @@ fn test_initialize_mint2() { do_process_instructions( &[ ( - initialize_mint2(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + initialize_mint2( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint_key, + &owner_key, + None, + 2, + ) + .unwrap(), vec![&mint_account], ), ( - initialize_mint2(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + initialize_mint2( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint_key, + &owner_key, + None, + 2, + ) + .unwrap(), vec![&mint_account], ), ], @@ -261,7 +317,7 @@ fn test_initialize_mint2() { do_process_instructions( &[( initialize_mint2( - &TOKEN_PROGRAM_ID, + &INSTRUCTION_TOKEN_PROGRAM_ID, &mint2_key, &owner_key, Some(&owner_key), @@ -300,7 +356,13 @@ fn test_initialize_mint_account() { // account is not rent exempt do_process_instructions( &[( - initialize_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), + initialize_account( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &mint_key, + &owner_key, + ) + .unwrap(), vec![ &account_account, &mint_account, @@ -316,7 +378,13 @@ fn test_initialize_mint_account() { // mint is not valid (not initialized) do_process_instructions( &[( - initialize_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), + initialize_account( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &mint_key, + &owner_key, + ) + .unwrap(), vec![ &account_account, &mint_account, @@ -330,7 +398,14 @@ fn test_initialize_mint_account() { // create mint do_process_instructions( &[( - initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + initialize_mint( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint_key, + &owner_key, + None, + 2, + ) + .unwrap(), vec![&mint_account, &rent_sysvar], )], &[Check::success()], @@ -342,7 +417,13 @@ fn test_initialize_mint_account() { do_process_instructions( &[( - initialize_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), + initialize_account( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &mint_key, + &owner_key, + ) + .unwrap(), vec![ &account_account, &mint_account, @@ -359,11 +440,24 @@ fn test_initialize_mint_account() { do_process_instructions( &[ ( - initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + initialize_mint( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint_key, + &owner_key, + None, + 2, + ) + .unwrap(), vec![&mint_account, &rent_sysvar], ), ( - initialize_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), + initialize_account( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &mint_key, + &owner_key, + ) + .unwrap(), vec![ &account_account, &mint_account, @@ -379,11 +473,24 @@ fn test_initialize_mint_account() { do_process_instructions( &[ ( - initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + initialize_mint( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint_key, + &owner_key, + None, + 2, + ) + .unwrap(), vec![&mint_account, &rent_sysvar], ), ( - initialize_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), + initialize_account( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &mint_key, + &owner_key, + ) + .unwrap(), vec![ &account_account, &mint_account, @@ -392,7 +499,13 @@ fn test_initialize_mint_account() { ], ), ( - initialize_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), + initialize_account( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &mint_key, + &owner_key, + ) + .unwrap(), vec![ &account_account, &mint_account, @@ -414,35 +527,40 @@ fn test_transfer_dups() { Account::get_packed_len(), &program_id, ); - //let mut account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); + //let mut account1_info: AccountInfo = (&account1_key, true, &mut + // account1_account).into(); let account2_key = Pubkey::new_unique(); let account2_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); - //let mut account2_info: AccountInfo = (&account2_key, false, &mut account2_account).into(); + //let mut account2_info: AccountInfo = (&account2_key, false, &mut + // account2_account).into(); let account3_key = Pubkey::new_unique(); let account3_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); - //let account3_info: AccountInfo = (&account3_key, false, &mut account3_account).into(); + //let account3_info: AccountInfo = (&account3_key, false, &mut + // account3_account).into(); let account4_key = Pubkey::new_unique(); let account4_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); - //let account4_info: AccountInfo = (&account4_key, true, &mut account4_account).into(); + //let account4_info: AccountInfo = (&account4_key, true, &mut + // account4_account).into(); let multisig_key = Pubkey::new_unique(); let multisig_account = SolanaAccount::new( multisig_minimum_balance(), Multisig::get_packed_len(), &program_id, ); - //let multisig_info: AccountInfo = (&multisig_key, true, &mut multisig_account).into(); + //let multisig_info: AccountInfo = (&multisig_key, true, &mut + // multisig_account).into(); let owner_key = Pubkey::new_unique(); let owner_account = SolanaAccount::default(); //let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into(); @@ -457,12 +575,25 @@ fn test_transfer_dups() { let setup_instructions = vec![ // create mint ( - initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + initialize_mint( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint_key, + &owner_key, + None, + 2, + ) + .unwrap(), vec![&mint_account, &rent_sysvar], ), // create account ( - initialize_account(&TOKEN_PROGRAM_ID, &account1_key, &mint_key, &account1_key).unwrap(), + initialize_account( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account1_key, + &mint_key, + &account1_key, + ) + .unwrap(), vec![ &account1_account, &mint_account, @@ -472,7 +603,13 @@ fn test_transfer_dups() { ), // create another account ( - initialize_account(&TOKEN_PROGRAM_ID, &account2_key, &mint_key, &owner_key).unwrap(), + initialize_account( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account2_key, + &mint_key, + &owner_key, + ) + .unwrap(), vec![ &account2_account, &mint_account, @@ -483,7 +620,7 @@ fn test_transfer_dups() { // mint to account ( mint_to( - &TOKEN_PROGRAM_ID, + &INSTRUCTION_TOKEN_PROGRAM_ID, &mint_key, &account1_key, &owner_key, @@ -604,8 +741,13 @@ fn test_transfer_dups() { Some(&setup_instructions), &[ ( - initialize_account(&TOKEN_PROGRAM_ID, &account3_key, &mint_key, &account2_key) - .unwrap(), + initialize_account( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account3_key, + &mint_key, + &account2_key, + ) + .unwrap(), vec![ &account3_account, &mint_account, @@ -615,7 +757,7 @@ fn test_transfer_dups() { ), ( mint_to( - &TOKEN_PROGRAM_ID, + &INSTRUCTION_TOKEN_PROGRAM_ID, &mint_key, &account3_key, &owner_key, @@ -646,8 +788,13 @@ fn test_transfer_dups() { Some(&setup_instructions), &[ ( - initialize_account(&TOKEN_PROGRAM_ID, &account3_key, &mint_key, &account2_key) - .unwrap(), + initialize_account( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account3_key, + &mint_key, + &account2_key, + ) + .unwrap(), vec![ &account3_account, &mint_account, @@ -657,7 +804,7 @@ fn test_transfer_dups() { ), ( mint_to( - &TOKEN_PROGRAM_ID, + &INSTRUCTION_TOKEN_PROGRAM_ID, &mint_key, &account3_key, &owner_key, @@ -695,12 +842,23 @@ fn test_transfer_dups() { Some(&setup_instructions), &[ ( - initialize_multisig(&TOKEN_PROGRAM_ID, &multisig_key, &[&account4_key], 1).unwrap(), + initialize_multisig( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &multisig_key, + &[&account4_key], + 1, + ) + .unwrap(), vec![&multisig_account, &rent_sysvar, &account4_account], ), ( - initialize_account(&TOKEN_PROGRAM_ID, &account4_key, &mint_key, &multisig_key) - .unwrap(), + initialize_account( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account4_key, + &mint_key, + &multisig_key, + ) + .unwrap(), vec![ &account4_account, &mint_account, @@ -710,7 +868,7 @@ fn test_transfer_dups() { ), ( mint_to( - &TOKEN_PROGRAM_ID, + &INSTRUCTION_TOKEN_PROGRAM_ID, &mint_key, &account4_key, &owner_key, @@ -729,12 +887,23 @@ fn test_transfer_dups() { Some(&setup_instructions), &[ ( - initialize_multisig(&TOKEN_PROGRAM_ID, &multisig_key, &[&account4_key], 1).unwrap(), + initialize_multisig( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &multisig_key, + &[&account4_key], + 1, + ) + .unwrap(), vec![&multisig_account, &rent_sysvar, &account4_account], ), ( - initialize_account(&TOKEN_PROGRAM_ID, &account4_key, &mint_key, &multisig_key) - .unwrap(), + initialize_account( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account4_key, + &mint_key, + &multisig_key, + ) + .unwrap(), vec![ &account4_account, &mint_account, @@ -744,7 +913,7 @@ fn test_transfer_dups() { ), ( mint_to( - &TOKEN_PROGRAM_ID, + &INSTRUCTION_TOKEN_PROGRAM_ID, &mint_key, &account4_key, &owner_key, @@ -780,12 +949,23 @@ fn test_transfer_dups() { Some(&setup_instructions), &[ ( - initialize_multisig(&TOKEN_PROGRAM_ID, &multisig_key, &[&account4_key], 1).unwrap(), + initialize_multisig( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &multisig_key, + &[&account4_key], + 1, + ) + .unwrap(), vec![&multisig_account, &rent_sysvar, &account4_account], ), ( - initialize_account(&TOKEN_PROGRAM_ID, &account4_key, &mint_key, &multisig_key) - .unwrap(), + initialize_account( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account4_key, + &mint_key, + &multisig_key, + ) + .unwrap(), vec![ &account4_account, &mint_account, @@ -795,7 +975,7 @@ fn test_transfer_dups() { ), ( mint_to( - &TOKEN_PROGRAM_ID, + &INSTRUCTION_TOKEN_PROGRAM_ID, &mint_key, &account4_key, &owner_key, From 1ef653f63c42d27b456d84d426c0cb6825a27754 Mon Sep 17 00:00:00 2001 From: febo Date: Mon, 6 Jan 2025 22:04:36 +0000 Subject: [PATCH 06/11] [wip]: Transfer tests --- program/tests/processor.rs | 889 ++++++++++++++++++++++++------------- 1 file changed, 587 insertions(+), 302 deletions(-) diff --git a/program/tests/processor.rs b/program/tests/processor.rs index feec2e23..5c30503d 100644 --- a/program/tests/processor.rs +++ b/program/tests/processor.rs @@ -19,8 +19,8 @@ use { spl_token::{ error::TokenError, instruction::{ - initialize_account, initialize_mint, initialize_mint2, initialize_multisig, mint_to, - transfer, transfer_checked, + approve, initialize_account, initialize_mint, initialize_mint2, initialize_multisig, + mint_to, transfer, transfer_checked, }, state::{Account, AccountState, Mint, Multisig}, }, @@ -1009,57 +1009,70 @@ fn test_transfer_dups() { &[Check::success()], ); } -/* + #[test] fn test_transfer() { let program_id = TARGET_TOKEN_PROGRAM_ID; let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( + let account_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( + let account2_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); let account3_key = Pubkey::new_unique(); - let mut account3_account = SolanaAccount::new( + let account3_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); let delegate_key = Pubkey::new_unique(); - let mut delegate_account = SolanaAccount::default(); + let delegate_account = SolanaAccount::default(); let mismatch_key = Pubkey::new_unique(); - let mut mismatch_account = SolanaAccount::new( + let mismatch_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); + let owner_account = SolanaAccount::default(); let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); + let owner2_account = SolanaAccount::default(); let mint_key = Pubkey::new_unique(); - let mut mint_account = + let mint_account = SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); let mint2_key = Pubkey::new_unique(); - let mut mint2_account = + let mint2_account = SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); + let rent_sysvar = rent_sysvar(); let setup_instructions = vec![ // create mint ( - initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), + initialize_mint( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint_key, + &owner_key, + None, + 2, + ) + .unwrap(), vec![&mint_account, &rent_sysvar], ), // create account ( - initialize_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), + initialize_account( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &mint_key, + &owner_key, + ) + .unwrap(), vec![ &account_account, &mint_account, @@ -1069,7 +1082,13 @@ fn test_transfer() { ), // create another account ( - initialize_account(&TOKEN_PROGRAM_ID, &account2_key, &mint_key, &owner_key).unwrap(), + initialize_account( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account2_key, + &mint_key, + &owner_key, + ) + .unwrap(), vec![ &account2_account, &mint_account, @@ -1079,7 +1098,13 @@ fn test_transfer() { ), // create another account ( - initialize_account(&TOKEN_PROGRAM_ID, &account3_key, &mint_key, &owner_key).unwrap(), + initialize_account( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account3_key, + &mint_key, + &owner_key, + ) + .unwrap(), vec![ &account3_account, &mint_account, @@ -1090,7 +1115,7 @@ fn test_transfer() { // mint to account ( mint_to( - &TOKEN_PROGRAM_ID, + &INSTRUCTION_TOKEN_PROGRAM_ID, &mint_key, &account_key, &owner_key, @@ -1102,12 +1127,25 @@ fn test_transfer() { ), // create a second mint ( - initialize_mint(&TOKEN_PROGRAM_ID, &mint2_key, &owner_key, None, 2).unwrap(), + initialize_mint( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint2_key, + &owner_key, + None, + 2, + ) + .unwrap(), vec![&mint2_account, &rent_sysvar], ), // create mismatch account using mint2 ( - initialize_account(&TOKEN_PROGRAM_ID, &mismatch_key, &mint2_key, &owner_key).unwrap(), + initialize_account( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mismatch_key, + &mint2_key, + &owner_key, + ) + .unwrap(), vec![ &mismatch_account, &mint2_account, @@ -1119,7 +1157,7 @@ fn test_transfer() { // missing signer let mut instruction = transfer( - &TOKEN_PROGRAM_ID, + &INSTRUCTION_TOKEN_PROGRAM_ID, &account_key, &account2_key, &owner_key, @@ -1142,7 +1180,7 @@ fn test_transfer() { Some(&setup_instructions), &[( transfer( - &TOKEN_PROGRAM_ID, + &INSTRUCTION_TOKEN_PROGRAM_ID, &account_key, &mismatch_key, &owner_key, @@ -1160,7 +1198,7 @@ fn test_transfer() { Some(&setup_instructions), &[( transfer( - &TOKEN_PROGRAM_ID, + &INSTRUCTION_TOKEN_PROGRAM_ID, &account_key, &account2_key, &owner2_key, @@ -1174,363 +1212,610 @@ fn test_transfer() { ); // account not owned by program - let not_program_id = Pubkey::new_unique(); - let mut not_program_id_account = account_account.clone(); - not_program_id_account.owner = not_program_id; + let not_program_key = Pubkey::new_unique(); + let mut account = Account::unpack_unchecked(&account_account.data).unwrap(); + account.state = AccountState::Initialized; + account.mint = mint_key; + account.owner = owner_key; + let mut not_program_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + ¬_program_key, + ); + Account::pack(account, &mut not_program_account.data).unwrap(); do_process_instructions_with_pre_instructions( Some(&setup_instructions), &[( transfer( - &TOKEN_PROGRAM_ID, - ¬_program_id, + &INSTRUCTION_TOKEN_PROGRAM_ID, + ¬_program_key, &account2_key, &owner_key, &[], 0, ) .unwrap(), - vec![¬_program_id_account, &account2_account, &owner2_account], + vec![¬_program_account, &account2_account, &owner2_account], )], &[Check::err(ProgramError::IncorrectProgramId)], ); - //account_account.owner = program_id; // account 2 not owned by program - let not_program_id = Pubkey::new_unique(); - account2_account.owner = not_program_id; - assert_eq!( - Err(ProgramError::IncorrectProgramId), - do_process_instruction( + let mut account2 = Account::unpack_unchecked(&account_account.data).unwrap(); + account2.state = AccountState::Initialized; + account2.mint = mint_key; + account2.owner = owner_key; + let mut not_program_account2 = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + ¬_program_key, + ); + Account::pack(account2, &mut not_program_account2.data).unwrap(); + + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( transfer( - &TOKEN_PROGRAM_ID, + &INSTRUCTION_TOKEN_PROGRAM_ID, &account_key, - &account2_key, + ¬_program_key, &owner_key, &[], 0, ) .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner2_account, - ], - ) + vec![&account_account, ¬_program_account2, &owner2_account], + )], + &[Check::err(ProgramError::IncorrectProgramId)], ); - account2_account.owner = program_id; // transfer - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &owner_key, - &[], - 1000, - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner_account, - ], - ) - .unwrap(); - - // insufficient funds - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - do_process_instruction( + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( transfer( - &TOKEN_PROGRAM_ID, - &account_key, - &account2_key, - &owner_key, - &[], - 1 - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner_account, - ], - ) - ); - - // transfer half back - do_process_instruction( - transfer( - &program_id, - &account2_key, - &account_key, - &owner_key, - &[], - 500, - ) - .unwrap(), - vec![ - &mut account2_account, - &mut account_account, - &mut owner_account, - ], - ) - .unwrap(); - - // incorrect decimals - assert_eq!( - Err(TokenError::MintDecimalsMismatch.into()), - do_process_instruction( - transfer_checked( - &program_id, - &account2_key, - &mint_key, + &INSTRUCTION_TOKEN_PROGRAM_ID, &account_key, - &owner_key, - &[], - 1, - 10 // <-- incorrect decimals - ) - .unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut account_account, - &mut owner_account, - ], - ) - ); - - // incorrect mint - assert_eq!( - Err(TokenError::MintMismatch.into()), - do_process_instruction( - transfer_checked( - &program_id, &account2_key, - &account3_key, // <-- incorrect mint - &account_key, &owner_key, &[], - 1, - 2 + 1000, ) .unwrap(), - vec![ - &mut account2_account, - &mut account3_account, // <-- incorrect mint - &mut account_account, - &mut owner_account, - ], - ) + vec![&account_account, &account2_account, &owner_account], + )], + &[Check::success()], ); - // transfer rest with explicit decimals - do_process_instruction( - transfer_checked( - &program_id, - &account2_key, - &mint_key, - &account_key, - &owner_key, - &[], - 500, - 2, - ) - .unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut account_account, - &mut owner_account, - ], - ) - .unwrap(); // insufficient funds - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - do_process_instruction( + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( transfer( - &TOKEN_PROGRAM_ID, - &account2_key, + &INSTRUCTION_TOKEN_PROGRAM_ID, &account_key, + &account2_key, &owner_key, &[], - 1 + 1001, ) .unwrap(), - vec![ - &mut account2_account, - &mut account_account, - &mut owner_account, - ], - ) + vec![&account_account, &account2_account, &owner_account], + )], + &[Check::err(TokenError::InsufficientFunds.into())], ); - // approve delegate - do_process_instruction( - approve( - &program_id, - &account_key, - &delegate_key, - &owner_key, - &[], - 100, - ) - .unwrap(), - vec![ - &mut account_account, - &mut delegate_account, - &mut owner_account, + // transfer half back + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[ + ( + transfer( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &account2_key, + &owner_key, + &[], + 1000, + ) + .unwrap(), + vec![&account_account, &account2_account, &owner_account], + ), + ( + transfer( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account2_key, + &account_key, + &owner_key, + &[], + 500, + ) + .unwrap(), + vec![&account2_account, &account_account, &owner_account], + ), ], - ) - .unwrap(); + &[Check::success()], + ); - // not a delegate of source account - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &owner2_key, // <-- incorrect owner or delegate - &[], - 1, - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner2_account, - ], - ) + // incorrect decimals + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[ + ( + transfer( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &account2_key, + &owner_key, + &[], + 1000, + ) + .unwrap(), + vec![&account_account, &account2_account, &owner_account], + ), + ( + transfer_checked( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account2_key, + &mint_key, + &account_key, + &owner_key, + &[], + 1, + 10, // <-- incorrect decimals + ) + .unwrap(), + vec![ + &account2_account, + &mint_account, + &account_account, + &owner_account, + ], + ), + ], + &[Check::err(TokenError::MintDecimalsMismatch.into())], ); - // insufficient funds approved via delegate + // incorrect mint + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[ + ( + transfer( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &account2_key, + &owner_key, + &[], + 1000, + ) + .unwrap(), + vec![&account_account, &account2_account, &owner_account], + ), + ( + transfer_checked( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account2_key, + &account3_key, // <-- incorrect mint + &account_key, + &owner_key, + &[], + 1, + 2, + ) + .unwrap(), + vec![ + &account2_account, + &account3_account, // <-- incorrect mint + &account_account, + &owner_account, + ], + ), + ], + &[Check::err(TokenError::MintMismatch.into())], + ); + + // transfer rest with explicit decimals + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[ + ( + transfer( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &account2_key, + &owner_key, + &[], + 1000, + ) + .unwrap(), + vec![&account_account, &account2_account, &owner_account], + ), + ( + transfer( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account2_key, + &account_key, + &owner_key, + &[], + 500, + ) + .unwrap(), + vec![&account2_account, &account_account, &owner_account], + ), + ( + transfer_checked( + &program_id, + &account2_key, + &mint_key, + &account_key, + &owner_key, + &[], + 500, + 2, + ) + .unwrap(), + vec![ + &account2_account, + &mint_account, + &account_account, + &owner_account, + ], + ), + ], + &[Check::success()], + ); + /* TODO: seems to be done already + // insufficient funds assert_eq!( Err(TokenError::InsufficientFunds.into()), do_process_instruction( transfer( - &program_id, - &account_key, + &TOKEN_PROGRAM_ID, &account2_key, - &delegate_key, + &account_key, + &owner_key, &[], - 101 + 1 ) .unwrap(), vec![ - &mut account_account, &mut account2_account, - &mut delegate_account, + &mut account_account, + &mut owner_account, ], ) ); + */ - // transfer via delegate - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &delegate_key, - &[], - 100, - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut delegate_account, - ], - ) - .unwrap(); - - // insufficient funds approved via delegate - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - transfer( - &program_id, + // approve delegate + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + approve( + &INSTRUCTION_TOKEN_PROGRAM_ID, &account_key, - &account2_key, &delegate_key, + &owner_key, &[], - 1 + 100, ) .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut delegate_account, - ], - ) + vec![&account_account, &delegate_account, &owner_account], + )], + &[Check::success()], + ); + + // not a delegate of source account + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[ + ( + approve( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, + ) + .unwrap(), + vec![&account_account, &delegate_account, &owner_account], + ), + ( + transfer( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &account2_key, + &owner2_key, // <-- incorrect owner or delegate + &[], + 1, + ) + .unwrap(), + vec![&account_account, &account2_account, &owner2_account], + ), + ], + &[Check::err(TokenError::OwnerMismatch.into())], + ); + + // insufficient funds approved via delegate + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[ + ( + approve( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, + ) + .unwrap(), + vec![&account_account, &delegate_account, &owner_account], + ), + ( + transfer( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &account2_key, + &delegate_key, + &[], + 101, + ) + .unwrap(), + vec![&account_account, &account2_account, &delegate_account], + ), + ], + &[Check::err(TokenError::InsufficientFunds.into())], + ); + + // transfer via delegate + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[ + ( + approve( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, + ) + .unwrap(), + vec![&account_account, &delegate_account, &owner_account], + ), + ( + transfer( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &account2_key, + &delegate_key, + &[], + 100, + ) + .unwrap(), + vec![&account_account, &account2_account, &delegate_account], + ), + ], + &[Check::success()], + ); + + // insufficient funds approved via delegate + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[ + ( + approve( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, + ) + .unwrap(), + vec![&account_account, &delegate_account, &owner_account], + ), + ( + transfer( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &account2_key, + &delegate_key, + &[], + 100, + ) + .unwrap(), + vec![&account_account, &account2_account, &delegate_account], + ), + ( + transfer( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &account2_key, + &delegate_key, + &[], + 1, + ) + .unwrap(), + vec![&account_account, &account2_account, &delegate_account], + ), + ], + &[Check::err(TokenError::OwnerMismatch.into())], ); // transfer rest - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &owner_key, - &[], - 900, - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner_account, + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[ + ( + approve( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, + ) + .unwrap(), + vec![&account_account, &delegate_account, &owner_account], + ), + ( + transfer( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &account2_key, + &delegate_key, + &[], + 100, + ) + .unwrap(), + vec![&account_account, &account2_account, &delegate_account], + ), + ( + transfer( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &account2_key, + &owner_key, + &[], + 900, + ) + .unwrap(), + vec![&account_account, &account2_account, &owner_account], + ), ], - ) - .unwrap(); + &[Check::success()], + ); // approve delegate - do_process_instruction( - approve( - &program_id, - &account_key, - &delegate_key, - &owner_key, - &[], - 100, - ) - .unwrap(), - vec![ - &mut account_account, - &mut delegate_account, - &mut owner_account, + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[ + ( + approve( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, + ) + .unwrap(), + vec![&account_account, &delegate_account, &owner_account], + ), + ( + transfer( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &account2_key, + &delegate_key, + &[], + 100, + ) + .unwrap(), + vec![&account_account, &account2_account, &delegate_account], + ), + ( + transfer( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &account2_key, + &owner_key, + &[], + 900, + ) + .unwrap(), + vec![&account_account, &account2_account, &owner_account], + ), + ( + approve( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, + ) + .unwrap(), + vec![&account_account, &delegate_account, &owner_account], + ), ], - ) - .unwrap(); + &[Check::success()], + ); // insufficient funds in source account via delegate - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &delegate_key, - &[], - 100 - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut delegate_account, - ], - ) + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[ + ( + approve( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, + ) + .unwrap(), + vec![&account_account, &delegate_account, &owner_account], + ), + ( + transfer( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &account2_key, + &delegate_key, + &[], + 100, + ) + .unwrap(), + vec![&account_account, &account2_account, &delegate_account], + ), + ( + transfer( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &account2_key, + &owner_key, + &[], + 900, + ) + .unwrap(), + vec![&account_account, &account2_account, &owner_account], + ), + ( + approve( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, + ) + .unwrap(), + vec![&account_account, &delegate_account, &owner_account], + ), + ( + transfer( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &account2_key, + &delegate_key, + &[], + 100, + ) + .unwrap(), + vec![&account_account, &account2_account, &delegate_account], + ), + ], + &[Check::err(TokenError::InsufficientFunds.into())], ); - } - +/* #[test] fn test_self_transfer() { let program_id = crate::id(); From 6496adccaac30077a4db03a0dee61e420c14e55d Mon Sep 17 00:00:00 2001 From: febo Date: Mon, 6 Jan 2025 22:24:11 +0000 Subject: [PATCH 07/11] [wip]: Update mollusk git reference --- Cargo.lock | 6 +++--- program/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 37fea2dd..e98547a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1559,7 +1559,7 @@ dependencies = [ [[package]] name = "mollusk-svm" version = "0.0.13" -source = "git+https://github.com/febo/mollusk.git?branch=data-slice-check#ab5d8157fd4d1dc2bd66c23fe516e3b6e7d8d6cd" +source = "git+https://github.com/buffalojoec/mollusk.git#c01523016195c315870bd9e4bfa3a64a6cffa659" dependencies = [ "bincode", "mollusk-svm-error", @@ -1576,7 +1576,7 @@ dependencies = [ [[package]] name = "mollusk-svm-error" version = "0.0.13" -source = "git+https://github.com/febo/mollusk.git?branch=data-slice-check#ab5d8157fd4d1dc2bd66c23fe516e3b6e7d8d6cd" +source = "git+https://github.com/buffalojoec/mollusk.git#c01523016195c315870bd9e4bfa3a64a6cffa659" dependencies = [ "solana-sdk", "thiserror 1.0.69", @@ -1585,7 +1585,7 @@ dependencies = [ [[package]] name = "mollusk-svm-keys" version = "0.0.13" -source = "git+https://github.com/febo/mollusk.git?branch=data-slice-check#ab5d8157fd4d1dc2bd66c23fe516e3b6e7d8d6cd" +source = "git+https://github.com/buffalojoec/mollusk.git#c01523016195c315870bd9e4bfa3a64a6cffa659" dependencies = [ "mollusk-svm-error", "solana-sdk", diff --git a/program/Cargo.toml b/program/Cargo.toml index f648045d..66123c27 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -22,7 +22,7 @@ thiserror = "2.0" [dev-dependencies] lazy_static = "1.5.0" -mollusk-svm = { version = "0.0.13", git = "https://github.com/febo/mollusk.git", branch = "data-slice-check" } +mollusk-svm = { version = "0.0.13", git = "https://github.com/buffalojoec/mollusk.git" } proptest = "1.5" serial_test = "3.2.0" solana-sdk = "2.1.0" From cfe754fe1cfdf17cacdd9fae10ab9c26ea3e519f Mon Sep 17 00:00:00 2001 From: febo Date: Tue, 7 Jan 2025 00:50:12 +0000 Subject: [PATCH 08/11] [wip]: Self transfer tests --- program/tests/processor.rs | 1056 +++++++++++++++++++----------------- 1 file changed, 567 insertions(+), 489 deletions(-) diff --git a/program/tests/processor.rs b/program/tests/processor.rs index 5c30503d..5ed6ea94 100644 --- a/program/tests/processor.rs +++ b/program/tests/processor.rs @@ -1466,7 +1466,7 @@ fn test_transfer() { ], &[Check::success()], ); - /* TODO: seems to be done already + /* TODO: seems to be tested already // insufficient funds assert_eq!( Err(TokenError::InsufficientFunds.into()), @@ -1815,537 +1815,615 @@ fn test_transfer() { &[Check::err(TokenError::InsufficientFunds.into())], ); } -/* - #[test] - fn test_self_transfer() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account3_key = Pubkey::new_unique(); - let mut account3_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let delegate_key = Pubkey::new_unique(); - let mut delegate_account = SolanaAccount::default(); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - // create mint - do_process_instruction( - initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); +#[test] +fn test_self_transfer() { + let program_id = TARGET_TOKEN_PROGRAM_ID; + let account_key = Pubkey::new_unique(); + let account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account2_key = Pubkey::new_unique(); + let account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account3_key = Pubkey::new_unique(); + let account3_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let delegate_key = Pubkey::new_unique(); + let delegate_account = SolanaAccount::default(); + let owner_key = Pubkey::new_unique(); + let owner_account = SolanaAccount::default(); + let owner2_key = Pubkey::new_unique(); + let owner2_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let rent_sysvar = rent_sysvar(); + let setup_instructions = vec![ + // create mint + ( + initialize_mint( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint_key, + &owner_key, + None, + 2, + ) + .unwrap(), + vec![&mint_account, &rent_sysvar], + ), // create account - do_process_instruction( - initialize_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), + ( + initialize_account( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &mint_key, + &owner_key, + ) + .unwrap(), vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, + &account_account, + &mint_account, + &owner_account, + &rent_sysvar, ], - ) - .unwrap(); - + ), // create another account - do_process_instruction( - initialize_account(&TOKEN_PROGRAM_ID, &account2_key, &mint_key, &owner_key).unwrap(), + ( + initialize_account( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account2_key, + &mint_key, + &owner_key, + ) + .unwrap(), vec![ - &mut account2_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, + &account2_account, + &mint_account, + &owner_account, + &rent_sysvar, ], - ) - .unwrap(); - + ), // create another account - do_process_instruction( - initialize_account(&TOKEN_PROGRAM_ID, &account3_key, &mint_key, &owner_key).unwrap(), + ( + initialize_account( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account3_key, + &mint_key, + &owner_key, + ) + .unwrap(), vec![ - &mut account3_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, + &account3_account, + &mint_account, + &owner_account, + &rent_sysvar, ], - ) - .unwrap(); - + ), // mint to account - do_process_instruction( - mint_to(&TOKEN_PROGRAM_ID, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - - let account_info = (&account_key, false, &mut account_account).into_account_info(); - let account3_info = (&account3_key, false, &mut account3_account).into_account_info(); - let delegate_info = (&delegate_key, true, &mut delegate_account).into_account_info(); - let owner_info = (&owner_key, true, &mut owner_account).into_account_info(); - let owner2_info = (&owner2_key, true, &mut owner2_account).into_account_info(); - let mint_info = (&mint_key, false, &mut mint_account).into_account_info(); + ( + mint_to( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint_key, + &account_key, + &owner_key, + &[], + 1000, + ) + .unwrap(), + vec![&mint_account, &account_account, &owner_account], + ), + ]; - // transfer - let instruction = transfer( - &program_id, - account_info.key, - account_info.key, - owner_info.key, - &[], - 1000, - ) - .unwrap(); - assert_eq!( - Ok(()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - account_info.clone(), - owner_info.clone(), - ], - &instruction.data, + // transfer + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + transfer( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &account_key, + &owner_key, + &[], + 1000, ) - ); + .unwrap(), + vec![&account_account, &account_account, &owner_account], + )], // no balance change... - let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); - assert_eq!(account.amount, 1000); + &[ + Check::success(), + Check::account(&account_key) + .data_slice(64, &1000u64.to_le_bytes()) + .build(), + ], + ); - // transfer checked - let instruction = transfer_checked( - &program_id, - account_info.key, - mint_info.key, - account_info.key, - owner_info.key, - &[], - 1000, - 2, - ) - .unwrap(); - assert_eq!( - Ok(()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - mint_info.clone(), - account_info.clone(), - owner_info.clone(), - ], - &instruction.data, + // transfer checked + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + transfer_checked( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &mint_key, + &account_key, + &owner_key, + &[], + 1000, + 2, ) - ); + .unwrap(), + vec![ + &account_account, + &mint_account, + &account_account, + &owner_account, + ], + )], // no balance change... - let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); - assert_eq!(account.amount, 1000); + &[ + Check::success(), + Check::account(&account_key) + .data_slice(64, &1000u64.to_le_bytes()) + .build(), + ], + ); - // missing signer - let mut owner_no_sign_info = owner_info.clone(); - let mut instruction = transfer( - &program_id, - account_info.key, - account_info.key, - owner_no_sign_info.key, - &[], - 1000, - ) - .unwrap(); - instruction.accounts[2].is_signer = false; - owner_no_sign_info.is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - account_info.clone(), - owner_no_sign_info.clone(), - ], - &instruction.data, - ) - ); + // missing signer + let mut instruction = transfer( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &account_key, + &owner_key, + &[], + 1000, + ) + .unwrap(); + instruction.accounts[2].is_signer = false; + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + instruction, + vec![&account_account, &account_account, &owner_account], + )], + &[Check::err(ProgramError::MissingRequiredSignature)], + ); - // missing signer checked - let mut instruction = transfer_checked( - &program_id, - account_info.key, - mint_info.key, - account_info.key, - owner_no_sign_info.key, - &[], - 1000, - 2, - ) - .unwrap(); - instruction.accounts[3].is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - mint_info.clone(), - account_info.clone(), - owner_no_sign_info, - ], - &instruction.data, - ) - ); + // missing signer checked + let mut instruction = transfer_checked( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &mint_key, + &account_key, + &owner_key, + &[], + 1000, + 2, + ) + .unwrap(); + instruction.accounts[3].is_signer = false; + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + instruction, + vec![ + &account_account, + &mint_account, + &account_account, + &owner_account, + ], + )], + &[Check::err(ProgramError::MissingRequiredSignature)], + ); - // missing owner - let instruction = transfer( - &program_id, - account_info.key, - account_info.key, - owner2_info.key, - &[], - 1000, - ) - .unwrap(); - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - account_info.clone(), - owner2_info.clone(), - ], - &instruction.data, + // missing owner + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + transfer( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &account_key, + &owner2_key, + &[], + 1000, ) - ); + .unwrap(), + vec![&account_account, &account_account, &owner2_account], + )], + &[Check::err(TokenError::OwnerMismatch.into())], + ); - // missing owner checked - let instruction = transfer_checked( - &program_id, - account_info.key, - mint_info.key, - account_info.key, - owner2_info.key, - &[], - 1000, - 2, - ) - .unwrap(); - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - mint_info.clone(), - account_info.clone(), - owner2_info.clone(), - ], - &instruction.data, + // missing owner checked + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + transfer_checked( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &mint_key, + &account_key, + &owner2_key, + &[], + 1000, + 2, ) - ); + .unwrap(), + vec![ + &account_account, + &mint_account, + &account_account, + &owner2_account, + ], + )], + &[Check::err(TokenError::OwnerMismatch.into())], + ); - // insufficient funds - let instruction = transfer( - &program_id, - account_info.key, - account_info.key, - owner_info.key, - &[], - 1001, - ) - .unwrap(); - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - account_info.clone(), - owner_info.clone(), - ], - &instruction.data, + // insufficient funds + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + transfer( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &account_key, + &owner2_key, + &[], + 1001, ) - ); + .unwrap(), + vec![&account_account, &account_account, &owner_account], + )], + &[Check::err(TokenError::InsufficientFunds.into())], + ); - // insufficient funds checked - let instruction = transfer_checked( - &program_id, - account_info.key, - mint_info.key, - account_info.key, - owner_info.key, - &[], - 1001, - 2, - ) - .unwrap(); - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - mint_info.clone(), - account_info.clone(), - owner_info.clone(), - ], - &instruction.data, + // insufficient funds checked + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + transfer_checked( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &mint_key, + &account_key, + &owner2_key, + &[], + 1001, + 2, ) - ); + .unwrap(), + vec![ + &account_account, + &mint_account, + &account_account, + &owner_account, + ], + )], + &[Check::err(TokenError::InsufficientFunds.into())], + ); - // incorrect decimals - let instruction = transfer_checked( - &program_id, - account_info.key, - mint_info.key, - account_info.key, - owner_info.key, - &[], - 1, - 10, // <-- incorrect decimals - ) - .unwrap(); - assert_eq!( - Err(TokenError::MintDecimalsMismatch.into()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - mint_info.clone(), - account_info.clone(), - owner_info.clone(), - ], - &instruction.data, + // incorrect decimals + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + transfer_checked( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &mint_key, + &account_key, + &owner2_key, + &[], + 1, + 10, // <-- incorrect decimals ) - ); + .unwrap(), + vec![ + &account_account, + &mint_account, + &account_account, + &owner_account, + ], + )], + &[Check::err(TokenError::MintDecimalsMismatch.into())], + ); - // incorrect mint - let instruction = transfer_checked( - &program_id, - account_info.key, - account3_info.key, // <-- incorrect mint - account_info.key, - owner_info.key, - &[], - 1, - 2, - ) - .unwrap(); - assert_eq!( - Err(TokenError::MintMismatch.into()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - account3_info.clone(), // <-- incorrect mint - account_info.clone(), - owner_info.clone(), - ], - &instruction.data, + // incorrect mint + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + transfer_checked( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &account3_key, // <-- incorrect mint + &account_key, + &owner_key, + &[], + 1, + 2, ) - ); - - // approve delegate - let instruction = approve( - &program_id, - account_info.key, - delegate_info.key, - owner_info.key, - &[], - 100, - ) - .unwrap(); - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - delegate_info.clone(), - owner_info.clone(), + .unwrap(), + vec![ + &account_account, + &account3_account, // <-- incorrect mint + &account_account, + &owner_account, ], - &instruction.data, - ) - .unwrap(); + )], + &[Check::err(TokenError::MintMismatch.into())], + ); - // delegate transfer - let instruction = transfer( - &program_id, - account_info.key, - account_info.key, - delegate_info.key, - &[], - 100, - ) - .unwrap(); - assert_eq!( - Ok(()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - account_info.clone(), - delegate_info.clone(), - ], - &instruction.data, + // approve delegate + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + approve( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, ) - ); - // no balance change... - let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); - assert_eq!(account.amount, 1000); - assert_eq!(account.delegated_amount, 100); + .unwrap(), + vec![&account_account, &delegate_account, &owner_account], + )], + &[Check::success()], + ); - // delegate transfer checked - let instruction = transfer_checked( - &program_id, - account_info.key, - mint_info.key, - account_info.key, - delegate_info.key, - &[], - 100, - 2, - ) - .unwrap(); - assert_eq!( - Ok(()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - mint_info.clone(), - account_info.clone(), - delegate_info.clone(), - ], - &instruction.data, - ) - ); - // no balance change... - let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); - assert_eq!(account.amount, 1000); - assert_eq!(account.delegated_amount, 100); + // delegate transfer + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[ + ( + approve( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, + ) + .unwrap(), + vec![&account_account, &delegate_account, &owner_account], + ), + ( + transfer( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &account_key, + &delegate_key, + &[], + 100, + ) + .unwrap(), + vec![&account_account, &account_account, &delegate_account], + ), + ], + &[ + Check::success(), + // no balance change... + Check::account(&account_key) + .data_slice(64, &1000u64.to_le_bytes()) + .build(), + Check::account(&account_key) + .data_slice(121, &100u64.to_le_bytes()) + .build(), + ], + ); - // delegate insufficient funds - let instruction = transfer( - &program_id, - account_info.key, - account_info.key, - delegate_info.key, - &[], - 101, - ) - .unwrap(); - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - account_info.clone(), - delegate_info.clone(), + // delegate transfer checked + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[ + ( + approve( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, + ) + .unwrap(), + vec![&account_account, &delegate_account, &owner_account], + ), + ( + transfer_checked( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &mint_key, + &account_key, + &delegate_key, + &[], + 100, + 2, + ) + .unwrap(), + vec![ + &account_account, + &mint_account, + &account_account, + &delegate_account, ], - &instruction.data, - ) - ); + ), + ], + &[ + Check::success(), + // no balance change... + Check::account(&account_key) + .data_slice(64, &1000u64.to_le_bytes()) + .build(), + Check::account(&account_key) + .data_slice(121, &100u64.to_le_bytes()) + .build(), + ], + ); - // delegate insufficient funds checked - let instruction = transfer_checked( - &program_id, - account_info.key, - mint_info.key, - account_info.key, - delegate_info.key, - &[], - 101, - 2, - ) - .unwrap(); - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - mint_info.clone(), - account_info.clone(), - delegate_info.clone(), - ], - &instruction.data, - ) - ); + // delegate insufficient funds + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[ + ( + approve( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, + ) + .unwrap(), + vec![&account_account, &delegate_account, &owner_account], + ), + ( + transfer( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &account_key, + &delegate_key, + &[], + 101, + ) + .unwrap(), + vec![&account_account, &account_account, &delegate_account], + ), + ], + &[Check::err(TokenError::InsufficientFunds.into())], + ); - // owner transfer with delegate assigned - let instruction = transfer( - &program_id, - account_info.key, - account_info.key, - owner_info.key, - &[], - 1000, - ) - .unwrap(); - assert_eq!( - Ok(()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - account_info.clone(), - owner_info.clone(), + // delegate insufficient funds checked + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[ + ( + approve( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, + ) + .unwrap(), + vec![&account_account, &delegate_account, &owner_account], + ), + ( + transfer_checked( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &mint_key, + &account_key, + &delegate_key, + &[], + 101, + 2, + ) + .unwrap(), + vec![ + &account_account, + &mint_account, + &account_account, + &delegate_account, ], - &instruction.data, - ) - ); - // no balance change... - let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); - assert_eq!(account.amount, 1000); + ), + ], + &[Check::err(TokenError::InsufficientFunds.into())], + ); - // owner transfer with delegate assigned checked - let instruction = transfer_checked( - &program_id, - account_info.key, - mint_info.key, - account_info.key, - owner_info.key, - &[], - 1000, - 2, - ) - .unwrap(); - assert_eq!( - Ok(()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - mint_info.clone(), - account_info.clone(), - owner_info.clone(), - ], - &instruction.data, - ) - ); - // no balance change... - let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); - assert_eq!(account.amount, 1000); - } + // owner transfer with delegate assigned + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[ + ( + approve( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, + ) + .unwrap(), + vec![&account_account, &delegate_account, &owner_account], + ), + ( + transfer( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &account_key, + &owner_key, + &[], + 1000, + ) + .unwrap(), + vec![&account_account, &account_account, &owner_account], + ), + ], + &[ + Check::success(), + // no balance change... + Check::account(&account_key) + .data_slice(64, &1000u64.to_le_bytes()) + .build(), + ], + ); + // owner transfer with delegate assigned checked + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[ + ( + approve( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, + ) + .unwrap(), + vec![&account_account, &delegate_account, &owner_account], + ), + ( + transfer_checked( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &mint_key, + &account_key, + &owner_key, + &[], + 1000, + 2, + ) + .unwrap(), + vec![ + &account_account, + &mint_account, + &account_account, + &owner_account, + ], + ), + ], + &[ + Check::success(), + // no balance change... + Check::account(&account_key) + .data_slice(64, &1000u64.to_le_bytes()) + .build(), + ], + ); +} +/* #[test] fn test_mintable_token_with_zero_supply() { let program_id = crate::id(); From 0566df01132e69ac4563f1036935cbf8395eb6e6 Mon Sep 17 00:00:00 2001 From: febo Date: Tue, 7 Jan 2025 01:46:06 +0000 Subject: [PATCH 09/11] [wip]: Mintable token tests --- program/tests/processor.rs | 237 ++++++++++++++++++++++++------------- 1 file changed, 153 insertions(+), 84 deletions(-) diff --git a/program/tests/processor.rs b/program/tests/processor.rs index 5ed6ea94..42e4cd1a 100644 --- a/program/tests/processor.rs +++ b/program/tests/processor.rs @@ -20,7 +20,7 @@ use { error::TokenError, instruction::{ approve, initialize_account, initialize_mint, initialize_mint2, initialize_multisig, - mint_to, transfer, transfer_checked, + mint_to, mint_to_checked, transfer, transfer_checked, }, state::{Account, AccountState, Mint, Multisig}, }, @@ -2423,106 +2423,175 @@ fn test_self_transfer() { ], ); } -/* - #[test] - fn test_mintable_token_with_zero_supply() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); +#[test] +fn test_mintable_token_with_zero_supply() { + let program_id = TARGET_TOKEN_PROGRAM_ID; + let account_key = Pubkey::new_unique(); + let account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let owner_key = Pubkey::new_unique(); + let owner_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let rent_sysvar = rent_sysvar(); + + let decimals = 2; + let setup_instructions = vec![ // create mint-able token with zero supply - let decimals = 2; - do_process_instruction( - initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, decimals).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); - assert_eq!( - mint, - Mint { - mint_authority: COption::Some(owner_key), - supply: 0, + ( + initialize_mint( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint_key, + &owner_key, + None, decimals, - is_initialized: true, - freeze_authority: COption::None, - } - ); - + ) + .unwrap(), + vec![&mint_account, &rent_sysvar], + ), // create account - do_process_instruction( - initialize_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), + ( + initialize_account( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &mint_key, + &owner_key, + ) + .unwrap(), vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, + &account_account, + &mint_account, + &owner_account, + &rent_sysvar, ], - ) - .unwrap(); - - // mint to - do_process_instruction( - mint_to(&TOKEN_PROGRAM_ID, &mint_key, &account_key, &owner_key, &[], 42).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - let _ = Mint::unpack(&mint_account.data).unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 42); + ), + ]; - // mint to 2, with incorrect decimals - assert_eq!( - Err(TokenError::MintDecimalsMismatch.into()), - do_process_instruction( - mint_to_checked( - &program_id, - &mint_key, - &account_key, - &owner_key, - &[], - 42, - decimals + 1 - ) - .unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - ); + let mut mint_data = [0u8; Mint::LEN]; + Mint { + mint_authority: COption::Some(owner_key), + supply: 0, + decimals, + is_initialized: true, + freeze_authority: COption::None, + } + .pack_into_slice(&mut mint_data); - let _ = Mint::unpack(&mint_account.data).unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 42); + // create mint-able token with zero supply + do_process_instructions( + &setup_instructions, + &[ + Check::success(), + Check::account(&mint_key).data(&mint_data).build(), + ], + ); - // mint to 2 - do_process_instruction( - mint_to_checked( - &program_id, + // mint to + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + mint_to( + &INSTRUCTION_TOKEN_PROGRAM_ID, &mint_key, &account_key, &owner_key, &[], 42, - decimals, ) .unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - let _ = Mint::unpack(&mint_account.data).unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 84); - } + vec![&mint_account, &account_account, &owner_account], + )], + &[ + Check::success(), + Check::account(&account_key) + .data_slice(64, &42u64.to_le_bytes()) + .build(), + ], + ); + // mint to 2, with incorrect decimals + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[ + ( + mint_to( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint_key, + &account_key, + &owner_key, + &[], + 42, + ) + .unwrap(), + vec![&mint_account, &account_account, &owner_account], + ), + ( + mint_to_checked( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint_key, + &account_key, + &owner_key, + &[], + 42, + decimals + 1, + ) + .unwrap(), + vec![&mint_account, &account_account, &owner_account], + ), + ], + &[ + Check::err(TokenError::MintDecimalsMismatch.into()), + // no balance change... + Check::account(&account_key) + .data_slice(64, &42u64.to_le_bytes()) + .build(), + ], + ); + + // mint to 2 + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[ + ( + mint_to( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint_key, + &account_key, + &owner_key, + &[], + 42, + ) + .unwrap(), + vec![&mint_account, &account_account, &owner_account], + ), + ( + mint_to_checked( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint_key, + &account_key, + &owner_key, + &[], + 42, + decimals, + ) + .unwrap(), + vec![&mint_account, &account_account, &owner_account], + ), + ], + &[ + Check::success(), + Check::account(&account_key) + .data_slice(64, &84u64.to_le_bytes()) + .build(), + ], + ); +} +/* #[test] fn test_approve_dups() { let program_id = crate::id(); From 9fe3489f90d0fc981b5e3170cbf7db0298ed5a3a Mon Sep 17 00:00:00 2001 From: febo Date: Tue, 7 Jan 2025 20:08:11 +0000 Subject: [PATCH 10/11] [wip]: Approve tests --- program/tests/processor.rs | 798 +++++++++++++++++++++---------------- 1 file changed, 465 insertions(+), 333 deletions(-) diff --git a/program/tests/processor.rs b/program/tests/processor.rs index 42e4cd1a..2644f0ba 100644 --- a/program/tests/processor.rs +++ b/program/tests/processor.rs @@ -19,8 +19,8 @@ use { spl_token::{ error::TokenError, instruction::{ - approve, initialize_account, initialize_mint, initialize_mint2, initialize_multisig, - mint_to, mint_to_checked, transfer, transfer_checked, + approve, approve_checked, initialize_account, initialize_mint, initialize_mint2, + initialize_multisig, mint_to, mint_to_checked, revoke, transfer, transfer_checked, }, state::{Account, AccountState, Mint, Multisig}, }, @@ -2591,91 +2591,107 @@ fn test_mintable_token_with_zero_supply() { ], ); } -/* - #[test] - fn test_approve_dups() { - let program_id = crate::id(); - let account1_key = Pubkey::new_unique(); - let mut account1_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_info: AccountInfo = (&account2_key, false, &mut account2_account).into(); - let account3_key = Pubkey::new_unique(); - let mut account3_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account3_info: AccountInfo = (&account3_key, true, &mut account3_account).into(); - let multisig_key = Pubkey::new_unique(); - let mut multisig_account = SolanaAccount::new( - multisig_minimum_balance(), - Multisig::get_packed_len(), - &program_id, - ); - let multisig_info: AccountInfo = (&multisig_key, true, &mut multisig_account).into(); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into(); - let rent_key = rent::id(); - let mut rent_sysvar = rent_sysvar(); - let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); - // create mint - do_process_instruction_dups( - initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), - vec![mint_info.clone(), rent_info.clone()], - ) - .unwrap(); +#[test] +fn test_approve_dups() { + let program_id = TARGET_TOKEN_PROGRAM_ID; + let account1_key = Pubkey::new_unique(); + let account1_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account2_key = Pubkey::new_unique(); + let account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account3_key = Pubkey::new_unique(); + let account3_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let multisig_key = Pubkey::new_unique(); + let multisig_account = SolanaAccount::new( + multisig_minimum_balance(), + Multisig::get_packed_len(), + &program_id, + ); + let owner_key = Pubkey::new_unique(); + let owner_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let rent_sysvar = rent_sysvar(); + let mut setup_instructions = vec![ + // create mint + ( + initialize_mint( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint_key, + &owner_key, + None, + 2, + ) + .unwrap(), + vec![&mint_account, &rent_sysvar], + ), // create account - do_process_instruction_dups( - initialize_account(&TOKEN_PROGRAM_ID, &account1_key, &mint_key, &account1_key).unwrap(), + ( + initialize_account( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account1_key, + &mint_key, + &account1_key, + ) + .unwrap(), vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - rent_info.clone(), + &account1_account, + &mint_account, + &account1_account, + &rent_sysvar, ], - ) - .unwrap(); - + ), // create another account - do_process_instruction_dups( - initialize_account(&TOKEN_PROGRAM_ID, &account2_key, &mint_key, &owner_key).unwrap(), + ( + initialize_account( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account2_key, + &mint_key, + &owner_key, + ) + .unwrap(), vec![ - account2_info.clone(), - mint_info.clone(), - owner_info.clone(), - rent_info.clone(), + &account2_account, + &mint_account, + &owner_account, + &rent_sysvar, ], - ) - .unwrap(); - + ), // mint to account - do_process_instruction_dups( - mint_to(&TOKEN_PROGRAM_ID, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), - vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], - ) - .unwrap(); + ( + mint_to( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint_key, + &account1_key, + &owner_key, + &[], + 1000, + ) + .unwrap(), + vec![&mint_account, &account1_account, &owner_account], + ), + ]; - // source-owner approve - do_process_instruction_dups( + // source-owner approve + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( approve( - &program_id, + &INSTRUCTION_TOKEN_PROGRAM_ID, &account1_key, &account2_key, &account1_key, @@ -2683,18 +2699,17 @@ fn test_mintable_token_with_zero_supply() { 500, ) .unwrap(), - vec![ - account1_info.clone(), - account2_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); + vec![&account1_account, &account2_account, &account1_account], + )], + &[Check::success()], + ); - // source-owner approve_checked - do_process_instruction_dups( + // source-owner approve_checked + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( approve_checked( - &program_id, + &INSTRUCTION_TOKEN_PROGRAM_ID, &account1_key, &mint_key, &account2_key, @@ -2705,216 +2720,307 @@ fn test_mintable_token_with_zero_supply() { ) .unwrap(), vec![ - account1_info.clone(), - mint_info.clone(), - account2_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // source-owner revoke - do_process_instruction_dups( - revoke(&TOKEN_PROGRAM_ID, &account1_key, &account1_key, &[]).unwrap(), - vec![account1_info.clone(), account1_info.clone()], - ) - .unwrap(); - - // test source-multisig signer - do_process_instruction_dups( - initialize_multisig(&TOKEN_PROGRAM_ID, &multisig_key, &[&account3_key], 1).unwrap(), - vec![ - multisig_info.clone(), - rent_info.clone(), - account3_info.clone(), - ], - ) - .unwrap(); - - do_process_instruction_dups( - initialize_account(&TOKEN_PROGRAM_ID, &account3_key, &mint_key, &multisig_key).unwrap(), - vec![ - account3_info.clone(), - mint_info.clone(), - multisig_info.clone(), - rent_info.clone(), + &account1_account, + &mint_account, + &account2_account, + &account1_account, ], - ) - .unwrap(); + )], + &[Check::success()], + ); - do_process_instruction_dups( - mint_to(&TOKEN_PROGRAM_ID, &mint_key, &account3_key, &owner_key, &[], 1000).unwrap(), - vec![mint_info.clone(), account3_info.clone(), owner_info.clone()], - ) - .unwrap(); + // source-owner revoke + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[ + ( + approve( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account1_key, + &account2_key, + &account1_key, + &[], + 500, + ) + .unwrap(), + vec![&account1_account, &account2_account, &account1_account], + ), + ( + revoke( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account1_key, + &account1_key, + &[], + ) + .unwrap(), + vec![&account1_account, &account1_account], + ), + ], + &[Check::success()], + ); - // source-multisig-signer approve - do_process_instruction_dups( - approve( - &program_id, - &account3_key, - &account2_key, + // test source-multisig signer + setup_instructions.extend_from_slice(&[ + ( + initialize_multisig( + &INSTRUCTION_TOKEN_PROGRAM_ID, &multisig_key, &[&account3_key], - 500, + 1, ) .unwrap(), - vec![ - account3_info.clone(), - account2_info.clone(), - multisig_info.clone(), - account3_info.clone(), - ], - ) - .unwrap(); - - // source-multisig-signer approve_checked - do_process_instruction_dups( - approve_checked( - &program_id, + vec![&multisig_account, &rent_sysvar, &account3_account], + ), + ( + initialize_account( + &INSTRUCTION_TOKEN_PROGRAM_ID, &account3_key, &mint_key, - &account2_key, &multisig_key, - &[&account3_key], - 500, - 2, ) .unwrap(), vec![ - account3_info.clone(), - mint_info.clone(), - account2_info.clone(), - multisig_info.clone(), - account3_info.clone(), - ], - ) - .unwrap(); + &account3_account, + &mint_account, + &multisig_account, + &rent_sysvar, + ], + ), + ( + mint_to( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint_key, + &account3_key, + &owner_key, + &[], + 1000, + ) + .unwrap(), + vec![&mint_account, &account3_account, &owner_account], + ), + ]); - // source-owner multisig-signer - do_process_instruction_dups( - revoke(&TOKEN_PROGRAM_ID, &account3_key, &multisig_key, &[&account3_key]).unwrap(), + do_process_instructions(&setup_instructions, &[Check::success()]); + + // source-multisig-signer approve + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + approve( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account3_key, + &account2_key, + &multisig_key, + &[&account3_key], + 500, + ) + .unwrap(), vec![ - account3_info.clone(), - multisig_info.clone(), - account3_info.clone(), + &account3_account, + &account2_account, + &multisig_account, + &account3_account, ], - ) - .unwrap(); - } + )], + &[Check::success()], + ); - #[test] - fn test_approve() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let delegate_key = Pubkey::new_unique(); - let mut delegate_account = SolanaAccount::default(); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); + // source-multisig-signer approve_checked + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + approve_checked( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account3_key, + &mint_key, + &account2_key, + &multisig_key, + &[&account3_key], + 500, + 2, + ) + .unwrap(), + vec![ + &account3_account, + &mint_account, + &account2_account, + &multisig_account, + &account3_account, + ], + )], + &[Check::success()], + ); - // create mint - do_process_instruction( - initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); + // source-owner multisig-signer + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[ + ( + approve_checked( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account3_key, + &mint_key, + &account2_key, + &multisig_key, + &[&account3_key], + 500, + 2, + ) + .unwrap(), + vec![ + &account3_account, + &mint_account, + &account2_account, + &multisig_account, + &account3_account, + ], + ), + ( + revoke( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account3_key, + &multisig_key, + &[&account3_key], + ) + .unwrap(), + vec![&account3_account, &multisig_account, &account3_account], + ), + ], + &[Check::success()], + ); +} + +#[test] +fn test_approve() { + let program_id = TARGET_TOKEN_PROGRAM_ID; + let account_key = Pubkey::new_unique(); + let account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account2_key = Pubkey::new_unique(); + let account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let delegate_key = Pubkey::new_unique(); + let delegate_account = SolanaAccount::default(); + let owner_key = Pubkey::new_unique(); + let owner_account = SolanaAccount::default(); + let owner2_key = Pubkey::new_unique(); + let owner2_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let rent_sysvar = rent_sysvar(); + let setup_instructions = vec![ + // create mint + ( + initialize_mint( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint_key, + &owner_key, + None, + 2, + ) + .unwrap(), + vec![&mint_account, &rent_sysvar], + ), // create account - do_process_instruction( - initialize_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), + ( + initialize_account( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &mint_key, + &owner_key, + ) + .unwrap(), vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, + &account_account, + &mint_account, + &owner_account, + &rent_sysvar, ], - ) - .unwrap(); - + ), // create another account - do_process_instruction( - initialize_account(&TOKEN_PROGRAM_ID, &account2_key, &mint_key, &owner_key).unwrap(), + ( + initialize_account( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account2_key, + &mint_key, + &owner_key, + ) + .unwrap(), vec![ - &mut account2_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, + &account2_account, + &mint_account, + &owner_account, + &rent_sysvar, ], - ) - .unwrap(); - + ), // mint to account - do_process_instruction( - mint_to(&TOKEN_PROGRAM_ID, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - - // missing signer - let mut instruction = approve( - &program_id, - &account_key, - &delegate_key, - &owner_key, - &[], - 100, - ) - .unwrap(); - instruction.accounts[2].is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - do_process_instruction( - instruction, - vec![ - &mut account_account, - &mut delegate_account, - &mut owner_account, - ], + ( + mint_to( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint_key, + &account_key, + &owner_key, + &[], + 1000, ) - ); + .unwrap(), + vec![&mint_account, &account_account, &owner_account], + ), + ]; - // no owner - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - approve( - &program_id, - &account_key, - &delegate_key, - &owner2_key, - &[], - 100 - ) - .unwrap(), - vec![ - &mut account_account, - &mut delegate_account, - &mut owner2_account, - ], + // missing signer + let mut instruction = approve( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, + ) + .unwrap(); + instruction.accounts[2].is_signer = false; + + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + instruction, + vec![&account_account, &delegate_account, &owner_account], + )], + &[Check::err(ProgramError::MissingRequiredSignature)], + ); + + // no owner + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + approve( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &delegate_key, + &owner2_key, + &[], + 100, ) - ); + .unwrap(), + vec![&account_account, &delegate_account, &owner2_account], + )], + &[Check::err(TokenError::OwnerMismatch.into())], + ); - // approve delegate - do_process_instruction( + // approve delegate + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( approve( - &program_id, + &INSTRUCTION_TOKEN_PROGRAM_ID, &account_key, &delegate_key, &owner_key, @@ -2922,66 +3028,67 @@ fn test_mintable_token_with_zero_supply() { 100, ) .unwrap(), - vec![ - &mut account_account, - &mut delegate_account, - &mut owner_account, - ], - ) - .unwrap(); + vec![&account_account, &delegate_account, &owner_account], + )], + &[Check::success()], + ); - // approve delegate 2, with incorrect decimals - assert_eq!( - Err(TokenError::MintDecimalsMismatch.into()), - do_process_instruction( - approve_checked( - &program_id, - &account_key, - &mint_key, - &delegate_key, - &owner_key, - &[], - 100, - 0 // <-- incorrect decimals - ) - .unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut delegate_account, - &mut owner_account, - ], + // approve delegate 2, with incorrect decimals + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + approve_checked( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &mint_key, + &delegate_key, + &owner_key, + &[], + 100, + 0, // <-- incorrect decimals ) - ); + .unwrap(), + vec![ + &account_account, + &mint_account, + &delegate_account, + &owner_account, + ], + )], + &[Check::err(TokenError::MintDecimalsMismatch.into())], + ); - // approve delegate 2, with incorrect mint - assert_eq!( - Err(TokenError::MintMismatch.into()), - do_process_instruction( - approve_checked( - &program_id, - &account_key, - &account2_key, // <-- bad mint - &delegate_key, - &owner_key, - &[], - 100, - 0 - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, // <-- bad mint - &mut delegate_account, - &mut owner_account, - ], + // approve delegate 2, with incorrect mint + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + approve_checked( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &account2_key, // <-- bad mint + &delegate_key, + &owner_key, + &[], + 100, + 0, ) - ); + .unwrap(), + vec![ + &account_account, + &account2_account, // <-- bad mint + &delegate_account, + &owner_account, + ], + )], + &[Check::err(TokenError::MintMismatch.into())], + ); - // approve delegate 2 - do_process_instruction( + // approve delegate 2 + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( approve_checked( - &program_id, + &INSTRUCTION_TOKEN_PROGRAM_ID, &account_key, &mint_key, &delegate_key, @@ -2992,22 +3099,47 @@ fn test_mintable_token_with_zero_supply() { ) .unwrap(), vec![ - &mut account_account, - &mut mint_account, - &mut delegate_account, - &mut owner_account, + &account_account, + &mint_account, + &delegate_account, + &owner_account, ], - ) - .unwrap(); - - // revoke delegate - do_process_instruction( - revoke(&TOKEN_PROGRAM_ID, &account_key, &owner_key, &[]).unwrap(), - vec![&mut account_account, &mut owner_account], - ) - .unwrap(); - } + )], + &[Check::success()], + ); + // revoke delegate + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[ + ( + approve_checked( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &mint_key, + &delegate_key, + &owner_key, + &[], + 100, + 2, + ) + .unwrap(), + vec![ + &account_account, + &mint_account, + &delegate_account, + &owner_account, + ], + ), + ( + revoke(&INSTRUCTION_TOKEN_PROGRAM_ID, &account_key, &owner_key, &[]).unwrap(), + vec![&account_account, &owner_account], + ), + ], + &[Check::success()], + ); +} +/* #[test] fn test_set_authority_dups() { let program_id = crate::id(); From bec282b8557b6151d2553dbada7a6270b22e6be8 Mon Sep 17 00:00:00 2001 From: febo Date: Thu, 9 Jan 2025 02:06:22 +0000 Subject: [PATCH 11/11] [wip]: Set authority tests --- program/tests/processor.rs | 890 ++++++++++++++++++++++--------------- 1 file changed, 536 insertions(+), 354 deletions(-) diff --git a/program/tests/processor.rs b/program/tests/processor.rs index 2644f0ba..3744dbdf 100644 --- a/program/tests/processor.rs +++ b/program/tests/processor.rs @@ -20,7 +20,8 @@ use { error::TokenError, instruction::{ approve, approve_checked, initialize_account, initialize_mint, initialize_mint2, - initialize_multisig, mint_to, mint_to_checked, revoke, transfer, transfer_checked, + initialize_multisig, mint_to, mint_to_checked, revoke, set_authority, transfer, + transfer_checked, AuthorityType, }, state::{Account, AccountState, Mint, Multisig}, }, @@ -3139,49 +3140,59 @@ fn test_approve() { &[Check::success()], ); } -/* - #[test] - fn test_set_authority_dups() { - let program_id = crate::id(); - let account1_key = Pubkey::new_unique(); - let mut account1_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); - let owner_key = Pubkey::new_unique(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into(); - let rent_key = rent::id(); - let mut rent_sysvar = rent_sysvar(); - let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); - // create mint - do_process_instruction_dups( - initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &mint_key, Some(&mint_key), 2).unwrap(), - vec![mint_info.clone(), rent_info.clone()], - ) - .unwrap(); +#[test] +fn test_set_authority_dups() { + let program_id = TARGET_TOKEN_PROGRAM_ID; + let account1_key = Pubkey::new_unique(); + let account1_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let owner_key = Pubkey::new_unique(); + let mint_key = Pubkey::new_unique(); + let mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let rent_sysvar = rent_sysvar(); + let setup_instructions = vec![ + // create mint + ( + initialize_mint( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint_key, + &mint_key, + Some(&mint_key), + 2, + ) + .unwrap(), + vec![&mint_account, &rent_sysvar], + ), // create account - do_process_instruction_dups( - initialize_account(&TOKEN_PROGRAM_ID, &account1_key, &mint_key, &account1_key).unwrap(), + ( + initialize_account( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account1_key, + &mint_key, + &account1_key, + ) + .unwrap(), vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - rent_info.clone(), + &account1_account, + &mint_account, + &account1_account, + &rent_sysvar, ], - ) - .unwrap(); + ), + ]; - // set mint_authority when currently self - do_process_instruction_dups( + // set mint_authority when currently self + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( set_authority( - &program_id, + &INSTRUCTION_TOKEN_PROGRAM_ID, &mint_key, Some(&owner_key), AuthorityType::MintTokens, @@ -3189,14 +3200,17 @@ fn test_approve() { &[], ) .unwrap(), - vec![mint_info.clone(), mint_info.clone()], - ) - .unwrap(); + vec![&mint_account, &mint_account], + )], + &[Check::success()], + ); - // set freeze_authority when currently self - do_process_instruction_dups( + // set freeze_authority when currently self + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( set_authority( - &program_id, + &INSTRUCTION_TOKEN_PROGRAM_ID, &mint_key, Some(&owner_key), AuthorityType::FreezeAccount, @@ -3204,14 +3218,17 @@ fn test_approve() { &[], ) .unwrap(), - vec![mint_info.clone(), mint_info.clone()], - ) - .unwrap(); + vec![&mint_account, &mint_account], + )], + &[Check::success()], + ); - // set account owner when currently self - do_process_instruction_dups( + // set account owner when currently self + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( set_authority( - &program_id, + &INSTRUCTION_TOKEN_PROGRAM_ID, &account1_key, Some(&owner_key), AuthorityType::AccountOwner, @@ -3219,18 +3236,29 @@ fn test_approve() { &[], ) .unwrap(), - vec![account1_info.clone(), account1_info.clone()], - ) - .unwrap(); + vec![&account1_account, &account1_account], + )], + &[Check::success()], + ); - // set close_authority when currently self - let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); - account.close_authority = COption::Some(account1_key); - Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); + // set close_authority when currently self + let mut account = Account::unpack_unchecked(&account1_account.data).unwrap(); + account.state = AccountState::Initialized; + account.mint = mint_key; + account.owner = owner_key; + account.close_authority = COption::Some(account1_key); + let mut close_authority_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &TARGET_TOKEN_PROGRAM_ID, + ); + Account::pack(account, &mut close_authority_account.data).unwrap(); - do_process_instruction_dups( + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( set_authority( - &program_id, + &INSTRUCTION_TOKEN_PROGRAM_ID, &account1_key, Some(&owner_key), AuthorityType::CloseAccount, @@ -3238,381 +3266,533 @@ fn test_approve() { &[], ) .unwrap(), - vec![account1_info.clone(), account1_info.clone()], - ) - .unwrap(); - } + vec![&close_authority_account, &close_authority_account], + )], + &[Check::success()], + ); +} - #[test] - fn test_set_authority() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let owner3_key = Pubkey::new_unique(); - let mut owner3_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint2_key = Pubkey::new_unique(); - let mut mint2_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); +#[test] +fn test_set_authority() { + let program_id = TARGET_TOKEN_PROGRAM_ID; + let account_key = Pubkey::new_unique(); + let account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account2_key = Pubkey::new_unique(); + let account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let owner_key = Pubkey::new_unique(); + let owner_account = SolanaAccount::default(); + let owner2_key = Pubkey::new_unique(); + let owner2_account = SolanaAccount::default(); + let owner3_key = Pubkey::new_unique(); + let owner3_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint2_key = Pubkey::new_unique(); + let mint2_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let rent_sysvar = rent_sysvar(); + let mut setup_instructions = vec![ // create new mint with owner - do_process_instruction( - initialize_mint(&TOKEN_PROGRAM_ID, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - + ( + initialize_mint( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint_key, + &owner_key, + None, + 2, + ) + .unwrap(), + vec![&mint_account, &rent_sysvar], + ), // create mint with owner and freeze_authority - do_process_instruction( - initialize_mint(&TOKEN_PROGRAM_ID, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(), - vec![&mut mint2_account, &mut rent_sysvar], + ( + initialize_mint( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint2_key, + &owner_key, + Some(&owner_key), + 2, + ) + .unwrap(), + vec![&mint2_account, &rent_sysvar], + ), + ]; + + // invalid account + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + set_authority( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + Some(&owner2_key), + AuthorityType::AccountOwner, + &owner_key, + &[], + ) + .unwrap(), + vec![&account_account, &owner_account], + )], + &[Check::err(ProgramError::UninitializedAccount)], + ); + + // create account + setup_instructions.push(( + initialize_account( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &mint_key, + &owner_key, ) - .unwrap(); + .unwrap(), + vec![ + &account_account, + &mint_account, + &owner_account, + &rent_sysvar, + ], + )); + + // create another account + setup_instructions.push(( + initialize_account( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account2_key, + &mint2_key, + &owner_key, + ) + .unwrap(), + vec![ + &account2_account, + &mint2_account, + &owner_account, + &rent_sysvar, + ], + )); - // invalid account - assert_eq!( - Err(ProgramError::UninitializedAccount), - do_process_instruction( + // missing owner + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + set_authority( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + Some(&owner_key), + AuthorityType::AccountOwner, + &owner2_key, + &[], + ) + .unwrap(), + vec![&account_account, &owner2_account], + )], + &[Check::err(TokenError::OwnerMismatch.into())], + ); + + // owner did not sign + let mut instruction = set_authority( + &program_id, + &account_key, + Some(&owner2_key), + AuthorityType::AccountOwner, + &owner_key, + &[], + ) + .unwrap(); + instruction.accounts[1].is_signer = false; + + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[(instruction, vec![&account_account, &owner_account])], + &[Check::err(ProgramError::MissingRequiredSignature)], + ); + + // wrong authority type + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + set_authority( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + Some(&owner2_key), + AuthorityType::FreezeAccount, + &owner_key, + &[], + ) + .unwrap(), + vec![&account_account, &owner_account], + )], + &[Check::err(TokenError::AuthorityTypeNotSupported.into())], + ); + + // account owner may not be set to None + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + set_authority( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + None, + AuthorityType::AccountOwner, + &owner_key, + &[], + ) + .unwrap(), + vec![&account_account, &owner_account], + )], + &[Check::err(TokenError::InvalidInstruction.into())], + ); + + // set delegate + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + approve( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &owner2_key, + &owner_key, + &[], + u64::MAX, + ) + .unwrap(), + vec![&account_account, &owner2_account, &owner_account], + )], + &[ + Check::success(), + Check::account(&account_key) + .data_slice(76, owner2_key.as_ref()) // delegate + .build(), + Check::account(&account_key) + .data_slice(121, &u64::MAX.to_le_bytes()) // delegated amount + .build(), + ], + ); + + // set owner + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + set_authority( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + Some(&owner3_key), + AuthorityType::AccountOwner, + &owner_key, + &[], + ) + .unwrap(), + vec![&account_account, &owner_account], + )], + &[Check::success()], + ); + + // check delegate cleared + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[ + ( + approve( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + &owner2_key, + &owner_key, + &[], + u64::MAX, + ) + .unwrap(), + vec![&account_account, &owner2_account, &owner_account], + ), + ( set_authority( - &program_id, + &INSTRUCTION_TOKEN_PROGRAM_ID, &account_key, - Some(&owner2_key), + Some(&owner3_key), AuthorityType::AccountOwner, &owner_key, - &[] + &[], ) .unwrap(), - vec![&mut account_account, &mut owner_account], - ) - ); - - // create account - do_process_instruction( - initialize_account(&TOKEN_PROGRAM_ID, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&TOKEN_PROGRAM_ID, &account2_key, &mint2_key, &owner_key).unwrap(), - vec![ - &mut account2_account, - &mut mint2_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); + vec![&account_account, &owner_account], + ), + ], + &[ + Check::success(), + Check::account(&account_key) + .data_slice(32, owner3_key.as_ref()) // authority + .build(), + Check::account(&account_key) + .data_slice(72, &[0u8; 4]) // delegate option + .build(), + Check::account(&account_key) + .data_slice(121, &0u64.to_le_bytes()) // delegated amount + .build(), + ], + ); - // missing owner - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( + // set owner without existing delegate + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[ + ( set_authority( - &program_id, + &INSTRUCTION_TOKEN_PROGRAM_ID, &account_key, - Some(&owner_key), + Some(&owner3_key), AuthorityType::AccountOwner, - &owner2_key, - &[] + &owner_key, + &[], ) .unwrap(), - vec![&mut account_account, &mut owner2_account], - ) - ); + vec![&account_account, &owner_account], + ), + ( + set_authority( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + Some(&owner2_key), + AuthorityType::AccountOwner, + &owner3_key, + &[], + ) + .unwrap(), + vec![&account_account, &owner3_account], + ), + ], + &[Check::success()], + ); - // owner did not sign - let mut instruction = set_authority( - &program_id, - &account_key, - Some(&owner2_key), - AuthorityType::AccountOwner, - &owner_key, - &[], - ) - .unwrap(); - instruction.accounts[1].is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - do_process_instruction(instruction, vec![&mut account_account, &mut owner_account,],) - ); + // set close_authority + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( + set_authority( + &INSTRUCTION_TOKEN_PROGRAM_ID, + &account_key, + Some(&owner2_key), + AuthorityType::CloseAccount, + &owner_key, + &[], + ) + .unwrap(), + vec![&account_account, &owner2_account], + )], + &[ + Check::success(), + Check::account(&account_key) + .data_slice(129, &[1, 0, 0, 0]) // close authority option + .build(), + Check::account(&account_key) + .data_slice(133, owner2_key.as_ref()) // close authority + .build(), + ], + ); - // wrong authority type - assert_eq!( - Err(TokenError::AuthorityTypeNotSupported.into()), - do_process_instruction( + // close_authority may be set to None + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[ + ( set_authority( - &program_id, + &INSTRUCTION_TOKEN_PROGRAM_ID, &account_key, Some(&owner2_key), - AuthorityType::FreezeAccount, + AuthorityType::CloseAccount, &owner_key, &[], ) .unwrap(), - vec![&mut account_account, &mut owner_account], - ) - ); - - // account owner may not be set to None - assert_eq!( - Err(TokenError::InvalidInstruction.into()), - do_process_instruction( + vec![&account_account, &owner2_account], + ), + ( set_authority( - &program_id, + &INSTRUCTION_TOKEN_PROGRAM_ID, &account_key, None, - AuthorityType::AccountOwner, - &owner_key, + AuthorityType::CloseAccount, + &owner2_key, &[], ) .unwrap(), - vec![&mut account_account, &mut owner_account], - ) - ); - - // set delegate - do_process_instruction( - approve( - &program_id, - &account_key, - &owner2_key, - &owner_key, - &[], - u64::MAX, - ) - .unwrap(), - vec![ - &mut account_account, - &mut owner2_account, - &mut owner_account, - ], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.delegate, COption::Some(owner2_key)); - assert_eq!(account.delegated_amount, u64::MAX); + vec![&account_account, &owner2_account], + ), + ], + &[ + Check::success(), + Check::account(&account_key) + .data_slice(129, &[0u8; 4]) // close authority option + .build(), + ], + ); - // set owner - do_process_instruction( + // wrong owner + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( set_authority( - &program_id, - &account_key, + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint_key, Some(&owner3_key), - AuthorityType::AccountOwner, - &owner_key, + AuthorityType::MintTokens, + &owner2_key, &[], ) .unwrap(), - vec![&mut account_account, &mut owner_account], - ) - .unwrap(); + vec![&mint_account, &owner2_account], + )], + &[Check::err(TokenError::OwnerMismatch.into())], + ); - // check delegate cleared - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.delegate, COption::None); - assert_eq!(account.delegated_amount, 0); + // owner did not sign + let mut instruction = set_authority( + &program_id, + &mint_key, + Some(&owner2_key), + AuthorityType::MintTokens, + &owner_key, + &[], + ) + .unwrap(); + instruction.accounts[1].is_signer = false; - // set owner without existing delegate - do_process_instruction( + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[(instruction, vec![&mint_account, &owner_account])], + &[Check::err(ProgramError::MissingRequiredSignature)], + ); + + // cannot freeze + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( set_authority( - &program_id, - &account_key, + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint_key, Some(&owner2_key), - AuthorityType::AccountOwner, - &owner3_key, + AuthorityType::FreezeAccount, + &owner_key, &[], ) .unwrap(), - vec![&mut account_account, &mut owner3_account], - ) - .unwrap(); + vec![&mint_account, &owner_account], + )], + &[Check::err(TokenError::MintCannotFreeze.into())], + ); - // set close_authority - do_process_instruction( + // set owner + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( set_authority( - &program_id, - &account_key, + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint_key, Some(&owner2_key), - AuthorityType::CloseAccount, - &owner2_key, + AuthorityType::MintTokens, + &owner_key, &[], ) .unwrap(), - vec![&mut account_account, &mut owner2_account], - ) - .unwrap(); + vec![&mint_account, &owner_account], + )], + &[Check::success()], + ); - // close_authority may be set to None - do_process_instruction( + // set owner to None + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( set_authority( - &program_id, - &account_key, + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint_key, None, - AuthorityType::CloseAccount, - &owner2_key, + AuthorityType::MintTokens, + &owner_key, &[], ) .unwrap(), - vec![&mut account_account, &mut owner2_account], - ) - .unwrap(); + vec![&mint_account, &owner_account], + )], + &[Check::success()], + ); - // wrong owner - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( + // test unsetting mint_authority is one-way operation + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[ + ( set_authority( - &program_id, + &INSTRUCTION_TOKEN_PROGRAM_ID, &mint_key, - Some(&owner3_key), + None, AuthorityType::MintTokens, - &owner2_key, - &[] + &owner_key, + &[], ) .unwrap(), - vec![&mut mint_account, &mut owner2_account], - ) - ); - - // owner did not sign - let mut instruction = set_authority( - &program_id, - &mint_key, - Some(&owner2_key), - AuthorityType::MintTokens, - &owner_key, - &[], - ) - .unwrap(); - instruction.accounts[1].is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - do_process_instruction(instruction, vec![&mut mint_account, &mut owner_account],) - ); - - // cannot freeze - assert_eq!( - Err(TokenError::MintCannotFreeze.into()), - do_process_instruction( + vec![&mint_account, &owner_account], + ), + ( set_authority( - &program_id, + &INSTRUCTION_TOKEN_PROGRAM_ID, &mint_key, - Some(&owner2_key), - AuthorityType::FreezeAccount, + Some(&owner_key), + AuthorityType::MintTokens, &owner_key, &[], ) .unwrap(), - vec![&mut mint_account, &mut owner_account], - ) - ); + vec![&mint_account, &owner_account], + ), + ], + &[Check::err(TokenError::FixedSupply.into())], + ); - // set owner - do_process_instruction( + // set freeze_authority + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[( set_authority( - &program_id, - &mint_key, + &INSTRUCTION_TOKEN_PROGRAM_ID, + &mint2_key, Some(&owner2_key), - AuthorityType::MintTokens, + AuthorityType::FreezeAccount, &owner_key, &[], ) .unwrap(), - vec![&mut mint_account, &mut owner_account], - ) - .unwrap(); - - // set owner to None - do_process_instruction( - set_authority( - &program_id, - &mint_key, - None, - AuthorityType::MintTokens, - &owner2_key, - &[], - ) - .unwrap(), - vec![&mut mint_account, &mut owner2_account], - ) - .unwrap(); + vec![&mint2_account, &owner_account], + )], + &[Check::success()], + ); - // test unsetting mint_authority is one-way operation - assert_eq!( - Err(TokenError::FixedSupply.into()), - do_process_instruction( + // test unsetting freeze_authority is one-way operation + do_process_instructions_with_pre_instructions( + Some(&setup_instructions), + &[ + ( set_authority( - &program_id, + &INSTRUCTION_TOKEN_PROGRAM_ID, &mint2_key, - Some(&owner2_key), - AuthorityType::MintTokens, + None, + AuthorityType::FreezeAccount, &owner_key, - &[] + &[], ) .unwrap(), - vec![&mut mint_account, &mut owner_account], - ) - ); - - // set freeze_authority - do_process_instruction( - set_authority( - &program_id, - &mint2_key, - Some(&owner2_key), - AuthorityType::FreezeAccount, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut mint2_account, &mut owner_account], - ) - .unwrap(); - - // test unsetting freeze_authority is one-way operation - do_process_instruction( - set_authority( - &program_id, - &mint2_key, - None, - AuthorityType::FreezeAccount, - &owner2_key, - &[], - ) - .unwrap(), - vec![&mut mint2_account, &mut owner2_account], - ) - .unwrap(); - - assert_eq!( - Err(TokenError::MintCannotFreeze.into()), - do_process_instruction( + vec![&mint2_account, &owner_account], + ), + ( set_authority( - &program_id, + &INSTRUCTION_TOKEN_PROGRAM_ID, &mint2_key, Some(&owner2_key), AuthorityType::FreezeAccount, @@ -3620,11 +3800,13 @@ fn test_approve() { &[], ) .unwrap(), - vec![&mut mint2_account, &mut owner2_account], - ) - ); - } - + vec![&mint2_account, &owner_account], + ), + ], + &[Check::err(TokenError::MintCannotFreeze.into())], + ); +} +/* #[test] fn test_mint_to_dups() { let program_id = crate::id();