-
Notifications
You must be signed in to change notification settings - Fork 142
DAO DAO Contracts Design
The DAO DAO contracts are governance Lego blocks. This enables highly customizable governance configurations that are upgradable in the face of vulnerabilities or bugs.
Each DAO is composed of at least three modules:
- A core module. This handles execution of messages on behalf of the DAO and holds the DAO's treasury.
- A voting power module. This module is responsible for determining the voting power of members. For example, it may be based on how many governance tokens you have staked, or multisig-style voting weights.
- At least one proposal module. Proposal modules handle the lifecycle of proposals. Different modules may support, for example, single or multiple choice voting. A DAO may register more than one proposal module to support any number of proposal types. Proposal modules are very powerful and can do way more than just manage proposals.
In addition, most DAOs will make use of a pre-propose module to enable proposal deposits and gating for who may create a proposal.
Modules are defined by their interface, not by their implementation. This enables DAOs to implement custom modules to support their governance requirements. For example, NETA DAO uses a custom proposal module, and Wynd DAO uses a custom voting module and staking system.
Here is a high level diagram of how these modules fit together to form a DAO:
The core module executes messages on behalf of the proposal
modules. To this end it exposes a ExecuteProposalHook { msgs }
method. This method may only be called by proposal modules that have
been registered with the core contract. For example, this may occur
when a proposal module has passed a proposal and would like to execute
it.
The core module may also route queries between proposal modules and
its voting module about voting power. To this end it implements the
same interface for queries that voting modules must implement.
Specifically, it implements a VotingPowerAtHeight { addr, height }
and TotalPowerAtHeight { height }
query. These queries will be
proxied to the core module's voting module and that response
returned. This allows proposal modules to make voting power queries
without needing any information about the current voting
configuration.
At all times the core contract must have one voting module associated with it and at least one proposal module associated with it.
The core contract may add and remove proposal and voting modules at
will by calling the UpdateVotingModule
and UpdateProposalModules
methods on itself.
To better support subDAOs the core contract may also be instantiated with an admin. This admin has the ability to execute messages on the core module outside of the regular governance flow. The current admin may also nominate a new admin or remove themselves. If no admin is set, the core module is considered its own admin and may nominate new admins itself. This admin functionality makes subDAOs accountable to their parent DAO.
The process for assigning a new admin has two steps:
- The current admin nominates a new admin.
- The new admin accepts the nomination and becomes the admin.
These are accomplished via the NominateAdmin
and
AcceptAdminNomination
messages. The current admin may, at any time,
withdraw their nomination by executing a WithdrawAdminNomination
message. In order to nominate a new admin any outstanding nomination
must be withdrawn.
The admin is not able to execute messages on a paused subDAO.
+---------------+ +----------------+
| core | | |
| | |special purpose |
| | /-->|contract |
| +-----+ /------- | |
| | key |---- +----------------+
+-----------+-----+
Items are key value pairs stored in the core contract. Their key is a string and their value is a string. One may use these to store information like the social media addresses of a DAO, or the contract address of a related smart contract.
The core contract may add and remove these items by calling the
SetItem
and RemoveItem
methods on itself. In practice this occurs
by proposal modules sending a execute hook that will cause the
core contract to call that method on itself.
Voting modules are responsible for tracking the voting power of DAO
members as a function of block height. They implement a
VotingPowerAtHeight
and TotalPowerAtHeight
query which other
modules may use to determine the weight of an addresses' vote on a
proposal. For voting modules that do voting based on a token the
module may also implement a TokenContract
query which will return
the address of the token being used.
Voting modules have an intentionally minimal interface. In practice, they are typically backed by aother contract which provides weights. For example, for token based DAOs voting power is determined by number of staked tokens. The voting power module then translates queries about staked balances into voting powers.
Here's an overview of how the pieces come together for staked balances based voting power:
And here's an example voting power query against that configuration:
Proposal modules are extremely flexible and don't have any particular interface they must implement. They only need to be aware of how to execute the proposal hook on the core contract.
It is imagined that proposal contracts will mostly implement some kind of proposal and voting system. For example, they might support ranked choice voting, multiple choice voting, or quadratic voting. In practice, this is not enforced and a core contract may register any proposal contract it would like.
cwd-proposal-single
is the standard proposal contract and allows for
single choice (yes or no) voting. Proposal contracts can manage
multiple proposals so a new one is not created for each proposal. In
the case of cwd-proposal-single
the contract implements a variety of
queries to help the frontend display proposal information. Future
proposal module authors may consider implementing a similar interface.
Pre-propose modules are an extension of proposal modules that enable pre-flight checks for proposal creation. For example, a pre-propose module may:
- require a proposal deposit is paid before proposal creation;
- only allow DAO members to create proposals;
- or, require a non-refundable payment of native tokens to create a proposal.
The above functionality is supported by the cwd-pre-propose-base
package and pre-propose module authors may use that to write
pre-propose modules for their proposal modules.
(2) what kind of module are you?
+-------------+ -----------------> +----------+
| frontend | | module |
| | | |
| | -----------------> +----------+
+-------------+ (3) module specific queries
|
|
| (1) what modules do you have?
|
v
+-----------+
|core |
| |
| |
+-----------+
All modules in this system must implement an Info {}
query which
return the contract's name and its version. To render a module the
frontend will then query a the core contract for its modules and then
query those modules for their info.