# `EEVM.Gas.Dynamic`
[🔗](https://github.com/mw2000/eevm/blob/v0.1.0/lib/eevm/gas/dynamic.ex#L1)

Dynamic gas costs that depend on opcode operands at runtime.

Unlike static costs (which are fixed per opcode), dynamic costs vary based on
the actual values being operated on — the size of data being hashed, the number
of log topics, the storage slot transition, etc.

## Covered Opcodes

| Opcode | Dynamic Cost | Reference |
|--------|-------------|-----------|
| EXP | 50 × byte_size(exponent); 10 before Spurious Dragon | EIP-160 |
| KECCAK256 | 6 × word_count(size) | Yellow Paper |
| CALLDATACOPY, CODECOPY, RETURNDATACOPY | 3 × word_count(size) | Yellow Paper |
| LOG0–LOG4 | 375 × topics + 8 × data_size (the 375 base is static) | Yellow Paper |
| CREATE2 | 6 × word_count(initcode_size) | EIP-1014 |
| CREATE/CREATE2 deploy | 200 × code_size | Yellow Paper |
| CALL value transfer | 9,000 gas | Yellow Paper |
| CALL, SELFDESTRUCT new account creation | 25,000 gas | Yellow Paper, EIP-150, EIP-161 |
| CALL gas forwarding | min(requested, available - available/64); requested before Tangerine Whistle | EIP-150 |
| CALL value stipend | 2,300 gas | Yellow Paper |
| SSTORE | per-fork schedule, see `sstore_cost/4` | EIP-2200, EIP-2929, EIP-3529 |

## References

- [Ethereum Yellow Paper, Appendix H](https://ethereum.github.io/yellowpaper/paper.pdf)
- [EIP-150: Gas cost changes for IO-heavy operations](https://eips.ethereum.org/EIPS/eip-150)
- [EIP-1014: Skinny CREATE2](https://eips.ethereum.org/EIPS/eip-1014)
- [EIP-2200: Structured Definitions for Net Gas Metering](https://eips.ethereum.org/EIPS/eip-2200)
- [EIP-2929: Gas cost increases for state access opcodes](https://eips.ethereum.org/EIPS/eip-2929)
- [EIP-3529: Reduction in refunds](https://eips.ethereum.org/EIPS/eip-3529)

# `call_forwarded_gas`

```elixir
@spec call_forwarded_gas(
  non_neg_integer(),
  non_neg_integer(),
  EEVM.HardforkConfig.t()
) ::
  non_neg_integer()
```

Gas a CALL-family or CREATE opcode hands to its child frame. From Tangerine
Whistle (EIP-150) the caller keeps 1/64 of what it has left and the request
is capped at the rest; before, the full request is forwarded, and a request
above the available gas is an out-of-gas error in the caller.

# `call_new_account_cost`

```elixir
@spec call_new_account_cost(
  boolean(),
  boolean(),
  non_neg_integer(),
  EEVM.HardforkConfig.t()
) ::
  non_neg_integer()
```

25,000 when a CALL brings an account into existence. From Spurious Dragon
(EIP-161) that is a value transfer to an empty account; before, a call to
any account that does not exist.

# `call_stipend`

```elixir
@spec call_stipend(non_neg_integer()) :: non_neg_integer()
```

# `call_value_cost`

```elixir
@spec call_value_cost(non_neg_integer()) :: non_neg_integer()
```

# `code_deposit_cost`

```elixir
@spec code_deposit_cost(non_neg_integer()) :: non_neg_integer()
```

# `copy_cost`

```elixir
@spec copy_cost(non_neg_integer()) :: non_neg_integer()
```

# `create2_hash_cost`

```elixir
@spec create2_hash_cost(non_neg_integer()) :: non_neg_integer()
```

# `exp_dynamic_cost`

```elixir
@spec exp_dynamic_cost(non_neg_integer(), EEVM.HardforkConfig.t()) ::
  non_neg_integer()
```

# `keccak256_dynamic_cost`

```elixir
@spec keccak256_dynamic_cost(non_neg_integer()) :: non_neg_integer()
```

# `log_cost`

```elixir
@spec log_cost(non_neg_integer(), non_neg_integer()) :: non_neg_integer()
```

Dynamic part of LOG0–LOG4: 375 per topic plus 8 per data byte. The 375
base (G_log) is the opcode's static cost in `EEVM.Gas.Static`.

# `selfdestruct_new_account_cost`

```elixir
@spec selfdestruct_new_account_cost(
  boolean(),
  boolean(),
  non_neg_integer(),
  EEVM.HardforkConfig.t()
) :: non_neg_integer()
```

25,000 when SELFDESTRUCT brings its beneficiary into existence: from
Tangerine Whistle (EIP-150) when the beneficiary does not exist, and from
Spurious Dragon (EIP-161) only when a non-zero balance moves to an empty
account. Nothing before Tangerine Whistle.

# `selfdestruct_refund`

```elixir
@spec selfdestruct_refund(boolean(), EEVM.HardforkConfig.t()) :: non_neg_integer()
```

Refund for a SELFDESTRUCT: 24,000 before London when the account has not
already been destroyed in this transaction (`destroyed?`), 0 from London
(EIP-3529).

# `sstore_cost`

```elixir
@spec sstore_cost(
  non_neg_integer(),
  non_neg_integer(),
  non_neg_integer(),
  EEVM.HardforkConfig.t()
) ::
  {non_neg_integer(), integer()}
```

Returns `{gas, refund_delta}` for an SSTORE writing `new_value` over
`current`, where `original` is the slot's value at the start of the
transaction. The cold-slot charge (EIP-2929) is separate, in
`EEVM.Gas.Access.sstore_access_cost/3`.

- Before Istanbul: 20,000 to set a zero slot, 5,000 for any other write,
  and a 15,000 refund for clearing one.
- Istanbul (EIP-2200) net metering: writes that leave the slot unchanged
  or touch an already-dirty slot cost SLOAD_GAS (800); refunds track
  whether the write clears the slot or restores its original value.
- Berlin (EIP-2929): SLOAD_GAS becomes 100 and the 5,000 reset cost 2,900.
- London (EIP-3529): the clearing refund drops to 4,800.

## Examples

    iex> EEVM.Gas.Dynamic.sstore_cost(7, 7, 0, EEVM.HardforkConfig.new(:byzantium))
    {5000, 15000}

    iex> EEVM.Gas.Dynamic.sstore_cost(7, 7, 0, EEVM.HardforkConfig.new(:istanbul))
    {5000, 15000}

    iex> EEVM.Gas.Dynamic.sstore_cost(7, 9, 9, EEVM.HardforkConfig.new(:istanbul))
    {800, 0}

    iex> EEVM.Gas.Dynamic.sstore_cost(7, 7, 0, EEVM.HardforkConfig.new(:london))
    {2900, 4800}

---

*Consult [api-reference.md](api-reference.md) for complete listing*
