lending: handle rounding consistently (#1883)
* handle rounding consistently * remove unused method * slightly increase test compute limits * reuse existing decimal functions
This commit is contained in:
parent
c24bc966f1
commit
c2b287788b
|
@ -51,11 +51,6 @@ impl Rate {
|
||||||
U128::from(WAD)
|
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
|
/// Create scaled decimal from percent value
|
||||||
pub fn from_percent(percent: u8) -> Self {
|
pub fn from_percent(percent: u8) -> Self {
|
||||||
Self(U128::from(percent as u64 * PERCENT_SCALER))
|
Self(U128::from(percent as u64 * PERCENT_SCALER))
|
||||||
|
@ -72,16 +67,6 @@ impl Rate {
|
||||||
Self(U128::from(scaled_val))
|
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
|
/// Calculates base^exp
|
||||||
pub fn try_pow(&self, mut exp: u64) -> Result<Rate, ProgramError> {
|
pub fn try_pow(&self, mut exp: u64) -> Result<Rate, ProgramError> {
|
||||||
let mut base = *self;
|
let mut base = *self;
|
||||||
|
|
|
@ -553,9 +553,8 @@ pub struct CollateralExchangeRate(Rate);
|
||||||
impl CollateralExchangeRate {
|
impl CollateralExchangeRate {
|
||||||
/// Convert reserve collateral to liquidity
|
/// Convert reserve collateral to liquidity
|
||||||
pub fn collateral_to_liquidity(&self, collateral_amount: u64) -> Result<u64, ProgramError> {
|
pub fn collateral_to_liquidity(&self, collateral_amount: u64) -> Result<u64, ProgramError> {
|
||||||
Decimal::from(collateral_amount)
|
self.decimal_collateral_to_liquidity(collateral_amount.into())?
|
||||||
.try_div(self.0)?
|
.try_floor_u64()
|
||||||
.try_round_u64()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert reserve collateral to liquidity
|
/// Convert reserve collateral to liquidity
|
||||||
|
@ -568,7 +567,8 @@ impl CollateralExchangeRate {
|
||||||
|
|
||||||
/// Convert reserve liquidity to collateral
|
/// Convert reserve liquidity to collateral
|
||||||
pub fn liquidity_to_collateral(&self, liquidity_amount: u64) -> Result<u64, ProgramError> {
|
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
|
/// Convert reserve liquidity to collateral
|
||||||
|
@ -662,9 +662,9 @@ impl ReserveFees {
|
||||||
if borrow_fee_rate > Rate::zero() && amount > Decimal::zero() {
|
if borrow_fee_rate > Rate::zero() && amount > Decimal::zero() {
|
||||||
let need_to_assess_host_fee = host_fee_rate > Rate::zero();
|
let need_to_assess_host_fee = host_fee_rate > Rate::zero();
|
||||||
let minimum_fee = if need_to_assess_host_fee {
|
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 {
|
} else {
|
||||||
1 // 1 token to owner, nothing else
|
1u64 // 1 token to owner, nothing else
|
||||||
};
|
};
|
||||||
|
|
||||||
let borrow_fee_amount = match fee_calculation {
|
let borrow_fee_amount = match fee_calculation {
|
||||||
|
@ -678,14 +678,18 @@ impl ReserveFees {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let borrow_fee = borrow_fee_amount.try_round_u64()?.max(minimum_fee);
|
let borrow_fee_decimal = borrow_fee_amount.max(minimum_fee.into());
|
||||||
if Decimal::from(borrow_fee) >= amount {
|
if borrow_fee_decimal >= amount {
|
||||||
msg!("Borrow amount is too small to receive liquidity after fees");
|
msg!("Borrow amount is too small to receive liquidity after fees");
|
||||||
return Err(LendingError::BorrowTooSmall.into());
|
return Err(LendingError::BorrowTooSmall.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let borrow_fee = borrow_fee_decimal.try_round_u64()?;
|
||||||
let host_fee = if need_to_assess_host_fee {
|
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 {
|
} else {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue