Combine Account is_native and rent_exempt_reserve fields; wrapped SOL amount reflects only amoutn over rent_exempt_reserve

This commit is contained in:
Tyera Eulberg 2020-08-27 01:20:49 -06:00 committed by Michael Vines
parent 181cdfa170
commit 8d0ba35407
2 changed files with 60 additions and 34 deletions

View File

@ -78,11 +78,11 @@ impl Processor {
account.delegated_amount = 0;
account.state = AccountState::Initialized;
if *mint_info.key == crate::native_mint::id() {
account.is_native = true;
account.amount = new_account_info.lamports();
account.rent_exempt_reserve = rent.minimum_balance(new_account_info_data_len);
let rent_exempt_reserve = rent.minimum_balance(new_account_info_data_len);
account.is_native = COption::Some(rent_exempt_reserve);
account.amount = new_account_info.lamports() - rent_exempt_reserve;
} else {
account.is_native = false;
account.is_native = COption::None;
account.amount = 0;
};
@ -183,11 +183,7 @@ impl Processor {
.checked_add(amount)
.ok_or(TokenError::Overflow)?;
if source_account.is_native {
// Ensure that wrapped SOL accounts remain rent-exempt
if source_account_info.lamports() < source_account.rent_exempt_reserve + amount {
return Err(TokenError::InsufficientFunds.into());
}
if source_account.is_native() {
**source_account_info.lamports.borrow_mut() -= amount;
**dest_account_info.lamports.borrow_mut() += amount;
}
@ -362,7 +358,7 @@ impl Processor {
return Err(TokenError::AccountFrozen.into());
}
if dest_account.is_native {
if dest_account.is_native() {
return Err(TokenError::NativeNotSupported.into());
}
if mint_info.key != &dest_account.mint {
@ -407,7 +403,7 @@ impl Processor {
let mut source_data = source_account_info.data.borrow_mut();
let source_account: &mut Account = state::unpack(&mut source_data)?;
if source_account.is_native {
if source_account.is_native() {
return Err(TokenError::NativeNotSupported.into());
}
if source_account.amount < amount {
@ -457,7 +453,7 @@ impl Processor {
let mut source_data = source_account_info.data.borrow_mut();
let source_account: &mut Account = state::unpack(&mut source_data)?;
if !source_account.is_native && source_account.amount != 0 {
if !source_account.is_native() && source_account.amount != 0 {
return Err(TokenError::NonNativeHasBalance.into());
}
@ -493,7 +489,7 @@ impl Processor {
let mut source_data = source_account_info.data.borrow_mut();
let source_account: &mut Account = state::unpack(&mut source_data)?;
if source_account.is_native {
if source_account.is_native() {
return Err(TokenError::NativeNotSupported.into());
}
if mint_info.key != &source_account.mint {
@ -2626,8 +2622,11 @@ mod tests {
let mut account_account =
SolanaAccount::new(account_minimum_balance(), size_of::<Account>(), &program_id);
let account2_key = pubkey_rand();
let mut account2_account =
SolanaAccount::new(account_minimum_balance(), size_of::<Account>(), &program_id);
let mut account2_account = SolanaAccount::new(
account_minimum_balance() + 42,
size_of::<Account>(),
&program_id,
);
let account3_key = pubkey_rand();
let mut account3_account =
SolanaAccount::new(account_minimum_balance(), size_of::<Account>(), &program_id);
@ -2697,8 +2696,8 @@ mod tests {
)
.unwrap();
let account: &mut Account = state::unpack(&mut account2_account.data).unwrap();
assert!(account.is_native);
assert_eq!(account.amount, account_minimum_balance());
assert!(account.is_native());
assert_eq!(account.amount, 42);
// close non-native account with balance
assert_eq!(
@ -2820,10 +2819,13 @@ mod tests {
)
.unwrap();
let account: &mut Account = state::unpack_unchecked(&mut account2_account.data).unwrap();
assert!(account.is_native);
assert!(account.is_native());
assert_eq!(account_account.lamports, 0);
assert_eq!(account.amount, 0);
assert_eq!(account3_account.lamports, 3 * account_minimum_balance() + 2);
assert_eq!(
account3_account.lamports,
3 * account_minimum_balance() + 2 + 42
);
}
#[test]
@ -2864,8 +2866,8 @@ mod tests {
)
.unwrap();
let account: &mut Account = state::unpack(&mut account_account.data).unwrap();
assert!(account.is_native);
assert_eq!(account.amount, account_minimum_balance() + 40);
assert!(account.is_native());
assert_eq!(account.amount, 40);
// initialize native account
do_process_instruction(
@ -2885,8 +2887,8 @@ mod tests {
)
.unwrap();
let account: &mut Account = state::unpack(&mut account2_account.data).unwrap();
assert!(account.is_native);
assert_eq!(account.amount, account_minimum_balance());
assert!(account.is_native());
assert_eq!(account.amount, 0);
// mint_to unsupported
assert_eq!(
@ -2914,7 +2916,28 @@ mod tests {
)
);
// initialize native account
// ensure can't transfer below rent-exempt reserve
assert_eq!(
Err(TokenError::InsufficientFunds.into()),
do_process_instruction(
transfer(
&program_id,
&account_key,
&account2_key,
&owner_key,
&[],
50,
)
.unwrap(),
vec![
&mut account_account,
&mut account2_account,
&mut owner_account,
],
)
);
// transfer between native accounts
do_process_instruction(
transfer(
&program_id,
@ -2934,13 +2957,13 @@ mod tests {
.unwrap();
let account: &mut Account = state::unpack(&mut account_account.data).unwrap();
assert!(account.is_native);
assert!(account.is_native());
assert_eq!(account_account.lamports, account_minimum_balance());
assert_eq!(account.amount, account_minimum_balance());
assert_eq!(account.amount, 0);
let account: &mut Account = state::unpack(&mut account2_account.data).unwrap();
assert!(account.is_native);
assert!(account.is_native());
assert_eq!(account2_account.lamports, account_minimum_balance() + 40);
assert_eq!(account.amount, account_minimum_balance() + 40);
assert_eq!(account.amount, 40);
// close native account
do_process_instruction(
@ -2953,7 +2976,7 @@ mod tests {
)
.unwrap();
let account: &mut Account = state::unpack_unchecked(&mut account_account.data).unwrap();
assert!(account.is_native);
assert!(account.is_native());
assert_eq!(account_account.lamports, 0);
assert_eq!(account.amount, 0);
assert_eq!(account3_account.lamports, 2 * account_minimum_balance());

View File

@ -40,21 +40,24 @@ pub struct Account {
pub delegate: COption<Pubkey>,
/// The account's state
pub state: AccountState,
/// Is this a native token
pub is_native: bool,
/// If is_some, this is a native token, and the value logs the rent-exempt reserve. An Account
/// is required to be rent-exempt, so the value is used by the Processor to ensure that wrapped
/// SOL accounts do not drop below this threshold.
pub is_native: COption<u64>,
/// The amount delegated
pub delegated_amount: u64,
/// Optional authority to close the account.
pub close_authority: COption<Pubkey>,
/// An Account is required to be rent-exempt. This value logs the reserve required to be
/// rent-exempt so that wrapped SOL accounts do not drop below this threshold.
pub rent_exempt_reserve: u64,
}
impl Account {
/// Checks if account is frozen
pub fn is_frozen(&self) -> bool {
self.state == AccountState::Frozen
}
/// Checks if account is native
pub fn is_native(&self) -> bool {
self.is_native.is_some()
}
}
impl IsInitialized for Account {
fn is_initialized(&self) -> bool {