Final ERC for modular, upgradeable contracts composed of multiple facets behind one address. Routes selectors to facet implementations via `diamondCut`, with optional `IDiamondLoupe` introspection — useful when contract size exceeds the 24 KB Spurious Dragon limit.
- 01very large contract systems
- 02modular per-feature upgrades
- 03shared facets across protocols
- 04Aavegotchi / GMX-style architectures
- git clone https://github.com/mudgen/diamond-3-hardhat
- forge install mudgen/diamond-1-hardhat
- pnpm add @solidstate/contracts
Build the proxy against `IDiamondCut` (`diamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata)` with `Add | Replace | Remove`) and `IDiamondLoupe` (`facets()`, `facetFunctionSelectors()`, `facetAddresses()`, `facetAddress(bytes4)`). Use the Diamond Storage pattern: each facet keeps state in a struct stored at a unique deterministic slot via `keccak256('namespace.storage')` — never use sequential storage slots. Emit `DiamondCut(FacetCut[], address, bytes)` on every change. The canonical references are Nick Mudge's `diamond-1`/`diamond-3` repos; SolidState provides a typed alternative.
- ⚑Storage collisions: facets share the diamond's storage, so two facets that declare overlapping state variables in their own contract storage will silently corrupt each other — always use Diamond Storage / AppStorage with namespaced struct slots.
- ⚑Selector clashes are common — adding two facets that both export `pause()` will revert the cut. Run a selector-collision check (e.g. via `diamond-1`'s `LibDiamond.diamondCut` or louper) before every upgrade.
- ⚑Removing a facet that other facets `delegatecall` or rely on (e.g. ownership, access control) can brick the diamond — keep an emergency `OwnershipFacet` and `DiamondCutFacet` always present.
- ⚑Initialization runs via `delegatecall` to the `_init` address with `_calldata` during `diamondCut` — failing inits revert the entire cut, but partially-initialized state from a prior cut can persist.
- ⚑Block explorers and verification tooling are weaker for diamonds than for single-implementation proxies — verify each facet separately and consider Louper / Diamond Inspector for off-chain visibility.
- ⚑The 24 KB EIP-170 limit applies per facet, not to the diamond as a whole — splitting facets too coarsely defeats the point.