Skip to content

Commit

Permalink
lending: handle rounding consistently (solana-labs#1883)
Browse files Browse the repository at this point in the history
* handle rounding consistently

* remove unused method

* slightly increase test compute limits

* reuse existing decimal functions
  • Loading branch information
jordaaash authored Dec 3, 2021
1 parent c24bc96 commit c2b2877
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 24 deletions.
15 changes: 0 additions & 15 deletions token-lending/program/src/math/rate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,6 @@ impl Rate {
U128::from(WAD)
}

// OPTIMIZE: use const slice when fixed in BPF toolchain
fn half_wad() -> U128 {
U128::from(HALF_WAD)
}

/// Create scaled decimal from percent value
pub fn from_percent(percent: u8) -> Self {
Self(U128::from(percent as u64 * PERCENT_SCALER))
Expand All @@ -72,16 +67,6 @@ impl Rate {
Self(U128::from(scaled_val))
}

/// Round scaled decimal to u64
pub fn try_round_u64(&self) -> Result<u64, ProgramError> {
let rounded_val = Self::half_wad()
.checked_add(self.0)
.ok_or(LendingError::MathOverflow)?
.checked_div(Self::wad())
.ok_or(LendingError::MathOverflow)?;
Ok(u64::try_from(rounded_val).map_err(|_| LendingError::MathOverflow)?)
}

/// Calculates base^exp
pub fn try_pow(&self, mut exp: u64) -> Result<Rate, ProgramError> {
let mut base = *self;
Expand Down
22 changes: 13 additions & 9 deletions token-lending/program/src/state/reserve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -553,9 +553,8 @@ pub struct CollateralExchangeRate(Rate);
impl CollateralExchangeRate {
/// Convert reserve collateral to liquidity
pub fn collateral_to_liquidity(&self, collateral_amount: u64) -> Result<u64, ProgramError> {
Decimal::from(collateral_amount)
.try_div(self.0)?
.try_round_u64()
self.decimal_collateral_to_liquidity(collateral_amount.into())?
.try_floor_u64()
}

/// Convert reserve collateral to liquidity
Expand All @@ -568,7 +567,8 @@ impl CollateralExchangeRate {

/// Convert reserve liquidity to collateral
pub fn liquidity_to_collateral(&self, liquidity_amount: u64) -> Result<u64, ProgramError> {
self.0.try_mul(liquidity_amount)?.try_round_u64()
self.decimal_liquidity_to_collateral(liquidity_amount.into())?
.try_floor_u64()
}

/// Convert reserve liquidity to collateral
Expand Down Expand Up @@ -662,9 +662,9 @@ impl ReserveFees {
if borrow_fee_rate > Rate::zero() && amount > Decimal::zero() {
let need_to_assess_host_fee = host_fee_rate > Rate::zero();
let minimum_fee = if need_to_assess_host_fee {
2 // 1 token to owner, 1 to host
2u64 // 1 token to owner, 1 to host
} else {
1 // 1 token to owner, nothing else
1u64 // 1 token to owner, nothing else
};

let borrow_fee_amount = match fee_calculation {
Expand All @@ -678,14 +678,18 @@ impl ReserveFees {
}
};

let borrow_fee = borrow_fee_amount.try_round_u64()?.max(minimum_fee);
if Decimal::from(borrow_fee) >= amount {
let borrow_fee_decimal = borrow_fee_amount.max(minimum_fee.into());
if borrow_fee_decimal >= amount {
msg!("Borrow amount is too small to receive liquidity after fees");
return Err(LendingError::BorrowTooSmall.into());
}

let borrow_fee = borrow_fee_decimal.try_round_u64()?;
let host_fee = if need_to_assess_host_fee {
host_fee_rate.try_mul(borrow_fee)?.try_round_u64()?.max(1)
borrow_fee_decimal
.try_mul(host_fee_rate)?
.try_round_u64()?
.max(1u64)
} else {
0
};
Expand Down

0 comments on commit c2b2877

Please sign in to comment.