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
18impl Eip1559Estimation {
19 pub const fn scale_by_pct(&mut self, pct: u64) {
29 self.max_fee_per_gas = self.max_fee_per_gas * (100 + pct as u128) / 100;
30 self.max_priority_fee_per_gas = self.max_priority_fee_per_gas * (100 + pct as u128) / 100;
31 }
32
33 pub const fn scaled_by_pct(mut self, pct: u64) -> Self {
35 self.scale_by_pct(pct);
36 self
37 }
38}
39
40pub fn calc_next_block_base_fee(
64 gas_used: u64,
65 gas_limit: u64,
66 base_fee: u64,
67 base_fee_params: BaseFeeParams,
68) -> u64 {
69 let gas_target = gas_limit / base_fee_params.elasticity_multiplier as u64;
71
72 match gas_used.cmp(&gas_target) {
73 core::cmp::Ordering::Equal => base_fee,
76 core::cmp::Ordering::Greater => {
79 base_fee
81 + (core::cmp::max(
82 1,
84 base_fee as u128 * (gas_used - gas_target) as u128
85 / (gas_target as u128 * base_fee_params.max_change_denominator),
86 ) as u64)
87 }
88 core::cmp::Ordering::Less => {
91 base_fee.saturating_sub(
93 (base_fee as u128 * (gas_target - gas_used) as u128
94 / (gas_target as u128 * base_fee_params.max_change_denominator))
95 as u64,
96 )
97 }
98 }
99}
100
101pub fn calculate_block_gas_limit(parent_gas_limit: u64, desired_gas_limit: u64) -> u64 {
104 let delta = (parent_gas_limit / GAS_LIMIT_BOUND_DIVISOR).saturating_sub(1);
105 let min_gas_limit = parent_gas_limit - delta;
106 let max_gas_limit = parent_gas_limit + delta;
107 desired_gas_limit.clamp(min_gas_limit, max_gas_limit)
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113 use crate::eip1559::constants::{MIN_PROTOCOL_BASE_FEE, MIN_PROTOCOL_BASE_FEE_U256};
114
115 #[test]
116 fn min_protocol_sanity() {
117 assert_eq!(MIN_PROTOCOL_BASE_FEE_U256.to::<u64>(), MIN_PROTOCOL_BASE_FEE);
118 }
119
120 #[test]
121 fn calculate_base_fee_success() {
122 let base_fee = [
123 1000000000, 1000000000, 1000000000, 1072671875, 1059263476, 1049238967, 1049238967, 0,
124 1, 2,
125 ];
126 let gas_used = [
127 10000000, 10000000, 10000000, 9000000, 10001000, 0, 10000000, 10000000, 10000000,
128 10000000,
129 ];
130 let gas_limit = [
131 10000000, 12000000, 14000000, 10000000, 14000000, 2000000, 18000000, 18000000,
132 18000000, 18000000,
133 ];
134 let next_base_fee = [
135 1125000000, 1083333333, 1053571428, 1179939062, 1116028649, 918084097, 1063811730, 1,
136 2, 3,
137 ];
138
139 for i in 0..base_fee.len() {
140 assert_eq!(
141 next_base_fee[i],
142 calc_next_block_base_fee(
143 gas_used[i],
144 gas_limit[i],
145 base_fee[i],
146 BaseFeeParams::ethereum(),
147 )
148 );
149 }
150 }
151
152 #[test]
153 fn calculate_optimism_sepolia_base_fee_success() {
154 let base_fee = [
155 1000000000, 1000000000, 1000000000, 1072671875, 1059263476, 1049238967, 1049238967, 0,
156 1, 2,
157 ];
158 let gas_used = [
159 10000000, 10000000, 10000000, 9000000, 10001000, 0, 10000000, 10000000, 10000000,
160 10000000,
161 ];
162 let gas_limit = [
163 10000000, 12000000, 14000000, 10000000, 14000000, 2000000, 18000000, 18000000,
164 18000000, 18000000,
165 ];
166 let next_base_fee = [
167 1100000048, 1080000000, 1065714297, 1167067046, 1128881311, 1028254188, 1098203452, 1,
168 2, 3,
169 ];
170
171 for i in 0..base_fee.len() {
172 assert_eq!(
173 next_base_fee[i],
174 calc_next_block_base_fee(
175 gas_used[i],
176 gas_limit[i],
177 base_fee[i],
178 BaseFeeParams::optimism_sepolia(),
179 )
180 );
181 }
182 }
183
184 #[test]
185 fn calculate_optimism_base_fee_success() {
186 let base_fee = [
187 1000000000, 1000000000, 1000000000, 1072671875, 1059263476, 1049238967, 1049238967, 0,
188 1, 2,
189 ];
190 let gas_used = [
191 10000000, 10000000, 10000000, 9000000, 10001000, 0, 10000000, 10000000, 10000000,
192 10000000,
193 ];
194 let gas_limit = [
195 10000000, 12000000, 14000000, 10000000, 14000000, 2000000, 18000000, 18000000,
196 18000000, 18000000,
197 ];
198 let next_base_fee = [
199 1100000048, 1080000000, 1065714297, 1167067046, 1128881311, 1028254188, 1098203452, 1,
200 2, 3,
201 ];
202
203 for i in 0..base_fee.len() {
204 assert_eq!(
205 next_base_fee[i],
206 calc_next_block_base_fee(
207 gas_used[i],
208 gas_limit[i],
209 base_fee[i],
210 BaseFeeParams::optimism(),
211 )
212 );
213 }
214 }
215
216 #[test]
217 fn calculate_optimism_canyon_base_fee_success() {
218 let base_fee = [
219 1000000000, 1000000000, 1000000000, 1072671875, 1059263476, 1049238967, 1049238967, 0,
220 1, 2,
221 ];
222 let gas_used = [
223 10000000, 10000000, 10000000, 9000000, 10001000, 0, 10000000, 10000000, 10000000,
224 10000000,
225 ];
226 let gas_limit = [
227 10000000, 12000000, 14000000, 10000000, 14000000, 2000000, 18000000, 18000000,
228 18000000, 18000000,
229 ];
230 let next_base_fee = [
231 1020000009, 1016000000, 1013142859, 1091550909, 1073187043, 1045042012, 1059031864, 1,
232 2, 3,
233 ];
234
235 for i in 0..base_fee.len() {
236 assert_eq!(
237 next_base_fee[i],
238 calc_next_block_base_fee(
239 gas_used[i],
240 gas_limit[i],
241 base_fee[i],
242 BaseFeeParams::optimism_canyon(),
243 )
244 );
245 }
246 }
247
248 #[test]
249 fn calculate_base_sepolia_base_fee_success() {
250 let base_fee = [
251 1000000000, 1000000000, 1000000000, 1072671875, 1059263476, 1049238967, 1049238967, 0,
252 1, 2,
253 ];
254 let gas_used = [
255 10000000, 10000000, 10000000, 9000000, 10001000, 0, 10000000, 10000000, 10000000,
256 10000000,
257 ];
258 let gas_limit = [
259 10000000, 12000000, 14000000, 10000000, 14000000, 2000000, 18000000, 18000000,
260 18000000, 18000000,
261 ];
262 let next_base_fee = [
263 1180000000, 1146666666, 1122857142, 1244299375, 1189416692, 1028254188, 1144836295, 1,
264 2, 3,
265 ];
266
267 for i in 0..base_fee.len() {
268 assert_eq!(
269 next_base_fee[i],
270 calc_next_block_base_fee(
271 gas_used[i],
272 gas_limit[i],
273 base_fee[i],
274 BaseFeeParams::base_sepolia(),
275 )
276 );
277 }
278 }
279}