Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions EIPS/eip-2780.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ A transaction’s intrinsic base is decomposed into explicit primitives, so warm

- if a contract, use `COLD_ACCOUNT_COST_CODE = 2,600`.

- if a [EIP-7702](./eip-7702.md) delegated account, use `COLD_ACCOUNT_COST_CODE = 2,600`. The delegation target incurs an additional `COLD_ACCOUNT_COST_CODE = 2,600` if cold, or `WARM_STATE_READ = 100` if already warm.

- if a precompile, it is warm at tx start and charged zero.

- Warmth discovered through an access list still applies and overrides the cold cost.
Expand Down Expand Up @@ -271,12 +273,14 @@ These changes refine execution-layer accounting to align with the primitives abo

| Case | Formula | Total Cost |
| ----------------------------------- | ---------------------------------------------------------------- | -------------------------:|
| (NOP) No-transfer to EOA | `TX_BASE_COST` | 4,500 |
| (NOP) No-transfer to empty account | `TX_BASE_COST` | 4,500 |
| (NOP) No-transfer to EOA | `TX_BASE_COST` + `COLD_ACCOUNT_COST_NOCODE` | 5,000 |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TX_BASE_COST already includes a COLD_ACCOUNT_COST_NOCODE for the sender. Can you explain why we are doing another charge for the receiver? In a no-transfer, is the receiver accessed?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. In the table, no-transfer to a contract charges TX_BASE_COST + COLD_ACCOUNT_COST_CODE. But we can't know if the account has code or not, without accessing it. This kind of forces us to load the account anyway which is why an additional charge for the EOA reciever is necessary

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that is correct

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense! Good catch

@misilva73 misilva73 Apr 22, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, thinking a bit about this and it does not make sense to me now. I understand we need to load the account before knowing whether it is a CODE or NOCODE cost. However, that does not mean we are actually doing two cold reads from the account trie. We are still only doing 1 and then charging a different value based on whether the account has code or not. Or am I missing something?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand. My thinking is that since we are forced to load the receiver account, we should either charge COLD_ACCOUNT_COST_NOCODE or COLD_ACCOUNT_COST_CODE depending on the account type (in addition to TX_BASE_COST).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, the TX_BASE_COST only includes the sender access cost. Apologies, this is what I was missing. I will approve now

| (NOP) No-transfer to empty account | `TX_BASE_COST` + `COLD_ACCOUNT_COST_NOCODE` | 5,000 |
| (NOP) ETH transfer to self | `TX_BASE_COST` | 4,500 |
| ETH Transfer to existing EOA | `TX_BASE_COST` + `COLD_ACCOUNT_COST_NOCODE` + `STATE_UPDATE` + `TRANSFER_LOG_COST` | 7,756 |
| No-transfer to contract | `TX_BASE_COST` + `COLD_ACCOUNT_COST_CODE` + **execution** | 7,100 + **execution** |
| ETH Transfer to contract | `TX_BASE_COST` + `COLD_ACCOUNT_COST_CODE` + `STATE_UPDATE` + `TRANSFER_LOG_COST` + **execution** | 9,856 + **execution** |
| No-transfer to 7702 delegated | `TX_BASE_COST` + `2 * COLD_ACCOUNT_COST_CODE` + **execution** | 9,700 + **execution** |
| ETH Transfer to 7702 delegated | `TX_BASE_COST` + `2 * COLD_ACCOUNT_COST_CODE` + `STATE_UPDATE` + `TRANSFER_LOG_COST` + **execution** | 12,456 + **execution** |
| ETH Transfer creating new account | `TX_BASE_COST` + `COLD_ACCOUNT_COST_NOCODE` + `GAS_NEW_ACCOUNT` + `TRANSFER_LOG_COST` | 31,756 |

This aligns costs with actual state work rather than legacy flat surcharges.
Expand All @@ -285,8 +289,9 @@ This aligns costs with actual state work rather than legacy flat surcharges.

- **[EIP-2930](./eip-2930.md) (Access List).** Intrinsic gas is `TX_BASE_COST` after `FORK_BLOCK`. Access lists keep their existing per-entry charges and warming semantics.
- **[EIP-2929](./eip-2929.md) (Gas cost increases for state access).** Refined by this EIP to price non-code cold touches at `500` and code-account cold touches at `2,600`.
- **[EIP-7702](./eip-7702.md) (Set EOA Code).** `TX_BASE_COST` remains `4,500` even if the sender temporarily assumes code for the transaction. Clients must not perform any disk code-load to determine sender type, since 7702 provides code inline. If the transaction executes code that reads or executes its own code, normal `COLD_ACCOUNT_COST_CODE` or `WARM_STATE_READ` costs apply at execution time as per the standard cold/warm model.
- **[EIP-7702](./eip-7702.md) (Set EOA Code).** `TX_BASE_COST` remains `4,500` even if the sender temporarily assumes code for the transaction. Clients must not perform any disk code-load to determine sender type, since 7702 provides code inline. If the transaction executes code that reads or executes its own code, normal `COLD_ACCOUNT_COST_CODE` or `WARM_STATE_READ` costs apply at execution time as per the standard cold/warm model. When `tx.to` is a 7702-delegated account, it is charged `COLD_ACCOUNT_COST_CODE = 2,600` at the intrinsic level. Resolving the delegation requires loading code from the delegation target, which incurs its own `COLD_ACCOUNT_COST_CODE = 2,600` if the target is cold, or `WARM_STATE_READ = 100` if already warm. This also applies to calls made to delegated accounts.
- **[EIP-7708](./eip-7708.md) (ETH transfers emit a log).** EIP-7708 emits a LOG3 transfer event for every nonzero-value ETH transfer. Under the legacy `21,000` base this cost was absorbed; with a reduced base it must be charged explicitly. This EIP introduces `TRANSFER_LOG_COST = 1,756` (LOG3 equivalent: `375 + 3×375 + 32×8`) applied to top-level value transfers, value-moving `CALL`s, and nonzero-value `SELFDESTRUCT` when it transfers value to a different account; for `SELFDESTRUCT`, the charge is applied at the point that transfer is processed.
- **[EIP-7928](./eip-7928.md) (Block-Level Access Lists).** The two-tier cold-access model (`COLD_ACCOUNT_COST_NOCODE` vs `COLD_ACCOUNT_COST_CODE`) requires loading the account from disk before the correct charge can be determined. For cold accounts, at least `COLD_ACCOUNT_COST_NOCODE` gas must be available before account access is attempted; if unavailable, the operation fails with out-of-gas without accessing the account. Once an account access is attempted, the account is added to the transaction's accessed set for the BAL. Thereafter, if the account is found to have code, the account read remains in the BAL even if the available gas is less than `COLD_ACCOUNT_COST_CODE` and the call frame fails with out-of-gas.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks correct to me, but wanted to double check with @nerolation - do you see any issues with this?

- **Calldata-pricing EIPs (e.g. [EIP-7623](./eip-7623.md)).** Unchanged. This EIP does not alter calldata pricing.

## Rationale
Expand Down
Loading