Common Patterns: Ownable, Pausable, Upgradeable Proxies
The patterns you'll see in every Solidity codebase. Access control, pause switches, the transparent and UUPS proxy models — when to use each and when each pattern goes wrong.
40 min · expert · part of Solidity & Smart Contract Development
What you'll learn
- The OpenZeppelin Library Is the De-Facto Standard
- Ownable: Single-Owner Access Control
- AccessControl: Role-Based Permissions
- Pausable: The Kill Switch
- Why Upgradeable Proxies Exist
- Transparent Proxy (TUP)
- UUPS Proxy and Storage Layout Rules
Key terms
- OpenZeppelin Contracts
- The audited, battle-tested standard library of Solidity patterns. Implements ERC standards, access control, pausability, upgradeable proxies. Default starting point for production contracts.
- Ownable / Ownable2Step
- Single-owner access control. Use Ownable2Step for production — the two-step transfer prevents the most expensive class of admin mistake.
- AccessControl
- Role-based access control. Each role is a `bytes32` constant; DEFAULT_ADMIN_ROLE can grant/revoke others. Separates duties so a compromised operational key has bounded blast radius.
- Pausable
- A modifier-based kill switch. `whenNotPaused` reverts state-changing calls during a pause. Trade-off: incident response capability vs. user trust in non-stoppability.
- Proxy Pattern
- A thin "proxy" contract holds storage and delegatecalls to a separate "implementation" contract for logic. The proxy address is the protocol's permanent identity; the implementation can be swapped to upgrade.
- Transparent Upgradeable Proxy (TUP)
- Proxy pattern where upgrade authorization lives on the proxy itself. Heavier per-call but safer — admin and user paths are routed separately.
- UUPS Proxy
- Proxy pattern where upgrade logic lives on the implementation. Cheaper per-call but you must include `_authorizeUpgrade` in every implementation, or you brick the proxy.
- Storage Collision
- A bug where a new implementation reorders, retypes, or deletes a state variable, so storage slots end up holding the wrong values. Catastrophic for upgradeable contracts. Prevent with strict layout discipline and the OZ Upgrades plugin.
- Initializer / __gap
- `initializer` is a modifier ensuring the init function can only run once. `__gap` is a reserved `uint256[N]` array between state variables, consumed as new variables are added — preserves layout across upgrades.
Read the full lesson in the CryptoBipto app.
Open lessonEducational only — not financial advice.
