1use crate::eip1559::{constants::GAS_LIMIT_BOUND_DIVISOR, BaseFeeParams};
2
3#[inline]
14pub fn calc_effective_gas_price(
15 max_fee_per_gas: u128,
16 max_priority_fee_per_gas: u128,
17 base_fee: Option<u64>,
18) -> u128 {
19 base_fee.map_or(max_fee_per_gas, |base_fee| {
20 let tip = max_fee_per_gas.saturating_sub(base_fee as u128);
23 if tip > max_priority_fee_per_gas {
24 max_priority_fee_per_gas + base_fee as u128
25 } else {
26 max_fee_per_gas
28 }
29 })
30}
31
32#[derive(Clone, Copy, Debug, PartialEq, Eq)]
36#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
37#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
38pub struct Eip1559Estimation {
39 #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
41 pub max_fee_per_gas: u128,
42 #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
44 pub max_priority_fee_per_gas: u128,
45}
46
47impl Eip1559Estimation {
48 pub const fn scale_by_pct(&mut self, pct: u64) {
58 self.max_fee_per_gas = self.max_fee_per_gas * (100 + pct as u128) / 100;
59 self.max_priority_fee_per_gas = self.max_priority_fee_per_gas * (100 + pct as u128) / 100;
60 }
61
62 pub const fn scaled_by_pct(mut self, pct: u64) -> Self {
64 self.scale_by_pct(pct);
65 self
66 }
67}
68
69pub fn calc_next_block_base_fee(
93 gas_used: u64,
94 gas_limit: u64,
95 base_fee: u64,
96 base_fee_params: BaseFeeParams,
97) -> u64 {
98 let gas_target = gas_limit / base_fee_params.elasticity_multiplier as u64;
100
101 match gas_used.cmp(&gas_target) {
102 core::cmp::Ordering::Equal => base_fee,
105 core::cmp::Ordering::Greater => {
108 base_fee
110 + (core::cmp::max(
111 1,
113 base_fee as u128 * (gas_used - gas_target) as u128
114 / (gas_target as u128 * base_fee_params.max_change_denominator),
115 ) as u64)
116 }
117 core::cmp::Ordering::Less => {
120 base_fee.saturating_sub(
122 (base_fee as u128 * (gas_target - gas_used) as u128
123 / (gas_target as u128 * base_fee_params.max_change_denominator))
124 as u64,
125 )
126 }
127 }
128}
129
130pub fn calculate_block_gas_limit(parent_gas_limit: u64, desired_gas_limit: u64) -> u64 {
133 let delta = (parent_gas_limit / GAS_LIMIT_BOUND_DIVISOR).saturating_sub(1);
134 let min_gas_limit = parent_gas_limit - delta;
135 let max_gas_limit = parent_gas_limit + delta;
136 desired_gas_limit.clamp(min_gas_limit, max_gas_limit)
137}
138
139#[cfg(test)]
140mod tests {
141 use super::*;
142 use crate::eip1559::constants::{MIN_PROTOCOL_BASE_FEE, MIN_PROTOCOL_BASE_FEE_U256};
143
144 #[test]
145 fn min_protocol_sanity() {
146 assert_eq!(MIN_PROTOCOL_BASE_FEE_U256.to::<u64>(), MIN_PROTOCOL_BASE_FEE);
147 }
148
149 #[test]
150 fn calculate_base_fee_success() {
151 let base_fee = [
152 1000000000, 1000000000, 1000000000, 1072671875, 1059263476, 1049238967, 1049238967, 0,
153 1, 2,
154 ];
155 let gas_used = [
156 10000000, 10000000, 10000000, 9000000, 10001000, 0, 10000000, 10000000, 10000000,
157 10000000,
158 ];
159 let gas_limit = [
160 10000000, 12000000, 14000000, 10000000, 14000000, 2000000, 18000000, 18000000,
161 18000000, 18000000,
162 ];
163 let next_base_fee = [
164 1125000000, 1083333333, 1053571428, 1179939062, 1116028649, 918084097, 1063811730, 1,
165 2, 3,
166 ];
167
168 for i in 0..base_fee.len() {
169 assert_eq!(
170 next_base_fee[i],
171 calc_next_block_base_fee(
172 gas_used[i],
173 gas_limit[i],
174 base_fee[i],
175 BaseFeeParams::ethereum(),
176 )
177 );
178 }
179 }
180
181 #[test]
182 fn calculate_optimism_sepolia_base_fee_success() {
183 let base_fee = [
184 1000000000, 1000000000, 1000000000, 1072671875, 1059263476, 1049238967, 1049238967, 0,
185 1, 2,
186 ];
187 let gas_used = [
188 10000000, 10000000, 10000000, 9000000, 10001000, 0, 10000000, 10000000, 10000000,
189 10000000,
190 ];
191 let gas_limit = [
192 10000000, 12000000, 14000000, 10000000, 14000000, 2000000, 18000000, 18000000,
193 18000000, 18000000,
194 ];
195 let next_base_fee = [
196 1100000048, 1080000000, 1065714297, 1167067046, 1128881311, 1028254188, 1098203452, 1,
197 2, 3,
198 ];
199
200 for i in 0..base_fee.len() {
201 assert_eq!(
202 next_base_fee[i],
203 calc_next_block_base_fee(
204 gas_used[i],
205 gas_limit[i],
206 base_fee[i],
207 BaseFeeParams::optimism_sepolia(),
208 )
209 );
210 }
211 }
212
213 #[test]
214 fn calculate_optimism_base_fee_success() {
215 let base_fee = [
216 1000000000, 1000000000, 1000000000, 1072671875, 1059263476, 1049238967, 1049238967, 0,
217 1, 2,
218 ];
219 let gas_used = [
220 10000000, 10000000, 10000000, 9000000, 10001000, 0, 10000000, 10000000, 10000000,
221 10000000,
222 ];
223 let gas_limit = [
224 10000000, 12000000, 14000000, 10000000, 14000000, 2000000, 18000000, 18000000,
225 18000000, 18000000,
226 ];
227 let next_base_fee = [
228 1100000048, 1080000000, 1065714297, 1167067046, 1128881311, 1028254188, 1098203452, 1,
229 2, 3,
230 ];
231
232 for i in 0..base_fee.len() {
233 assert_eq!(
234 next_base_fee[i],
235 calc_next_block_base_fee(
236 gas_used[i],
237 gas_limit[i],
238 base_fee[i],
239 BaseFeeParams::optimism(),
240 )
241 );
242 }
243 }
244
245 #[test]
246 fn calculate_optimism_canyon_base_fee_success() {
247 let base_fee = [
248 1000000000, 1000000000, 1000000000, 1072671875, 1059263476, 1049238967, 1049238967, 0,
249 1, 2,
250 ];
251 let gas_used = [
252 10000000, 10000000, 10000000, 9000000, 10001000, 0, 10000000, 10000000, 10000000,
253 10000000,
254 ];
255 let gas_limit = [
256 10000000, 12000000, 14000000, 10000000, 14000000, 2000000, 18000000, 18000000,
257 18000000, 18000000,
258 ];
259 let next_base_fee = [
260 1020000009, 1016000000, 1013142859, 1091550909, 1073187043, 1045042012, 1059031864, 1,
261 2, 3,
262 ];
263
264 for i in 0..base_fee.len() {
265 assert_eq!(
266 next_base_fee[i],
267 calc_next_block_base_fee(
268 gas_used[i],
269 gas_limit[i],
270 base_fee[i],
271 BaseFeeParams::optimism_canyon(),
272 )
273 );
274 }
275 }
276
277 #[test]
278 fn calculate_base_sepolia_base_fee_success() {
279 let base_fee = [
280 1000000000, 1000000000, 1000000000, 1072671875, 1059263476, 1049238967, 1049238967, 0,
281 1, 2,
282 ];
283 let gas_used = [
284 10000000, 10000000, 10000000, 9000000, 10001000, 0, 10000000, 10000000, 10000000,
285 10000000,
286 ];
287 let gas_limit = [
288 10000000, 12000000, 14000000, 10000000, 14000000, 2000000, 18000000, 18000000,
289 18000000, 18000000,
290 ];
291 let next_base_fee = [
292 1180000000, 1146666666, 1122857142, 1244299375, 1189416692, 1028254188, 1144836295, 1,
293 2, 3,
294 ];
295
296 for i in 0..base_fee.len() {
297 assert_eq!(
298 next_base_fee[i],
299 calc_next_block_base_fee(
300 gas_used[i],
301 gas_limit[i],
302 base_fee[i],
303 BaseFeeParams::base_sepolia(),
304 )
305 );
306 }
307 }
308}