From 87331fd926e93557249bf20ea1ca0a37dc5ca6ae Mon Sep 17 00:00:00 2001 From: Jack May Date: Tue, 23 Jun 2020 09:16:58 -0700 Subject: [PATCH] Add instruction helpers (#52) --- token/src/instruction.rs | 276 ++++- token/src/state.rs | 2370 ++++++++++++++++++++++---------------- 2 files changed, 1648 insertions(+), 998 deletions(-) diff --git a/token/src/instruction.rs b/token/src/instruction.rs index b66a7a89bb6..17f57320ee3 100644 --- a/token/src/instruction.rs +++ b/token/src/instruction.rs @@ -1,5 +1,13 @@ //! Instruction types +use crate::error::TokenError; +use solana_sdk::{ + instruction::{AccountMeta, Instruction}, + program_error::ProgramError, + pubkey::Pubkey, +}; +use std::mem::size_of; + /// Specifies the financial specifics of a token. #[repr(C)] #[derive(Clone, Copy, Debug, Default, PartialEq)] @@ -13,7 +21,7 @@ pub struct TokenInfo { /// Instructions supported by the token program. #[repr(C)] #[derive(Clone, Debug, PartialEq)] -pub enum Instruction { +pub enum TokenInstruction { /// Creates a new token and deposit all the newly minted tokens in an account. /// /// # Accounts expected by this instruction: @@ -75,5 +83,271 @@ pub enum Instruction { /// 0. `[signer]` Owner of the account to burn from. /// 1. `[writable]` Account to burn from. /// 2. `[writable]` Token being burned. + /// 3. Optional: `[writable]` Source account if key 1 is a delegate account. Burn(u64), } +impl TokenInstruction { + /// Deserializes a byte buffer into an [TokenInstruction](enum.TokenInstruction.html) + pub fn deserialize(input: &[u8]) -> Result { + if input.len() < size_of::() { + return Err(ProgramError::InvalidAccountData); + } + Ok(match input[0] { + 0 => { + #[allow(clippy::cast_ptr_alignment)] + let info: &TokenInfo = unsafe { &*(&input[1] as *const u8 as *const TokenInfo) }; + Self::NewToken(*info) + } + 1 => Self::NewAccount, + 2 => { + #[allow(clippy::cast_ptr_alignment)] + let amount: &u64 = unsafe { &*(&input[1] as *const u8 as *const u64) }; + Self::Transfer(*amount) + } + 3 => { + #[allow(clippy::cast_ptr_alignment)] + let amount: &u64 = unsafe { &*(&input[1] as *const u8 as *const u64) }; + Self::Approve(*amount) + } + 4 => Self::SetOwner, + 5 => { + #[allow(clippy::cast_ptr_alignment)] + let amount: &u64 = unsafe { &*(&input[1] as *const u8 as *const u64) }; + Self::MintTo(*amount) + } + 6 => { + #[allow(clippy::cast_ptr_alignment)] + let amount: &u64 = unsafe { &*(&input[1] as *const u8 as *const u64) }; + Self::Burn(*amount) + } + _ => return Err(ProgramError::InvalidAccountData), + }) + } + + /// Serializes an [TokenInstruction](enum.TokenInstruction.html) into a byte buffer + pub fn serialize(self: &Self) -> Result, ProgramError> { + let mut output = vec![0u8; size_of::()]; + match self { + Self::NewToken(info) => { + output[0] = 0; + #[allow(clippy::cast_ptr_alignment)] + let value = unsafe { &mut *(&mut output[1] as *mut u8 as *mut TokenInfo) }; + *value = *info; + } + Self::NewAccount => output[0] = 1, + Self::Transfer(amount) => { + output[0] = 2; + #[allow(clippy::cast_ptr_alignment)] + let value = unsafe { &mut *(&mut output[1] as *mut u8 as *mut u64) }; + *value = *amount; + } + Self::Approve(amount) => { + output[0] = 3; + #[allow(clippy::cast_ptr_alignment)] + let value = unsafe { &mut *(&mut output[1] as *mut u8 as *mut u64) }; + *value = *amount; + } + Self::SetOwner => output[0] = 4, + Self::MintTo(amount) => { + output[0] = 5; + #[allow(clippy::cast_ptr_alignment)] + let value = unsafe { &mut *(&mut output[1] as *mut u8 as *mut u64) }; + *value = *amount; + } + Self::Burn(amount) => { + output[0] = 6; + #[allow(clippy::cast_ptr_alignment)] + let value = unsafe { &mut *(&mut output[1] as *mut u8 as *mut u64) }; + *value = *amount; + } + } + Ok(output) + } +} + +/// Creates a 'NewToken' instruction +pub fn new_token( + token_program_id: &Pubkey, + token_pubkey: &Pubkey, + account_pubkey: Option<&Pubkey>, + owner_pubkey: Option<&Pubkey>, + token_info: TokenInfo, +) -> Result { + let data = TokenInstruction::NewToken(token_info).serialize()?; + + let mut accounts = vec![AccountMeta::new(*token_pubkey, true)]; + if token_info.supply != 0 { + match account_pubkey { + Some(pubkey) => accounts.push(AccountMeta::new(*pubkey, false)), + None => { + return Err(ProgramError::NotEnoughAccountKeys); + } + } + } + match owner_pubkey { + Some(pubkey) => accounts.push(AccountMeta::new_readonly(*pubkey, false)), + None => { + if token_info.supply == 0 { + return Err(TokenError::OwnerRequiredIfNoInitialSupply.into()); + } + } + } + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + +/// Creates a `NewAccount` instruction +pub fn new_account( + token_program_id: &Pubkey, + account_pubkey: &Pubkey, + owner_pubkey: &Pubkey, + token_pubkey: &Pubkey, + source_pubkey: Option<&Pubkey>, +) -> Result { + let data = TokenInstruction::NewAccount.serialize()?; + + let mut accounts = vec![ + AccountMeta::new(*account_pubkey, true), + AccountMeta::new_readonly(*owner_pubkey, false), + AccountMeta::new_readonly(*token_pubkey, false), + ]; + if let Some(pubkey) = source_pubkey { + accounts.push(AccountMeta::new_readonly(*pubkey, false)); + } + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + +/// Creates a `Transfer` instruction +pub fn transfer( + token_program_id: &Pubkey, + owner_pubkey: &Pubkey, + account_pubkey: &Pubkey, + destination_pubkey: &Pubkey, + source_pubkey: Option<&Pubkey>, + amount: u64, +) -> Result { + let data = TokenInstruction::Transfer(amount).serialize()?; + + let mut accounts = vec![ + AccountMeta::new_readonly(*owner_pubkey, true), + AccountMeta::new(*account_pubkey, false), + AccountMeta::new(*destination_pubkey, false), + ]; + if let Some(pubkey) = source_pubkey { + accounts.push(AccountMeta::new(*pubkey, false)); + } + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + +/// Creates an `Approve` instruction +pub fn approve( + token_program_id: &Pubkey, + owner_pubkey: &Pubkey, + source_pubkey: &Pubkey, + delegate_pubkey: &Pubkey, + amount: u64, +) -> Result { + let data = TokenInstruction::Approve(amount).serialize()?; + + let accounts = vec![ + AccountMeta::new_readonly(*owner_pubkey, true), + AccountMeta::new_readonly(*source_pubkey, false), + AccountMeta::new(*delegate_pubkey, false), + ]; + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + +/// 0. `[signer]` Current owner of the account. +/// 1. `[writable]` account to change the owner of. +/// 2. `[]` New owner of the account. + +/// Creates an `SetOwner` instruction +pub fn set_owner( + token_program_id: &Pubkey, + owner_pubkey: &Pubkey, + account_pubkey: &Pubkey, + new_owner_pubkey: &Pubkey, +) -> Result { + let data = TokenInstruction::SetOwner.serialize()?; + + let accounts = vec![ + AccountMeta::new_readonly(*owner_pubkey, true), + AccountMeta::new(*account_pubkey, false), + AccountMeta::new_readonly(*new_owner_pubkey, false), + ]; + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + +/// Creates an `MintTo` instruction +pub fn mint_to( + token_program_id: &Pubkey, + owner_pubkey: &Pubkey, + token_pubkey: &Pubkey, + account_pubkey: &Pubkey, + amount: u64, +) -> Result { + let data = TokenInstruction::MintTo(amount).serialize()?; + + let accounts = vec![ + AccountMeta::new_readonly(*owner_pubkey, true), + AccountMeta::new(*token_pubkey, false), + AccountMeta::new(*account_pubkey, false), + ]; + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + +/// Creates an `Burn` instruction +pub fn burn( + token_program_id: &Pubkey, + owner_pubkey: &Pubkey, + account_pubkey: &Pubkey, + token_pubkey: &Pubkey, + source_pubkey: Option<&Pubkey>, + amount: u64, +) -> Result { + let data = TokenInstruction::Burn(amount).serialize()?; + + let mut accounts = vec![ + AccountMeta::new_readonly(*owner_pubkey, true), + AccountMeta::new(*account_pubkey, false), + AccountMeta::new(*token_pubkey, false), + ]; + if let Some(pubkey) = source_pubkey { + accounts.push(AccountMeta::new(*pubkey, false)); + } + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} diff --git a/token/src/state.rs b/token/src/state.rs index cff750732ba..c47dc56603d 100644 --- a/token/src/state.rs +++ b/token/src/state.rs @@ -2,7 +2,7 @@ use crate::{ error::TokenError, - instruction::{Instruction, TokenInfo}, + instruction::{TokenInfo, TokenInstruction}, }; use solana_sdk::{ account_info::AccountInfo, entrypoint::ProgramResult, info, program_error::ProgramError, @@ -71,7 +71,7 @@ impl Default for State { } impl<'a> State { - /// Processes a [NewToken](enum.Instruction.html) instruction. + /// Processes a [NewToken](enum.TokenInstruction.html) instruction. pub fn process_new_token>>( account_info_iter: &mut I, info: TokenInfo, @@ -117,7 +117,7 @@ impl<'a> State { State::Token(Token { info, owner }).serialize(&mut token_account_info.data.borrow_mut()) } - /// Processes a [NewAccount](enum.Instruction.html) instruction. + /// Processes a [NewAccount](enum.TokenInstruction.html) instruction. pub fn process_new_account>>( account_info_iter: &mut I, ) -> ProgramResult { @@ -151,7 +151,7 @@ impl<'a> State { State::Account(token_account).serialize(&mut new_account_data) } - /// Processes a [Transfer](enum.Instruction.html) instruction. + /// Processes a [Transfer](enum.TokenInstruction.html) instruction. pub fn process_transfer>>( account_info_iter: &mut I, amount: u64, @@ -214,7 +214,7 @@ impl<'a> State { Ok(()) } - /// Processes an [Approve](enum.Instruction.html) instruction. + /// Processes an [Approve](enum.TokenInstruction.html) instruction. pub fn process_approve>>( account_info_iter: &mut I, amount: u64, @@ -265,7 +265,7 @@ impl<'a> State { Ok(()) } - /// Processes a [SetOwner](enum.Instruction.html) instruction. + /// Processes a [SetOwner](enum.TokenInstruction.html) instruction. pub fn process_set_owner>>( account_info_iter: &mut I, ) -> ProgramResult { @@ -304,7 +304,7 @@ impl<'a> State { Ok(()) } - /// Processes a [MintTo](enum.Instruction.html) instruction. + /// Processes a [MintTo](enum.TokenInstruction.html) instruction. pub fn process_mintto>>( account_info_iter: &mut I, amount: u64, @@ -354,7 +354,7 @@ impl<'a> State { Ok(()) } - /// Processes a [Burn](enum.Instruction.html) instruction. + /// Processes a [Burn](enum.TokenInstruction.html) instruction. pub fn process_burn>>( account_info_iter: &mut I, amount: u64, @@ -431,35 +431,35 @@ impl<'a> State { accounts: &'a [AccountInfo<'a>], input: &[u8], ) -> ProgramResult { - let instruction = Instruction::deserialize(input)?; + let instruction = TokenInstruction::deserialize(input)?; let account_info_iter = &mut accounts.iter(); match instruction { - Instruction::NewToken(info) => { + TokenInstruction::NewToken(info) => { info!("Instruction: NewToken"); Self::process_new_token(account_info_iter, info) } - Instruction::NewAccount => { + TokenInstruction::NewAccount => { info!("Instruction: NewAccount"); Self::process_new_account(account_info_iter) } - Instruction::Transfer(amount) => { + TokenInstruction::Transfer(amount) => { info!("Instruction: Transfer"); Self::process_transfer(account_info_iter, amount) } - Instruction::Approve(amount) => { + TokenInstruction::Approve(amount) => { info!("Instruction: Approve"); Self::process_approve(account_info_iter, amount) } - Instruction::SetOwner => { + TokenInstruction::SetOwner => { info!("Instruction: SetOwner"); Self::process_set_owner(account_info_iter) } - Instruction::MintTo(amount) => { + TokenInstruction::MintTo(amount) => { info!("Instruction: MintTo"); Self::process_mintto(account_info_iter, amount) } - Instruction::Burn(amount) => { + TokenInstruction::Burn(amount) => { info!("Instruction: Burn"); Self::process_burn(account_info_iter, amount) } @@ -468,23 +468,17 @@ impl<'a> State { /// Deserializes a byte buffer into a Token Program [State](struct.State.html) pub fn deserialize(input: &'a [u8]) -> Result { - if input.len() < size_of::() { + if input.len() < size_of::() { return Err(ProgramError::InvalidAccountData); } Ok(match input[0] { 0 => Self::Unallocated, 1 => { - if input.len() < size_of::() + size_of::() { - return Err(ProgramError::InvalidAccountData); - } #[allow(clippy::cast_ptr_alignment)] let token: &Token = unsafe { &*(&input[1] as *const u8 as *const Token) }; Self::Token(*token) } 2 => { - if input.len() < size_of::() + size_of::() { - return Err(ProgramError::InvalidAccountData); - } #[allow(clippy::cast_ptr_alignment)] let account: &Account = unsafe { &*(&input[1] as *const u8 as *const Account) }; Self::Account(*account) @@ -496,24 +490,18 @@ impl<'a> State { /// Serializes Token Program [State](struct.State.html) into a byte buffer pub fn serialize(self: &Self, output: &mut [u8]) -> ProgramResult { - if output.len() < size_of::() { + if output.len() < size_of::() { return Err(ProgramError::InvalidAccountData); } match self { Self::Unallocated => output[0] = 0, Self::Token(token) => { - if output.len() < size_of::() + size_of::() { - return Err(ProgramError::InvalidAccountData); - } output[0] = 1; #[allow(clippy::cast_ptr_alignment)] let value = unsafe { &mut *(&mut output[1] as *mut u8 as *mut Token) }; *value = *token; } Self::Account(account) => { - if output.len() < size_of::() + size_of::() { - return Err(ProgramError::InvalidAccountData); - } output[0] = 2; #[allow(clippy::cast_ptr_alignment)] let value = unsafe { &mut *(&mut output[1] as *mut u8 as *mut Account) }; @@ -525,117 +513,6 @@ impl<'a> State { } } -impl Instruction { - /// Deserializes a byte buffer into an [Instruction](enum.Instruction.html) - pub fn deserialize(input: &[u8]) -> Result { - if input.len() < size_of::() { - return Err(ProgramError::InvalidAccountData); - } - Ok(match input[0] { - 0 => { - if input.len() < size_of::() + size_of::() { - return Err(ProgramError::InvalidAccountData); - } - #[allow(clippy::cast_ptr_alignment)] - let info: &TokenInfo = unsafe { &*(&input[1] as *const u8 as *const TokenInfo) }; - Self::NewToken(*info) - } - 1 => Self::NewAccount, - 2 => { - if input.len() < size_of::() + size_of::() { - return Err(ProgramError::InvalidAccountData); - } - #[allow(clippy::cast_ptr_alignment)] - let amount: &u64 = unsafe { &*(&input[1] as *const u8 as *const u64) }; - Self::Transfer(*amount) - } - 3 => { - if input.len() < size_of::() + size_of::() { - return Err(ProgramError::InvalidAccountData); - } - #[allow(clippy::cast_ptr_alignment)] - let amount: &u64 = unsafe { &*(&input[1] as *const u8 as *const u64) }; - Self::Approve(*amount) - } - 4 => Self::SetOwner, - 5 => { - if input.len() < size_of::() + size_of::() { - return Err(ProgramError::InvalidAccountData); - } - #[allow(clippy::cast_ptr_alignment)] - let amount: &u64 = unsafe { &*(&input[1] as *const u8 as *const u64) }; - Self::MintTo(*amount) - } - 6 => { - if input.len() < size_of::() + size_of::() { - return Err(ProgramError::InvalidAccountData); - } - #[allow(clippy::cast_ptr_alignment)] - let amount: &u64 = unsafe { &*(&input[1] as *const u8 as *const u64) }; - Self::Burn(*amount) - } - _ => return Err(ProgramError::InvalidAccountData), - }) - } - - /// Serializes an [Instruction](enum.Instruction.html) into a byte buffer - pub fn serialize(self: &Self, output: &mut [u8]) -> ProgramResult { - if output.len() < size_of::() { - return Err(ProgramError::InvalidAccountData); - } - match self { - Self::NewToken(info) => { - if output.len() < size_of::() + size_of::() { - return Err(ProgramError::InvalidAccountData); - } - output[0] = 0; - #[allow(clippy::cast_ptr_alignment)] - let value = unsafe { &mut *(&mut output[1] as *mut u8 as *mut TokenInfo) }; - *value = *info; - } - Self::NewAccount => output[0] = 1, - Self::Transfer(amount) => { - if output.len() < size_of::() + size_of::() { - return Err(ProgramError::InvalidAccountData); - } - output[0] = 2; - #[allow(clippy::cast_ptr_alignment)] - let value = unsafe { &mut *(&mut output[1] as *mut u8 as *mut u64) }; - *value = *amount; - } - Self::Approve(amount) => { - if output.len() < size_of::() + size_of::() { - return Err(ProgramError::InvalidAccountData); - } - output[0] = 3; - #[allow(clippy::cast_ptr_alignment)] - let value = unsafe { &mut *(&mut output[1] as *mut u8 as *mut u64) }; - *value = *amount; - } - Self::SetOwner => output[0] = 4, - Self::MintTo(amount) => { - if output.len() < size_of::() + size_of::() { - return Err(ProgramError::InvalidAccountData); - } - output[0] = 5; - #[allow(clippy::cast_ptr_alignment)] - let value = unsafe { &mut *(&mut output[1] as *mut u8 as *mut u64) }; - *value = *amount; - } - Self::Burn(amount) => { - if output.len() < size_of::() + size_of::() { - return Err(ProgramError::InvalidAccountData); - } - output[0] = 6; - #[allow(clippy::cast_ptr_alignment)] - let value = unsafe { &mut *(&mut output[1] as *mut u8 as *mut u64) }; - *value = *amount; - } - } - Ok(()) - } -} - // Pulls in the stubs required for `info!()` #[cfg(not(target_arch = "bpf"))] solana_sdk_bpf_test::stubs!(); @@ -643,19 +520,36 @@ solana_sdk_bpf_test::stubs!(); #[cfg(test)] mod tests { use super::*; - use solana_sdk::{account::Account, account_info::create_is_signer_account_infos}; + use crate::instruction::{approve, burn, mint_to, new_account, new_token, set_owner, transfer}; + use solana_sdk::{ + account::Account, account_info::create_is_signer_account_infos, instruction::Instruction, + }; fn new_pubkey(id: u8) -> Pubkey { - Pubkey::new(&vec![ + Pubkey::new(&[ id, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ]) } + fn do_process_instruction( + instruction: Instruction, + accounts: Vec<&mut Account>, + ) -> ProgramResult { + let mut meta = instruction + .accounts + .iter() + .zip(accounts) + .map(|(account_meta, account)| (&account_meta.pubkey, account_meta.is_signer, account)) + .collect::>(); + + let account_infos = create_is_signer_account_infos(&mut meta); + State::process(&instruction.program_id, &account_infos, &instruction.data) + } + #[test] fn test_new_token() { let program_id = new_pubkey(1); - let mut instruction_data = vec![0u8; size_of::()]; let token_account_key = new_pubkey(2); let mut token_account_account = Account::new(0, size_of::(), &program_id); let token_account2_key = new_pubkey(3); @@ -670,116 +564,157 @@ mod tests { let mut token2_account = Account::new(0, size_of::(), &program_id); // account not created - let instruction = Instruction::NewToken(TokenInfo { - supply: 1000, - decimals: 2, - }); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&token_key, true, &mut token_account), - (&token_account_key, false, &mut token_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); assert_eq!( Err(ProgramError::InvalidArgument), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + new_token( + &program_id, + &token_key, + Some(&token_account_key), + None, + TokenInfo { + supply: 1000, + decimals: 2, + } + ) + .unwrap(), + vec![&mut token_account, &mut token_account_account] + ) ); // create account - let instruction = Instruction::NewAccount; - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&token_account_key, true, &mut token_account_account), - (&owner_key, false, &mut owner_account), - (&token_key, false, &mut token_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + new_account( + &program_id, + &token_account_key, + &owner_key, + &token_key, + None, + ) + .unwrap(), + vec![ + &mut token_account_account, + &mut owner_account, + &mut token_account, + ], + ) + .unwrap(); // create new token - let instruction = Instruction::NewToken(TokenInfo { - supply: 1000, - decimals: 2, - }); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&token_key, true, &mut token_account), - (&token_account_key, false, &mut token_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + new_token( + &program_id, + &token_key, + Some(&token_account_key), + None, + TokenInfo { + supply: 1000, + decimals: 2, + }, + ) + .unwrap(), + vec![&mut token_account, &mut token_account_account], + ) + .unwrap(); // create another account - let instruction = Instruction::NewAccount; - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&token_account2_key, true, &mut token_account2_account), - (&owner_key, false, &mut owner_account), - (&token_key, false, &mut token_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + new_account( + &program_id, + &token_account2_key, + &owner_key, + &token_key, + None, + ) + .unwrap(), + vec![ + &mut token_account2_account, + &mut owner_account, + &mut token_account, + ], + ) + .unwrap(); // token mismatch - let instruction = Instruction::NewToken(TokenInfo { - supply: 1000, - decimals: 2, - }); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&token2_key, true, &mut token2_account), - (&token_account2_key, false, &mut token_account2_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); assert_eq!( Err(TokenError::TokenMismatch.into()), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + new_token( + &program_id, + &token2_key, + Some(&token_account2_key), + None, + TokenInfo { + supply: 1000, + decimals: 2, + }, + ) + .unwrap(), + vec![&mut token2_account, &mut token_account2_account] + ) ); // create delegate account - let instruction = Instruction::NewAccount; - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&delegate_account_key, true, &mut delegate_account_account), - (&owner_key, false, &mut owner_account), - (&token_key, false, &mut token_account), - (&token_account_key, false, &mut token_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + new_account( + &program_id, + &delegate_account_key, + &owner_key, + &token_key, + Some(&token_account_key), + ) + .unwrap(), + vec![ + &mut delegate_account_account, + &mut owner_account, + &mut token_account, + &mut token_account_account, + ], + ) + .unwrap(); // account is a delegate token - let instruction = Instruction::NewToken(TokenInfo { - supply: 1000, - decimals: 2, - }); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&token_key, true, &mut token_account), - (&delegate_account_key, false, &mut delegate_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); assert_eq!( Err(TokenError::AlreadyInUse.into()), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + new_token( + &program_id, + &token_key, + Some(&delegate_account_key), + None, + TokenInfo { + supply: 1000, + decimals: 2, + }, + ) + .unwrap(), + vec![&mut token_account, &mut delegate_account_account] + ) ); // create twice - let mut accounts = vec![ - (&token_key, true, &mut token_account), - (&token_account_key, false, &mut token_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); assert_eq!( Err(TokenError::AlreadyInUse.into()), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + new_token( + &program_id, + &token_key, + Some(&token_account_key), + None, + TokenInfo { + supply: 1000, + decimals: 2, + }, + ) + .unwrap(), + vec![&mut token_account, &mut token_account_account] + ) ); } #[test] fn test_new_token_account() { let program_id = new_pubkey(1); - let mut instruction_data = vec![0u8; size_of::()]; let token_account_key = new_pubkey(2); let mut token_account_account = Account::new(0, size_of::(), &program_id); let owner_key = new_pubkey(3); @@ -788,45 +723,69 @@ mod tests { let mut token_account = Account::new(0, size_of::(), &program_id); // missing signer - let instruction = Instruction::NewAccount; - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&token_account_key, false, &mut token_account_account), - (&owner_key, false, &mut owner_account), - (&token_key, false, &mut token_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); + let mut instruction = new_account( + &program_id, + &token_account_key, + &owner_key, + &token_key, + None, + ) + .unwrap(); + instruction.accounts[0].is_signer = false; assert_eq!( Err(ProgramError::MissingRequiredSignature), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + instruction, + vec![ + &mut token_account_account, + &mut owner_account, + &mut token_account, + ], + ) ); // create account - let mut accounts = vec![ - (&token_account_key, true, &mut token_account_account), - (&owner_key, false, &mut owner_account), - (&token_key, false, &mut token_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + new_account( + &program_id, + &token_account_key, + &owner_key, + &token_key, + None, + ) + .unwrap(), + vec![ + &mut token_account_account, + &mut owner_account, + &mut token_account, + ], + ) + .unwrap(); // create twice - let mut accounts = vec![ - (&token_account_key, true, &mut token_account_account), - (&owner_key, false, &mut owner_account), - (&token_key, false, &mut token_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); assert_eq!( Err(TokenError::AlreadyInUse.into()), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + new_account( + &program_id, + &token_account_key, + &owner_key, + &token_key, + None, + ) + .unwrap(), + vec![ + &mut token_account_account, + &mut owner_account, + &mut token_account, + ], + ) ); } #[test] fn test_transfer() { let program_id = new_pubkey(1); - let mut instruction_data = vec![0u8; size_of::()]; let token_account_key = new_pubkey(2); let mut token_account_account = Account::new(0, size_of::(), &program_id); let token_account2_key = new_pubkey(3); @@ -850,302 +809,462 @@ mod tests { let mut token2_account = Account::new(0, size_of::(), &program_id); // create account - let instruction = Instruction::NewAccount; - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&token_account_key, true, &mut token_account_account), - (&owner_key, false, &mut owner_account), - (&token_key, false, &mut token_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + new_account( + &program_id, + &token_account_key, + &owner_key, + &token_key, + None, + ) + .unwrap(), + vec![ + &mut token_account_account, + &mut owner_account, + &mut token_account, + ], + ) + .unwrap(); // create another account - let instruction = Instruction::NewAccount; - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&token_account2_key, true, &mut token_account2_account), - (&owner_key, false, &mut owner_account), - (&token_key, false, &mut token_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + new_account( + &program_id, + &token_account2_key, + &owner_key, + &token_key, + None, + ) + .unwrap(), + vec![ + &mut token_account2_account, + &mut owner_account, + &mut token_account, + ], + ) + .unwrap(); // create another account - let instruction = Instruction::NewAccount; - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&token_account3_key, true, &mut token_account3_account), - (&owner_key, false, &mut owner_account), - (&token_key, false, &mut token_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + new_account( + &program_id, + &token_account3_key, + &owner_key, + &token_key, + None, + ) + .unwrap(), + vec![ + &mut token_account3_account, + &mut owner_account, + &mut token_account, + ], + ) + .unwrap(); // create mismatch account - let instruction = Instruction::NewAccount; - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&mismatch_account_key, true, &mut mismatch_account_account), - (&owner_key, false, &mut owner_account), - (&token2_key, false, &mut token2_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + new_account( + &program_id, + &mismatch_account_key, + &owner_key, + &token2_key, + None, + ) + .unwrap(), + vec![ + &mut mismatch_account_account, + &mut owner_account, + &mut token2_account, + ], + ) + .unwrap(); // create delegate account - let instruction = Instruction::NewAccount; - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&delegate_account_key, true, &mut delegate_account_account), - (&owner_key, false, &mut owner_account), - (&token_key, false, &mut token_account), - (&token_account_key, false, &mut token_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + new_account( + &program_id, + &delegate_account_key, + &owner_key, + &token_key, + Some(&token_account_key), + ) + .unwrap(), + vec![ + &mut delegate_account_account, + &mut owner_account, + &mut token_account, + &mut token_account_account, + ], + ) + .unwrap(); // create mismatch delegate account - let instruction = Instruction::NewAccount; - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - ( + do_process_instruction( + new_account( + &program_id, &mismatch_delegate_account_key, - true, + &owner_key, + &token2_key, + Some(&token_account_key), + ) + .unwrap(), + vec![ &mut mismatch_delegate_account_account, - ), - (&owner_key, false, &mut owner_account), - (&token2_key, false, &mut token2_account), - (&token_account_key, false, &mut token_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + &mut owner_account, + &mut token2_account, + &mut token_account_account, + ], + ) + .unwrap(); // create new token - let instruction = Instruction::NewToken(TokenInfo { - supply: 1000, - decimals: 2, - }); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&token_key, true, &mut token_account), - (&token_account_key, false, &mut token_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + new_token( + &program_id, + &token_key, + Some(&token_account_key), + None, + TokenInfo { + supply: 1000, + decimals: 2, + }, + ) + .unwrap(), + vec![&mut token_account, &mut token_account_account], + ) + .unwrap(); // missing signer - let instruction = Instruction::Transfer(1000); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, false, &mut owner_account), - (&token_account_key, false, &mut token_account_account), - (&token_account2_key, false, &mut token_account2_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); + let mut instruction = transfer( + &program_id, + &owner_key, + &token_account_key, + &token_account2_key, + None, + 1000, + ) + .unwrap(); + instruction.accounts[0].is_signer = false; assert_eq!( Err(ProgramError::MissingRequiredSignature), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + instruction, + vec![ + &mut owner_account, + &mut token_account_account, + &mut token_account2_account, + ], + ) ); // destination is delegate - let instruction = Instruction::Transfer(1000); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&token_account2_key, false, &mut token_account2_account), - (&delegate_account_key, false, &mut delegate_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); assert_eq!( Err(TokenError::DestinationIsDelegate.into()), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + transfer( + &program_id, + &owner_key, + &token_account2_key, + &delegate_account_key, + None, + 1000, + ) + .unwrap(), + vec![ + &mut owner_account, + &mut token_account2_account, + &mut delegate_account_account, + ], + ) ); // mismatch token - let instruction = Instruction::Transfer(1000); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&token_account2_key, false, &mut token_account2_account), - (&mismatch_account_key, false, &mut mismatch_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); assert_eq!( Err(TokenError::TokenMismatch.into()), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + transfer( + &program_id, + &owner_key, + &token_account2_key, + &mismatch_account_key, + None, + 1000, + ) + .unwrap(), + vec![ + &mut owner_account, + &mut token_account2_account, + &mut mismatch_account_account, + ], + ) ); // missing owner - let instruction = Instruction::Transfer(1000); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner2_key, true, &mut owner2_account), - (&token_account_key, false, &mut token_account_account), - (&token_account2_key, false, &mut token_account2_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); assert_eq!( Err(TokenError::NoOwner.into()), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + transfer( + &program_id, + &owner2_key, + &token_account_key, + &token_account2_key, + None, + 1000, + ) + .unwrap(), + vec![ + &mut owner2_account, + &mut token_account_account, + &mut token_account2_account, + ], + ) ); // transfer - let instruction = Instruction::Transfer(1000); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&token_account_key, false, &mut token_account_account), - (&token_account2_key, false, &mut token_account2_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + transfer( + &program_id, + &owner_key, + &token_account_key, + &token_account2_key, + None, + 1000, + ) + .unwrap(), + vec![ + &mut owner_account, + &mut token_account_account, + &mut token_account2_account, + ], + ) + .unwrap(); // insufficient funds - let instruction = Instruction::Transfer(1); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&token_account_key, false, &mut token_account_account), - (&token_account2_key, false, &mut token_account2_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); assert_eq!( Err(TokenError::InsufficientFunds.into()), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + transfer( + &program_id, + &owner_key, + &token_account_key, + &token_account2_key, + None, + 1, + ) + .unwrap(), + vec![ + &mut owner_account, + &mut token_account_account, + &mut token_account2_account, + ], + ) ); // transfer half back - let instruction = Instruction::Transfer(500); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&token_account2_key, false, &mut token_account2_account), - (&token_account_key, false, &mut token_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + transfer( + &program_id, + &owner_key, + &token_account2_key, + &token_account_key, + None, + 500, + ) + .unwrap(), + vec![ + &mut owner_account, + &mut token_account2_account, + &mut token_account_account, + ], + ) + .unwrap(); // transfer rest - let instruction = Instruction::Transfer(500); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&token_account2_key, false, &mut token_account2_account), - (&token_account_key, false, &mut token_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + transfer( + &program_id, + &owner_key, + &token_account2_key, + &token_account_key, + None, + 500, + ) + .unwrap(), + vec![ + &mut owner_account, + &mut token_account2_account, + &mut token_account_account, + ], + ) + .unwrap(); // insufficient funds - let instruction = Instruction::Transfer(1); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&token_account2_key, false, &mut token_account2_account), - (&token_account_key, false, &mut token_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); assert_eq!( Err(TokenError::InsufficientFunds.into()), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + transfer( + &program_id, + &owner_key, + &token_account2_key, + &token_account_key, + None, + 1, + ) + .unwrap(), + vec![ + &mut owner_account, + &mut token_account2_account, + &mut token_account_account, + ], + ) ); // approve delegate - let instruction = Instruction::Approve(100); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&token_account_key, false, &mut token_account_account), - (&delegate_account_key, false, &mut delegate_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + approve( + &program_id, + &owner_key, + &token_account_key, + &delegate_account_key, + 100, + ) + .unwrap(), + vec![ + &mut owner_account, + &mut token_account_account, + &mut delegate_account_account, + ], + ) + .unwrap(); // not a delegate of source account - let instruction = Instruction::Transfer(100); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&delegate_account_key, false, &mut delegate_account_account), - (&token_account2_key, false, &mut token_account2_account), - (&token_account3_key, false, &mut token_account3_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); assert_eq!( Err(TokenError::NotDelegate.into()), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + transfer( + &program_id, + &owner_key, + &delegate_account_key, + &token_account2_key, + Some(&token_account3_key), + 100, + ) + .unwrap(), + vec![ + &mut owner_account, + &mut delegate_account_account, + &mut token_account2_account, + &mut token_account3_account + ], + ) ); // transfer via delegate - let instruction = Instruction::Transfer(100); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&delegate_account_key, false, &mut delegate_account_account), - (&token_account2_key, false, &mut token_account2_account), - (&token_account_key, false, &mut token_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + transfer( + &program_id, + &owner_key, + &delegate_account_key, + &token_account2_key, + Some(&token_account_key), + 100, + ) + .unwrap(), + vec![ + &mut owner_account, + &mut delegate_account_account, + &mut token_account2_account, + &mut token_account_account, + ], + ) + .unwrap(); // insufficient funds approved via delegate - let instruction = Instruction::Transfer(100); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&delegate_account_key, false, &mut delegate_account_account), - (&token_account2_key, false, &mut token_account2_account), - (&token_account_key, false, &mut token_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); assert_eq!( Err(TokenError::InsufficientFunds.into()), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + transfer( + &program_id, + &owner_key, + &delegate_account_key, + &token_account2_key, + Some(&token_account_key), + 100, + ) + .unwrap(), + vec![ + &mut owner_account, + &mut delegate_account_account, + &mut token_account2_account, + &mut token_account_account + ], + ) ); // transfer rest - let instruction = Instruction::Transfer(900); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&token_account_key, false, &mut token_account_account), - (&token_account2_key, false, &mut token_account2_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + transfer( + &program_id, + &owner_key, + &token_account_key, + &token_account2_key, + None, + 900, + ) + .unwrap(), + vec![ + &mut owner_account, + &mut token_account_account, + &mut token_account2_account, + ], + ) + .unwrap(); // approve delegate - let instruction = Instruction::Approve(100); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&token_account_key, false, &mut token_account_account), - (&delegate_account_key, false, &mut delegate_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + approve( + &program_id, + &owner_key, + &token_account_key, + &delegate_account_key, + 100, + ) + .unwrap(), + vec![ + &mut owner_account, + &mut token_account_account, + &mut delegate_account_account, + ], + ) + .unwrap(); // insufficient funds in source account via delegate - let instruction = Instruction::Transfer(100); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&delegate_account_key, false, &mut delegate_account_account), - (&token_account2_key, false, &mut token_account2_account), - (&token_account_key, false, &mut token_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); assert_eq!( Err(TokenError::InsufficientFunds.into()), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + transfer( + &program_id, + &owner_key, + &delegate_account_key, + &token_account2_key, + Some(&token_account_key), + 100, + ) + .unwrap(), + vec![ + &mut owner_account, + &mut delegate_account_account, + &mut token_account2_account, + &mut token_account_account + ], + ) ); } #[test] fn test_mintable_token_with_zero_supply() { let program_id = new_pubkey(1); - let mut instruction_data = vec![0u8; size_of::()]; let token_account_key = new_pubkey(2); let mut token_account_account = Account::new(0, size_of::(), &program_id); let owner_key = new_pubkey(6); @@ -1154,27 +1273,39 @@ mod tests { let mut token_account = Account::new(0, size_of::(), &program_id); // create account - let instruction = Instruction::NewAccount; - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&token_account_key, true, &mut token_account_account), - (&owner_key, false, &mut owner_account), - (&token_key, false, &mut token_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + new_account( + &program_id, + &token_account_key, + &owner_key, + &token_key, + None, + ) + .unwrap(), + vec![ + &mut token_account_account, + &mut owner_account, + &mut token_account, + ], + ) + .unwrap(); // create mintable token without owner - let instruction = Instruction::NewToken(TokenInfo { - supply: 0, - decimals: 2, - }); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![(&token_key, true, &mut token_account)]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); + let mut instruction = new_token( + &program_id, + &token_key, + None, + Some(&owner_key), + TokenInfo { + supply: 0, + decimals: 2, + }, + ) + .unwrap(); + instruction.accounts.pop(); assert_eq!( Err(TokenError::OwnerRequiredIfNoInitialSupply.into()), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction(instruction, vec![&mut token_account]) ); // create mintable token with zero supply @@ -1182,15 +1313,11 @@ mod tests { supply: 0, decimals: 2, }; - let instruction = Instruction::NewToken(info); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&token_key, true, &mut token_account), - (&owner_key, false, &mut owner_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); - + do_process_instruction( + new_token(&program_id, &token_key, None, Some(&owner_key), info).unwrap(), + vec![&mut token_account, &mut token_account_account], + ) + .unwrap(); if let State::Token(token) = State::deserialize(&token_account.data).unwrap() { assert_eq!( token, @@ -1204,15 +1331,15 @@ mod tests { } // mint to - let instruction = Instruction::MintTo(42); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&token_key, false, &mut token_account), - (&token_account_key, false, &mut token_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + mint_to(&program_id, &owner_key, &token_key, &token_account_key, 42).unwrap(), + vec![ + &mut owner_account, + &mut token_account, + &mut token_account_account, + ], + ) + .unwrap(); if let State::Token(token) = State::deserialize(&token_account.data).unwrap() { assert_eq!(token.info.supply, 42); @@ -1231,7 +1358,6 @@ mod tests { #[test] fn test_approve() { let program_id = new_pubkey(1); - let mut instruction_data = vec![0u8; size_of::()]; let token_account_key = new_pubkey(2); let mut token_account_account = Account::new(0, size_of::(), &program_id); let token_account2_key = new_pubkey(3); @@ -1251,172 +1377,240 @@ mod tests { let mut token2_account = Account::new(0, size_of::(), &program_id); // create account - let instruction = Instruction::NewAccount; - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&token_account_key, true, &mut token_account_account), - (&owner_key, false, &mut owner_account), - (&token_key, false, &mut token_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + new_account( + &program_id, + &token_account_key, + &owner_key, + &token_key, + None, + ) + .unwrap(), + vec![ + &mut token_account_account, + &mut owner_account, + &mut token_account, + ], + ) + .unwrap(); // create another account - let instruction = Instruction::NewAccount; - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&token_account2_key, true, &mut token_account2_account), - (&owner_key, false, &mut owner_account), - (&token_key, false, &mut token_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + new_account( + &program_id, + &token_account2_key, + &owner_key, + &token_key, + None, + ) + .unwrap(), + vec![ + &mut token_account2_account, + &mut owner_account, + &mut token_account, + ], + ) + .unwrap(); // create delegate account - let instruction = Instruction::NewAccount; - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&delegate_account_key, true, &mut delegate_account_account), - (&owner_key, false, &mut owner_account), - (&token_key, false, &mut token_account), - (&token_account_key, false, &mut token_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + new_account( + &program_id, + &delegate_account_key, + &owner_key, + &token_key, + Some(&token_account_key), + ) + .unwrap(), + vec![ + &mut delegate_account_account, + &mut owner_account, + &mut token_account, + &mut token_account_account, + ], + ) + .unwrap(); // create mismatch delegate account - let instruction = Instruction::NewAccount; - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - ( + do_process_instruction( + new_account( + &program_id, &mismatch_delegate_account_key, - true, + &owner_key, + &token2_key, + Some(&token_account_key), + ) + .unwrap(), + vec![ &mut mismatch_delegate_account_account, - ), - (&owner_key, false, &mut owner_account), - (&token2_key, false, &mut token2_account), - (&token_account_key, false, &mut token_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + &mut owner_account, + &mut token2_account, + &mut token_account_account, + ], + ) + .unwrap(); // create new token - let instruction = Instruction::NewToken(TokenInfo { - supply: 1000, - decimals: 2, - }); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&token_key, true, &mut token_account), - (&token_account_key, false, &mut token_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + new_token( + &program_id, + &token_key, + Some(&token_account_key), + None, + TokenInfo { + supply: 1000, + decimals: 2, + }, + ) + .unwrap(), + vec![&mut token_account, &mut token_account_account], + ) + .unwrap(); // token mismatch - let instruction = Instruction::Approve(100); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&token_account_key, false, &mut token_account_account), - ( - &mismatch_delegate_account_key, - false, - &mut mismatch_delegate_account_account, - ), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); assert_eq!( Err(TokenError::TokenMismatch.into()), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + approve( + &program_id, + &owner_key, + &token_account_key, + &mismatch_delegate_account_key, + 100, + ) + .unwrap(), + vec![ + &mut owner_account, + &mut token_account_account, + &mut mismatch_delegate_account_account, + ], + ) ); // missing signer - let instruction = Instruction::Approve(100); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, false, &mut owner_account), - (&token_account_key, false, &mut token_account_account), - (&delegate_account_key, false, &mut delegate_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); + let mut instruction = approve( + &program_id, + &owner_key, + &token_account_key, + &delegate_account_key, + 100, + ) + .unwrap(); + instruction.accounts[0].is_signer = false; assert_eq!( Err(ProgramError::MissingRequiredSignature), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + instruction, + vec![ + &mut owner_account, + &mut token_account_account, + &mut delegate_account_account, + ], + ) ); - // missing signer - let instruction = Instruction::Approve(100); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner2_key, true, &mut owner2_account), - (&token_account_key, false, &mut token_account_account), - (&delegate_account_key, false, &mut delegate_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); + // no owner assert_eq!( Err(TokenError::NoOwner.into()), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + approve( + &program_id, + &owner2_key, + &token_account_key, + &delegate_account_key, + 100, + ) + .unwrap(), + vec![ + &mut owner2_account, + &mut token_account_account, + &mut delegate_account_account, + ], + ) ); // destination is delegate - let instruction = Instruction::Approve(100); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&delegate_account_key, false, &mut delegate_account_account), - (&token_account_key, false, &mut token_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); assert_eq!( Err(ProgramError::InvalidArgument), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + approve( + &program_id, + &owner_key, + &delegate_account_key, + &token_account_key, + 100, + ) + .unwrap(), + vec![ + &mut owner_account, + &mut delegate_account_account, + &mut token_account_account, + ], + ) ); // not a delegate - let instruction = Instruction::Approve(100); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&token_account2_key, false, &mut token_account2_account), - (&token_account_key, false, &mut token_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); assert_eq!( Err(TokenError::NotDelegate.into()), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + approve( + &program_id, + &owner_key, + &token_account2_key, + &token_account_key, + 100, + ) + .unwrap(), + vec![ + &mut owner_account, + &mut token_account2_account, + &mut token_account_account, + ], + ) ); // not a delegate of source - let instruction = Instruction::Approve(100); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&token_account2_key, false, &mut token_account2_account), - (&delegate_account_key, false, &mut delegate_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); assert_eq!( Err(TokenError::NotDelegate.into()), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + approve( + &program_id, + &owner_key, + &token_account2_key, + &delegate_account_key, + 100, + ) + .unwrap(), + vec![ + &mut owner_account, + &mut token_account2_account, + &mut delegate_account_account, + ], + ) ); // approve delegate - let instruction = Instruction::Approve(100); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&token_account_key, false, &mut token_account_account), - (&delegate_account_key, false, &mut delegate_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + approve( + &program_id, + &owner_key, + &token_account_key, + &delegate_account_key, + 100, + ) + .unwrap(), + vec![ + &mut owner_account, + &mut token_account_account, + &mut delegate_account_account, + ], + ) + .unwrap(); } #[test] fn test_set_owner() { let program_id = new_pubkey(1); - let mut instruction_data = vec![0u8; size_of::()]; let token_account_key = new_pubkey(2); let mut token_account_account = Account::new(0, size_of::(), &program_id); let token_account2_key = new_pubkey(2); @@ -1433,157 +1627,172 @@ mod tests { let mut token2_account = Account::new(0, size_of::(), &program_id); // invalid account - let instruction = Instruction::SetOwner; - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, false, &mut owner_account), - (&token_account_key, false, &mut token_account_account), - (&owner2_key, false, &mut owner2_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); assert_eq!( Err(ProgramError::InvalidArgument), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + set_owner(&program_id, &owner_key, &token_account_key, &owner2_key,).unwrap(), + vec![ + &mut owner_account, + &mut token_account_account, + &mut owner2_account, + ], + ) ); // create account - let instruction = Instruction::NewAccount; - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&token_account_key, true, &mut token_account_account), - (&owner_key, false, &mut owner_account), - (&token_key, false, &mut token_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + new_account( + &program_id, + &token_account_key, + &owner_key, + &token_key, + None, + ) + .unwrap(), + vec![ + &mut token_account_account, + &mut owner_account, + &mut token_account, + ], + ) + .unwrap(); // create token account - let instruction = Instruction::NewAccount; - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&token_account2_key, true, &mut token_account2_account), - (&owner_key, false, &mut owner_account), - (&token2_key, false, &mut token2_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + new_account( + &program_id, + &token_account2_key, + &owner_key, + &token2_key, + None, + ) + .unwrap(), + vec![ + &mut token_account2_account, + &mut owner_account, + &mut token2_account, + ], + ) + .unwrap(); // missing owner - let instruction = Instruction::SetOwner; - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner2_key, false, &mut owner2_account), - (&token_account_key, false, &mut token_account_account), - (&owner3_key, false, &mut owner3_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); assert_eq!( Err(TokenError::NoOwner.into()), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + set_owner(&program_id, &owner2_key, &token_account_key, &owner_key,).unwrap(), + vec![ + &mut owner2_account, + &mut token_account_account, + &mut owner_account, + ], + ) ); // owner did not sign - let mut accounts = vec![ - (&owner_key, false, &mut owner_account), - (&token_account_key, true, &mut token_account_account), - (&owner2_key, false, &mut owner2_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); + let mut instruction = + set_owner(&program_id, &owner_key, &token_account_key, &owner2_key).unwrap(); + instruction.accounts[0].is_signer = false; assert_eq!( Err(ProgramError::MissingRequiredSignature), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + instruction, + vec![ + &mut owner_account, + &mut token_account_account, + &mut owner2_account, + ], + ) ); // set owner - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&token_account_key, true, &mut token_account_account), - (&owner2_key, false, &mut owner2_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + set_owner(&program_id, &owner_key, &token_account_key, &owner2_key).unwrap(), + vec![ + &mut owner_account, + &mut token_account_account, + &mut owner2_account, + ], + ) + .unwrap(); // create new token with owner - let instruction = Instruction::NewToken(TokenInfo { - supply: 1000, - decimals: 2, - }); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&token_key, true, &mut token_account), - (&token_account_key, false, &mut token_account_account), - (&owner_key, false, &mut owner_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); - - // missing owner - let instruction = Instruction::SetOwner; - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner2_key, false, &mut owner2_account), - (&token_key, false, &mut token_account), - (&owner3_key, false, &mut owner3_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); + do_process_instruction( + new_token( + &program_id, + &token_key, + Some(&token_account_key), + Some(&owner_key), + TokenInfo { + supply: 1000, + decimals: 2, + }, + ) + .unwrap(), + vec![ + &mut token_account, + &mut token_account_account, + &mut owner_account, + ], + ) + .unwrap(); + + // wrong account assert_eq!( Err(TokenError::NoOwner.into()), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + set_owner(&program_id, &owner2_key, &token_key, &owner3_key,).unwrap(), + vec![&mut owner2_account, &mut token_account, &mut owner3_account,], + ) ); // owner did not sign - let mut accounts = vec![ - (&owner_key, false, &mut owner_account), - (&token_key, true, &mut token_account), - (&owner2_key, false, &mut owner2_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); + let mut instruction = set_owner(&program_id, &owner_key, &token_key, &owner2_key).unwrap(); + instruction.accounts[0].is_signer = false; assert_eq!( Err(ProgramError::MissingRequiredSignature), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + instruction, + vec![&mut owner_account, &mut token_account, &mut owner2_account,], + ) ); // set owner - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&token_key, true, &mut token_account), - (&owner2_key, false, &mut owner2_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + set_owner(&program_id, &owner_key, &token_key, &owner2_key).unwrap(), + vec![&mut owner_account, &mut token_account, &mut owner2_account], + ) + .unwrap(); // create new token without owner - let instruction = Instruction::NewToken(TokenInfo { - supply: 1000, - decimals: 2, - }); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&token2_key, true, &mut token2_account), - (&token_account2_key, false, &mut token_account2_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + new_token( + &program_id, + &token2_key, + Some(&token_account2_key), + None, + TokenInfo { + supply: 1000, + decimals: 2, + }, + ) + .unwrap(), + vec![&mut token2_account, &mut token_account2_account], + ) + .unwrap(); // set owner for unownable token - let instruction = Instruction::SetOwner; - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&token2_key, true, &mut token2_account), - (&owner2_key, false, &mut owner2_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); assert_eq!( Err(TokenError::NoOwner.into()), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + set_owner(&program_id, &owner_key, &token2_key, &owner2_key,).unwrap(), + vec![&mut owner_account, &mut token_account, &mut owner2_account,], + ) ); } #[test] fn test_mint_to() { let program_id = new_pubkey(1); - let mut instruction_data = vec![0u8; size_of::()]; let token_account_key = new_pubkey(2); let mut token_account_account = Account::new(0, size_of::(), &program_id); let token_account2_key = new_pubkey(3); @@ -1606,85 +1815,127 @@ mod tests { let mut uninitialized_account = Account::new(0, size_of::(), &program_id); // create token account - let instruction = Instruction::NewAccount; - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&token_account_key, true, &mut token_account_account), - (&owner_key, false, &mut owner_account), - (&token_key, false, &mut token_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + new_account( + &program_id, + &token_account_key, + &owner_key, + &token_key, + None, + ) + .unwrap(), + vec![ + &mut token_account_account, + &mut owner_account, + &mut token_account, + ], + ) + .unwrap(); // create another token account - let instruction = Instruction::NewAccount; - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&token_account2_key, true, &mut token_account2_account), - (&owner_key, false, &mut owner_account), - (&token_key, false, &mut token_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + new_account( + &program_id, + &token_account2_key, + &owner_key, + &token_key, + None, + ) + .unwrap(), + vec![ + &mut token_account2_account, + &mut owner_account, + &mut token_account, + ], + ) + .unwrap(); // create another token account - let instruction = Instruction::NewAccount; - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&token_account3_key, true, &mut token_account3_account), - (&owner_key, false, &mut owner_account), - (&token_key, false, &mut token_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + new_account( + &program_id, + &token_account3_key, + &owner_key, + &token_key, + None, + ) + .unwrap(), + vec![ + &mut token_account3_account, + &mut owner_account, + &mut token_account, + ], + ) + .unwrap(); // create mismatch token account - let instruction = Instruction::NewAccount; - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&mismatch_account_key, true, &mut mismatch_account_account), - (&owner_key, false, &mut owner_account), - (&token2_key, false, &mut token2_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + new_account( + &program_id, + &mismatch_account_key, + &owner_key, + &token2_key, + None, + ) + .unwrap(), + vec![ + &mut mismatch_account_account, + &mut owner_account, + &mut token2_account, + ], + ) + .unwrap(); // create delegate account - let instruction = Instruction::NewAccount; - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&delegate_account_key, true, &mut delegate_account_account), - (&owner_key, false, &mut owner_account), - (&token_key, false, &mut token_account), - (&token_account_key, false, &mut token_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + new_account( + &program_id, + &delegate_account_key, + &owner_key, + &token_key, + Some(&token_account_key), + ) + .unwrap(), + vec![ + &mut delegate_account_account, + &mut owner_account, + &mut token_account, + &mut token_account_account, + ], + ) + .unwrap(); // create new token with owner - let instruction = Instruction::NewToken(TokenInfo { - supply: 1000, - decimals: 2, - }); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&token_key, true, &mut token_account), - (&token_account_key, false, &mut token_account_account), - (&owner_key, false, &mut owner_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + new_token( + &program_id, + &token_key, + Some(&token_account_key), + Some(&owner_key), + TokenInfo { + supply: 1000, + decimals: 2, + }, + ) + .unwrap(), + vec![ + &mut token_account, + &mut token_account_account, + &mut owner_account, + ], + ) + .unwrap(); // mint to - let instruction = Instruction::MintTo(42); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&token_key, false, &mut token_account), - (&token_account2_key, false, &mut token_account2_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + mint_to(&program_id, &owner_key, &token_key, &token_account2_key, 42).unwrap(), + vec![ + &mut owner_account, + &mut token_account, + &mut token_account2_account, + ], + ) + .unwrap(); if let State::Token(token) = State::deserialize(&token_account.data).unwrap() { assert_eq!(token.info.supply, 1000 + 42); @@ -1700,80 +1951,98 @@ mod tests { } // missing signer - let instruction = Instruction::MintTo(42); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, false, &mut owner_account), - (&token_key, false, &mut token_account), - (&token_account2_key, false, &mut token_account2_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); + let mut instruction = + mint_to(&program_id, &owner_key, &token_key, &token_account2_key, 42).unwrap(); + instruction.accounts[0].is_signer = false; assert_eq!( Err(ProgramError::MissingRequiredSignature), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + instruction, + vec![ + &mut owner_account, + &mut token_account, + &mut token_account2_account, + ], + ) ); // destination is delegate - let instruction = Instruction::MintTo(42); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&token_key, false, &mut token_account), - (&delegate_account_key, false, &mut delegate_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); assert_eq!( Err(TokenError::DestinationIsDelegate.into()), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + mint_to( + &program_id, + &owner_key, + &token_key, + &delegate_account_key, + 42 + ) + .unwrap(), + vec![ + &mut owner_account, + &mut token_account, + &mut delegate_account_account, + ], + ) ); // mismatch token - let instruction = Instruction::MintTo(42); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&token_key, false, &mut token_account), - (&mismatch_account_key, false, &mut mismatch_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); assert_eq!( Err(TokenError::TokenMismatch.into()), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + mint_to( + &program_id, + &owner_key, + &token_key, + &mismatch_account_key, + 42 + ) + .unwrap(), + vec![ + &mut owner_account, + &mut token_account, + &mut mismatch_account_account, + ], + ) ); // missing owner - let instruction = Instruction::MintTo(42); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner2_key, true, &mut owner2_account), - (&token_key, false, &mut token_account), - (&token_account2_key, false, &mut token_account2_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); assert_eq!( Err(TokenError::NoOwner.into()), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + mint_to( + &program_id, + &owner2_key, + &token_key, + &token_account2_key, + 42 + ) + .unwrap(), + vec![ + &mut owner2_account, + &mut token_account, + &mut token_account2_account, + ], + ) ); // uninitialized destination account - let instruction = Instruction::MintTo(42); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&token_key, false, &mut token_account), - (&uninitialized_key, false, &mut uninitialized_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); assert_eq!( Err(ProgramError::InvalidArgument), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + mint_to(&program_id, &owner_key, &token_key, &uninitialized_key, 42).unwrap(), + vec![ + &mut owner_account, + &mut token_account, + &mut uninitialized_account, + ], + ) ); } #[test] fn test_burn() { let program_id = new_pubkey(1); - let mut instruction_data = vec![0u8; size_of::()]; let token_account_key = new_pubkey(2); let mut token_account_account = Account::new(0, size_of::(), &program_id); let token_account2_key = new_pubkey(3); @@ -1797,142 +2066,214 @@ mod tests { let mut token2_account = Account::new(0, size_of::(), &program_id); // create token account - let instruction = Instruction::NewAccount; - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&token_account_key, true, &mut token_account_account), - (&owner_key, false, &mut owner_account), - (&token_key, false, &mut token_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + new_account( + &program_id, + &token_account_key, + &owner_key, + &token_key, + None, + ) + .unwrap(), + vec![ + &mut token_account_account, + &mut owner_account, + &mut token_account, + ], + ) + .unwrap(); // create another token account - let instruction = Instruction::NewAccount; - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&token_account2_key, true, &mut token_account2_account), - (&owner_key, false, &mut owner_account), - (&token_key, false, &mut token_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + new_account( + &program_id, + &token_account2_key, + &owner_key, + &token_key, + None, + ) + .unwrap(), + vec![ + &mut token_account2_account, + &mut owner_account, + &mut token_account, + ], + ) + .unwrap(); // create another token account - let instruction = Instruction::NewAccount; - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&token_account3_key, true, &mut token_account3_account), - (&owner_key, false, &mut owner_account), - (&token_key, false, &mut token_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + new_account( + &program_id, + &token_account3_key, + &owner_key, + &token_key, + None, + ) + .unwrap(), + vec![ + &mut token_account3_account, + &mut owner_account, + &mut token_account, + ], + ) + .unwrap(); // create mismatch token account - let instruction = Instruction::NewAccount; - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&mismatch_account_key, true, &mut mismatch_account_account), - (&owner_key, false, &mut owner_account), - (&token2_key, false, &mut token2_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + new_account( + &program_id, + &mismatch_account_key, + &owner_key, + &token2_key, + None, + ) + .unwrap(), + vec![ + &mut mismatch_account_account, + &mut owner_account, + &mut token2_account, + ], + ) + .unwrap(); // create delegate account - let instruction = Instruction::NewAccount; - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&delegate_account_key, true, &mut delegate_account_account), - (&owner_key, false, &mut owner_account), - (&token_key, false, &mut token_account), - (&token_account_key, false, &mut token_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); - + do_process_instruction( + new_account( + &program_id, + &delegate_account_key, + &owner_key, + &token_key, + Some(&token_account_key), + ) + .unwrap(), + vec![ + &mut delegate_account_account, + &mut owner_account, + &mut token_account, + &mut token_account_account, + ], + ) + .unwrap(); // create mismatch delegate account - let instruction = Instruction::NewAccount; - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - ( + do_process_instruction( + new_account( + &program_id, &mismatch_delegate_account_key, - true, + &owner_key, + &token2_key, + Some(&token_account_key), + ) + .unwrap(), + vec![ &mut mismatch_delegate_account_account, - ), - (&owner_key, false, &mut owner_account), - (&token2_key, false, &mut token2_account), - (&token_account_key, false, &mut token_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + &mut owner_account, + &mut token2_account, + &mut token_account_account, + ], + ) + .unwrap(); // create new token - let instruction = Instruction::NewToken(TokenInfo { - supply: 1000, - decimals: 2, - }); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&token_key, true, &mut token_account), - (&token_account_key, false, &mut token_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + new_token( + &program_id, + &token_key, + Some(&token_account_key), + None, + TokenInfo { + supply: 1000, + decimals: 2, + }, + ) + .unwrap(), + vec![&mut token_account, &mut token_account_account], + ) + .unwrap(); // missing signer - let instruction = Instruction::Burn(42); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, false, &mut owner_account), - (&token_account_key, false, &mut token_account_account), - (&token_key, false, &mut token_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); + let mut instruction = burn( + &program_id, + &owner_key, + &token_account_key, + &token_key, + None, + 42, + ) + .unwrap(); + instruction.accounts[0].is_signer = false; assert_eq!( Err(ProgramError::MissingRequiredSignature), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + instruction, + vec![ + &mut owner_account, + &mut token_account_account, + &mut token_account + ], + ) ); // mismatch token - let instruction = Instruction::Burn(42); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&mismatch_account_key, false, &mut mismatch_account_account), - (&token_key, false, &mut token_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); assert_eq!( Err(TokenError::TokenMismatch.into()), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + burn( + &program_id, + &owner_key, + &mismatch_account_key, + &token_key, + None, + 42 + ) + .unwrap(), + vec![ + &mut owner_account, + &mut mismatch_account_account, + &mut token_account + ], + ) ); // missing owner - let instruction = Instruction::Burn(42); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner2_key, true, &mut owner2_account), - (&token_account_key, false, &mut token_account_account), - (&token_key, false, &mut token_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); assert_eq!( Err(TokenError::NoOwner.into()), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + burn( + &program_id, + &owner2_key, + &token_account_key, + &token_key, + None, + 42 + ) + .unwrap(), + vec![ + &mut owner2_account, + &mut token_account_account, + &mut token_account + ], + ) ); // burn - let instruction = Instruction::Burn(42); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&token_account_key, false, &mut token_account_account), - (&token_key, false, &mut token_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + burn( + &program_id, + &owner_key, + &token_account_key, + &token_key, + None, + 42, + ) + .unwrap(), + vec![ + &mut owner_account, + &mut token_account_account, + &mut token_account, + ], + ) + .unwrap(); if let State::Token(token) = State::deserialize(&token_account.data).unwrap() { assert_eq!(token.info.supply, 1000 - 42); @@ -1946,56 +2287,84 @@ mod tests { } // insufficient funds - let instruction = Instruction::Burn(100000000); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&token_account_key, false, &mut token_account_account), - (&token_key, false, &mut token_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); assert_eq!( Err(TokenError::InsufficientFunds.into()), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + burn( + &program_id, + &owner_key, + &token_account_key, + &token_key, + None, + 100_000_000 + ) + .unwrap(), + vec![ + &mut owner_account, + &mut token_account_account, + &mut token_account + ], + ) ); // approve delegate - let instruction = Instruction::Approve(84); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&token_account_key, false, &mut token_account_account), - (&delegate_account_key, false, &mut delegate_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + approve( + &program_id, + &owner_key, + &token_account_key, + &delegate_account_key, + 84, + ) + .unwrap(), + vec![ + &mut owner_account, + &mut token_account_account, + &mut delegate_account_account, + ], + ) + .unwrap(); // not a delegate of source account - let instruction = Instruction::Burn(84); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&delegate_account_key, false, &mut delegate_account_account), - (&token_key, false, &mut token_account), - (&token_account2_key, false, &mut token_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); assert_eq!( - Err(TokenError::NotDelegate.into()), - State::process(&program_id, &mut account_infos, &instruction_data) + Err(TokenError::InsufficientFunds.into()), + do_process_instruction( + burn( + &program_id, + &owner_key, + &token_account_key, + &token_key, + None, + 100_000_000 + ) + .unwrap(), + vec![ + &mut owner_account, + &mut token_account_account, + &mut token_account + ], + ) ); // burn via delegate - let instruction = Instruction::Burn(84); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&delegate_account_key, false, &mut delegate_account_account), - (&token_key, false, &mut token_account), - (&token_account_key, false, &mut token_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); - State::process(&program_id, &mut account_infos, &instruction_data).unwrap(); + do_process_instruction( + burn( + &program_id, + &owner_key, + &delegate_account_key, + &token_key, + Some(&token_account_key), + 84, + ) + .unwrap(), + vec![ + &mut owner_account, + &mut delegate_account_account, + &mut token_account, + &mut token_account_account, + ], + ) + .unwrap(); if let State::Token(token) = State::deserialize(&token_account.data).unwrap() { assert_eq!(token.info.supply, 1000 - 42 - 84); @@ -2009,18 +2378,25 @@ mod tests { } // insufficient funds approved via delegate - let instruction = Instruction::Burn(100); - instruction.serialize(&mut instruction_data).unwrap(); - let mut accounts = vec![ - (&owner_key, true, &mut owner_account), - (&delegate_account_key, false, &mut delegate_account_account), - (&token_key, false, &mut token_account), - (&token_account_key, false, &mut token_account_account), - ]; - let mut account_infos = create_is_signer_account_infos(&mut accounts); assert_eq!( Err(TokenError::InsufficientFunds.into()), - State::process(&program_id, &mut account_infos, &instruction_data) + do_process_instruction( + burn( + &program_id, + &owner_key, + &delegate_account_key, + &token_key, + Some(&token_account_key), + 100, + ) + .unwrap(), + vec![ + &mut owner_account, + &mut delegate_account_account, + &mut token_account, + &mut token_account_account, + ], + ) ); } }