Checks-Effects-Interactions Explained in Detail
Checks-Effects-Interactions is a control-flow pattern for functions that touch state and then call external code. The safe order is: validate the request, update internal state, then perform the external interaction.
The pattern reduces the chance that a callback can observe stale balances, shares, debt, or permissions.
Smart contract example
The unsafe version sends ETH before clearing the balance:
function withdraw() external {
uint256 amount = balances[msg.sender];
require(amount > 0, "empty");
(bool ok,) = msg.sender.call{value: amount}("");
require(ok, "send failed");
balances[msg.sender] = 0;
}
The safer CEI order clears the balance before the external call:
function withdraw() external {
uint256 amount = balances[msg.sender];
require(amount > 0, "empty");
balances[msg.sender] = 0;
(bool ok,) = msg.sender.call{value: amount}("");
require(ok, "send failed");
}
Checks-Effects-Interactions in Auditing
CEI is a baseline review technique. It gives auditors a fast way to spot callback windows before deeper invariant testing.
CEI is not a complete defense. Cross-function reentrancy, read-only reentrancy, token hooks, and multi-contract state machines can still break a protocol that appears to follow CEI in one function. Use the reentrancy attack guide to trace those callback variants beyond a single withdrawal function.
Red flags in code
-
ETH transfer before balance, debt, share, or collateral updates.
-
Token transfer before accounting is finalized.
-
call,delegatecall, hooks, or callbacks inside sensitive functions. -
Partial state updates before an external interaction.
-
CEI applied to one function while sibling functions touch the same state.
-
Complex protocols relying on CEI without invariant tests.
How to test or review it
-
Mark every external interaction in the function.
-
List the state that is updated before and after each interaction.
-
Try a malicious receiver that calls back during the interaction.
-
Test same-function and cross-function callback paths.
-
Check whether protocol invariants hold during the callback window.
-
Pair CEI with a reentrancy guard when shared state remains exposed.
Keep learning this topic
Reentrancy
Reentrancy is a smart contract vulnerability where external code calls back into a contract before the first call finishes, often before balances, ownership, or other state has been updated.
Reentrancy Guard
A reentrancy guard is a lock that prevents a protected function from being entered again while it is already executing.
Read-Only Reentrancy
Read-only reentrancy happens when a view function returns stale or inconsistent state during an unfinished state transition, and another contract relies on that value.
Reentrancy
Reentrancy in Solidity explained with real exploit flow, vulnerable patterns, and practical defenses like checks-effects-interactions and reentrancy guards.
Smart Contract Audit Checklist
Use this SCH tool to turn the concept into practical audit work.
Practice this in real audit scenarios
Definitions help, but auditors need reps. SCH turns concepts like Checks-Effects-Interactions into exploit labs, code review habits, and report-writing practice.
Start the free trial or see the full smart contract auditing course.