1use crate::eip1559::{constants::GAS_LIMIT_BOUND_DIVISOR, BaseFeeParams};
2
3#[derive(Clone, Copy, Debug, PartialEq, Eq)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
9pub struct Eip1559Estimation {
10 #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
12 pub max_fee_per_gas: u128,
13 #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
15 pub max_priority_fee_per_gas: u128,
16}
17
18pub fn calc_next_block_base_fee(
42 gas_used: u64,
43 gas_limit: u64,
44 base_fee: u64,
45 base_fee_params: BaseFeeParams,
46) -> u64 {
47 let gas_target = gas_limit / base_fee_params.elasticity_multiplier as u64;
49
50 match gas_used.cmp(&gas_target) {
51 core::cmp::Ordering::Equal => base_fee,
54 core::cmp::Ordering::Greater => {
57 base_fee
59 + (core::cmp::max(
60 1,
62 base_fee as u128 * (gas_used - gas_target) as u128
63 / (gas_target as u128 * base_fee_params.max_change_denominator),
64 ) as u64)
65 }
66 core::cmp::Ordering::Less => {
69 base_fee.saturating_sub(
71 (base_fee as u128 * (gas_target - gas_used) as u128
72 / (gas_target as u128 * base_fee_params.max_change_denominator))
73 as u64,
74 )
75 }
76 }
77}
78
79pub fn calculate_block_gas_limit(parent_gas_limit: u64, desired_gas_limit: u64) -> u64 {
82 let delta = (parent_gas_limit / GAS_LIMIT_BOUND_DIVISOR).saturating_sub(1);
83 let min_gas_limit = parent_gas_limit - delta;
84 let max_gas_limit = parent_gas_limit + delta;
85 desired_gas_limit.clamp(min_gas_limit, max_gas_limit)
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91 use crate::eip1559::constants::{MIN_PROTOCOL_BASE_FEE, MIN_PROTOCOL_BASE_FEE_U256};
92
93 #[test]
94 fn min_protocol_sanity() {
95 assert_eq!(MIN_PROTOCOL_BASE_FEE_U256.to::<u64>(), MIN_PROTOCOL_BASE_FEE);
96 }
97
98 #[test]
99 fn calculate_base_fee_success() {
100 let base_fee = [
101 1000000000, 1000000000, 1000000000, 1072671875, 1059263476, 1049238967, 1049238967, 0,
102 1, 2,
103 ];
104 let gas_used = [
105 10000000, 10000000, 10000000, 9000000, 10001000, 0, 10000000, 10000000, 10000000,
106 10000000,
107 ];
108 let gas_limit = [
109 10000000, 12000000, 14000000, 10000000, 14000000, 2000000, 18000000, 18000000,
110 18000000, 18000000,
111 ];
112 let next_base_fee = [
113 1125000000, 1083333333, 1053571428, 1179939062, 1116028649, 918084097, 1063811730, 1,
114 2, 3,
115 ];
116
117 for i in 0..base_fee.len() {
118 assert_eq!(
119 next_base_fee[i],
120 calc_next_block_base_fee(
121 gas_used[i],
122 gas_limit[i],
123 base_fee[i],
124 BaseFeeParams::ethereum(),
125 )
126 );
127 }
128 }
129
130 #[test]
131 fn calculate_optimism_sepolia_base_fee_success() {
132 let base_fee = [
133 1000000000, 1000000000, 1000000000, 1072671875, 1059263476, 1049238967, 1049238967, 0,
134 1, 2,
135 ];
136 let gas_used = [
137 10000000, 10000000, 10000000, 9000000, 10001000, 0, 10000000, 10000000, 10000000,
138 10000000,
139 ];
140 let gas_limit = [
141 10000000, 12000000, 14000000, 10000000, 14000000, 2000000, 18000000, 18000000,
142 18000000, 18000000,
143 ];
144 let next_base_fee = [
145 1100000048, 1080000000, 1065714297, 1167067046, 1128881311, 1028254188, 1098203452, 1,
146 2, 3,
147 ];
148
149 for i in 0..base_fee.len() {
150 assert_eq!(
151 next_base_fee[i],
152 calc_next_block_base_fee(
153 gas_used[i],
154 gas_limit[i],
155 base_fee[i],
156 BaseFeeParams::optimism_sepolia(),
157 )
158 );
159 }
160 }
161
162 #[test]
163 fn calculate_optimism_base_fee_success() {
164 let base_fee = [
165 1000000000, 1000000000, 1000000000, 1072671875, 1059263476, 1049238967, 1049238967, 0,
166 1, 2,
167 ];
168 let gas_used = [
169 10000000, 10000000, 10000000, 9000000, 10001000, 0, 10000000, 10000000, 10000000,
170 10000000,
171 ];
172 let gas_limit = [
173 10000000, 12000000, 14000000, 10000000, 14000000, 2000000, 18000000, 18000000,
174 18000000, 18000000,
175 ];
176 let next_base_fee = [
177 1100000048, 1080000000, 1065714297, 1167067046, 1128881311, 1028254188, 1098203452, 1,
178 2, 3,
179 ];
180
181 for i in 0..base_fee.len() {
182 assert_eq!(
183 next_base_fee[i],
184 calc_next_block_base_fee(
185 gas_used[i],
186 gas_limit[i],
187 base_fee[i],
188 BaseFeeParams::optimism(),
189 )
190 );
191 }
192 }
193
194 #[test]
195 fn calculate_optimism_canyon_base_fee_success() {
196 let base_fee = [
197 1000000000, 1000000000, 1000000000, 1072671875, 1059263476, 1049238967, 1049238967, 0,
198 1, 2,
199 ];
200 let gas_used = [
201 10000000, 10000000, 10000000, 9000000, 10001000, 0, 10000000, 10000000, 10000000,
202 10000000,
203 ];
204 let gas_limit = [
205 10000000, 12000000, 14000000, 10000000, 14000000, 2000000, 18000000, 18000000,
206 18000000, 18000000,
207 ];
208 let next_base_fee = [
209 1020000009, 1016000000, 1013142859, 1091550909, 1073187043, 1045042012, 1059031864, 1,
210 2, 3,
211 ];
212
213 for i in 0..base_fee.len() {
214 assert_eq!(
215 next_base_fee[i],
216 calc_next_block_base_fee(
217 gas_used[i],
218 gas_limit[i],
219 base_fee[i],
220 BaseFeeParams::optimism_canyon(),
221 )
222 );
223 }
224 }
225
226 #[test]
227 fn calculate_base_sepolia_base_fee_success() {
228 let base_fee = [
229 1000000000, 1000000000, 1000000000, 1072671875, 1059263476, 1049238967, 1049238967, 0,
230 1, 2,
231 ];
232 let gas_used = [
233 10000000, 10000000, 10000000, 9000000, 10001000, 0, 10000000, 10000000, 10000000,
234 10000000,
235 ];
236 let gas_limit = [
237 10000000, 12000000, 14000000, 10000000, 14000000, 2000000, 18000000, 18000000,
238 18000000, 18000000,
239 ];
240 let next_base_fee = [
241 1180000000, 1146666666, 1122857142, 1244299375, 1189416692, 1028254188, 1144836295, 1,
242 2, 3,
243 ];
244
245 for i in 0..base_fee.len() {
246 assert_eq!(
247 next_base_fee[i],
248 calc_next_block_base_fee(
249 gas_used[i],
250 gas_limit[i],
251 base_fee[i],
252 BaseFeeParams::base_sepolia(),
253 )
254 );
255 }
256 }
257}