Skip to main content
Important: We do not provide financial advice or custody funds. All transactions occur on third-party platforms.

Reentrancy: Classic & Cross-Function

The DAO hack, the CEI pattern, ReentrancyGuard, and the read-only and cross-function variants that still drain protocols a decade later.

40 min · expert · part of Smart Contract Security & Auditing

The DAO: Where It All Started

On June 17, 2016, an attacker drained roughly **3.6 million ETH** (worth approximately **$60 million** at the time, and a much larger sum at today's prices) from The DAO — a decentralized investment fund that had raised about $150 million in the largest crowdfunding event in history up to that point. The bug they exploited was a reentrancy vulnerability so canonical that it now defines an entire category. The vulnerable code looked, in essence, like this: ```solidity function withdraw() public { uint amount = balances[msg.sender]; (bool ok, ) = msg.sender.call{value: amount}(""); require(ok); balances[msg.sender] = 0; // state update AFTER the call } ``` The attacker created a malicious contract whose fallback function called `withdraw` again. When The DAO's `withdraw` sent ETH to that contract, the fallback fired *before* The DAO had a chance to zero out the balance. So the attacker's recorded balance was still non-zero, and they could withdraw again. And again. And again, recursively, until either The DAO ran out of funds or the gas ran out. **The aftermath shaped Ethereum forever.** A contentious hard fork on July 20, 2016 (block 1,920,000) effectively reversed the hack, returning the stolen ETH to a recovery contract. A faction rejected the fork on philosophical grounds (immutability above all else) and continued the original chain, which became Ethereum Classic (ETC). The fork is the foundational event that gave us today's ETH-vs-ETC split, and the bug that caused it is the reason every Solidity developer learns about reentrancy on day one. The remarkable thing is that nearly a decade later, reentrancy bugs still happen — just in more sophisticated variants. The pattern of "external call before state update" is easy to write and surprisingly easy to overlook in code review.

Also in this lesson

  • Checks-Effects-Interactions (CEI)
  • ReentrancyGuard: The Belt-and-Suspenders Defense
  • Read-Only Reentrancy
  • Cross-Function and Cross-Contract Reentrancy
  • Solidity 0.8.x and Modern Defenses

Key terms

Reentrancy
A class of vulnerability where a contract makes an external call before fully updating its own state, allowing the called contract to re-enter and exploit the inconsistent state — the bug class that drained The DAO in June 2016.
The DAO hack
June 17, 2016 exploit that drained roughly 3.6 million ETH (~$60M at the time) from The DAO via reentrancy. Led to the contentious July 20, 2016 hard fork that produced today's Ethereum / Ethereum Classic split.
Checks-Effects-Interactions (CEI)
The canonical defense pattern for reentrancy: validate inputs first (checks), then update all state (effects), then make external calls last (interactions). Ensures any reentrant call sees fully-updated state.
ReentrancyGuard
OpenZeppelin's mutex-based reentrancy lock, exposed via the nonReentrant modifier. Reverts if any guarded function is called recursively. ReentrancyGuardTransient (2024) uses EIP-1153 transient storage for lower gas.
Read-only reentrancy
A reentrancy variant where the attacker exploits view functions that return stale or inconsistent state during a multi-step external call, often to manipulate a different protocol that reads that view as a price oracle. Implicated in the July 2023 Curve incident.
Cross-function reentrancy
Reentrancy that re-enters a different function on the same contract — not the originally-called function — to exploit shared state. Defeated by applying the same reentrancy lock to all functions that touch the same state.
Cross-contract reentrancy
Reentrancy across contract boundaries within a protocol, where a guard on contract A doesn't protect the state in contract B that A interacts with.
Solidity 0.8.x built-in overflow checks
Since Solidity 0.8.0 (Dec 16, 2020), arithmetic over/underflow reverts by default, eliminating the need for SafeMath. The unchecked { } block opts out for performance.
EIP-1153 transient storage
Transaction-scoped storage that resets at end of transaction, shipped in the Dencun upgrade (March 13, 2024). Used in ReentrancyGuardTransient for substantially cheaper reentrancy locks.
ERC-777 hook reentrancy
Token standards with transfer callbacks (ERC-777, ERC-1363) can re-enter on every transfer. Famously exploited against Uniswap V1 imBTC and others; one reason ERC-777 is now generally discouraged.

Continue this lesson — 5 more sections in the CryptoBipto app.

Open lesson

Educational only — not financial advice.