A comprehensive reference for the Ethereum Virtual Machine (EVM), compiled from evm.codes, ethereum.org, and wolflo/evm-opcodes. This page holds the detailed notes: full opcode tables with gas and stack behavior, gas cost formulas, precompiled contracts, hardfork changes, and additional resources. For a short primer and the opcode threat index, see Threat Models.
Table of Contents
- What Is the EVM?
- Execution Environment
- Opcode Reference Table
- Opcode Categories
- Gas Costs
- Dynamic Gas Cost Formulas
- Precompiled Contracts
- Additional Resources
What Is the EVM?
The Ethereum Virtual Machine is a stack-based computer responsible for executing smart contract instructions. Key properties:
- Stack-based: All instructions take parameters from the stack (except
PUSHx, which reads from code). - Deterministic: The same input always produces the same output across all nodes.
- 256-bit word size: All stack items are 32 bytes (256 bits).
- Max stack depth: 1024 items.
- Opcodes: Values 0x00 through 0xFF (0-255), each with a mnemonic name. The EVM currently implements ~141 opcodes, 65 of which are parametric variants (
PUSHn,DUPn,SWAPn,LOGn).
Smart Contract Execution
A smart contract is a sequence of opcodes. The EVM reads and executes each instruction sequentially, except:
- JUMP / JUMPI: Alter the program counter to a
JUMPDEST. - REVERT: Halts execution, reverts state, refunds unused gas.
- STOP / RETURN: Halts execution normally.
If an instruction cannot execute (insufficient gas, stack underflow), execution reverts and all state changes are rolled back.
Execution Environment
When the EVM executes a contract, it creates a call context with the following data regions:
| Region | Persistence | Access Opcodes | Description |
|---|---|---|---|
| Code | Permanent (on-chain) | CODESIZE, CODECOPY, EXTCODESIZE, EXTCODECOPY | Immutable contract bytecode |
| Stack | Per call context | PUSHn, POP, DUPn, SWAPn | LIFO list of 32-byte elements, max 1024 items |
| Memory | Per call context | MLOAD, MSTORE, MSTORE8, MSIZE | Byte-addressable, initialized to zero, volatile |
| Storage | Permanent (on-chain) | SLOAD, SSTORE | 32-byte key → 32-byte value mapping, per contract |
| Transient Storage | Per transaction | TLOAD, TSTORE | Like storage but cleared after each transaction (EIP-1153) |
| Calldata | Per call context | CALLDATALOAD, CALLDATASIZE, CALLDATACOPY | Immutable input data for the call |
| Return Data | Per call context | RETURNDATASIZE, RETURNDATACOPY | Data returned from the last external call |
Program Counter (PC)
The PC tracks the next instruction to execute. It increments by 1 byte per instruction, except:
PUSHnskips the nextnbytes (its immediate data).JUMP/JUMPIset the PC to a specifiedJUMPDEST.
Opcode Reference Table
Notation:
a, b => a + bmeans the opcode popsaandbfrom the stack and pushes the result..represents “nothing” (no stack input/output).- All arithmetic is modulo 2^256. Division by zero returns 0.
0x00-0x0B: Stop & Arithmetic
| Hex | Name | Gas | Stack | Description |
|---|---|---|---|---|
| 00 | STOP | 0 | — | Halt execution |
| 01 | ADD | 3 | a, b ⇒ a + b | Addition modulo 2^256 |
| 02 | MUL | 5 | a, b ⇒ a * b | Multiplication modulo 2^256 |
| 03 | SUB | 3 | a, b ⇒ a - b | Subtraction modulo 2^256 |
| 04 | DIV | 5 | a, b ⇒ a // b | Unsigned integer division |
| 05 | SDIV | 5 | a, b ⇒ a // b | Signed integer division |
| 06 | MOD | 5 | a, b ⇒ a % b | Unsigned modulus |
| 07 | SMOD | 5 | a, b ⇒ a % b | Signed modulus |
| 08 | ADDMOD | 8 | a, b, N ⇒ (a + b) % N | Addition modulo N |
| 09 | MULMOD | 8 | a, b, N ⇒ (a * b) % N | Multiplication modulo N |
| 0A | EXP | dynamic | a, b ⇒ a ** b | Exponentiation modulo 2^256 |
| 0B | SIGNEXTEND | 5 | b, x ⇒ SIGNEXTEND(x, b) | Sign-extend x from (b+1) bytes to 32 bytes |
0x10-0x1D: Comparison & Bitwise Logic
| Hex | Name | Gas | Stack | Description |
|---|---|---|---|---|
| 10 | LT | 3 | a, b ⇒ a < b | Unsigned less-than |
| 11 | GT | 3 | a, b ⇒ a > b | Unsigned greater-than |
| 12 | SLT | 3 | a, b ⇒ a < b | Signed less-than |
| 13 | SGT | 3 | a, b ⇒ a > b | Signed greater-than |
| 14 | EQ | 3 | a, b ⇒ a == b | Equality |
| 15 | ISZERO | 3 | a ⇒ a == 0 | Is zero |
| 16 | AND | 3 | a, b ⇒ a & b | Bitwise AND |
| 17 | OR | 3 | a, b ⇒ a | b | Bitwise OR |
| 18 | XOR | 3 | a, b ⇒ a ^ b | Bitwise XOR |
| 19 | NOT | 3 | a ⇒ ~a | Bitwise NOT |
| 1A | BYTE | 3 | i, x ⇒ (x >> (248 - i*8)) & 0xFF | Extract byte at position i |
| 1B | SHL | 3 | shift, val ⇒ val << shift | Shift left |
| 1C | SHR | 3 | shift, val ⇒ val >> shift | Logical shift right |
| 1D | SAR | 3 | shift, val ⇒ val >> shift | Arithmetic shift right |
0x20: Cryptographic
| Hex | Name | Gas | Stack | Description |
|---|---|---|---|---|
| 20 | KECCAK256 | dynamic | offset, length ⇒ keccak256(mem[offset:offset+length]) | Compute Keccak-256 hash |
0x30-0x3F: Environmental Information
| Hex | Name | Gas | Stack | Description |
|---|---|---|---|---|
| 30 | ADDRESS | 2 | . ⇒ address(this) | Address of executing contract |
| 31 | BALANCE | dynamic | addr ⇒ addr.balance | Balance in wei (warm/cold access) |
| 32 | ORIGIN | 2 | . ⇒ tx.origin | Transaction originator address |
| 33 | CALLER | 2 | . ⇒ msg.sender | Direct caller address |
| 34 | CALLVALUE | 2 | . ⇒ msg.value | Value sent with call, in wei |
| 35 | CALLDATALOAD | 3 | idx ⇒ msg.data[idx:idx+32] | Read 32-byte word from calldata |
| 36 | CALLDATASIZE | 2 | . ⇒ len(msg.data) | Calldata size in bytes |
| 37 | CALLDATACOPY | dynamic | dstOst, ost, len ⇒ . | Copy calldata to memory |
| 38 | CODESIZE | 2 | . ⇒ len(this.code) | Size of executing contract code |
| 39 | CODECOPY | dynamic | dstOst, ost, len ⇒ . | Copy contract code to memory |
| 3A | GASPRICE | 2 | . ⇒ tx.gasprice | Gas price of transaction |
| 3B | EXTCODESIZE | dynamic | addr ⇒ len(addr.code) | Size of external contract code |
| 3C | EXTCODECOPY | dynamic | addr, dstOst, ost, len ⇒ . | Copy external code to memory |
| 3D | RETURNDATASIZE | 2 | . ⇒ size | Size of last call’s return data |
| 3E | RETURNDATACOPY | dynamic | dstOst, ost, len ⇒ . | Copy return data to memory |
| 3F | EXTCODEHASH | dynamic | addr ⇒ hash | Keccak-256 of external code |
0x40-0x4A: Block Information
| Hex | Name | Gas | Stack | Description |
|---|---|---|---|---|
| 40 | BLOCKHASH | 20 | blockNum ⇒ blockHash(blockNum) | Hash of a recent block (last 256) |
| 41 | COINBASE | 2 | . ⇒ block.coinbase | Current block proposer address |
| 42 | TIMESTAMP | 2 | . ⇒ block.timestamp | Current block timestamp |
| 43 | NUMBER | 2 | . ⇒ block.number | Current block number |
| 44 | PREVRANDAO | 2 | . ⇒ randomness_beacon | Randomness beacon (post-Merge; was DIFFICULTY) |
| 45 | GASLIMIT | 2 | . ⇒ block.gaslimit | Current block gas limit |
| 46 | CHAINID | 2 | . ⇒ chain_id | Current chain ID (EIP-155) |
| 47 | SELFBALANCE | 5 | . ⇒ address(this).balance | Balance of executing contract |
| 48 | BASEFEE | 2 | . ⇒ block.basefee | Base fee of current block (EIP-1559) |
| 49 | BLOBHASH | 3 | idx ⇒ tx.blob_versioned_hashes[idx] | Blob versioned hash (EIP-4844) |
| 4A | BLOBBASEFEE | 2 | . ⇒ block.blobbasefee | Blob base fee (EIP-7516) |
0x50-0x5F: Stack, Memory, Storage & Flow
| Hex | Name | Gas | Stack | Description |
|---|---|---|---|---|
| 50 | POP | 2 | _ ⇒ . | Remove top stack item |
| 51 | MLOAD | 3* | offset ⇒ mem[offset:offset+32] | Load word from memory |
| 52 | MSTORE | 3* | offset, val ⇒ . | Store word to memory |
| 53 | MSTORE8 | 3* | offset, val ⇒ . | Store single byte to memory |
| 54 | SLOAD | dynamic | key ⇒ storage[key] | Load word from storage |
| 55 | SSTORE | dynamic | key, val ⇒ . | Store word to storage |
| 56 | JUMP | 8 | dst ⇒ . | Set PC to dst (must be JUMPDEST) |
| 57 | JUMPI | 10 | dst, cond ⇒ . | Conditional jump |
| 58 | PC | 2 | . ⇒ $pc | Current program counter |
| 59 | MSIZE | 2 | . ⇒ len(mem) | Size of active memory in bytes |
| 5A | GAS | 2 | . ⇒ gasRemaining | Remaining gas |
| 5B | JUMPDEST | 1 | — | Mark valid jump destination |
| 5C | TLOAD | 100 | key ⇒ tstorage[key] | Load from transient storage (EIP-1153) |
| 5D | TSTORE | 100 | key, val ⇒ . | Store to transient storage (EIP-1153) |
| 5E | MCOPY | dynamic | dst, src, len ⇒ . | Copy memory area (EIP-5656) |
| 5F | PUSH0 | 2 | . ⇒ 0 | Push zero onto stack (EIP-3855) |
* Plus memory expansion cost if applicable.
0x60-0x7F: Push Operations
All PUSH opcodes cost 3 gas and push 1-32 bytes from the code onto the stack.
| Hex | Name | Bytes Pushed |
|---|---|---|
| 60 | PUSH1 | 1 byte (uint8) |
| 61 | PUSH2 | 2 bytes (uint16) |
| 62 | PUSH3 | 3 bytes (uint24) |
| … | … | … |
| 7F | PUSH32 | 32 bytes (uint256) |
0x80-0x8F: Duplication Operations
All DUP opcodes cost 3 gas. DUPn clones the nth stack item to the top.
| Hex | Name | Stack Effect |
|---|---|---|
| 80 | DUP1 | a ⇒ a, a |
| 81 | DUP2 | _, a ⇒ a, _, a |
| … | … | … |
| 8F | DUP16 | ..., a ⇒ a, ..., a |
0x90-0x9F: Swap Operations
All SWAP opcodes cost 3 gas. SWAPn swaps the top stack item with the (n+1)th item.
| Hex | Name | Stack Effect |
|---|---|---|
| 90 | SWAP1 | a, b ⇒ b, a |
| 91 | SWAP2 | a, _, b ⇒ b, _, a |
| … | … | … |
| 9F | SWAP16 | a, ..., b ⇒ b, ..., a |
0xA0-0xA4: Logging
| Hex | Name | Gas | Stack | Description |
|---|---|---|---|---|
| A0 | LOG0 | dynamic | offset, length ⇒ . | Log with 0 topics |
| A1 | LOG1 | dynamic | offset, length, topic0 ⇒ . | Log with 1 topic |
| A2 | LOG2 | dynamic | offset, length, topic0, topic1 ⇒ . | Log with 2 topics |
| A3 | LOG3 | dynamic | offset, length, topic0, topic1, topic2 ⇒ . | Log with 3 topics |
| A4 | LOG4 | dynamic | offset, length, topic0, topic1, topic2, topic3 ⇒ . | Log with 4 topics |
0xF0-0xFF: System Operations
| Hex | Name | Gas | Stack | Description |
|---|---|---|---|---|
| F0 | CREATE | dynamic | val, offset, length ⇒ addr | Create new contract; addr = keccak256(rlp([sender, nonce])) |
| F1 | CALL | dynamic | gas, addr, val, argOst, argLen, retOst, retLen ⇒ success | Call another contract |
| F2 | CALLCODE | dynamic | gas, addr, val, argOst, argLen, retOst, retLen ⇒ success | Like DELEGATECALL but doesn’t propagate msg.sender/value |
| F3 | RETURN | 0* | offset, length ⇒ . | Return data from memory |
| F4 | DELEGATECALL | dynamic | gas, addr, argOst, argLen, retOst, retLen ⇒ success | Call with caller’s context |
| F5 | CREATE2 | dynamic | val, offset, length, salt ⇒ addr | Create with deterministic address |
| FA | STATICCALL | dynamic | gas, addr, argOst, argLen, retOst, retLen ⇒ success | Read-only call (no state modification) |
| FD | REVERT | 0* | offset, length ⇒ . | Revert with return data, refund unused gas |
| FE | INVALID | all gas | — | Designated invalid opcode; consumes all gas |
| FF | SELFDESTRUCT | dynamic | addr ⇒ . | Mark contract for destruction, send ETH to addr |
* Plus memory expansion cost if applicable.
Opcode Categories
| Category | Opcodes | Purpose |
|---|---|---|
| Arithmetic | ADD, MUL, SUB, DIV, SDIV, MOD, SMOD, ADDMOD, MULMOD, EXP, SIGNEXTEND | Math operations on 256-bit integers |
| Comparison | LT, GT, SLT, SGT, EQ, ISZERO | Boolean comparisons returning 0 or 1 |
| Bitwise | AND, OR, XOR, NOT, BYTE, SHL, SHR, SAR | Bit manipulation |
| Cryptographic | KECCAK256 | Hashing |
| Environmental | ADDRESS, BALANCE, ORIGIN, CALLER, CALLVALUE, CALLDATALOAD, CALLDATASIZE, CALLDATACOPY, CODESIZE, CODECOPY, GASPRICE, EXTCODESIZE, EXTCODECOPY, RETURNDATASIZE, RETURNDATACOPY, EXTCODEHASH | Context about the call and external contracts |
| Block | BLOCKHASH, COINBASE, TIMESTAMP, NUMBER, PREVRANDAO, GASLIMIT, CHAINID, SELFBALANCE, BASEFEE, BLOBHASH, BLOBBASEFEE | Current block/chain info |
| Stack/Memory/Storage | POP, MLOAD, MSTORE, MSTORE8, SLOAD, SSTORE, TLOAD, TSTORE, MCOPY, PUSH0, PUSH1-32, DUP1-16, SWAP1-16 | Data manipulation |
| Flow Control | JUMP, JUMPI, PC, MSIZE, GAS, JUMPDEST, STOP | Execution flow |
| Logging | LOG0-LOG4 | Emit event logs |
| System | CREATE, CALL, CALLCODE, RETURN, DELEGATECALL, CREATE2, STATICCALL, REVERT, INVALID, SELFDESTRUCT | Contract interaction and lifecycle |
Gas Costs
Intrinsic Gas
Every transaction pays gas before any opcode execution:
| Component | Cost |
|---|---|
| Base transaction | 21,000 gas |
| Contract creation (tx.to == null) | +32,000 gas |
| Calldata zero byte | 4 gas/byte |
| Calldata non-zero byte | 16 gas/byte (64 before Istanbul) |
Memory Expansion
Memory grows dynamically. Cost is quadratic in size, computed as:
memory_size_word = (memory_byte_size + 31) / 32
memory_cost = (memory_size_word ** 2) / 512 + (3 * memory_size_word)
expansion_cost = new_memory_cost - previous_memory_cost
Memory cost is linear up to ~724 bytes, then grows quadratically. Opcodes that trigger expansion include: MLOAD, MSTORE, MSTORE8, RETURN, REVERT, CALLDATACOPY, CODECOPY, EXTCODECOPY, RETURNDATACOPY, CREATE, CALL, etc. A zero-length access does not trigger expansion.
Access Sets (EIP-2929, Post-Berlin)
Two transaction-wide sets track “touched” addresses and storage slots:
| Access Type | Warm Cost | Cold Cost |
|---|---|---|
| Address (BALANCE, EXTCODESIZE, etc.) | 100 gas | 2,600 gas |
| Storage slot (SLOAD) | 100 gas | 2,100 gas |
Addresses initialized as warm at transaction start:
tx.senderandtx.to- All precompiled contract addresses (post-Berlin)
- The COINBASE address (post-Shanghai)
EIP-2930 allows transactions to pre-populate access sets: 2,400 gas per address, 1,900 gas per (address, slot) pair.
Gas Refunds
Only SSTORE can trigger refunds (post-London/EIP-3529). Maximum refund is capped at 1/5 of total transaction gas consumed. Refunds are applied at transaction end; they do not prevent out-of-gas failures during execution.
Dynamic Gas Cost Formulas
EXP (0x0A)
gas_cost = 10 + 50 * byte_len_exponent
Where byte_len_exponent is the number of bytes in the exponent.
KECCAK256 (0x20)
data_size_words = (data_size + 31) / 32
gas_cost = 30 + 6 * data_size_words + mem_expansion_cost
COPY Operations (CALLDATACOPY, CODECOPY, RETURNDATACOPY)
data_size_words = (data_size + 31) / 32
gas_cost = 3 + 3 * data_size_words + mem_expansion_cost
EXTCODECOPY
data_size_words = (data_size + 31) / 32
gas_cost = access_cost + 3 * data_size_words + mem_expansion_cost
Where access_cost = 100 (warm) or 2,600 (cold).
SLOAD
gas_cost = 100 (warm)
gas_cost = 2100 (cold)
SSTORE
The most complex gas calculation, depending on current value, new value, original value, and warm/cold access:
| Scenario | Gas Cost | Refund |
|---|---|---|
| Cold access surcharge | +2,100 | — |
| No-op (new == current) | +100 | — |
| Clean slot: 0 → nonzero | +20,000 | — |
| Clean slot: nonzero → different nonzero | +2,900 | — |
| Clean slot: nonzero → 0 | +2,900 | +4,800 |
| Dirty slot (any change) | +100 | varies |
| Dirty slot reset to original nonzero | +100 | +2,800 |
| Dirty slot reset to original zero | +100 | +19,900 |
Minimum 2,300 gas must remain to execute SSTORE (backward compatibility).
LOG Operations
gas_cost = 375 + 375 * num_topics + 8 * data_size + mem_expansion_cost
CREATE
gas_cost = 32000 + mem_expansion_cost + code_deposit_cost
code_deposit_cost = 200 * returned_code_size
CREATE2
data_size_words = (init_code_size + 31) / 32
gas_cost = 32000 + 6 * data_size_words + mem_expansion_cost + code_deposit_cost
CALL Operations
base_gas = access_cost + mem_expansion_cost
| Condition | Additional Cost |
|---|---|
Sending value (call_value > 0) | +9,000 gas |
| Creating new account (CALL only, value > 0 to empty address) | +25,000 gas |
Gas forwarded with call:
remaining_gas = available_gas - base_gas
all_but_one_64th = remaining_gas - (remaining_gas / 64)
gas_sent_with_call = min(requested_gas, all_but_one_64th)
If call_value > 0, a 2,300 gas stipend is added to the gas sent (but not to the cost).
SELFDESTRUCT
gas_cost = 5000
+ 25000 (if balance > 0 AND target is empty)
+ 2600 (if target is cold)
Precompiled Contracts
Precompiled contracts are special functions bundled into the EVM at fixed addresses. They are called like regular contracts via CALL, STATICCALL, etc. After Berlin, all precompile addresses are always warm.
For all precompiles: if input is shorter than expected, it is zero-padded at the end. Surplus bytes are ignored.
| Address | Name | EIP | Gas | Description |
|---|---|---|---|---|
| 0x01 | ecRecover | — | 3,000 | ECDSA public key recovery from signature |
| 0x02 | SHA2-256 | — | 60 + 12 * words | SHA-256 hash |
| 0x03 | RIPEMD-160 | — | 600 + 120 * words | RIPEMD-160 hash |
| 0x04 | Identity | — | 15 + 3 * words | Returns input unchanged (data copy) |
| 0x05 | ModExp | EIP-198 | dynamic | Modular exponentiation: base^exp % mod |
| 0x06 | ecAdd | EIP-196 | 150 | Point addition on alt_bn128 elliptic curve |
| 0x07 | ecMul | EIP-196 | 6,000 | Scalar multiplication on alt_bn128 |
| 0x08 | ecPairing | EIP-197 | 45,000 + 34,000 * pairs | Bilinear pairing check on alt_bn128 |
| 0x09 | blake2f | EIP-152 | per rounds | BLAKE2b compression function F |
Precompile Details
ecRecover (0x01): Recovers the signer address from an ECDSA signature. Input: 128 bytes (hash, v, r, s). Output: 32 bytes (left-padded address).
SHA2-256 (0x02): Standard SHA-256 hash. Input: arbitrary bytes. Output: 32 bytes.
RIPEMD-160 (0x03): RIPEMD-160 hash. Input: arbitrary bytes. Output: 32 bytes (left-padded to 32 bytes from 20-byte hash).
Identity (0x04): Returns input data unchanged. Useful for copying memory via CALL.
ModExp (0x05): Computes base^exponent % modulus for arbitrary-precision integers. Gas cost depends on input sizes and exponent magnitude.
ecAdd (0x06): Adds two points on the BN256 (alt_bn128) elliptic curve. Used in zk-SNARK verification.
ecMul (0x07): Multiplies a point on BN256 by a scalar. Used in zk-SNARK verification.
ecPairing (0x08): Checks a bilinear pairing equation on BN256. Fundamental for zk-SNARK proof verification. Input: k pairs of (G1 point, G2 point). Returns 1 if pairing check passes, 0 otherwise.
blake2f (0x09): Runs the BLAKE2b compression function F for a given number of rounds. Enables BLAKE2b interoperability for cross-chain verification (e.g., Zcash).
Key Hardfork Changes
| Hardfork | EIPs | Notable Changes |
|---|---|---|
| Istanbul | EIP-1884, EIP-2028 | Calldata cost reduced from 64 to 16 gas/byte (non-zero). SLOAD increased to 800 gas. |
| Berlin | EIP-2929, EIP-2930 | Warm/cold access pricing. Optional access lists. |
| London | EIP-3529, EIP-1559 | Gas refund cap reduced to 1/5. SELFDESTRUCT no longer provides refund. Base fee mechanism. |
| Shanghai | EIP-3651 | COINBASE address is warm at start of transaction. |
| Cancun | EIP-1153, EIP-4844, EIP-5656, EIP-7516 | Transient storage (TLOAD/TSTORE). Blob transactions (BLOBHASH). MCOPY opcode. BLOBBASEFEE. |
Additional Resources
- evm.codes — Interactive opcode reference with playground
- evm.codes Playground — Step-through EVM execution debugger
- Ethereum Yellow Paper — Formal EVM specification
- Jello Paper — Readable rewrite of the Yellow Paper
- wolflo/evm-opcodes — Gas cost reference
- Ethereum EVM Illustrated (2018) — Visual EVM guide
- EVM Deep Dives by noxx — Deep technical series
- Mastering Ethereum - EVM Chapter — Book chapter on EVM internals
- EVM: Solidity to Bytecode (Video) — From Solidity to memory and storage
- EOF Full Guide — EVM Object Format
- Remix IDE — Solidity IDE with gas estimation
- smlxl Blog — EVM and blockchain writeups
*Sources: evm.codes, ethereum.org/opcodes, wolflo/evm-opcodes.