Allow source to be owner/close_authority in CloseAccount (#438)
* Add failing tests * No need to hold source RefMut in process_close_account and process_toggle_freeze_account
This commit is contained in:
parent
1fcc84beb3
commit
6c9e8ac1ce
|
@ -552,32 +552,32 @@ impl Processor {
|
||||||
let dest_account_info = next_account_info(account_info_iter)?;
|
let dest_account_info = next_account_info(account_info_iter)?;
|
||||||
let authority_info = next_account_info(account_info_iter)?;
|
let authority_info = next_account_info(account_info_iter)?;
|
||||||
|
|
||||||
let mut source_data = source_account_info.data.borrow_mut();
|
let mut source_account = Account::unpack(&source_account_info.data.borrow())?;
|
||||||
Account::unpack_mut(&mut source_data, &mut |source_account: &mut Account| {
|
if !source_account.is_native() && source_account.amount != 0 {
|
||||||
if !source_account.is_native() && source_account.amount != 0 {
|
return Err(TokenError::NonNativeHasBalance.into());
|
||||||
return Err(TokenError::NonNativeHasBalance.into());
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let authority = source_account
|
let authority = source_account
|
||||||
.close_authority
|
.close_authority
|
||||||
.unwrap_or(source_account.owner);
|
.unwrap_or(source_account.owner);
|
||||||
Self::validate_owner(
|
Self::validate_owner(
|
||||||
program_id,
|
program_id,
|
||||||
&authority,
|
&authority,
|
||||||
authority_info,
|
authority_info,
|
||||||
account_info_iter.as_slice(),
|
account_info_iter.as_slice(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let dest_starting_lamports = dest_account_info.lamports();
|
let dest_starting_lamports = dest_account_info.lamports();
|
||||||
**dest_account_info.lamports.borrow_mut() = dest_starting_lamports
|
**dest_account_info.lamports.borrow_mut() = dest_starting_lamports
|
||||||
.checked_add(source_account_info.lamports())
|
.checked_add(source_account_info.lamports())
|
||||||
.ok_or(TokenError::Overflow)?;
|
.ok_or(TokenError::Overflow)?;
|
||||||
|
|
||||||
**source_account_info.lamports.borrow_mut() = 0;
|
**source_account_info.lamports.borrow_mut() = 0;
|
||||||
source_account.amount = 0;
|
source_account.amount = 0;
|
||||||
|
|
||||||
Ok(())
|
Account::pack(source_account, &mut source_account_info.data.borrow_mut())?;
|
||||||
})
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Processes a [FreezeAccount](enum.TokenInstruction.html) or a
|
/// Processes a [FreezeAccount](enum.TokenInstruction.html) or a
|
||||||
|
@ -592,37 +592,37 @@ impl Processor {
|
||||||
let mint_info = next_account_info(account_info_iter)?;
|
let mint_info = next_account_info(account_info_iter)?;
|
||||||
let authority_info = next_account_info(account_info_iter)?;
|
let authority_info = next_account_info(account_info_iter)?;
|
||||||
|
|
||||||
let mut source_data = source_account_info.data.borrow_mut();
|
let mut source_account = Account::unpack(&source_account_info.data.borrow())?;
|
||||||
Account::unpack_mut(&mut source_data, &mut |source_account: &mut Account| {
|
if source_account.is_native() {
|
||||||
if source_account.is_native() {
|
return Err(TokenError::NativeNotSupported.into());
|
||||||
return Err(TokenError::NativeNotSupported.into());
|
}
|
||||||
}
|
if mint_info.key != &source_account.mint {
|
||||||
if mint_info.key != &source_account.mint {
|
return Err(TokenError::MintMismatch.into());
|
||||||
return Err(TokenError::MintMismatch.into());
|
}
|
||||||
}
|
if freeze && source_account.is_frozen() || !freeze && !source_account.is_frozen() {
|
||||||
if freeze && source_account.is_frozen() || !freeze && !source_account.is_frozen() {
|
return Err(TokenError::InvalidState.into());
|
||||||
return Err(TokenError::InvalidState.into());
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let mint = Mint::unpack(&mint_info.data.borrow_mut())?;
|
let mint = Mint::unpack(&mint_info.data.borrow_mut())?;
|
||||||
match mint.freeze_authority {
|
match mint.freeze_authority {
|
||||||
COption::Some(authority) => Self::validate_owner(
|
COption::Some(authority) => Self::validate_owner(
|
||||||
program_id,
|
program_id,
|
||||||
&authority,
|
&authority,
|
||||||
authority_info,
|
authority_info,
|
||||||
account_info_iter.as_slice(),
|
account_info_iter.as_slice(),
|
||||||
),
|
),
|
||||||
COption::None => Err(TokenError::MintCannotFreeze.into()),
|
COption::None => Err(TokenError::MintCannotFreeze.into()),
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
source_account.state = if freeze {
|
source_account.state = if freeze {
|
||||||
AccountState::Frozen
|
AccountState::Frozen
|
||||||
} else {
|
} else {
|
||||||
AccountState::Initialized
|
AccountState::Initialized
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(())
|
Account::pack(source_account, &mut source_account_info.data.borrow_mut())?;
|
||||||
})
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Processes an [Instruction](enum.Instruction.html).
|
/// Processes an [Instruction](enum.Instruction.html).
|
||||||
|
@ -3566,6 +3566,97 @@ mod tests {
|
||||||
signers[5].is_signer = true;
|
signers[5].is_signer = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_close_account_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 account2_key = pubkey_rand();
|
||||||
|
let mut account2_account = SolanaAccount::new(
|
||||||
|
account_minimum_balance(),
|
||||||
|
Account::get_packed_len(),
|
||||||
|
&program_id,
|
||||||
|
);
|
||||||
|
let account2_info: AccountInfo = (&account2_key, true, &mut account2_account).into();
|
||||||
|
let owner_key = pubkey_rand();
|
||||||
|
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();
|
||||||
|
|
||||||
|
// source-owner close
|
||||||
|
do_process_instruction_dups(
|
||||||
|
close_account(
|
||||||
|
&program_id,
|
||||||
|
&account1_key,
|
||||||
|
&account2_key,
|
||||||
|
&account1_key,
|
||||||
|
&[],
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
vec![
|
||||||
|
account1_info.clone(),
|
||||||
|
account2_info.clone(),
|
||||||
|
account1_info.clone(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// source-close-authority close
|
||||||
|
Account::unpack_unchecked_mut(
|
||||||
|
&mut account1_info.data.borrow_mut(),
|
||||||
|
&mut |account: &mut Account| {
|
||||||
|
account.close_authority = COption::Some(account1_key);
|
||||||
|
account.owner = owner_key;
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
do_process_instruction_dups(
|
||||||
|
close_account(
|
||||||
|
&program_id,
|
||||||
|
&account1_key,
|
||||||
|
&account2_key,
|
||||||
|
&account1_key,
|
||||||
|
&[],
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
vec![
|
||||||
|
account1_info.clone(),
|
||||||
|
account2_info.clone(),
|
||||||
|
account1_info.clone(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_close_account() {
|
fn test_close_account() {
|
||||||
let program_id = pubkey_rand();
|
let program_id = pubkey_rand();
|
||||||
|
@ -4389,6 +4480,75 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_freeze_thaw_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 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, &owner_key, Some(&account1_key), 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();
|
||||||
|
|
||||||
|
// freeze where mint freeze_authority is account
|
||||||
|
do_process_instruction_dups(
|
||||||
|
freeze_account(&program_id, &account1_key, &mint_key, &account1_key, &[]).unwrap(),
|
||||||
|
vec![
|
||||||
|
account1_info.clone(),
|
||||||
|
mint_info.clone(),
|
||||||
|
account1_info.clone(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// thaw where mint freeze_authority is account
|
||||||
|
Account::unpack_unchecked_mut(
|
||||||
|
&mut account1_info.data.borrow_mut(),
|
||||||
|
&mut |account: &mut Account| {
|
||||||
|
account.state = AccountState::Frozen;
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
do_process_instruction_dups(
|
||||||
|
thaw_account(&program_id, &account1_key, &mint_key, &account1_key, &[]).unwrap(),
|
||||||
|
vec![
|
||||||
|
account1_info.clone(),
|
||||||
|
mint_info.clone(),
|
||||||
|
account1_info.clone(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_freeze_account() {
|
fn test_freeze_account() {
|
||||||
let program_id = pubkey_rand();
|
let program_id = pubkey_rand();
|
||||||
|
|
Loading…
Reference in New Issue