How to create an UUPS Proxy

Hariharan Iyappan
Coinmonks
6 min readSep 12, 2022

--

What is UUPS Proxy?

UUPS stands for Universal Upgradeable Proxy Standard and was first documented in EIP1822. In this proxy pattern the responsibility of upgrading the implementation contract address is with the implementation contract itself. In contrast, in the transparent proxy pattern the responsibility of upgrading the implementation contract address is that of the proxy contract and the proxy admin contract. For a more detailed explanation of the transparent proxy pattern check out this article.

When we try to upgrade a smart contract deployed with the UUPS proxy pattern, the proxy contract makes a call to the implementation contract. Which checks if the user upgrading has permission to upgrade the implementation and then goes ahead and changes the implementation contract address to a new one.

UUPS proxy pattern is recommended over transparent proxy pattern because it saves gas during initial deployment by removing the need for proxy admin contract, which is required in transparent proxy pattern. There is one caveat when using UUPS proxy pattern that needs to be kept in mind. If you upgrade your proxy with a non UUPS compatible implementation you can never upgrade it afterwards. Such a mistake can be fatal as you have lost the upgradeability which was our backdoor to fixing such mistakes.

Let’s dive in and deploy a smart contract with the UUPS proxy pattern.

This Github repository has the code for this article feel free to save it for future use. You can clone it if you want to follow along without setting up from scratch.

Project Set Up

We will be using Hardhat for our Ethereum development workflow. I am using WSL2 in a windows machine for this walkthrough. You can adjust the steps slightly in case you are using a different set up. Let’s get started!

Run the following commands to create a directory and initialize it as a node project.

Install hardhat in this directory.

Initialize a hardhat type script project in the directory. Run the below command and choose “Create a TypeScript project” option. Go with the default parameters for rest of the prompts.

Install the Open zeppelin hardhat upgrades plugin which we’re going to use to easily deploy our proxy.

Also install the upgradeable contracts from Open zeppelin which is the upgradeable counterpart of Open zeppelin contracts.

Copy and paste the following into the hardhat.config.ts file. This will do the basic hardhat set up we require for this project.

Implementation contract to deploy with UUPS Proxy

Inside contracts folder create a folder for the implementation contract for which we’re going to deploy a UUPS proxy.

In the contracts directory create a file named VersionAware.sol and copy paste the following code in it.

Here we create a basic skeleton of our implementation contracts so that we can easily see the version upgrades visibly after deployment and upgrade.

In the contracts/uups directory create two files named UupsProxyPatternV1.sol and UupsProxyPatternV2.sol and copy paste the following code into it.

UupsProxyPatternV1.sol

UupsProxyPatternV2.sol

Note that in both the contracts we inherit from UUPSUpgradeable.sol which makes out contract UUPS upgrade compatible. Inheriting from this contract requires us to implement the _authorizeUpgrade function that is used to decide whether the caller is allowed to upgrade or not.

Here I attempt to explain a few advanced details of the the above contracts. Consider skipping it now and coming back later if you have difficulty understanding this on first read. Typical upgradeable contracts should not have a constructor because the constructor of the implementation contract can never be run in the context of the proxy contract. We have added a constructor here which is safe as it does not set to any of the storage variables. Leaving a contract without initializing it can pose a security threat. Calling the _disableInitializers method in the constructor makes the implementation contract not initializable which is much safer than leaving the implementation without a constructor and not initialized. Note that I have used initializer modifier in the initialize method in V1. This modifier makes sure that this initialize method is called only once, like solidity ensures for constructors. Also note that in V2 the modifier of the initialize method is reinitializer(2). Here 2 represents the version of the implementation contract. The reinitializer modifier has to be used instead of initializer because the proxy contract has already been initialized once in V1. There are more things and details to know about Initializer.sol contract which all upgradeable smart contracts should inherit. I will write more detailed article on it in future.

Now, run the following command to compile the smart contracts.

UUPS Proxy Deployment and Upgrade

First we will deploy version 1 with UUPS proxy and then upgrade it to version 2. We will use a hardhat script to do this. Create a script named uups.js in scripts folder and copy paste the following code in it.

We first deploy version 1 of the smart contract with proxy. The Open zeppelin upgrades deployProxy method takes care of it for us. Once version 1 is deployed with proxy we call the getContractNameWithVersion function on the proxy. This method will return a string according to what we made this method return in version 1 of the contract. Then we proceed to upgrade this contract with the upgradeProxy method. After the upgrade is over we call the getContractNameWithVersion function again to see the change in the string returned. Let’s run the script and see the results. Use the following command to run the script.

You should see the following printed on your console.

Yay! the results are as expected. The implementation contract is successfully upgraded to version 2. This is how you deploy and upgrade future versions of your contract with the UUPS proxy pattern however complicated your smart contract gets.

Thanks for reading.

Who am I?

I am a full stack blockchain developer, passionate about building a decentralized and potentially more inclusive future. Have a blockchain development need?

Get in touch: 📧 hariharan@alumni.iitm.ac.in

Github

New to trading? Try crypto trading bots or copy trading

--

--

Hariharan Iyappan
Coinmonks

Passionate techie | IITM 2020 | Software Engineer @PhonePe