1#![cfg_attr(feature = "frozen-abi", feature(min_specialization))]
3#[cfg(feature = "serde")]
4use serde_derive::{Deserialize, Serialize};
5
6#[cfg_attr(feature = "frozen-abi", derive(solana_frozen_abi_macro::AbiExample))]
7#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
8#[derive(PartialEq, Clone, Debug, Copy)]
9#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
10pub struct Inflation {
11 pub initial: f64,
13
14 pub terminal: f64,
16
17 pub taper: f64,
20
21 pub foundation: f64,
23 pub foundation_term: f64,
25
26 __unused: f64,
28}
29
30const DEFAULT_INITIAL: f64 = 0.08;
31const DEFAULT_TERMINAL: f64 = 0.015;
32const DEFAULT_TAPER: f64 = 0.15;
33const DEFAULT_FOUNDATION: f64 = 0.05;
34const DEFAULT_FOUNDATION_TERM: f64 = 7.0;
35
36impl Default for Inflation {
37 fn default() -> Self {
38 Self {
39 initial: DEFAULT_INITIAL,
40 terminal: DEFAULT_TERMINAL,
41 taper: DEFAULT_TAPER,
42 foundation: DEFAULT_FOUNDATION,
43 foundation_term: DEFAULT_FOUNDATION_TERM,
44 __unused: 0.0,
45 }
46 }
47}
48
49impl Inflation {
50 pub fn new_disabled() -> Self {
51 Self {
52 initial: 0.0,
53 terminal: 0.0,
54 taper: 0.0,
55 foundation: 0.0,
56 foundation_term: 0.0,
57 __unused: 0.0,
58 }
59 }
60
61 pub fn new_fixed(validator: f64) -> Self {
63 Self {
64 initial: validator,
65 terminal: validator,
66 taper: 1.0,
67 foundation: 0.0,
68 foundation_term: 0.0,
69 __unused: 0.0,
70 }
71 }
72
73 pub fn pico() -> Self {
74 Self::new_fixed(0.0001) }
76
77 pub fn full() -> Self {
78 Self {
79 initial: DEFAULT_INITIAL,
80 terminal: DEFAULT_TERMINAL,
81 taper: DEFAULT_TAPER,
82 foundation: 0.0,
83 foundation_term: 0.0,
84 __unused: 0.0,
85 }
86 }
87
88 pub fn total(&self, year: f64) -> f64 {
90 assert!(year >= 0.0);
91 let tapered = self.initial * ((1.0 - self.taper).powf(year));
92
93 if tapered > self.terminal {
94 tapered
95 } else {
96 self.terminal
97 }
98 }
99
100 pub fn validator(&self, year: f64) -> f64 {
102 self.total(year) - self.foundation(year)
103 }
104
105 pub fn foundation(&self, year: f64) -> f64 {
107 if year < self.foundation_term {
108 self.total(year) * self.foundation
109 } else {
110 0.0
111 }
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118
119 #[test]
120 fn test_inflation_basic() {
121 let inflation = Inflation::default();
122
123 let mut last = inflation.total(0.0);
124
125 for year in &[0.1, 0.5, 1.0, DEFAULT_FOUNDATION_TERM, 100.0] {
126 let total = inflation.total(*year);
127 assert_eq!(
128 total,
129 inflation.validator(*year) + inflation.foundation(*year)
130 );
131 assert!(total < last);
132 assert!(total >= inflation.terminal);
133 last = total;
134 }
135 assert_eq!(last, inflation.terminal);
136 }
137
138 #[test]
139 fn test_inflation_fixed() {
140 let inflation = Inflation::new_fixed(0.001);
141 for year in &[0.1, 0.5, 1.0, DEFAULT_FOUNDATION_TERM, 100.0] {
142 assert_eq!(inflation.total(*year), 0.001);
143 }
144 }
145}