Upgradeable via delegatecall proxies
- A small proxy contract holds state; it delegatecalls into a separate implementation contract that holds code. This is implemented using delegatecall
- Upgrade ⇒ change the implementation address.
- Variants: Transparent Proxy, UUPS, Beacon
- Cons: Storage-layout discipline required, upgrade authority must be secure, testing discipline is non-negotiable.
- Modular routing (Diamond)
delegatecall & storage
delegatecall runs the callee’s code in the caller’s storage context.
- So the proxy’s storage must line up with what the implementation expects.
- To avoid clashes, upgrades use fixed storage slots (EIP-1967) or namespaced slots.
EIP-1967 storage slots
- Standardized
bytes32 slots for implementation, admin, and (for beacons) beacon (to update multiple proxies)
- The implementation address is stored in slot 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc
- The admin address is stored in slot 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103
- This prevents collision with your app’s own state.
- OpenZeppelin’s Transparent Upgradeable Proxy and UUPS contracts both use ERC 1967 for defining where to store the variables
- By seeing if a contract has a non-zero value in the aforementioned slots, block explorers can tell if a contract is a proxy contract or not.
2A) Transparent Proxy
- The proxy has an admin and has admin functions