Part III · Chapter 11 of 43 · Byzantium

EIP-214: STATICCALL — a call that promises not to touch anything

Contracts constantly call other contracts just to read a value — a price, a balance, a view function. But a normal call lets the callee do whatever it wants, including change state or re-enter you. STATICCALL is a call that the EVM guarantees is read-only: any attempt to modify state inside it reverts. A small guarantee that quietly underpins oracles, view functions, and reentrancy safety.

Updated Sep 13, 2026 · 8 min
Assumed
  • the EVM call model
  • state & reentrancy

Byzantium, October 2017. Byzantium’s third landmark (after REVERT and the zk precompiles) is a new kind of call. Contracts constantly need to ask another contract something — the current price from an oracle, a balance, the result of a view function. But in the EVM, “ask” and “act” used the same instruction: a CALL runs the callee’s code, and that code can do anything. So merely reading from a contract you don’t fully trust meant handing it the keys. EIP-214 adds STATICCALL: a call the protocol guarantees can’t change a thing. Let’s derive it.

1 step Reading is dangerous

The problem: a CALL to read grants full power

When your contract does a plain CALL to fetch a value, the EVM runs the callee’s code, and there’s nothing stopping that code from doing more than answer. It can SSTORE to its own storage, emit logs, create contracts — or, most dangerously, reentrancy When a contract you call calls back into you before your first function has finished, potentially catching you in a half-updated state. The classic drain-the-vault attack. A read that can trigger arbitrary code is a reentrancy risk. — call back into you mid-execution, catching you in an inconsistent state. So calling an untrusted contract just to read a number was a genuine attack surface: the act of asking a question let the answerer run arbitrary code.

you just want to read — but a CALL lets the callee do anything your contract CALL oracle.price() read? re-enters you ↩ untrusted contract SSTORE · reenter · LOG it can mutate state or re-enter — reading became an attack surface you had no way to say 'call this, but you may not change anything'
A plain CALL to read a value still runs the callee's full code — it can write state, emit logs, or re-enter your contract mid-call. Reading from an untrusted contract became an attack surface, and you had no way to say 'call this, but you may not change anything.'

→ Step 2: a call the EVM forces to be read-only.

2 step A read-only call

STATICCALL: state changes revert, guaranteed

STATICCALL The Byzantium opcode 0xFA. It calls a contract like CALL, but marks the entire call frame — and every sub-call it makes — as static: any state-modifying opcode encountered inside it reverts. The result is a call guaranteed to be read-only. (opcode 0xFA) runs the callee exactly like CALL, with one iron rule: for the duration of that frame and all of its sub-calls, any state-changing opcode reverts. SSTORE, CREATE, SELFDESTRUCT, LOG, a value-bearing CALL — all forbidden. The callee can read all it likes (SLOAD, compute, call other views) to produce an answer, but it cannot alter storage, emit events, or move value. So a STATICCALL is a guaranteed read: the callee can’t reenter-and-mutate, because it can’t mutate at all.

STATICCALL — run it, but forbid any state change your contract STATICCALL 0xFA read-only frame SLOAD · view ✓ SSTORE · CREATE ✗ any write → revert the whole call frame (and its sub-calls) can't touch state a guaranteed read — the callee can't reenter-and-mutate
STATICCALL (0xFA) runs the callee in a read-only frame: SLOAD and pure computation are fine, but any state-changing opcode — SSTORE, CREATE, LOG, value transfer — reverts. The restriction covers the whole frame and its sub-calls, so the callee simply can't change anything.

→ Step 3: what a read-only guarantee unlocks.

3 step Where it's load-bearing

The payoff: safe reads, view functions, reentrancy safety

A guaranteed read-only call is a small primitive with a wide footprint. It lets a contract read an untrusted oracle without fear that the oracle mutates state or re-enters. It’s how Solidity enforces view / pure calls Solidity functions marked view (read state) or pure (read nothing) are called via STATICCALL, so the compiler's promise that they don't modify state is actually enforced by the EVM, not just by convention. at the EVM level — the compiler compiles calls to view functions as STATICCALL, so the “doesn’t modify state” promise is enforced, not merely declared. And it’s a foundational tool for reentrancy safety: a static call can’t reenter and write, so read paths become safe by construction.

a guaranteed read-only call — the building block for… safe oracle reads read untrusted safely view / pure calls compiler-enforced reentrancy safety can't reenter + write read but not write — a small guarantee with wide reach
A guaranteed read-only call underpins safe reads from untrusted oracles, EVM-enforced view/pure functions, and reentrancy safety — a static call can't reenter and write. One small guarantee, wide reach.
04 Go Deeper Where to take it from here