1use cosmwasm_std::{to_json_binary, Addr, Binary, Uint128};
2use cw20::Cw20Coin;
3use cw_multi_test::{App, Executor};
4use cw_utils::Duration;
5use dao_interface::state::{Admin, ModuleInstantiateInfo};
6use dao_voting::threshold::ActiveThreshold;
7use dao_voting_cw4::msg::GroupContract;
8
9use crate::contracts::{
10 cw20_balances_voting_contract, cw20_base_contract, cw20_stake_contract,
11 cw20_staked_balances_voting_contract, cw4_group_contract, dao_dao_contract,
12 dao_voting_cw4_contract,
13};
14
15const CREATOR_ADDR: &str = "creator";
16
17pub fn instantiate_with_cw20_balances_governance(
18 app: &mut App,
19 governance_code_id: u64,
20 governance_instantiate: Binary,
21 initial_balances: Option<Vec<Cw20Coin>>,
22) -> Addr {
23 let cw20_id = app.store_code(cw20_base_contract());
24 let core_id = app.store_code(dao_dao_contract());
25 let votemod_id = app.store_code(cw20_balances_voting_contract());
26
27 let initial_balances = initial_balances.unwrap_or_else(|| {
28 vec![Cw20Coin {
29 address: CREATOR_ADDR.to_string(),
30 amount: Uint128::new(100_000_000),
31 }]
32 });
33
34 let initial_balances: Vec<Cw20Coin> = {
36 let mut already_seen = vec![];
37 initial_balances
38 .into_iter()
39 .filter(|Cw20Coin { address, amount: _ }| {
40 if already_seen.contains(address) {
41 false
42 } else {
43 already_seen.push(address.clone());
44 true
45 }
46 })
47 .collect()
48 };
49
50 let governance_instantiate = dao_interface::msg::InstantiateMsg {
51 dao_uri: None,
52 admin: None,
53 name: "DAO DAO".to_string(),
54 description: "A DAO that builds DAOs".to_string(),
55 image_url: None,
56 automatically_add_cw20s: true,
57 automatically_add_cw721s: true,
58 voting_module_instantiate_info: ModuleInstantiateInfo {
59 code_id: votemod_id,
60 msg: to_json_binary(&dao_voting_cw20_balance::msg::InstantiateMsg {
61 token_info: dao_voting_cw20_balance::msg::TokenInfo::New {
62 code_id: cw20_id,
63 label: "DAO DAO governance token".to_string(),
64 name: "DAO".to_string(),
65 symbol: "DAO".to_string(),
66 decimals: 6,
67 initial_balances,
68 marketing: None,
69 },
70 })
71 .unwrap(),
72 admin: Some(Admin::CoreModule {}),
73 funds: vec![],
74 label: "DAO DAO voting module".to_string(),
75 },
76 proposal_modules_instantiate_info: vec![ModuleInstantiateInfo {
77 code_id: governance_code_id,
78 msg: governance_instantiate,
79 admin: Some(Admin::CoreModule {}),
80 funds: vec![],
81 label: "DAO DAO governance module".to_string(),
82 }],
83 initial_items: None,
84 };
85
86 app.instantiate_contract(
87 core_id,
88 Addr::unchecked(CREATOR_ADDR),
89 &governance_instantiate,
90 &[],
91 "DAO DAO",
92 None,
93 )
94 .unwrap()
95}
96
97pub fn instantiate_with_staked_balances_governance(
98 app: &mut App,
99 governance_code_id: u64,
100 governance_instantiate: Binary,
101 initial_balances: Option<Vec<Cw20Coin>>,
102) -> Addr {
103 let initial_balances = initial_balances.unwrap_or_else(|| {
104 vec![Cw20Coin {
105 address: CREATOR_ADDR.to_string(),
106 amount: Uint128::new(100_000_000),
107 }]
108 });
109
110 let initial_balances: Vec<Cw20Coin> = {
112 let mut already_seen = vec![];
113 initial_balances
114 .into_iter()
115 .filter(|Cw20Coin { address, amount: _ }| {
116 if already_seen.contains(address) {
117 false
118 } else {
119 already_seen.push(address.clone());
120 true
121 }
122 })
123 .collect()
124 };
125
126 let cw20_id = app.store_code(cw20_base_contract());
127 let cw20_stake_id = app.store_code(cw20_stake_contract());
128 let staked_balances_voting_id = app.store_code(cw20_staked_balances_voting_contract());
129 let core_contract_id = app.store_code(dao_dao_contract());
130
131 let instantiate_core = dao_interface::msg::InstantiateMsg {
132 dao_uri: None,
133 admin: None,
134 name: "DAO DAO".to_string(),
135 description: "A DAO that builds DAOs".to_string(),
136 image_url: None,
137 automatically_add_cw20s: true,
138 automatically_add_cw721s: false,
139 voting_module_instantiate_info: ModuleInstantiateInfo {
140 code_id: staked_balances_voting_id,
141 msg: to_json_binary(&dao_voting_cw20_staked::msg::InstantiateMsg {
142 active_threshold: None,
143 token_info: dao_voting_cw20_staked::msg::TokenInfo::New {
144 code_id: cw20_id,
145 label: "DAO DAO governance token.".to_string(),
146 name: "DAO DAO".to_string(),
147 symbol: "DAO".to_string(),
148 decimals: 6,
149 initial_balances: initial_balances.clone(),
150 marketing: None,
151 staking_code_id: cw20_stake_id,
152 unstaking_duration: Some(Duration::Height(6)),
153 initial_dao_balance: None,
154 },
155 })
156 .unwrap(),
157 admin: None,
158 funds: vec![],
159 label: "DAO DAO voting module".to_string(),
160 },
161 proposal_modules_instantiate_info: vec![ModuleInstantiateInfo {
162 code_id: governance_code_id,
163 label: "DAO DAO governance module.".to_string(),
164 admin: Some(Admin::CoreModule {}),
165 msg: governance_instantiate,
166 funds: vec![],
167 }],
168 initial_items: None,
169 };
170
171 let core_addr = app
172 .instantiate_contract(
173 core_contract_id,
174 Addr::unchecked(CREATOR_ADDR),
175 &instantiate_core,
176 &[],
177 "DAO DAO",
178 None,
179 )
180 .unwrap();
181
182 let gov_state: dao_interface::query::DumpStateResponse = app
183 .wrap()
184 .query_wasm_smart(
185 core_addr.clone(),
186 &dao_interface::msg::QueryMsg::DumpState {},
187 )
188 .unwrap();
189 let voting_module = gov_state.voting_module;
190
191 let staking_contract: Addr = app
192 .wrap()
193 .query_wasm_smart(
194 voting_module.clone(),
195 &dao_voting_cw20_staked::msg::QueryMsg::StakingContract {},
196 )
197 .unwrap();
198 let token_contract: Addr = app
199 .wrap()
200 .query_wasm_smart(
201 voting_module,
202 &dao_interface::voting::Query::TokenContract {},
203 )
204 .unwrap();
205
206 for Cw20Coin { address, amount } in initial_balances {
208 app.execute_contract(
209 Addr::unchecked(address),
210 token_contract.clone(),
211 &cw20::Cw20ExecuteMsg::Send {
212 contract: staking_contract.to_string(),
213 amount,
214 msg: to_json_binary(&cw20_stake::msg::ReceiveMsg::Stake {}).unwrap(),
215 },
216 &[],
217 )
218 .unwrap();
219 }
220
221 app.update_block(|block| block.height += 1);
223
224 core_addr
225}
226
227pub fn instantiate_with_staking_active_threshold(
228 app: &mut App,
229 code_id: u64,
230 governance_instantiate: Binary,
231 initial_balances: Option<Vec<Cw20Coin>>,
232 active_threshold: Option<ActiveThreshold>,
233) -> Addr {
234 let cw20_id = app.store_code(cw20_base_contract());
235 let cw20_staking_id = app.store_code(cw20_stake_contract());
236 let governance_id = app.store_code(dao_dao_contract());
237 let votemod_id = app.store_code(cw20_staked_balances_voting_contract());
238
239 let initial_balances = initial_balances.unwrap_or_else(|| {
240 vec![
241 Cw20Coin {
242 address: "blob".to_string(),
243 amount: Uint128::new(100_000_000),
244 },
245 Cw20Coin {
246 address: "blue".to_string(),
247 amount: Uint128::new(100_000_000),
248 },
249 ]
250 });
251
252 let governance_instantiate = dao_interface::msg::InstantiateMsg {
253 dao_uri: None,
254 admin: None,
255 name: "DAO DAO".to_string(),
256 description: "A DAO that builds DAOs".to_string(),
257 image_url: None,
258 automatically_add_cw20s: true,
259 automatically_add_cw721s: true,
260 voting_module_instantiate_info: ModuleInstantiateInfo {
261 code_id: votemod_id,
262 msg: to_json_binary(&dao_voting_cw20_staked::msg::InstantiateMsg {
263 token_info: dao_voting_cw20_staked::msg::TokenInfo::New {
264 code_id: cw20_id,
265 label: "DAO DAO governance token".to_string(),
266 name: "DAO".to_string(),
267 symbol: "DAO".to_string(),
268 decimals: 6,
269 initial_balances,
270 marketing: None,
271 staking_code_id: cw20_staking_id,
272 unstaking_duration: None,
273 initial_dao_balance: None,
274 },
275 active_threshold,
276 })
277 .unwrap(),
278 admin: Some(Admin::CoreModule {}),
279 funds: vec![],
280 label: "DAO DAO voting module".to_string(),
281 },
282 proposal_modules_instantiate_info: vec![ModuleInstantiateInfo {
283 code_id,
284 msg: governance_instantiate,
285 admin: Some(Admin::CoreModule {}),
286 funds: vec![],
287 label: "DAO DAO governance module".to_string(),
288 }],
289 initial_items: None,
290 };
291
292 app.instantiate_contract(
293 governance_id,
294 Addr::unchecked(CREATOR_ADDR),
295 &governance_instantiate,
296 &[],
297 "DAO DAO",
298 None,
299 )
300 .unwrap()
301}
302
303pub fn instantiate_with_cw4_groups_governance(
304 app: &mut App,
305 core_code_id: u64,
306 proposal_module_instantiate: Binary,
307 initial_weights: Option<Vec<Cw20Coin>>,
308) -> Addr {
309 let cw4_id = app.store_code(cw4_group_contract());
310 let core_id = app.store_code(dao_dao_contract());
311 let votemod_id = app.store_code(dao_voting_cw4_contract());
312
313 let initial_weights = initial_weights.unwrap_or_default();
314
315 let initial_weights: Vec<cw4::Member> = {
317 let mut already_seen = vec![];
318 initial_weights
319 .into_iter()
320 .filter(|Cw20Coin { address, .. }| {
321 if already_seen.contains(address) {
322 false
323 } else {
324 already_seen.push(address.clone());
325 true
326 }
327 })
328 .map(|Cw20Coin { address, amount }| cw4::Member {
329 addr: address,
330 weight: amount.u128() as u64,
331 })
332 .collect()
333 };
334
335 let governance_instantiate = dao_interface::msg::InstantiateMsg {
336 dao_uri: None,
337 admin: None,
338 name: "DAO DAO".to_string(),
339 description: "A DAO that builds DAOs".to_string(),
340 image_url: None,
341 automatically_add_cw20s: true,
342 automatically_add_cw721s: true,
343 voting_module_instantiate_info: ModuleInstantiateInfo {
344 code_id: votemod_id,
345 msg: to_json_binary(&dao_voting_cw4::msg::InstantiateMsg {
346 group_contract: GroupContract::New {
347 cw4_group_code_id: cw4_id,
348 initial_members: initial_weights,
349 },
350 })
351 .unwrap(),
352 admin: Some(Admin::CoreModule {}),
353 funds: vec![],
354 label: "DAO DAO voting module".to_string(),
355 },
356 proposal_modules_instantiate_info: vec![ModuleInstantiateInfo {
357 code_id: core_code_id,
358 msg: proposal_module_instantiate,
359 admin: Some(Admin::CoreModule {}),
360 funds: vec![],
361 label: "DAO DAO governance module".to_string(),
362 }],
363 initial_items: None,
364 };
365
366 let addr = app
367 .instantiate_contract(
368 core_id,
369 Addr::unchecked(CREATOR_ADDR),
370 &governance_instantiate,
371 &[],
372 "DAO DAO",
373 None,
374 )
375 .unwrap();
376
377 app.update_block(|block| block.height += 1);
379
380 addr
381}