solana_fee_structure/
lib.rs1#![cfg_attr(docsrs, feature(doc_auto_cfg))]
3#![cfg_attr(feature = "frozen-abi", feature(min_specialization))]
4
5use std::num::NonZeroU32;
6
7#[derive(Debug, Default, Clone, Eq, PartialEq)]
9pub struct FeeBin {
10 pub limit: u64,
12 pub fee: u64,
14}
15
16pub struct FeeBudgetLimits {
17 pub loaded_accounts_data_size_limit: NonZeroU32,
18 pub heap_cost: u64,
19 pub compute_unit_limit: u64,
20 pub prioritization_fee: u64,
21}
22
23#[derive(Debug, Clone, Eq, PartialEq)]
25pub struct FeeStructure {
26 pub lamports_per_signature: u64,
28 pub lamports_per_write_lock: u64,
30 pub compute_fee_bins: Vec<FeeBin>,
32}
33
34#[cfg_attr(
35 feature = "serde",
36 derive(serde_derive::Deserialize, serde_derive::Serialize)
37)]
38#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)]
39pub struct FeeDetails {
40 transaction_fee: u64,
41 prioritization_fee: u64,
42}
43
44impl FeeDetails {
45 pub fn new(transaction_fee: u64, prioritization_fee: u64) -> Self {
46 Self {
47 transaction_fee,
48 prioritization_fee,
49 }
50 }
51
52 pub fn total_fee(&self) -> u64 {
53 self.transaction_fee.saturating_add(self.prioritization_fee)
54 }
55
56 pub fn accumulate(&mut self, fee_details: &FeeDetails) {
57 self.transaction_fee = self
58 .transaction_fee
59 .saturating_add(fee_details.transaction_fee);
60 self.prioritization_fee = self
61 .prioritization_fee
62 .saturating_add(fee_details.prioritization_fee)
63 }
64
65 pub fn transaction_fee(&self) -> u64 {
66 self.transaction_fee
67 }
68
69 pub fn prioritization_fee(&self) -> u64 {
70 self.prioritization_fee
71 }
72}
73
74pub const ACCOUNT_DATA_COST_PAGE_SIZE: u64 = 32_u64.saturating_mul(1024);
75
76impl FeeStructure {
77 pub fn get_max_fee(&self, num_signatures: u64, num_write_locks: u64) -> u64 {
78 num_signatures
79 .saturating_mul(self.lamports_per_signature)
80 .saturating_add(num_write_locks.saturating_mul(self.lamports_per_write_lock))
81 .saturating_add(
82 self.compute_fee_bins
83 .last()
84 .map(|bin| bin.fee)
85 .unwrap_or_default(),
86 )
87 }
88
89 pub fn calculate_memory_usage_cost(
90 loaded_accounts_data_size_limit: u32,
91 heap_cost: u64,
92 ) -> u64 {
93 (loaded_accounts_data_size_limit as u64)
94 .saturating_add(ACCOUNT_DATA_COST_PAGE_SIZE.saturating_sub(1))
95 .saturating_div(ACCOUNT_DATA_COST_PAGE_SIZE)
96 .saturating_mul(heap_cost)
97 }
98}
99
100impl Default for FeeStructure {
101 fn default() -> Self {
102 Self {
103 lamports_per_signature: 5000,
104 lamports_per_write_lock: 0,
105 compute_fee_bins: vec![FeeBin {
106 limit: 1_400_000,
107 fee: 0,
108 }],
109 }
110 }
111}
112
113#[cfg(feature = "frozen-abi")]
114impl ::solana_frozen_abi::abi_example::AbiExample for FeeStructure {
115 fn example() -> Self {
116 FeeStructure::default()
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123
124 #[test]
125 fn test_calculate_memory_usage_cost() {
126 let heap_cost = 99;
127 const K: u32 = 1024;
128
129 assert_eq!(
133 heap_cost,
134 FeeStructure::calculate_memory_usage_cost(31 * K, heap_cost)
135 );
136
137 assert_eq!(
139 heap_cost,
140 FeeStructure::calculate_memory_usage_cost(32 * K, heap_cost)
141 );
142
143 assert_eq!(
145 heap_cost * 2,
146 FeeStructure::calculate_memory_usage_cost(33 * K, heap_cost)
147 );
148
149 assert_eq!(
151 heap_cost * 2,
152 FeeStructure::calculate_memory_usage_cost(64 * K, heap_cost)
153 );
154 }
155}