use pyra_types::{KaminoReserve, KAMINO_FRACTION_SCALE};
use crate::error::{MathError, MathResult};
const SPOT_WEIGHT_PRECISION: u128 = 10_000;
const PRICE_PRECISION: u128 = 1_000_000;
pub fn get_kamino_asset_weight(reserve: &KaminoReserve) -> u128 {
(reserve.config.loan_to_value_pct as u128)
.saturating_mul(SPOT_WEIGHT_PRECISION)
.saturating_div(100)
}
pub fn get_kamino_liability_weight(reserve: &KaminoReserve) -> MathResult<u128> {
let threshold = reserve.config.liquidation_threshold_pct as u128;
if threshold == 0 {
return Err(MathError::Overflow);
}
SPOT_WEIGHT_PRECISION
.checked_mul(100)
.ok_or(MathError::Overflow)?
.checked_div(threshold)
.ok_or(MathError::Overflow)
}
pub fn get_kamino_price(reserve: &KaminoReserve) -> MathResult<i128> {
let price = reserve
.liquidity
.market_price_sf
.checked_mul(PRICE_PRECISION)
.ok_or(MathError::Overflow)?
.checked_div(KAMINO_FRACTION_SCALE)
.ok_or(MathError::Overflow)?;
i128::try_from(price).map_err(|_| MathError::Overflow)
}
#[cfg(test)]
#[allow(
clippy::allow_attributes,
clippy::allow_attributes_without_reason,
clippy::unwrap_used,
clippy::expect_used,
clippy::panic,
clippy::arithmetic_side_effects,
reason = "test code"
)]
mod tests {
use super::*;
use pyra_types::{KaminoReserveConfig, KaminoReserveLiquidity};
fn make_reserve_with_config(ltv: u8, liq_threshold: u8, price_sf: u128) -> KaminoReserve {
KaminoReserve {
liquidity: KaminoReserveLiquidity {
market_price_sf: price_sf,
mint_decimals: 6,
..Default::default()
},
config: KaminoReserveConfig {
loan_to_value_pct: ltv,
liquidation_threshold_pct: liq_threshold,
borrow_factor_pct: 100,
..Default::default()
},
..Default::default()
}
}
#[test]
fn asset_weight_80_ltv() {
let reserve = make_reserve_with_config(80, 85, 0);
assert_eq!(get_kamino_asset_weight(&reserve), 8_000);
}
#[test]
fn asset_weight_100_ltv() {
let reserve = make_reserve_with_config(100, 100, 0);
assert_eq!(get_kamino_asset_weight(&reserve), 10_000);
}
#[test]
fn asset_weight_0_ltv() {
let reserve = make_reserve_with_config(0, 85, 0);
assert_eq!(get_kamino_asset_weight(&reserve), 0);
}
#[test]
fn asset_weight_50_ltv() {
let reserve = make_reserve_with_config(50, 85, 0);
assert_eq!(get_kamino_asset_weight(&reserve), 5_000);
}
#[test]
fn liability_weight_85_threshold() {
let reserve = make_reserve_with_config(80, 85, 0);
assert_eq!(get_kamino_liability_weight(&reserve).unwrap(), 11_764);
}
#[test]
fn liability_weight_100_threshold() {
let reserve = make_reserve_with_config(80, 100, 0);
assert_eq!(get_kamino_liability_weight(&reserve).unwrap(), 10_000);
}
#[test]
fn liability_weight_50_threshold() {
let reserve = make_reserve_with_config(80, 50, 0);
assert_eq!(get_kamino_liability_weight(&reserve).unwrap(), 20_000);
}
#[test]
fn liability_weight_zero_threshold_errors() {
let reserve = make_reserve_with_config(80, 0, 0);
assert!(get_kamino_liability_weight(&reserve).is_err());
}
#[test]
fn price_one_dollar() {
let price_sf = 1u128 << 60; let reserve = make_reserve_with_config(80, 85, price_sf);
assert_eq!(get_kamino_price(&reserve).unwrap(), 1_000_000);
}
#[test]
fn price_hundred_dollars() {
let price_sf = 100u128 << 60;
let reserve = make_reserve_with_config(80, 85, price_sf);
assert_eq!(get_kamino_price(&reserve).unwrap(), 100_000_000);
}
#[test]
fn price_zero() {
let reserve = make_reserve_with_config(80, 85, 0);
assert_eq!(get_kamino_price(&reserve).unwrap(), 0);
}
#[test]
fn price_fractional() {
let price_sf = 1u128 << 59; let reserve = make_reserve_with_config(80, 85, price_sf);
assert_eq!(get_kamino_price(&reserve).unwrap(), 500_000);
}
}