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
Summary
Functions
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.
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.
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.
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.
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).
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.
Functions
@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.
@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.
@spec call_stipend(non_neg_integer()) :: non_neg_integer()
@spec call_value_cost(non_neg_integer()) :: non_neg_integer()
@spec code_deposit_cost(non_neg_integer()) :: non_neg_integer()
@spec copy_cost(non_neg_integer()) :: non_neg_integer()
@spec create2_hash_cost(non_neg_integer()) :: non_neg_integer()
@spec exp_dynamic_cost(non_neg_integer(), EEVM.HardforkConfig.t()) :: non_neg_integer()
@spec keccak256_dynamic_cost(non_neg_integer()) :: non_neg_integer()
@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.
@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.
@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).
@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}