Contact

Welcome to Protokol’s Web3 Innovation series where we explore all the latest innovations and best practice in the web3 space.

In this first edition of the series, we will explore what Upgradable Smart Contracts are and how they enable developers to build dApps that can be continuously upgraded with new logic, as well as fix bugs and patch vulnerabilities discovered after launch. 

We will also explore the different types of proxy upgrade patterns developers can use to build Upgradable Smart Contracts and the benefits and drawbacks of using Upgradable Smart Contracts in dApp development. 

Smart Contracts & dApps

Smart contracts are executable pieces of code designed specifically for blockchains. They execute their functionality automatically when certain pre-determined parameters are met, thus completing blockchain transactions. 

Decentralised applications (dApps) are built on top of blockchains such as Ethereum, and smart contracts execute the functionality of those applications on the blockchain network. Smart contracts follow one of the core tenets of blockchain technology – they’re immutable. This means that once they’ve been deployed to the blockchain, they can’t be changed or altered and are permanently in place. 

Whilst this immutability affords an inherently high level of security, it hinders developers’ ability to alter their dApps once deployed. Upgradable Smart Contracts were developed to offer a solutions. Blockchain developers have a choice as to whether they want to program traditional, permanent smart contracts to power their dApps, or build them with the ability to be upgraded further down the line. 

Developing Upgradable Smart Contracts does carry potential risks, so sufficient planning and deep knowledge of blockchain programming languages such as Solidity and Rust are required.

What is an Upgradable Smart Contract?

Conventionally, to make alterations to a dApp or fix discovered bugs discovered after deployment, developers would have to upload an improved smart contract to a new blockchain address and migrate the entire dApp there which can be costly and time-consuming. 

To avoid this, developers can create Upgradable Smart Contracts when building their dApps. The name ‘Upgradable Smart Contract’ might seem a little misleading as it implies altering the code of an existing smart contract after it has been deployed to the blockchain, which isn’t the case. 

Rather, it describes the process of swapping out one smart contract for another or changing which code a certain contract executes. dApps often run multiple smart contracts simultaneously that work in tandem, each with a specific role in the overall dApp functionality.  

For example, you might have a dApp with a frontend contract that handles the user interaction and data storage and a backend contract that fulfils the dApp’s business functionality. Both these smart contracts are immutable, of course.  

However, when they’re built using an established upgradable design pattern, the backend (implementation) contract can be exchanged for an updated version whilst shielding the customer-facing portion of the dApp’s functionality as the frontend smart contract remains in-state.

How Do Upgradable Smart Contracts Work?

Developers might find a bug after launching their dApp that they want to patch, or they may want to update the source code to add new features and improve functionality. 

To prepare for this, there are several upgrade patterns that developers can use when initially programming their smart contract. The most popular upgrade patterns involve data separation by using proxies. The EVM (Ethereum Virtual Machine) has an in-built opcode named ‘delegatecall’. The ‘delegatecall’ function allows one contract to execute code from another while preserving the original context. 

This essentially means that the implementation contract – the one that contains the business logic for the dApp’s functionality – can use the data contained in the proxy contract’s storage to execute the dApp’s business function without impeding the proxy’s function. 

For example, in a DeFi dApp, the proxy would store the input data from the user such as the token type and amount they want to trade. The implementation contract would then mirror that data, using its built-in logic to trade the user’s currency for another currency and then send it back to the proxy to update its output to the user. 

Without the implementation contract, the data stored within the proxy wouldn’t have a context for use. Without the proxy, the implementation contract wouldn’t have any data upon which to base its functionality. 

When you upgrade a smart contract, a new implementation contract is added to the blockchain at a different address, and the proxy is reoriented to communicate with the new implementation contract at the new address. 

This allows developers to update the logic contained within the implementation contract without jeopardising the dApp’s stored user data or interfering with the customer experience.

Transparent Proxy Pattern

One of the main types of proxy design patterns used is the Transparent Proxy Pattern, which contains the upgrade functionality within the proxy contract. This includes giving an admin privileged access to interact with the proxy pattern and trigger upgrades by updating the logic implementation contract address. 

Early iterations of this method were revealed to be vulnerable due to a concept known as proxy selector clashing – this occurs when call functions within the proxy and implementation contracts are identical, leading to code confusion and potentially to smart contract exploits.  

This was fixed within the Transparent Proxy Pattern by ensuring that the ‘delegatecall’ function is only executed if the sender isn’t a contract admin.

Universal Upgradable Proxy Standard (UUPS)

The UUPS directly competes with the Transparent Proxy Pattern for most popular, with the difference being that the upgrade functionality sits with the implementation contract rather than the proxy contract. 

The proxy contract contains a unique storage slot that contains the address of the implementation contract. This address is updated whenever the implementation contract is updated. UUPS also offers the ability to make future upgrades impossible, giving more security and control to dApp developers, and is more cost-effective than the Transparent Proxy Pattern. 

Diamond Proxy Pattern

One of the more complex upgrade patterns, the Diamond Proxy Pattern separates a contract’s functions down into a variety of smaller contracts to address contract size limitations. In this case, the proxy contract controls all of these smaller contracts (called ‘facets’), allowing for the automatic upgrading of several smart contracts at the same time.

Example Upgradable Smart Contract

In the image below you’ll see an example Upgradable Smart Contract built using OpenZeppelin and the UUPS proxy pattern:

Benefits & Drawbacks of Upgradable Smart Contracts 

Upgradable Smart Contracts can be a double-edged sword, and there are several pros and cons to using them.

Pros:

  • Fix Vulnerabilities & Bugs – Just like with web2 applications, Upgradable Smart Contracts allow developers to fix unanticipated bugs and patch vulnerabilities after they’ve launched their application, whereas traditional smart contracts do not.
  • Implementing New Features – Technologies tend to improve over time as new innovations are brought forward. Upgradable Smart Contracts can enable source code updates to be implemented when these innovations surface, allowing developers to keep their app competitive.
  • Experimentation – While the immutability of smart contracts is a core concept on the blockchain and has many benefits, in a way it can stifle the innovation that occurs from experimentation with new methodologies. Upgradable Smart Contracts allow for developers to experiment with new code on the blockchain without interfering with the dApp’s functionality.

Cons:

  • Concerns Around Decentralisation – Decentralisation is a core tenet of blockchain technology. Having powerful admins that are able to alter the functionality of a dApp is counterintuitive to the concept of decentralisation, and opens up the potential for bad actors.
  • Technical Vulnerabilities – Impacting immutability gives rise to the risk of further security issues and vulnerabilities within dApp and smart contract infrastructure. Storage clashes and function selector conflicts have not been completely eliminated from smart contract upgrade patterns.

Conclusion

Upgradable Smart Contracts allow developers to make iterative updates to their dApps and fix post-launch bugs while protecting the user experience. However, they also can lead to complications and potential vulnerabilities within your smart contract infrastructure. 

Whilst they may seem like the logical next step in achieving user-friendly dApp development, using Upgradable Smart Contracts is a decision that should be made after careful consideration. 

If you’re looking to develop a dApp and want expert technical guidance relating to Upgradable Smart Contracts or more, reach out to Protokol today.

Book a call

Need help implementing Upgradable Smart Contracts into your dApp? Whether you need technical guidance, additional development resource, or a full-scale solution development partner, Protokol are here to help.
Reach out