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.
- 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.
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.
→ Step 2: a call the EVM forces to be read-only.
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.
→ Step 3: what a read-only guarantee unlocks.
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.