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_PER_AUTH_BASE_COST`: the state-independent regular-gas base charged
70/// per EIP-7702 authorization at the intrinsic phase under EIP-2780
71/// (ethereum/EIPs#11844).
72///
73/// `AUTH_TUPLE_BYTES * TX_DATA_TOKEN_FLOOR + PRECOMPILE_ECRECOVER + COLD_ACCOUNT_ACCESS + 2 * WARM_ACCESS`
74/// = `101*16 + 3,000 + 3,000 + 200 = 7,816`. Covers the authorization's calldata,
75/// the ECDSA recovery, the authority's cold access, and the warm writes every
76/// authorization performs. The state-dependent remainder (`ACCOUNT_WRITE` and the
77/// new-account / delegation-bytes state gas) is charged at runtime, only for the
78/// authorities that incur it.
79pub const EIP7702_PER_AUTH_BASE_REGULAR: u64 = EIP7702_AUTH_TUPLE_BYTES * TX_DATA_TOKEN_FLOOR
80 + EIP7702_ECRECOVER_COST
81 + COLD_ACCOUNT_ACCESS
82 + 2 * WARM_ACCESS;
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87
88 /// Values must match the parameters table in ethereum/EIPs#11802.
89 #[test]
90 fn constants_match_spec() {
91 assert_eq!(WARM_ACCESS, 100); // unchanged by EIP-8038
92 assert_eq!(COLD_ACCOUNT_ACCESS, 3_000);
93 assert_eq!(ACCOUNT_WRITE, 8_000);
94 assert_eq!(COLD_STORAGE_ACCESS, 3_000);
95 assert_eq!(STORAGE_WRITE, 10_000);
96 assert_eq!(STORAGE_CLEAR_REFUND, 12_480);
97 assert_eq!(CREATE_ACCESS, 11_000);
98 assert_eq!(ACCESS_LIST_ADDRESS_COST, 3_000);
99 assert_eq!(ACCESS_LIST_STORAGE_KEY_COST, 3_000);
100 assert_eq!(CALL_VALUE, 10_300);
101 assert_eq!(EIP7702_PER_AUTH_BASE_REGULAR, 7_816);
102 }
103
104 /// Spec-defined relationships between the parameters (kept as derivations so a
105 /// renumber of one base value propagates correctly).
106 #[test]
107 fn derived_relations() {
108 assert_eq!(CREATE_ACCESS, ACCOUNT_WRITE + COLD_STORAGE_ACCESS);
109 assert_eq!(CALL_VALUE, ACCOUNT_WRITE + 2_300);
110 assert_eq!(ACCESS_LIST_ADDRESS_COST, COLD_ACCOUNT_ACCESS);
111 assert_eq!(ACCESS_LIST_STORAGE_KEY_COST, COLD_STORAGE_ACCESS);
112 assert_eq!(
113 STORAGE_CLEAR_REFUND,
114 (STORAGE_WRITE + COLD_STORAGE_ACCESS) * 4_800 / 5_000
115 );
116 assert_eq!(
117 COLD_ACCOUNT_ACCESS_ADDITIONAL,
118 COLD_ACCOUNT_ACCESS - WARM_ACCESS
119 );
120 assert_eq!(
121 COLD_STORAGE_ACCESS_ADDITIONAL,
122 COLD_STORAGE_ACCESS - WARM_ACCESS
123 );
124 }
125}