ZeppelinOS: Upgradable Smart Contracts

Image for post
Image for post
Image Source: https://zeppelinos.org/

Complete E2E setup to implement an upgradable smart contract with ZeppelinOS (version 2.0.0)

ZeppelinOS is an open-source, distributed platform of tools and services on top of the EVM to develop and manage smart contract applications securely.

Pre-requisite:

node and npm installed.

Steps to follow:

  1. Install zeppelin os npm package globally

2. Make a new project directory

3. Initialize the newly created directory

This command will create a package.json file with initial project information.

package.json

4. Initialize the directory with ZeppelinOS

Console output:

Successfully written zos.json

This command will create a truffle project with zos.json file.

truffle-config.js

This file contains the network properties.

zos.json

This file contains the deployed contract information. As we will deploy smart contracts it will show under contracts.

Folder Structure

| package.json
| truffle-config.js
| zos.json
|
+ — -contracts
| .gitkeep
|
+ — -migrations
| .gitkeep

5. Add zeppelin library as node module

This module contains the files that support the smart contract upgradability. We will use these features while creating the smart contract.

6. Create a smart contract under contracts folder

Elixir.sol

Note: with ZeppelinOS we can’t use a constructor function.

Here we are importing the Initializable.sol contract from ZeppelinOS library and extending our Elixir contract with that. This file contains the initializer method which will make sure that initialize function will work as a constructor.

7. Compile the smart contract with ZeppelinOS

Console output:

Compiling contracts
Compiling .\contracts\Elixir.sol…
Compiling zos-lib/contracts/Initializable.sol…
Writing artifacts to .\build\contracts

Adding Elixir
Successfully written zos.json

This command will compile the solidity smart contract and place it under build/contracts folder, now we have a contract available in zos.json file.

zos.json

If you are getting errors while compilation, it may be because of solidity compiler version. To overcome these errors install valid compiler version mentioned below.

8. Install and run ganache-cli

Ganache is a personal blockchain for Ethereum development you can use to deploy contracts, develop your applications, and run tests. It is available as both a desktop application as well as a command-line tool (formerly known as the TestRPC).

Now, start ganache-cli on port 9545

9. Create ZeppelinOS session using the local address provided by ganache

Console output:

Using network local, sender address 0xf7ee5fe58b503bc4b03f8fbd95eebdb37ee29bce by default.

senders_address is one of the local address provided by the ganache-cli.

Note: Don’t use the first address from ganache-cli. It may cause some errors while interacting with the deployed contract.

10. Push/ Deploy the smart contract on the local net

Console output:

Using session with network local, sender address 0xf7ee5fe58b503bc4b03f8fbd95eebdb37ee29bce
Compiling contracts
Compiling .\contracts\Elixir.sol…
Compiling zos-lib/contracts/Initializable.sol…
Writing artifacts to .\build\contracts

Validating contract Elixir
Uploading Elixir contract as Elixir
Deploying logic contract for Elixir
Created zos.dev-1545075280693.json

It will create a logic contract instance and zos.dev-<network_id>.json file.

This file (zos.dev-1545075280693.json) contains the properties of logic contract (address, hashes etc) and has a field to update the values for the proxy contract.

11. Create a proxy contract for the deployed logic contract that can be accessed by delegate calls

Console output:

Using session with network local, sender address 0xf7ee5fe58b503bc4b03f8fbd95eebdb37ee29bce
Creating proxy to logic contract
0x079402e050ae5fe91445b9d2e31771ff82d1c430 and initializing by calling initialize with:
— _automation_tool (string): “protractor”
Instance created at 0x00709a8485ece42ed7ebdc4f6307711bf28450a2
0x00709a8485ece42ed7ebdc4f6307711bf28450a2
Updated zos.dev-1545075280693.json

This command helps to initialize and create a proxy contract for deployed logic contract. So, we can easily upgrade the proxy contract and access the data from the logic contract by delegate calls.

It’ll console output the address of deployed proxy contract, we’ll use this proxy contract address to make the delegate calls.

Updated proxy properties in zos.dev-1545075280693.json file.

Here address0x00709a8485ece42ed7ebdc4f6307711bf28450a2 is of deployed proxy contract and implementation 0x8738d8b87d770220aaf91239adc62a2ff3f88bbe is for the address of deployed logic contract.

12. Use truffle develop to interact with the deployed proxy contract

truffle(develop)> elixir = Elixir.at(“0x00709a8485ece42ed7ebdc4f6307711bf28450a2”)

Console output: contract properties

truffle(develop)> elixir. elixir_automation_tool().then(console.log)

Console output: protractor

13. Update the existing smart contract

Elixir.sol

Added new function automation_language()

14. Push the new changes and update the deployed proxy contract

Console output:

Using session with network local, sender address 0xf7ee5fe58b503bc4b03f8fbd95eebdb37ee29bce
Compiling contracts
Compiling .\contracts\Elixir.sol…
Compiling zos-lib/contracts/Initializable.sol…
Writing artifacts to .\build\contracts

Validating contract Elixir
Uploading Elixir contract as Elixir
Deploying logic contract for Elixir
Updated zos.dev-1545075280693.json

Console output:

Using session with network local, sender address 0xf7ee5fe58b503bc4b03f8fbd95eebdb37ee29bce
Upgrading proxy to logic contract
0xc9daa46260e693dcff0f640f1b9fa9e795e7e3de
Instance at 0x00709a8485ece42ed7ebdc4f6307711bf28450a2 upgraded
0x00709a8485ece42ed7ebdc4f6307711bf28450a2
Updated zos.dev-1545075280693.json

upgraded the logic contract and mapped to same proxy contract instance.

zos.dev-1545075280693.json

15. Use truffle develop to interact with upgraded contract

truffle(develop)> elixir = Elixir.at(“0x00709a8485ece42ed7ebdc4f6307711bf28450a2”)

Console output: contract properties

truffle(develop)> elixir. elixir_automation_tool().then(console.log)
Console output: protractor

Upgraded smart contract function call

truffle(develop)> elixir.automation_language().then(console.log)
Console output: protractor : typescript

Final Folder Structure

| package.json
| package-lock.json
| truffle-config.js
| zos.dev-1545075280693.json
| zos.json
|
| node_modules
|.zos.session
|
+ — -contracts
| Elixir.sol
| .gitkeep
|
+ — -build
| + — -contracts
| | Elixir.json
| | Initializable.json
|
+ — -migrations
| .gitkeep

This is how we can achieve smart contract upgradability using ZeppelinOS.

Written by

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store