If you’ve ever deployed a smart contract onto a blockchain you know that this isn’t a task to be taken lightly. The code you deploy is immutable, meaning it lives on the blockchain forever and cannot be modified if a mistake is made. This can be problematic because we as humans, often make mistakes. That is why upgradeable smart contracts are becoming increasingly popular, enabling you to upgrade or modify your contract after deployment as well as future-proof it for years to come.
This article is intended to use simplified, non-technical language for easy reading and understanding. In future articles, we will be doing technical deep dives into the various upgradeable patterns.
A standard scenario
To understand upgradeability, we must first understand how the typical smart contract interaction occurs. To do this we will use a simple example where Alice wishes to transfer her NFT to Bob, as shown in Figure 1 below. In this scenario, Alice will interact directly with the NFT contract to execute the transfer. All logic (functions) and storage related to the NFT is stored in the NFT contract.
The upgraded scenario
If the same scenario was to occur with an upgradeable contract, there actually wouldn’t be any difference from Alice’s perspective. She would still interact with an NFT to do the transfer, however, behind the scenes, things would look different. To achieve upgradeability we have to convert our single NFT smart contract into two contracts:
- A logic contract
- A proxy contract
The logic contract looks very similar to the original NFT smart contract. It contains the functions your smart contract needs to execute. However, unlike a normal smart contract, the logic contract is not interacted with directly. Instead, all interactions must happen via a proxy contract.
The proxy contract is what Alice believes to be the actual NFT. It is the contract she interacts with directly to execute the transfer function (or any function she desires). However, proxy contracts often have no logic which means they don’t know how to execute your desired function. So when Alice executes a transfer on the proxy contract the proxy needs to ask the logic contract how to do it as shown in Figure 2.
This pattern is called the proxy pattern and it makes upgradeability possible by allowing you to add new features (functions) by simply deploying a new logic contract and connecting it to the same proxy. So in our example with Alice, if the admin of the NFT contract wanted to enable a new feature such as NFT burning it could be done by deploying a new logic contract with the new feature and connecting it to the proxy as shown in Figure 3. From Alice’s perspective, the contract has been upgraded because she can continue to interact with the same NFT (the proxy contract) as she always has but suddenly new features are available to her.
It is also worth mentioning that even though all the logic is held in the logic contract all storage for the NFT is held in the proxy contract. This means you can rest assured that all data associated with the NFT won’t be lost when you upgrade.
The proxy pattern we have discussed is the most widely adopted upgradeability pattern and it covers proxies such as the Simple Proxy, Transparent Proxy, and Universal Upgradeable Proxy Standard (UUPS). However, there are other patterns out there such as Metamorphic Contracts and the Diamond Proxy Pattern. The Diamond Proxy pattern in particular is a powerful new standard that is worth looking into, and we intend to write a whole separate article on that.
Upgradeability is a great tool to consider when creating your smart contracts. It can help you recover from worst-case scenarios as well as ship new features without disruption to the end user. It is also flexible, which means you have the option to disable upgradability in the future. However, upgradeability adds additional complexity to your codebase so if you decide to use upgradeability, it’s even more important that you hire a skilled developer/team and consider undergoing an audit.