๐Ÿ”’ Checks-Effects-Interactions: Preventing Reentrancy

Master reentrancy guards, mutex locks, and the CEI pattern

โ†
Previous Section
Attack Mechanics

๐Ÿ›ก๏ธ Preventing Reentrancy Attacks

Now that you understand how reentrancy attacks work, let's explore the battle-tested methods developers use to protect their smart contracts.

๐ŸŽฏ Interactive: Prevention Methods

Explore 4 proven techniques to prevent reentrancy attacks:

๐Ÿ“‹

Checks-Effects-Interactions

Basic

Fundamental pattern: check conditions, update state, then call externally

Effectiveness
95%
Gas Impact
None
Implementation
Change code order
Pattern Order:
1. Checks โœ“
Validate all conditions
2. Effects ๐Ÿ“
Update contract state
3. Interactions ๐Ÿ”—
Make external calls

๐ŸŽฏ Interactive: Code Pattern Comparison

See the difference between vulnerable and secure implementations:

โŒ Vulnerable: External Call Before State Update

function withdraw(uint amount) external {
  // โœ… Check condition
  require(balances[msg.sender] >= amount, "Insufficient balance");
  
  // โŒ DANGER: External call before state update
  (bool success, ) = msg.sender.call{value: amount}("");
  require(success, "Transfer failed");
  
  // โŒ TOO LATE: State update after external call
  // Attacker can reenter before reaching here
  balances[msg.sender] -= amount;
  
  emit Withdrawal(msg.sender, amount);
}
๐Ÿšจ Problems:
  • โ€ข Balance check passes on reentry (balance unchanged)
  • โ€ข Attacker withdraws multiple times
  • โ€ข Contract drained before balance update

Best Practices Checklist

โœ…
Always use ReentrancyGuard

Import OpenZeppelin's ReentrancyGuard and add nonReentrant modifier to functions with external calls.

โœ…
Follow Checks-Effects-Interactions

Order matters: validate inputs, update state, then make external calls. Never reverse this order.

โœ…
Use transfer() or send() for simple ETH transfers

These methods have 2,300 gas limit, preventing complex reentrancy. Only use call when necessary.

โœ…
Consider Pull Payment Pattern

Let users withdraw funds rather than pushing payments. Eliminates external calls from core logic.

โœ…
Audit external calls carefully

Every external call is a potential attack vector. Document why each is necessary and ensure proper guards.

โœ…
Test with reentrancy attack simulations

Write test cases that attempt reentrancy. If tests pass, your contract is vulnerable!

Common Mistakes to Avoid

โŒ
Trusting External Contracts

Never assume external contracts are safe. Always use guards even with "trusted" addresses.

โŒ
Incomplete State Updates

Update ALL related state before external calls, not just the obvious variable.

โŒ
Only Checking Direct Reentrancy

Cross-function reentrancy is harder to spot. Protect all functions that share state.

โŒ
Forgetting Fallback Functions

Remember that receive() and fallback() can contain attack code.

๐Ÿ’ก Pro Tips

๐Ÿ”
Use static analysis tools: Tools like Slither, Mythril, and Securify can detect reentrancy vulnerabilities automatically.
๐Ÿ“š
Learn from audits: Read public audit reports to see how professionals identify and fix reentrancy issues.
๐Ÿงช
Write attack contracts: Build malicious contracts in your tests to verify your defenses actually work.