Smart Contract Upgradeability

Because new features are needed and bugs happen

Desimira Mitkova
LimeChain
5 min readJun 27, 2018

--

Yeah, it happened to me! I am sure, it happened to many other blockchain developers too - to stare at the already deployed smart contract wondering how to fix a bug or add a feature! That is the moment we all pout at the immutability of the blockchain (one of its' biggest advantages actually).

Here at Limechain, we’ve been using a technique that helps to make our contracts upgradable. It prevents our work from future troubles as bugs, hacker attacks or just the incapability to add more functionalities that may be needed in the future. Our upgradeable smart contract systems are already in production and being used by real life users. Therefore we can confidently say - it works!

We have adopted the Aragon’s team upgradeable concept which is based on the idea to deploy new smart contract with new functionalities without loosing the stored data. The biggest challenge is to keep this data and keep it useful afterwards. The simple and powerful solution is to separate logic and data in different smart contracts. In other words we use one contract to implement the logic and another to store the data. All this becomes possible trough proxy which stores the data. In addition it delegates the execution of the logic to a separate “implementation” smart contract.

Yeah, it sounds a little bit confusing. It took me a while to fully grasp the way it works, but to be honest, it’s harder to explain and to write this article than to write the actual code.

Let me try to scheme out the process.

The Proxy itself does the substantial work when it comes to making our smart contract system upgradeable. It is a simple contract that needs to know the address of the implementation contract to which it is going to delegate execution. It also has a method to change this address (when the time comes to switch to the new contract). The main part is in its fallback function. But let’s first see some code.

*For the purposes of this article and to make it more readable we add the upgradeImplementation function in the Proxy, but we highly recommend to be done in the implementation. That would save some memory in the proxy.

As you’re well aware, in Solidity when a function that has not been defined is requested, the execution goes to the fallback. Therefore when we try to execute a function that our Proxy contract doesn’t know the transaction moves to the fallback function. The fallback executes some EVM assembly with the goal 1. to “redirect” or “delegate” calls to the contract which should execute the logic and also 2. to store the result of execution in the proxy storage so that we won’t lose data when upgrading to the new implementation contract. You can see the assembly code below.

All you now need in order to communicate with this upgradeable system is an interface of the implementation contract. Please, don’t forget that the main Implementation contract must extend the interface.

The purpose of this interface is to “wrap” the Proxy and to “lie” the client side that this is a regular contract with some functions they can execute.

How does it look as a code when we have to deploy the upgradeability system?

It’s a great chance to present you the new tool our team have developed - etherlime, which allows us easily to deploy compiled contracts.

That is how it works:

Once, we deploy our Implementation1 contract and the Proxy, we can proceed with the so called “wrapping”. Next step is to use the interface at the Proxy address.

Now when you look up at the Proxy, you can access all the functions from Implementation1 contract. Because they are just an abstract functions, when you call one of them, the fallback would be activated and would delegate the execution to the implementation smart contract through the assembly.

  1. Call a function
  2. Trigger fallback
  3. Execute the assembly
  4. Execute implementation logic and store the data at the Proxy storage space

Here comes the sublime moment when the need for update occurs. Just deploy your new contract Implementation2, then execute upgradeImplementation() method. This will change the address of implementation to the new contract who will receive delegated calls.

❗Don’t forget that the new contract must have all the variables in the same order as the first one!

In the Proxy instance you will see the newly added function four() and will be able to execute the additional implemented logic. That’s all! Was it hard?

Of course, as most things in our everyday life, the upgradeability smart contract system has its pros and cons too.

Pros:

  • Forces the developer to maintain old data in new implementations
  • The system looks like a single contract for the client side apps

Cons:

  • Gives a power to the person who can update the contract
  • Changes the basic concept of immutability

Do you notice any vulnerabilities in the process? Feel free to share your views and experience with upgrading smart contracts.

Useful links:

Lime tech talks on gitter - https://gitter.im/lime-tech-talks/Lobby

Check out our latest development tool https://medium.com/limechain/etherlime-framework-8cbb270944d6

Join our Ethereum developers Facebook group - https://www.facebook.com/groups/423353978137302/

Sources:

Check out Aragon’s blog on Medium - https://blog.aragon.one/

Thanks to the Aragon team for their helpful development.

--

--