Live on Sepolia testnet
- BoxV1 (implementation v1): 0x93c4c2bdecd10809b7aa4dabab52fc068d7c0fa6
- BoxV2 (implementation v2): 0x1dfe668525caecdde986c8395adfb609f12db89d
- Proxy (ERC1967Proxy): 0x9081f5e9dc38ecc02ffd2916a4b0c51bd4437a79
This project demonstrates a UUPS (Universal Upgradeable Proxy Standard) smart contract workflow using Foundry and OpenZeppelin. The system consists of a single ERC1967 proxy whose logic can be upgraded from BoxV1 to BoxV2 without changing the proxy address or losing state.
The contracts are deployed and upgraded using Foundry scripts, and the upgrade flow is validated with Foundry-based tests.
-
ERC1967Proxy
- Holds all contract state
- Delegates calls to the current implementation
-
BoxV1 (Initial Implementation)
- UUPS-enabled
- Uses initializer pattern instead of constructor
- Exposes read-only functionality
-
BoxV2 (Upgraded Implementation)
- Extends functionality by allowing state mutation
- Preserves storage layout to ensure safe upgrades
-
Upgrade Pattern
- UUPS-based upgrade via the proxy
- Proxy calls upgrade logic defined in the implementation
BoxV1is deployed as an implementation contract.- An
ERC1967Proxyis deployed pointing toBoxV1. - The proxy becomes the primary contract users interact with.
The proxy address remains constant across upgrades.
- A new implementation (
BoxV2) is deployed. - The proxy calls the UUPS upgrade function.
- The proxy’s implementation pointer is updated.
- All existing state is preserved.
After the upgrade, calls to the proxy execute BoxV2 logic.
The test suite validates:
- The proxy initially behaves like
BoxV1 - Functions introduced in
BoxV2are unavailable before upgrade - The upgrade successfully switches logic to
BoxV2 - State can be written and read correctly after upgrade
-
Upgrade Authorization
- The
_authorizeUpgradehook must be restricted (e.g. owner or multisig) - Leaving it unrestricted allows anyone to upgrade the contract
- The
-
Initializer Safety
- Initializers are disabled on implementation contracts to prevent misuse
-
Storage Layout
- New versions must only append state variables
- Reordering or removing variables can corrupt storage
For UUPS proxies:
- Verify implementation contracts on Etherscan (BoxV1, BoxV2)
- Mark the proxy as a proxy contract on Etherscan
- Once linked, Etherscan will display the ABI and allow interaction via the proxy address
- Foundry (forge, cast)
- OpenZeppelin Contracts
- OpenZeppelin Upgradeable Contracts
- ERC1967 + UUPS standard
- Cheaper upgrades than Transparent Proxy
- Upgrade logic lives in the implementation
- Clear separation of state (proxy) and logic (implementation)
- Widely used in production protocols
MIT
Dhruv Charne
This repository is intended for learning, experimentation, and as a reference for production-grade upgradeable smart contract patterns using Foundry.