use crate::MathError;
use sp_arithmetic::{
traits::{CheckedAdd, CheckedDiv, CheckedMul},
FixedPointNumber, FixedU128,
};
use core::convert::TryInto;
type Balance = u128;
pub fn calculate_loyalty_multiplier<Period: num_traits::CheckedSub + TryInto<u32> + TryInto<u128>>(
periods: Period,
initial_reward_percentage: FixedU128,
scale_coef: u32,
) -> Result<FixedU128, MathError> {
let denom = initial_reward_percentage
.checked_add(&1.into())
.ok_or(MathError::Overflow)?
.checked_mul(&FixedU128::from(scale_coef as u128))
.ok_or(MathError::Overflow)?;
let periods = FixedU128::from(TryInto::<u128>::try_into(periods).map_err(|_e| MathError::Overflow)?);
let tau = periods.checked_div(&denom).ok_or(MathError::Overflow)?;
let tau_mul_initial_reward_percentage = tau.checked_mul(&initial_reward_percentage).ok_or(MathError::Overflow)?;
let tau_add_tau_mul_initial_reward_percentage = tau
.checked_add(&tau_mul_initial_reward_percentage)
.ok_or(MathError::Overflow)?;
let num = tau_add_tau_mul_initial_reward_percentage
.checked_add(&initial_reward_percentage)
.ok_or(MathError::Overflow)?;
let denom = tau_add_tau_mul_initial_reward_percentage
.checked_add(&1.into())
.ok_or(MathError::Overflow)?;
num.checked_div(&denom).ok_or(MathError::Overflow)
}
pub fn calculate_global_pool_reward_per_period(
yield_per_period: FixedU128,
total_pool_shares_z: Balance,
max_reward_per_period: Balance,
) -> Result<Balance, MathError> {
Ok(yield_per_period
.checked_mul_int(total_pool_shares_z)
.ok_or(MathError::Overflow)?
.min(max_reward_per_period))
}
pub fn calculate_accumulated_rps(
accumulated_rps_now: Balance,
total_shares: Balance,
reward: Balance,
) -> Result<Balance, MathError> {
reward
.checked_div(total_shares)
.ok_or(MathError::Overflow)?
.checked_add(accumulated_rps_now)
.ok_or(MathError::Overflow)
}
pub fn calculate_user_reward(
accumulated_rpvs: Balance,
valued_shares: Balance, accumulated_claimed_rewards: Balance,
accumulated_rpvs_now: Balance,
loyalty_multiplier: FixedU128,
) -> Result<(Balance, Balance), MathError> {
let max_rewards = calculate_reward(accumulated_rpvs, accumulated_rpvs_now, valued_shares)?;
if max_rewards == 0 {
return Ok((0, 0));
}
let claimable_rewards = loyalty_multiplier
.checked_mul_int(max_rewards)
.ok_or(MathError::Overflow)?;
let unclaimable_rewards = max_rewards.checked_sub(claimable_rewards).ok_or(MathError::Overflow)?;
let user_rewards = claimable_rewards
.checked_sub(accumulated_claimed_rewards)
.ok_or(MathError::Overflow)?;
Ok((user_rewards, unclaimable_rewards))
}
pub fn calculate_valued_shares(shares: Balance, incentivized_asset_balance: Balance) -> Result<Balance, MathError> {
shares
.checked_mul(incentivized_asset_balance)
.ok_or(MathError::Overflow)
}
pub fn calculate_global_pool_shares(valued_shares: Balance, multiplier: FixedU128) -> Result<Balance, MathError> {
multiplier.checked_mul_int(valued_shares).ok_or(MathError::Overflow)
}
pub fn calculate_reward(
accumulated_rps_start: Balance,
accumulated_rps_now: Balance,
shares: Balance,
) -> Result<Balance, MathError> {
accumulated_rps_now
.checked_sub(accumulated_rps_start)
.ok_or(MathError::Overflow)?
.checked_mul(shares)
.ok_or(MathError::Overflow)
}