--- eip: 8488 title: Versioned Opcodes for Gas Repricing description: V2 opcodes for EIP-8037/8038 schedule; new contracts only; versioned DELEGATECALL. author: Leo Glisic (@lglisic60) discussions-to: https://ethereum-magicians.org/t/eip-8038-state-access-gas-cost-update/25693 status: Draft type: Standards Track category: Core created: 2026-11-08 requires: 8037, 8038 --- ## Abstract This EIP introduces a parallel V2 opcode set whose gas costs follow [EIP-8037](./eip-8037.md) and [EIP-8038](./eip-8038.md). Contracts deployed after activation may contain only V2 opcodes; a `code_version` bit is set on acceptance. A new `DELEGATECALL_V2` opcode enforces that its target also has `code_version >= 2`. Legacy contracts continue to execute under the pre-Glamsterdam gas schedule indefinitely. ## Motivation Glamsterdam currently faces a trade-off with [EIP-8037](./eip-8037.md) and [EIP-8038](./eip-8038.md). Applying the new gas schedule and metering rules uniformly risks breaking or griefing existing contracts that rely on current gas-cost invariants. Deferring or removing the EIPs avoids that breakage but also postpones the state-growth controls that support a substantially higher gas limit. This EIP provides a third option. It applies the [EIP-8037](./eip-8037.md)/[EIP-8038](./eip-8038.md) schedule only to newly deployed bytecode, while already-deployed contracts continue under the legacy schedule. Upgradeable systems migrate naturally when their implementations are replaced. The result is that the repricing still occurs for all future code, existing contracts are unaffected, and the gas limit can be raised incrementally as the share of V2 execution grows and observed state growth remains acceptable. In addition, gas-introspection opcodes (`GAS`, `GASLIMIT`) are omitted from the V2 set. This prevents contracts from encoding assumptions about internal gas accounting that would be invalidated by future schedule changes. At a high level the EIP does three things: 1. Grandfathers the current gas schedule and metering behavior for all existing contracts. 2. Requires newly deployed contracts to use a V2 opcode set that carries the new schedule and excludes gas-introspection opcodes. 3. Notes higher-level mechanisms (standardized out-of-gas signaling, gas-spent receipts) that can replace functionality currently obtained via introspection; these are left to companion proposals. Because active contracts are upgraded or replaced over time, the proportion of state growth occurring under the legacy schedule is expected to decline. Other Glamsterdam changes can still support a partial gas-limit increase immediately; further increases can follow as V2 adoption progresses. ## Specification ### V2 Opcode Set For every opcode whose gas cost or observable gas accounting changes under [EIP-8037](./eip-8037.md) or [EIP-8038](./eip-8038.md), a V2 counterpart is defined (e.g., `SSTORE_V2`, `SLOAD_V2`, `CALL_V2`, `DELEGATECALL_V2`, `CREATE_V2`, `CREATE2_V2`). Each V2 opcode is identical to its predecessor except: - It uses the gas schedule defined by [EIP-8037](./eip-8037.md) and [EIP-8038](./eip-8038.md). - The following opcodes are not defined in the V2 set: `GAS` (`0x5a`), `GASLIMIT` (`0x45`), and any other opcode whose primary purpose is to expose internal gas metering. Attempts to include them in V2 bytecode are rejected at deployment. All other semantics (stack, memory, storage, call behavior, refunds, etc.) remain unchanged unless explicitly altered by [EIP-8037](./eip-8037.md)/[EIP-8038](./eip-8038.md). ### Deployment Gate When runtime bytecode is deposited (via `CREATE`, `CREATE2`, or any other code-creation path) after this EIP activates: 1. The bytecode is scanned. 2. If it contains any non-V2 opcode that possesses a V2 counterpart, or any omitted gas-introspection opcode, the deployment fails (the create operation reverts). 3. On success, the account's `code_version` field is set to `2`. Legacy accounts retain `code_version = 0` (or unset). The scan applies to the final runtime code that will be stored, not merely the initcode. ### DELEGATECALL_V2 `DELEGATECALL_V2` has identical semantics to `DELEGATECALL` except for the following additional check, performed after the target account is loaded and before control is transferred: - If the target's `code_version < 2`, the call fails immediately (success flag = 0, no callee state changes, unused gas returned according to normal rules). The version check is a single account-field read and incurs no extra gas beyond ordinary call overhead. Regular `CALL`, `STATICCALL`, and legacy `DELEGATECALL` are unchanged and may target any code version. `DELEGATECALL_V2` succeeds only for targets whose bytecode was accepted by the V2 deployment gate (and therefore contains only V2 opcodes). The `code_version` bit is the persistent record of that acceptance. ### Interaction with EIP-8037 Dual-Gas Accounting - Execution of V2 opcodes uses the [EIP-8037](./eip-8037.md)/[EIP-8038](./eip-8038.md) gas schedule (including any state-gas reservoir mechanics). - Execution of legacy opcodes continues to use the pre-Glamsterdam schedule. - The version that applies is determined solely by the opcode being executed. ## Rationale - Opcode duplication makes the active gas schedule self-describing in the bytecode. No runtime lookup of deployment block or external version is required beyond the one-time `code_version` bit. - The deployment gate is a linear scan of the same class already performed by clients (e.g., [EIP-3541](./eip-3541.md)). - Recording `code_version` at deployment time makes the `DELEGATECALL_V2` check O(1) and reuses work the gate has already performed. - Only delegatecall-style opcodes need the restriction, because only they execute target code in the caller's context. Ordinary calls run in the callee's context under the callee's own opcode set. - Omitting gas-introspection opcodes from V2 prevents contracts from encoding assumptions about internal metering that would be invalidated by future schedule changes. ## Backwards Compatibility All contracts deployed before activation continue to execute exactly as before, under the legacy gas schedule. No existing bytecode is invalidated. Only new deployments and uses of `DELEGATECALL_V2` are affected. Proxy-based systems that upgrade their implementation after activation automatically receive the new schedule on subsequent delegatecalls, without requiring changes to the proxy itself. ## Test Cases 1. Legacy contract deploys and executes under old gas costs. 2. Post-activation deployment containing any replaced legacy opcode reverts. 3. Post-activation deployment containing only V2 opcodes succeeds and sets `code_version = 2`. 4. `DELEGATECALL_V2` from a V2 contract to another V2 contract succeeds and runs V2 gas rules. 5. `DELEGATECALL_V2` to a legacy contract fails. 6. Ordinary `CALL` from V2 code to a legacy contract succeeds and executes the legacy code under old rules. 7. Proxy (legacy or V2) delegatecalling a newly deployed V2 implementation executes the implementation under the new gas schedule. 8. Bytecode containing `GAS` or `GASLIMIT` is rejected at deployment under the V2 rules. ## Security Considerations - The deployment gate must be applied uniformly on every code-deposit path; any omission would allow post-fork creation of legacy-opcode contracts. - `DELEGATECALL_V2` failure is indistinguishable from an ordinary failed call and does not introduce new reentrancy or gas-griefing vectors beyond those of `DELEGATECALL`. - Future opcode generations (V3, etc.) can reuse the same pattern: new opcodes, updated gate, and a version check that accepts `code_version >= N`. - Clients must ensure the `code_version` bit and the opcode tables remain consensus-critical and identically implemented. ## Copyright Copyright and related rights waived via [CC0](../LICENSE.md).