use cfg_primitives::SECONDS_PER_YEAR;
use frame_support::{
dispatch::DispatchResult,
pallet_prelude::{RuntimeDebug, TypeInfo},
Parameter,
};
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
use sp_arithmetic::{
traits::{EnsureAdd, EnsureDiv, EnsureSub},
ArithmeticError, FixedPointNumber,
};
use sp_runtime::{
traits::{Get, Member, One, Zero},
DispatchError,
};
use crate::Seconds;
#[derive(Encode, Decode, Clone, PartialEq, Eq, TypeInfo, RuntimeDebug, MaxEncodedLen)]
pub enum CompoundingSchedule {
Secondly,
}
#[derive(Encode, Decode, Clone, PartialEq, Eq, TypeInfo, RuntimeDebug, MaxEncodedLen)]
pub enum InterestRate<Rate> {
Fixed {
rate_per_year: Rate,
compounding: CompoundingSchedule,
},
}
impl<Rate: FixedPointNumber> InterestRate<Rate> {
pub fn per_year(&self) -> Rate {
match self {
InterestRate::Fixed { rate_per_year, .. } => *rate_per_year,
}
}
pub fn per_sec(&self) -> Result<Rate, ArithmeticError> {
self.per_year()
.ensure_div(Rate::saturating_from_integer(SECONDS_PER_YEAR))?
.ensure_add(One::one())
}
}
impl<Rate> InterestRate<Rate> {
pub fn try_map_rate<F, E>(self, f: F) -> Result<Self, E>
where
F: FnOnce(Rate) -> Result<Rate, E>,
{
Ok(match self {
Self::Fixed {
rate_per_year,
compounding,
} => Self::Fixed {
rate_per_year: f(rate_per_year)?,
compounding,
},
})
}
}
impl<Rate: EnsureAdd + EnsureSub> InterestRate<Rate> {
pub fn ensure_add(self, rate: Rate) -> Result<InterestRate<Rate>, ArithmeticError> {
self.try_map_rate(|r| r.ensure_add(rate))
}
pub fn ensure_sub(self, rate: Rate) -> Result<InterestRate<Rate>, ArithmeticError> {
self.try_map_rate(|r| r.ensure_sub(rate))
}
}
pub trait InterestAccrual<Rate, Balance, Adjustment> {
type MaxRateCount: Get<u32>;
type NormalizedDebt: Member + Parameter + MaxEncodedLen + TypeInfo + Copy + Zero;
type Rates: RateCollection<Rate, Balance, Self::NormalizedDebt>;
fn calculate_debt(
interest_rate: &InterestRate<Rate>,
normalized_debt: Self::NormalizedDebt,
when: Seconds,
) -> Result<Balance, DispatchError>;
fn adjust_normalized_debt(
interest_rate: &InterestRate<Rate>,
normalized_debt: Self::NormalizedDebt,
adjustment: Adjustment,
) -> Result<Self::NormalizedDebt, DispatchError>;
fn renormalize_debt(
old_interest_rate: &InterestRate<Rate>,
new_interest_rate: &InterestRate<Rate>,
normalized_debt: Self::NormalizedDebt,
) -> Result<Self::NormalizedDebt, DispatchError>;
fn reference_rate(interest_rate: &InterestRate<Rate>) -> DispatchResult;
fn unreference_rate(interest_rate: &InterestRate<Rate>) -> DispatchResult;
fn validate_rate(interest_rate: &InterestRate<Rate>) -> DispatchResult;
fn rates() -> Self::Rates;
}
pub trait RateCollection<Rate, Balance, NormalizedDebt> {
fn current_debt(
&self,
interest_rate: &InterestRate<Rate>,
normalized_debt: NormalizedDebt,
) -> Result<Balance, DispatchError>;
}