solana_sdk/
inflation.rs

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