Aaryamann Challani

Engineer and amateur cook writing about privacy, cryptography, and distributed systems

← Back to posts

Contract Proxy Patterns

These are the major proxy patterns used in production-grade contracts

OpenZeppelin Transparent Upgradeable Proxies

EIP: None

In transparent proxies, the upgrade of the implementation is handled by the proxy. This leads to a larger contract size for the proxy. It is called "transparent", because the proxy is virtually indistinguishable to the end user from the logic contract (i.e the contract it proxies requests to). There are a few functions which only the admin can access, like upgradeTo(address implementation). None of the requests made by the admin are forwarded to the logic contract, thereby ensuring that proxy selector clashing does not occur. Note that in most cases, the admin of the proxy will be a contract ProxyAdmin .

Implementation Examples:

If you're using hardhat, you will usually go with one of the following methods -

If you're using truffle, you can use @openzeppelin/truffle-upgrades

OpenZeppelin UUPS

EIP: 1822, 1967

As mentioned in the EIP, UUPS stands for Universal Upgradeable Proxy Standard

It differs from transparent proxies, by leaving upgrade functionality to the implementation contracts. This allows for smaller proxy size, and cheaper deployment. It uses an ERC1967Proxy implementation for the proxy. By leaving the implementation to handle upgrades, it opens a backdoor of sorts, since the upgrades can be executed by an arbitrary address with selector clashing. That is why it is imperative to setup access-control for the admin functions, or by setting a flag that prevents upgrades.

Implementation Examples:

  • This tutorial by OZ explains the difference between transparent and UUPS proxies, and shows you how to deploy using hardhat and truffle

Diamond

EIP: 2535

The diamond upgrade pattern employs a one-to-many proxy pattern. There can be multiple different implementations, each with their own functions that are proxied to. The best part about this pattern is that all current contracts are compliant to work as "Diamond Facets" (any function that is external to the proxy)

"Facets" can be added/removed/replaced easily, reducing complexity of contracts

Due to the structure of diamond contracts, it can be used to circumvent the 24kb limitation of contract size (since a diamond can have any amount of facets)

It has not been accepted yet, it is being deliberated here

Nick Mudge is the author of the pattern, and a lot of resources relating to it are on his blog.

Implementation Examples:

  • OZ doesn't have a standard diamond library yet, but hardhat-deploy has an example here, which just uses Nick's reference implementation

Conclusion

Contract upgradeability is made easy by the folks over at OZ, which prevent you from reinventing the wheel for standard contracts!

Thanks for reading!