1#![allow(clippy::arithmetic_side_effects)]
6#![no_std]
7#![cfg_attr(docsrs, feature(doc_cfg))]
8#![cfg_attr(feature = "frozen-abi", feature(min_specialization))]
9#[cfg(feature = "frozen-abi")]
10extern crate std;
11
12#[cfg(feature = "sysvar")]
13pub mod sysvar;
14
15use solana_sdk_macro::CloneZeroed;
16
17const DEFAULT_SLOTS_PER_EPOCH: u64 = 432_000;
19#[cfg(test)]
20static_assertions::const_assert_eq!(
21 DEFAULT_SLOTS_PER_EPOCH,
22 solana_clock::DEFAULT_SLOTS_PER_EPOCH
23);
24
25#[repr(C)]
27#[cfg_attr(feature = "frozen-abi", derive(solana_frozen_abi_macro::AbiExample))]
28#[cfg_attr(
29 feature = "serde",
30 derive(serde_derive::Deserialize, serde_derive::Serialize)
31)]
32#[derive(PartialEq, CloneZeroed, Debug)]
33pub struct Rent {
34 #[deprecated(
36 since = "3.1.0",
37 note = "Field will be renamed to `lamports_per_byte` in v4, use `Rent::new_with_lamports_per_byte` to create, and `Rent::minimum_balance` or `Rent::is_exempt`"
38 )]
39 pub lamports_per_byte_year: u64,
40
41 #[deprecated(
44 since = "3.1.0",
45 note = "Exemption threshold will be set to 1f64 with SIMD-0194 and should no longer be used"
46 )]
47 pub exemption_threshold: f64,
48
49 #[deprecated(
54 since = "3.1.0",
55 note = "The concept of rent no longer exists, only rent-exemption"
56 )]
57 pub burn_percent: u8,
58}
59
60#[deprecated(
68 since = "3.1.0",
69 note = "The concept of rent no longer exists, only rent-exemption. Use `DEFAULT_LAMPORTS_PER_BYTE` instead"
70)]
71pub const DEFAULT_LAMPORTS_PER_BYTE_YEAR: u64 = 1_000_000_000 / 100 * 365 / (1024 * 1024);
72
73pub const DEFAULT_LAMPORTS_PER_BYTE: u64 = 6_960;
81
82#[deprecated(
85 since = "3.1.0",
86 note = "The concept of rent no longer exists, only rent-exemption"
87)]
88pub const DEFAULT_EXEMPTION_THRESHOLD: f64 = 2.0;
89
90#[deprecated(
95 since = "3.1.0",
96 note = "The concept of rent no longer exists, only rent-exemption"
97)]
98pub const DEFAULT_BURN_PERCENT: u8 = 50;
99
100pub const ACCOUNT_STORAGE_OVERHEAD: u64 = 128;
105
106impl Default for Rent {
107 #[allow(deprecated)]
108 fn default() -> Self {
109 Self {
110 lamports_per_byte_year: DEFAULT_LAMPORTS_PER_BYTE_YEAR,
111 exemption_threshold: DEFAULT_EXEMPTION_THRESHOLD,
112 burn_percent: DEFAULT_BURN_PERCENT,
113 }
114 }
115}
116
117impl Rent {
118 #[deprecated(
123 since = "3.1.0",
124 note = "The concept of rent no longer exists, only rent-exemption"
125 )]
126 #[allow(deprecated)]
127 pub fn calculate_burn(&self, rent_collected: u64) -> (u64, u64) {
128 let burned_portion = (rent_collected * u64::from(self.burn_percent)) / 100;
129 (burned_portion, rent_collected - burned_portion)
130 }
131
132 #[allow(deprecated)]
134 pub fn minimum_balance(&self, data_len: usize) -> u64 {
135 let bytes = data_len as u64;
136 (((ACCOUNT_STORAGE_OVERHEAD + bytes) * self.lamports_per_byte_year) as f64
137 * self.exemption_threshold) as u64
138 }
139
140 pub fn is_exempt(&self, balance: u64, data_len: usize) -> bool {
142 balance >= self.minimum_balance(data_len)
143 }
144
145 #[deprecated(
147 since = "3.1.0",
148 note = "The concept of rent no longer exists, only rent-exemption"
149 )]
150 #[allow(deprecated)]
151 pub fn due(&self, balance: u64, data_len: usize, years_elapsed: f64) -> RentDue {
152 if self.is_exempt(balance, data_len) {
153 RentDue::Exempt
154 } else {
155 RentDue::Paying(self.due_amount(data_len, years_elapsed))
156 }
157 }
158
159 #[deprecated(
161 since = "3.1.0",
162 note = "The concept of rent no longer exists, only rent-exemption"
163 )]
164 #[allow(deprecated)]
165 pub fn due_amount(&self, data_len: usize, years_elapsed: f64) -> u64 {
166 let actual_data_len = data_len as u64 + ACCOUNT_STORAGE_OVERHEAD;
167 let lamports_per_year = self.lamports_per_byte_year * actual_data_len;
168 (lamports_per_year as f64 * years_elapsed) as u64
169 }
170
171 #[allow(deprecated)]
175 pub fn free() -> Self {
176 Self {
177 lamports_per_byte_year: 0,
178 ..Rent::default()
179 }
180 }
181
182 #[deprecated(
186 since = "3.1.0",
187 note = "The concept of rent no longer exists, only rent-exemption, use `Rent::with_lamports_per_byte`"
188 )]
189 #[allow(deprecated)]
190 pub fn with_slots_per_epoch(slots_per_epoch: u64) -> Self {
191 let ratio = slots_per_epoch as f64 / DEFAULT_SLOTS_PER_EPOCH as f64;
192 let exemption_threshold = DEFAULT_EXEMPTION_THRESHOLD * ratio;
193 let lamports_per_byte_year = (DEFAULT_LAMPORTS_PER_BYTE_YEAR as f64 / ratio) as u64;
194 Self {
195 lamports_per_byte_year,
196 exemption_threshold,
197 ..Self::default()
198 }
199 }
200
201 #[allow(deprecated)]
203 pub fn with_lamports_per_byte(lamports_per_byte: u64) -> Self {
204 Self {
205 lamports_per_byte_year: lamports_per_byte,
206 exemption_threshold: 1.0,
207 ..Self::default()
208 }
209 }
210}
211
212#[deprecated(
214 since = "3.1.0",
215 note = "The concept of rent no longer exists, only rent-exemption"
216)]
217#[derive(Debug, Copy, Clone, Eq, PartialEq)]
218pub enum RentDue {
219 Exempt,
221 Paying(u64),
223}
224
225#[allow(deprecated)]
226impl RentDue {
227 pub fn lamports(&self) -> u64 {
229 match self {
230 RentDue::Exempt => 0,
231 RentDue::Paying(x) => *x,
232 }
233 }
234
235 pub fn is_exempt(&self) -> bool {
237 match self {
238 RentDue::Exempt => true,
239 RentDue::Paying(_) => false,
240 }
241 }
242}
243
244#[cfg(test)]
245mod tests {
246 use super::*;
247
248 #[test]
249 #[allow(deprecated)]
250 fn test_due() {
251 let default_rent = Rent::default();
252
253 assert_eq!(
254 default_rent.due(0, 2, 1.2),
255 RentDue::Paying(
256 (((2 + ACCOUNT_STORAGE_OVERHEAD) * DEFAULT_LAMPORTS_PER_BYTE_YEAR) as f64 * 1.2)
257 as u64
258 ),
259 );
260 assert_eq!(
261 default_rent.due(
262 (((2 + ACCOUNT_STORAGE_OVERHEAD) * DEFAULT_LAMPORTS_PER_BYTE_YEAR) as f64
263 * DEFAULT_EXEMPTION_THRESHOLD) as u64,
264 2,
265 1.2
266 ),
267 RentDue::Exempt,
268 );
269
270 let custom_rent = Rent {
271 lamports_per_byte_year: 5,
272 exemption_threshold: 2.5,
273 ..Rent::default()
274 };
275
276 assert_eq!(
277 custom_rent.due(0, 2, 1.2),
278 RentDue::Paying(
279 (((2 + ACCOUNT_STORAGE_OVERHEAD) * custom_rent.lamports_per_byte_year) as f64 * 1.2)
280 as u64,
281 )
282 );
283
284 assert_eq!(
285 custom_rent.due(
286 (((2 + ACCOUNT_STORAGE_OVERHEAD) * custom_rent.lamports_per_byte_year) as f64
287 * custom_rent.exemption_threshold) as u64,
288 2,
289 1.2
290 ),
291 RentDue::Exempt
292 );
293 }
294
295 #[test]
296 #[allow(deprecated)]
297 fn test_rent_due_lamports() {
298 assert_eq!(RentDue::Exempt.lamports(), 0);
299
300 let amount = 123;
301 assert_eq!(RentDue::Paying(amount).lamports(), amount);
302 }
303
304 #[test]
305 #[allow(deprecated)]
306 fn test_rent_due_is_exempt() {
307 assert!(RentDue::Exempt.is_exempt());
308 assert!(!RentDue::Paying(0).is_exempt());
309 }
310
311 #[test]
312 #[allow(deprecated)]
313 fn test_clone() {
314 let rent = Rent {
315 lamports_per_byte_year: 1,
316 exemption_threshold: 2.2,
317 burn_percent: 3,
318 };
319 #[allow(clippy::clone_on_copy)]
320 let cloned_rent = rent.clone();
321 assert_eq!(cloned_rent, rent);
322 }
323}