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

Commit a17fffe

Browse files
authored
stake-pool: Ceiling all fee calculations (HAL-01) (#6153)
stake-pool: Ceiling all fee calculations
1 parent 0d6832e commit a17fffe

File tree

4 files changed

+19
-24
lines changed

4 files changed

+19
-24
lines changed

stake-pool/program/src/state.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -942,9 +942,13 @@ impl Fee {
942942
if self.denominator == 0 {
943943
return Some(0);
944944
}
945-
(amt as u128)
946-
.checked_mul(self.numerator as u128)?
947-
.checked_div(self.denominator as u128)
945+
let numerator = (amt as u128).checked_mul(self.numerator as u128)?;
946+
// ceiling the calculation by adding (denominator - 1) to the numerator
947+
let denominator = self.denominator as u128;
948+
numerator
949+
.checked_add(denominator)?
950+
.checked_sub(1)?
951+
.checked_div(denominator)
948952
}
949953

950954
/// Withdrawal fees have some additional restrictions,

stake-pool/program/tests/helpers/mod.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -897,15 +897,17 @@ impl StakePoolAccounts {
897897
}
898898

899899
pub fn calculate_fee(&self, amount: u64) -> u64 {
900-
amount * self.epoch_fee.numerator / self.epoch_fee.denominator
900+
(amount * self.epoch_fee.numerator + self.epoch_fee.denominator - 1)
901+
/ self.epoch_fee.denominator
901902
}
902903

903904
pub fn calculate_withdrawal_fee(&self, pool_tokens: u64) -> u64 {
904-
pool_tokens * self.withdrawal_fee.numerator / self.withdrawal_fee.denominator
905+
(pool_tokens * self.withdrawal_fee.numerator + self.withdrawal_fee.denominator - 1)
906+
/ self.withdrawal_fee.denominator
905907
}
906908

907909
pub fn calculate_inverse_withdrawal_fee(&self, pool_tokens: u64) -> u64 {
908-
pool_tokens * self.withdrawal_fee.denominator
910+
(pool_tokens * self.withdrawal_fee.denominator + self.withdrawal_fee.denominator - 1)
909911
/ (self.withdrawal_fee.denominator - self.withdrawal_fee.numerator)
910912
}
911913

@@ -914,7 +916,8 @@ impl StakePoolAccounts {
914916
}
915917

916918
pub fn calculate_sol_deposit_fee(&self, pool_tokens: u64) -> u64 {
917-
pool_tokens * self.sol_deposit_fee.numerator / self.sol_deposit_fee.denominator
919+
(pool_tokens * self.sol_deposit_fee.numerator + self.sol_deposit_fee.denominator - 1)
920+
/ self.sol_deposit_fee.denominator
918921
}
919922

920923
pub fn calculate_sol_referral_fee(&self, deposit_fee_collected: u64) -> u64 {

stake-pool/program/tests/withdraw_sol.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -214,15 +214,15 @@ async fn fail_overdraw_reserve() {
214214
.await;
215215
assert!(error.is_none(), "{:?}", error);
216216

217-
// try to withdraw one lamport, will overdraw
217+
// try to withdraw one lamport after fees, will overdraw
218218
let error = stake_pool_accounts
219219
.withdraw_sol(
220220
&mut context.banks_client,
221221
&context.payer,
222222
&context.last_blockhash,
223223
&user,
224224
&pool_token_account,
225-
1,
225+
2,
226226
None,
227227
)
228228
.await

stake-pool/program/tests/withdraw_with_fee.rs

+3-15
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ mod helpers;
66
use {
77
bincode::deserialize,
88
helpers::*,
9-
solana_program::{borsh0_10::try_from_slice_unchecked, pubkey::Pubkey, stake},
9+
solana_program::{pubkey::Pubkey, stake},
1010
solana_program_test::*,
1111
solana_sdk::signature::{Keypair, Signer},
12-
spl_stake_pool::{minimum_stake_lamports, state},
12+
spl_stake_pool::minimum_stake_lamports,
1313
};
1414

1515
#[tokio::test]
@@ -183,20 +183,8 @@ async fn success_empty_out_stake_with_fee() {
183183
.await;
184184
let lamports_to_withdraw =
185185
validator_stake_account.lamports - minimum_stake_lamports(&meta, stake_minimum_delegation);
186-
let stake_pool_account = get_account(
187-
&mut context.banks_client,
188-
&stake_pool_accounts.stake_pool.pubkey(),
189-
)
190-
.await;
191-
let stake_pool =
192-
try_from_slice_unchecked::<state::StakePool>(stake_pool_account.data.as_slice()).unwrap();
193-
let fee = stake_pool.stake_withdrawal_fee;
194-
let inverse_fee = state::Fee {
195-
numerator: fee.denominator - fee.numerator,
196-
denominator: fee.denominator,
197-
};
198186
let pool_tokens_to_withdraw =
199-
lamports_to_withdraw * inverse_fee.denominator / inverse_fee.numerator;
187+
stake_pool_accounts.calculate_inverse_withdrawal_fee(lamports_to_withdraw);
200188

201189
let last_blockhash = context
202190
.banks_client

0 commit comments

Comments
 (0)