Home Web3 SecuritySmart Contract Audit What are Upgradable Smart Contracts?

What are Upgradable Smart Contracts?

by ImmuneBytes

Smart contracts have been the biggest and most important developments in the blockchain space- Giving us the true meaning of decentralization. These are self-executing computer programs that operate without the need for intermediaries. Smart contracts provide a bunch of benefits to their users including transparency, decentralization, etc. These benefits have helped smart contracts to revolutionize various industries and remove the need for traditional intermediaries.

In addition to smart contracts, there are now upgradable smart contracts sometimes also referred to as” self-upgradable smart contracts” that enable developers to make any changes or updates to the contract’s code after it has been deployed on the blockchain. This was not possible in traditional smart contracts as they were immutable (meaning their code couldn’t be altered once deployed).

However, with upgradable smart contracts users get the magic wand of making controlled and secure changes to the contract’s logic or functionality.

In this article, we will deal with upgradable smart contracts, their benefits and use cases, challenges, and more. So stay in touch as we devour into the land of upgradable smart contracts.

Smart Contracts 2.0: Upgradable Smart Contracts

Upgradable smart contracts are a new version of smart contracts where users get to make updates and changes to the already deployed smart contracts on the blockchain. This new version of the smart contract has a unique component attached to it, which separates the contract’s logic and storage data into different components.

Logic contracts contain the main code and functionality of smart contracts which helps in specifying how the code behaves and processes transactions. Whereas, a storage contract holds the state and data of the smart contract by storing information about the contract’s variables and current state.

Now if the developers are looking to update an upgradable smart contract all they need to do is deploy a new version of the logic contract while keeping the storage contract intact. Post-deployment the storage contract will interact with the new logic contract, enabling the contract to continue with the latest changes.

With this new update, there is a common question that arises as to was there a need for upgradable smart contracts. The answer to this is yes, as despite the benefits there were various limitations surrounding the traditional smart contracts that needed special attention.

So let’s have a look at the challenges faced by traditional smart contracts and how upgradable smart contracts came into the limelight to overcome these challenges.

Upgradable Smart Contracts: A Necessity

There were various limitations surrounding the traditional smart contracts and it’s only with the introduction of upgradable smart contracts that smart contracts witnessed a new wake of dawn. The challenges are as follows:

  1. Unfixable Bugs: Traditional Smart Contracts were designed to be immutable, which meant that once deployed on the blockchain, their code couldn’t be changed. However, this posed a concern because if any bugs needed fixing, it was immune to any changes. This is where upgradable smart contracts come in handy, as they are mutable and allow developers to address bugs and improve the issues without compromising on the existing functionality.
  2. Non-Adaptability: Blockchain technology is an ever-changing space that requires continuous updates, and this is something that is impossible in traditional smart contracts. With upgradable smart contracts developers can seamlessly integrate new technologies and accommodate various new features and functionality.
  3. Security Concerns: Cybersecurity has been so embedded in our day-to-day lives that there’s no waving off such threats until and unless we have a solid security measure aligned for the same. Traditional smart contracts lacked security concerns as they saved people from various attacks yet with constant security upgrades, traditional smart contracts couldn’t match up. Thus, upgradable smart contracts came up that enable users to reinforce security measures by allowing smart contract updates and protecting them from potential risks.
  4. Partial Decentralisation: Traditional smart contracts also lacked the power of decentralization to some extent. However, upgradable smart contracts were designed in a way to be governed by Decentralized Autonomous Organizations (DAOs). This helped the stakeholders to collectively decide on the upgrades and improvements and fostered a community-driven decision-making mechanism.
  5. Complex Upgrades: In traditional smart contracts, the applicants used to face various complexities when it came to upgrades Developers had to completely destroy the existing contract on the blockchain and then upload a new one with added functionalities/bug fixes and point the network to it. Now with upgradable smart contracts users experience a smoother transition where they don’t have to migrate their data or tokens to a new contract. This resulted in the simplification of the process and reduced user friction.

These were the limitations that were addressed with the launch of upgradable smart contracts.
Besides addressing various limitations, we cannot let go of the benefits offered by upgradable smart contracts to its users, which was not the case with traditional smart contracts.

Here is a list of a few benefits of upgradable smart contracts, which are as follows:

  • Bug Fixes: Due to its divided nature it becomes easier for users to fix any bugs which arise after the deployment of smart contracts. This results in the adaptability with increased efficiency and security of smart contracts.
  • Future-Proofreading: With the updates, smart contracts can now be future-ready for all the enhancements and improvements in their functionality, resulting in adaptability and interaction of new features when required.
  • Cost-Effective: Instead of creating a new smart contract due to a bug that is not fixable, upgradable smart contracts allow for updates and modification of the specific parts in the smart contract that the developers wish to alter. Thereby, saving both time and resources.
  • User Trust: Users are more likely to trust a system that can be upgraded and maintained as needed. This guarantee can draw in more users, aiding in the sustained prosperity of the app.
  • Interoperability: Upgradability enables compatibility with evolving standards and protocols, ensuring that the smart contract can seamlessly integrate with other systems and platforms.
  • Long-Term Sustainability: The ability to evolve and adapt over time enhances the longevity and sustainability of the application. upgradable smart contracts can remain relevant and valuable in the ever-changing blockchain landscape.

These advantages are among those provided by smart contracts with upgradability features.

Now, that we are done with all the theoretical aspects of upgradable smart contracts, it’s important to learn the mechanism that is required to implement and run an upgradable smart contract.

Upgradable Smart Contract’s Working Mechanism

When we consider smart contracts both upgradability and mutability are poles apart. However, none of these functionalities can change the program deployed on an address on the Ethereum network.To achieve this, developers must alter the code executed during user interactions with a smart contract, utilizing several approaches:

  1. Versioned Contract Deployment: Developers may craft various iterations of a smart contract, transferring data from an older version to a new instantiation of the contract.
  2. Logic and State Separation: Another approach involves creating separate contracts to store the business logic and state, allowing for easier upgrades of the logic contract while preserving the data.
  3. Utilization of Proxy Patterns: Developers can employ proxy patterns, where function calls are delegated from a fixed proxy contract to an updatable logic contract. This approach allows for modifications to the logic without impacting the proxy.
  4. Permanent Core Contract with Flexible Auxiliary Contracts: This approach involves developers creating a non-modifiable core contract that interfaces with adaptable auxiliary contracts responsible for executing certain functions, thereby allowing for upgradability.

These methods allow developers to maintain a level of flexibility and upgradability in their smart contracts.

Amongst all methods, Proxy Patterns is one of the major element that results in the seamless implementation of upgradable smart contracts.

Proxy Patterns: Core Element of Upgradable Smart Contracts

Proxy Patterns involve the utilization of proxy contracts as a bridge between the users and the core logic contract. Acting as an intermediary Proxy Patterns enables a formal, structural, and seamless approach to handling smart contract upgrades.

When an upgrade takes place, the proxy contract is directed to point to the new logic contract, effectively channeling all user interactions toward the updated logic. This results in the continuity of user interaction while enabling the implementation of improved and updated logic transparently.

However, Proxy patterns in smart contract development have several limitations to consider. While offering upgradability, they can complicate functionality, pose challenges in logic updates, and enforce immutability for consistent addresses. Additionally, storage separation and function selector clashes may arise, and security risks can increase due to the expanded attack surface.

Moreover, Gas costs may also rise, standardized best practices could be lacking, and formal verification might be difficult. Navigating these trade-offs requires a deep understanding, potentially extending the learning curve and impacting development efficiency.

This led to the creation of various EVM proxy patterns, each tailored to meet the unique needs and requirements of different users.Certainly, here are several types of proxy patterns commonly used:

a) Simple Proxy Patterns

In the Ethereum Virtual Mchine (EVM), each smart contract operates within its own “execution context”, encompassing code execution space, storage, and an ether balance. The proxy contract maintains storage variables to manage addresses of other dApp smart contracts. To direct transactions the proxy employs a custom mechanism using “delegatecall,” allowing logic contracts to be invoked while running code within the proxy’s context.

This mechanism is housed in the proxy contracts’ fallback function, handling unsupported calls by redirecting them to logic contracts. Delegatecall ensures logic contract code execution in the proxy’s context, permitting state changes within the proxy contract. This decoupling of application state and logic enables seamless logic updates.

However, potential issues include storage collisions and “proxy selector clashing,” where proxy and logic contracts share functions with identical names or signatures, causing security vulnerabilities. This collision can also arise between functions with different names due to bytecode-level identifiers. The “transparent” proxy pattern, advocated by OpenZeppelin, addresses these challenges, providing a secure solution for smart contract upgrades.

b) Transparent Proxy Patterns

In Transparent Proxy Patterns, function calls initiated by users are routed directly to the logic contract instead of the proxy, with the exception being when the caller is the admin of the proxy. This admin privilege ensures that administrative actions are managed by the proxy, not by the logic contracts. The distinction is made based on the caller’s identity, determined by the message sender value.

The proxy’s fallback function analyzes the caller and function selector, triggering its own functions or delegating calls to logic contracts accordingly. OpenZeppelin contracts enhance this pattern by introducing a ProxyAdmin contract responsible for upgrade-related tasks. Users engage with the proxy, which in turn delegates calls to the logic contracts.

However, upgrade and admin actions are routed through the ProxyAdmin contract, providing an additional layer of abstraction.

Despite its benefits, the transparent proxy pattern has limitations. It requires cautious handling to prevent function selector clashes, incurs additional gas costs due to delegatecall operations, and can involve higher deployment gas costs.

a) The Universal Upgradable Proxy Standard (UUPS)

The Universal Upgradable Proxy Standard (UUPS) was introduced via the Ethereum Improvement Proposal (EIP) 1822. This proposal outlined a standardized approach for creating upgradable smart contracts on Ethereum by separating storage and logic, addressing function selector clashes, optimizing gas costs, and enhancing security. EIP-1822 aimed to establish consistent practices, interoperability, and improved security for Ethereum’s smart contract ecosystem.

UUPS was introduced to resolve several issues associated with previous proxy patterns by introducing a single entry point to reduce function selector clashes, simplifying logic updates through separate storage and logic contracts, optimizing gas costs, enhancing security with standardized interactions, promoting compatibility and interoperability, facilitating auditing, and making upgradable patterns more accessible for broader developer adoption.

In the UUPS (Universal Upgradeable Proxy Standard), upgrades are managed by the logic contract, particularly through the “proxiable” smart contract, from which the logic contract inherits its functionality. The upgrade mechanism, embedded in the proxiable parent contract, updates the address of the logic contract. This new address is then stored within the proxy contract. A primary challenge with this system is that if an updated logic contract does not inherit from the proxiable contract, the crucial upgrade functionality is not included. This oversight can render future upgrades to the smart contract impossible.

Indeed, the UUPS pattern offers a distinct advantage in that it allows for the removal of upgradability by simply ceasing to inherit from the proxiable contract. This option to disable upgrades is a feature not available in the Transparent Proxy pattern. Due to this advantage, OpenZeppelin and others recommend using UUPS over Transparent Proxies, even though Transparent Proxies are more popular at the time of writing.

b) Strategy pattern

This approach entails developing software applications that interact with other programs to execute specific functionalities. In the context of Ethereum development, employing the strategy pattern would involve creating a smart contract that executes functions by calling other contracts. The core business logic resides in the primary smart contract, which utilizes the functionalities of auxiliary “satellite contracts” through well-defined interfaces.

The primary smart contract, in addition to its core operational duties, manages the deployment and selection of “satellite contracts.” It stores the addresses of each satellite implementation and facilitates switching between them based on specific requirements or changing circumstances. You can readily deploy a new “satellite contract” and update the main contract with its address for immediate integration. By dynamically managing the addresses of “satellite contracts”, the main contract can readily switch between pre-deployed implementations, effectively changing its operational logic.

This approach deviates from the classic strategy pattern by delegating specific functionalities to external “satellite contracts,” allowing for dynamic switching and updates to the implemented logic without impacting the user interface or core business logic in the main contract. Introducing new functionalities or optimizations becomes a seamless process thanks to the “satellite contract” approach, allowing for targeted changes without disrupting the established core infrastructure.

While this pattern excels at implementing minor upgrades and tweaks, it might not be the ideal solution for introducing major functionality overhauls or entirely new features. A crucial drawback of this pattern is its vulnerability to main contract compromise. If the central contract containing the “satellite contract” addresses is hacked (illustrated by the image of a hacker breaching a server), the entire upgrade mechanism becomes unusable, potentially leaving the system exposed.

c) Diamond pattern

The diamond pattern has been brought by the Ethereum Improvement Proposal (EIP-2535) on the proxy pattern. Diamond proxies break the one-to-one relationship between proxy and implementation contracts. They leverage a “facet” registry within the proxy itself, enabling flexible delegation of function calls to any number of independent logic contracts, fostering modularity and code reuse.

The individual logic contracts constituting the diamond pattern are referred to as “facets,” each encapsulating specific functionalities. To facilitate dynamic routing, the diamond proxy leverages a “function selector registry.” This registry maps unique function identifiers (selectors) to the designated facet addresses, ensuring accurate delegation of calls to the appropriate logic contracts.

Upon receiving a user’s function call, the proxy contract consults its internal mapping to identify the corresponding facet entrusted with handling that specific functionality. The proxy contract seamlessly engages the delegatecall opcode within its fallback function, meticulously relaying the incoming function call to the designated facet contract for execution.

Following are some pros of the diamond upgrade pattern:

  • Helps in the upgradation of a minor part of the contract without changing the entire code.
  • By distributing functionalities across dedicated “facets,” the diamond pattern transcends traditional monolithic contracts, effectively bypassing size constraints and paving the way for scalable expansion.
  • Allows a modular permissions approach, where you can restrict entities to upgrading certain functions within a smart contract.
  • Unlike traditional smart contracts, the Diamond pattern doesn’t impose any cap on the number of “facets” (implementation contracts) you can integrate.
  • The Diamond pattern empowers you to maintain a meticulous audit trail of all facet deployments and logic updates.
  • By leveraging internal facet interactions, the diamond pattern minimizes the need for external function calls during upgrades resulting in reduced gas optimization.

Deployment of upgradable Smart Contracts on Ethereum

Let’s walk through a simplified example of how an upgradable smart contract is deployed on the Ethereum blockchain using the Proxy Pattern.

Smart Contract Logic
Assume we have a basic smart contract called MyContract that stores a simple counter value and allows users to increment it.

Proxy Contract
Next, we create a proxy contract, MyContractProxy, that will act as an intermediary between users and the actual logic contract. The proxy contract will hold the address of the current logic contract and forward all function calls to it.

Deployment and Upgrades

To deploy the upgradable smart contract, we follow these steps:

Step 1: Deploy the Logic Contract
Deploy the MyContract logic contract first. Let’s say it gets deployed at address 0xLogicContract.

Step2: Deploy the Proxy Contract
Next, deploy the MyContractProxy contract, passing the address of the logic contract as a constructor parameter. The proxy contract will now point to the logic contract.

Step 3: Interact with the Proxy
Now, to interact with the upgradable smart contract, users will interact with the MyContractProxy contract. All function calls will be forwarded to the current logic contract (0xLogicContract), which holds the actual implementation of the functions.

Step 4: Upgrading the Contract
If there’s a need to upgrade the contract, deploy a new version of MyContract with the desired changes. Let’s say the new version gets deployed at address 0xNewLogicContract.

Then, update the logic contract address in the proxy contract to point to the new version:

Now, all function calls made to the proxy contract will be directed to the updated logic contract (0xNewLogicContract), effectively upgrading the contract without changing the proxy contract’s address.

Conclusion

In conclusion, upgradable smart contracts have numerous benefits in the context of flexibility and adaptability, but several challenges need special attention. The complexity of managing upgrades, potential security risks, and the need for proper governance mechanisms are among the hurdles that developers need to overcome. Additionally, ensuring smooth data migration and optimal gas efficiency during upgrades are essential considerations for sustainable contract maintenance.

While the challenges of upgradable smart contracts are real, the future holds tremendous potential for unlocking unprecedented opportunities in the realm of decentralized applications. As developers and stakeholders work together to overcome these obstacles, upgradable smart contracts will undoubtedly shape a more dynamic, secure, and vibrant blockchain landscape, revolutionizing the way we interact with technology and laying the foundation for a decentralized future.

You may also like