use hopper_runtime::error::ProgramError;
#[inline(always)]
pub fn collateralization_ratio_bps(
collateral_value: u64,
debt_value: u64,
) -> Result<u64, ProgramError> {
if debt_value == 0 {
return Ok(u64::MAX);
}
let ratio = (collateral_value as u128)
.checked_mul(10_000)
.ok_or(ProgramError::ArithmeticOverflow)?
/ (debt_value as u128);
Ok(ratio as u64)
}
#[inline(always)]
pub fn check_healthy(
collateral_value: u64,
debt_value: u64,
liquidation_threshold_bps: u64,
) -> Result<(), ProgramError> {
let ratio = collateralization_ratio_bps(collateral_value, debt_value)?;
if ratio < liquidation_threshold_bps {
return Err(ProgramError::InvalidArgument);
}
Ok(())
}
#[inline(always)]
pub fn check_liquidatable(
collateral_value: u64,
debt_value: u64,
liquidation_threshold_bps: u64,
) -> Result<(), ProgramError> {
let ratio = collateralization_ratio_bps(collateral_value, debt_value)?;
if ratio >= liquidation_threshold_bps {
return Err(ProgramError::InvalidArgument);
}
Ok(())
}
#[inline(always)]
pub fn max_liquidation_amount(debt_value: u64, close_factor_bps: u64) -> Result<u64, ProgramError> {
let max = (debt_value as u128)
.checked_mul(close_factor_bps as u128)
.ok_or(ProgramError::ArithmeticOverflow)?
/ 10_000;
Ok(max.min(debt_value as u128) as u64)
}
#[inline(always)]
pub fn liquidation_seize_amount(repay_amount: u64, bonus_bps: u64) -> Result<u64, ProgramError> {
let seized = (repay_amount as u128)
.checked_mul((10_000u64 + bonus_bps) as u128)
.ok_or(ProgramError::ArithmeticOverflow)?
/ 10_000;
if seized > u64::MAX as u128 {
return Err(ProgramError::ArithmeticOverflow);
}
Ok(seized as u64)
}
#[inline(always)]
pub fn simple_interest(
principal: u64,
rate_bps_per_period: u64,
periods: u64,
) -> Result<u64, ProgramError> {
let interest = (principal as u128)
.checked_mul(rate_bps_per_period as u128)
.ok_or(ProgramError::ArithmeticOverflow)?
.checked_mul(periods as u128)
.ok_or(ProgramError::ArithmeticOverflow)?
/ 10_000;
if interest > u64::MAX as u128 {
return Err(ProgramError::ArithmeticOverflow);
}
Ok(interest as u64)
}
#[inline(always)]
pub fn utilization_rate_bps(borrows: u64, cash: u64) -> Result<u64, ProgramError> {
let total = (borrows as u128) + (cash as u128);
if total == 0 {
return Ok(0);
}
let util = (borrows as u128) * 10_000 / total;
Ok(util as u64)
}