pallet_parachain_staking/
inflation.rs1use crate::pallet::{BalanceOf, Config, Pallet};
19use frame_support::traits::{fungible::Inspect, Get};
20use parity_scale_codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
21use scale_info::TypeInfo;
22use serde::{Deserialize, Serialize};
23use sp_runtime::PerThing;
24use sp_runtime::{Perbill, RuntimeDebug};
25use substrate_fixed::transcendental::pow as floatpow;
26use substrate_fixed::types::I64F64;
27
28const MS_PER_YEAR: u64 = 31_557_600_000;
30
31fn rounds_per_year<T: Config>() -> u32 {
32 let blocks_per_round = <Pallet<T>>::round().length as u64;
33 let blocks_per_year = MS_PER_YEAR / T::BlockTime::get();
34 (blocks_per_year / blocks_per_round) as u32
35}
36
37#[derive(
38 Eq,
39 PartialEq,
40 Clone,
41 Copy,
42 Encode,
43 Decode,
44 DecodeWithMemTracking,
45 Default,
46 Deserialize,
47 RuntimeDebug,
48 MaxEncodedLen,
49 Serialize,
50 TypeInfo,
51)]
52pub struct Range<T> {
53 pub min: T,
54 pub ideal: T,
55 pub max: T,
56}
57
58impl<T: Ord> Range<T> {
59 pub fn is_valid(&self) -> bool {
60 self.max >= self.ideal && self.ideal >= self.min
61 }
62}
63
64impl<T: Ord + Copy> From<T> for Range<T> {
65 fn from(other: T) -> Range<T> {
66 Range {
67 min: other,
68 ideal: other,
69 max: other,
70 }
71 }
72}
73pub fn perbill_annual_to_perbill_round(
76 annual: Range<Perbill>,
77 rounds_per_year: u32,
78) -> Range<Perbill> {
79 let exponent = I64F64::from_num(1) / I64F64::from_num(rounds_per_year);
80 let annual_to_round = |annual: Perbill| -> Perbill {
81 let x = I64F64::from_num(annual.deconstruct()) / I64F64::from_num(Perbill::ACCURACY);
82 let y: I64F64 = floatpow(I64F64::from_num(1) + x, exponent)
83 .expect("Cannot overflow since rounds_per_year is u32 so worst case 0; QED");
84 Perbill::from_parts(
85 ((y - I64F64::from_num(1)) * I64F64::from_num(Perbill::ACCURACY))
86 .ceil()
87 .to_num::<u32>(),
88 )
89 };
90 Range {
91 min: annual_to_round(annual.min),
92 ideal: annual_to_round(annual.ideal),
93 max: annual_to_round(annual.max),
94 }
95}
96pub fn annual_to_round<T: Config>(annual: Range<Perbill>) -> Range<Perbill> {
98 let periods = rounds_per_year::<T>();
99 perbill_annual_to_perbill_round(annual, periods)
100}
101
102pub fn round_issuance_range<T: Config>(round: Range<Perbill>) -> Range<BalanceOf<T>> {
104 let circulating = if let Some(threshold) = T::LinearInflationThreshold::get() {
105 core::cmp::min(T::Currency::total_issuance(), threshold)
106 } else {
107 T::Currency::total_issuance()
108 };
109 Range {
110 min: round.min * circulating,
111 ideal: round.ideal * circulating,
112 max: round.max * circulating,
113 }
114}
115
116#[derive(
117 Eq, PartialEq, Clone, Encode, Decode, Default, Deserialize, RuntimeDebug, Serialize, TypeInfo,
118)]
119pub struct InflationInfo<Balance> {
120 pub expect: Range<Balance>,
122 pub annual: Range<Perbill>,
124 pub round: Range<Perbill>,
126}
127
128impl<Balance> InflationInfo<Balance> {
129 pub fn new<T: Config>(
130 annual: Range<Perbill>,
131 expect: Range<Balance>,
132 ) -> InflationInfo<Balance> {
133 InflationInfo {
134 expect,
135 annual,
136 round: annual_to_round::<T>(annual),
137 }
138 }
139 pub fn set_round_from_annual<T: Config>(&mut self, new: Range<Perbill>) {
141 self.round = annual_to_round::<T>(new);
142 }
143 pub fn reset_round<T: Config>(&mut self, new_length: u32) {
145 let periods = (MS_PER_YEAR / T::BlockTime::get()) / (new_length as u64);
146 self.round = perbill_annual_to_perbill_round(self.annual, periods as u32);
147 }
148 pub fn set_expectations(&mut self, expect: Range<Balance>) {
150 self.expect = expect;
151 }
152}
153
154#[cfg(test)]
155mod tests {
156 use super::*;
157 fn mock_annual_to_round(annual: Range<Perbill>, rounds_per_year: u32) -> Range<Perbill> {
158 perbill_annual_to_perbill_round(annual, rounds_per_year)
159 }
160 fn mock_round_issuance_range(
161 circulating: u128,
163 round: Range<Perbill>,
165 ) -> Range<u128> {
166 Range {
167 min: round.min * circulating,
168 ideal: round.ideal * circulating,
169 max: round.max * circulating,
170 }
171 }
172 #[test]
173 fn simple_issuance_conversion() {
174 let expected_round_issuance_range: Range<u128> = Range {
178 min: 48_909,
179 ideal: 48_909,
180 max: 48_909,
181 };
182 let schedule = Range {
183 min: Perbill::from_percent(5),
184 ideal: Perbill::from_percent(5),
185 max: Perbill::from_percent(5),
186 };
187 assert_eq!(
188 expected_round_issuance_range,
189 mock_round_issuance_range(10_000_000, mock_annual_to_round(schedule, 10))
190 );
191 }
192 #[test]
193 fn range_issuance_conversion() {
194 let expected_round_issuance_range: Range<u128> = Range {
198 min: 29_603,
199 ideal: 39298,
200 max: 48_909,
201 };
202 let schedule = Range {
203 min: Perbill::from_percent(3),
204 ideal: Perbill::from_percent(4),
205 max: Perbill::from_percent(5),
206 };
207 assert_eq!(
208 expected_round_issuance_range,
209 mock_round_issuance_range(10_000_000, mock_annual_to_round(schedule, 10))
210 );
211 }
212 #[test]
213 fn expected_parameterization() {
214 let expected_round_schedule: Range<u128> = Range {
215 min: 45,
216 ideal: 56,
217 max: 56,
218 };
219 let schedule = Range {
220 min: Perbill::from_percent(4),
221 ideal: Perbill::from_percent(5),
222 max: Perbill::from_percent(5),
223 };
224 assert_eq!(
225 expected_round_schedule,
226 mock_round_issuance_range(10_000_000, mock_annual_to_round(schedule, 8766))
227 );
228 }
229 #[test]
230 fn inflation_does_not_panic_at_round_number_limit() {
231 let schedule = Range {
232 min: Perbill::from_percent(100),
233 ideal: Perbill::from_percent(100),
234 max: Perbill::from_percent(100),
235 };
236 mock_round_issuance_range(u32::MAX.into(), mock_annual_to_round(schedule, u32::MAX));
237 mock_round_issuance_range(u64::MAX.into(), mock_annual_to_round(schedule, u32::MAX));
238 mock_round_issuance_range(u128::MAX.into(), mock_annual_to_round(schedule, u32::MAX));
239 mock_round_issuance_range(u32::MAX.into(), mock_annual_to_round(schedule, 1));
240 mock_round_issuance_range(u64::MAX.into(), mock_annual_to_round(schedule, 1));
241 mock_round_issuance_range(u128::MAX.into(), mock_annual_to_round(schedule, 1));
242 }
243}