revm_primitives/eip8038.rs
1//! EIP-8038: State-Access Gas Cost Update
2//!
3//! Increases the gas cost of state-access operations to reflect Ethereum's
4//! larger state. The values below are the parameters proposed in
5//! [ethereum/EIPs#11802](https://github.com/ethereum/EIPs/pull/11802) (still a
6//! draft — treat as preliminary), superseding the earlier `previous_value + 1`
7//! placeholders.
8//!
9//! Active alongside EIP-7904 and EIP-8037 starting at the Amsterdam hardfork.
10
11/// Cold touch of an account (was 2,600 pre-EIP-8038).
12pub const COLD_ACCOUNT_ACCESS: u64 = 3_000;
13
14/// Surcharge for writing to an account that changes one account leaf value for
15/// the first time (was 6,700 pre-EIP-8038).
16pub const ACCOUNT_WRITE: u64 = 8_000;
17
18/// Cold touch of a storage slot (was 2,100 pre-EIP-8038).
19pub const COLD_STORAGE_ACCESS: u64 = 3_000;
20
21/// Surcharge for writing to a storage slot that changes its value for the
22/// first time (was 2,800 pre-EIP-8038).
23pub const STORAGE_WRITE: u64 = 10_000;
24
25/// Touch of an already-warm account or storage slot. Unchanged by EIP-8038.
26pub const WARM_ACCESS: u64 = 100;
27
28/// Refund for clearing a storage slot (was 4,800 pre-EIP-8038).
29///
30/// Derived per the spec as `(STORAGE_WRITE + COLD_STORAGE_ACCESS) * 4800 / 5000`.
31pub const STORAGE_CLEAR_REFUND: u64 = (STORAGE_WRITE + COLD_STORAGE_ACCESS) * 4_800 / 5_000;
32
33/// State access cost for contract deployment (was 7,000 pre-EIP-8038).
34///
35/// Per the spec, `CREATE_ACCESS = ACCOUNT_WRITE + COLD_STORAGE_ACCESS`. This does
36/// not match the legacy decomposition (`GAS_CREATE - GAS_NEW_ACCOUNT = 7,000`); the
37/// EIP keeps that discrepancy rather than reconciling it.
38pub const CREATE_ACCESS: u64 = ACCOUNT_WRITE + COLD_STORAGE_ACCESS;
39
40/// Gas charged per storage key included in a transaction's access list
41/// (was 1,900 pre-EIP-8038). Derived per the spec as `COLD_STORAGE_ACCESS`.
42pub const ACCESS_LIST_STORAGE_KEY_COST: u64 = COLD_STORAGE_ACCESS;
43
44/// Gas charged per address included in a transaction's access list
45/// (was 2,400 pre-EIP-8038). Derived per the spec as `COLD_ACCOUNT_ACCESS`.
46pub const ACCESS_LIST_ADDRESS_COST: u64 = COLD_ACCOUNT_ACCESS;
47
48/// Cold premium on top of `WARM_ACCESS` for account access.
49pub const COLD_ACCOUNT_ACCESS_ADDITIONAL: u64 = COLD_ACCOUNT_ACCESS - WARM_ACCESS;
50
51/// Cold premium on top of `WARM_ACCESS` for storage access.
52pub const COLD_STORAGE_ACCESS_ADDITIONAL: u64 = COLD_STORAGE_ACCESS - WARM_ACCESS;
53
54/// CALL value transfer cost: `ACCOUNT_WRITE + CALL_STIPEND` per the EIP.
55pub const CALL_VALUE: u64 = ACCOUNT_WRITE + 2_300;
56
57/// Calldata bytes charged for one EIP-7702 authorization tuple (execution-specs
58/// `AUTH_TUPLE_BYTES`): chain id, authority address, nonce, signature parity, and
59/// the two signature scalars. Charged at the calldata floor rate.
60pub const EIP7702_AUTH_TUPLE_BYTES: u64 = 101;
61
62/// ecRecover precompile base cost, charged once per EIP-7702 authorization to
63/// recover the authority.
64pub const EIP7702_ECRECOVER_COST: u64 = 3_000;
65
66/// Calldata floor rate per token under EIP-7976 (Amsterdam).
67pub const TX_DATA_TOKEN_FLOOR: u64 = 16;
68
69/// Regular-gas portion of EIP-7702 `PER_EMPTY_ACCOUNT_COST` under EIP-8038.
70///
71/// Per execution-specs, the regular per-auth charge is
72/// `ACCOUNT_WRITE + REGULAR_PER_AUTH_BASE_COST`, where
73/// `REGULAR_PER_AUTH_BASE_COST = AUTH_TUPLE_BYTES * TX_DATA_TOKEN_FLOOR + PRECOMPILE_ECRECOVER + COLD_ACCOUNT_ACCESS + 2 * WARM_ACCESS`.
74/// Evaluates to `8,000 + (101*16 + 3,000 + 3,000 + 200) = 8,000 + 7,816 = 15,816`.
75/// (The per-auth state gas — `NEW_ACCOUNT + AUTH_BASE` — is charged separately.)
76pub const EIP7702_PER_EMPTY_ACCOUNT_REGULAR: u64 = ACCOUNT_WRITE
77 + (EIP7702_AUTH_TUPLE_BYTES * TX_DATA_TOKEN_FLOOR
78 + EIP7702_ECRECOVER_COST
79 + COLD_ACCOUNT_ACCESS
80 + 2 * WARM_ACCESS);
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85
86 /// Values must match the parameters table in ethereum/EIPs#11802.
87 #[test]
88 fn constants_match_spec() {
89 assert_eq!(WARM_ACCESS, 100); // unchanged by EIP-8038
90 assert_eq!(COLD_ACCOUNT_ACCESS, 3_000);
91 assert_eq!(ACCOUNT_WRITE, 8_000);
92 assert_eq!(COLD_STORAGE_ACCESS, 3_000);
93 assert_eq!(STORAGE_WRITE, 10_000);
94 assert_eq!(STORAGE_CLEAR_REFUND, 12_480);
95 assert_eq!(CREATE_ACCESS, 11_000);
96 assert_eq!(ACCESS_LIST_ADDRESS_COST, 3_000);
97 assert_eq!(ACCESS_LIST_STORAGE_KEY_COST, 3_000);
98 assert_eq!(CALL_VALUE, 10_300);
99 assert_eq!(EIP7702_PER_EMPTY_ACCOUNT_REGULAR, 15_816);
100 }
101
102 /// Spec-defined relationships between the parameters (kept as derivations so a
103 /// renumber of one base value propagates correctly).
104 #[test]
105 fn derived_relations() {
106 assert_eq!(CREATE_ACCESS, ACCOUNT_WRITE + COLD_STORAGE_ACCESS);
107 assert_eq!(CALL_VALUE, ACCOUNT_WRITE + 2_300);
108 assert_eq!(ACCESS_LIST_ADDRESS_COST, COLD_ACCOUNT_ACCESS);
109 assert_eq!(ACCESS_LIST_STORAGE_KEY_COST, COLD_STORAGE_ACCESS);
110 assert_eq!(
111 STORAGE_CLEAR_REFUND,
112 (STORAGE_WRITE + COLD_STORAGE_ACCESS) * 4_800 / 5_000
113 );
114 assert_eq!(
115 COLD_ACCOUNT_ACCESS_ADDITIONAL,
116 COLD_ACCOUNT_ACCESS - WARM_ACCESS
117 );
118 assert_eq!(
119 COLD_STORAGE_ACCESS_ADDITIONAL,
120 COLD_STORAGE_ACCESS - WARM_ACCESS
121 );
122 }
123}