|
@@ -161,19 +161,18 @@ impl Processor {
|
|
|
return Ok(());
|
|
|
}
|
|
|
|
|
|
- let mut source_data = source_account_info.data.borrow_mut();
|
|
|
- let mut dest_data = dest_account_info.data.borrow_mut();
|
|
|
- Account::unpack_mut(&mut source_data, &mut |source_account: &mut Account| {
|
|
|
- Account::unpack_mut(&mut dest_data, &mut |dest_account: &mut Account| {
|
|
|
+ let mut source_account = Account::unpack(&source_account_info.data.borrow())?;
|
|
|
+ let mut dest_account = Account::unpack(&dest_account_info.data.borrow())?;
|
|
|
+
|
|
|
if source_account.amount < amount {
|
|
|
return Err(TokenError::InsufficientFunds.into());
|
|
|
}
|
|
|
- if source_account.mint != dest_account.mint {
|
|
|
- return Err(TokenError::MintMismatch.into());
|
|
|
- }
|
|
|
if source_account.is_frozen() || dest_account.is_frozen() {
|
|
|
return Err(TokenError::AccountFrozen.into());
|
|
|
}
|
|
|
+ if source_account.mint != dest_account.mint {
|
|
|
+ return Err(TokenError::MintMismatch.into());
|
|
|
+ }
|
|
|
|
|
|
if let Some((mint_info, expected_decimals)) = expected_mint_info {
|
|
|
if source_account.mint != *mint_info.key {
|
|
@@ -234,9 +233,10 @@ impl Processor {
|
|
|
.ok_or(TokenError::Overflow)?;
|
|
|
}
|
|
|
|
|
|
+ Account::pack(source_account, &mut source_account_info.data.borrow_mut())?;
|
|
|
+ Account::pack(dest_account, &mut dest_account_info.data.borrow_mut())?;
|
|
|
+
|
|
|
Ok(())
|
|
|
- })
|
|
|
- })
|
|
|
}
|
|
|
|
|
|
/// Processes an [Approve](enum.TokenInstruction.html) instruction.
|
|
@@ -815,6 +815,13 @@ mod tests {
|
|
|
Processor::process(&instruction.program_id, &account_infos, &instruction.data)
|
|
|
}
|
|
|
|
|
|
+ fn do_process_instruction_dups(
|
|
|
+ instruction: Instruction,
|
|
|
+ account_infos: Vec<AccountInfo>,
|
|
|
+ ) -> ProgramResult {
|
|
|
+ Processor::process(&instruction.program_id, &account_infos, &instruction.data)
|
|
|
+ }
|
|
|
+
|
|
|
fn return_token_error_as_program_error() -> ProgramError {
|
|
|
TokenError::MintMismatch.into()
|
|
|
}
|
|
@@ -1089,6 +1096,318 @@ mod tests {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
+ #[test]
|
|
|
+ fn test_transfer_dups() {
|
|
|
+ let program_id = pubkey_rand();
|
|
|
+ let account1_key = pubkey_rand();
|
|
|
+ let mut 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_rand();
|
|
|
+ let mut 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_rand();
|
|
|
+ let mut 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_rand();
|
|
|
+ let mut 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_rand();
|
|
|
+ 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_rand();
|
|
|
+ let mut owner_account = SolanaAccount::default();
|
|
|
+ let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into();
|
|
|
+ let mint_key = pubkey_rand();
|
|
|
+ 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(&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(&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(&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(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(),
|
|
|
+ vec![mint_info.clone(), account1_info.clone(), owner_info.clone()],
|
|
|
+ )
|
|
|
+ .unwrap();
|
|
|
+
|
|
|
+ // source-owner transfer
|
|
|
+ do_process_instruction_dups(
|
|
|
+ transfer(
|
|
|
+ &program_id,
|
|
|
+ &account1_key,
|
|
|
+ &account2_key,
|
|
|
+ &account1_key,
|
|
|
+ &[],
|
|
|
+ 500,
|
|
|
+ )
|
|
|
+ .unwrap(),
|
|
|
+ vec![
|
|
|
+ account1_info.clone(),
|
|
|
+ account2_info.clone(),
|
|
|
+ account1_info.clone(),
|
|
|
+ ],
|
|
|
+ )
|
|
|
+ .unwrap();
|
|
|
+
|
|
|
+ // source-owner transfer2
|
|
|
+ do_process_instruction_dups(
|
|
|
+ transfer2(
|
|
|
+ &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-delegate transfer
|
|
|
+ Account::unpack_unchecked_mut(
|
|
|
+ &mut account1_info.data.borrow_mut(),
|
|
|
+ &mut |account: &mut Account| {
|
|
|
+ account.amount = 1000;
|
|
|
+ account.delegated_amount = 1000;
|
|
|
+ account.delegate = COption::Some(account1_key);
|
|
|
+ account.owner = owner_key;
|
|
|
+ Ok(())
|
|
|
+ },
|
|
|
+ )
|
|
|
+ .unwrap();
|
|
|
+
|
|
|
+ do_process_instruction_dups(
|
|
|
+ transfer(
|
|
|
+ &program_id,
|
|
|
+ &account1_key,
|
|
|
+ &account2_key,
|
|
|
+ &account1_key,
|
|
|
+ &[],
|
|
|
+ 500,
|
|
|
+ )
|
|
|
+ .unwrap(),
|
|
|
+ vec![
|
|
|
+ account1_info.clone(),
|
|
|
+ account2_info.clone(),
|
|
|
+ account1_info.clone(),
|
|
|
+ ],
|
|
|
+ )
|
|
|
+ .unwrap();
|
|
|
+
|
|
|
+ // source-delegate transfer2
|
|
|
+ do_process_instruction_dups(
|
|
|
+ transfer2(
|
|
|
+ &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();
|
|
|
+
|
|
|
+ // test destination-owner transfer
|
|
|
+ do_process_instruction_dups(
|
|
|
+ initialize_account(&program_id, &account3_key, &mint_key, &account2_key).unwrap(),
|
|
|
+ vec![
|
|
|
+ account3_info.clone(),
|
|
|
+ mint_info.clone(),
|
|
|
+ account2_info.clone(),
|
|
|
+ rent_info.clone(),
|
|
|
+ ],
|
|
|
+ )
|
|
|
+ .unwrap();
|
|
|
+ do_process_instruction_dups(
|
|
|
+ mint_to(&program_id, &mint_key, &account3_key, &owner_key, &[], 1000).unwrap(),
|
|
|
+ vec![mint_info.clone(), account3_info.clone(), owner_info.clone()],
|
|
|
+ )
|
|
|
+ .unwrap();
|
|
|
+
|
|
|
+ account1_info.is_signer = false;
|
|
|
+ account2_info.is_signer = true;
|
|
|
+ do_process_instruction_dups(
|
|
|
+ transfer(
|
|
|
+ &program_id,
|
|
|
+ &account3_key,
|
|
|
+ &account2_key,
|
|
|
+ &account2_key,
|
|
|
+ &[],
|
|
|
+ 500,
|
|
|
+ )
|
|
|
+ .unwrap(),
|
|
|
+ vec![
|
|
|
+ account3_info.clone(),
|
|
|
+ account2_info.clone(),
|
|
|
+ account2_info.clone(),
|
|
|
+ ],
|
|
|
+ )
|
|
|
+ .unwrap();
|
|
|
+
|
|
|
+ // destination-owner transfer2
|
|
|
+ do_process_instruction_dups(
|
|
|
+ transfer2(
|
|
|
+ &program_id,
|
|
|
+ &account3_key,
|
|
|
+ &mint_key,
|
|
|
+ &account2_key,
|
|
|
+ &account2_key,
|
|
|
+ &[],
|
|
|
+ 500,
|
|
|
+ 2,
|
|
|
+ )
|
|
|
+ .unwrap(),
|
|
|
+ vec![
|
|
|
+ account3_info.clone(),
|
|
|
+ mint_info.clone(),
|
|
|
+ account2_info.clone(),
|
|
|
+ account2_info.clone(),
|
|
|
+ ],
|
|
|
+ )
|
|
|
+ .unwrap();
|
|
|
+
|
|
|
+ // test source-multisig signer
|
|
|
+ do_process_instruction_dups(
|
|
|
+ initialize_multisig(&program_id, &multisig_key, &[&account4_key], 1).unwrap(),
|
|
|
+ vec![
|
|
|
+ multisig_info.clone(),
|
|
|
+ rent_info.clone(),
|
|
|
+ account4_info.clone(),
|
|
|
+ ],
|
|
|
+ )
|
|
|
+ .unwrap();
|
|
|
+
|
|
|
+ do_process_instruction_dups(
|
|
|
+ initialize_account(&program_id, &account4_key, &mint_key, &multisig_key).unwrap(),
|
|
|
+ vec![
|
|
|
+ account4_info.clone(),
|
|
|
+ mint_info.clone(),
|
|
|
+ multisig_info.clone(),
|
|
|
+ rent_info.clone(),
|
|
|
+ ],
|
|
|
+ )
|
|
|
+ .unwrap();
|
|
|
+
|
|
|
+ do_process_instruction_dups(
|
|
|
+ mint_to(&program_id, &mint_key, &account4_key, &owner_key, &[], 1000).unwrap(),
|
|
|
+ vec![mint_info.clone(), account4_info.clone(), owner_info.clone()],
|
|
|
+ )
|
|
|
+ .unwrap();
|
|
|
+
|
|
|
+ // source-multisig-signer transfer
|
|
|
+ do_process_instruction_dups(
|
|
|
+ transfer(
|
|
|
+ &program_id,
|
|
|
+ &account4_key,
|
|
|
+ &account2_key,
|
|
|
+ &multisig_key,
|
|
|
+ &[&account4_key],
|
|
|
+ 500,
|
|
|
+ )
|
|
|
+ .unwrap(),
|
|
|
+ vec![
|
|
|
+ account4_info.clone(),
|
|
|
+ account2_info.clone(),
|
|
|
+ multisig_info.clone(),
|
|
|
+ account4_info.clone(),
|
|
|
+ ],
|
|
|
+ )
|
|
|
+ .unwrap();
|
|
|
+
|
|
|
+ // source-multisig-signer transfer2
|
|
|
+ do_process_instruction_dups(
|
|
|
+ transfer2(
|
|
|
+ &program_id,
|
|
|
+ &account4_key,
|
|
|
+ &mint_key,
|
|
|
+ &account2_key,
|
|
|
+ &multisig_key,
|
|
|
+ &[&account4_key],
|
|
|
+ 500,
|
|
|
+ 2,
|
|
|
+ )
|
|
|
+ .unwrap(),
|
|
|
+ vec![
|
|
|
+ account4_info.clone(),
|
|
|
+ mint_info.clone(),
|
|
|
+ account2_info.clone(),
|
|
|
+ multisig_info.clone(),
|
|
|
+ account4_info.clone(),
|
|
|
+ ],
|
|
|
+ )
|
|
|
+ .unwrap();
|
|
|
+ }
|
|
|
+
|
|
|
#[test]
|
|
|
fn test_transfer() {
|
|
|
let program_id = pubkey_rand();
|