1use auto_impl::auto_impl;
2use revm::context_interface::cfg::{GasId, GasParams};
3use tempo_chainspec::hardfork::TempoHardfork;
4
5#[auto_impl(&, Arc, Box, &mut)]
7pub trait TempoGasParams {
8 fn gas_params(&self) -> &GasParams;
9
10 fn tx_tip1000_auth_account_creation_cost(&self) -> u64 {
11 self.gas_params().get(GasId::new(255))
12 }
13
14 fn tx_tip1000_auth_account_creation_state_gas(&self) -> u64 {
15 self.gas_params().get(GasId::new(254))
16 }
17}
18
19impl TempoGasParams for GasParams {
20 fn gas_params(&self) -> &GasParams {
21 self
22 }
23}
24
25const SSTORE_SET_COST: u64 = 250_000;
27const CREATE_COST: u64 = 500_000;
28const NEW_ACCOUNT_COST: u64 = 250_000;
29const CODE_DEPOSIT_COST_T1: u64 = 1_000;
30const AUTH_ACCOUNT_CREATION_COST: u64 = 250_000;
31const EIP7702_PER_EMPTY_ACCOUNT_COST_T1: u64 = 12_500;
32
33const T4_SSTORE_SET_REGULAR: u64 = 20_000;
39const T4_NEW_ACCOUNT_REGULAR: u64 = 25_000;
40const T4_CREATE_REGULAR: u64 = 32_000;
41const T4_CODE_DEPOSIT_REGULAR: u64 = 200;
42const T4_EIP7702_PER_AUTH_TOTAL: u64 = 250_000; const T4_SSTORE_SET_STATE: u64 = SSTORE_SET_COST - T4_SSTORE_SET_REGULAR; const T4_NEW_ACCOUNT_STATE: u64 = NEW_ACCOUNT_COST - T4_NEW_ACCOUNT_REGULAR; const T4_CREATE_STATE: u64 = CREATE_COST - T4_CREATE_REGULAR; const T4_CODE_DEPOSIT_STATE: u64 = 2_300;
49
50const T4_SSTORE_SET_REFUND: u64 = T4_SSTORE_SET_STATE + 17_800; #[inline]
61pub fn tempo_gas_params_with_amsterdam(
62 spec: TempoHardfork,
63 amsterdam_eip8037_enabled: bool,
64) -> GasParams {
65 let mut gas_params = GasParams::new_spec(spec.into());
66 let mut overrides = vec![];
67 if amsterdam_eip8037_enabled {
68 overrides.extend([
72 (GasId::sstore_set_without_load_cost(), T4_SSTORE_SET_REGULAR),
74 (GasId::sstore_set_state_gas(), T4_SSTORE_SET_STATE),
75 (GasId::sstore_set_refund(), T4_SSTORE_SET_REFUND),
76 (GasId::tx_create_cost(), T4_CREATE_REGULAR),
78 (GasId::create(), T4_CREATE_REGULAR),
79 (GasId::create_state_gas(), T4_CREATE_STATE),
80 (GasId::new_account_cost(), T4_NEW_ACCOUNT_REGULAR),
82 (GasId::new_account_state_gas(), T4_NEW_ACCOUNT_STATE),
83 (
84 GasId::new_account_cost_for_selfdestruct(),
85 T4_NEW_ACCOUNT_REGULAR,
86 ),
87 (GasId::code_deposit_cost(), T4_CODE_DEPOSIT_REGULAR),
89 (GasId::code_deposit_state_gas(), T4_CODE_DEPOSIT_STATE),
90 (
92 GasId::tx_eip7702_per_empty_account_cost(),
93 T4_EIP7702_PER_AUTH_TOTAL,
94 ),
95 (
96 GasId::tx_eip7702_per_auth_state_gas(),
97 T4_NEW_ACCOUNT_STATE, ),
99 (GasId::tx_eip7702_auth_refund(), 0),
103 (GasId::new(255), T4_NEW_ACCOUNT_REGULAR),
105 (GasId::new(254), T4_NEW_ACCOUNT_STATE),
106 ]);
107 } else if spec.is_t1() {
108 overrides.extend([
110 (GasId::sstore_set_without_load_cost(), SSTORE_SET_COST),
111 (GasId::tx_create_cost(), CREATE_COST),
112 (GasId::create(), CREATE_COST),
113 (GasId::new_account_cost(), NEW_ACCOUNT_COST),
114 (GasId::new_account_cost_for_selfdestruct(), NEW_ACCOUNT_COST),
115 (GasId::code_deposit_cost(), CODE_DEPOSIT_COST_T1),
116 (
117 GasId::tx_eip7702_per_empty_account_cost(),
118 EIP7702_PER_EMPTY_ACCOUNT_COST_T1,
119 ),
120 (GasId::new(255), AUTH_ACCOUNT_CREATION_COST),
121 ]);
122 }
123
124 gas_params.override_gas(overrides);
125 gas_params
126}
127
128#[inline]
133pub fn tempo_gas_params(spec: TempoHardfork) -> GasParams {
134 tempo_gas_params_with_amsterdam(spec, false)
135}
136
137#[cfg(test)]
138mod tests {
139 use super::*;
140
141 #[test]
142 fn test_t1_gas_params_no_state_gas_split() {
143 let gas_params = tempo_gas_params_with_amsterdam(TempoHardfork::T1, false);
144
145 assert_eq!(
147 gas_params.get(GasId::sstore_set_without_load_cost()),
148 250_000
149 );
150 assert_eq!(gas_params.get(GasId::new_account_cost()), 250_000);
151 assert_eq!(gas_params.get(GasId::tx_create_cost()), 500_000);
152 assert_eq!(gas_params.get(GasId::create()), 500_000);
153 assert_eq!(gas_params.get(GasId::code_deposit_cost()), 1_000);
154
155 let upstream = GasParams::new_spec(TempoHardfork::T1.into());
157 assert_eq!(
158 gas_params.get(GasId::sstore_set_state_gas()),
159 upstream.get(GasId::sstore_set_state_gas()),
160 "T1 should not override state gas params"
161 );
162 assert_eq!(
163 gas_params.get(GasId::new_account_state_gas()),
164 upstream.get(GasId::new_account_state_gas()),
165 );
166 assert_eq!(
167 gas_params.get(GasId::create_state_gas()),
168 upstream.get(GasId::create_state_gas()),
169 );
170 }
171
172 #[test]
186 fn test_t4_gas_params_splits_storage_costs() {
187 let gas_params = tempo_gas_params_with_amsterdam(TempoHardfork::T4, true);
188
189 assert_eq!(
193 gas_params.get(GasId::sstore_set_without_load_cost()),
194 20_000,
195 "SSTORE set_without_load matches the retained zero->non-zero write component"
196 );
197 assert_eq!(
198 gas_params.get(GasId::new_account_cost()),
199 25_000,
200 "Account creation regular gas per spec"
201 );
202 assert_eq!(
203 gas_params.get(GasId::new_account_cost_for_selfdestruct()),
204 25_000
205 );
206 assert_eq!(
207 gas_params.get(GasId::tx_create_cost()),
208 32_000,
209 "CREATE base regular gas per spec"
210 );
211 assert_eq!(
212 gas_params.get(GasId::create()),
213 32_000,
214 "CREATE base regular gas per spec"
215 );
216 assert_eq!(gas_params.get(GasId::code_deposit_cost()), 200);
217
218 assert_eq!(
220 gas_params.get(GasId::sstore_set_state_gas()),
221 230_000,
222 "SSTORE state gas per spec"
223 );
224 assert_eq!(
225 gas_params.get(GasId::new_account_state_gas()),
226 225_000,
227 "Account creation state gas per spec"
228 );
229 assert_eq!(
230 gas_params.get(GasId::create_state_gas()),
231 468_000,
232 "CREATE base state gas per spec"
233 );
234 assert_eq!(gas_params.get(GasId::code_deposit_state_gas()), 2_300);
235
236 assert_eq!(
238 gas_params.get(GasId::new(255)),
239 25_000,
240 "Auth account creation regular gas per spec"
241 );
242 assert_eq!(
243 gas_params.get(GasId::new(254)),
244 225_000,
245 "Auth account creation state gas per spec"
246 );
247
248 assert_eq!(
250 gas_params.get(GasId::tx_eip7702_per_empty_account_cost()),
251 250_000,
252 "EIP-7702 per auth total = 25k regular + 225k state per spec"
253 );
254 assert_eq!(
255 gas_params.tx_eip7702_per_auth_state_gas(),
256 225_000,
257 "EIP-7702 per auth state gas per spec"
258 );
259 assert_eq!(
260 gas_params.tx_eip7702_per_empty_account_cost()
261 - gas_params.tx_eip7702_per_auth_state_gas(),
262 25_000,
263 "EIP-7702 per auth regular gas = total - state = 25k"
264 );
265 assert_eq!(
266 gas_params.tx_eip7702_auth_refund(),
267 0,
268 "TIP-1000: no refund for existing accounts on T1+"
269 );
270
271 assert_eq!(
274 gas_params.get(GasId::sstore_set_refund()),
275 247_800,
276 "SSTORE set refund = state(230k) + regular(17.8k) per spec"
277 );
278 }
279
280 #[test]
287 fn test_t4_totals_match_spec() {
288 let t4 = tempo_gas_params_with_amsterdam(TempoHardfork::T4, true);
289
290 let warm_sstore_regular =
292 t4.get(GasId::sstore_set_without_load_cost()) + t4.warm_storage_read_cost();
293 assert_eq!(
294 warm_sstore_regular + t4.get(GasId::sstore_set_state_gas()),
295 250_100,
296 "warm SSTORE total must be 250,100"
297 );
298
299 let cold_sstore_regular = warm_sstore_regular + t4.cold_storage_cost();
301 assert_eq!(
302 cold_sstore_regular + t4.get(GasId::sstore_set_state_gas()),
303 252_200,
304 "cold SSTORE total must include Berlin cold slot access charging"
305 );
306
307 assert_eq!(
309 t4.get(GasId::new_account_cost()) + t4.get(GasId::new_account_state_gas()),
310 250_000,
311 "new_account total must be 250,000"
312 );
313
314 assert_eq!(
316 t4.get(GasId::create()) + t4.get(GasId::create_state_gas()),
317 500_000,
318 "CREATE total must be 500,000"
319 );
320
321 assert_eq!(
323 t4.get(GasId::code_deposit_cost()) + t4.get(GasId::code_deposit_state_gas()),
324 2_500,
325 "code_deposit total must be 2,500/byte"
326 );
327
328 assert_eq!(
330 t4.get(GasId::new(255)) + t4.get(GasId::new(254)),
331 250_000,
332 "auth_account_creation total must be 250,000"
333 );
334
335 assert_eq!(
337 (t4.tx_eip7702_per_empty_account_cost() - t4.tx_eip7702_per_auth_state_gas())
338 + t4.tx_eip7702_per_auth_state_gas(),
339 250_000,
340 "EIP-7702 per auth total must be 250,000"
341 );
342 }
343}