Explorar el Código

contract/dao: Initial integration tests setup.

parazyd hace 3 años
padre
commit
3cedf88cdc

+ 8 - 0
Cargo.lock

@@ -1171,10 +1171,18 @@ dependencies = [
 name = "darkfi-dao-contract"
 version = "0.3.0"
 dependencies = [
+ "async-std",
+ "darkfi",
  "darkfi-money-contract",
  "darkfi-sdk",
  "darkfi-serial",
  "getrandom 0.2.8",
+ "halo2_proofs",
+ "log",
+ "rand",
+ "simplelog",
+ "sled",
+ "sqlx",
 ]
 
 [[package]]

+ 11 - 7
src/consensus/validator.rs

@@ -23,8 +23,10 @@ use darkfi_sdk::{
     crypto::{
         constants::MERKLE_DEPTH,
         contract_id::MONEY_CONTRACT_ID,
+        //contract_id::{DAO_CONTRACT_ID, MONEY_CONTRACT_ID},
         schnorr::{SchnorrPublic, SchnorrSecret},
-        MerkleNode, PublicKey,
+        MerkleNode,
+        PublicKey,
     },
     db::SMART_CONTRACT_ZKAS_DB_NAME,
     incrementalmerkletree::{bridgetree::BridgeTree, Tree},
@@ -154,12 +156,14 @@ impl ValidatorState {
                 include_bytes!("../contract/money/money_contract.wasm").to_vec(),
                 money_contract_deploy_payload,
             ),
-            //(
-            //    "DAO Contract",
-            //    *DAO_CONTRACT_ID,
-            //    include_bytes!("../contract/dao/dao_contract.wasm").to_vec(),
-            //    dao_contract_deploy_payload,
-            //),
+            /*
+            (
+                "DAO Contract",
+                *DAO_CONTRACT_ID,
+                include_bytes!("../contract/dao/dao_contract.wasm").to_vec(),
+                dao_contract_deploy_payload,
+            ),
+            */
         ];
 
         info!("Deploying native wasm contracts");

+ 21 - 1
src/contract/dao/Cargo.toml

@@ -13,6 +13,21 @@ darkfi-sdk = { path = "../../sdk" }
 darkfi-serial = { path = "../../serial", features = ["derive", "crypto"] }
 darkfi-money-contract = { path = "../money", features = ["no-entrypoint"] }
 
+# The following dependencies are used for the client API and
+# probably shouldn't be in WASM
+darkfi = { path = "../../../", features = ["zk", "rpc"], optional = true }
+halo2_proofs = { version = "0.2.0", optional = true }
+log = { version = "0.4.17", optional = true }
+rand = { version = "0.8.5", optional = true }
+
+# These are used just for the integration tests
+[dev-dependencies]
+async-std = {version = "1.12.0", features = ["attributes"]}
+darkfi = {path = "../../../", features = ["tx", "blockchain"]}
+simplelog = "0.12.0"
+sled = "0.34.7"
+sqlx = {version = "0.6.2", features = ["runtime-async-std-native-tls", "sqlite"]}
+
 # We need to disable random using "custom" which makes the crate a noop
 # so the wasm32-unknown-unknown target is enabled.
 [target.'cfg(target_arch = "wasm32")'.dependencies]
@@ -21,4 +36,9 @@ getrandom = { version = "0.2.8", features = ["custom"] }
 [features]
 default = []
 no-entrypoint = []
-client = []
+client = [
+    "darkfi",
+    "rand",
+    "log",
+    "halo2_proofs",
+]

+ 6 - 2
src/contract/dao/Makefile

@@ -28,8 +28,12 @@ $(WASM_BIN): $(WASM_SRC) $(PROOFS_BIN)
 $(PROOFS_BIN): $(ZKAS) $(PROOFS_SRC)
 	$(ZKAS) $(basename $@) -o $@
 
-test: all
-	$(CARGO) test --release --features=no-entrypoint,client --package darkfi-dao-contract
+test-integration: all
+	$(CARGO) test --release --features=no-entrypoint,client \
+		--package darkfi-dao-contract \
+		--test integration
+
+test:
 
 clean:
 	rm -f $(PROOFS_BIN) $(WASM_BIN)

+ 140 - 0
src/contract/dao/src/client.rs

@@ -0,0 +1,140 @@
+/* This file is part of DarkFi (https://dark.fi)
+ *
+ * Copyright (C) 2020-2022 Dyne.org foundation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+use darkfi::{
+    zk::{proof::ProvingKey, vm::ZkCircuit, vm_stack::Witness, Proof},
+    zkas::ZkBinary,
+    Result,
+};
+use darkfi_sdk::{
+    crypto::{poseidon_hash, PublicKey, SecretKey, TokenId},
+    pasta::pallas,
+};
+use halo2_proofs::circuit::Value;
+use log::debug;
+use rand::rngs::OsRng;
+
+use crate::state::{DaoBulla, DaoMintParams};
+
+struct DaoMintRevealed {
+    pub bulla: DaoBulla,
+}
+
+impl DaoMintRevealed {
+    pub fn compute(
+        dao_proposer_limit: pallas::Base,
+        dao_quorum: pallas::Base,
+        dao_approval_ratio_quot: pallas::Base,
+        dao_approval_ratio_base: pallas::Base,
+        gov_token_id: TokenId,
+        dao_pubkey: &PublicKey,
+        dao_bulla_blind: pallas::Base,
+    ) -> Self {
+        let (pub_x, pub_y) = dao_pubkey.xy();
+
+        let dao_bulla = poseidon_hash([
+            dao_proposer_limit,
+            dao_quorum,
+            dao_approval_ratio_quot,
+            dao_approval_ratio_base,
+            gov_token_id.inner(),
+            pub_x,
+            pub_y,
+            dao_bulla_blind,
+        ]);
+
+        Self { bulla: DaoBulla::from(dao_bulla) }
+    }
+
+    pub fn to_vec(&self) -> Vec<pallas::Base> {
+        vec![self.bulla.inner()]
+    }
+}
+
+fn create_dao_mint_proof(
+    zkbin: &ZkBinary,
+    pk: &ProvingKey,
+    dao_proposer_limit: pallas::Base,
+    dao_quorum: pallas::Base,
+    dao_approval_ratio_quot: pallas::Base,
+    dao_approval_ratio_base: pallas::Base,
+    gov_token_id: TokenId,
+    dao_pubkey: &PublicKey,
+    dao_bulla_blind: pallas::Base,
+) -> Result<(Proof, DaoMintRevealed)> {
+    let revealed = DaoMintRevealed::compute(
+        dao_proposer_limit,
+        dao_quorum,
+        dao_approval_ratio_quot,
+        dao_approval_ratio_base,
+        gov_token_id,
+        dao_pubkey,
+        dao_bulla_blind,
+    );
+
+    let (pub_x, pub_y) = dao_pubkey.xy();
+
+    // NOTE: It's important to keep these in the same order as the zkas code.
+    let prover_witnesses = vec![
+        Witness::Base(Value::known(dao_proposer_limit)),
+        Witness::Base(Value::known(dao_quorum)),
+        Witness::Base(Value::known(dao_approval_ratio_quot)),
+        Witness::Base(Value::known(dao_approval_ratio_base)),
+        Witness::Base(Value::known(gov_token_id.inner())),
+        Witness::Base(Value::known(pub_x)),
+        Witness::Base(Value::known(pub_y)),
+        Witness::Base(Value::known(dao_bulla_blind)),
+    ];
+
+    let circuit = ZkCircuit::new(prover_witnesses, zkbin.clone());
+    let proof = Proof::create(pk, &[circuit], &revealed.to_vec(), &mut OsRng)?;
+
+    Ok((proof, revealed))
+}
+
+pub fn build_dao_mint_tx(
+    dao_proposer_limit: u64,
+    dao_quorum: u64,
+    dao_approval_ratio_quot: u64,
+    dao_approval_ratio_base: u64,
+    gov_token_id: TokenId,
+    dao_pubkey: &PublicKey,
+    dao_bulla_blind: pallas::Base,
+    signature_secret: &SecretKey,
+    dao_mint_zkbin: &ZkBinary,
+    dao_mint_pk: &ProvingKey,
+) -> Result<(DaoMintParams, Vec<Proof>)> {
+    debug!("Building DAO contract mint transaction");
+
+    let (proof, revealed) = create_dao_mint_proof(
+        dao_mint_zkbin,
+        dao_mint_pk,
+        pallas::Base::from(dao_proposer_limit),
+        pallas::Base::from(dao_quorum),
+        pallas::Base::from(dao_approval_ratio_quot),
+        pallas::Base::from(dao_approval_ratio_base),
+        gov_token_id,
+        dao_pubkey,
+        dao_bulla_blind,
+    )?;
+
+    let dao_bulla = revealed.bulla;
+    let dao_mint_params = DaoMintParams { dao_bulla };
+
+    Ok((dao_mint_params, vec![proof]))
+}

+ 29 - 24
src/contract/dao/src/entrypoint.rs

@@ -42,7 +42,9 @@ use crate::{
         DaoExecParams, DaoExecUpdate, DaoMintParams, DaoMintUpdate, DaoProposeParams,
         DaoProposeUpdate, DaoVoteParams, DaoVoteUpdate, ProposalVotes,
     },
-    DaoFunction,
+    DaoFunction, DAO_CONTRACT_ZKAS_DAO_EXEC_NS, DAO_CONTRACT_ZKAS_DAO_MINT_NS,
+    DAO_CONTRACT_ZKAS_DAO_PROPOSE_BURN_NS, DAO_CONTRACT_ZKAS_DAO_PROPOSE_MAIN_NS,
+    DAO_CONTRACT_ZKAS_DAO_VOTE_BURN_NS, DAO_CONTRACT_ZKAS_DAO_VOTE_MAIN_NS,
 };
 
 darkfi_sdk::define_contract!(
@@ -63,15 +65,7 @@ pub const DAO_PROPOSAL_VOTES_TREE: &str = "dao_proposal_votes";
 pub const DAO_MERKLE_TREE: &str = "dao_merkle_tree";
 pub const DAO_PROPOSAL_MERKLE_TREE: &str = "dao_proposals_merkle_tree";
 
-// These are zkas circuit namespaces
-pub const ZKAS_DAO_EXEC_NS: &str = "DaoExec";
-pub const ZKAS_DAO_MINT_NS: &str = "DaoMint";
-pub const ZKAS_DAO_VOTE_BURN_NS: &str = "DaoVoteInput";
-pub const ZKAS_DAO_VOTE_MAIN_NS: &str = "DaoVoteMain";
-pub const ZKAS_DAO_PROPOSE_BURN_NS: &str = "DaoProposeInput";
-pub const ZKAS_DAO_PROPOSE_MAIN_NS: &str = "DaoProposeMain";
-
-fn init_contract(cid: ContractId, ix: &[u8]) -> ContractResult {
+fn init_contract(cid: ContractId, _ix: &[u8]) -> ContractResult {
     // The zkas circuits can simply be embedded in the wasm and set up by
     // the initialization. Note that the tree should then be called "zkas".
     // The lookups can then be done by `contract_id+_zkas+namespace`.
@@ -86,12 +80,12 @@ fn init_contract(cid: ContractId, ix: &[u8]) -> ContractResult {
     let dao_propose_burn_bin = include_bytes!("../proof/dao-propose-burn.zk.bin");
     let dao_propose_main_bin = include_bytes!("../proof/dao-propose-main.zk.bin");
 
-    db_set(zkas_db, &serialize(&ZKAS_DAO_EXEC_NS), &dao_exec_bin[..])?;
-    db_set(zkas_db, &serialize(&ZKAS_DAO_MINT_NS), &dao_mint_bin[..])?;
-    db_set(zkas_db, &serialize(&ZKAS_DAO_VOTE_BURN_NS), &dao_vote_burn_bin[..])?;
-    db_set(zkas_db, &serialize(&ZKAS_DAO_VOTE_MAIN_NS), &dao_vote_main_bin[..])?;
-    db_set(zkas_db, &serialize(&ZKAS_DAO_PROPOSE_BURN_NS), &dao_propose_burn_bin[..])?;
-    db_set(zkas_db, &serialize(&ZKAS_DAO_PROPOSE_MAIN_NS), &dao_propose_main_bin[..])?;
+    db_set(zkas_db, &serialize(&DAO_CONTRACT_ZKAS_DAO_EXEC_NS), &dao_exec_bin[..])?;
+    db_set(zkas_db, &serialize(&DAO_CONTRACT_ZKAS_DAO_MINT_NS), &dao_mint_bin[..])?;
+    db_set(zkas_db, &serialize(&DAO_CONTRACT_ZKAS_DAO_VOTE_BURN_NS), &dao_vote_burn_bin[..])?;
+    db_set(zkas_db, &serialize(&DAO_CONTRACT_ZKAS_DAO_VOTE_MAIN_NS), &dao_vote_main_bin[..])?;
+    db_set(zkas_db, &serialize(&DAO_CONTRACT_ZKAS_DAO_PROPOSE_BURN_NS), &dao_propose_burn_bin[..])?;
+    db_set(zkas_db, &serialize(&DAO_CONTRACT_ZKAS_DAO_PROPOSE_MAIN_NS), &dao_propose_main_bin[..])?;
 
     // Set up a database tree to hold the Merkle tree for DAO bullas
     let dao_bulla_db = match db_lookup(cid, DAO_BULLA_TREE) {
@@ -108,7 +102,11 @@ fn init_contract(cid: ContractId, ix: &[u8]) -> ContractResult {
         None => {
             // We didn't find a tree, so just make a new one.
             let tree = MerkleTree::new(100);
-            db_set(dao_bulla_db, &serialize(&DAO_MERKLE_TREE), &serialize(&tree))?;
+            let mut tree_data = vec![];
+
+            tree_data.write_u32(0)?;
+            tree.encode(&mut tree_data)?;
+            db_set(dao_bulla_db, &serialize(&DAO_MERKLE_TREE), &tree_data)?;
         }
     };
 
@@ -133,7 +131,11 @@ fn init_contract(cid: ContractId, ix: &[u8]) -> ContractResult {
         None => {
             // We didn't find a tree, so just make a new one.
             let tree = MerkleTree::new(100);
-            db_set(dao_proposal_db, &serialize(&DAO_PROPOSAL_MERKLE_TREE), &serialize(&tree))?;
+            let mut tree_data = vec![];
+
+            tree_data.write_u32(0)?;
+            tree.encode(&mut tree_data)?;
+            db_set(dao_proposal_db, &serialize(&DAO_PROPOSAL_MERKLE_TREE), &tree_data)?;
         }
     };
 
@@ -163,6 +165,7 @@ fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
             let params: DaoMintParams = deserialize(&self_.data[1..])?;
 
             // No checks in Mint, just return the update.
+            // TODO: Should it check that there isn't an existing one?
             let update = DaoMintUpdate { dao_bulla: params.dao_bulla };
             let mut update_data = vec![];
             update_data.write_u8(DaoFunction::Mint as u8)?;
@@ -396,9 +399,11 @@ fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult {
             let params: DaoMintParams = deserialize(&self_.data[1..])?;
 
             let mut zk_public_values: Vec<(String, Vec<pallas::Base>)> = vec![];
+            // TODO: Why no signatures? Should it be signed with the DAO keypair?
             let signature_pubkeys: Vec<PublicKey> = vec![];
 
-            zk_public_values.push((ZKAS_DAO_MINT_NS.to_string(), vec![params.dao_bulla.inner()]));
+            zk_public_values
+                .push((DAO_CONTRACT_ZKAS_DAO_MINT_NS.to_string(), vec![params.dao_bulla.inner()]));
 
             let mut metadata = vec![];
             zk_public_values.encode(&mut metadata)?;
@@ -426,7 +431,7 @@ fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult {
                 let (sig_x, sig_y) = input.signature_public.xy();
 
                 zk_public_values.push((
-                    ZKAS_DAO_PROPOSE_BURN_NS.to_string(),
+                    DAO_CONTRACT_ZKAS_DAO_PROPOSE_BURN_NS.to_string(),
                     vec![
                         *value_coords.x(),
                         *value_coords.y(),
@@ -440,7 +445,7 @@ fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult {
 
             let total_funds_coords = total_funds_commit.to_affine().coordinates().unwrap();
             zk_public_values.push((
-                ZKAS_DAO_PROPOSE_MAIN_NS.to_string(),
+                DAO_CONTRACT_ZKAS_DAO_PROPOSE_MAIN_NS.to_string(),
                 vec![
                     params.token_commit,
                     params.dao_merkle_root.inner(),
@@ -476,7 +481,7 @@ fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult {
                 let (sig_x, sig_y) = input.signature_public.xy();
 
                 zk_public_values.push((
-                    ZKAS_DAO_VOTE_BURN_NS.to_string(),
+                    DAO_CONTRACT_ZKAS_DAO_VOTE_BURN_NS.to_string(),
                     vec![
                         input.nullifier.inner(),
                         *value_coords.x(),
@@ -493,7 +498,7 @@ fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult {
             let all_vote_commit_coords = all_votes_commit.to_affine().coordinates().unwrap();
 
             zk_public_values.push((
-                ZKAS_DAO_VOTE_MAIN_NS.to_string(),
+                DAO_CONTRACT_ZKAS_DAO_VOTE_MAIN_NS.to_string(),
                 vec![
                     params.token_commit,
                     params.proposal_bulla,
@@ -524,7 +529,7 @@ fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult {
             let input_value_coords = params.input_value_commit.to_affine().coordinates().unwrap();
 
             zk_public_values.push((
-                ZKAS_DAO_EXEC_NS.to_string(),
+                DAO_CONTRACT_ZKAS_DAO_EXEC_NS.to_string(),
                 vec![
                     params.proposal,
                     params.coin_0,

+ 12 - 0
src/contract/dao/src/lib.rs

@@ -23,6 +23,18 @@ pub mod entrypoint;
 
 pub mod state;
 
+#[cfg(feature = "client")]
+/// Transaction building API for clients interacting with this contract
+pub mod client;
+
+// These are the zkas circuit namespaces
+pub const DAO_CONTRACT_ZKAS_DAO_MINT_NS: &str = "DaoMint";
+pub const DAO_CONTRACT_ZKAS_DAO_EXEC_NS: &str = "DaoExec";
+pub const DAO_CONTRACT_ZKAS_DAO_VOTE_BURN_NS: &str = "DaoVoteInput";
+pub const DAO_CONTRACT_ZKAS_DAO_VOTE_MAIN_NS: &str = "DaoVoteMain";
+pub const DAO_CONTRACT_ZKAS_DAO_PROPOSE_BURN_NS: &str = "DaoProposeInput";
+pub const DAO_CONTRACT_ZKAS_DAO_PROPOSE_MAIN_NS: &str = "DaoProposeMain";
+
 #[repr(u8)]
 pub enum DaoFunction {
     Mint = 0x00,

+ 129 - 0
src/contract/dao/tests.unused/harness.rs

@@ -0,0 +1,129 @@
+/* This file is part of DarkFi (https://dark.fi)
+ *
+ * Copyright (C) 2020-2022 Dyne.org foundation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+use std::collections::HashMap;
+
+use darkfi::{
+    consensus::{
+        constants::{TESTNET_GENESIS_HASH_BYTES, TESTNET_GENESIS_TIMESTAMP},
+        ValidatorState, ValidatorStatePtr,
+    },
+    wallet::WalletDb,
+    zk::{proof::ProvingKey, vm::ZkCircuit, vm_stack::empty_witnesses},
+    zkas::ZkBinary,
+    Result,
+};
+use darkfi_sdk::{
+    crypto::{
+        contract_id::{DAO_CONTRACT_ID, MONEY_CONTRACT_ID},
+        ContractId, Keypair, MerkleTree,
+    },
+    db::SMART_CONTRACT_ZKAS_DB_NAME,
+    pasta::group::ff::PrimeField,
+};
+use darkfi_serial::serialize;
+use log::{info, warn};
+use rand::rngs::OsRng;
+
+use darkfi_dao_contract::DAO_CONTRACT_ZKAS_DAO_MINT_NS;
+
+pub fn init_logger() -> Result<()> {
+    let mut cfg = simplelog::ConfigBuilder::new();
+    cfg.add_filter_ignore("sled".to_string());
+    if let Err(_) = simplelog::TermLogger::init(
+        //simplelog::LevelFilter::Info,
+        simplelog::LevelFilter::Debug,
+        //simplelog::LevelFilter::Trace,
+        cfg.build(),
+        simplelog::TerminalMode::Mixed,
+        simplelog::ColorChoice::Auto,
+    ) {
+        warn!("Logger already initialized");
+    }
+
+    Ok(())
+}
+
+pub struct DaoTestHarness {
+    pub alice_kp: Keypair,
+    pub dao_kp: Keypair,
+    pub alice_state: ValidatorStatePtr,
+    pub alice_dao_merkle_tree: MerkleTree,
+    pub money_contract_id: ContractId,
+    pub dao_contract_id: ContractId,
+    pub proving_keys: HashMap<[u8; 32], Vec<(&'static str, ProvingKey)>>,
+    pub dao_mint_zkbin: ZkBinary,
+    pub dao_mint_pk: ProvingKey,
+}
+
+impl DaoTestHarness {
+    pub async fn new() -> Result<Self> {
+        let alice_kp = Keypair::random(&mut OsRng);
+        let dao_kp = Keypair::random(&mut OsRng);
+
+        let alice_wallet = WalletDb::new("sqlite::memory:", "foo").await?;
+
+        let alice_sled_db = sled::Config::new().temporary(true).open()?;
+
+        let alice_state = ValidatorState::new(
+            &alice_sled_db,
+            *TESTNET_GENESIS_TIMESTAMP,
+            *TESTNET_GENESIS_HASH_BYTES,
+            alice_wallet,
+            vec![],
+            false,
+        )
+        .await?;
+
+        let alice_dao_merkle_tree = MerkleTree::new(100);
+
+        let money_contract_id = *MONEY_CONTRACT_ID;
+        let dao_contract_id = *DAO_CONTRACT_ID;
+
+        let alice_sled = alice_state.read().await.blockchain.sled_db.clone();
+        let db_handle = alice_state.read().await.blockchain.contracts.lookup(
+            &alice_sled,
+            &dao_contract_id,
+            SMART_CONTRACT_ZKAS_DB_NAME,
+        )?;
+
+        let dao_mint_zkbin = db_handle.get(&serialize(&DAO_CONTRACT_ZKAS_DAO_MINT_NS))?.unwrap();
+        info!("Decoding bincode");
+        let dao_mint_zkbin = ZkBinary::decode(&dao_mint_zkbin)?;
+        let dao_mint_witnesses = empty_witnesses(&dao_mint_zkbin);
+        let dao_mint_circuit = ZkCircuit::new(dao_mint_witnesses, dao_mint_zkbin.clone());
+
+        info!("Creating zk proving keys");
+        let k = 13;
+        let mut proving_keys = HashMap::<[u8; 32], Vec<(&str, ProvingKey)>>::new();
+        let dao_mint_pk = ProvingKey::build(k, &dao_mint_circuit);
+        let pks = vec![(DAO_CONTRACT_ZKAS_DAO_MINT_NS, dao_mint_pk.clone())];
+        proving_keys.insert(dao_contract_id.inner().to_repr(), pks);
+
+        Ok(Self {
+            alice_kp,
+            dao_kp,
+            alice_state,
+            alice_dao_merkle_tree,
+            money_contract_id,
+            dao_contract_id,
+            proving_keys,
+            dao_mint_zkbin,
+            dao_mint_pk,
+        })
+    }
+}

+ 94 - 0
src/contract/dao/tests.unused/integration.rs

@@ -0,0 +1,94 @@
+/* This file is part of DarkFi (https://dark.fi)
+ *
+ * Copyright (C) 2020-2022 Dyne.org foundation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+use darkfi::{tx::Transaction, Result};
+use darkfi_sdk::{
+    crypto::TokenId,
+    pasta::{group::ff::Field, pallas},
+    tx::ContractCall,
+};
+use darkfi_serial::Encodable;
+use log::info;
+use rand::rngs::OsRng;
+
+use darkfi_dao_contract::{client::build_dao_mint_tx, DaoFunction};
+
+mod harness;
+use harness::{init_logger, DaoTestHarness};
+
+#[async_std::test]
+async fn integration_test() -> Result<()> {
+    init_logger()?;
+
+    let mut th = DaoTestHarness::new().await?;
+
+    // Money parameters
+    //let xdrk_supply = 1_000_000;
+    //let xrdk_token_id = TokenId::from(pallas::Base::random(&mut OsRng));
+
+    // Governance token parameters
+    //let gdrk_supply = 1_000_000;
+    let gdrk_token_id = TokenId::from(pallas::Base::random(&mut OsRng));
+
+    // DAO parameters
+    let dao_proposer_limit = 110;
+    let dao_quorum = 110;
+    let dao_approval_ratio_quot = 1;
+    let dao_approval_ratio_base = 2;
+
+    // =================
+    // DaoFunction::Mint
+    // =================
+
+    let dao_bulla_blind = pallas::Base::random(&mut OsRng);
+
+    info!("[Alice] =========================");
+    info!("[Alice] Building Dao::Mint params");
+    info!("[Alice] =========================");
+    let (params, proofs) = build_dao_mint_tx(
+        dao_proposer_limit,
+        dao_quorum,
+        dao_approval_ratio_quot,
+        dao_approval_ratio_base,
+        gdrk_token_id,
+        &th.dao_kp.public,
+        dao_bulla_blind,
+        &th.dao_kp.secret,
+        &th.dao_mint_zkbin,
+        &th.dao_mint_pk,
+    )?;
+
+    info!("[Alice] ==========================================");
+    info!("[Alice] Building Dao::Mint transaction with params");
+    info!("[Alice] ==========================================");
+    let mut data = vec![DaoFunction::Mint as u8];
+    params.encode(&mut data)?;
+    let calls = vec![ContractCall { contract_id: th.dao_contract_id, data }];
+    let proofs = vec![proofs];
+    let mut tx = Transaction { calls, proofs, signatures: vec![] };
+    let sigs = tx.create_sigs(&mut OsRng, &[])?;
+    tx.signatures = vec![sigs];
+
+    info!("[Alice] ===============================");
+    info!("[Alice] Executing Dao::Mint transaction");
+    info!("[Alice] ===============================");
+    th.alice_state.read().await.verify_transactions(&[tx.clone()], true).await?;
+    // TODO: Witness and add to wallet merkle tree?
+
+    Ok(())
+}

+ 1 - 1
src/contract/money/src/client.rs

@@ -696,7 +696,7 @@ pub fn build_transfer_tx(
     burn_pk: &ProvingKey,
     clear_input: bool,
 ) -> Result<(MoneyTransferParams, Vec<Proof>, Vec<SecretKey>, Vec<OwnCoin>)> {
-    debug!("Building money contract transaction");
+    debug!("Building money contract transfer transaction");
     assert!(value != 0);
     if !clear_input {
         assert!(!coins.is_empty());

+ 2 - 10
src/contract/money/tests/drop_pay_swap.rs

@@ -45,19 +45,11 @@ use darkfi_money_contract::{
 };
 
 mod harness;
-use harness::MoneyTestHarness;
+use harness::{init_logger, MoneyTestHarness};
 
 #[async_std::test]
 async fn money_contract_transfer() -> Result<()> {
-    let mut cfg = simplelog::ConfigBuilder::new();
-    cfg.add_filter_ignore("sled".to_string());
-    simplelog::TermLogger::init(
-        //simplelog::LevelFilter::Debug,
-        simplelog::LevelFilter::Info,
-        cfg.build(),
-        simplelog::TerminalMode::Mixed,
-        simplelog::ColorChoice::Auto,
-    )?;
+    init_logger()?;
 
     // Some numbers we want to assert
     const ALICE_INITIAL: u64 = 100;

+ 1 - 1
tests/zkvm_opcodes.rs

@@ -45,7 +45,7 @@ use darkfi::{
 
 #[test]
 fn zkvm_opcodes() -> Result<()> {
-    TermLogger::init(LevelFilter::Debug, Config::default(), TerminalMode::Mixed, ColorChoice::Auto)
+    TermLogger::init(LevelFilter::Info, Config::default(), TerminalMode::Mixed, ColorChoice::Auto)
         .unwrap();
 
     let bincode = include_bytes!("../proof/opcodes.zk.bin");