How to make upgradeable Smart Contracts with ZeppelinOS

0 28


Photo by Hitesh Choudhary on Unsplash

Could you imagine a world where apps never update? No more bug fixes, no more new features. Need to change something in your mobile app? Well, you can always create another one! Looks scary, right?

It’s hard to imagine, but Ethereum world looked exactly like that not so long ago. All published contracts were closed for updates. If you want to upgrade a contract you need to publish another one and yes, data migration was your pain.

Fortunately, everything changed a few years ago when it became possible to use delegatecall to implement the proxy pattern. It was a door to the world of amazing opportunities for upgradability. However, this approach has been adopted rather slowly and at this moment upgradability is still perceived as a nice feature instead of something every blockchain project must have.

In this article, I’ll show you that it’s surprisingly easy to make your Ethereum project upgradeable. Interested? Let’s go.

Several strategies to make contracts upgradeable

  • Separate logic and data contracts. In this case, the logic can be replaced while keeping the data unchanged. That’s what you need for an upgradeable system. However in this case you need to force users to switch to the new logic contract.

After some research our team chose ZeppelinOS and here is why

After some research our team chose ZeppelinOS and here is why

  • It was developed by Zeppelin, the team who is well known for OpenZeppelin framework of reusable smart contracts.

There is a detailed tutorial which can help you to create your first ZOS project: https://docs.zeppelinos.org/docs/deploying.html. If you’re already familiar with ZOS or an experienced blockchain engineer, you can check out the following script to quickly set up a ZOS project:

Here is a simple example to illustrate all changes you need to make in one place:

Let’s go through all of them:

  1. Inherit zos-lib/contracts/Initializable contract.

You may consider EVM package as a usual npm package already deployed to major networks (kovan, rinkeby, ropsten and mainnet), that you don’t need to redeploy. Instead, you just need to link such a package to your project:

zos link openzeppelin-eth

It is automatically connected once you deploy your contracts. However, during testing, you still have to deploy these packages to a local network. Fortunately, it’s pretty simple:

zos push — deploy-dependencies

I’m not going to discuss the module system in detail in this article. If necessary, you can find more information about the topic here.

First of all, an upgradeable contract in ZOS is presented with logic and proxy contracts. The Proxy has a reference to the logic, and a “delegate” calls it. Once you push your contract to the network you can see the addresses of both contracts:

In practice, you only need a proxy address. Once you upload a new version of the contract, it uploads a new logic contract and updates the reference in the proxy (the proxy address remains the same). So when you reference an upgradeable contract from another contract, you refer to a proxy address. Moreover, if you make a call from your contract to another one, msg.sender becomes a proxy address as well. In other words, all other contracts working with upgradeable contract know only the other party’s proxy address and work with it.

Another important thing is that all data is stored in the proxy contract. So you can think about it as the following:

  • Proxy keeps storage

The above said means that you don’t have to migrate your data. It is enough to update contract API to make it work with the same data storage capacity. Besides, you can store more data in the new version by providing your contract with new storage members, in this way all new data becomes associated with the proxy contract.

At first, this upgradeable proxy pattern may seem to be magic. Still this concept is built on top of delegatecall feature, and you can find full proxy implementation in the AdminUpgradeabilityProxy contract. You can actually create and upgrade a proxy by yourself because it’s quite simple:

This is a perfectly working sample which you can use in your tests or solidity code to create a proxy from another contract. As an option, you can use already existing BaseApp contract to create and upgrade a proxy contract.

There are a few limitations you need to keep in mind when developing ZOS contracts:

  1. You have to use dedicated admin role for an upgradeable contract. Usually in Ethereum world the owner of a contract has exclusive access to its functionality, but you cannot take roles both of an owner and admin simultaneously. Only the admin was intended to have access to upgradeable functions (like upgradeTo or changeAdmin); hence any call from the admin to other proxy methods was supposed to fail. So remember that you need a separate account to deploy and upgrade your contracts.
  • keep old fields unchanged

You can find more details about this topic in the ZeppelinOS documentation: https://docs.zeppelinos.org/docs/writing_contracts.html#modifying-your-contracts

ZeppelinOS is a promising platform to improve development on Ethereum. Upgradability is a must-have feature for the future of smart contracts, and together with the module system, it appears to be a great basis for an ecosystem of secure decentralized applications. It’s still relatively new, and there are not that many articles about this topic, which makes it sometimes hard to find answers to important questions. However, it has already been improved a lot since version 2.x release, and I believe that it will be even better adjusted in the future.

Overall, using ZOS in production was quite a positive experience, and we’ll keep working with this platform and help it to grow!

You might also like

Pin It on Pinterest

Share This

Share this post with your friends!

WhatsApp chat