integration.rs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2024 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use darkfi::Result;
  19. use darkfi_contract_test_harness::{init_logger, Holder, TestHarness};
  20. use darkfi_dao_contract::{
  21. model::{Dao, DaoBlindAggregateVote},
  22. DaoFunction,
  23. };
  24. use darkfi_money_contract::{
  25. model::{CoinAttributes, TokenAttributes, DARK_TOKEN_ID},
  26. MoneyFunction,
  27. };
  28. use darkfi_sdk::{
  29. crypto::{
  30. pasta_prelude::*,
  31. pedersen_commitment_u64, poseidon_hash,
  32. util::{fp_mod_fv, fp_to_u64},
  33. BaseBlind, Blind, FuncId, FuncRef, DAO_CONTRACT_ID, MONEY_CONTRACT_ID,
  34. },
  35. pasta::pallas,
  36. };
  37. use log::info;
  38. use rand::rngs::OsRng;
  39. #[test]
  40. fn integration_test() -> Result<()> {
  41. smol::block_on(async {
  42. init_logger();
  43. // Holders this test will use:
  44. // * Alice, Bob, and Charlie are members of the DAO.
  45. // * Dao is the DAO wallet
  46. // * Rachel is the proposal recipient.
  47. const HOLDERS: [Holder; 5] =
  48. [Holder::Alice, Holder::Bob, Holder::Charlie, Holder::Dao, Holder::Rachel];
  49. // Initialize harness
  50. let mut th = TestHarness::new(&HOLDERS, false).await?;
  51. // We'll use the ALICE token as the DAO governance token
  52. let wallet = th.holders.get_mut(&Holder::Alice).unwrap();
  53. //wallet.bench_wasm = true;
  54. let mint_authority = wallet.token_mint_authority;
  55. let gov_token_blind = BaseBlind::random(&mut OsRng);
  56. let auth_func_id = FuncRef {
  57. contract_id: *MONEY_CONTRACT_ID,
  58. func_code: MoneyFunction::AuthTokenMintV1 as u8,
  59. }
  60. .to_func_id();
  61. let token_attrs = TokenAttributes {
  62. auth_parent: auth_func_id,
  63. user_data: poseidon_hash([mint_authority.public.x(), mint_authority.public.y()]),
  64. blind: gov_token_blind,
  65. };
  66. let gov_token_id = token_attrs.to_token_id();
  67. const ALICE_GOV_SUPPLY: u64 = 100_000_000;
  68. const BOB_GOV_SUPPLY: u64 = 100_000_000;
  69. const CHARLIE_GOV_SUPPLY: u64 = 100_000_000;
  70. // And the DRK token as the treasury token
  71. let drk_token_id = *DARK_TOKEN_ID;
  72. const DRK_TOKEN_SUPPLY: u64 = 1_000_000_000;
  73. // The tokens we want to send via the transfer proposal
  74. const TRANSFER_PROPOSAL_AMOUNT: u64 = 250_000_000;
  75. // Block height to verify against
  76. let mut current_block_height = 0;
  77. // DAO parameters
  78. let dao_keypair = th.holders.get(&Holder::Dao).unwrap().keypair;
  79. let dao = Dao {
  80. proposer_limit: 100_000_000,
  81. quorum: 200_000_000,
  82. approval_ratio_base: 2,
  83. approval_ratio_quot: 1,
  84. gov_token_id,
  85. public_key: dao_keypair.public,
  86. bulla_blind: Blind::random(&mut OsRng),
  87. };
  88. // =======================================
  89. // Airdrop some treasury tokens to the DAO
  90. // =======================================
  91. info!("[Dao] Building DAO airdrop tx");
  92. assert_eq!(current_block_height, 0);
  93. let spend_hook =
  94. FuncRef { contract_id: *DAO_CONTRACT_ID, func_code: DaoFunction::Exec as u8 }
  95. .to_func_id();
  96. let (genesis_mint_tx, genesis_mint_params) = th
  97. .genesis_mint(
  98. &Holder::Dao,
  99. DRK_TOKEN_SUPPLY,
  100. Some(spend_hook),
  101. Some(dao.to_bulla().inner()),
  102. )
  103. .await?;
  104. for holder in &HOLDERS {
  105. th.execute_genesis_mint_tx(
  106. holder,
  107. genesis_mint_tx.clone(),
  108. &genesis_mint_params,
  109. current_block_height,
  110. true,
  111. )
  112. .await?;
  113. }
  114. th.assert_trees(&HOLDERS);
  115. let _dao_tokens = &th.holders.get(&Holder::Dao).unwrap().unspent_money_coins;
  116. assert!(_dao_tokens.len() == 1);
  117. assert!(_dao_tokens[0].note.token_id == *DARK_TOKEN_ID);
  118. assert!(_dao_tokens[0].note.value == DRK_TOKEN_SUPPLY);
  119. current_block_height += 1;
  120. // ====================
  121. // Dao::Mint
  122. // Create the DAO bulla
  123. // ====================
  124. info!("Stage 1. Creating DAO bulla");
  125. info!("[Dao] Building DAO mint tx");
  126. let (dao_mint_tx, dao_mint_params, fee_params) =
  127. th.dao_mint(&Holder::Alice, &dao, &dao_keypair, current_block_height).await?;
  128. for holder in &HOLDERS {
  129. info!("[{holder:?}] Executing DAO Mint tx");
  130. th.execute_dao_mint_tx(
  131. holder,
  132. dao_mint_tx.clone(),
  133. &dao_mint_params,
  134. &fee_params,
  135. current_block_height,
  136. true,
  137. )
  138. .await?;
  139. }
  140. th.assert_trees(&HOLDERS);
  141. current_block_height += 1;
  142. // ======================================
  143. // Mint the governance token to 3 holders
  144. // ======================================
  145. info!("Stage 3. Minting governance token");
  146. info!("[Alice] Building governance token mint tx for Alice");
  147. let (a_token_mint_tx, a_token_mint_params, a_auth_token_mint_params, a_fee_params) = th
  148. .token_mint(
  149. ALICE_GOV_SUPPLY,
  150. &Holder::Alice,
  151. &Holder::Alice,
  152. gov_token_blind,
  153. None,
  154. None,
  155. current_block_height,
  156. )
  157. .await?;
  158. for holder in &HOLDERS {
  159. info!("[{holder:?}] Executing governance token mint tx for Alice");
  160. th.execute_token_mint_tx(
  161. holder,
  162. a_token_mint_tx.clone(),
  163. &a_token_mint_params,
  164. &a_auth_token_mint_params,
  165. &a_fee_params,
  166. current_block_height,
  167. true,
  168. )
  169. .await?;
  170. }
  171. th.assert_trees(&HOLDERS);
  172. let _alice_tokens = &th.holders.get(&Holder::Alice).unwrap().unspent_money_coins;
  173. assert!(_alice_tokens.len() == 1);
  174. assert!(_alice_tokens[0].note.token_id == gov_token_id);
  175. assert!(_alice_tokens[0].note.value == ALICE_GOV_SUPPLY);
  176. info!("[Alice] Building governance token mint tx for Bob");
  177. let (b_token_mint_tx, b_token_mint_params, b_auth_token_mint_params, b_fee_params) = th
  178. .token_mint(
  179. BOB_GOV_SUPPLY,
  180. &Holder::Alice,
  181. &Holder::Bob,
  182. gov_token_blind,
  183. None,
  184. None,
  185. current_block_height,
  186. )
  187. .await?;
  188. for holder in &HOLDERS {
  189. info!("[{holder:?}] Executing governance token mint tx for Bob");
  190. th.execute_token_mint_tx(
  191. holder,
  192. b_token_mint_tx.clone(),
  193. &b_token_mint_params,
  194. &b_auth_token_mint_params,
  195. &b_fee_params,
  196. current_block_height,
  197. true,
  198. )
  199. .await?;
  200. }
  201. th.assert_trees(&HOLDERS);
  202. let _bob_tokens = &th.holders.get(&Holder::Bob).unwrap().unspent_money_coins;
  203. assert!(_bob_tokens.len() == 1);
  204. assert!(_bob_tokens[0].note.token_id == gov_token_id);
  205. assert!(_bob_tokens[0].note.value == BOB_GOV_SUPPLY);
  206. info!("[Alice] Building governance token mint tx for Charlie");
  207. let (c_token_mint_tx, c_token_mint_params, c_auth_token_mint_params, c_fee_params) = th
  208. .token_mint(
  209. CHARLIE_GOV_SUPPLY,
  210. &Holder::Alice,
  211. &Holder::Charlie,
  212. gov_token_blind,
  213. None,
  214. None,
  215. current_block_height,
  216. )
  217. .await?;
  218. for holder in &HOLDERS {
  219. info!("[{holder:?}] Executing governance token mint tx for Charlie");
  220. th.execute_token_mint_tx(
  221. holder,
  222. c_token_mint_tx.clone(),
  223. &c_token_mint_params,
  224. &c_auth_token_mint_params,
  225. &c_fee_params,
  226. current_block_height,
  227. true,
  228. )
  229. .await?;
  230. }
  231. th.assert_trees(&HOLDERS);
  232. let _charlie_tokens = &th.holders.get(&Holder::Charlie).unwrap().unspent_money_coins;
  233. assert!(_charlie_tokens.len() == 1);
  234. assert!(_charlie_tokens[0].note.token_id == gov_token_id);
  235. assert!(_charlie_tokens[0].note.value == CHARLIE_GOV_SUPPLY);
  236. current_block_height += 1;
  237. // ================
  238. // Dao::Propose
  239. // Propose the votes
  240. // ================
  241. info!("Stage 4. Propose the votes");
  242. // We can add whatever we want in here, even arbitrary text
  243. // It's up to the auth module to decide what to do with it.
  244. let user_data = pallas::Base::ZERO;
  245. info!("[Alice] Building DAO generic proposal tx");
  246. let (
  247. propose_generic_tx,
  248. propose_generic_params,
  249. propose_generic_fee_params,
  250. propose_generic_info,
  251. ) = th.dao_propose_generic(&Holder::Alice, user_data, &dao, current_block_height).await?;
  252. // TODO: look into proposal expiry once time for voting has finished
  253. // TODO: Is it possible for an invalid transfer() to be constructed on exec()?
  254. // Need to look into this.
  255. info!("[Alice] Building DAO transfer proposal tx");
  256. // These coins are passed around to all DAO members who verify its validity
  257. // They also check hashing them equals the proposal_commit
  258. let transfer_proposal_coinattrs = vec![CoinAttributes {
  259. public_key: th.holders.get(&Holder::Rachel).unwrap().keypair.public,
  260. value: TRANSFER_PROPOSAL_AMOUNT,
  261. token_id: drk_token_id,
  262. spend_hook: FuncId::none(),
  263. user_data: pallas::Base::ZERO,
  264. blind: Blind::random(&mut OsRng),
  265. }];
  266. let (
  267. propose_transfer_tx,
  268. propose_transfer_params,
  269. propose_transfer_fee_params,
  270. propose_transfer_info,
  271. ) = th
  272. .dao_propose_transfer(
  273. &Holder::Alice,
  274. &transfer_proposal_coinattrs,
  275. user_data,
  276. &dao,
  277. current_block_height,
  278. )
  279. .await?;
  280. for holder in &HOLDERS {
  281. info!("[{holder:?}] Executing DAO generic proposal tx");
  282. th.execute_dao_propose_tx(
  283. holder,
  284. propose_generic_tx.clone(),
  285. &propose_generic_params,
  286. &propose_generic_fee_params,
  287. current_block_height,
  288. true,
  289. )
  290. .await?;
  291. info!("[{holder:?}] Executing DAO transfer proposal tx");
  292. th.execute_dao_propose_tx(
  293. holder,
  294. propose_transfer_tx.clone(),
  295. &propose_transfer_params,
  296. &propose_transfer_fee_params,
  297. current_block_height,
  298. true,
  299. )
  300. .await?;
  301. }
  302. th.assert_trees(&HOLDERS);
  303. current_block_height += 1;
  304. // =====================================
  305. // Dao::Vote
  306. // Proposals are accepted. Start the votes.
  307. // =====================================
  308. info!("Stage 5. Start voting");
  309. info!("[Alice] Building generic vote tx (yes)");
  310. let (alice_generic_vote_tx, alice_generic_vote_params, alice_generic_vote_fee_params) = th
  311. .dao_vote(
  312. &Holder::Alice,
  313. true,
  314. &dao,
  315. &dao_keypair,
  316. &propose_generic_info,
  317. current_block_height,
  318. )
  319. .await?;
  320. info!("[Alice] Building transfer vote tx (yes)");
  321. let (alice_transfer_vote_tx, alice_transfer_vote_params, alice_transfer_vote_fee_params) =
  322. th.dao_vote(
  323. &Holder::Alice,
  324. true,
  325. &dao,
  326. &dao_keypair,
  327. &propose_transfer_info,
  328. current_block_height,
  329. )
  330. .await?;
  331. info!("[Bob] Building generic vote tx (no)");
  332. let (bob_generic_vote_tx, bob_generic_vote_params, bob_generic_vote_fee_params) = th
  333. .dao_vote(
  334. &Holder::Bob,
  335. false,
  336. &dao,
  337. &dao_keypair,
  338. &propose_generic_info,
  339. current_block_height,
  340. )
  341. .await?;
  342. info!("[Bob] Building transfer vote tx (no)");
  343. let (bob_transfer_vote_tx, bob_transfer_vote_params, bob_transfer_vote_fee_params) = th
  344. .dao_vote(
  345. &Holder::Bob,
  346. false,
  347. &dao,
  348. &dao_keypair,
  349. &propose_transfer_info,
  350. current_block_height,
  351. )
  352. .await?;
  353. info!("[Charlie] Building generic vote tx (no)");
  354. let (charlie_generic_vote_tx, charlie_generic_vote_params, charlie_generic_vote_fee_params) =
  355. th.dao_vote(
  356. &Holder::Charlie,
  357. true,
  358. &dao,
  359. &dao_keypair,
  360. &propose_generic_info,
  361. current_block_height,
  362. )
  363. .await?;
  364. info!("[Charlie] Building transfer vote tx (yes)");
  365. let (
  366. charlie_transfer_vote_tx,
  367. charlie_transfer_vote_params,
  368. charlie_transfer_vote_fee_params,
  369. ) = th
  370. .dao_vote(
  371. &Holder::Charlie,
  372. true,
  373. &dao,
  374. &dao_keypair,
  375. &propose_transfer_info,
  376. current_block_height,
  377. )
  378. .await?;
  379. for holder in &HOLDERS {
  380. info!("[{holder:?}] Executing Alice generic vote tx");
  381. th.execute_dao_vote_tx(
  382. holder,
  383. alice_generic_vote_tx.clone(),
  384. &alice_generic_vote_fee_params,
  385. current_block_height,
  386. true,
  387. )
  388. .await?;
  389. info!("[{holder:?}] Executing Alice transfer vote tx");
  390. th.execute_dao_vote_tx(
  391. holder,
  392. alice_transfer_vote_tx.clone(),
  393. &alice_transfer_vote_fee_params,
  394. current_block_height,
  395. true,
  396. )
  397. .await?;
  398. info!("[{holder:?}] Executing Bob generic vote tx");
  399. th.execute_dao_vote_tx(
  400. holder,
  401. bob_generic_vote_tx.clone(),
  402. &bob_generic_vote_fee_params,
  403. current_block_height,
  404. true,
  405. )
  406. .await?;
  407. info!("[{holder:?}] Executing Bob transfer vote tx");
  408. th.execute_dao_vote_tx(
  409. holder,
  410. bob_transfer_vote_tx.clone(),
  411. &bob_transfer_vote_fee_params,
  412. current_block_height,
  413. true,
  414. )
  415. .await?;
  416. info!("[{holder:?}] Executing Charlie generic vote tx");
  417. th.execute_dao_vote_tx(
  418. holder,
  419. charlie_generic_vote_tx.clone(),
  420. &charlie_generic_vote_fee_params,
  421. current_block_height,
  422. true,
  423. )
  424. .await?;
  425. info!("[{holder:?}] Executing Charlie transfer vote tx");
  426. th.execute_dao_vote_tx(
  427. holder,
  428. charlie_transfer_vote_tx.clone(),
  429. &charlie_transfer_vote_fee_params,
  430. current_block_height,
  431. true,
  432. )
  433. .await?;
  434. }
  435. // Gather and decrypt all generic vote notes
  436. let vote_note_1 =
  437. alice_generic_vote_params.note.decrypt_unsafe(&dao_keypair.secret).unwrap();
  438. let vote_note_2 = bob_generic_vote_params.note.decrypt_unsafe(&dao_keypair.secret).unwrap();
  439. let vote_note_3 =
  440. charlie_generic_vote_params.note.decrypt_unsafe(&dao_keypair.secret).unwrap();
  441. // Count the votes
  442. let mut total_yes_generic_vote_value = 0;
  443. let mut total_all_generic_vote_value = 0;
  444. let mut blind_total_generic_vote = DaoBlindAggregateVote::default();
  445. let mut total_yes_generic_vote_blind = Blind::ZERO;
  446. let mut total_all_generic_vote_blind = Blind::ZERO;
  447. for (i, (note, params)) in [
  448. (vote_note_1, alice_generic_vote_params),
  449. (vote_note_2, bob_generic_vote_params),
  450. (vote_note_3, charlie_generic_vote_params),
  451. ]
  452. .iter()
  453. .enumerate()
  454. {
  455. // Note format: [
  456. // vote_option,
  457. // yes_vote_blind,
  458. // all_vote_value_fp,
  459. // all_vote_blind,
  460. // ]
  461. let vote_option = fp_to_u64(note[0]).unwrap();
  462. let yes_vote_blind = Blind(fp_mod_fv(note[1]));
  463. let all_vote_value = fp_to_u64(note[2]).unwrap();
  464. let all_vote_blind = Blind(fp_mod_fv(note[3]));
  465. assert!(vote_option == 0 || vote_option == 1);
  466. total_yes_generic_vote_blind += yes_vote_blind;
  467. total_all_generic_vote_blind += all_vote_blind;
  468. // Update private values
  469. // vote_option is either 0 or 1
  470. let yes_vote_value = vote_option * all_vote_value;
  471. total_yes_generic_vote_value += yes_vote_value;
  472. total_all_generic_vote_value += all_vote_value;
  473. // Update public values
  474. let yes_vote_commit = params.yes_vote_commit;
  475. let all_vote_commit = params.inputs.iter().map(|i| i.vote_commit).sum();
  476. let blind_vote = DaoBlindAggregateVote { yes_vote_commit, all_vote_commit };
  477. blind_total_generic_vote.aggregate(blind_vote);
  478. // Just for the debug
  479. let vote_result = match vote_option != 0 {
  480. true => "yes",
  481. false => "no",
  482. };
  483. info!(
  484. "Voter {} voted {} with {} tokens in generic vote",
  485. i, vote_result, all_vote_value
  486. );
  487. }
  488. info!(
  489. "Generic vote outcome = {} / {}",
  490. total_yes_generic_vote_value, total_all_generic_vote_value
  491. );
  492. assert!(
  493. blind_total_generic_vote.all_vote_commit ==
  494. pedersen_commitment_u64(
  495. total_all_generic_vote_value,
  496. total_all_generic_vote_blind
  497. )
  498. );
  499. assert!(
  500. blind_total_generic_vote.yes_vote_commit ==
  501. pedersen_commitment_u64(
  502. total_yes_generic_vote_value,
  503. total_yes_generic_vote_blind
  504. )
  505. );
  506. // Gather and decrypt all transfer vote notes
  507. let vote_note_1 =
  508. alice_transfer_vote_params.note.decrypt_unsafe(&dao_keypair.secret).unwrap();
  509. let vote_note_2 =
  510. bob_transfer_vote_params.note.decrypt_unsafe(&dao_keypair.secret).unwrap();
  511. let vote_note_3 =
  512. charlie_transfer_vote_params.note.decrypt_unsafe(&dao_keypair.secret).unwrap();
  513. // Count the votes
  514. let mut total_yes_transfer_vote_value = 0;
  515. let mut total_all_transfer_vote_value = 0;
  516. let mut blind_total_transfer_vote = DaoBlindAggregateVote::default();
  517. let mut total_yes_transfer_vote_blind = Blind::ZERO;
  518. let mut total_all_transfer_vote_blind = Blind::ZERO;
  519. for (i, (note, params)) in [
  520. (vote_note_1, alice_transfer_vote_params),
  521. (vote_note_2, bob_transfer_vote_params),
  522. (vote_note_3, charlie_transfer_vote_params),
  523. ]
  524. .iter()
  525. .enumerate()
  526. {
  527. // Note format: [
  528. // vote_option,
  529. // yes_vote_blind,
  530. // all_vote_value_fp,
  531. // all_vote_blind,
  532. // ]
  533. let vote_option = fp_to_u64(note[0]).unwrap();
  534. let yes_vote_blind = Blind(fp_mod_fv(note[1]));
  535. let all_vote_value = fp_to_u64(note[2]).unwrap();
  536. let all_vote_blind = Blind(fp_mod_fv(note[3]));
  537. assert!(vote_option == 0 || vote_option == 1);
  538. total_yes_transfer_vote_blind += yes_vote_blind;
  539. total_all_transfer_vote_blind += all_vote_blind;
  540. // Update private values
  541. // vote_option is either 0 or 1
  542. let yes_vote_value = vote_option * all_vote_value;
  543. total_yes_transfer_vote_value += yes_vote_value;
  544. total_all_transfer_vote_value += all_vote_value;
  545. // Update public values
  546. let yes_vote_commit = params.yes_vote_commit;
  547. let all_vote_commit = params.inputs.iter().map(|i| i.vote_commit).sum();
  548. let blind_vote = DaoBlindAggregateVote { yes_vote_commit, all_vote_commit };
  549. blind_total_transfer_vote.aggregate(blind_vote);
  550. // Just for the debug
  551. let vote_result = match vote_option != 0 {
  552. true => "yes",
  553. false => "no",
  554. };
  555. info!(
  556. "Voter {} voted {} with {} tokens in transfer vote",
  557. i, vote_result, all_vote_value
  558. );
  559. }
  560. info!(
  561. "Transfer vote outcome = {} / {}",
  562. total_yes_transfer_vote_value, total_all_transfer_vote_value
  563. );
  564. assert!(
  565. blind_total_transfer_vote.all_vote_commit ==
  566. pedersen_commitment_u64(
  567. total_all_transfer_vote_value,
  568. total_all_transfer_vote_blind
  569. )
  570. );
  571. assert!(
  572. blind_total_transfer_vote.yes_vote_commit ==
  573. pedersen_commitment_u64(
  574. total_yes_transfer_vote_value,
  575. total_yes_transfer_vote_blind
  576. )
  577. );
  578. th.assert_trees(&HOLDERS);
  579. current_block_height += 1;
  580. // ================
  581. // Dao::Exec
  582. // Execute the votes
  583. // ================
  584. info!("Stage 6. Execute the votes");
  585. info!("[Dao] Building generic Dao::Exec tx");
  586. let (exec_generic_tx, exec_generic_fee_params) = th
  587. .dao_exec_generic(
  588. &Holder::Alice,
  589. &dao,
  590. &propose_generic_info,
  591. total_yes_generic_vote_value,
  592. total_all_generic_vote_value,
  593. total_yes_generic_vote_blind,
  594. total_all_generic_vote_blind,
  595. current_block_height,
  596. )
  597. .await?;
  598. info!("[Dao] Building transfer Dao::Exec tx");
  599. let (exec_transfer_tx, xfer_params, exec_transfer_fee_params) = th
  600. .dao_exec_transfer(
  601. &Holder::Alice,
  602. &dao,
  603. &propose_transfer_info,
  604. transfer_proposal_coinattrs,
  605. total_yes_transfer_vote_value,
  606. total_all_transfer_vote_value,
  607. total_yes_transfer_vote_blind,
  608. total_all_transfer_vote_blind,
  609. current_block_height,
  610. )
  611. .await?;
  612. for holder in &HOLDERS {
  613. info!("[{holder:?}] Executing generic Dao::Exec tx");
  614. th.execute_dao_exec_tx(
  615. holder,
  616. exec_generic_tx.clone(),
  617. None,
  618. &exec_generic_fee_params,
  619. current_block_height,
  620. true,
  621. )
  622. .await?;
  623. info!("[{holder:?}] Executing transfer Dao::Exec tx");
  624. th.execute_dao_exec_tx(
  625. holder,
  626. exec_transfer_tx.clone(),
  627. Some(&xfer_params),
  628. &exec_transfer_fee_params,
  629. current_block_height,
  630. true,
  631. )
  632. .await?;
  633. }
  634. th.assert_trees(&HOLDERS);
  635. let rachel_wallet = th.holders.get(&Holder::Rachel).unwrap();
  636. assert!(rachel_wallet.unspent_money_coins[0].note.value == TRANSFER_PROPOSAL_AMOUNT);
  637. assert!(rachel_wallet.unspent_money_coins[0].note.token_id == drk_token_id);
  638. let dao_wallet = th.holders.get(&Holder::Dao).unwrap();
  639. assert!(
  640. dao_wallet.unspent_money_coins[0].note.value ==
  641. DRK_TOKEN_SUPPLY - TRANSFER_PROPOSAL_AMOUNT
  642. );
  643. assert!(dao_wallet.unspent_money_coins[0].note.token_id == drk_token_id);
  644. // Thanks for reading
  645. Ok(())
  646. })
  647. }