From 9d68e40dcfb6107532502f669504f6ab8072f030 Mon Sep 17 00:00:00 2001 From: Helkomine Date: Tue, 23 Jun 2026 00:06:03 +0700 Subject: [PATCH 1/5] Update eip-8038.md --- EIPS/eip-8038.md | 56 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/EIPS/eip-8038.md b/EIPS/eip-8038.md index 6f857659593fa7..038fe608311679 100644 --- a/EIPS/eip-8038.md +++ b/EIPS/eip-8038.md @@ -33,8 +33,8 @@ Upon activation of this EIP, the following parameters of the gas model are intro | `ACCOUNT_WRITE` | Surcharge for when writing to an account changes one account leaf value for the first time | 6,700¹ | 8,000 | +19% | `*CALL` opcodes, `SELFDESTRUCT`, EOA delegations and ETH transfers | | `COLD_STORAGE_ACCESS` | Cold touch of a storage slot | 2,100 | 3,000 | +43% | `SSTORE` and `SLOAD` | | `STORAGE_WRITE` | Surcharge for when writing to a storage slot changes its value for the first time | 2,800² | 10,000 | +257% | `SSTORE` | -| `WARM_ACCESS` | Touch of an already-warm account or storage slot | 100 | 100 | +0% | `SSTORE`, `SLOAD`, `*CALL` opcodes, `BALANCE` and `EXT*` opcodes | -| `STORAGE_CLEAR_REFUND` | Refund for clearing a storage slot | 4,800 | 12,480 | +160% | `SSTORE` | +| `LOW_WARM_ACCESS` | Warm access cost for read-only opcodes | - | 5 | - | `SLOAD`, `BALANCE`, and `EXT*` opcodes | +| `WARM_ACCESS` | Warm access cost for opcodes that must account for `REVERT` execution paths | 100 | 100 | +0% | `SSTORE`, `*CALL` opcodes, and `CREATE*` opcodes | | `CREATE_ACCESS` | State access costs for contract deployment (include account cold access and account write) | 7,000³ | 11,000 | +57% | `CREATE`/ `CREATE2` | | `ACCESS_LIST_STORAGE_KEY_COST` | Gas charged per storage key included in a transaction's access list | 1,900 | 3,000 | +58% | `SSTORE` and `SLOAD` | | `ACCESS_LIST_ADDRESS_COST` | Gas charged per address included in a transaction's access list | 2,400 | 3,000 | +25% | `*CALL` opcodes, `BALANCE`, `SELFDESTRUCT` and `EXT*` opcodes | @@ -45,25 +45,53 @@ Upon activation of this EIP, the following parameters of the gas model are intro ³: 7,000 = `GAS_CREATE` (32,000) - `GAS_NEW_ACCOUNT` (25,000) -### `SSTORE` pricing +### Introduction of `state_access_gas_reservoir` + +A new counter, `state_access_gas_reservoir`, is introduced to replace the refund counter. + +This counter is initialized to zero at the beginning of each transaction. + +Its operation is analogous to the `state_gas_reservoir` defined in [EIP-8037](./eip-8037.md): it accumulates all gas refills generated by eligible operations, and all state-access charges (excluding the opcode base cost itself) MUST first consume gas from this reservoir before consuming gas from `gas_left`. + +### Introduction of `balance_updated` and `account_updated` + +Two new global sets, `balance_updated` and `account_updated`, are introduced to track accounts whose state has been modified during transaction execution. + +`balance_updated` records accounts whose balance has changed. Membership in this set is temporary and may be reverted by subsequent operations. + +`account_updated` records accounts that have undergone permanent account-level modifications, such as account creation or changes to account state-root-related fields. + +These sets operate alongside existing global sets such as `access_list_address`. -In addition, the `SSTORE` cost formula is updated to include the following independent costs: +The rules governing insertion into and removal from these sets are defined by the relevant opcodes below. -1. Access costs: `COLD_STORAGE_ACCESS` or `WARM_ACCESS`, depending on whether the storage slot is cold or warm. -2. Write cost: additionally charge `STORAGE_WRITE` if the new value is different from the present value and the present value equals the original value (First time change). -3. State creation cost: additionally charge `GAS_STORAGE_SET` (per [EIP-8037](./eip-8037.md)) if the original value is zero, the current value is zero, and the new value is non-zero. +### `SLOAD` Pricing -Refunds are also updated as follows. Each rule is an adjustment to the transaction's refund counter and is evaluated on every `SSTORE`: +The base cost of the `SLOAD` opcode is set to `LOW_WARM_ACCESS`. + +If the accessed storage slot is cold, an additional `COLD_STORAGE_ACCESS` charge is applied. + +### `BALANCE` Pricing + +The base cost of the `BALANCE` opcode is set to `LOW_WARM_ACCESS`. + +If the accessed account is cold, an additional `COLD_ACCOUNT_ACCESS` charge is applied. + +### `EXT*` Pricing + +The base cost of all `EXT*` opcodes is set to 2 * `LOW_WARM_ACCESS`. + +If the accessed account is cold, an additional `COLD_ACCOUNT_ACCESS` charge is applied. + +### `SSTORE` pricing -1. `STORAGE_CLEAR_REFUND` is added if the original value is non-zero, the current value is non-zero and the new value is zero (a slot is cleared). -2. `STORAGE_CLEAR_REFUND` is subtracted if the original value is non-zero, the current value is zero and the new value is non-zero (a slot that was cleared earlier in the same transaction is restored). This reverses the refund granted by rule 1, so that clearing and then restoring a slot within the same transaction is never net-profitable. -3. `STORAGE_WRITE` is refunded if the new value equals the original value and differs from the current value (a first-time change made earlier in the same transaction is reset back to its original value). +The base cost of the `SSTORE` opcode is set to `WARM_ACCESS`. -Rules 2 and 3 mirror the refund accounting of [EIP-2200](./eip-2200.md) and [EIP-3529](./eip-3529.md) for slots that are modified more than once within a transaction: a `STORAGE_WRITE` charge or `STORAGE_CLEAR_REFUND` granted on an earlier `SSTORE` to the same slot is undone when a later `SSTORE` returns the slot to its original value. Without these reversals, a round trip such as `x → 0 → x` would yield a net refund even though the slot ends the transaction unchanged. +If the accessed storage slot is cold, an additional `COLD_STORAGE_ACCESS` charge is applied. -These refunds go to the transaction's refund counter and are capped to 20% of the total gas used by the transaction, as per the current refund mechanism. +Per [EIP-7777](./eip-7778.md), the refund counter has been removed, which also eliminates refunds for clearing storage slots. -The rules for state creation cost charges and refills are addressed in [EIP-8037](./eip-8037.md). +Transaction-internal refunds are instead redirected to `state_access_gas_reservoir` for state-access costs and to `state_gas_reservoir` for state-creation costs. Cases and their corresponding costs are detailed in the table below: From b81f7933581e3b02b4969ebac218e28bd1663423 Mon Sep 17 00:00:00 2001 From: Helkomine Date: Tue, 23 Jun 2026 11:45:43 +0700 Subject: [PATCH 2/5] fix spelling --- EIPS/eip-8038.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-8038.md b/EIPS/eip-8038.md index 038fe608311679..03611d66702efc 100644 --- a/EIPS/eip-8038.md +++ b/EIPS/eip-8038.md @@ -89,7 +89,7 @@ The base cost of the `SSTORE` opcode is set to `WARM_ACCESS`. If the accessed storage slot is cold, an additional `COLD_STORAGE_ACCESS` charge is applied. -Per [EIP-7777](./eip-7778.md), the refund counter has been removed, which also eliminates refunds for clearing storage slots. +Per [EIP-7778](./eip-7778.md), the refund counter has been removed, which also eliminates refunds for clearing storage slots. Transaction-internal refunds are instead redirected to `state_access_gas_reservoir` for state-access costs and to `state_gas_reservoir` for state-creation costs. From a26ed8295b91f69bd0aa93080669b25cf837a5dd Mon Sep 17 00:00:00 2001 From: Helkomine Date: Tue, 23 Jun 2026 13:50:11 +0700 Subject: [PATCH 3/5] rename access_list_address to accessed_addresses (EIP-2929) --- EIPS/eip-8038.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-8038.md b/EIPS/eip-8038.md index 03611d66702efc..e644d88f1b00b9 100644 --- a/EIPS/eip-8038.md +++ b/EIPS/eip-8038.md @@ -61,7 +61,7 @@ Two new global sets, `balance_updated` and `account_updated`, are introduced to `account_updated` records accounts that have undergone permanent account-level modifications, such as account creation or changes to account state-root-related fields. -These sets operate alongside existing global sets such as `access_list_address`. +These sets operate alongside existing global sets such as `accessed_addresses`. The rules governing insertion into and removal from these sets are defined by the relevant opcodes below. From 38d7e2ae529c2198f930bd0197dd321ae7745e29 Mon Sep 17 00:00:00 2001 From: Helkomine Date: Tue, 23 Jun 2026 14:12:55 +0700 Subject: [PATCH 4/5] Add the missing details --- EIPS/eip-8038.md | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/EIPS/eip-8038.md b/EIPS/eip-8038.md index e644d88f1b00b9..865ec1cb5a1b21 100644 --- a/EIPS/eip-8038.md +++ b/EIPS/eip-8038.md @@ -71,15 +71,15 @@ The base cost of the `SLOAD` opcode is set to `LOW_WARM_ACCESS`. If the accessed storage slot is cold, an additional `COLD_STORAGE_ACCESS` charge is applied. -### `BALANCE` Pricing +### `BALANCE` and `EXTCODEHASH` pricing -The base cost of the `BALANCE` opcode is set to `LOW_WARM_ACCESS`. +The base cost of `BALANCE` and `EXTCODEHASH` is set to `LOW_WARM_ACCESS`. If the accessed account is cold, an additional `COLD_ACCOUNT_ACCESS` charge is applied. -### `EXT*` Pricing +### `EXTCODESIZE` and `EXTCODECOPY` pricing -The base cost of all `EXT*` opcodes is set to 2 * `LOW_WARM_ACCESS`. +The base cost of `EXTCODESIZE` and `EXTCODECOPY` is set to 2 * `LOW_WARM_ACCESS`. If the accessed account is cold, an additional `COLD_ACCOUNT_ACCESS` charge is applied. @@ -95,18 +95,14 @@ Transaction-internal refunds are instead redirected to `state_access_gas_reservo Cases and their corresponding costs are detailed in the table below: -| Original value | Current value | New value | Access status | Description | Regular-gas charges/refunds | State-gas charges/refills | +| Original value | Current value | New value | Access status | Description | Regular-gas charges/State-access-gas refills | State-gas charges/refills | | :---: | :---: | :---: | :---: | :---: | :---: | :---: | -| 0 | 0 | x | Cold | New slot | `COLD_STORAGE_ACCESS` + `STORAGE_WRITE` charged | `GAS_STORAGE_SET` charged | +| 0 | 0 | x | Cold | New slot | `WARM_ACCESS` + `COLD_STORAGE_ACCESS` + `STORAGE_WRITE` charged | `GAS_STORAGE_SET` charged | | 0 | 0 | x | Warm | New slot | `WARM_ACCESS` + `STORAGE_WRITE` charged | `GAS_STORAGE_SET` charged | -| x | x | y | Cold | Existing slot, first change | `COLD_STORAGE_ACCESS` + `STORAGE_WRITE` charged | no state-gas adjustments | +| x | x | y | Cold | Existing slot, first change | `WARM_ACCESS` + `COLD_STORAGE_ACCESS` + `STORAGE_WRITE` charged | no state-gas adjustments | | x | x | y | Warm | Existing slot, first change | `WARM_ACCESS` + `STORAGE_WRITE` charged | no state-gas adjustments | -| x | x | 0 | Cold | Cleared slot, non-zero at transaction start | `COLD_STORAGE_ACCESS` + `STORAGE_WRITE` charged, `STORAGE_CLEAR_REFUND` refunded | no state-gas adjustments | -| x | x | 0 | Warm | Cleared slot, non-zero at transaction start | `WARM_ACCESS` + `STORAGE_WRITE` charged, `STORAGE_CLEAR_REFUND` refunded | no state-gas adjustments | -| 0 | x | 0 | Warm | Set slot reset to zero (zero at transaction start) | `WARM_ACCESS` charged, `STORAGE_WRITE` refunded | `GAS_STORAGE_SET` refilled | -| x | y | x | Warm | Previously-modified slot reset to original value | `WARM_ACCESS` charged, `STORAGE_WRITE` refunded | no state-gas adjustments | -| x | 0 | x | Warm | Cleared slot restored to original value | `WARM_ACCESS` charged, `STORAGE_WRITE` refunded, `STORAGE_CLEAR_REFUND` reversed | no state-gas adjustments | -| x | 0 | y | Warm | Cleared slot written to a new non-zero value | `WARM_ACCESS` charged, `STORAGE_CLEAR_REFUND` reversed | no state-gas adjustments | +| 0 | x | 0 | Warm | Set slot reset to zero (zero at transaction start) | `WARM_ACCESS` charged, `STORAGE_WRITE` refilled | `GAS_STORAGE_SET` refilled | +| x | y | x | Warm | Previously-modified slot reset to original value | `WARM_ACCESS` charged, `STORAGE_WRITE` refilled | no state-gas adjustments | | x | y | z | Warm | Previously-modified slot written to again | `WARM_ACCESS` charged | no state-gas adjustments | ### Account access pricing @@ -119,30 +115,32 @@ For `CALL` and `CALLCODE` operations, `CALL_VALUE` is set to `ACCOUNT_WRITE + CA #### `CREATE`/`CREATE2` -`CREATE` and `CREATE2` operations don't have explicit warm/cold pricing. Instead, they are charged `CREATE_ACCESS` in regular-gas and `GAS_NEW_ACCOUNT` in state-gas (per [EIP-8037](./eip-8037.md)). `CREATE_ACCESS` is defined as `ACCOUNT_WRITE` + `COLD_STORAGE_ACCESS`. +The base cost of the `CREATE*` family is set to WARM_ACCESS. + +This charge is applied uniformly to operations that require `REVERT`-path handling. + +`CREATE` and `CREATE2` operations don't have explicit warm/cold pricing. Instead, they are charged `CREATE_ACCESS` in regular-gas and `GAS_NEW_ACCOUNT` in state-gas (per [EIP-8037](./eip-8037.md)). `CREATE_ACCESS` is defined as `ACCOUNT_WRITE` + `COLD_STORAGE_ACCESS`. This represents the maximum state-access charge associated with account accessing. Note: this definition does not exactly match the legacy decomposition shown in footnote ³ of the Parameters table (`GAS_CREATE` - `GAS_NEW_ACCOUNT` = 7,000). The pre-existing accounting in the protocol is not internally consistent here, and this EIP keeps the discrepancy rather than attempting to reconcile it. +When entering a creation frame, refund accounting is performed if the target account was previously updated before becoming the destination of the creation operation (for example, an account that received ETH before contract creation). The account MUST be permanently inserted into `account_updated`. If the account exists in `balance_updated`, `ACCOUNT_WRITE` MUST be refilled into `state_access_gas_reservoir`, and the account MUST be removed from `balance_updated`. + #### `SELFDESTRUCT` For `SELFDESTRUCT`, an additional charge of `ACCOUNT_WRITE` is added if a positive balance is sent to an empty account. -#### `EXT*` family update - -Besides the current access costs, `EXTCODESIZE` and `EXTCODECOPY` are charged an additional `WARM_ACCESS`. - #### Overview The cases for account-related operations and their corresponding costs are summarized in the table below: | Operation | Access charge | `ACCOUNT_WRITE` charged | Additional charge | | :--- | :---: | :--- | :--- | -| `CALL` / `CALLCODE` | `COLD_ACCOUNT_ACCESS` or `WARM_ACCESS` | when value is transferred (via `CALL_VALUE` = `ACCOUNT_WRITE` + `CALL_STIPEND`) | — | -| `DELEGATECALL` / `STATICCALL` | `COLD_ACCOUNT_ACCESS` or `WARM_ACCESS` | never (no value transfer) | — | +| `CALL` / `CALLCODE` | `WARM_ACCESS`, surcharge `COLD_ACCOUNT_ACCESS` | when value is transferred (via `CALL_VALUE` = `ACCOUNT_WRITE` + `CALL_STIPEND`) | — | +| `DELEGATECALL` / `STATICCALL` | `WARM_ACCESS`, surcharge `COLD_ACCOUNT_ACCESS` | never (no value transfer) | — | | `CREATE` / `CREATE2` | `CREATE_ACCESS` (= `ACCOUNT_WRITE` + `COLD_STORAGE_ACCESS`) | always (folded into `CREATE_ACCESS`) | `GAS_NEW_ACCOUNT` in state-gas (per [EIP-8037](./eip-8037.md)) | | `SELFDESTRUCT` | `COLD_ACCOUNT_ACCESS` or `WARM_ACCESS` | when a positive balance is sent to an empty account | — | -| `BALANCE` / `EXTCODEHASH` | `COLD_ACCOUNT_ACCESS` or `WARM_ACCESS` | never | — | -| `EXTCODESIZE` / `EXTCODECOPY` | `COLD_ACCOUNT_ACCESS` or `WARM_ACCESS` | never | `WARM_ACCESS` (second database read) | +| `BALANCE` / `EXTCODEHASH` | `LOW_WARM_ACCESS`, surcharge `COLD_ACCOUNT_ACCESS` | never | — | +| `EXTCODESIZE` / `EXTCODECOPY` | `LOW_WARM_ACCESS`, surcharge `COLD_ACCOUNT_ACCESS` | never | `LOW_WARM_ACCESS` (second database read) | | EOA delegation ([EIP-7702](./eip-7702.md)) | `COLD_ACCOUNT_ACCESS` or `WARM_ACCESS` per authority | per authorization (intrinsic cost) | see authorizations table below | ### [EIP-7702](./eip-7702.md) authorizations pricing From c7b1be47ad91896dc929bc0ed62c8b3af49e2911 Mon Sep 17 00:00:00 2001 From: Helkomine Date: Tue, 23 Jun 2026 14:30:37 +0700 Subject: [PATCH 5/5] add details --- EIPS/eip-8038.md | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/EIPS/eip-8038.md b/EIPS/eip-8038.md index 865ec1cb5a1b21..81a6defdfaaef6 100644 --- a/EIPS/eip-8038.md +++ b/EIPS/eip-8038.md @@ -57,9 +57,9 @@ Its operation is analogous to the `state_gas_reservoir` defined in [EIP-8037](./ Two new global sets, `balance_updated` and `account_updated`, are introduced to track accounts whose state has been modified during transaction execution. -`balance_updated` records accounts whose balance has changed. Membership in this set is temporary and may be reverted by subsequent operations. +- `balance_updated` records accounts whose balance has changed. Membership in this set is temporary and may be reverted by subsequent operations. -`account_updated` records accounts that have undergone permanent account-level modifications, such as account creation or changes to account state-root-related fields. +- `account_updated` records accounts that have undergone permanent account-level modifications, such as account creation or changes to account state-root-related fields. These sets operate alongside existing global sets such as `accessed_addresses`. @@ -111,11 +111,30 @@ The rules that determine when `COLD_ACCOUNT_ACCESS` and `WARM_ACCESS` are charge #### `CALL`/`CALLCODE` -For `CALL` and `CALLCODE` operations, `CALL_VALUE` is set to `ACCOUNT_WRITE + CALL_STIPEND`, where `CALL_STIPEND` = 2,300. +The base cost of the `*CALL` family is set to `WARM_ACCESS`. + +If the target account is cold, an additional `COLD_ACCOUNT_ACCESS` charge is applied. + +During transaction execution, each account maintains the following values: + +- `original_balance`: the account balance at the beginning of the transaction. This value remains constant throughout the transaction. +- `current_balance`: the current account balance. +- `new_balance`: the balance after the pending update. + +For `CALL` and `CALLCODE` operations, `CALL_VALUE` is set to `ACCOUNT_WRITE + CALL_STIPEND`, where `CALL_STIPEND` = 2,300. This represents the maximum state-access charge for a value-transferring call. Upon entering the call frame, gas accounting is performed according to the table below: + +| `original_balance` | `current_balance` | `new_balance` | `account_updated` | `balance_updated` update | Description | Regular-gas charges/ State-access-gas refills | +| :---: | :---: | :---: | :---: | :---: | :---: | :---: | +| x | x | y | false | added | First temporary update | no adjustments | +| x | x | y | true | unchanged | First permanent update | `ACCOUNT_WRITE` refilled | +| x | y | x | false | removed | Temporary reset | 2 * `ACCOUNT_WRITE` refilled | +| x | y | x | true | unchanged | Permanent reset | `ACCOUNT_WRITE` refilled | +| x | y | z | false | unchanged | Subsequent temporary update | `ACCOUNT_WRITE` refilled | +| x | y | z | true | unchanged | Subsequent permanent update | `ACCOUNT_WRITE` refilled | #### `CREATE`/`CREATE2` -The base cost of the `CREATE*` family is set to WARM_ACCESS. +The base cost of the `CREATE*` family is set to `WARM_ACCESS`. This charge is applied uniformly to operations that require `REVERT`-path handling. @@ -137,7 +156,7 @@ The cases for account-related operations and their corresponding costs are summa | :--- | :---: | :--- | :--- | | `CALL` / `CALLCODE` | `WARM_ACCESS`, surcharge `COLD_ACCOUNT_ACCESS` | when value is transferred (via `CALL_VALUE` = `ACCOUNT_WRITE` + `CALL_STIPEND`) | — | | `DELEGATECALL` / `STATICCALL` | `WARM_ACCESS`, surcharge `COLD_ACCOUNT_ACCESS` | never (no value transfer) | — | -| `CREATE` / `CREATE2` | `CREATE_ACCESS` (= `ACCOUNT_WRITE` + `COLD_STORAGE_ACCESS`) | always (folded into `CREATE_ACCESS`) | `GAS_NEW_ACCOUNT` in state-gas (per [EIP-8037](./eip-8037.md)) | +| `CREATE` / `CREATE2` | `WARM_ACCESS` + `CREATE_ACCESS` (= `WARM_ACCESS` + `ACCOUNT_WRITE` + `COLD_STORAGE_ACCESS`) | always (folded into `CREATE_ACCESS`) | `GAS_NEW_ACCOUNT` in state-gas (per [EIP-8037](./eip-8037.md)) | | `SELFDESTRUCT` | `COLD_ACCOUNT_ACCESS` or `WARM_ACCESS` | when a positive balance is sent to an empty account | — | | `BALANCE` / `EXTCODEHASH` | `LOW_WARM_ACCESS`, surcharge `COLD_ACCOUNT_ACCESS` | never | — | | `EXTCODESIZE` / `EXTCODECOPY` | `LOW_WARM_ACCESS`, surcharge `COLD_ACCOUNT_ACCESS` | never | `LOW_WARM_ACCESS` (second database read) |