Enter the Dōjō: Celo Governance Proposals

Keyko’s how-to guide to creating Celo Governance Proposals for Upgrading System Contracts

Sami Mäkelä
Keyko
5 min readMay 15, 2020

--

This tutorial will show how to deploy new versions of system contracts to the Celo network, and how to make proposals to upgrade them. We’ll also see how to verify the contract on Blockscout. The part about writing proposals should be helpful for other kinds of proposals like setting network parameters, and not just contract upgrades.

Source: Flickr

Deploying the contract

In a nutshell, the structure of Celo system contracts is as follows:

  • The addresses of Celo contracts are stored in the registry contract (address 0xce10)
  • These contracts are implemented using the unstructured storage proxy pattern (https://blog.openzeppelin.com/upgradeability-using-unstructured-storage/). This means that the addresses contain the storage, but the code is in a different address (the implementation address)
  • The Governance contract is the owner of all these contracts.

So the addresses that are in the registry are actually the “Proxy” contracts in the source code. For example, if you query the registry for “LockedGold”, you’ll get the address of “LockedGoldProxy” contract, and the code corresponding to “LockedGold.sol” is stored in the implementation address of the proxy contract.

We are going to create a governance proposal for upgrading a Celo system contract, so first we have to get the Celo contract source code.

git clone https://github.com/celo-org/celo-monorepo
cd celo-monorepo

Some of the tooling was outdated, so we have to checkout an updated branch

git checkout mrsmkl/upgrade-command

Let’s build the dependencies:

yarn && cd packages/dev-utils && yarn build
cd ../utils && yarn build
cd ../protocol && yarn build

The contract we have selected to upgrade is “DowntimeSlasher” because we want to add an event that is emitted when this kind of slashing is performed. The following are the phases to upgrading the contract:

  1. Modifying the contract source code. In our case, the source has already been modified in the master branch compared to Baklava.
  2. Compile the code to EVM bytecode.
  3. Deploy the bytecode to create a contract inside the Celo network.
  4. Set the contract implementation in the proxy to point to our new contract. This last step needs to be done using governance. We do not want to create a new proxy because we want to persist the old data.

Let’s compile our contracts:

export NETWORK=baklava
yarn run truffle compile --network $NETWORK --build_directory \ $PWD/build/$NETWORK

The script to upgrade contracts is at “scripts/truffle/upgrade.ts”. This script assumes your default account at http://localhost:8545 has to be unlocked. Also edit truffle-config.js to make it use your address. For example, if your address is “0xa614aa339dc70f708f8941773a302258f012f56b”, change the constant “OG_FROM” to

const OG_FROM = '0xa614aa339dc70f708f8941773a302258f012f56b'

This works for the Baklava network, in other networks you should just change the corresponding line.

Then we can run the script using:

yarn run truffle exec ./scripts/truffle/upgrade.js \
--network $NETWORK --build_directory $PWD/build/$NETWORK \
--contract DowntimeSlasher

This should deploy the contract and output the contract address. It will be needed when writing the proposal. This time it returned “0xf04d24429aA0c62eFBEFf34377FA3ff8303fe029”.

Verifying contracts

From imgflip.com

People will be suspicious if you are proposing a contract change without providing source code. A very good way to increase trust is to verify the code in Blockscout. Blockscout should also show enough info so that people can verify the contract themselves.

In this case, the verification can be performed using the following command:

yarn run truffle run verify-blockscout DowntimeSlasher \
--blockscout-url https://baklava-blockscout.celo-testnet.org/ \
--network $NETWORK

Replace the Baklava Blockscout address if you are using a different network.

The assets at build/$NETWORK/contracts have enough information to perform the verification, so you don’t have to specify the contract address or other details.

Writing and submitting governance proposals

Now we can start writing the actual governance proposal. The proposal is a list of transactions that the governance contract will execute if the proposal passes.

[{"contract": "DowntimeSlasherProxy",
"function": "_setImplementation",
"args": ["0xf04d24429aA0c62eFBEFf34377FA3ff8303fe029"],
"value": "0"
},
{"contract": "DowntimeSlasher",
"function": "setSlashingIncentives",
"args": ["100000000000000000000", "900000000000000000000"],
"value": "0"
}]

For our proposal, we only need one transaction as it will set the implementation of the contract. But for completeness, I added another transaction that will make slashing rewards higher. The method used can be found here (https://github.com/celo-org/celo-monorepo/blob/master/packages/protocol/contracts/governance/SlasherUtil.sol#L29). The onlyOwner modifier means that this method can only be called by the owner of the contract; that is, the Governance contract.

Here is a breakdown of the fields used in the proposal:

  • The field ‘contract’ is the name of the contract in the registry. So this means the proxy contract address (this includes all the storage). In this case we have to use the “DowntimeSlasherProxy” because otherwise celocli cannot build the proposal.
  • The field “function” is the name of the method that is called from the contract.
  • The field “args” is the list of arguments. Argument types are read from the ABI that is built-in to celocli. In this case the argument should be the address.
  • The field “value” is the cGLD value of the transaction.

Now we just need to post the proposal using celocli. If you haven’t installed celocli yet, it can be installed using command:

yarn global add @celo/celocli

To make a proposal, a deposit of 100 cGLD is needed.

celocli governance:propose --deposit 100000000000000000000 \
--descriptionURL https://baklava-blockscout.celo-testnet.org/address/0x5195479f57a05b36b27d315e9ab3450c9c077b36/contracts \
--jsonTransactions proposal.json \
--from 0xa614aa339dc70f708f8941773a302258f012f56b

The deposit can be withdrawn by using celocli governance:withdraw (perhaps available in the next version of celocli).

And that’s it…upgrade proposed!

From imgflip.com

Conclusion

As you can see, creating and submitting a Celo governance proposal is pretty straightforward. Most of the complexity is in the governance proposal itself. Trustworthiness is also a factor, so it’s best if the upgrades are clear and transparent for the community to validate.

As always, Keyko is here to help, so feel free to ping us anytime at info@keyko.io.

www.keyko.io

--

--