How to add DAO governance to existing token contracts

Natacha De la Rosa
Tally
Published in
5 min readJun 1, 2022

--

In my previous post, I talked about how to make your NFT contract DAO-ready from day one. But what if you have already deployed your NFT or ERC20 token contract without a future DAO? How can you add DAO governance using that existing token? Let's find out.

You can turn your token contract into a DAO by adding a Governor Contract to manage proposals and votes for your DAO. But before you can do that, you'll need to make sure your token contract is compatible with the governor.

The governor expects a particular interface from the token contract. Here's a summary of what it needs:

  • Your token contract needs a delegate(), delegateBySig(), and delegates() functions to delegate votes from one user to another.
  • Your token contract needs to have a clear definition of how to calculate the voting power of each token holder. Usually, one token = one vote, but you can also customize a formula based on the token supply. It needs to have these function definitions getVotes(), getPastVotes() and getPastTotalSupply().
  • Last but not least, your token contract needs to emit event logs for vote changes, token transfers, and delegation changes. It needs to have these specific events definitions DelegateChanged, DelegateVotesChanged, and Transfer.

To get more information about what these functions and events signatures look like and what they should return, please read the Open Zeppelin IVotes definition.

Now that you know what your token contract needs, I can explain how you can achieve this. There are two ways, depending on how you created your token contract in the first place.

With the OpenZeppelin contracts library, I can add ERC20Votes or ERC721Votes accordingly depending on my token type and override some necessary methods even if my contract is not upgradable.

If your contract is upgradable, you'll need to create a new implementation and update the proxy so it implements the additional libraries your token contract needs.

If your contract is not upgradable, you'll create an additional contract with the features I've mentioned above. Then you'll need to allow users to stake the tokens they hold to mint the new ones.

1. Your token contract is upgradable

If this is your case, you have the easiest path forward.

You need to have administration permissions of the contract to perform these changes. If you don't, you won't be able to update the token implementation of the upgradable contract.

First, let's say I have the following token contract that I've deployed on Rinkeby. It doesn't support delegation or any other voting capabilities, but it is upgradable:

Now, I need to update my token to have a new implementation that supports delegation and other voting capabilities like so:

After that, I can run the update task, and my contract will have the new implementation I need:

That's it, and now my token contract has everything it needs to be used with my governor contract!

2. Your token contract is not upgradable

If this is your case, don't worry. Everything has a solution. You'll need a few more steps but nothing too complicated.

I'll first create a new contract; you can make it upgradable or not, but in this example, I'll make it not upgradable to show both sides. If you want to create it to be upgradable, you can refer to the previous one I created.

I will implement the features I need to make my token compatible with a governor contract in this new token contract. Then I'll create two additional functions to allow my token users to stake their tokens and withdraw them from this contract.

You will also need to create a simple UI to allow your users to do these actions. That's all you'll need to do. Let's jump right into it.

Let's say I have this ERC721 token that is already deployed in Rinkeby, but it doesn't have any upgradable capabilities:

In this case, I'll need to create a new ERC721 token that has the DAO capabilities I need. This new contract will allow current token holders to deposit their owned tokens. Then, they can receive the new voting token and participate in my DAO. The token holders will also have the option to withdraw their staked tokens.

Let's start by creating the new ERC721 token like so:

My new ERC721 token contract should have these functionalities:

  • Mintable: I'll use this functionality to mint a unique token for my token holders each time they stake a token they hold of OldNFTToken into the NewNFTToken.
  • Burnable: I'll use this functionality to burn a minted NewNFTToken when the holder withdraws NewNFTToken.

Now I'll add two new functions to my new contract to manage the staking and withdrawing processes:

  1. First, create a state variable to receive the current NFT contract address.

2. Now, I'll update the constructor to receive the address of my OldNFTToken.

3. I'll also update the safeMint function to look like so:

4. Then, I'll add the functions to stake and withdraw

5. Last but not least, I'll add ERC721Receiver implementation to my contract so that it can support safe transfers:

Now the new ERC721 token should look like this:

That's it. Now you can use the NewNFTToken in your governor.

3. Adding a Governor

Now that we have seen how to update both types of tokens to support voting and delegation so they work with the governor contract, I'll create the contracts I need to deploy my governor. First, I'll create a Timelock contract:

2. Now, I'll create my governor contract. It should look like so:

We can now compile and generate the typings of our contracts:

yarn compile & yarn typechain

3. Finally, I'll create a hardhat task to deploy our contracts. It should look like so:

Now to deploy our new governor, we can run:

yarn hardhat deploy:Governance

We have completed this small tutorial, and we've learned how to update our token contract to be DAO-ready and deploy a governor contract for them. You can create a DAO and list it on Tally with your new governor and token.

You can find the sample code for this tutorial here.

I hope you enjoyed this post. Feel free to post in the comments with your thoughts, questions, and any requests for future posts.

--

--