Governance for Smart Contract Upgrades

Content migrated from https://docs.openzeppelin.com/sdk/upgrades-governance.
This article was originally published in September 2018, and may no longer reflect best practices.

Governance for Smart Contract Upgrades

Introduction

The OpenZeppelin CLI provides the chance to have upgradeable smart contracts which follows the immutability rules guaranteed by the Ethereum blockchain. However, it is desirable to have a mechanism that allows all parties involved to decide on whether a contract should be upgraded or not, instead of having an unilateral decision.

Given that there are many projects already working on really good solutions to achieve decentralized governance, we’ve been exploring some of them to study how they can be integrated with the OpenZeppelin CLI to manage contract upgrades.

In this case, we will use a multisignature wallet.

Getting started

A multisig is a contract that can execute arbitrary transactions, with the restriction that a certain number of owners must agree upon them. We highly recommend using the Gnosis MultiSig Wallet, which was audited by the OpenZeppelin team and has a https://wallet.gnosis.pm/[useful dApp] for submitting and confirming transactions. You can use it easily to deploy your own multisig wallet.

Once inside your OpenZeppelin project, let’s suppose we have an arbitrary contract called MyContract. Now let’s see how we can create an upgradeable instance of it being handled by a multisig wallet. In order to do that, we will need first to register this contract, push it to the network and create a new upgradeable instance of it as we explained in the previous sections:

$ npx oz add MyContract
$ npx oz push -n ropsten
$ npx oz create MyContract -n ropsten

We have our contract deployed to the ropsten network, with an instance of our MyContract contract up and running. At this point, the ownership of the project is being controlled by the deployer account, which can unilaterally decide when to upgrade any of its contracts.

Transferring control

Since we want to avoid having a single account with full control over our MyContract instance, we’ll transfer control of it to our multisig contract. To do this, we’ll use the set-admin command to yield control to the multisig account.

$ npx oz set-admin [MYCONTRACT_ADDRESS] [MULTISIG_ADDRESS] -y

NOTE: Please remember to replace [MYCONTRACT_ADDRESS] by the address of the upgradeable instance of MyContract we created above. Additionally, [MULTISIG_ADDRESS] should be replaced by the address of your multisig wallet contract.

IMPORTANT: The -y option is mandatory to carry out this action. Bear in mind that this could be an irreversible operation in case you specify an incorrect admin address.

Now, if we want to upgrade our MyContract instance to a new version, we’ll need to perform the operation from the multisig contract. Note that we have transferred only the ownership of our MyContract instance. If we had created more instances of MyContract, or of any other contract, they would still be under control of the deployer account.

The same applies to our OpenZeppelin CLI app. This allows us to keep interacting with our project via the CLI, by creating new instances or registering new logic contracts, as we’ll be doing in the next step.

Uploading a new version

Let’s suppose we extend the functionality somehow. The first step is to upload this new logic contract to the blockchain. Since the whole project is still managed by our deployer account, we can easily do that from the CLI by running:

$ oz add MyContract
$ oz push

Now that our new logic contract is uploaded to the network, we can proceed to upgrade our MyContract instance.

Upgrading our contract instance

At this point, if we attempt to upgrade our MyContract instance to the new version through the CLI, we’ll get an error since the deployer account no longer has upgrade rights over the contract instance. We need to go through the multisig to perform this operation, as the CLI’s account.

Let’s submit a transaction to the multisig wallet for our contract instance to be upgraded. We can do this from the Gnosis dApp by including the proxy’s ABI and choosing to invoke upgradeTo. We also need to supply the address of the new implementation, which can be found in the output of the last openzeppelin push command or in the .openzeppelin/ropsten.json file.

This will create a new transaction in the multisig wallet for the MyContract instance to be upgraded to the latest MyContract implementation. However, since this requires the approval of at least another multisig owner, the upgrade is still pending.

As soon as another owner of the multisig account confirms this transaction, it will be executed on the spot and our MyContract instance contract will be upgraded to the desired version, allowing us to make use of the new functionality we built.

2 Likes

Gnosis multisig 2.0 a.k.a. as “Safe” is available now. It looks very different and is more user friendly. These instructions do not apply for the new version.

However it does not support ABI encoding yet, though the support is coming. You can still use Proxy with the wallet as long as you create Data field from ABI encodings by hand.

2 Likes

Continuing the discussion from Governance for Smart Contract Upgrades:

Hello! I’ve been following this for a while now, and need the updated answer for a project I’m working on.

If you would be so kind, could you update your ETH StackExchange and this forum’s answers to include updates for ABI support? I have not been able to find a concise description of this support being added as of 2021.

Lastly, how cheap can one realistically make the implementation updates for these contracts? If these are not inexpensive updates, then how is updating a contract economically feasible?

1 Like

Hi @Aleph0,

Welcome to the community :wave:

Things have moved on since this was first posted. To deploy upgradeable contracts we use OpenZeppelin Upgrades Plugins (https://docs.openzeppelin.com/upgrades-plugins/1.x/). OpenZeppelin CLI is no longer being developed (see: Building for interoperability: why we’re focusing on Upgrades Plugins).

For a multisig you may want to look at Gnosis Safe rather than Gnosis Multisig.

The following tutorials show how to upgrade a contract controlled by a Gnosis Safe.

As for the cost of upgrading, you are deploying a new implementation contract each time you upgrade, so the cost of this depends on the price of gas (which increases with network congestion) and the price of Ether. Which at the moment means that any contract deployment is not a low cost exercise.