← Protocols
ERC-1967 — Standard Proxy Storage Slots
Standard / EIP·EVM

ERC-1967 — Standard Proxy Storage Slots

01Description

Final ERC defining well-known, collision-resistant storage slots for proxy implementation, admin, and beacon addresses. Lets block explorers, indexers, and wallets reliably detect upgradeable contracts.

02Best for
  • 01upgradeable contract patterns
  • 02explorer/indexer detection
  • 03transparent proxies
  • 04UUPS proxies
  • 05beacon proxies
03Install
  • pnpm add @openzeppelin/contracts @openzeppelin/contracts-upgradeable
  • forge install vectorized/solady
05Prompt snippet
Store the implementation address at `bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)` (`0x360894...382bbc`), the admin at `keccak256('eip1967.proxy.admin') - 1` (`0xb53127...d6103`), and the beacon at `keccak256('eip1967.proxy.beacon') - 1` (`0xa3f0ad...133d50`). Use OpenZeppelin's `ERC1967Utils` (or Solady's `ERC1967`) helpers — never roll the slot constants by hand. Emit `Upgraded(address)`, `AdminChanged(address,address)`, and `BeaconUpgraded(address)` from those helpers so Etherscan, Tenderly, and Sourcify proxy detection light up automatically.
06Gotchas
  • Slot uniqueness is load-bearing — using `keccak256('eip1967.proxy.implementation')` directly (without the `- 1`) lands on a hashable preimage and explorers will not recognize the proxy.
  • Hand-coding slot constants instead of importing from OpenZeppelin/Solady risks one-bit typos that silently break upgrade paths and detection.
  • ERC-1967 only standardizes storage layout — it does NOT define who can upgrade. Pair it with a transparent proxy admin or UUPS `_authorizeUpgrade` for access control.
  • Implementation contracts behind ERC-1967 proxies must be initializer-based (no constructor state) and use `__gap` arrays to reserve future storage in upgradeable inheritance chains.
  • Forgetting to emit `Upgraded` after `_setImplementation` makes off-chain indexers miss upgrades, even though the proxy still works.
07Alternatives