fbpx

Code your first DAO

Rahul Ravindran

DAOs are an effective and safe way to work with like-minded folks around the globe. DAOs are like digital organizations with a bank account. This could be the next big trend in crypto, and they could be the future of companies

Why do we need DAOs?

Starting an organization with someone that involves funding and money requires a lot of trust in the people you’re working with. But it’s hard to trust someone you’ve only ever interacted with on the internet. With DAOs you don’t need to trust anyone else in the group, just the DAO’s code, which is 100% transparent and verifiable by anyone.

This opens up so many new opportunities for global collaboration and coordination.

Token-based membership

Usually fully permissionless, depending on the token used. Mostly these governance tokens can be traded permissionlessly on a decentralized exchange. Others must be earned through providing liquidity or some other ‘proof-of-work’. Either way, simply holding the token grants access to voting.

Typically used to govern broad decentralized protocols and/or tokens themselves.

MakerDAO – MakerDAO’s token MKR is widely available on decentralized exchanges. So anyone can buy into having voting power on the Maker protocol’s future.

Setup

We’ll be using hardhat framework for this; to get started create a folder and run

npm init --yes
npm install --save-dev hardhat

In the same directory where you installed Hardhat run:

npx hardhat

And select create an empty hardhat.config.js

Finally, install ethers.js and waffle

npm install --save-dev @nomiclabs/hardhat-ethers ethers @nomiclabs/hardhat-waffle ethereum-waffle chai

Add the highlighted line to the top of hardhat.config.js:

require("@nomiclabs/hardhat-waffle");

Start by creating a new directory called contracts and create a file inside the directory called GovernanceToken.sol

We’ll use the openzeppelin for our token, so install it using

npm install --save-dev @openzeppelin/contracts

Smart Contracts

Next, we’ll create our governance token with a max supply of 1000 and override some of the functions that are required.

Now, let’s create a protocol we want to govern using this token. That’s this really simple box contract, that’s going to be owned by the DAO that we create.

lets create a function called store that can be called by the DAO to change state variable.

// contracts/Box.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/access/Ownable.sol";

contract Box is Ownable {
    uint256 private value;

    // Emitted when the stored value changes
    event ValueChanged(uint256 newValue);

    // Stores a new value in the contract
    function store(uint256 newValue) public onlyOwner {
        value = newValue;
        emit ValueChanged(newValue);
    }

    // Reads the last stored value
    function retrieve() public view returns (uint256) {
        return value;
    }
}

Next, let’s create our governance contracts, so inside a folder called Governance create a file called GovernanceContract.sol this contract will hold all the logic for our DAO.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/governance/Governor.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorCountingSimple.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorVotes.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorVotesQuorumFraction.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorTimelockControl.sol";
import "../GovernanceToken.sol";

contract GovernorContract is
    Governor,
    GovernorCountingSimple,
    GovernorVotes,
    GovernorVotesQuorumFraction,
    GovernorTimelockControl
{
    uint256 public s_votingDelay;
    uint256 public s_votingPeriod;

    constructor(
        GovernanceToken _token,
        TimelockController _timelock,
        uint256 _quorumPercentage,
        uint256 _votingPeriod,
        uint256 _votingDelay
    )
        Governor("GovernorContract")
        GovernorVotes(_token)
        GovernorVotesQuorumFraction(_quorumPercentage)
        GovernorTimelockControl(_timelock)
    {
        s_votingDelay = _votingDelay;
        s_votingPeriod = _votingPeriod;
    }

    function votingDelay() public view override returns (uint256) {
        return s_votingDelay; // 1 = 1 block
    }

    function votingPeriod() public view override returns (uint256) {
        return s_votingPeriod; // 45818 = 1 week
    }

    // The following functions are overrides required by Solidity.

    function quorum(uint256 blockNumber)
        public
        view
        override(IGovernor, GovernorVotesQuorumFraction)
        returns (uint256)
    {
        return super.quorum(blockNumber);
    }

    function getVotes(address account, uint256 blockNumber)
        public
        view
        override(IGovernor, GovernorVotes)
        returns (uint256)
    {
        return super.getVotes(account, blockNumber);
    }

    function state(uint256 proposalId)
        public
        view
        override(Governor, GovernorTimelockControl)
        returns (ProposalState)
    {
        return super.state(proposalId);
    }

    function propose(
        address[] memory targets,
        uint256[] memory values,
        bytes[] memory calldatas,
        string memory description
    ) public override(Governor, IGovernor) returns (uint256) {
        return super.propose(targets, values, calldatas, description);
    }

    function _execute(
        uint256 proposalId,
        address[] memory targets,
        uint256[] memory values,
        bytes[] memory calldatas,
        bytes32 descriptionHash
    ) internal override(Governor, GovernorTimelockControl) {
        super._execute(proposalId, targets, values, calldatas, descriptionHash);
    }

    function _cancel(
        address[] memory targets,
        uint256[] memory values,
        bytes[] memory calldatas,
        bytes32 descriptionHash
    ) internal override(Governor, GovernorTimelockControl) returns (uint256) {
        return super._cancel(targets, values, calldatas, descriptionHash);
    }

    function _executor()
        internal
        view
        override(Governor, GovernorTimelockControl)
        returns (address)
    {
        return super._executor();
    }

    function supportsInterface(bytes4 interfaceId)
        public
        view
        override(Governor, GovernorTimelockControl)
        returns (bool)
    {
        return super.supportsInterface(interfaceId);
    }
}

You can use the openzepplin wizard to customize your governancecontract

Lastly we need to create a GovernanceTimelock.sol this is the contract that’s is going to own our protocol including the funds in our DAO.

It’s going to need 3 input parameters: a minimum delay is how long you are going to wait before executing, proposers are list of members who can participate in voting and executor is list of addresses that are going to execute proposals.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/governance/TimelockController.sol";

contract GovernanceTimeLock is TimelockController {
    // minDelay is how long you have to wait before executing
    // proposers is the list of addresses that can propose
    // executors is the list of addresses that can execute
    constructor(
        uint256 minDelay,
        address[] memory proposers,
        address[] memory executors
    ) TimelockController(minDelay, proposers, executors) {}
}

Back to the GovernanceContract.sol, the constructor takes 2 parameter: the Governance we created to asser the voting power and GovernanceTimelock instance to manage our DAO.

Now to compile run:

npx hardhat compile

Conclusion

So that’s it for this coding tutorial of a DAO.
If you want to know more about DAOs checkout this video where Julien explains how DAOs work.

0 Comments

Leave a Reply

More great articles

Best Way To Learn Solidity For Beginners

If you want to code Ethereum Dapps, you will need to learn Solidity, the programming language for smart contracts. Although…

Read Story

How much blockchain developers REALLY make?

According to Hired, blockchain developers can command salaries between 140,000 USD to 180,000 USD. Sounds amazing, right? But is it…

Read Story

The Ultimate collection of Solidity Interview Questions | 100 questions

In this article you will find 100 questions to prepare your Solidity job interview. Questions are grouped into easy, intermediate…

Read Story

Never miss a minute

Get great content to your inbox every week. No spam.
[contact-form-7 id="6" title="Footer CTA Subscribe Form"]
Arrow-up