use cfg_traits::{
interest::{InterestAccrual, InterestRate, RateCollection},
TimeAsSecs,
};
use cfg_types::adjustments::Adjustment;
use frame_support::RuntimeDebugNoBound;
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
use sp_runtime::{traits::Zero, DispatchError, DispatchResult};
use crate::pallet::Config;
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebugNoBound, TypeInfo, MaxEncodedLen)]
#[scale_info(skip_type_params(T))]
pub struct ActiveInterestRate<T: Config> {
interest_rate: InterestRate<T::Rate>,
normalized_acc: T::Balance,
penalty: T::Rate,
}
impl<T: Config> ActiveInterestRate<T> {
pub fn activate(interest_rate: InterestRate<T::Rate>) -> Result<Self, DispatchError> {
T::InterestAccrual::reference_rate(&interest_rate)?;
Ok(Self {
interest_rate,
normalized_acc: T::Balance::zero(),
penalty: T::Rate::zero(),
})
}
pub fn deactivate(self) -> Result<InterestRate<T::Rate>, DispatchError> {
T::InterestAccrual::unreference_rate(&self.interest_rate)?;
Ok(self.interest_rate)
}
pub fn has_debt(&self) -> bool {
!self.normalized_acc.is_zero()
}
pub fn rate(&self) -> &InterestRate<T::Rate> {
&self.interest_rate
}
pub fn penalty(&self) -> T::Rate {
self.penalty
}
pub fn current_debt(&self) -> Result<T::Balance, DispatchError> {
let now = T::Time::now();
T::InterestAccrual::calculate_debt(&self.interest_rate, self.normalized_acc, now)
}
pub fn current_debt_cached<Rates>(&self, cache: &Rates) -> Result<T::Balance, DispatchError>
where
Rates: RateCollection<T::Rate, T::Balance, T::Balance>,
{
cache.current_debt(&self.interest_rate, self.normalized_acc)
}
pub fn adjust_debt(&mut self, adjustment: Adjustment<T::Balance>) -> DispatchResult {
self.normalized_acc = T::InterestAccrual::adjust_normalized_debt(
&self.interest_rate,
self.normalized_acc,
adjustment,
)?;
Ok(())
}
pub fn set_penalty(&mut self, new_penalty: T::Rate) -> DispatchResult {
let base_rate = self.interest_rate.clone().ensure_sub(self.penalty)?;
self.update_rate(base_rate, new_penalty)
}
pub fn set_base_rate(&mut self, base_rate: InterestRate<T::Rate>) -> DispatchResult {
self.update_rate(base_rate, self.penalty)
}
fn update_rate(
&mut self,
new_base_rate: InterestRate<T::Rate>,
new_penalty: T::Rate,
) -> DispatchResult {
let new_rate = new_base_rate.ensure_add(new_penalty)?;
let old_rate = self.interest_rate.clone();
T::InterestAccrual::reference_rate(&new_rate)?;
self.normalized_acc =
T::InterestAccrual::renormalize_debt(&old_rate, &new_rate, self.normalized_acc)?;
self.interest_rate = new_rate;
self.penalty = new_penalty;
T::InterestAccrual::unreference_rate(&old_rate)
}
}