From 288b4388688c1c5e6e37d226ef3ac192149069c7 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Fri, 11 Sep 2020 20:52:53 -0600 Subject: [PATCH] Allow destination or mint to be mint_authority in MintTo and MintTo2 (#436) * Add failing test * No need to hold dest or mint RefMut in process_mint_to --- token/program-v3/src/processor.rs | 171 +++++++++++++++++++++++------- 1 file changed, 134 insertions(+), 37 deletions(-) diff --git a/token/program-v3/src/processor.rs b/token/program-v3/src/processor.rs index bfb29f10093e1d..850359a2d6eba5 100644 --- a/token/program-v3/src/processor.rs +++ b/token/program-v3/src/processor.rs @@ -421,50 +421,49 @@ impl Processor { let dest_account_info = next_account_info(account_info_iter)?; let owner_info = next_account_info(account_info_iter)?; - let mut dest_account_data = dest_account_info.data.borrow_mut(); - Account::unpack_mut(&mut dest_account_data, &mut |dest_account: &mut Account| { - if dest_account.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } + let mut dest_account = Account::unpack(&dest_account_info.data.borrow())?; + if dest_account.is_frozen() { + return Err(TokenError::AccountFrozen.into()); + } - if dest_account.is_native() { - return Err(TokenError::NativeNotSupported.into()); - } - if mint_info.key != &dest_account.mint { - return Err(TokenError::MintMismatch.into()); + if dest_account.is_native() { + return Err(TokenError::NativeNotSupported.into()); + } + if mint_info.key != &dest_account.mint { + return Err(TokenError::MintMismatch.into()); + } + + let mut mint = Mint::unpack(&mint_info.data.borrow())?; + if let Some(expected_decimals) = expected_decimals { + if expected_decimals != mint.decimals { + return Err(TokenError::MintDecimalsMismatch.into()); } + } - let mut mint_data = mint_info.data.borrow_mut(); - Mint::unpack_mut(&mut mint_data, &mut |mint: &mut Mint| { - if let Some(expected_decimals) = expected_decimals { - if expected_decimals != mint.decimals { - return Err(TokenError::MintDecimalsMismatch.into()); - } - } + match mint.mint_authority { + COption::Some(mint_authority) => Self::validate_owner( + program_id, + &mint_authority, + owner_info, + account_info_iter.as_slice(), + )?, + COption::None => return Err(TokenError::FixedSupply.into()), + } - match mint.mint_authority { - COption::Some(mint_authority) => Self::validate_owner( - program_id, - &mint_authority, - owner_info, - account_info_iter.as_slice(), - )?, - COption::None => return Err(TokenError::FixedSupply.into()), - } + dest_account.amount = dest_account + .amount + .checked_add(amount) + .ok_or(TokenError::Overflow)?; - dest_account.amount = dest_account - .amount - .checked_add(amount) - .ok_or(TokenError::Overflow)?; + mint.supply = mint + .supply + .checked_add(amount) + .ok_or(TokenError::Overflow)?; - mint.supply = mint - .supply - .checked_add(amount) - .ok_or(TokenError::Overflow)?; + Account::pack(dest_account, &mut dest_account_info.data.borrow_mut())?; + Mint::pack(mint, &mut mint_info.data.borrow_mut())?; - Ok(()) - }) - }) + Ok(()) } /// Processes a [Burn](enum.TokenInstruction.html) instruction. @@ -2524,6 +2523,104 @@ mod tests { ); } + #[test] + fn test_mint_to_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 account1_info: AccountInfo = (&account1_key, true, &mut account1_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, true, &mut mint_account).into(); + let rent_key = rent::id(); + let mut rent_sysvar = rent_sysvar(); + let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); + + // create mint + do_process_instruction_dups( + initialize_mint(&program_id, &mint_key, &mint_key, None, 2).unwrap(), + vec![mint_info.clone(), rent_info.clone()], + ) + .unwrap(); + + // create account + do_process_instruction_dups( + initialize_account(&program_id, &account1_key, &mint_key, &owner_key).unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + owner_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + + // mint_to when mint_authority is self + do_process_instruction_dups( + mint_to(&program_id, &mint_key, &account1_key, &mint_key, &[], 42).unwrap(), + vec![mint_info.clone(), account1_info.clone(), mint_info.clone()], + ) + .unwrap(); + + // mint_to2 when mint_authority is self + do_process_instruction_dups( + mint_to2(&program_id, &mint_key, &account1_key, &mint_key, &[], 42, 2).unwrap(), + vec![mint_info.clone(), account1_info.clone(), mint_info.clone()], + ) + .unwrap(); + + // mint_to when mint_authority is account owner + Mint::unpack_unchecked_mut(&mut mint_info.data.borrow_mut(), &mut |mint: &mut Mint| { + mint.mint_authority = COption::Some(account1_key); + Ok(()) + }) + .unwrap(); + do_process_instruction_dups( + mint_to( + &program_id, + &mint_key, + &account1_key, + &account1_key, + &[], + 42, + ) + .unwrap(), + vec![ + mint_info.clone(), + account1_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // mint_to2 when mint_authority is account owner + do_process_instruction_dups( + mint_to( + &program_id, + &mint_key, + &account1_key, + &account1_key, + &[], + 42, + ) + .unwrap(), + vec![ + mint_info.clone(), + account1_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + } + #[test] fn test_mint_to() { let program_id = pubkey_rand();