use pendzl::{
math::{errors::MathError, operations::mul_div},
traits::Balance,
};
use crate::math::{
e18_mul_e18_div_e18_to_e18_rdown,
interest_rate_math::utilization_rate_to_interest_rate_e18, E6_U128, E6_U32,
};
use super::InterestRateModel;
#[derive(Debug, scale::Encode, scale::Decode)]
#[cfg_attr(
feature = "std",
derive(scale_info::TypeInfo, ink::storage::traits::StorageLayout)
)]
pub struct ReserveData {
pub activated: bool,
pub frozen: bool,
pub total_deposit: Balance,
pub current_deposit_rate_e18: u64,
pub total_debt: Balance,
pub current_debt_rate_e18: u64,
}
#[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)]
#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
pub enum ReserveDataError {
AlreadySet,
Inactive,
Frozen,
}
impl Default for ReserveData {
fn default() -> Self {
ReserveData {
activated: true,
frozen: false,
total_deposit: 0,
current_deposit_rate_e18: 0,
total_debt: 0,
current_debt_rate_e18: 0,
}
}
}
impl ReserveData {
pub fn set_is_active(
&mut self,
active: bool,
) -> Result<(), ReserveDataError> {
if self.activated == active {
return Err(ReserveDataError::AlreadySet);
}
self.activated = active;
Ok(())
}
pub fn ensure_activated(&self) -> Result<(), ReserveDataError> {
if !self.activated {
return Err(ReserveDataError::Inactive);
}
Ok(())
}
pub fn set_is_frozen(
&mut self,
freeze: bool,
) -> Result<(), ReserveDataError> {
if self.frozen == freeze {
return Err(ReserveDataError::AlreadySet);
}
self.activated = freeze;
Ok(())
}
pub fn ensure_not_frozen(&self) -> Result<(), ReserveDataError> {
if self.frozen {
return Err(ReserveDataError::Frozen);
}
Ok(())
}
pub fn increase_total_deposit(
&mut self,
amount: &Balance,
) -> Result<(), MathError> {
self.total_deposit = self
.total_deposit
.checked_add(*amount)
.ok_or(MathError::Overflow)?;
Ok(())
}
pub fn decrease_total_deposit(
&mut self,
amount: &Balance,
) -> Result<(), MathError> {
self.total_deposit = self
.total_deposit
.checked_sub(*amount)
.ok_or(MathError::Underflow)?;
Ok(())
}
pub fn increase_total_debt(
&mut self,
amount: &Balance,
) -> Result<(), MathError> {
self.total_debt = self
.total_debt
.checked_add(*amount)
.ok_or(MathError::Overflow)?;
Ok(())
}
pub fn decrease_total_debt(
&mut self,
amount: &Balance,
) -> Result<(), MathError> {
self.total_debt = self
.total_debt
.checked_sub(*amount)
.ok_or(MathError::Underflow)?;
Ok(())
}
pub fn add_interests(
&mut self,
interests: (Balance, Balance),
) -> Result<(Balance, Balance), MathError> {
self.increase_total_deposit(&interests.0)?;
self.increase_total_debt(&interests.1)?;
Ok(interests)
}
pub fn current_utilization_rate_e6(&self) -> Result<u32, MathError> {
if self.total_deposit == 0 {
return Ok(E6_U32);
}
let total_debt = self.total_debt;
match u32::try_from(mul_div(
total_debt,
E6_U128,
self.total_deposit,
pendzl::math::operations::Rounding::Down,
)?) {
Ok(v) => Ok(v),
_ => Err(MathError::Overflow),
}
}
pub fn recalculate_current_rates(
&mut self,
interest_rate_model: &InterestRateModel,
) -> Result<(), MathError> {
ink::env::debug_println!("recalculate_current_rates");
if self.total_debt == 0 {
self.current_debt_rate_e18 = 0;
self.current_deposit_rate_e18 = 0;
return Ok(());
}
let utilization_rate_e6 = self.current_utilization_rate_e6()?;
ink::env::debug_println!(
"utilization_rate_e6: {}",
utilization_rate_e6
);
self.current_debt_rate_e18 = utilization_rate_to_interest_rate_e18(
utilization_rate_e6,
interest_rate_model,
)?;
ink::env::debug_println!(
"current_debt_rate_e18: {}",
self.current_debt_rate_e18
);
if self.total_deposit != 0 {
self.current_deposit_rate_e18 = e18_mul_e18_div_e18_to_e18_rdown(
self.total_debt,
self.current_debt_rate_e18,
self.total_deposit,
)?;
} else {
self.current_deposit_rate_e18 = 0;
}
Ok(())
}
}