Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.

Commit 8d0ba35

Browse files
Tyera Eulbergmvines
authored andcommitted
Combine Account is_native and rent_exempt_reserve fields; wrapped SOL amount reflects only amoutn over rent_exempt_reserve
1 parent 181cdfa commit 8d0ba35

File tree

2 files changed

+60
-34
lines changed

2 files changed

+60
-34
lines changed

token/program/src/processor.rs

Lines changed: 52 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,11 @@ impl Processor {
7878
account.delegated_amount = 0;
7979
account.state = AccountState::Initialized;
8080
if *mint_info.key == crate::native_mint::id() {
81-
account.is_native = true;
82-
account.amount = new_account_info.lamports();
83-
account.rent_exempt_reserve = rent.minimum_balance(new_account_info_data_len);
81+
let rent_exempt_reserve = rent.minimum_balance(new_account_info_data_len);
82+
account.is_native = COption::Some(rent_exempt_reserve);
83+
account.amount = new_account_info.lamports() - rent_exempt_reserve;
8484
} else {
85-
account.is_native = false;
85+
account.is_native = COption::None;
8686
account.amount = 0;
8787
};
8888

@@ -183,11 +183,7 @@ impl Processor {
183183
.checked_add(amount)
184184
.ok_or(TokenError::Overflow)?;
185185

186-
if source_account.is_native {
187-
// Ensure that wrapped SOL accounts remain rent-exempt
188-
if source_account_info.lamports() < source_account.rent_exempt_reserve + amount {
189-
return Err(TokenError::InsufficientFunds.into());
190-
}
186+
if source_account.is_native() {
191187
**source_account_info.lamports.borrow_mut() -= amount;
192188
**dest_account_info.lamports.borrow_mut() += amount;
193189
}
@@ -362,7 +358,7 @@ impl Processor {
362358
return Err(TokenError::AccountFrozen.into());
363359
}
364360

365-
if dest_account.is_native {
361+
if dest_account.is_native() {
366362
return Err(TokenError::NativeNotSupported.into());
367363
}
368364
if mint_info.key != &dest_account.mint {
@@ -407,7 +403,7 @@ impl Processor {
407403
let mut source_data = source_account_info.data.borrow_mut();
408404
let source_account: &mut Account = state::unpack(&mut source_data)?;
409405

410-
if source_account.is_native {
406+
if source_account.is_native() {
411407
return Err(TokenError::NativeNotSupported.into());
412408
}
413409
if source_account.amount < amount {
@@ -457,7 +453,7 @@ impl Processor {
457453
let mut source_data = source_account_info.data.borrow_mut();
458454
let source_account: &mut Account = state::unpack(&mut source_data)?;
459455

460-
if !source_account.is_native && source_account.amount != 0 {
456+
if !source_account.is_native() && source_account.amount != 0 {
461457
return Err(TokenError::NonNativeHasBalance.into());
462458
}
463459

@@ -493,7 +489,7 @@ impl Processor {
493489
let mut source_data = source_account_info.data.borrow_mut();
494490
let source_account: &mut Account = state::unpack(&mut source_data)?;
495491

496-
if source_account.is_native {
492+
if source_account.is_native() {
497493
return Err(TokenError::NativeNotSupported.into());
498494
}
499495
if mint_info.key != &source_account.mint {
@@ -2626,8 +2622,11 @@ mod tests {
26262622
let mut account_account =
26272623
SolanaAccount::new(account_minimum_balance(), size_of::<Account>(), &program_id);
26282624
let account2_key = pubkey_rand();
2629-
let mut account2_account =
2630-
SolanaAccount::new(account_minimum_balance(), size_of::<Account>(), &program_id);
2625+
let mut account2_account = SolanaAccount::new(
2626+
account_minimum_balance() + 42,
2627+
size_of::<Account>(),
2628+
&program_id,
2629+
);
26312630
let account3_key = pubkey_rand();
26322631
let mut account3_account =
26332632
SolanaAccount::new(account_minimum_balance(), size_of::<Account>(), &program_id);
@@ -2697,8 +2696,8 @@ mod tests {
26972696
)
26982697
.unwrap();
26992698
let account: &mut Account = state::unpack(&mut account2_account.data).unwrap();
2700-
assert!(account.is_native);
2701-
assert_eq!(account.amount, account_minimum_balance());
2699+
assert!(account.is_native());
2700+
assert_eq!(account.amount, 42);
27022701

27032702
// close non-native account with balance
27042703
assert_eq!(
@@ -2820,10 +2819,13 @@ mod tests {
28202819
)
28212820
.unwrap();
28222821
let account: &mut Account = state::unpack_unchecked(&mut account2_account.data).unwrap();
2823-
assert!(account.is_native);
2822+
assert!(account.is_native());
28242823
assert_eq!(account_account.lamports, 0);
28252824
assert_eq!(account.amount, 0);
2826-
assert_eq!(account3_account.lamports, 3 * account_minimum_balance() + 2);
2825+
assert_eq!(
2826+
account3_account.lamports,
2827+
3 * account_minimum_balance() + 2 + 42
2828+
);
28272829
}
28282830

28292831
#[test]
@@ -2864,8 +2866,8 @@ mod tests {
28642866
)
28652867
.unwrap();
28662868
let account: &mut Account = state::unpack(&mut account_account.data).unwrap();
2867-
assert!(account.is_native);
2868-
assert_eq!(account.amount, account_minimum_balance() + 40);
2869+
assert!(account.is_native());
2870+
assert_eq!(account.amount, 40);
28692871

28702872
// initialize native account
28712873
do_process_instruction(
@@ -2885,8 +2887,8 @@ mod tests {
28852887
)
28862888
.unwrap();
28872889
let account: &mut Account = state::unpack(&mut account2_account.data).unwrap();
2888-
assert!(account.is_native);
2889-
assert_eq!(account.amount, account_minimum_balance());
2890+
assert!(account.is_native());
2891+
assert_eq!(account.amount, 0);
28902892

28912893
// mint_to unsupported
28922894
assert_eq!(
@@ -2914,7 +2916,28 @@ mod tests {
29142916
)
29152917
);
29162918

2917-
// initialize native account
2919+
// ensure can't transfer below rent-exempt reserve
2920+
assert_eq!(
2921+
Err(TokenError::InsufficientFunds.into()),
2922+
do_process_instruction(
2923+
transfer(
2924+
&program_id,
2925+
&account_key,
2926+
&account2_key,
2927+
&owner_key,
2928+
&[],
2929+
50,
2930+
)
2931+
.unwrap(),
2932+
vec![
2933+
&mut account_account,
2934+
&mut account2_account,
2935+
&mut owner_account,
2936+
],
2937+
)
2938+
);
2939+
2940+
// transfer between native accounts
29182941
do_process_instruction(
29192942
transfer(
29202943
&program_id,
@@ -2934,13 +2957,13 @@ mod tests {
29342957
.unwrap();
29352958

29362959
let account: &mut Account = state::unpack(&mut account_account.data).unwrap();
2937-
assert!(account.is_native);
2960+
assert!(account.is_native());
29382961
assert_eq!(account_account.lamports, account_minimum_balance());
2939-
assert_eq!(account.amount, account_minimum_balance());
2962+
assert_eq!(account.amount, 0);
29402963
let account: &mut Account = state::unpack(&mut account2_account.data).unwrap();
2941-
assert!(account.is_native);
2964+
assert!(account.is_native());
29422965
assert_eq!(account2_account.lamports, account_minimum_balance() + 40);
2943-
assert_eq!(account.amount, account_minimum_balance() + 40);
2966+
assert_eq!(account.amount, 40);
29442967

29452968
// close native account
29462969
do_process_instruction(
@@ -2953,7 +2976,7 @@ mod tests {
29532976
)
29542977
.unwrap();
29552978
let account: &mut Account = state::unpack_unchecked(&mut account_account.data).unwrap();
2956-
assert!(account.is_native);
2979+
assert!(account.is_native());
29572980
assert_eq!(account_account.lamports, 0);
29582981
assert_eq!(account.amount, 0);
29592982
assert_eq!(account3_account.lamports, 2 * account_minimum_balance());

token/program/src/state.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,21 +40,24 @@ pub struct Account {
4040
pub delegate: COption<Pubkey>,
4141
/// The account's state
4242
pub state: AccountState,
43-
/// Is this a native token
44-
pub is_native: bool,
43+
/// If is_some, this is a native token, and the value logs the rent-exempt reserve. An Account
44+
/// is required to be rent-exempt, so the value is used by the Processor to ensure that wrapped
45+
/// SOL accounts do not drop below this threshold.
46+
pub is_native: COption<u64>,
4547
/// The amount delegated
4648
pub delegated_amount: u64,
4749
/// Optional authority to close the account.
4850
pub close_authority: COption<Pubkey>,
49-
/// An Account is required to be rent-exempt. This value logs the reserve required to be
50-
/// rent-exempt so that wrapped SOL accounts do not drop below this threshold.
51-
pub rent_exempt_reserve: u64,
5251
}
5352
impl Account {
5453
/// Checks if account is frozen
5554
pub fn is_frozen(&self) -> bool {
5655
self.state == AccountState::Frozen
5756
}
57+
/// Checks if account is native
58+
pub fn is_native(&self) -> bool {
59+
self.is_native.is_some()
60+
}
5861
}
5962
impl IsInitialized for Account {
6063
fn is_initialized(&self) -> bool {

0 commit comments

Comments
 (0)