1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
use crate::MathError;
use crate::MathError::Overflow;
use sp_arithmetic::{
traits::{CheckedAdd, CheckedDiv, CheckedMul, CheckedSub},
FixedPointNumber, FixedU128,
};
use crate::to_balance;
use crate::types::Balance;
use core::convert::TryInto;
use primitive_types::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 periods = FixedU128::from(TryInto::<u128>::try_into(periods).map_err(|_e| MathError::Overflow)?);
let sc_coef = FixedU128::from(scale_coef as u128);
let num = initial_reward_percentage
.checked_mul(&sc_coef)
.ok_or(MathError::Overflow)?
.checked_add(&periods)
.ok_or(MathError::Overflow)?;
let denom = periods.checked_add(&sc_coef).ok_or(MathError::Overflow)?;
num.checked_div(&denom).ok_or(MathError::Overflow)
}
pub fn calculate_accumulated_rps(
accumulated_rps_now: FixedU128,
total_shares: Balance,
reward: Balance,
) -> Result<FixedU128, MathError> {
let rps = FixedU128::checked_from_rational(reward, total_shares).ok_or(MathError::DivisionByZero)?;
rps.checked_add(&accumulated_rps_now).ok_or(MathError::Overflow)
}
pub fn calculate_user_reward(
accumulated_rpvs: FixedU128,
valued_shares: Balance, accumulated_claimed_rewards: Balance,
accumulated_rpvs_now: FixedU128,
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_farm_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: FixedU128,
accumulated_rps_now: FixedU128,
shares: Balance,
) -> Result<Balance, MathError> {
accumulated_rps_now
.checked_sub(&accumulated_rps_start)
.ok_or(MathError::Overflow)?
.checked_mul_int(shares)
.ok_or(MathError::Overflow)
}
pub fn calculate_yield_farm_rewards(
yield_farm_rpz: FixedU128,
global_farm_rpz: FixedU128,
multiplier: FixedU128,
total_valued_shares: Balance,
) -> Result<(FixedU128, Balance), MathError> {
let stake_in_global_farm =
calculate_global_farm_shares(total_valued_shares, multiplier).map_err(|_| MathError::Overflow)?;
let yield_farm_rewards =
calculate_reward(yield_farm_rpz, global_farm_rpz, stake_in_global_farm).map_err(|_| MathError::Overflow)?;
let delta_rpvs =
FixedU128::checked_from_rational(yield_farm_rewards, total_valued_shares).ok_or(MathError::Overflow)?;
Ok((delta_rpvs, yield_farm_rewards))
}
pub fn calculate_global_farm_rewards<Period: num_traits::CheckedSub + TryInto<u32> + TryInto<u128>>(
total_shares_z: Balance,
price_adjustment: FixedU128,
yield_per_period: FixedU128,
max_reward_per_period: Balance,
periods_since_last_update: Period,
) -> Result<Balance, MathError> {
let total_shares_z_adjusted = price_adjustment
.checked_mul_int(total_shares_z)
.ok_or(MathError::Overflow)?;
let periods = TryInto::<u128>::try_into(periods_since_last_update).map_err(|_e| MathError::Overflow)?;
let calculated_rewards = U128::from(total_shares_z_adjusted)
.full_mul(yield_per_period.into_inner().into())
.checked_mul(periods.into())
.ok_or(MathError::Overflow)?
.checked_div(FixedU128::DIV.into())
.ok_or(MathError::Overflow)?;
let rewards = to_balance!(calculated_rewards)?;
let max_reward_for_periods = max_reward_per_period.checked_mul(periods).ok_or(MathError::Overflow)?;
Ok(rewards.min(max_reward_for_periods))
}