Educational implementation of a simple ERC-1967 upgradeable proxy built with Foundry.
This repository is focused on understanding proxy mechanics step by step:
- ERC-1967 storage slots for implementation and admin
- delegatecall-based call forwarding
- admin-controlled implementation upgrades
- storage preservation across upgrades
- separation between proxy mechanics and access-control logic
This is a learning project and example implementation, not a production-ready proxy system.
Reference:
- ERC-1967: https://eips.ethereum.org/EIPS/eip-1967
The project is split into small layers so each responsibility stays visible:
-
src/proxy/Proxy.solBase proxy mechanics. Stores the implementation address in the ERC-1967 slot, performsdelegatecall, and provides internal initialization and upgrade helpers. -
src/proxy/ProxyAdminControl.solAdmin-related logic. Stores the admin address in the ERC-1967 admin slot, provides admin validation, initialization, admin transfer, and admin events. -
src/proxy/AdminUpgradeableProxy.solComposition layer that connects proxy upgrade logic with admin-based access control. -
src/CounterProxy.solConcrete example proxy used in tests. -
src/Counter.solSimple implementation contract used to demonstrate proxy behavior.
- ERC-1967 implementation slot
- ERC-1967 admin slot
- admin-controlled
updateTo(...) - implementation address validation
- admin initialization and admin transfer
- implementation change event
- admin change events
- upgrade tests
- admin-flow tests
- storage preservation test across upgrades
The main goal is not to compete with production libraries, but to make proxy internals easy to inspect:
- proxy state lives in proxy storage, not implementation storage
- direct calls to implementation do not mutate proxy state
- upgrading implementation changes behavior without moving storage
- access control can be composed separately from proxy mechanics
This repository intentionally stays small and does not aim to replace audited production solutions.
Examples of things that are still simplified:
- no transparent proxy restrictions for admin calls through
fallback - no full production hardening
- no deployment framework around proxy administration
- no compatibility guarantees beyond the tested example layouts
Build the project:
forge buildRun the tests:
forge testFormat the code:
forge fmtIf you want a battle-tested production implementation, use audited libraries such as OpenZeppelin.
If you want to understand how an ERC-1967 proxy works under the hood, this repository is meant to be a compact reference and tutorial project.