solana_fee_structure/
lib.rs1#![cfg_attr(docsrs, feature(doc_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 resource_fee: u64,
44}
45
46impl FeeDetails {
47 pub fn new(transaction_fee: u64, prioritization_fee: u64) -> Self {
48 Self {
49 transaction_fee,
50 prioritization_fee,
51 resource_fee: 0,
52 }
53 }
54
55 pub fn new_with_resource_fee(
56 transaction_fee: u64,
57 prioritization_fee: u64,
58 resource_fee: u64,
59 ) -> Self {
60 Self {
61 transaction_fee,
62 prioritization_fee,
63 resource_fee,
64 }
65 }
66
67 pub fn total_fee(&self) -> u64 {
68 self.transaction_fee
69 .saturating_add(self.prioritization_fee)
70 .saturating_add(self.resource_fee)
71 }
72
73 pub fn accumulate(&mut self, fee_details: &FeeDetails) {
74 self.transaction_fee = self
75 .transaction_fee
76 .saturating_add(fee_details.transaction_fee);
77 self.prioritization_fee = self
78 .prioritization_fee
79 .saturating_add(fee_details.prioritization_fee);
80 self.resource_fee = self.resource_fee.saturating_add(fee_details.resource_fee);
81 }
82
83 pub fn transaction_fee(&self) -> u64 {
84 self.transaction_fee
85 }
86
87 pub fn prioritization_fee(&self) -> u64 {
88 self.prioritization_fee
89 }
90
91 pub fn resource_fee(&self) -> u64 {
92 self.resource_fee
93 }
94}
95
96pub const ACCOUNT_DATA_COST_PAGE_SIZE: u64 = 32_u64.saturating_mul(1024);
97
98impl FeeStructure {
99 pub fn get_max_fee(&self, num_signatures: u64, num_write_locks: u64) -> u64 {
100 num_signatures
101 .saturating_mul(self.lamports_per_signature)
102 .saturating_add(num_write_locks.saturating_mul(self.lamports_per_write_lock))
103 .saturating_add(
104 self.compute_fee_bins
105 .last()
106 .map(|bin| bin.fee)
107 .unwrap_or_default(),
108 )
109 }
110
111 pub fn calculate_memory_usage_cost(
112 loaded_accounts_data_size_limit: u32,
113 heap_cost: u64,
114 ) -> u64 {
115 (loaded_accounts_data_size_limit as u64)
116 .saturating_add(ACCOUNT_DATA_COST_PAGE_SIZE.saturating_sub(1))
117 .saturating_div(ACCOUNT_DATA_COST_PAGE_SIZE)
118 .saturating_mul(heap_cost)
119 }
120}
121
122impl Default for FeeStructure {
123 fn default() -> Self {
124 Self {
125 lamports_per_signature: 5000,
126 lamports_per_write_lock: 0,
127 compute_fee_bins: vec![FeeBin {
128 limit: 1_400_000,
129 fee: 0,
130 }],
131 }
132 }
133}
134
135#[cfg(feature = "frozen-abi")]
136impl ::solana_frozen_abi::abi_example::AbiExample for FeeStructure {
137 fn example() -> Self {
138 FeeStructure::default()
139 }
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145
146 #[test]
147 fn test_calculate_memory_usage_cost() {
148 let heap_cost = 99;
149 const K: u32 = 1024;
150
151 assert_eq!(
155 heap_cost,
156 FeeStructure::calculate_memory_usage_cost(31 * K, heap_cost)
157 );
158
159 assert_eq!(
161 heap_cost,
162 FeeStructure::calculate_memory_usage_cost(32 * K, heap_cost)
163 );
164
165 assert_eq!(
167 heap_cost * 2,
168 FeeStructure::calculate_memory_usage_cost(33 * K, heap_cost)
169 );
170
171 assert_eq!(
173 heap_cost * 2,
174 FeeStructure::calculate_memory_usage_cost(64 * K, heap_cost)
175 );
176 }
177}