Annotated EIP-8037 · design rationale walkthrough
Core · Standards Track · Draft

State Creation Gas Cost Increase

A guided, annotated reading of EIP-8037 — why Ethereum proposes to make new state expensive, meter it on its own axis, and how that quietly unblocks raising the block gas limit.

EIP 8037 Status Draft Created 2025-10-01 Category Core Requires 2780 · 6780 · 7623 · 7702 · 7825 · 7904 · 7928 · 7976 · 7981 · 8038
📄 Canonical EIP ↗ 💬 Magicians discussion ↗ 🔬 ethresear.ch: two-resource equations ↗

How to read this page

This is EIP-8037 with a commentary track. The proposal is dense and assumes you already hold a stack of other EIPs in your head — so each idea is shown twice.

◀ Specification (left / blue)

The blue panels reproduce or faithfully paraphrase what EIP-8037 actually says — the parameters, formulas, tables, and rules. Numbers and code here match the EIP.

💡 Annotation (right / teal)

The teal panels are commentary: why the rule exists, what problem it solves, which other EIP it leans on, and where each magic number comes from.

References to other proposals look like EIP-8011 and link to the canonical text. Three widgets let you turn the dials yourself: a CPSB derivation, a cost calculator, and a reservoir model. Everything runs locally — no network needed.

The big picture

Before the details: hold these three sentences in your head and the whole EIP falls into place.

1 · State growth is the thing that breaks when you raise the gas limit. Compute and bandwidth are transient — they cost a node for one block and are gone. New state (accounts, storage slots, contract code) is forever: every full node must keep it on disk and pay to traverse it on every future block. Raising the block gas limit to scale throughput pours fuel on state growth. So state growth must be priced high enough that scaling the limit doesn't bury node operators.
2 · Today, creating state is mispriced and inconsistent. The same byte of new state costs wildly different amounts depending on how you create it — ~200 gas/byte to deploy code, ~313 gas/byte to fill a storage slot. EIP-8037 picks one number, CPSB = 1530 gas per state byte, and charges every state-creating operation bytes_created × CPSB.
3 · Make state its own resource so the price hike doesn't strangle everything else. If you just raised these costs inside the single gas counter, expensive state would eat the budget for ordinary compute, and the per-transaction gas cap (EIP-7825) would cap contract deployments at ~7.5 kB. So EIP-8037 splits gas into two dimensions — regular-gas and state-gas — metered independently at the block level (the EIP-8011 idea), and lets state-gas escape the per-tx cap via a "reservoir."

scale L1 raise block gas limit state grows faster nodes hit the disk wall EIP-8037: price & meter state

How the pieces fit

EIP-8037 sits at the center of a cluster of "make-Ethereum-scale-safely" proposals. It requires ten of them. Here they are, grouped by the role they play in 8037's design.

Metering foundation Companion repricing Block-size / throughput levers Account & state model System contracts
🧱 The metering foundation

The framework EIP-8037 instantiates and the charging model it borrows.

  • EIP-8011 Multidimensional Gas Metering.Gives gas a 6-component cost vector and meters each block by its bottleneck resource. 8037 is the first concrete instance: it activates the state dimension.
  • EIP-7928 Block-Level Access Lists.Splits state-opcode gas into pre-state (no DB needed) and post-state (needs a read) phases. 8037 reuses this two-phase model to decide when state-gas is charged.
🤝 The companion

The other half of the repricing; they cross-reference each other.

  • EIP-8038 State-access Gas Cost Update.8037 prices state creation; 8038 prices state access (reads/writes to existing state). 8038 defines the regular-gas surcharges (ACCOUNT_WRITE, CREATE_ACCESS, COLD_ACCOUNT_ACCESS) that ride alongside 8037's state-gas charges.
📦 Block-size & throughput levers

The sibling EIPs that make room to raise the gas limit. 8037 is the state-growth lever in this family.

  • EIP-7825 Transaction Gas Limit Cap (2²⁴).Caps any tx at 16,777,216 gas. 8037 must work around this cap (see the reservoir) so deployments stay possible.
  • EIP-7904 Compute Gas Cost Increase.Reprices underpriced compute opcodes/precompiles. Supplies the updated PRECOMPILE_ECRECOVER used in 8037's auth-cost math.
  • EIP-7623 Increase Calldata Cost.Introduces the calldata floor. 8037's final tx_gas_used applies this floor after refunds.
  • EIP-7976 Increase Calldata Floor Cost (64/64).Raises the 7623 floor further. Part of the same shrink-the-worst-case-block program.
  • EIP-7981 Increase Access List Cost.Charges access-list data so it can't dodge the calldata floor. Same family.
  • EIP-7778 Block Gas Accounting without Refunds.Stops refunds from letting a block exceed its real compute budget. 8037 specifies how its two-dimensional accounting composes with 7778.
👤 Account & state model

The rules that define what counts as new state — and a mispricing 8037 must patch.

  • EIP-7702 Set Code for EOAs.A new state-creation vector: writing a 23-byte 0xef0100‖addr delegation. 8037 must meter it, hence STATE_BYTES_PER_AUTH_BASE = 23.
  • EIP-6780 SELFDESTRUCT only in same tx.Determines when an account is actually removed from state — which determines when state-gas should (not) be refilled.
  • EIP-2780 Reduce intrinsic transaction gas.Fixes the mispricing 8037 creates: a value-transfer to a fresh account would be far cheaper than the new-account charge, so 2780 adds the surcharge back at the intrinsic level.
  • EIP-161 State trie clearing.The canonical definition of an "empty"/"existent" account that 8037 uses to decide if a leaf is new.
  • EIP-684 Revert on creation collision.Defines valid CREATE/CREATE2 targets — e.g. an address with balance but no code is a valid target whose leaf already exists.
  • EIP-170 Contract code size limit (24,576 B).The 24 kB ceiling used in 8037's "deploy a max-size contract" cost examples.
⚙️ System contracts

Protocol-invoked contracts that write storage every block — 8037 raises their system-call gas limit so they don't break.

  • EIP-2935 Historical block hashes in state.
  • EIP-4788 Beacon block root in the EVM.
  • EIP-7002 EL-triggerable withdrawals.Supplies MAX_WITHDRAWAL_REQUESTS_PER_BLOCK = 16, reused as SYSTEM_MAX_SSTORES_PER_CALL.
  • EIP-7251 Increase MAX_EFFECTIVE_BALANCE (consolidations).

§Abstract

EIP-8037 · Abstract

This proposal increases the cost of state creation operations, thus avoiding excessive state growth under increased block gas limits. It introduces a new variable, CPSB (cost per state byte), and sets this unit of gas cost per new state byte by targeting an average state growth of 120 GiB per year at a reference block gas limit of 150M gas units.

It also introduces an independent metering for state creation costs, thus allowing for increased throughput and for larger contract deployments without being limited by the single transaction gas limit.

💡 Two ideas, bundled

The abstract quietly contains both halves of the EIP:

  • A price. One unit — CPSB — derived from a policy target ("don't grow state faster than 120 GiB/yr at a 150M limit"). Everything that makes state is charged in multiples of it.
  • A meter. State creation gets its own gas dimension, so the price can be cranked up without shrinking the budget for compute — and so the EIP-7825 per-tx cap stops blocking large deployments.

"Average state growth" and "reference gas limit" are the tell that CPSB is a policy knob, not a measured constant — unlike the benchmark-derived numbers in EIP-8038 / EIP-7904.

§Motivation

Two distinct problems: (a) state creation is priced inconsistently, and (b) under higher gas limits, unbounded state growth becomes the binding constraint on the whole network.

EIP-8037 · Motivation — mispricing

State creation does not have a harmonized cost. Contract deployment costs only ~200 gas/byte created, while new storage slots cost ~313 gas/byte. Deploying duplicated bytecode costs the same as new bytecode, even though clients don't store duplicated code in the database.

💡 The same byte, different prices

Gas is supposed to track real cost to a node. But a byte that lands in the state trie costs a node the same regardless of which opcode put it there. The pre-8037 schedule charges by opcode (a 20k flat SSTORE, a 200/byte code deposit) rather than by bytes-of-state, so identical disk impact carries different prices. EIP-8037's fix is to price the byte, not the opcode.

EIP-8037 · Motivation — the growth wall

As of January 2026, a Geth node's state DB is ~390 GiB. After the gas limit went 30M → 60M, average new state per day more than tripled (~105 MiB → ~326 MiB), i.e. ~116 GiB/year.

The response is not linear: a 2× limit bump produced a ~3× jump in daily new state. Extrapolating to a 200M limit gives ~387 GiB/year — which from 390 GiB breaches the 650 GiB performance-degradation threshold in under a year.

💡 Why this is urgent, not theoretical

The scary part is the super-linear response. Naively you'd assume 2× the gas → 2× the state. Reality was ~3×, because cheap state invites behavior that wasn't worth it before. So as the community pushes toward 150M–300M to scale L1, the state-growth curve bends upward faster than the limit does.

650 GiB is the soft wall where ordinary nodes start to degrade — and degraded nodes mean fewer people can run them, which is a decentralization problem, not just a UX one. This is the same scaling-safety program as 7825, 7623, 7904 — each removes one bottleneck that would otherwise cap the gas limit.

Chart: new state added per day, showing the jump after the 30M→60M gas limit increase
From EIP-8037: daily new state added. The step-change after the 30M → 60M limit increase is the empirical core of the motivation.

§New parameters

EIP-8037 · New parameters
ParameterValue
CPSB1530
STATE_BYTES_PER_STORAGE_SET64
STATE_BYTES_PER_NEW_ACCOUNT120
STATE_BYTES_PER_AUTH_BASE23
SYSTEM_MAX_SSTORES_PER_CALL16
💡 Where each number comes from
  • CPSB = 1530 — gas charged per byte of new state. Derived from the 120 GiB/yr @ 150M policy target →
  • 64 — on-disk bytes for a new storage slot: 32-byte key hash + 32-byte value. Breakdown →
  • 120 — on-disk bytes for a new account leaf (key + nonce + balance + codeHash + storageRoot).
  • 23 — bytes for a 7702 delegation: 0xef0100 (3) + address (20).
  • 16 — borrowed from 7002's MAX_WITHDRAWAL_REQUESTS_PER_BLOCK; the most storage writes any system call is expected to do. Used here →

Notice the pattern: a state op's state-gas is always bytes × CPSB. The three "bytes" constants are the only per-op variation.

§Parameter changes

Every state-creating cost is re-expressed as bytes × CPSB charged to state-gas, plus a separate regular-gas charge for the transient work (hashing, account touch). The split is the whole point.

EIP-8037 · Parameter changes (state-gas | regular-gas)
ParameterCurrentNew state-gasNew regular-gasOps
GAS_CREATE32,000120 × CPSBCREATE_ACCESSCREATE(2)
GAS_CODE_DEPOSIT200/byteCPSB /byte6 × ceil(len/32)CREATE(2)
GAS_NEW_ACCOUNT25,000120 × CPSB0CALL, SELFDESTRUCT
GAS_STORAGE_SET20,00064 × CPSB0SSTORE
PER_EMPTY_ACCOUNT_COST25,000120 × CPSBACCOUNT_WRITE7702 deleg.
PER_AUTH_BASE_COST12,50023 × CPSBREGULAR_PER_AUTH_BASE_COST7702 deleg.

CREATE_ACCESS, ACCOUNT_WRITE, COLD_ACCOUNT_ACCESS are defined & valued in EIP-8038 (not yet final). REGULAR_PER_AUTH_BASE_COST = calldata (1,616) + ecRecover + cold account access + 2× warm access.

💡 Read the two right-hand columns as "forever" vs "right now"

This table is the cleanest place to see the dimension split:

  • New state-gas = the permanent cost of the byte sitting in everyone's database forever. Always bytes × CPSB.
  • New regular-gas = the transient work that happens once: hashing the code (6 × ceil(len/32)), touching/writing the account leaf (ACCOUNT_WRITE, CREATE_ACCESS).

Why charge regular-gas at all for a state op? Because writing to disk is real, parallelizable work that belongs on the throughput-metered axis. Only the long-term storage belongs on state-gas. (The Rationale is explicit: "any operation that grows the state should consume both.")

GAS_CODE_DEPOSIT dropping the duplicate-code subsidy and adding a hash cost reflects that clients dedupe identical bytecode — you pay CPSB/byte for the storage but a small hash fee for the compute.

§Multidimensional metering for state creation

EIP-8037 · Two gas dimensions

Two gas dimensions are introduced: regular-gas and state-gas. "New state costs" go to state-gas; "new regular costs" and everything else go to regular-gas.

At the transaction level the user pays for both; the total cost is their sum. The EIP-7825 transaction gas limit applies only to regular-gas; state-gas is capped only by tx.gas.

At the block level, only the gas used in the bottleneck resource counts toward "is the block full?" and the base-fee update. Each of the block gas limit and target now bounds the bottleneck dimension, not a single combined counter.

💡 This is EIP-8011, made concrete

EIP-8011 proposed the abstract machinery: give gas a cost vector, and meter the block by max() over dimensions instead of sum(). 8037 is the first EIP to actually switch one dimension on — state — and leaves the rest collapsed into "regular."

Why max() not sum()? A block is "full" when it would overload the network. Different resources overload independently: a block can be heavy on compute or heavy on new state. Summing them double-penalizes a tx that's heavy on one and light on the other. Metering each axis separately lets the builder pack a compute-heavy tx and a state-heavy tx into the same block — that's the throughput win.

The subtle, powerful consequence: you can raise the state price arbitrarily (to protect disk) and it never steals from the compute budget, because they're now separate axes.

Old: one counter
sum
full when sum ≥ limit
New: two counters, block full at the taller one
limit
regular
state
full when max(regular, state) ≥ limit
The block is bounded by whichever dimension is the bottleneck — so a price hike on state never shrinks the compute budget.

§The reservoir model

A transaction has only one gas field, tx.gas. So how do you cap regular-gas at the 7825 limit while letting state-gas run higher? You split tx.gas into two buckets at the start, and drain them by different rules.

EIP-8037 · Reservoir initialization
intrinsic_gas        = intrinsic_regular_gas + intrinsic_state_gas
execution_gas        = tx.gas - intrinsic_gas
regular_gas_budget   = TX_MAX_GAS_LIMIT - intrinsic_regular_gas
gas_left             = min(regular_gas_budget, execution_gas)
state_gas_reservoir  = execution_gas - gas_left

Charging rules:

  • Regular-gas charges deduct from gas_left only.
  • State-gas charges deduct from state_gas_reservoir first; when empty, from gas_left.
  • Undoing a state creation refills the reservoir.
  • The GAS opcode returns gas_left only — the reservoir is invisible to it.
💡 The trick: overflow goes in the reservoir

gas_left is clamped to at most TX_MAX_GAS_LIMIT − intrinsic_regular_gas. Any gas the user supplied beyond that cap can't be regular-gas — so it lands in state_gas_reservoir, where only state charges can reach it.

This statically enforces "regular-gas ≤ 7825 cap" with a single gas field. Running out of gas_left just looks like ordinary out-of-gas — no new error type. Meanwhile a giant contract deploy can pour, say, 38M of state-gas through the reservoir while its compute stays under the 16.7M cap.

Why hide the reservoir from GAS? Contracts use gasleft() to budget sub-calls; exposing reservoir gas would let a contract accidentally forward state-only gas into a compute context. (This is also the root of the ERC-4337 caveat.)

🪣 Try it — the reservoir split

Set a transaction's gas and its fixed (intrinsic) costs. Watch how tx.gas divides into the capped gas_left and the overflow state_gas_reservoir. TX_MAX_GAS_LIMIT = 16,777,216 (2²⁴), per EIP-7825.

gas_left (regular budget)
state_gas_reservoir
max regular-gas spendable

§Gas accounting for SSTORE

EIP-8037 · SSTORE state-gas (charged at end of opcode)
origcurnewDescriptionState-gas
0x0Cleared slot, zero at tx start64·CPSB refilled
00xNew slot64·CPSB charged
xx0Cleared, non-zero at tx startno adjustment
x0xCleared slot restoredno adjustment
x/0yzAll other writes to existing slotno adjustment
💡 State-gas tracks the leaf, not the write

State-gas is charged exactly when a slot goes from "absent" to "present" in the trie, and refilled when that's undone within the same tx. The guiding question is always: "does a new leaf exist at the end of this transaction?"

  • Row 2 (0→0→x): a genuinely new slot → charge.
  • Row 1 (0→x→0): a slot that was created and then zeroed in the same tx → no net new leaf → refill the charge.
  • Rows 3–5: the slot already existed at tx start (orig ≠ 0) or no creation happened → state size is unchanged → state-gas is untouched. Clearing an old slot is handled by the ordinary regular-gas refund in EIP-8038, not here.

This mirrors the classic EIP-2200 original/current/new state machine — but split so the creation piece lives on the new axis.

§Gas accounting for new accounts

EIP-8037 · New-account state-gas
OperationState-gas charged
CALL* with value → non-existent account120·CPSB
CREATE/CREATE2 size L → existent accountL·CPSB
CREATE/CREATE2 size L → non-existent account(120+L)·CPSB
SELFDESTRUCT transfer creates new account120·CPSB

An account is existent if it already has a leaf in the state trie per EIP-161 (nonzero balance, nonzero nonce, or non-empty code). An address with only a balance is existent and a valid EIP-684 CREATE target — so deploying there charges only L·CPSB.

Charged just before the call frame; refilled if the frame reverts/halts or the op fails before entering (insufficient balance, stack depth).

💡 "Existent" is doing real work here

The whole table reduces to one rule: charge 120·CPSB only if a brand-new account leaf appears, and L·CPSB for the L bytes of code.

The 684/161 distinction is the interesting case: an address that someone pre-funded with ETH (balance, but no code, zero nonce) already has a leaf. Deploying a contract there updates that leaf rather than adding one — so you skip the 120-byte account charge and pay only for the code. The EIP is careful to get this right because counterfactual / pre-funded deployment addresses are common (think CREATE2 factories, smart-wallet deployment).

Charge-then-refill (rather than charge-on-success) keeps metering conservative: the gas must be reserved before the frame runs, so a tx can't sneak in a creation it didn't budget for. If the creation doesn't stick, the reservation comes back.

§SELFDESTRUCT, halts & reverts

EIP-8037 · SELFDESTRUCT refills

For an account created in the same transaction, SELFDESTRUCT removes it (and its data) so it never lands in the trie — but this produces no state-gas refill, and no change to execution_state_gas_used.

For an account that existed before the tx, SELFDESTRUCT only transfers balance and the account is not removed — so no refill. This is consistent with EIP-6780.

💡 Why no refill, even when nothing is left behind?

This looks asymmetric with the SSTORE/CREATE refill rules — and it's deliberate. EIP-6780 already restricts real account deletion to the same-transaction-as-creation case. EIP-8037 chooses not to reward that path with a refill, because offering a refund for create-then-destroy would re-open exactly the kind of gas-refund gaming that 3529 and 7778 spent years closing. You paid to create; the transient work was real; no money back.

EIP-8037 · Halts & reverts

Revert: child-frame state changes roll back; state-gas charged in the child is refunded to the parent's state_gas_reservoir; remaining gas_left returns to the parent — standard EVM semantics. execution_state_gas_used decreases accordingly.

Exceptional halt: the reservoir resets to its value at the start of the child frame (all child state-gas refunded), and the child's gas_left is fully consumed.

Same rules apply at the top frame and for create-tx address collisions.

💡 The reservoir inherits EVM's existing revert discipline

The mental model: state_gas_reservoir behaves like a second gas counter that obeys the same frame semantics gas always has. Revert → unused/charged-but-undone gas flows back up. Exceptional halt (e.g. invalid opcode, out-of-gas) → that frame's allotted gas_left is burned, but state-gas it never committed is still refunded, because the state change it would have caused didn't happen.

Keeping these aligned with existing semantics is what lets clients implement the second dimension without rewriting their call-frame machinery — a recurring design goal across 8011/8037 ("minimal changes to the protocol").

§Accounting for EIP-7702 authorizations

EIP-8037 · 7702 charge-worst-case-then-refund

At intrinsic time, each 7702 authorization is charged the worst-case delegation cost. During processing, per authorization:

  • If the authority's leaf already exists → refill the 120·CPSB portion to the reservoir, and refund the ACCOUNT_WRITE portion.
  • If the authority's codeHash is already a delegation, or the authorization is clearing the delegation (address == 0) → also refill the 23·CPSB portion.

Because execution_state_gas_used starts at 0, these refills can push it negative before any execution charge; implementations may track the refill separately.

💡 You can't know the cost until you look — so assume the worst

A 7702 authorization's true state impact depends on the authority's current on-chain state, which isn't known at intrinsic-gas time (before execution). Two unknowns:

  • Does a fresh account leaf get created? (→ the 120-byte charge)
  • Are the 23 delegation bytes genuinely new, or is the slot already a delegation / being cleared? (→ the 23-byte charge)

The EIP charges the maximum up front (new account + new delegation) and refunds whichever pieces turn out not to apply. This is the same conservative "reserve worst case, refill on discovery" pattern as the new-account rules — it guarantees a tx always pre-pays for the most state it could create.

This mirrors 7702's own structure, where PER_EMPTY_ACCOUNT_COST is charged then partially refunded if the authority already existed — 8037 just re-expresses that refund in the two-dimensional world.

§Pre/post-state validation & block-level accounting

EIP-8037 · Pre/post-state (from EIP-7928)

EIP-7928 defines two-phase validation for state opcodes: pre-state costs (determinable without touching state) and post-state costs (need a state read).

Under 8037, the regular-gas portion follows 7928 unchanged and is charged at opcode time against gas_left. The state-gas portion is computed and deducted at the end of the opcode, drawing from the reservoir first, then gas_left. For SSTORE, the GAS_CALL_STIPEND pre-state check applies to gas_left only.

💡 State-gas is a "post-state" cost by nature

You can't know how much new state an opcode makes until you've read the current state (is the slot empty? does the account exist?). That's exactly 7928's post-state bucket. So 8037 naturally slots state-gas into the post-state phase — charged at end-of-opcode, once the answer is known — while the predictable warm/cold access fees stay in the pre-state phase on gas_left.

Excluding the reservoir from the GAS_CALL_STIPEND check keeps the 2,300-gas stipend's meaning intact: the stipend is about compute headroom, which lives in gas_left.

EIP-8037 · Block header & base fee
tx_state_gas   = intrinsic_state_gas + execution_state_gas_used
tx_regular_gas = tx_gas_used_after_refund - tx_state_gas

block_regular_gas_used += tx_regular_gas
block_state_gas_used   += tx_state_gas

gas_used = max(block_regular_gas_used, block_state_gas_used)
assert gas_used <= block.gas_limit
gas_used_delta = parent.gas_used - parent.gas_target

Receipt cumulative_gas_used tracks the per-tx tx_gas_used (post-refund, post-floor), so receipt[i] − receipt[i−1] is what tx i actually paid.

💡 max() at the block, sum() at the wallet

This is the 8011 rule in code. The header's gas_used is the bottleneck dimension — the taller of the two bars — and that's what's checked against the limit and what drives the base fee. A user still pays the sum of their two dimensions, so UX is unchanged; only the block-fullness arithmetic differs.

The 7778 variant swaps tx_gas_used_after_refund for the pre-refund value, so refunds don't shrink the block's accounted compute — closing the same loophole 7778 targets, now per-dimension.

§System contracts & system transactions

EIP-8037 · Raised system-call gas limit
SYSTEM_CALL_GAS_LIMIT =
   30_000_000 + STATE_BYTES_PER_STORAGE_SET × CPSB × SYSTEM_MAX_SSTORES_PER_CALL
 = 30_000_000 + 64 × 1530 × 16
 = 31_566_720

Applies to system contracts invoked at block boundaries: 2935, 4788, 7002, 7251. SYSTEM_MAX_SSTORES_PER_CALL = 16 matches MAX_WITHDRAWAL_REQUESTS_PER_BLOCK (7002), the largest per-block write bound. The extra budget sits in the reservoir; system calls aren't subject to the 7825 cap and don't count against the block limit.

💡 Don't accidentally brick the protocol's own contracts

System contracts run with a fixed 30M gas budget every block. They write storage (a ring buffer of block hashes, beacon roots, a withdrawal queue…). If a storage write suddenly costs 64·CPSB = 97,920 state-gas instead of 20,000, a system call that used to fit in 30M might run dry — and a failing system call is a consensus problem, not a user inconvenience.

So 8037 hands them exactly enough extra headroom to absorb the worst case: 16 fresh slots × the new per-slot state cost. Pinning 16 to 7002's existing bound means the margin tracks the real worst case rather than a guess. Putting the surplus in the reservoir keeps it usable only for state, so the change can't silently expand their compute budget.

§Rationale — deriving CPSB

CPSB isn't measured; it's solved for. Pick a state-growth budget and a reference gas limit, assume the fee market sits at its target on average, and the cost-per-byte falls out by division.

EIP-8037 · The derivation

Inputs: target 120 GiB/yr (= 128,849,018,880 B); reference limit 150M; 12s slots → 2,628,000 blocks/yr; average state-gas utilization 50% (the base fee equilibrates at the target = half the limit).

total_state_gas_per_year
  = (150,000,000 / 2) × 2,628,000
  = 1.971 × 10¹⁴ gas

CPSB = total_state_gas_per_year / target_bytes
     = 1.971×10¹⁴ / 128,849,018,880
     ≈ 1530 gas / byte
💡 Reading the assumptions
  • 50% utilization is the keystone. Under EIP-1559-style fees, the base fee pushes usage toward the target, which is half the limit. So on average only half a block's gas is available for state before the base fee bites — hence the /2.
  • 150M reference is a deliberate middle ground between today's 60M and a hoped-for ~300M: high enough that CPSB won't need re-deriving immediately, low enough that the day-one price hike isn't brutal.
  • 120 GiB/yr is the policy choice — slow enough to keep nodes under the 650 GiB wall for years, given the ~390 GiB starting point.

Because it's a policy number, the EIP says plainly: if a future limit increase changes expected growth, just re-derive CPSB in a follow-up EIP. Turn the dials below to feel how sensitive it is.

🧮 Try it — derive CPSB yourself

Adjust the policy inputs. The EIP's defaults (120 GiB, 150M, 50%, 12s) give 1530. The lower table shows the equilibrium state growth this CPSB implies at other block limits — reproducing the EIP's worst-case table.

Derived CPSB
1530 gas/byte
State-gas / year
Blocks / year
Block limitEquilibrium growth (GiB/yr)

§Rationale — harmonization across state creation

EIP-8037 · Gas per byte, today

Under current pricing, the gas cost to create one byte of state depends entirely on the method (intrinsic tx cost ignored):

MethodGas/byte
Deploy 24kB contract~200
Fund fresh EOA with 1 wei~208
Add delegate flag to funded EOA (7702)~219
7702 authorization to empty address~274
Fill new storage slot (SSTORE 0→x)~313

Fix CPSB once, then derive each op's cost as bytes_created × CPSB (64/slot, 120/account, 23/auth).

💡 From a 1.5× spread to a flat line

The disk doesn't care whether a byte arrived via SSTORE or CODECOPY — but the gas schedule charged anywhere from 200 to 313 gas/byte for it, a ~1.5× spread with no physical justification. That spread is an arbitrage surface: rational actors route state creation through the cheapest opcode, distorting behavior for no reason.

8037 collapses the whole column to a single number, CPSB, and lets the only legitimate variable — how many bytes — set the price. Same disk impact, same cost, regardless of path. The bars below show the "before" spread snapping to one harmonized height (and rising to the level needed to actually bound growth).

Current gas-per-byte (orange, uneven) vs. EIP-8037 (violet, all = CPSB). Toggle to compare.

💸 Try it — what does creating state cost now?

Pick an operation and see its state-gas under EIP-8037 (= bytes × CPSB), the multiple over today's cost, and the ETH price at a chosen base fee. EIP-8037's own table uses 0.08 Gwei (the post-60M-increase average).

Current gas
EIP-8037 state-gas
Multiple
≈ cost in ETH

State-gas only; EIP-8038 regular-gas surcharges (account write, hashing) apply on top.

§Rationale — where the byte counts come from

EIP-8037 · On-disk footprints

New account = 120 bytes

Account hash (key)32
Nonce8
Balance16
Code hash32
Storage root32
Total120

New slot = 64 B (32 key hash + 32 value). 7702 auth = 23 B (0xef0100 3 + address 20).

These count only the leaf payload + its keccak key — not intermediate trie nodes — so they're a lower bound on real growth.

💡 Honest, and deliberately conservative

The byte counts are the literal fields a client must persist for a new leaf, hashed key included. There's no fudge factor.

The footnote matters: real state growth is worse than these numbers, because inserting a leaf also rewrites intermediate trie nodes (branch/extension nodes, RLP encoding overhead). By pricing only the lower bound, 8037 errs toward under-charging — a conscious choice to avoid over-penalizing users while still bending the growth curve. If anything, it leaves room to raise CPSB later.

The 23-byte auth figure is why 7702 is in the requires list at all: the delegation indicator is a genuinely new kind of state, and it had to be assigned a byte cost like everything else.

§Rationale — EIP-7825 & the contract-size trap

EIP-8037 · The trap, and the escape

EIP-7825 caps any transaction at TX_MAX_GAS_LIMIT = 16,777,216. If that cap applied to state-gas too, then with CPSB = 1530 the largest deployable contract would be only ~7.5 kB:

(16,777,216 − 21,000 − 5,000,000 − 120×1530) / 1530 ≈ 7,564 bytes

Fix: apply the 7825 cap to regular-gas only. This doesn't weaken 7825's scaling intent, because regular-gas meters everything that benefits from parallelization; state growth doesn't (it's a disk write, and that write's transient cost is already in regular-gas). The reservoir then carries the overflow state-gas.

💡 Two good ideas that collide — and the reconciliation

This is the most elegant bit of the whole proposal. 7825 caps per-tx gas to bound worst-case block-validation time (a DoS / sync-time concern). 8037 makes state expensive. Stack them naively and you've accidentally banned contracts bigger than 7.5 kB — well under the EIP-170 24 kB limit. That would break real deployments.

The resolution rests on a clean principle: 7825's cap exists to bound the work that can't be parallelized away. Compute and the act of writing fit that. But the long-term cost of state existing doesn't threaten single-block validation time at all — it's a slow, cumulative, disk-capacity problem, governed by the block-level state-gas limit, not the per-tx cap. So state-gas is rightly exempt from 7825, and the reservoir is just the plumbing that delivers that exemption through a one-field gas API.

The example budgets 5M regular gas for constructor execution on top of the base costs — realistic for a heavy deploy — and still only clears ~7.5 kB without the fix.

EIP-8037 · Higher throughput

Metering state separately also means raising state costs in line with the block limit won't shrink the gas available for everything else — yielding higher throughput, per the original argument in EIP-8011.

💡 The payoff loop

Put the pieces together and you get a virtuous loop: separate metering → state price can rise to whatever protects the disk → that price increase doesn't tax compute → so the block gas limit can keep rising for throughput → which is the original goal. 8037 isn't just a tax; it's the piece that makes future gas-limit increases safe on the state axis.

§Backwards compatibility

EIP-8037 · Tooling & the 7778 variant

A backwards-incompatible repricing requiring a network upgrade. Wallets & nodes MUST update eth_estimateGas to account for state-gas, the reservoir model, and two-dimensional block accounting — or risk underestimating and producing failed txs. End users keep their workflows.

If implemented with EIP-7778, block accounting uses tx_gas_used_before_refund instead of the after-refund value.

💡 The estimator is where this bites

Users won't notice the two dimensions — but eth_estimateGas absolutely must. A naive estimator that still thinks in one combined number could under-fund the state dimension and silently bounce transactions. This is the practical reason the EIP keeps the per-tx interface single-valued (tx.gas) even while the accounting is two-dimensional: minimize the blast radius on tooling.

EIP-8037 · Deterministic deployers

Pre-signed, hardcoded-gas deployment factories (Nick's method @ 100k gas; ERC-2470, Create2Deployer, ImmutableCreate2Factory, CreateX) will no longer execute, because state-creation cost now exceeds their fixed gas limit.

Existing networks (mainnet, L2s) are unaffected — the factories are already deployed there. Only new networks (devnets/testnets) activating 8037 from genesis must regenerate the pre-signed txs or pre-deploy the factories at genesis.

💡 A pre-signed transaction can't be re-priced

Nick's-method factories rely on a transaction signed by a key nobody controls, with a gas limit frozen at signing time. You can't bump that gas limit without the key — so once deployment costs more than the frozen limit, that exact transaction is dead on any chain where it hasn't already run.

It's a non-issue for chains where these canonical addresses already exist, and a genesis-time chore for brand-new chains. The EIP flags it because so much tooling assumes CreateX et al. live at fixed addresses everywhere.

§Security considerations

EIP-8037 · Mispricing vs. ETH transfers

Creating a new account now costs 120×CPSB (≈183,600 gas), but transferring ETH to a fresh account costs 21,000. Users could dodge the new-account charge by first sending a plain 21k transfer to instantiate the account.

EIP-2780 closes this: a non-create tx with value > 0 targeting a non-existent account adds GAS_NEW_ACCOUNT to intrinsic cost.

💡 8037 creates a hole; 2780 patches it

This is why 2780 is a hard dependency. The instant new accounts get expensive inside the EVM but a top-level value transfer that creates the very same account stays at 21k, you've built an arbitrage: route account creation through a cheap transfer. The same byte of state would have two wildly different prices again — re-introducing exactly the inconsistency harmonization set out to kill.

2780 restores the symmetry by charging the new-account surcharge at the transaction's entry point too, so every path that births an account pays the same. (2780 does much more — it overhauls intrinsic gas — but this surcharge is the part 8037 leans on.)

EIP-8037 · Block-building complexity

Optimal block construction now balances usage across two dimensions, not one. Sophisticated builders may extract an edge, raising centralization concerns. But greedy heuristics (fill until one dimension saturates) stay effective and keep building feasible for local/less-sophisticated builders.

💡 Bin-packing in 2-D is genuinely harder

One-dimensional block packing is "fill to the limit." Two dimensions turns it into a knapsack-flavored problem: you want to fill both the regular and state axes efficiently, and the most profitable mix is non-obvious. That's a real lever for sophisticated builders. The EIP's honest position is that the harm is bounded — simple "greedy until something saturates" still gets you most of the way — and this concern is inherited directly from 8011, which carries the same caveat.

EIP-8037 · ERC-4337 bundles

The GAS opcode returns gas_left only and can't see the reservoir. Bundlers that meter sub-calls via gasleft() deltas (e.g. the ERC-4337 EntryPoint) can't attribute state-gas funded by the reservoir. Because all user-ops in a bundle share one reservoir, one op's state refunds can subsidize another's charges invisibly. Bundlers/EntryPoint MUST account for state-gas explicitly, not via gasleft() deltas.

💡 The price of hiding the reservoir

Hiding the reservoir from GAS is what makes the reservoir model safe for ordinary contracts — but it has a cost. ERC-4337 account abstraction meters how much gas each user-operation consumes by sampling gasleft() before and after — and that sample is now blind to state-gas. Worse, the reservoir is shared across the whole bundle, so accounting done purely with gasleft() deltas can mis-attribute or cross-subsidize between users.

The mandate is therefore unavoidable: 4337 infrastructure must track state-gas charges and refills explicitly, out of band from gasleft(). It's a concrete example of how a clean protocol-level abstraction (one gas field, hidden reservoir) pushes complexity outward to the layers that were exploiting the old transparency.

§Glossary

The vocabulary EIP-8037 invents or repurposes.

CPSB
Cost Per State Byte = 1530 gas. The single unit; every state op's state-gas is bytes × CPSB.
regular-gas
The dimension that meters transient, parallelizable work — compute, access, the act of writing. Subject to the EIP-7825 per-tx cap.
state-gas
The dimension that meters permanent state growth. Charged at bytes × CPSB; exempt from the 7825 cap; lives in the reservoir.
state_gas_reservoir
A second per-tx gas bucket holding gas beyond the 7825 regular-gas budget. State charges drain it first; the GAS opcode can't see it.
gas_left
The regular-gas bucket, clamped to TX_MAX_GAS_LIMIT − intrinsic_regular_gas. What GAS/gasleft() returns.
bottleneck resource
The dimension with the highest cumulative block gas. block.gas_used = max(regular, state) drives fullness & base fee.
existent account
Per EIP-161: has nonzero balance, nonzero nonce, or non-empty code — i.e. already has a state-trie leaf. Determines whether the 120-byte charge applies.
STATE_BYTES_PER_*
The per-op byte footprints: NEW_ACCOUNT=120, STORAGE_SET=64, AUTH_BASE=23.
SYSTEM_MAX_SSTORES_PER_CALL
16 — the most new slots a system call should write, = 7002's MAX_WITHDRAWAL_REQUESTS_PER_BLOCK. Sets the system-call gas headroom.

§All referenced EIPs

Everything EIP-8037 names, with one line on why. draft = still moving; final = shipped.

  • 8011draft — Multidimensional Gas Metering. The framework 8037 instantiates.
  • 8038draft — State-access gas update. Companion; defines the regular-gas surcharges.
  • 7928draft — Block-Level Access Lists. Pre/post-state two-phase charging model.
  • 7825final — Transaction Gas Limit Cap (2²⁴). The cap state-gas escapes via the reservoir.
  • 7904draft — Compute Gas Cost Increase. Supplies updated ECRECOVER.
  • 7778draft — Block Gas Accounting without Refunds. Composes with 8037's block accounting.
  • 7702final — Set Code for EOAs. The 23-byte delegation state vector.
  • 7623final — Increase Calldata Cost. The calldata floor 8037 applies post-refund.
  • 7976draft — Increase Calldata Floor (64/64). Same block-shrinking family.
  • 7981draft — Increase Access List Cost. Closes the calldata-floor bypass.
  • 6780final — SELFDESTRUCT only in same tx. Governs when state is removed (→ refill rules).
  • 2780draft — Reduce intrinsic tx gas. Patches the ETH-transfer mispricing 8037 creates.
  • 161final — State trie clearing. Defines "empty"/"existent" accounts.
  • 684final — Revert on creation collision. Valid CREATE targets.
  • 170final — Contract code size limit (24,576 B).
  • 2935final — Historical block hashes in state. System contract.
  • 4788final — Beacon block root in the EVM. System contract.
  • 7002final — EL-triggerable withdrawals. Source of the 16 bound. System contract.
  • 7251final — MAX_EFFECTIVE_BALANCE / consolidations. System contract.
  • ERC-4337 Account Abstraction. The bundler gasleft() caveat.