Abstract
This EIP introduces net gas metering for account changes, mirroring the scheme EIP-2200 established for storage, on top of the transaction gas structure of EIP-2780.
An account counts as changed once its balance or nonce differs from its value at the start of the transaction.
The value transfer cost of CALL and CALLCODE — CALL_VALUE, defined by EIP-8038 as ACCOUNT_WRITE + CALL_STIPEND — is replaced by CALL_VALUE_BASE_GAS, itemized as the stipend plus the EIP-7708 transfer log and consumed in full when charged, plus CLEAN_BALANCE_CHANGE_GAS for each modified account whose balance or nonce has not yet changed in the transaction; already-changed accounts add nothing.
When a transfer returns an account to its original balance while its nonce is unchanged, BALANCE_RESET_REFUND is added to the refund counter, and EIP-2780's runtime ACCOUNT_WRITE charge for an EIP-7702 authorization is conditioned on the same predicate.
The gas stipend becomes a floor on the subcall gas limit: if a value-bearing subcall's gas limit is below CALL_STIPEND it is raised to CALL_STIPEND, and gas granted by the raise is not returned.
A transfer between two unmodified accounts costs 8000 gas, matching the current effective cost; a transfer between two already-modified accounts costs only the base of 4000 gas.
Motivation
The gas cost of an in-execution value transfer is flat per transfer — CALL_VALUE, currently ACCOUNT_WRITE + CALL_STIPEND = 10300, an effective 8000 since the unused portion of the 2300 stipend routinely returns to the caller — regardless of whether the affected accounts were already modified within the same transaction.
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-1283, EIP-2200, EIP-2929 and EIP-3529, refined by EIP-8038: the first change of a slot pays the full write cost, subsequent changes pay WARM_ACCESS (100) gas, and a slot reset to its original value earns a refund.
Account balances — the most frequently written state on Ethereum — never received the same treatment: EIP-8038 names ACCOUNT_WRITE a surcharge for changing an account leaf "for the first time", but for CALL it is charged flat on every transfer, with no first-change tracking.
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 mispricing penalizes common composition patterns:
- Forwarders and routers that receive
msg.valueand pass it on pay twice for what is, in state, a single transfer. Under this EIP the pass-through hop nets4000gas, since the intermediary's balance returns full circle to its original value. - Refund patterns where a contract returns excess ether to the payer pay full price for balance changes that partially or fully cancel. A complete round trip (deposit and return within one transaction) drops from an effective
16000to a net8000gas. - Batched operations, including EIP-7702 delegated accounts executing multiple transfers, pay the full cost per transfer even when the same accounts are touched repeatedly. A contract distributing ether to
Nrecipients pays the sender-side writeNtimes; 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 an effective 8000 * N today; under this EIP it nets 8000 + 4000 * (N - 1), a 38% reduction at N = 4.
Pricing of the transaction-level value transfer is handled by EIP-2780 (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 (= 2000) |
BALANCE_RESET_REFUND | = CLEAN_BALANCE_CHANGE_GAS (= 2000) |
CALL_STIPEND | 2300 (unchanged value; now a floor on the subcall gas limit) |
TRANSFER_LOG_COST | 1756 (per EIP-2780; a LOG3 with 32 data bytes, unchanged) |
CALL_VALUE_BASE_GAS is CALL_STIPEND + TRANSFER_LOG_COST (2300 + 1756 = 4056) rounded to 4000; ACCOUNT_WRITE (currently 8000) is the parameter of EIP-8038, and retuning it there retunes this schedule.
Note that CALL_VALUE_BASE_GAS + 2 * CLEAN_BALANCE_CHANGE_GAS = ACCOUNT_WRITE: since the base is consumed in full, a transfer between two unmodified accounts costs exactly the current effective cost, CALL_VALUE - CALL_STIPEND.
Definitions
- Original balance and original nonce: the balance and nonce an account holds after the transaction's intrinsic effects, excluding authorization processing: after the up-front gas purchase and nonce increment of the transaction sender and after the transaction-level value transfer, but before EIP-7702 authorization processing. For accounts not touched by these intrinsic operations, these equal the account's values at the start of the transaction. Although authorization processing precedes the transaction-level value transfer, the baseline is well defined without a snapshot: it is the pre-transaction state adjusted by the statically known gas purchase, sender nonce increment and transaction value. Note that for the transaction sender and recipient the original balance deliberately differs from the balance they would hold if the transaction were reverted; see Rationale.
- 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.
Value transfer cost
The flat CALL_VALUE charge applied by CALL (0xF1) when the transferred value is nonzero is replaced by the following:
- Charge
CALL_VALUE_BASE_GAS. - Apply the 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 to the account being credited (the call target), with new balance equal to current balance plus the transferred value.
- If the debited and credited accounts are the same account — a self-transfer via
CALL, or anyCALLCODEwith nonzero value, whose transfer debits and credits the executing account itself — no balance changes, so no balance change charge applies and the call costsCALL_VALUE_BASE_GASalone.
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/64ths 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: when the callee frame completes, whether by success or by revert, the gas returned to the caller is min(callee_gas_remaining, gas_limit) with the original, unraised gas limit, and if the call fails without creating a callee frame (insufficient balance or call depth limit) the unraised gas limit is returned.
All other components of the call cost are unchanged:
- The EIP-2929 account access cost, memory expansion cost and the base call cost are charged as before.
- The new-account state-gas charge of EIP-8037 continues to apply when the transferred value is nonzero and the call target is dead, as defined in EIP-161.
- The EIP-7708 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/64ths of remaining gas available to 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_REFUNDto 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.
This EIP never removes gas from the refund counter.
EIP-7702 authorization processing
Applying a valid EIP-7702 authorization tuple increments the authority's nonce and sets its code.
Because a nonce only ever increments, this makes the authority account dirty irreversibly: a nonce-dirtied account can never return to its original state within the transaction, and authorization processing can never trigger BALANCE_RESET_REFUND.
The only metering question at application time is therefore whether the authority is already dirty.
EIP-2780 charges ACCOUNT_WRITE at runtime, during authorization processing, if the authorization is the first write to the authority within the transaction, approximated there as the authority differing from tx.to.
This EIP replaces that approximation with the exact test: charge ACCOUNT_WRITE if and only if the authority is clean at the time the tuple is applied; a dirty authority incurs no account-write charge, its warm writes being already priced by REGULAR_PER_AUTH_BASE_COST.
During authorization processing an authority is dirty if it was targeted by an earlier tuple in the same list, and — when the transaction carries nonzero value — if it equals the transaction sender or recipient, whose current balance differs from the value-transfer-adjusted baseline.
The latter is intended: both of those leaves are written by the transaction's intrinsic effects, priced by TX_VALUE_COST, so their authorization carries no additional first-write cost.
Conversely, in a zero-value transaction an authority equal to tx.to is clean and is charged ACCOUNT_WRITE: the delegation itself is the first write to that leaf, a case the tx.to approximation exempted.
The intrinsic per-authorization cost (REGULAR_PER_AUTH_BASE_COST) and the state-gas charges of EIP-8037 are 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) 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 defines it as ACCOUNT_WRITE + CALL_STIPEND — a first-change account write surcharge that is nevertheless charged on every transfer, with the stipend portion routinely rebated to the caller when the callee does not use it, making the effective cost ACCOUNT_WRITE = 8000.
This EIP itemizes what a transfer actually consumes.
Two costs recur on every transfer regardless of prior account changes and form the base: the stipend granted to the callee and the EIP-7708 transfer log, their sum of 4056 rounded to 4000.
The account touch is deliberately not part of the base — it is already priced by the EIP-2929 access cost charged on every call, and including it again would charge the same touch twice.
The remainder, ACCOUNT_WRITE - CALL_VALUE_BASE_GAS = 4000, is the first-change write premium, split evenly across the two modified accounts as CLEAN_BALANCE_CHANGE_GAS = 2000 and charged only when the modified account is clean — giving ACCOUNT_WRITE the first-change semantics its definition claims.
A dirty account adds nothing: its leaf write was paid by its first change, and the in-memory balance update has no cost that the access charge does not already cover.
The clean-clean total equals the current effective cost of 8000 exactly, and the dirty-to-dirty cost is the bare base of 4000 — the stipend and the log, the only resources that transfer consumes anew.
A self-transfer, or CALLCODE with value, changes no balance and costs the base alone.
Such transfers move value to the same account and emit no EIP-7708 log, yet still pay the TRANSFER_LOG_COST component of the base; a single unconditional base was preferred over a conditional charge for an operation that is already a no-op.
Gas stipend as a gas limit floor
The additive stipend served one purpose: guaranteeing the callee of a value transfer enough gas to run minimal receive logic even when the caller forwards none.
The guarantee deployed contracts rely on is the floor — Solidity's transfer and send forward zero gas and expect exactly CALL_STIPEND to arrive — not the addition of 2300 on top of an explicitly forwarded budget.
Restating the gas stipend as a floor on the subcall's gas limit preserves the guarantee while shrinking the special case: a gas limit of at least CALL_STIPEND gives a value call ordinary call semantics, and only below it does the base-prepaid raise exist, as use-it-or-lose-it gas.
Under current rules the unused portion of the additive stipend returns to the caller, so a parent frame ends a value call with up to 2300 gas it never paid for.
With the flat CALL_VALUE charge this rebate is harmless, but combined with a schedule whose dirty path charges only the base it becomes an exploit surface: the parent would recover most of the charge, and the effective cost of a dirty transfer would collapse to charge - 2300.
Prepaying the worst-case top-up inside CALL_VALUE_BASE_GAS and never returning it makes the caller's payment final: the parent can never be rewarded gas from a child call.
The combination strictly dominates the current rules for callers.
For a value call whose gas limit is at least CALL_STIPEND and whose callee consumes s gas, the caller's remaining gas afterwards is G - charge - s compared to G - 8000 - s today; since charge <= 8000, the caller is always left with at least as much gas, with equality exactly for a transfer between two unmodified accounts.
Below a gas limit of CALL_STIPEND the caller does better still, as part of the callee's consumption is drawn from the prepaid raise.
Nonce as part of the dirtiness predicate
The resource being metered is the account trie leaf, which commits to the account's nonce, balance, storage root and code hash; a change to any of them forces the same end-of-block leaf write.
Including the nonce in the predicate captures the in-execution sources of leaf writes that a balance comparison misses: CREATE/CREATE2 incrementing the creator's nonce, the initialization of a newly created account, and EIP-7702 authorization processing.
The nonce also guards the reset refund: an account whose balance comes full circle but whose nonce changed still requires a leaf write, so BALANCE_RESET_REFUND demands both conditions.
Because a nonce only ever increases, this guard is permanent — a nonce-dirtied account can never return to clean within the transaction.
Code changes need no separate clause because every operation that changes an account's code within a transaction also increments its nonce.
Storage-root changes are deliberately excluded: detecting "any slot of this account changed" cannot be done by comparing two field values and would require per-account dirty-slot tracking; a future EIP may extend the predicate.
Exact first-write predicate for authorizations
EIP-2780 already charges the state-dependent portion of authorization cost at runtime, during authorization processing, where the authority's state is readable — but it approximates "first write to the authority" with the static condition that the authority differ from tx.to.
With dirtiness tracking available, the approximation is replaced by the exact test at no additional implementation cost, and the two predicates identify the same event in almost every case, since the only writes preceding authorization processing are the transaction's intrinsic effects and earlier tuples.
The exact test diverges from the approximation twice, both times in the right direction.
An authority equal to the sender or recipient of a value-bearing transaction is dirty against the value-transfer-adjusted baseline, so it is exempt from ACCOUNT_WRITE — correctly, as TX_VALUE_COST already pays for those leaves.
An authority equal to tx.to of a zero-value transaction is clean, so it pays ACCOUNT_WRITE — correcting an undercharge of the approximation, which exempted a delegation that is in fact the first and only write to that leaf.
The larger effect runs in the other direction: every applied authorization marks its authority dirty, so subsequent transfers involving delegated accounts during execution are metered at the dirty rate.
Baseline at the start of execution
For storage, EIP-2200's original value — "the value if a reversion happens on the current transaction" — coincides with the value at the start of execution.
For balances the two differ: if the transaction reverts, the transaction-level value transfer is undone but the gas purchase is not.
Defining the baseline as the reversion state would make the transaction sender and recipient start execution dirty without any charged balance change, and a transfer returning the sender's balance to that baseline would mint an unbacked BALANCE_RESET_REFUND.
With an EIP-7702 delegated sender this becomes a loop: value out through the delegated account, value back from a cooperating contract, collecting 2000 of refund per round trip backed by no per-account charge at all.
Anchoring original balance at the start of execution — after the intrinsic gas purchase and value transfer — makes every account start clean, so every divergence from the baseline passes through a charged path and every refund is backed by a prior charge.
Authorization processing is deliberately excluded from the baseline. This lets the authorization rule observe whether an authority was already changed, and it means an applied delegation leaves the authority dirty for the whole execution phase, so transfers through delegated accounts take the dirty path. The transaction sender's nonce increment, by contrast, is included in the baseline, so the sender starts execution clean.
Refund soundness
The scheme maintains the invariant that, per account, gas added to the refund counter never exceeds gas previously charged for that account's divergence. An account can diverge from its original state only through:
- the clean branch of the balance change charge:
2000charged, equal to the2000refunded at most once per divergence; - a
CREATE/CREATE2endowment or nonce increment: at leastCREATE_ACCESS(11000) charged; - a
SELFDESTRUCTsweep: at least5000charged; - an applied EIP-7702 authorization on a clean authority:
ACCOUNT_WRITE(8000) charged.
Each divergence path charges at least BALANCE_RESET_REFUND, and after a refund the account is clean again, so repeating the cycle repeats the full clean charge; every transfer in such a cycle additionally consumes the full base.
The authorities exempt from ACCOUNT_WRITE — those equal to the sender or recipient of a value-bearing transaction — have their leaf writes paid by TX_VALUE_COST, and having changed nonces they can never satisfy the BALANCE_RESET_REFUND condition, so no refund can arise from an uncharged divergence.
The EIP-3529 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.
No gas cost increase is anticipated for value transfers. As shown in Rationale, the caller's remaining gas after a value call is always greater than or equal to what it would be under current rules, with equality only for transfers between unmodified accounts. Contracts that forward fixed gas amounts to sub-calls therefore cannot newly run out of gas.
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.
And a caller no longer receives unused stipend gas back, which arises only when its gas limit was below CALL_STIPEND; contracts that measure gasleft() around value calls are never left with less gas than under current rules, because the reduced charge more than compensates.
One authorization case becomes more expensive: an EIP-7702 authorization whose authority equals tx.to of a zero-value transaction is charged ACCOUNT_WRITE, which the tx.to approximation of EIP-2780 exempted.
This corrects an undercharge — the delegation is the first write to that leaf — rather than repricing correctly-charged behavior.
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 roughly twice as cheap; the stipend and the 63/64ths rule are untouched inside the callee frame, so stipend-based reentrancy protections are unaffected.
- Gas estimation becomes order-dependent, as it already is for EIP-2929 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 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 likewise effective consumption: the CALL_VALUE charge (10300) less the 2300 unused stipend returned under current rules.
Calls that create a new account additionally incur the unchanged EIP-8037 new-account state-gas charges under both columns.
| Scenario | Charged | Refund | Net | Before this EIP |
|---|---|---|---|---|
A→B x | 8000 | 0 | 8000 | 8000 |
A→B x; A→B x | 12000 | 0 | 12000 | 16000 |
A→B x; B→C x | 14000 | 2000 | 12000 | 16000 |
A→B x; B→C y | 14000 | 0 | 14000 | 16000 |
A→B x; B→A x | 12000 | 4000 | 8000 | 16000 |
A→A x (self-transfer) | 4000 | 0 | 4000 | 8000 |
CALLCODE with value x | 4000 | 0 | 4000 | 8000 |
A→B x, balance of A less than x | 8000 | 0 | 8000 | 8000 |
Worked example for A→B x; B→C x:
the first call charges 4000 + 2000 + 2000 = 8000 (both accounts clean).
The second call charges the 4000 base, nothing for dirty B, and 2000 for clean C, totaling 6000; because B's new balance equals its original balance, 2000 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. Soliditytransfer): the gas limit is raised to2300; no gas returns to the caller.0 < g < 2300: the gas limit is raised to2300;min(2300 - s, g)gas returns to the caller.g >= 2300: no raise occurs; the callee runs withggas and unused gas returns in full — ordinary call semantics, with no additive stipend.- The call fails on insufficient balance or depth limit:
ggas is returned.
Account-change cases involving nonces and EIP-7702 authorizations:
- A transaction carrying an authorization for
B, whose execution then performsA→B x: the transfer charges4000 + 2000 = 6000, since the applied authorization leftBdirty. - An authorization list containing two valid tuples for the same authority: only the first application charges
ACCOUNT_WRITE. - An authorization whose authority equals the sender or recipient of a value-bearing transaction: no
ACCOUNT_WRITEis charged. - An authorization whose authority equals
tx.toof a zero-value transaction:ACCOUNT_WRITEis charged. - Contract
Aperforms aCREATEand thenA→B x:A's nonce differs from its original, so the transfer charges4000 + 2000 = 6000. A→B x, thenBperforms aCREATE, thenB→A x:AearnsBALANCE_RESET_REFUND, butBdoes 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 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 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.
The invariant that must be preserved under any retuning is CALL_VALUE_BASE_GAS > CALL_STIPEND, currently 4000 > 2300 with a wide margin.
Transfer log volume
EIP-7708 emits a transfer log for every nonzero-value CALL to a different account and relies on the transfer cost to bound log volume.
This EIP prices the log explicitly: TRANSFER_LOG_COST is a component of CALL_VALUE_BASE_GAS, charged and consumed on every transfer, so even the cheapest log-emitting transfer — the bare base of 4000 gas between two changed accounts — pays more than the 1756 cost of the equivalent LOG3 with 32 data bytes.
Self-transfers emit no log yet still pay the component (see Rationale).
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.
