atlas_inflation/
lib.rs

1//! configuration for network inflation
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![cfg_attr(feature = "frozen-abi", feature(min_specialization))]
4#[cfg(feature = "serde")]
5use serde_derive::{Deserialize, Serialize};
6
7#[cfg_attr(feature = "frozen-abi", derive(atlas_frozen_abi_macro::AbiExample))]
8#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
9#[derive(PartialEq, Clone, Debug, Copy)]
10#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
11pub struct Inflation {
12    /// Initial inflation percentage, from time=0
13    pub initial: f64,
14
15    /// Terminal inflation percentage, to time=INF
16    pub terminal: f64,
17
18    /// Rate per year, at which inflation is lowered until reaching terminal
19    ///  i.e. inflation(year) == MAX(terminal, initial*((1-taper)^year))
20    pub taper: f64,
21
22    /// Percentage of total inflation allocated to the foundation
23    pub foundation: f64,
24    /// Duration of foundation pool inflation, in years
25    pub foundation_term: f64,
26
27    /// DEPRECATED, this field is currently unused
28    __unused: f64,
29}
30
31const DEFAULT_INITIAL: f64 = 0.08;
32const DEFAULT_TERMINAL: f64 = 0.015;
33const DEFAULT_TAPER: f64 = 0.15;
34const DEFAULT_FOUNDATION: f64 = 0.05;
35const DEFAULT_FOUNDATION_TERM: f64 = 7.0;
36
37impl Default for Inflation {
38    fn default() -> Self {
39        Self {
40            initial: DEFAULT_INITIAL,
41            terminal: DEFAULT_TERMINAL,
42            taper: DEFAULT_TAPER,
43            foundation: DEFAULT_FOUNDATION,
44            foundation_term: DEFAULT_FOUNDATION_TERM,
45            __unused: 0.0,
46        }
47    }
48}
49
50impl Inflation {
51    pub fn new_disabled() -> Self {
52        Self {
53            initial: 0.0,
54            terminal: 0.0,
55            taper: 0.0,
56            foundation: 0.0,
57            foundation_term: 0.0,
58            __unused: 0.0,
59        }
60    }
61
62    // fixed inflation rate at `validator` percentage for staking rewards, and none for foundation
63    pub fn new_fixed(validator: f64) -> Self {
64        Self {
65            initial: validator,
66            terminal: validator,
67            taper: 1.0,
68            foundation: 0.0,
69            foundation_term: 0.0,
70            __unused: 0.0,
71        }
72    }
73
74    pub fn pico() -> Self {
75        Self::new_fixed(0.0001) // 0.01% inflation
76    }
77
78    pub fn full() -> Self {
79        Self {
80            initial: DEFAULT_INITIAL,
81            terminal: DEFAULT_TERMINAL,
82            taper: DEFAULT_TAPER,
83            foundation: 0.0,
84            foundation_term: 0.0,
85            __unused: 0.0,
86        }
87    }
88
89    /// inflation rate at year
90    pub fn total(&self, year: f64) -> f64 {
91        assert!(year >= 0.0);
92        let tapered = self.initial * ((1.0 - self.taper).powf(year));
93
94        if tapered > self.terminal {
95            tapered
96        } else {
97            self.terminal
98        }
99    }
100
101    /// portion of total that goes to validators
102    pub fn validator(&self, year: f64) -> f64 {
103        self.total(year) - self.foundation(year)
104    }
105
106    /// portion of total that goes to foundation
107    pub fn foundation(&self, year: f64) -> f64 {
108        if year < self.foundation_term {
109            self.total(year) * self.foundation
110        } else {
111            0.0
112        }
113    }
114}
115
116#[cfg(test)]
117mod tests {
118    use super::*;
119
120    #[test]
121    fn test_inflation_basic() {
122        let inflation = Inflation::default();
123
124        let mut last = inflation.total(0.0);
125
126        for year in &[0.1, 0.5, 1.0, DEFAULT_FOUNDATION_TERM, 100.0] {
127            let total = inflation.total(*year);
128            assert_eq!(
129                total,
130                inflation.validator(*year) + inflation.foundation(*year)
131            );
132            assert!(total < last);
133            assert!(total >= inflation.terminal);
134            last = total;
135        }
136        assert_eq!(last, inflation.terminal);
137    }
138
139    #[test]
140    fn test_inflation_fixed() {
141        let inflation = Inflation::new_fixed(0.001);
142        for year in &[0.1, 0.5, 1.0, DEFAULT_FOUNDATION_TERM, 100.0] {
143            assert_eq!(inflation.total(*year), 0.001);
144        }
145    }
146}