principlejavascriptCritical
Reentrancy vulnerability: the checks-effects-interactions pattern
Viewed 0 times
Solidity 0.8.x, OpenZeppelin 5.x
reentrancychecks-effects-interactionsnonReentrantReentrancyGuardsecurityThe DAO
Problem
A function that sends ETH or calls an external contract before updating state allows a malicious contract to re-enter and drain funds, as seen in The DAO hack.
Solution
Always follow checks-effects-interactions: validate inputs, update state, then call external contracts. Use OpenZeppelin's ReentrancyGuard for critical functions.
function withdraw(uint256 amount) external nonReentrant {
require(balances[msg.sender] >= amount); // check
balances[msg.sender] -= amount; // effect
(bool ok,) = msg.sender.call{value: amount}(''); // interaction
require(ok);
}Why
When a contract calls an external address, control flow passes to that address. If internal state hasn't been updated yet, the external call can re-enter and exploit the stale state.
Gotchas
- Transfer and send have a 2300 gas stipend that prevents reentrancy but are deprecated — use call instead with reentrancy guards
- Cross-function reentrancy is possible even if a single function is protected — all state-modifying functions need consistent guards
- Read-only reentrancy is a subtler variant where a view function is exploited mid-transaction
Code Snippets
Safe withdrawal following checks-effects-interactions
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import '@openzeppelin/contracts/utils/ReentrancyGuard.sol';
contract SafeVault is ReentrancyGuard {
mapping(address => uint256) public balances;
function deposit() external payable {
balances[msg.sender] += msg.value;
}
function withdraw(uint256 amount) external nonReentrant {
require(balances[msg.sender] >= amount, 'Insufficient balance'); // Check
balances[msg.sender] -= amount; // Effect (before external call)
(bool ok, ) = msg.sender.call{value: amount}(''); // Interaction
require(ok, 'Transfer failed');
}
}Context
Auditing or writing contracts that handle ETH withdrawals or interact with untrusted external contracts
Revisions (0)
No revisions yet.