Upgradeable proxy contracts- Seperating logic, functionality, & storage contracts. Examples? Resources?

I understand one of the best ways to make your contracts upgradeable is to seperate into 3 separate contracts and send via delegate call from the proxy to the functional contract. The design is usually...

1.)Proxy contract (the one the users interact with)
2.)Functional contract (This holds all the app logic)
3.)Storage contract- holds strorage variables & data (both the proxy & functional contracts inherit from the storage contract)

Anyone know of any projects on Mainnet ETH that have a similar contract design? Or can you recommend any resources that discuss how to implement this kind of upgradeability? Or is there any Open Zepp standard library contracts that help with this? Thanks

OpenZeppelin documentation refers to both (2) and (3) together as the implementation contract. These could either be together or separate (using inheritance) as you suggested. There is some discussion in this thread about separating the storage contract, and The Graph uses a similar pattern.

Note the proxy contract generally should NOT inherit from the storage contract -- ideally the proxy contract should not have any storage variables at all (and should only use unstructured storage) otherwise it could conflict with the implementation in terms of storage layout.

You can just use a standard proxy contract and don't usually need to write one yourself. We suggest using the Upgrades Plugins which help with deploying the implementation and proxy contract together using the various available proxy patterns.

Thanks for the response and links. This was helpful. Complicated stuff though. If you are or anyone reading this is aware of any Open Zeppelin video tutorials or other video tutorials on understanding and constructing this please send my way. The docs alone are tough to understand in a practical sense, at least for me they are.

Here are some video tutorials on upgradeable contracts:

The forum also has some written tutorials:

If you are more looking for information about avoiding storage conflicts, see this doc.
The approached used in the OpenZeppelin upgradeable contracts library is to use storage gaps which involves unused variables as mentioned in the last point of the link above (and this issue aims to support this pattern in the Upgrades Plugins soon).

1 Like