3.7 Smart Contract Patterns and Anti-Patterns
Every smart contract is built from patterns — recognizable code shapes that solve recurring problems. Some patterns prevent vulnerabilities. Some optimize gas. Some make code more legible. And some are mistakes that repeat across projects until they earn names, get catalogued, and become the things experienced developers look for first during review.
This section presents the patterns and anti-patterns that matter most for security. The seven subsections that follow are organized by what the pattern is for, not by what kind of vulnerability they address. A reentrancy guard appears in 3.7.1 (Control Flow) because it shapes how a function executes; a circuit breaker appears in 3.7.5 (Defensive) because it constrains damage when something goes wrong. The same vulnerability — reentrancy — appears as the motivation in multiple subsections but the patterns are organized by their structural role in the contract.
The deep treatment of the underlying vulnerabilities themselves — what they are, how they're exploited, what they cost — lives in Section 3.8 (Common Vulnerabilities). This section is about the design-time choices that prevent those vulnerabilities from being introduced in the first place.
How to Read This Section
The subsections progress from foundational to specialized:
3.7.1 Security-Critical Control Flow Patterns establishes the three patterns every value-handling contract needs: Checks-Effects-Interactions, Reentrancy Guards, and Pull-over-Push payments. These are the load-bearing safety patterns; the rest of the section assumes them.
3.7.2 State & Storage Patterns covers how to organize contract state safely: Explicit Storage Buckets for upgrade-safe layouts, Bitmap Nonces for efficient set tracking, and State Machines for phase-based contracts.
3.7.3 Access & Authorization Patterns covers who can do what: Ownable for minimal cases, Role-Based Access Control for hierarchical permissions, and Multi-Signature requirements at both the wallet and contract layers.
3.7.4 External Interaction Patterns covers how contracts interact with the outside world: Commit-Reveal, Merkle Proofs, Multicall, NFT Receive Hooks, ERC-20 Permit, and Factory Proofs.
3.7.5 Defensive Patterns assumes something will eventually go wrong and constrains the damage: Circuit Breakers / Pause, Rate Limiting, and Withdrawal Patterns.
3.7.6 Optimization Patterns with Security Trade-offs covers when to reach for techniques that sacrifice safety for performance: selector-based dispatch, inline assembly, and eth_call tricks.
3.7.7 Anti-Patterns Catalog is a scannable reference of 24 common mistakes — the pre-review checklist version of everything else in this section.
The subsections can be read in order or referenced individually. Each subsection includes its own cross-references to related material elsewhere in the book.
Conventions Used Throughout
All code in this section follows the conventions established for the book:
- Solidity version pragma is specified explicitly in each example. The default is
^0.8.20. Version-specific behavior (pre/post 0.8.0 arithmetic, transient storage in 0.8.24+, etc.) is called out where it matters. - OpenZeppelin contracts are used as the default implementation reference. Where a pattern's mechanics are the teaching point, the raw implementation is also shown.
- Foundry is the primary test framework. Hardhat alternatives are noted only where they differ meaningfully.
- Solidity custom errors are preferred over revert strings in newer examples for gas efficiency and structured handling.
Each pattern's subsection follows a consistent structure: what the pattern is → idiomatic implementation → what it trades off → when not to use it → how to test it. The Anti-Patterns Catalog uses a tighter format: vulnerable example → correct form → cross-reference.
The Bigger Picture
A contract that applies every pattern in this section and avoids every anti-pattern is not automatically secure. Logic bugs, oracle manipulation, MEV exposure, governance attacks, and protocol-level economic flaws remain — and several of those topics get their own sections later in this book (3.11 Advanced Contract Security, 3.10 Past Exploits, 3.8 Common Vulnerabilities). What this section does provide is the baseline: the design-time choices that, when made correctly, eliminate large classes of vulnerabilities before they enter the codebase.
The patterns here represent decades of accumulated experience across thousands of contracts, hundreds of audits, and dozens of catastrophic exploits. Each one earned its place by showing up — either as a defense that worked, or as the absence of a defense that didn't. Following them is not optional discipline; it is the minimum bar for a contract that handles meaningful value.
Sections 3.7.1 through 3.7.7 follow.