Skip to content

Commit 4a4c913

Browse files
committed
added guide on adding a proposal module
1 parent 6f156d6 commit 4a4c913

File tree

1 file changed

+223
-0
lines changed

1 file changed

+223
-0
lines changed
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
---
2+
sidebar_position: 5
3+
---
4+
5+
# How to add a proposal module
6+
7+
The proposal module system enables DAOs to support any type of execution flow
8+
that can be coded in a smart contract.
9+
10+
DAO DAO provides two modules:
11+
12+
- single choice (e.g. Yes/No/Abstain)
13+
- multiple choice (e.g. A/B/C/None of the Above)
14+
15+
You can always add new modules or disable existing ones, though there must
16+
always be at least one module enabled (or else the DAO will not function). The
17+
most likely reason one would want to add a new module is to use a new version
18+
with new features. Because the proposal module interface is standardized and
19+
unchanging, newer versions of proposal modules should be backwards compatible.
20+
21+
Adding and disabling proposal modules is not common, and can be dangerous, and
22+
thus is not easily supported by the UI, but it is not hard to do with a little
23+
bit of time.
24+
25+
> ⚠️ Be careful to verify all proposal modules function correctly before
26+
> disabling one you no longer need, because if the only enabled proposal modules
27+
> are broken or the addresses are incorrect, the DAO will be bricked and all
28+
> assets will be locked.
29+
30+
## Guide
31+
32+
First you need the code IDs of the proposal module and its corresponding
33+
pre-propose module. You can find all uploaded DAO DAO code IDs here:
34+
https://github.com/DA0-DA0/dao-dao-ui/blob/development/packages/utils/constants/codeIds.json
35+
36+
The following guide will add the `v2.6.0` single choice proposal module to a DAO
37+
on Osmosis mainnet (`osmosis-1`), so we need the `dao-proposal-single` and
38+
`dao-pre-propose-single` code IDs.
39+
40+
Here is the configuration we will use:
41+
42+
- threshold: majority
43+
- quorum: 20%
44+
- max voting period: 1 week
45+
- only members can execute: true
46+
- close proposal on execution failure: true
47+
- allow revoting: false
48+
- submission policy: DAO members only
49+
- no proposal deposit
50+
51+
You can look at the JSON schemas' `instantiate` definitions for the proposal and
52+
pre-propose modules to see the configuration fields you need to set, as well as
53+
the `dao-dao-core` contract's JSON schema to see the `update_proposal_modules`
54+
execution message that performs the actual update:
55+
56+
- [dao-proposal-single JSON schema](https://github.com/DA0-DA0/dao-contracts/blob/development/contracts/proposal/dao-proposal-single/schema/dao-proposal-single.json)
57+
- [dao-pre-propose-single JSON
58+
schema](https://github.com/DA0-DA0/dao-contracts/blob/development/contracts/pre-propose/dao-pre-propose-single/schema/dao-pre-propose-single.json)
59+
- [dao-dao-core JSON schema](https://github.com/DA0-DA0/dao-contracts/blob/development/contracts/dao-dao-core/schema/dao-dao-core.json)
60+
61+
You can also look at the Rust source code, which contains the corresponding
62+
`InstantiateMsg` and `ExecuteMsg` structs, though you will need to know how
63+
serde serializes various types and enums which can be tricky. The JSON schemas
64+
above contain all the information you need, but here is the source code for
65+
reference:
66+
67+
- [dao-proposal-single `InstantiateMsg`
68+
struct](https://github.com/DA0-DA0/dao-contracts/blob/development/contracts/proposal/dao-proposal-single/src/msg.rs)
69+
- [dao-pre-propose-single `InstantiateMsg`
70+
struct](https://github.com/DA0-DA0/dao-contracts/blob/development/contracts/pre-propose/dao-pre-propose-single/src/contract.rs)
71+
which just extends the [dao-pre-propose-base `InstantiateMsg`
72+
struct](https://github.com/DA0-DA0/dao-contracts/blob/development/packages/dao-pre-propose-base/src/msg.rs)
73+
- [dao-dao-core `ExecuteMsg`
74+
struct](https://github.com/DA0-DA0/dao-contracts/blob/development/packages/dao-interface/src/msg.rs)
75+
defined in the `dao-interface` crate.
76+
77+
Putting that all together, the full message we need to execute on the DAO via a
78+
proposal, with everything decoded for readability, follows:
79+
80+
```
81+
{
82+
"update_proposal_modules": {
83+
"to_add": [{
84+
"admin": { "core_module": {} },
85+
"code_id": 1252,
86+
"label": "dao-proposal-single-v2.6.0",
87+
"msg": {
88+
"threshold": {
89+
"threshold_quorum": {
90+
"threshold": { "majority": {} },
91+
"quorum": { "percent": "0.2" }
92+
}
93+
},
94+
"max_voting_period": { "time": 604800 },
95+
"only_members_execute": true,
96+
"close_proposal_on_execution_failure": true,
97+
"allow_revoting": false,
98+
"pre_propose_info": {
99+
"module_may_propose": {
100+
"info": {
101+
"code_id": 1250,
102+
"msg": {
103+
"submission_policy": {
104+
"specific": {
105+
"dao_members": true,
106+
"allowlist": [],
107+
"denylist": []
108+
}
109+
},
110+
"extension": {}
111+
},
112+
"admin": { "core_module": {} },
113+
"funds": [],
114+
"label": "dao-pre-propose-single-v2.6.0"
115+
}
116+
}
117+
}
118+
},
119+
"funds": []
120+
}],
121+
"to_disable": []
122+
}
123+
}
124+
```
125+
126+
Now we have to recursively encode the `msg` fields with base64, so starting from
127+
the innermost `msg` field for the pre-propose module instantiation message:
128+
129+
```
130+
{
131+
"submission_policy": {
132+
"specific": {
133+
"dao_members": true,
134+
"allowlist": [],
135+
"denylist": []
136+
}
137+
},
138+
"extension": {}
139+
}
140+
```
141+
142+
This gets base64-encoded to:
143+
144+
```
145+
ewogICJzdWJtaXNzaW9uX3BvbGljeSI6IHsKICAgICJzcGVjaWZpYyI6IHsKICAgICAgImRhb19tZW1iZXJzIjogdHJ1ZSwKICAgICAgImFsbG93bGlzdCI6IFtdLAogICAgICAiZGVueWxpc3QiOiBbXQogICAgfQogIH0sCiAgImV4dGVuc2lvbiI6IHt9Cn0=
146+
```
147+
148+
Now isolate the proposal module instantiation `msg`, and replace the pre-propose
149+
module instantiation `msg` field with the base64-encoded pre-propose module
150+
instantiation message from above:
151+
152+
```
153+
{
154+
"threshold": {
155+
"threshold_quorum": {
156+
"threshold": { "majority": {} },
157+
"quorum": { "percent": "0.2" }
158+
}
159+
},
160+
"max_voting_period": { "time": 604800 },
161+
"only_members_execute": true,
162+
"close_proposal_on_execution_failure": true,
163+
"allow_revoting": false,
164+
"pre_propose_info": {
165+
"module_may_propose": {
166+
"info": {
167+
"code_id": 1250,
168+
"msg": "ewogICJzdWJtaXNzaW9uX3BvbGljeSI6IHsKICAgICJzcGVjaWZpYyI6IHsKICAgICAgImRhb19tZW1iZXJzIjogdHJ1ZSwKICAgICAgImFsbG93bGlzdCI6IFtdLAogICAgICAiZGVueWxpc3QiOiBbXQogICAgfQogIH0sCiAgImV4dGVuc2lvbiI6IHt9Cn0=",
169+
"admin": { "core_module": {} },
170+
"funds": [],
171+
"label": "dao-pre-propose-single-v2.6.0"
172+
}
173+
}
174+
}
175+
}
176+
```
177+
178+
This gets base64-encoded to:
179+
180+
```
181+
ewogICJ0aHJlc2hvbGQiOiB7CiAgICAidGhyZXNob2xkX3F1b3J1bSI6IHsKICAgICAgInRocmVzaG9sZCI6IHsgIm1ham9yaXR5Ijoge30gfSwKICAgICAgInF1b3J1bSI6IHsgInBlcmNlbnQiOiAiMC4yIiB9CiAgICB9CiAgfSwKICAibWF4X3ZvdGluZ19wZXJpb2QiOiB7ICJ0aW1lIjogNjA0ODAwIH0sCiAgIm9ubHlfbWVtYmVyc19leGVjdXRlIjogdHJ1ZSwKICAiY2xvc2VfcHJvcG9zYWxfb25fZXhlY3V0aW9uX2ZhaWx1cmUiOiB0cnVlLAogICJhbGxvd19yZXZvdGluZyI6IGZhbHNlLAogICJwcmVfcHJvcG9zZV9pbmZvIjogewogICAgIm1vZHVsZV9tYXlfcHJvcG9zZSI6IHsKICAgICAgImluZm8iOiB7CiAgICAgICAgImNvZGVfaWQiOiAxMjUwLAogICAgICAgICJtc2ciOiAiZXdvZ0lDSnpkV0p0YVhOemFXOXVYM0J2YkdsamVTSTZJSHNLSUNBZ0lDSnpjR1ZqYVdacFl5STZJSHNLSUNBZ0lDQWdJbVJoYjE5dFpXMWlaWEp6SWpvZ2RISjFaU3dLSUNBZ0lDQWdJbUZzYkc5M2JHbHpkQ0k2SUZ0ZExBb2dJQ0FnSUNBaVpHVnVlV3hwYzNRaU9pQmJYUW9nSUNBZ2ZRb2dJSDBzQ2lBZ0ltVjRkR1Z1YzJsdmJpSTZJSHQ5Q24wPSIsCiAgICAgICAgImFkbWluIjogeyAiY29yZV9tb2R1bGUiOiB7fSB9LAogICAgICAgICJmdW5kcyI6IFtdLAogICAgICAgICJsYWJlbCI6ICJkYW8tcHJlLXByb3Bvc2Utc2luZ2xlLXYyLjYuMCIKICAgICAgfQogICAgfQogIH0KfQ==
182+
```
183+
184+
Now replace the proposal module instantiation `msg` field in the
185+
`update_proposal_modules` execution message with the base64-encoded proposal
186+
module instantiation message from above:
187+
188+
```
189+
{
190+
"update_proposal_modules": {
191+
"to_add": [{
192+
"admin": { "core_module": {} },
193+
"code_id": 1252,
194+
"label": "dao-proposal-single-v2.6.0",
195+
"msg": "ewogICJ0aHJlc2hvbGQiOiB7CiAgICAidGhyZXNob2xkX3F1b3J1bSI6IHsKICAgICAgInRocmVzaG9sZCI6IHsgIm1ham9yaXR5Ijoge30gfSwKICAgICAgInF1b3J1bSI6IHsgInBlcmNlbnQiOiAiMC4yIiB9CiAgICB9CiAgfSwKICAibWF4X3ZvdGluZ19wZXJpb2QiOiB7ICJ0aW1lIjogNjA0ODAwIH0sCiAgIm9ubHlfbWVtYmVyc19leGVjdXRlIjogdHJ1ZSwKICAiY2xvc2VfcHJvcG9zYWxfb25fZXhlY3V0aW9uX2ZhaWx1cmUiOiB0cnVlLAogICJhbGxvd19yZXZvdGluZyI6IGZhbHNlLAogICJwcmVfcHJvcG9zZV9pbmZvIjogewogICAgIm1vZHVsZV9tYXlfcHJvcG9zZSI6IHsKICAgICAgImluZm8iOiB7CiAgICAgICAgImNvZGVfaWQiOiAxMjUwLAogICAgICAgICJtc2ciOiAiZXdvZ0lDSnpkV0p0YVhOemFXOXVYM0J2YkdsamVTSTZJSHNLSUNBZ0lDSnpjR1ZqYVdacFl5STZJSHNLSUNBZ0lDQWdJbVJoYjE5dFpXMWlaWEp6SWpvZ2RISjFaU3dLSUNBZ0lDQWdJbUZzYkc5M2JHbHpkQ0k2SUZ0ZExBb2dJQ0FnSUNBaVpHVnVlV3hwYzNRaU9pQmJYUW9nSUNBZ2ZRb2dJSDBzQ2lBZ0ltVjRkR1Z1YzJsdmJpSTZJSHQ5Q24wPSIsCiAgICAgICAgImFkbWluIjogeyAiY29yZV9tb2R1bGUiOiB7fSB9LAogICAgICAgICJmdW5kcyI6IFtdLAogICAgICAgICJsYWJlbCI6ICJkYW8tcHJlLXByb3Bvc2Utc2luZ2xlLXYyLjYuMCIKICAgICAgfQogICAgfQogIH0KfQ==",
196+
"funds": []
197+
}],
198+
"to_disable": []
199+
}
200+
}
201+
```
202+
203+
And you have the full message to execute on the DAO via a proposal. You can now
204+
use the DAO DAO UI to create a proposal with the `Execute Smart Contract`
205+
action, with the contract address being the DAO's `dao-dao-core` contract, and
206+
the message field containing the above text.
207+
208+
Once you execute this, test the new proposal module by creating a proposal,
209+
voting on it, and executing it. If everything seems to work, you can now disable
210+
the old single choice proposal module by executing the following message in
211+
another proposal:
212+
213+
```
214+
{
215+
"update_proposal_modules": {
216+
"to_add": [],
217+
"to_disable": ["EXISTING PROPOSAL MODULE ADDRESS"]
218+
}
219+
}
220+
```
221+
222+
Ideally, wait a while to see the new proposal module in action before disabling
223+
the old one.

0 commit comments

Comments
 (0)