---
eip: 8358
title: Net Gas Metering for Account Changes
description: Make repeated value transfers cheaper by charging account changes once per transaction and refunding accounts that return to original state
author: Dragan Rakita (@rakita), Charles Cooper (@charles-cooper)
discussions-to: https://ethereum-magicians.org/t/eip-8358-net-gas-metering-for-account-changes/29304
status: Draft
type: Standards Track
category: Core
created: 2026-07-26
requires: 161, 2200, 2780, 2929, 3529, 7702, 7708, 8037, 8038
---

## Abstract

This EIP applies net gas metering to account balance changes. A value-bearing `CALL` pays a base cost and a charge for each account it changes for the first time in the transaction. Later changes to the same accounts cost less, and restoring an account's original balance earns a refund if its nonce is also unchanged. The gas stipend becomes a minimum callee gas limit. An applied [EIP-7702](./eip-7702.md) authorization marks its authority as changed for later calls.

## Motivation

The gas cost of a value-bearing `CALL` is flat per call: `CALL_VALUE` is `ACCOUNT_WRITE + CALL_STIPEND = 11300`, or `9000` when the unused `2300` stipend returns to the caller. This cost does not depend on earlier changes to the accounts.
The dominant resource behind that cost is the state write: at the end of a block, each account whose balance or nonce changed requires one update of its account trie leaf.
That write happens once per modified account, not once per transfer.
A transaction that moves ether through the same accounts repeatedly pays for state writes that never happen.

Storage received net gas metering through [EIP-2200](./eip-2200.md), later updated by [EIP-8038](./eip-8038.md): the first change to a slot pays its write cost, later changes pay the access cost, and restoring its original value earns a refund.
Account balances have no equivalent rule. [EIP-8038](./eip-8038.md) charges `ACCOUNT_WRITE` on every value-bearing call, even if the same accounts were changed earlier in the transaction.
The result is that a token balance implemented in contract storage enjoys accurate metering while native ether does not. Ether is the only asset on Ethereum whose repeated movement is priced as if every hop were an independent state write.

This cost penalizes common composition patterns:

* **Forwarders and routers** that receive `msg.value` and pass it on pay twice for a balance change that cancels out. Under this EIP the pass-through hop nets `4000` gas, since the intermediary's balance returns to its original value.
* **Refund patterns** where a contract returns excess ether to the payer pay full price for balance changes that cancel. A complete round trip (deposit and return within one transaction) drops from `18000` to `8000` gas before the refund cap.
* **Batched operations**, including [EIP-7702](./eip-7702.md) delegated accounts executing multiple transfers, pay the full cost per transfer even when the same accounts are touched repeatedly. A contract distributing ether to `N` recipients pays the sender-side write `N` times; under this EIP it pays it once — and a delegated account's authorization already marks it as changed before execution begins.

An `N`-hop pass-through chain costs `9000 * N` today; under this EIP it nets `9000 + 4000 * (N - 1)` before the refund cap.

Pricing of the transaction-level value transfer is handled by [EIP-2780](./eip-2780.md) (`TX_VALUE_COST`); this EIP extends net metering to transfers performed during execution.

## Specification

### Parameters

| Constant | Value |
| - | - |
| `CALL_VALUE_BASE_GAS` | `4000` |
| `CLEAN_BALANCE_CHANGE_GAS` | `(ACCOUNT_WRITE - CALL_VALUE_BASE_GAS) / 2` (= `2500`) |
| `BALANCE_RESET_REFUND` | `CLEAN_BALANCE_CHANGE_GAS` (= `2500`) |
| `CALL_STIPEND` | `2300` (unchanged value; now a floor on the subcall gas limit) |

`ACCOUNT_WRITE` is `9000` under [EIP-8038](./eip-8038.md). The base accounts for the `2300` stipend and the [EIP-7708](./eip-7708.md) transfer log. Its `4000` value is close to their combined `4056` gas cost. Since `CALL_VALUE_BASE_GAS + 2 * CLEAN_BALANCE_CHANGE_GAS = ACCOUNT_WRITE`, a call that changes two clean accounts consumes `9000` gas, the same as `CALL_VALUE - CALL_STIPEND` under EIP-8038.

### Definitions

* **Original balance** and **original nonce**: the values at the start of the transaction, adjusted for the sender's upfront gas debit and nonce increment, and for the transaction's value transfer. A self-transfer changes neither balance. A contract-creation transaction transfers value to its deployment address. No [EIP-7702](./eip-7702.md) authorization is included in these original values.
* **Current balance** and **current nonce**: the values an account holds immediately before the metered operation.
* **New balance**: the balance an account would hold immediately after the metered transfer.

An account is *clean* if its *current balance* equals its *original balance* and its *current nonce* equals its *original nonce*; it is *dirty* (changed) otherwise.

The order is: derive the original values from the pre-transaction state; check intrinsic gas, debit the sender's gas, and increment its nonce; initialize the gas counters and process authorizations; warm the recipient and apply the remaining runtime charges; apply the transaction-level transfer; then enter the first EVM frame. [EIP-2780](./eip-2780.md) specifies the pre-execution charges. The original values are a comparison baseline, not a snapshot taken during execution. They exclude authorization changes even though authorizations are processed before the transaction-level transfer.

### Value transfer cost

Replace the flat `CALL_VALUE` charge for a nonzero-value `CALL` (`0xF1`) or `CALLCODE` (`0xF2`) with the following:

* Charge `CALL_VALUE_BASE_GAS`.
* Apply the [balance change charge](#balance-change-charge) to the account being debited (the currently executing account), with *new balance* equal to *current balance* minus the transferred value.
* Apply the [balance change charge](#balance-change-charge) to the account being credited (the call target), with *new balance* equal to *current balance* plus the transferred value.
* A self-transfer via `CALL` changes no balance, so it pays only `CALL_VALUE_BASE_GAS`. The same applies to `CALLCODE` with nonzero value.

When the transferred value is nonzero, the gas stipend acts as a floor on the subcall's gas limit.
Let *gas limit* be the gas the caller makes available to the callee, after the 63/64 rule is applied.
The *gas limit* is evaluated against `CALL_STIPEND`: if it is at least `CALL_STIPEND`, the call proceeds with ordinary call semantics and no adjustment; if it is lower, the callee's gas limit is raised to `CALL_STIPEND`.
No gas is added on top of the *gas limit* — the additive stipend is removed.
Gas granted by the raise is prepaid by `CALL_VALUE_BASE_GAS` and is not returned. On success or revert, the caller receives `min(callee_gas_remaining, gas limit)`, using the original *gas limit*. If the call fails before entering a child frame because of insufficient balance or call depth, the caller receives the original *gas limit*.

All other components of the call cost are unchanged:

* The [EIP-2929](./eip-2929.md) account access cost, memory expansion cost and the base call cost are charged as before.
* The new-account state-gas charge of [EIP-8037](./eip-8037.md) continues to apply when the transferred value is nonzero and the call target is dead, as defined in [EIP-161](./eip-161.md).
* The [EIP-7708](./eip-7708.md) transfer log continues to be emitted for nonzero-value calls to a different account; its cost is a component of `CALL_VALUE_BASE_GAS`.
* Calls with zero value are unaffected by this EIP.

The charges above are applied at the time the call instruction executes, before computing the 63/64 rule's gas limit for the callee, exactly as the replaced `CALL_VALUE` charge was.
If the call subsequently fails without performing the transfer — because the debited account's balance is insufficient or the call depth limit is reached — the charges are still consumed, matching current behavior, but no refund is issued and no balance changes.

### Balance change charge

For an account with a given *original balance*, *current balance* and *new balance*, where *new balance* differs from *current balance*:

* If the account is clean, charge `CLEAN_BALANCE_CHANGE_GAS`.
* If the account is dirty, charge nothing.
  Additionally, if *new balance* equals *original balance* and *current nonce* equals *original nonce* (the account has returned to its original state), add `BALANCE_RESET_REFUND` to the refund counter.

The refund counter is the existing transaction-scoped counter used by `SSTORE` refunds:
additions revert together with the call frame they were made in, and the total refund applied at the end of the transaction is capped as specified in [EIP-3529](./eip-3529.md).
This EIP never removes gas from the refund counter.

### EIP-7702 authorization processing

Applying a valid [EIP-7702](./eip-7702.md) authorization tuple increments the authority's nonce and sets its code.
Because the original nonce excludes authorization processing, an applied authorization leaves the authority dirty for later calls. Its nonce cannot return to the original value within the transaction, so a balance change involving that authority cannot earn `BALANCE_RESET_REFUND`. Authorization charges, including the first-write `ACCOUNT_WRITE` rule of [EIP-2780](./eip-2780.md), remain unchanged.

### Interaction with other account-modifying operations

Dirtiness is derived solely from comparing balances and nonces against their original values, so a change effected by any means updates the metering of subsequent operations.
In particular, the value endowment of `CREATE` and `CREATE2` and the balance sweep of `SELFDESTRUCT` make the affected accounts dirty, as do nonce changes: a `CREATE` or `CREATE2` increments the creator's nonce and initializes the created account's nonce, and authorization processing increments the authority's nonce.

The gas costs of `CREATE`, `CREATE2` and `SELFDESTRUCT` (as restricted by [EIP-6780](./eip-6780.md)) are themselves unchanged by this EIP, to keep the change minimal.

Gas costs and semantics not specified above remain unchanged.
`DELEGATECALL` and `STATICCALL` transfer no value and are unaffected.

## Rationale

### Per-account decomposition of the value transfer cost

The `CALL_VALUE` charge is a lump sum: [EIP-8038](./eip-8038.md) defines it as `ACCOUNT_WRITE + CALL_STIPEND`, charged on every value-bearing call. The unused stipend normally returns to the caller, making the effective cost `ACCOUNT_WRITE = 9000`.
The base of `4000` prices the stipend and the [EIP-7708](./eip-7708.md) transfer log together. The account access cost is already charged separately under [EIP-2929](./eip-2929.md). The remaining `5000` is split between the two accounts: each clean account that changes pays `2500`. A dirty account pays no further balance-change charge. Thus, a call changing two clean accounts costs `9000`, while one changing two dirty accounts costs `4000`.

[EIP-7973](./eip-7973.md) proposes a similar discount for repeated account writes. This EIP uses the cost components of EIP-8038, specifies a refund when a balance change is undone, and leaves `SSTORE` pricing unchanged.

A self-transfer, or `CALLCODE` with value, changes no balance and costs the base alone.
They emit no [EIP-7708](./eip-7708.md) log, but still pay the same base so the cost rule stays simple.

### Gas stipend as a gas limit floor

The stipend guarantees a callee at least `2300` gas when the caller forwards none, as Solidity's `transfer` and `send` do. The floor keeps that guarantee. A caller that forwards more gas no longer receives an additional `2300`.

Under the old additive rule, unused stipend gas returns to the caller. With a `4000` base and no clean-account charges, returning that gas would make a repeated transfer cost as little as `1700`. The new rule prepays any gas needed to reach the floor and does not return that extra gas.

### Nonce as part of the dirtiness predicate

An account leaf contains its balance and nonce. `CREATE`/`CREATE2` and [EIP-7702](./eip-7702.md) authorizations can change the nonce without changing the balance. Including the nonce prevents a refund when the balance returns to its original value but the leaf still needs a write. Code changes in these operations also increment the nonce. Storage-root changes are outside this EIP's predicate.

### Baseline at the start of execution

The baseline includes the transaction-level transfer so a sender and recipient without authorizations start EVM execution clean. Otherwise, the transfer could make an account appear dirty without paying this EIP's clean-account charge, and a later return to the baseline could earn a refund without a prior charge.

Authorizations are excluded so that an authority's nonce increment remains visible to subsequent calls. The sender's transaction nonce increment is included because it is already covered by `TX_BASE_COST`.

### Refund soundness

For each account, a `BALANCE_RESET_REFUND` must be backed by an earlier charge. A balance change from a clean account pays `CLEAN_BALANCE_CHANGE_GAS`, equal to the refund. A `CREATE`/`CREATE2` endowment or a `SELFDESTRUCT` sweep also pays more than the refund. An account whose nonce changes cannot earn the refund. After a refund, the account is clean again, so another round trip pays the clean charge again.
The [EIP-3529](./eip-3529.md) cap of `gas_used // MAX_REFUND_QUOTIENT` bounds total refunds as defense in depth.

## Backwards Compatibility

This EIP requires a hard fork, since it modifies gas metering rules.

The value-transfer charge is no higher than the current effective `9000` gas for a call that changes two clean accounts, and is lower when either account is dirty. The changed stipend can still affect execution: a callee given an explicit gas limit above zero may receive less gas and may fail where it previously succeeded.

Two observable behaviors change.
A callee's gas limit becomes `max(gas_limit, CALL_STIPEND)` instead of `gas_limit + CALL_STIPEND`: a callee invoked with an explicitly chosen gas limit receives up to `2300` less gas than before, while the stipend guarantee that deployed zero-forwarding patterns (`transfer`/`send`) rely on is preserved exactly.
The caller also no longer receives unused gas from a stipend-funded increase to the callee's limit. A contract that reads `gasleft()` around a value call can observe a different amount, especially if the callee follows a different execution path.

Two economic (non-consensus) effects should be noted:

* Contracts that rely on the cost of a value transfer as an implicit rate limit on repeated deposits or withdrawals within one transaction will find repetition cheaper.
* Gas estimation becomes order-dependent, as it already is for [EIP-2929](./eip-2929.md) warm and cold access: the cost of a value call depends on prior account changes within the transaction. Wallets and RPC providers must estimate against the transaction's actual starting state.

## Test Cases

The table below lists the value-transfer component of gas consumed by the caller, excluding the [EIP-2929](./eip-2929.md) access cost, base call cost and memory costs.
All accounts are warm and existing, have sufficient balances (except where noted), callees consume no gas, and `x` and `y` are distinct nonzero values.
Arrows denote a `CALL` transferring the indicated value.
The "Before this EIP" column is effective consumption: the `CALL_VALUE` charge (`11300`) less the `2300` unused stipend returned under current rules. "Net" subtracts the refund earned in these examples before applying the transaction refund cap.
Calls that create a new account additionally incur the unchanged [EIP-8037](./eip-8037.md) new-account state-gas charges under both columns.

| Scenario | Charged | Refund | Net | Before this EIP |
| - | - | - | - | - |
| `A→B x` | 9000 | 0 | 9000 | 9000 |
| `A→B x; A→B x` | 13000 | 0 | 13000 | 18000 |
| `A→B x; B→C x` | 15500 | 2500 | 13000 | 18000 |
| `A→B x; B→C y` | 15500 | 0 | 15500 | 18000 |
| `A→B x; B→A x` | 13000 | 5000 | 8000 | 18000 |
| `A→A x` (self-transfer) | 4000 | 0 | 4000 | 9000 |
| `CALLCODE` with value `x` | 4000 | 0 | 4000 | 9000 |
| `A→B x`, balance of `A` less than `x` | 9000 | 0 | 9000 | 9000 |

Worked example for `A→B x; B→C x`:
the first call charges `4000 + 2500 + 2500 = 9000` (both accounts clean).
The second call charges the `4000` base, nothing for dirty `B`, and `2500` for clean `C`, totaling `6500`; because `B`'s new balance equals its original balance, `2500` is added to the refund counter.

Gas stipend floor cases, for a value call with subcall gas limit `g` and a callee that consumes `s` gas:

* `g = 0` (e.g. Solidity `transfer`): the gas limit is raised to `2300`; no gas returns to the caller.
* `0 < g < 2300`: the gas limit is raised to `2300`; `min(2300 - s, g)` gas returns to the caller.
* `g >= 2300`: no raise occurs; the callee runs with `g` gas and unused gas returns in full — ordinary call semantics, with no additive stipend.
* The call fails on insufficient balance or depth limit: `g` gas is returned.

Account-change cases involving nonces and [EIP-7702](./eip-7702.md) authorizations:

* A transaction carrying an authorization for `B`, whose execution then performs `A→B x`: the transfer charges `4000 + 2500 = 6500`, since the applied authorization left `B` dirty.
* An authorization for `tx.sender` leaves the sender dirty for later calls, while its `ACCOUNT_WRITE` charge remains governed by EIP-2780.
* Contract `A` performs a `CREATE` and then `A→B x`: `A`'s nonce differs from its original, so the transfer charges `4000 + 2500 = 6500`.
* `A→B x`, then `B` performs a `CREATE`, then `B→A x`: `A` earns `BALANCE_RESET_REFUND`, but `B` does not — its balance came full circle while its nonce changed, so its account leaf must still be written.

Tests should additionally cover: reverted sub-frames restoring cleanliness and rolling back refunds; the gas stipend floor under callee revert; transfers interleaved with `CREATE` endowments and `SELFDESTRUCT` sweeps; cleanliness of the transaction sender and recipient at the start of execution, including a self-sponsored authorization dirtying the sender; and the [EIP-3529](./eip-3529.md) refund cap.
Test cases in `ethereum/execution-spec-tests` are to be added.

## Security Considerations

### Gas stipend amplification

A value-bearing call runs its callee with a gas limit of at least `CALL_STIPEND`.
Gas above the caller's chosen gas limit exists only when that limit is below `CALL_STIPEND`; it is bounded by `CALL_STIPEND`, prepaid by the base charge, and never returned.
If a value call could be charged less than that floor, floor gas could recursively fund further value calls, each level of such a self-sustaining chain running on a fresh floor and producing call frames, balance updates and [EIP-7708](./eip-7708.md) transfer logs paid for by gas the transaction never supplied.
Under this EIP the cheapest value call costs `CALL_VALUE_BASE_GAS = 4000 > 2300`, so a callee running on the floor can never fund another value-bearing call, and a transaction with gas limit `G` can never cause more than `G` gas of execution, with no dependence on the size of the per-account charge.
Any future cost change must preserve `CALL_VALUE_BASE_GAS > CALL_STIPEND`, currently `4000 > 2300`.

### Transfer log volume

[EIP-7708](./eip-7708.md) emits a transfer log for every nonzero-value `CALL` to a different account and relies on the transfer cost to bound log volume.
Even the cheapest log-emitting transfer pays the `4000` base, more than the `1756` gas cost of the equivalent `LOG3` with 32 data bytes. Self-transfers emit no log but still pay the base.
Refunds cannot push the per-log cost below this floor, since every `BALANCE_RESET_REFUND` is preceded by an equal clean charge on the same account and every transfer consumes the full base.
Emitting logs through value transfers therefore never becomes cheaper than emitting them directly with the `LOG` opcodes, and the worst-case log volume per block remains governed by the `LOG` opcodes themselves.

## Copyright

Copyright and related rights waived via [CC0](../LICENSE.md).
