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
use substrate_fixed::{
transcendental::{pow, sqrt},
types::I64F64,
};
use frame_support::log;
use sp_arithmetic::helpers_128bit;
use sp_core::U256;
use sp_runtime::{Perbill, SaturatedConversion};
use crate::*;
pub const MILLISECONDS_PER_YEAR: TsInMs = (366 * 24 * 60 * 60) * 1000;
pub fn compute_total_payout<T: Config>(
era_duration: TsInMs,
living_time: TsInMs,
total_left: RingBalance<T>,
payout_fraction: Perbill,
) -> (RingBalance<T>, RingBalance<T>) {
log::info!(
target: "darwinia-staking",
"era_duration: {}, living_time: {}, total_left: {:?}, payout_fraction: {:?}",
era_duration,
living_time,
total_left,
payout_fraction,
);
let inflation = {
let maximum = {
let total_left = total_left.saturated_into::<Balance>();
helpers_128bit::multiply_by_rational(
total_left,
era_duration as _,
MILLISECONDS_PER_YEAR as _,
)
.unwrap_or(0)
};
let year = {
let year = living_time / MILLISECONDS_PER_YEAR + 1;
year as u32
};
compute_inflation(maximum, year).unwrap_or(0)
};
let payout = payout_fraction * inflation;
(
<RingBalance<T>>::saturated_from::<Balance>(payout),
<RingBalance<T>>::saturated_from::<Balance>(inflation),
)
}
pub fn compute_inflation(maximum: Balance, year: u32) -> Option<u128> {
type F64 = I64F64;
if let Ok(a) = sqrt::<F64, F64>(F64::from_num(year)) {
let b: F64 = F64::from_num(99) / 100;
if let Ok(c) = pow::<F64, F64>(b, a) {
let d: F64 = F64::from_num(1) - c;
let e: F64 = F64::from_num(maximum) * d;
#[cfg(test)]
{
let a_f64 = (year as f64).sqrt();
let b_f64 = 0.99_f64;
let c_f64 = b_f64.powf(a_f64);
let d_f64 = 1.00_f64 - c_f64;
let e_f64 = maximum as f64 * d_f64;
sp_runtime::assert_eq_error_rate!(
e.floor(),
e_f64 as u128,
if e_f64 == 0.00_f64 { 0 } else { 3 }
);
}
return Some(e.floor().to_num());
} else {
log::error!(target: "darwniia-staking", "Compute Inflation Failed at Step 1");
}
} else {
log::error!(target: "darwniia-staking", "Compute Inflation Failed at Step 0");
}
None
}
pub fn compute_kton_reward<T: Config>(value: RingBalance<T>, months: u8) -> KtonBalance<T> {
let value: U256 = value.saturated_into::<Balance>().into();
let n = U256::from(67).pow(U256::from(months));
let d = U256::from(66).pow(U256::from(months));
let quot = n / d;
let rem = n % d;
let precision: U256 = 1000.into();
(value * (precision * (quot - 1) + precision * rem / d) / U256::from(1_970_000))
.as_u128()
.saturated_into()
}