Przeglądaj źródła

example/dao: rename foo_contract to foo and update imports

Dastan-glitch 3 lat temu
rodzic
commit
c035ba4744

+ 0 - 174
example/dao/contract/dao_contract/propose/validate.rs

@@ -1,174 +0,0 @@
-use std::any::{Any, TypeId};
-
-use darkfi_sdk::crypto::MerkleNode;
-use darkfi_serial::{Encodable, SerialDecodable, SerialEncodable};
-use log::error;
-use pasta_curves::{
-    arithmetic::CurveAffine,
-    group::{Curve, Group},
-    pallas,
-};
-
-use darkfi::{
-    crypto::{keypair::PublicKey, types::DrkCircuitField},
-    Error as DarkFiError,
-};
-
-use crate::{
-    contract::{
-        dao_contract, dao_contract::State as DaoState, money_contract,
-        money_contract::state::State as MoneyState,
-    },
-    note::EncryptedNote2,
-    util::{CallDataBase, StateRegistry, Transaction, UpdateBase},
-};
-
-// used for debugging
-// const TARGET: &str = "dao_contract::propose::validate::state_transition()";
-
-#[derive(Debug, Clone, thiserror::Error)]
-pub enum Error {
-    #[error("Invalid input merkle root")]
-    InvalidInputMerkleRoot,
-
-    #[error("Invalid DAO merkle root")]
-    InvalidDaoMerkleRoot,
-
-    #[error("DarkFi error: {0}")]
-    DarkFiError(String),
-}
-type Result<T> = std::result::Result<T, Error>;
-
-impl From<DarkFiError> for Error {
-    fn from(err: DarkFiError) -> Self {
-        Self::DarkFiError(err.to_string())
-    }
-}
-
-#[derive(Clone, SerialEncodable, SerialDecodable)]
-pub struct CallData {
-    pub header: Header,
-    pub inputs: Vec<Input>,
-}
-
-impl CallDataBase for CallData {
-    fn zk_public_values(&self) -> Vec<(String, Vec<DrkCircuitField>)> {
-        let mut zk_publics = Vec::new();
-        let mut total_funds_commit = pallas::Point::identity();
-
-        assert!(!self.inputs.is_empty(), "inputs length cannot be zero");
-        for input in &self.inputs {
-            total_funds_commit += input.value_commit;
-            let value_coords = input.value_commit.to_affine().coordinates().unwrap();
-
-            let sigpub_coords = input.signature_public.0.to_affine().coordinates().unwrap();
-
-            zk_publics.push((
-                "dao-propose-burn".to_string(),
-                vec![
-                    *value_coords.x(),
-                    *value_coords.y(),
-                    self.header.token_commit,
-                    input.merkle_root.inner(),
-                    *sigpub_coords.x(),
-                    *sigpub_coords.y(),
-                ],
-            ));
-        }
-
-        let total_funds_coords = total_funds_commit.to_affine().coordinates().unwrap();
-        zk_publics.push((
-            "dao-propose-main".to_string(),
-            vec![
-                self.header.token_commit,
-                self.header.dao_merkle_root.inner(),
-                self.header.proposal_bulla,
-                *total_funds_coords.x(),
-                *total_funds_coords.y(),
-            ],
-        ));
-
-        zk_publics
-    }
-
-    fn as_any(&self) -> &dyn Any {
-        self
-    }
-
-    fn signature_public_keys(&self) -> Vec<PublicKey> {
-        let mut signature_public_keys = vec![];
-        for input in self.inputs.clone() {
-            signature_public_keys.push(input.signature_public);
-        }
-        signature_public_keys
-    }
-
-    fn encode_bytes(
-        &self,
-        mut writer: &mut dyn std::io::Write,
-    ) -> core::result::Result<usize, std::io::Error> {
-        self.encode(&mut writer)
-    }
-}
-
-#[derive(Clone, SerialEncodable, SerialDecodable)]
-pub struct Header {
-    pub dao_merkle_root: MerkleNode,
-    pub token_commit: pallas::Base,
-    pub proposal_bulla: pallas::Base,
-    pub enc_note: EncryptedNote2,
-}
-
-#[derive(Clone, SerialEncodable, SerialDecodable)]
-pub struct Input {
-    pub value_commit: pallas::Point,
-    pub merkle_root: MerkleNode,
-    pub signature_public: PublicKey,
-}
-
-pub fn state_transition(
-    states: &StateRegistry,
-    func_call_index: usize,
-    parent_tx: &Transaction,
-) -> Result<Box<dyn UpdateBase + Send>> {
-    let func_call = &parent_tx.func_calls[func_call_index];
-    let call_data = func_call.call_data.as_any();
-
-    assert_eq!((*call_data).type_id(), TypeId::of::<CallData>());
-    let call_data = call_data.downcast_ref::<CallData>();
-
-    // This will be inside wasm so unwrap is fine.
-    let call_data = call_data.unwrap();
-
-    // Check the merkle roots for the input coins are valid
-    for input in &call_data.inputs {
-        let money_state = states.lookup::<MoneyState>(*money_contract::CONTRACT_ID).unwrap();
-        if !money_state.is_valid_merkle(&input.merkle_root) {
-            return Err(Error::InvalidInputMerkleRoot)
-        }
-    }
-
-    let state = states.lookup::<DaoState>(*dao_contract::CONTRACT_ID).unwrap();
-
-    // Is the DAO bulla generated in the ZK proof valid
-    if !state.is_valid_dao_merkle(&call_data.header.dao_merkle_root) {
-        return Err(Error::InvalidDaoMerkleRoot)
-    }
-
-    // TODO: look at gov tokens avoid using already spent ones
-    // Need to spend original coin and generate 2 nullifiers?
-
-    Ok(Box::new(Update { proposal_bulla: call_data.header.proposal_bulla }))
-}
-
-#[derive(Clone)]
-pub struct Update {
-    pub proposal_bulla: pallas::Base,
-}
-
-impl UpdateBase for Update {
-    fn apply(self: Box<Self>, states: &mut StateRegistry) {
-        let state = states.lookup_mut::<DaoState>(*dao_contract::CONTRACT_ID).unwrap();
-        state.add_proposal_bulla(self.proposal_bulla);
-    }
-}

+ 0 - 272
example/dao/contract/dao_contract/propose/wallet.rs

@@ -1,272 +0,0 @@
-use darkfi_sdk::crypto::MerkleNode;
-use darkfi_serial::{SerialDecodable, SerialEncodable};
-use halo2_proofs::circuit::Value;
-use incrementalmerkletree::Hashable;
-use pasta_curves::{
-    arithmetic::CurveAffine,
-    group::{ff::Field, Curve},
-    pallas,
-};
-use rand::rngs::OsRng;
-
-use darkfi::{
-    crypto::{
-        keypair::{PublicKey, SecretKey},
-        util::{pedersen_commitment_u64, poseidon_hash},
-        Proof,
-    },
-    zk::vm::{Witness, ZkCircuit},
-};
-
-use crate::{
-    contract::{
-        dao_contract::{
-            mint::wallet::DaoParams,
-            propose::validate::{CallData, Header, Input},
-            CONTRACT_ID,
-        },
-        money_contract,
-    },
-    note,
-    util::{FuncCall, ZkContractInfo, ZkContractTable},
-};
-
-#[derive(SerialEncodable, SerialDecodable)]
-pub struct Note {
-    pub proposal: Proposal,
-}
-
-pub struct BuilderInput {
-    pub secret: SecretKey,
-    pub note: money_contract::transfer::wallet::Note,
-    pub leaf_position: incrementalmerkletree::Position,
-    pub merkle_path: Vec<MerkleNode>,
-    pub signature_secret: SecretKey,
-}
-
-#[derive(SerialEncodable, SerialDecodable, Clone)]
-pub struct Proposal {
-    pub dest: PublicKey,
-    pub amount: u64,
-    pub serial: pallas::Base,
-    pub token_id: pallas::Base,
-    pub blind: pallas::Base,
-}
-
-pub struct Builder {
-    pub inputs: Vec<BuilderInput>,
-    pub proposal: Proposal,
-    pub dao: DaoParams,
-    pub dao_leaf_position: incrementalmerkletree::Position,
-    pub dao_merkle_path: Vec<MerkleNode>,
-    pub dao_merkle_root: MerkleNode,
-}
-
-impl Builder {
-    pub fn build(self, zk_bins: &ZkContractTable) -> FuncCall {
-        let mut proofs = vec![];
-
-        let gov_token_blind = pallas::Base::random(&mut OsRng);
-
-        let mut inputs = vec![];
-        let mut total_funds = 0;
-        let mut total_funds_blinds = pallas::Scalar::from(0);
-
-        for input in self.inputs {
-            let funds_blind = pallas::Scalar::random(&mut OsRng);
-            total_funds += input.note.value;
-            total_funds_blinds += funds_blind;
-
-            let signature_public = PublicKey::from_secret(input.signature_secret);
-
-            let zk_info = zk_bins.lookup(&"dao-propose-burn".to_string()).unwrap();
-            let zk_info = if let ZkContractInfo::Binary(info) = zk_info {
-                info
-            } else {
-                panic!("Not binary info")
-            };
-            let zk_bin = zk_info.bincode.clone();
-
-            // Note from the previous output
-            let note = input.note;
-            let leaf_pos: u64 = input.leaf_position.into();
-
-            let prover_witnesses = vec![
-                Witness::Base(Value::known(input.secret.inner())),
-                Witness::Base(Value::known(note.serial)),
-                Witness::Base(Value::known(pallas::Base::from(0))),
-                Witness::Base(Value::known(pallas::Base::from(0))),
-                Witness::Base(Value::known(pallas::Base::from(note.value))),
-                Witness::Base(Value::known(note.token_id)),
-                Witness::Base(Value::known(note.coin_blind)),
-                Witness::Scalar(Value::known(funds_blind)),
-                Witness::Base(Value::known(gov_token_blind)),
-                Witness::Uint32(Value::known(leaf_pos.try_into().unwrap())),
-                Witness::MerklePath(Value::known(input.merkle_path.clone().try_into().unwrap())),
-                Witness::Base(Value::known(input.signature_secret.inner())),
-            ];
-
-            let public_key = PublicKey::from_secret(input.secret);
-            let coords = public_key.0.to_affine().coordinates().unwrap();
-
-            let coin = poseidon_hash::<8>([
-                *coords.x(),
-                *coords.y(),
-                pallas::Base::from(note.value),
-                note.token_id,
-                note.serial,
-                pallas::Base::from(0),
-                pallas::Base::from(0),
-                note.coin_blind,
-            ]);
-
-            let merkle_root = {
-                let position: u64 = input.leaf_position.into();
-                let mut current = MerkleNode::from(coin);
-                for (level, sibling) in input.merkle_path.iter().enumerate() {
-                    let level = level as u8;
-                    current = if position & (1 << level) == 0 {
-                        MerkleNode::combine(level.into(), &current, sibling)
-                    } else {
-                        MerkleNode::combine(level.into(), sibling, &current)
-                    };
-                }
-                current
-            };
-
-            let token_commit = poseidon_hash::<2>([note.token_id, gov_token_blind]);
-            assert_eq!(self.dao.gov_token_id, note.token_id);
-
-            let value_commit = pedersen_commitment_u64(note.value, funds_blind);
-            let value_coords = value_commit.to_affine().coordinates().unwrap();
-
-            let sigpub_coords = signature_public.0.to_affine().coordinates().unwrap();
-
-            let public_inputs = vec![
-                *value_coords.x(),
-                *value_coords.y(),
-                token_commit,
-                merkle_root.inner(),
-                *sigpub_coords.x(),
-                *sigpub_coords.y(),
-            ];
-            let circuit = ZkCircuit::new(prover_witnesses, zk_bin);
-
-            let proving_key = &zk_info.proving_key;
-            let input_proof = Proof::create(proving_key, &[circuit], &public_inputs, &mut OsRng)
-                .expect("DAO::propose() proving error!");
-            proofs.push(input_proof);
-
-            let input = Input { value_commit, merkle_root, signature_public };
-            inputs.push(input);
-        }
-
-        let total_funds_commit = pedersen_commitment_u64(total_funds, total_funds_blinds);
-        let total_funds_coords = total_funds_commit.to_affine().coordinates().unwrap();
-        let total_funds = pallas::Base::from(total_funds);
-
-        let token_commit = poseidon_hash::<2>([self.dao.gov_token_id, gov_token_blind]);
-
-        let proposal_dest_coords = self.proposal.dest.0.to_affine().coordinates().unwrap();
-        let proposal_dest_x = *proposal_dest_coords.x();
-        let proposal_dest_y = *proposal_dest_coords.y();
-
-        let proposal_amount = pallas::Base::from(self.proposal.amount);
-
-        let dao_proposer_limit = pallas::Base::from(self.dao.proposer_limit);
-        let dao_quorum = pallas::Base::from(self.dao.quorum);
-        let dao_approval_ratio_quot = pallas::Base::from(self.dao.approval_ratio_quot);
-        let dao_approval_ratio_base = pallas::Base::from(self.dao.approval_ratio_base);
-
-        let dao_pubkey_coords = self.dao.public_key.0.to_affine().coordinates().unwrap();
-
-        let dao_bulla = poseidon_hash::<8>([
-            dao_proposer_limit,
-            dao_quorum,
-            dao_approval_ratio_quot,
-            dao_approval_ratio_base,
-            self.dao.gov_token_id,
-            *dao_pubkey_coords.x(),
-            *dao_pubkey_coords.y(),
-            self.dao.bulla_blind,
-        ]);
-
-        let dao_leaf_position: u64 = self.dao_leaf_position.into();
-
-        let proposal_bulla = poseidon_hash::<8>([
-            proposal_dest_x,
-            proposal_dest_y,
-            proposal_amount,
-            self.proposal.serial,
-            self.proposal.token_id,
-            dao_bulla,
-            self.proposal.blind,
-            // @tmp-workaround
-            self.proposal.blind,
-        ]);
-
-        let zk_info = zk_bins.lookup(&"dao-propose-main".to_string()).unwrap();
-        let zk_info = if let ZkContractInfo::Binary(info) = zk_info {
-            info
-        } else {
-            panic!("Not binary info")
-        };
-        let zk_bin = zk_info.bincode.clone();
-        let prover_witnesses = vec![
-            // Proposers total number of gov tokens
-            Witness::Base(Value::known(total_funds)),
-            Witness::Scalar(Value::known(total_funds_blinds)),
-            // Used for blinding exported gov token ID
-            Witness::Base(Value::known(gov_token_blind)),
-            // proposal params
-            Witness::Base(Value::known(proposal_dest_x)),
-            Witness::Base(Value::known(proposal_dest_y)),
-            Witness::Base(Value::known(proposal_amount)),
-            Witness::Base(Value::known(self.proposal.serial)),
-            Witness::Base(Value::known(self.proposal.token_id)),
-            Witness::Base(Value::known(self.proposal.blind)),
-            // DAO params
-            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(self.dao.gov_token_id)),
-            Witness::Base(Value::known(*dao_pubkey_coords.x())),
-            Witness::Base(Value::known(*dao_pubkey_coords.y())),
-            Witness::Base(Value::known(self.dao.bulla_blind)),
-            Witness::Uint32(Value::known(dao_leaf_position.try_into().unwrap())),
-            Witness::MerklePath(Value::known(self.dao_merkle_path.try_into().unwrap())),
-        ];
-        let public_inputs = vec![
-            token_commit,
-            self.dao_merkle_root.inner(),
-            proposal_bulla,
-            *total_funds_coords.x(),
-            *total_funds_coords.y(),
-        ];
-        let circuit = ZkCircuit::new(prover_witnesses, zk_bin);
-
-        let proving_key = &zk_info.proving_key;
-        let main_proof = Proof::create(proving_key, &[circuit], &public_inputs, &mut OsRng)
-            .expect("DAO::propose() proving error!");
-        proofs.push(main_proof);
-
-        let note = Note { proposal: self.proposal };
-        let enc_note = note::encrypt(&note, &self.dao.public_key).unwrap();
-        let header = Header {
-            dao_merkle_root: self.dao_merkle_root,
-            proposal_bulla,
-            token_commit,
-            enc_note,
-        };
-
-        let call_data = CallData { header, inputs };
-
-        FuncCall {
-            contract_id: *CONTRACT_ID,
-            func_id: *super::FUNC_ID,
-            call_data: Box::new(call_data),
-            proofs,
-        }
-    }
-}

+ 0 - 96
example/dao/contract/dao_contract/state.rs

@@ -1,96 +0,0 @@
-use std::{any::Any, collections::HashMap};
-
-use darkfi_sdk::crypto::{constants::MERKLE_DEPTH, MerkleNode, Nullifier};
-use darkfi_serial::{SerialDecodable, SerialEncodable};
-use incrementalmerkletree::{bridgetree::BridgeTree, Tree};
-use pasta_curves::{group::Group, pallas};
-
-use crate::util::HashableBase;
-
-#[derive(Clone, SerialEncodable, SerialDecodable)]
-pub struct DaoBulla(pub pallas::Base);
-
-type MerkleTree = BridgeTree<MerkleNode, MERKLE_DEPTH>;
-
-pub struct ProposalVotes {
-    // TODO: might be more logical to have 'yes_votes_commit' and 'no_votes_commit'
-    /// Weighted vote commit
-    pub yes_votes_commit: pallas::Point,
-    /// All value staked in the vote
-    pub all_votes_commit: pallas::Point,
-    /// Vote nullifiers
-    pub vote_nulls: Vec<Nullifier>,
-}
-
-impl ProposalVotes {
-    pub fn nullifier_exists(&self, nullifier: &Nullifier) -> bool {
-        self.vote_nulls.iter().any(|n| n == nullifier)
-    }
-}
-
-/// This DAO state is for all DAOs on the network. There should only be a single instance.
-pub struct State {
-    dao_bullas: Vec<DaoBulla>,
-    pub dao_tree: MerkleTree,
-    pub dao_roots: Vec<MerkleNode>,
-
-    //proposal_bullas: Vec<pallas::Base>,
-    pub proposal_tree: MerkleTree,
-    pub proposal_roots: Vec<MerkleNode>,
-    pub proposal_votes: HashMap<HashableBase, ProposalVotes>,
-}
-
-impl State {
-    pub fn new() -> Box<dyn Any + Send> {
-        Box::new(Self {
-            dao_bullas: Vec::new(),
-            dao_tree: MerkleTree::new(100),
-            dao_roots: Vec::new(),
-            //proposal_bullas: Vec::new(),
-            proposal_tree: MerkleTree::new(100),
-            proposal_roots: Vec::new(),
-            proposal_votes: HashMap::new(),
-        })
-    }
-
-    pub fn add_dao_bulla(&mut self, bulla: DaoBulla) {
-        let node = MerkleNode::from(bulla.0);
-        self.dao_bullas.push(bulla);
-        self.dao_tree.append(&node);
-        self.dao_roots.push(self.dao_tree.root(0).unwrap());
-    }
-
-    pub fn add_proposal_bulla(&mut self, bulla: pallas::Base) {
-        let node = MerkleNode::from(bulla);
-        //self.proposal_bullas.push(bulla);
-        self.proposal_tree.append(&node);
-        self.proposal_roots.push(self.proposal_tree.root(0).unwrap());
-        self.proposal_votes.insert(
-            HashableBase(bulla),
-            ProposalVotes {
-                yes_votes_commit: pallas::Point::identity(),
-                all_votes_commit: pallas::Point::identity(),
-                vote_nulls: Vec::new(),
-            },
-        );
-    }
-
-    pub fn lookup_proposal_votes(&self, proposal_bulla: pallas::Base) -> Option<&ProposalVotes> {
-        self.proposal_votes.get(&HashableBase(proposal_bulla))
-    }
-    pub fn lookup_proposal_votes_mut(
-        &mut self,
-        proposal_bulla: pallas::Base,
-    ) -> Option<&mut ProposalVotes> {
-        self.proposal_votes.get_mut(&HashableBase(proposal_bulla))
-    }
-
-    pub fn is_valid_dao_merkle(&self, root: &MerkleNode) -> bool {
-        self.dao_roots.iter().any(|m| m == root)
-    }
-
-    // TODO: This never gets called.
-    pub fn _is_valid_proposal_merkle(&self, root: &MerkleNode) -> bool {
-        self.proposal_roots.iter().any(|m| m == root)
-    }
-}

+ 0 - 207
example/dao/contract/dao_contract/vote/validate.rs

@@ -1,207 +0,0 @@
-use std::any::{Any, TypeId};
-
-use darkfi_sdk::crypto::{MerkleNode, Nullifier};
-use darkfi_serial::{Encodable, SerialDecodable, SerialEncodable};
-use log::error;
-use pasta_curves::{
-    arithmetic::CurveAffine,
-    group::{Curve, Group},
-    pallas,
-};
-
-use darkfi::{
-    crypto::{keypair::PublicKey, types::DrkCircuitField},
-    Error as DarkFiError,
-};
-
-use crate::{
-    contract::{
-        dao_contract, dao_contract::State as DaoState, money_contract,
-        money_contract::state::State as MoneyState,
-    },
-    note::EncryptedNote2,
-    util::{CallDataBase, StateRegistry, Transaction, UpdateBase},
-};
-
-#[derive(Debug, Clone, thiserror::Error)]
-pub enum Error {
-    #[error("Invalid proposal")]
-    InvalidProposal,
-
-    #[error("Voting with already spent coinage")]
-    SpentCoin,
-
-    #[error("Double voting")]
-    DoubleVote,
-
-    #[error("Invalid input merkle root")]
-    InvalidInputMerkleRoot,
-
-    #[error("DarkFi error: {0}")]
-    DarkFiError(String),
-}
-type Result<T> = std::result::Result<T, Error>;
-
-impl From<DarkFiError> for Error {
-    fn from(err: DarkFiError) -> Self {
-        Self::DarkFiError(err.to_string())
-    }
-}
-
-#[derive(Clone, SerialEncodable, SerialDecodable)]
-pub struct CallData {
-    pub header: Header,
-    pub inputs: Vec<Input>,
-}
-
-impl CallDataBase for CallData {
-    fn zk_public_values(&self) -> Vec<(String, Vec<DrkCircuitField>)> {
-        let mut zk_publics = Vec::new();
-        let mut all_votes_commit = pallas::Point::identity();
-
-        assert!(!self.inputs.is_empty(), "inputs length cannot be zero");
-        for input in &self.inputs {
-            all_votes_commit += input.vote_commit;
-            let value_coords = input.vote_commit.to_affine().coordinates().unwrap();
-
-            let sigpub_coords = input.signature_public.0.to_affine().coordinates().unwrap();
-
-            zk_publics.push((
-                "dao-vote-burn".to_string(),
-                vec![
-                    input.nullifier.inner(),
-                    *value_coords.x(),
-                    *value_coords.y(),
-                    self.header.token_commit,
-                    input.merkle_root.inner(),
-                    *sigpub_coords.x(),
-                    *sigpub_coords.y(),
-                ],
-            ));
-        }
-
-        let yes_vote_commit_coords = self.header.yes_vote_commit.to_affine().coordinates().unwrap();
-
-        let vote_commit_coords = all_votes_commit.to_affine().coordinates().unwrap();
-
-        zk_publics.push((
-            "dao-vote-main".to_string(),
-            vec![
-                self.header.token_commit,
-                self.header.proposal_bulla,
-                *yes_vote_commit_coords.x(),
-                *yes_vote_commit_coords.y(),
-                *vote_commit_coords.x(),
-                *vote_commit_coords.y(),
-            ],
-        ));
-
-        zk_publics
-    }
-
-    fn as_any(&self) -> &dyn Any {
-        self
-    }
-
-    fn signature_public_keys(&self) -> Vec<PublicKey> {
-        let mut signature_public_keys = vec![];
-        for input in self.inputs.clone() {
-            signature_public_keys.push(input.signature_public);
-        }
-        signature_public_keys
-    }
-
-    fn encode_bytes(
-        &self,
-        mut writer: &mut dyn std::io::Write,
-    ) -> core::result::Result<usize, std::io::Error> {
-        self.encode(&mut writer)
-    }
-}
-
-#[derive(Clone, SerialEncodable, SerialDecodable)]
-pub struct Header {
-    pub token_commit: pallas::Base,
-    pub proposal_bulla: pallas::Base,
-    pub yes_vote_commit: pallas::Point,
-    pub enc_note: EncryptedNote2,
-}
-
-#[derive(Clone, SerialEncodable, SerialDecodable)]
-pub struct Input {
-    pub nullifier: Nullifier,
-    pub vote_commit: pallas::Point,
-    pub merkle_root: MerkleNode,
-    pub signature_public: PublicKey,
-}
-
-pub fn state_transition(
-    states: &StateRegistry,
-    func_call_index: usize,
-    parent_tx: &Transaction,
-) -> Result<Box<dyn UpdateBase + Send>> {
-    let func_call = &parent_tx.func_calls[func_call_index];
-    let call_data = func_call.call_data.as_any();
-
-    assert_eq!((*call_data).type_id(), TypeId::of::<CallData>());
-    let call_data = call_data.downcast_ref::<CallData>();
-
-    // This will be inside wasm so unwrap is fine.
-    let call_data = call_data.unwrap();
-
-    let dao_state = states.lookup::<DaoState>(*dao_contract::CONTRACT_ID).unwrap();
-
-    // Check proposal_bulla exists
-    let votes_info = dao_state.lookup_proposal_votes(call_data.header.proposal_bulla);
-    if votes_info.is_none() {
-        return Err(Error::InvalidProposal)
-    }
-    let votes_info = votes_info.unwrap();
-
-    // Check the merkle roots for the input coins are valid
-    let mut vote_nulls = Vec::new();
-    let mut all_vote_commit = pallas::Point::identity();
-    for input in &call_data.inputs {
-        let money_state = states.lookup::<MoneyState>(*money_contract::CONTRACT_ID).unwrap();
-        if !money_state.is_valid_merkle(&input.merkle_root) {
-            return Err(Error::InvalidInputMerkleRoot)
-        }
-
-        if money_state.nullifier_exists(&input.nullifier) {
-            return Err(Error::SpentCoin)
-        }
-
-        if votes_info.nullifier_exists(&input.nullifier) {
-            return Err(Error::DoubleVote)
-        }
-
-        all_vote_commit += input.vote_commit;
-
-        vote_nulls.push(input.nullifier);
-    }
-
-    Ok(Box::new(Update {
-        proposal_bulla: call_data.header.proposal_bulla,
-        vote_nulls,
-        yes_vote_commit: call_data.header.yes_vote_commit,
-        all_vote_commit,
-    }))
-}
-
-#[derive(Clone)]
-pub struct Update {
-    proposal_bulla: pallas::Base,
-    vote_nulls: Vec<Nullifier>,
-    pub yes_vote_commit: pallas::Point,
-    pub all_vote_commit: pallas::Point,
-}
-
-impl UpdateBase for Update {
-    fn apply(mut self: Box<Self>, states: &mut StateRegistry) {
-        let state = states.lookup_mut::<DaoState>(*dao_contract::CONTRACT_ID).unwrap();
-        let votes_info = state.lookup_proposal_votes_mut(self.proposal_bulla).unwrap();
-        votes_info.yes_votes_commit += self.yes_vote_commit;
-        votes_info.all_votes_commit += self.all_vote_commit;
-        votes_info.vote_nulls.append(&mut self.vote_nulls);
-    }
-}

+ 0 - 287
example/dao/contract/dao_contract/vote/wallet.rs

@@ -1,287 +0,0 @@
-use darkfi_sdk::crypto::{MerkleNode, Nullifier};
-use darkfi_serial::{SerialDecodable, SerialEncodable};
-use halo2_proofs::circuit::Value;
-use incrementalmerkletree::Hashable;
-use log::debug;
-use pasta_curves::{
-    arithmetic::CurveAffine,
-    group::{ff::Field, Curve},
-    pallas,
-};
-use rand::rngs::OsRng;
-
-use darkfi::{
-    crypto::{
-        keypair::{Keypair, PublicKey, SecretKey},
-        util::{pedersen_commitment_u64, poseidon_hash},
-        Proof,
-    },
-    zk::vm::{Witness, ZkCircuit},
-};
-
-use crate::{
-    contract::{
-        dao_contract::{
-            mint::wallet::DaoParams,
-            propose::wallet::Proposal,
-            vote::validate::{CallData, Header, Input},
-            CONTRACT_ID,
-        },
-        money_contract,
-    },
-    note,
-    util::{FuncCall, ZkContractInfo, ZkContractTable},
-};
-
-#[derive(SerialEncodable, SerialDecodable)]
-pub struct Note {
-    pub vote: Vote,
-    pub vote_value: u64,
-    pub vote_value_blind: pallas::Scalar,
-}
-
-#[derive(SerialEncodable, SerialDecodable)]
-pub struct Vote {
-    pub vote_option: bool,
-    pub vote_option_blind: pallas::Scalar,
-}
-
-pub struct BuilderInput {
-    pub secret: SecretKey,
-    pub note: money_contract::transfer::wallet::Note,
-    pub leaf_position: incrementalmerkletree::Position,
-    pub merkle_path: Vec<MerkleNode>,
-    pub signature_secret: SecretKey,
-}
-
-// TODO: should be token locking voting?
-// Inside ZKproof, check proposal is correct.
-pub struct Builder {
-    pub inputs: Vec<BuilderInput>,
-    pub vote: Vote,
-    pub vote_keypair: Keypair,
-    pub proposal: Proposal,
-    pub dao: DaoParams,
-}
-
-impl Builder {
-    pub fn build(self, zk_bins: &ZkContractTable) -> FuncCall {
-        debug!(target: "dao_contract::vote::wallet::Builder", "build()");
-        let mut proofs = vec![];
-
-        let gov_token_blind = pallas::Base::random(&mut OsRng);
-
-        let mut inputs = vec![];
-        let mut vote_value = 0;
-        let mut vote_value_blind = pallas::Scalar::from(0);
-
-        for input in self.inputs {
-            let value_blind = pallas::Scalar::random(&mut OsRng);
-
-            vote_value += input.note.value;
-            vote_value_blind += value_blind;
-
-            let signature_public = PublicKey::from_secret(input.signature_secret);
-
-            let zk_info = zk_bins.lookup(&"dao-vote-burn".to_string()).unwrap();
-
-            let zk_info = if let ZkContractInfo::Binary(info) = zk_info {
-                info
-            } else {
-                panic!("Not binary info")
-            };
-            let zk_bin = zk_info.bincode.clone();
-
-            // Note from the previous output
-            let note = input.note;
-            let leaf_pos: u64 = input.leaf_position.into();
-
-            let prover_witnesses = vec![
-                Witness::Base(Value::known(input.secret.inner())),
-                Witness::Base(Value::known(note.serial)),
-                Witness::Base(Value::known(pallas::Base::from(0))),
-                Witness::Base(Value::known(pallas::Base::from(0))),
-                Witness::Base(Value::known(pallas::Base::from(note.value))),
-                Witness::Base(Value::known(note.token_id)),
-                Witness::Base(Value::known(note.coin_blind)),
-                Witness::Scalar(Value::known(vote_value_blind)),
-                Witness::Base(Value::known(gov_token_blind)),
-                Witness::Uint32(Value::known(leaf_pos.try_into().unwrap())),
-                Witness::MerklePath(Value::known(input.merkle_path.clone().try_into().unwrap())),
-                Witness::Base(Value::known(input.signature_secret.inner())),
-            ];
-
-            let public_key = PublicKey::from_secret(input.secret);
-            let coords = public_key.0.to_affine().coordinates().unwrap();
-
-            let coin = poseidon_hash::<8>([
-                *coords.x(),
-                *coords.y(),
-                pallas::Base::from(note.value),
-                note.token_id,
-                note.serial,
-                pallas::Base::from(0),
-                pallas::Base::from(0),
-                note.coin_blind,
-            ]);
-
-            let merkle_root = {
-                let position: u64 = input.leaf_position.into();
-                let mut current = MerkleNode::from(coin);
-                for (level, sibling) in input.merkle_path.iter().enumerate() {
-                    let level = level as u8;
-                    current = if position & (1 << level) == 0 {
-                        MerkleNode::combine(level.into(), &current, sibling)
-                    } else {
-                        MerkleNode::combine(level.into(), sibling, &current)
-                    };
-                }
-                current
-            };
-
-            let token_commit = poseidon_hash::<2>([note.token_id, gov_token_blind]);
-            assert_eq!(self.dao.gov_token_id, note.token_id);
-
-            let nullifier =
-                Nullifier::from(poseidon_hash::<2>([input.secret.inner(), note.serial]));
-
-            let vote_commit = pedersen_commitment_u64(note.value, vote_value_blind);
-            let vote_commit_coords = vote_commit.to_affine().coordinates().unwrap();
-
-            let sigpub_coords = signature_public.0.to_affine().coordinates().unwrap();
-
-            let public_inputs = vec![
-                nullifier.inner(),
-                *vote_commit_coords.x(),
-                *vote_commit_coords.y(),
-                token_commit,
-                merkle_root.inner(),
-                *sigpub_coords.x(),
-                *sigpub_coords.y(),
-            ];
-
-            let circuit = ZkCircuit::new(prover_witnesses, zk_bin);
-            let proving_key = &zk_info.proving_key;
-            debug!(target: "dao_contract::vote::wallet::Builder", "input_proof Proof::create()");
-            let input_proof = Proof::create(proving_key, &[circuit], &public_inputs, &mut OsRng)
-                .expect("DAO::vote() proving error!");
-            proofs.push(input_proof);
-
-            let input = Input { nullifier, vote_commit, merkle_root, signature_public };
-            inputs.push(input);
-        }
-
-        let token_commit = poseidon_hash::<2>([self.dao.gov_token_id, gov_token_blind]);
-
-        let proposal_dest_coords = self.proposal.dest.0.to_affine().coordinates().unwrap();
-
-        let proposal_amount = pallas::Base::from(self.proposal.amount);
-
-        let dao_proposer_limit = pallas::Base::from(self.dao.proposer_limit);
-        let dao_quorum = pallas::Base::from(self.dao.quorum);
-        let dao_approval_ratio_quot = pallas::Base::from(self.dao.approval_ratio_quot);
-        let dao_approval_ratio_base = pallas::Base::from(self.dao.approval_ratio_base);
-
-        let dao_pubkey_coords = self.dao.public_key.0.to_affine().coordinates().unwrap();
-
-        let dao_bulla = poseidon_hash::<8>([
-            dao_proposer_limit,
-            dao_quorum,
-            dao_approval_ratio_quot,
-            dao_approval_ratio_base,
-            self.dao.gov_token_id,
-            *dao_pubkey_coords.x(),
-            *dao_pubkey_coords.y(),
-            self.dao.bulla_blind,
-        ]);
-
-        let proposal_bulla = poseidon_hash::<8>([
-            *proposal_dest_coords.x(),
-            *proposal_dest_coords.y(),
-            proposal_amount,
-            self.proposal.serial,
-            self.proposal.token_id,
-            dao_bulla,
-            self.proposal.blind,
-            // @tmp-workaround
-            self.proposal.blind,
-        ]);
-
-        let vote_option = self.vote.vote_option as u64;
-        assert!(vote_option == 0 || vote_option == 1);
-
-        let yes_vote_commit =
-            pedersen_commitment_u64(vote_option * vote_value, self.vote.vote_option_blind);
-        let yes_vote_commit_coords = yes_vote_commit.to_affine().coordinates().unwrap();
-
-        let all_vote_commit = pedersen_commitment_u64(vote_value, vote_value_blind);
-        let all_vote_commit_coords = all_vote_commit.to_affine().coordinates().unwrap();
-
-        let zk_info = zk_bins.lookup(&"dao-vote-main".to_string()).unwrap();
-        let zk_info = if let ZkContractInfo::Binary(info) = zk_info {
-            info
-        } else {
-            panic!("Not binary info")
-        };
-        let zk_bin = zk_info.bincode.clone();
-
-        let prover_witnesses = vec![
-            // proposal params
-            Witness::Base(Value::known(*proposal_dest_coords.x())),
-            Witness::Base(Value::known(*proposal_dest_coords.y())),
-            Witness::Base(Value::known(proposal_amount)),
-            Witness::Base(Value::known(self.proposal.serial)),
-            Witness::Base(Value::known(self.proposal.token_id)),
-            Witness::Base(Value::known(self.proposal.blind)),
-            // DAO params
-            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(self.dao.gov_token_id)),
-            Witness::Base(Value::known(*dao_pubkey_coords.x())),
-            Witness::Base(Value::known(*dao_pubkey_coords.y())),
-            Witness::Base(Value::known(self.dao.bulla_blind)),
-            // Vote
-            Witness::Base(Value::known(pallas::Base::from(vote_option))),
-            Witness::Scalar(Value::known(self.vote.vote_option_blind)),
-            // Total number of gov tokens allocated
-            Witness::Base(Value::known(pallas::Base::from(vote_value))),
-            Witness::Scalar(Value::known(vote_value_blind)),
-            // gov token
-            Witness::Base(Value::known(gov_token_blind)),
-        ];
-
-        let public_inputs = vec![
-            token_commit,
-            proposal_bulla,
-            // this should be a value commit??
-            *yes_vote_commit_coords.x(),
-            *yes_vote_commit_coords.y(),
-            *all_vote_commit_coords.x(),
-            *all_vote_commit_coords.y(),
-        ];
-
-        let circuit = ZkCircuit::new(prover_witnesses, zk_bin);
-
-        let proving_key = &zk_info.proving_key;
-        debug!(target: "dao_contract::vote::wallet::Builder", "main_proof = Proof::create()");
-        let main_proof = Proof::create(proving_key, &[circuit], &public_inputs, &mut OsRng)
-            .expect("DAO::vote() proving error!");
-        proofs.push(main_proof);
-
-        let note = Note { vote: self.vote, vote_value, vote_value_blind };
-        let enc_note = note::encrypt(&note, &self.vote_keypair.public).unwrap();
-
-        let header = Header { token_commit, proposal_bulla, yes_vote_commit, enc_note };
-
-        let call_data = CallData { header, inputs };
-
-        FuncCall {
-            contract_id: *CONTRACT_ID,
-            func_id: *super::FUNC_ID,
-            call_data: Box::new(call_data),
-            proofs,
-        }
-    }
-}

+ 0 - 114
example/dao/contract/money_contract/state.rs

@@ -1,114 +0,0 @@
-use darkfi_sdk::crypto::{constants::MERKLE_DEPTH, MerkleNode, Nullifier};
-use incrementalmerkletree::{bridgetree::BridgeTree, Tree};
-
-use darkfi::crypto::{
-    coin::Coin,
-    keypair::{PublicKey, SecretKey},
-};
-
-use super::transfer;
-use crate::note::EncryptedNote2;
-
-type MerkleTree = BridgeTree<MerkleNode, MERKLE_DEPTH>;
-
-pub struct OwnCoin {
-    pub coin: Coin,
-    pub note: transfer::wallet::Note,
-    pub leaf_position: incrementalmerkletree::Position,
-}
-
-pub struct WalletCache {
-    // Normally this would be a HashMap, but SecretKey is not Hash-able
-    // TODO: This can be HashableBase
-    cache: Vec<(SecretKey, Vec<OwnCoin>)>,
-}
-
-impl WalletCache {
-    pub fn new() -> Self {
-        Self { cache: Vec::new() }
-    }
-
-    /// Must be called at the start to begin tracking received coins for this secret.
-    pub fn track(&mut self, secret: SecretKey) {
-        self.cache.push((secret, Vec::new()));
-    }
-
-    /// Get all coins received by this secret key
-    /// track() must be called on this secret before calling this or the function will panic.
-    pub fn get_received(&mut self, secret: &SecretKey) -> Vec<OwnCoin> {
-        for (other_secret, own_coins) in self.cache.iter_mut() {
-            if *secret == *other_secret {
-                // clear own_coins vec, and return current contents
-                return std::mem::take(own_coins)
-            }
-        }
-        panic!("you forget to track() this secret!");
-    }
-
-    pub fn try_decrypt_note(
-        &mut self,
-        coin: Coin,
-        ciphertext: EncryptedNote2,
-        tree: &mut MerkleTree,
-    ) {
-        // Loop through all our secret keys...
-        for (secret, own_coins) in self.cache.iter_mut() {
-            // .. attempt to decrypt the note ...
-            if let Ok(note) = ciphertext.decrypt(secret) {
-                let leaf_position = tree.witness().expect("coin should be in tree");
-                own_coins.push(OwnCoin { coin, note, leaf_position });
-            }
-        }
-    }
-}
-
-/// The state machine, held in memory.
-pub struct State {
-    /// The entire Merkle tree state
-    pub tree: MerkleTree,
-    /// List of all previous and the current Merkle roots.
-    /// This is the hashed value of all the children.
-    pub merkle_roots: Vec<MerkleNode>,
-    /// Nullifiers prevent double spending
-    pub nullifiers: Vec<Nullifier>,
-
-    /// Public key of the cashier
-    pub cashier_signature_public: PublicKey,
-
-    /// Public key of the faucet
-    pub faucet_signature_public: PublicKey,
-
-    pub wallet_cache: WalletCache,
-}
-
-impl State {
-    pub fn new(
-        cashier_signature_public: PublicKey,
-        faucet_signature_public: PublicKey,
-    ) -> Box<Self> {
-        Box::new(Self {
-            tree: MerkleTree::new(100),
-            merkle_roots: vec![],
-            nullifiers: vec![],
-            cashier_signature_public,
-            faucet_signature_public,
-            wallet_cache: WalletCache::new(),
-        })
-    }
-
-    pub fn is_valid_cashier_public_key(&self, public: &PublicKey) -> bool {
-        public == &self.cashier_signature_public
-    }
-
-    pub fn is_valid_faucet_public_key(&self, public: &PublicKey) -> bool {
-        public == &self.faucet_signature_public
-    }
-
-    pub fn is_valid_merkle(&self, merkle_root: &MerkleNode) -> bool {
-        self.merkle_roots.iter().any(|m| m == merkle_root)
-    }
-
-    pub fn nullifier_exists(&self, nullifier: &Nullifier) -> bool {
-        self.nullifiers.iter().any(|n| n == nullifier)
-    }
-}

+ 0 - 374
example/dao/contract/money_contract/transfer/validate.rs

@@ -1,374 +0,0 @@
-use std::any::{Any, TypeId};
-
-use darkfi_sdk::crypto::{MerkleNode, Nullifier};
-use darkfi_serial::{Encodable, SerialDecodable, SerialEncodable};
-use incrementalmerkletree::Tree;
-use log::{debug, error};
-use pasta_curves::{group::Group, pallas};
-
-use darkfi::{
-    crypto::{
-        coin::Coin,
-        keypair::PublicKey,
-        types::{DrkCircuitField, DrkTokenId, DrkValueBlind, DrkValueCommit},
-        util::{pedersen_commitment_base, pedersen_commitment_u64},
-        BurnRevealedValues, MintRevealedValues,
-    },
-    Error as DarkFiError,
-};
-
-use crate::{
-    contract::{
-        dao_contract,
-        money_contract::{state::State, CONTRACT_ID},
-    },
-    note::EncryptedNote2,
-    util::{CallDataBase, StateRegistry, Transaction, UpdateBase},
-};
-
-const TARGET: &str = "money_contract::transfer::validate::state_transition()";
-
-/// A struct representing a state update.
-/// This gets applied on top of an existing state.
-#[derive(Clone)]
-pub struct Update {
-    /// All nullifiers in a transaction
-    pub nullifiers: Vec<Nullifier>,
-    /// All coins in a transaction
-    pub coins: Vec<Coin>,
-    /// All encrypted notes in a transaction
-    pub enc_notes: Vec<EncryptedNote2>,
-}
-
-impl UpdateBase for Update {
-    fn apply(mut self: Box<Self>, states: &mut StateRegistry) {
-        let state = states.lookup_mut::<State>(*CONTRACT_ID).unwrap();
-
-        // Extend our list of nullifiers with the ones from the update
-        state.nullifiers.append(&mut self.nullifiers);
-
-        //// Update merkle tree and witnesses
-        for (coin, enc_note) in self.coins.into_iter().zip(self.enc_notes.into_iter()) {
-            // Add the new coins to the Merkle tree
-            let node = MerkleNode::from(coin.0);
-            state.tree.append(&node);
-
-            // Keep track of all Merkle roots that have existed
-            state.merkle_roots.push(state.tree.root(0).unwrap());
-
-            state.wallet_cache.try_decrypt_note(coin, enc_note, &mut state.tree);
-        }
-    }
-}
-
-pub fn state_transition(
-    states: &StateRegistry,
-    func_call_index: usize,
-    parent_tx: &Transaction,
-) -> Result<Box<dyn UpdateBase + Send>> {
-    // Check the public keys in the clear inputs to see if they're coming
-    // from a valid cashier or faucet.
-    debug!(target: TARGET, "Iterate clear_inputs");
-    let func_call = &parent_tx.func_calls[func_call_index];
-    let call_data = func_call.call_data.as_any();
-
-    assert_eq!((*call_data).type_id(), TypeId::of::<CallData>());
-    let call_data = call_data.downcast_ref::<CallData>();
-
-    // This will be inside wasm so unwrap is fine.
-    let call_data = call_data.unwrap();
-
-    let state = states.lookup::<State>(*CONTRACT_ID).expect("Return type is not of type State");
-
-    // Code goes here
-    for (i, input) in call_data.clear_inputs.iter().enumerate() {
-        let pk = &input.signature_public;
-        // TODO: this depends on the token ID
-        if !state.is_valid_cashier_public_key(pk) && !state.is_valid_faucet_public_key(pk) {
-            error!(target: TARGET, "Invalid pubkey for clear input: {:?}", pk);
-            return Err(Error::VerifyFailed(VerifyFailed::InvalidCashierOrFaucetKey(i)))
-        }
-    }
-
-    // Nullifiers in the transaction
-    let mut nullifiers = Vec::with_capacity(call_data.inputs.len());
-
-    debug!(target: TARGET, "Iterate inputs");
-    for (i, input) in call_data.inputs.iter().enumerate() {
-        let merkle = &input.revealed.merkle_root;
-
-        // The Merkle root is used to know whether this is a coin that
-        // existed in a previous state.
-        if !state.is_valid_merkle(merkle) {
-            error!(target: TARGET, "Invalid Merkle root (input {})", i);
-            debug!(target: TARGET, "root: {:?}", merkle);
-            return Err(Error::VerifyFailed(VerifyFailed::InvalidMerkle(i)))
-        }
-
-        // Check the spend_hook is satisfied
-        // The spend_hook says a coin must invoke another contract function when being spent
-        // If the value is set, then we check the function call exists
-        let spend_hook = &input.revealed.spend_hook;
-        if spend_hook != &pallas::Base::from(0) {
-            // spend_hook is set so we enforce the rules
-            let mut is_found = false;
-            for (i, func_call) in parent_tx.func_calls.iter().enumerate() {
-                // Skip current func_call
-                if i == func_call_index {
-                    continue
-                }
-
-                // TODO: we need to change these to pallas::Base
-                // temporary workaround for now
-                // if func_call.func_id == spend_hook ...
-                if func_call.func_id == *dao_contract::exec::FUNC_ID {
-                    is_found = true;
-                    break
-                }
-            }
-            if !is_found {
-                return Err(Error::VerifyFailed(VerifyFailed::SpendHookNotSatisfied))
-            }
-        }
-
-        // The nullifiers should not already exist.
-        // It is the double-spend protection.
-        let nullifier = &input.revealed.nullifier;
-        if state.nullifier_exists(nullifier) ||
-            (1..nullifiers.len()).any(|i| nullifiers[i..].contains(&nullifiers[i - 1]))
-        {
-            error!(target: TARGET, "Duplicate nullifier found (input {})", i);
-            debug!(target: TARGET, "nullifier: {:?}", nullifier);
-            return Err(Error::VerifyFailed(VerifyFailed::NullifierExists(i)))
-        }
-
-        nullifiers.push(input.revealed.nullifier);
-    }
-
-    debug!(target: TARGET, "Verifying call data");
-    match call_data.verify() {
-        Ok(()) => {
-            debug!(target: TARGET, "Verified successfully")
-        }
-        Err(e) => {
-            error!(target: TARGET, "Failed verifying zk proofs: {}", e);
-            return Err(Error::VerifyFailed(VerifyFailed::ProofVerifyFailed(e.to_string())))
-        }
-    }
-
-    // Newly created coins for this transaction
-    let mut coins = Vec::with_capacity(call_data.outputs.len());
-    let mut enc_notes = Vec::with_capacity(call_data.outputs.len());
-
-    for output in &call_data.outputs {
-        // Gather all the coins
-        coins.push(output.revealed.coin);
-        enc_notes.push(output.enc_note.clone());
-    }
-
-    Ok(Box::new(Update { nullifiers, coins, enc_notes }))
-}
-
-/// A DarkFi transaction
-#[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
-pub struct CallData {
-    /// Clear inputs
-    pub clear_inputs: Vec<ClearInput>,
-    /// Anonymous inputs
-    pub inputs: Vec<Input>,
-    /// Anonymous outputs
-    pub outputs: Vec<Output>,
-}
-
-impl CallDataBase for CallData {
-    fn zk_public_values(&self) -> Vec<(String, Vec<DrkCircuitField>)> {
-        let mut public_values = Vec::new();
-        for input in &self.inputs {
-            public_values.push(("money-transfer-burn".to_string(), input.revealed.make_outputs()));
-        }
-        for output in &self.outputs {
-            public_values.push(("money-transfer-mint".to_string(), output.revealed.make_outputs()));
-        }
-        public_values
-    }
-
-    fn as_any(&self) -> &dyn Any {
-        self
-    }
-
-    fn signature_public_keys(&self) -> Vec<PublicKey> {
-        let mut signature_public_keys = Vec::new();
-        for input in self.clear_inputs.clone() {
-            signature_public_keys.push(input.signature_public);
-        }
-        signature_public_keys
-    }
-
-    fn encode_bytes(
-        &self,
-        mut writer: &mut dyn std::io::Write,
-    ) -> core::result::Result<usize, std::io::Error> {
-        self.encode(&mut writer)
-    }
-}
-impl CallData {
-    /// Verify the transaction
-    pub fn verify(&self) -> VerifyResult<()> {
-        //  must have minimum 1 clear or anon input, and 1 output
-        if self.clear_inputs.len() + self.inputs.len() == 0 {
-            error!("tx::verify(): Missing inputs");
-            return Err(VerifyFailed::LackingInputs)
-        }
-        if self.outputs.is_empty() {
-            error!("tx::verify(): Missing outputs");
-            return Err(VerifyFailed::LackingOutputs)
-        }
-
-        // Accumulator for the value commitments
-        let mut valcom_total = DrkValueCommit::identity();
-
-        // Add values from the clear inputs
-        for input in &self.clear_inputs {
-            valcom_total += pedersen_commitment_u64(input.value, input.value_blind);
-        }
-        // Add values from the inputs
-        for input in &self.inputs {
-            valcom_total += &input.revealed.value_commit;
-        }
-        // Subtract values from the outputs
-        for output in &self.outputs {
-            valcom_total -= &output.revealed.value_commit;
-        }
-
-        // If the accumulator is not back in its initial state,
-        // there's a value mismatch.
-        if valcom_total != DrkValueCommit::identity() {
-            error!("tx::verify(): Missing funds");
-            return Err(VerifyFailed::MissingFunds)
-        }
-
-        // Verify that the token commitments match
-        if !self.verify_token_commitments() {
-            error!("tx::verify(): Token ID mismatch");
-            return Err(VerifyFailed::TokenMismatch)
-        }
-
-        Ok(())
-    }
-
-    fn verify_token_commitments(&self) -> bool {
-        assert_ne!(self.outputs.len(), 0);
-        let token_commit_value = self.outputs[0].revealed.token_commit;
-
-        let mut failed =
-            self.inputs.iter().any(|input| input.revealed.token_commit != token_commit_value);
-
-        failed = failed ||
-            self.outputs.iter().any(|output| output.revealed.token_commit != token_commit_value);
-
-        failed = failed ||
-            self.clear_inputs.iter().any(|input| {
-                pedersen_commitment_base(input.token_id, input.token_blind) != token_commit_value
-            });
-        !failed
-    }
-}
-
-/// A transaction's clear input
-#[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
-pub struct ClearInput {
-    /// Input's value (amount)
-    pub value: u64,
-    /// Input's token ID
-    pub token_id: DrkTokenId,
-    /// Blinding factor for `value`
-    pub value_blind: DrkValueBlind,
-    /// Blinding factor for `token_id`
-    pub token_blind: DrkValueBlind,
-    /// Public key for the signature
-    pub signature_public: PublicKey,
-}
-
-/// A transaction's anonymous input
-#[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
-pub struct Input {
-    /// Public inputs for the zero-knowledge proof
-    pub revealed: BurnRevealedValues,
-}
-
-/// A transaction's anonymous output
-#[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
-pub struct Output {
-    /// Public inputs for the zero-knowledge proof
-    pub revealed: MintRevealedValues,
-    /// The encrypted note
-    pub enc_note: EncryptedNote2,
-}
-
-#[derive(Debug, Clone, thiserror::Error)]
-pub enum Error {
-    #[error(transparent)]
-    VerifyFailed(#[from] VerifyFailed),
-
-    #[error("DarkFi error: {0}")]
-    DarkFiError(String),
-}
-
-/// Transaction verification errors
-#[derive(Debug, Clone, thiserror::Error)]
-pub enum VerifyFailed {
-    #[error("Transaction has no inputs")]
-    LackingInputs,
-
-    #[error("Transaction has no outputs")]
-    LackingOutputs,
-
-    #[error("Invalid cashier/faucet public key for clear input {0}")]
-    InvalidCashierOrFaucetKey(usize),
-
-    #[error("Invalid Merkle root for input {0}")]
-    InvalidMerkle(usize),
-
-    #[error("Spend hook invoking function is not attached")]
-    SpendHookNotSatisfied,
-
-    #[error("Nullifier already exists for input {0}")]
-    NullifierExists(usize),
-
-    #[error("Token commitments in inputs or outputs to not match")]
-    TokenMismatch,
-
-    #[error("Money in does not match money out (value commitments)")]
-    MissingFunds,
-
-    #[error("Failed verifying zk proofs: {0}")]
-    ProofVerifyFailed(String),
-
-    #[error("Internal error: {0}")]
-    InternalError(String),
-
-    #[error("DarkFi error: {0}")]
-    DarkFiError(String),
-}
-
-type Result<T> = std::result::Result<T, Error>;
-
-impl From<Error> for VerifyFailed {
-    fn from(err: Error) -> Self {
-        Self::InternalError(err.to_string())
-    }
-}
-
-impl From<DarkFiError> for VerifyFailed {
-    fn from(err: DarkFiError) -> Self {
-        Self::DarkFiError(err.to_string())
-    }
-}
-
-impl From<DarkFiError> for Error {
-    fn from(err: DarkFiError) -> Self {
-        Self::DarkFiError(err.to_string())
-    }
-}
-/// Result type used in transaction verifications
-pub type VerifyResult<T> = std::result::Result<T, VerifyFailed>;

+ 0 - 219
example/dao/contract/money_contract/transfer/wallet.rs

@@ -1,219 +0,0 @@
-use darkfi_sdk::crypto::MerkleNode;
-use darkfi_serial::{SerialDecodable, SerialEncodable};
-use pasta_curves::group::ff::Field;
-use rand::rngs::OsRng;
-
-use darkfi::{
-    crypto::{
-        burn_proof::create_burn_proof,
-        keypair::{PublicKey, SecretKey},
-        mint_proof::create_mint_proof,
-        types::{
-            DrkCoinBlind, DrkSerial, DrkSpendHook, DrkTokenId, DrkUserData, DrkUserDataBlind,
-            DrkValueBlind,
-        },
-    },
-    Result,
-};
-
-use crate::{
-    contract::money_contract::{
-        transfer::validate::{CallData, ClearInput, Input, Output},
-        CONTRACT_ID,
-    },
-    note,
-    util::{FuncCall, ZkContractInfo, ZkContractTable},
-};
-
-#[derive(Clone, SerialEncodable, SerialDecodable)]
-pub struct Note {
-    pub serial: DrkSerial,
-    pub value: u64,
-    pub token_id: DrkTokenId,
-    pub spend_hook: DrkSpendHook,
-    pub user_data: DrkUserData,
-    pub coin_blind: DrkCoinBlind,
-    pub value_blind: DrkValueBlind,
-    pub token_blind: DrkValueBlind,
-}
-
-pub struct Builder {
-    pub clear_inputs: Vec<BuilderClearInputInfo>,
-    pub inputs: Vec<BuilderInputInfo>,
-    pub outputs: Vec<BuilderOutputInfo>,
-}
-
-pub struct BuilderClearInputInfo {
-    pub value: u64,
-    pub token_id: DrkTokenId,
-    pub signature_secret: SecretKey,
-}
-
-pub struct BuilderInputInfo {
-    pub leaf_position: incrementalmerkletree::Position,
-    pub merkle_path: Vec<MerkleNode>,
-    pub secret: SecretKey,
-    pub note: Note,
-    pub user_data_blind: DrkUserDataBlind,
-    pub value_blind: DrkValueBlind,
-    pub signature_secret: SecretKey,
-}
-
-pub struct BuilderOutputInfo {
-    pub value: u64,
-    pub token_id: DrkTokenId,
-    pub public: PublicKey,
-    pub serial: DrkSerial,
-    pub coin_blind: DrkCoinBlind,
-    pub spend_hook: DrkSpendHook,
-    pub user_data: DrkUserData,
-}
-
-impl Builder {
-    fn compute_remainder_blind(
-        clear_inputs: &[ClearInput],
-        input_blinds: &[DrkValueBlind],
-        output_blinds: &[DrkValueBlind],
-    ) -> DrkValueBlind {
-        let mut total = DrkValueBlind::zero();
-
-        for input in clear_inputs {
-            total += input.value_blind;
-        }
-
-        for input_blind in input_blinds {
-            total += input_blind;
-        }
-
-        for output_blind in output_blinds {
-            total -= output_blind;
-        }
-
-        total
-    }
-
-    pub fn build(self, zk_bins: &ZkContractTable) -> Result<FuncCall> {
-        assert!(self.clear_inputs.len() + self.inputs.len() > 0);
-
-        let mut clear_inputs = vec![];
-        let token_blind = DrkValueBlind::random(&mut OsRng);
-        for input in &self.clear_inputs {
-            let signature_public = PublicKey::from_secret(input.signature_secret);
-            let value_blind = DrkValueBlind::random(&mut OsRng);
-
-            let clear_input = ClearInput {
-                value: input.value,
-                token_id: input.token_id,
-                value_blind,
-                token_blind,
-                signature_public,
-            };
-            clear_inputs.push(clear_input);
-        }
-
-        let mut proofs = vec![];
-        let mut inputs = vec![];
-        let mut input_blinds = vec![];
-
-        for input in self.inputs {
-            let value_blind = input.value_blind;
-            input_blinds.push(value_blind);
-
-            let zk_info = zk_bins.lookup(&"money-transfer-burn".to_string()).unwrap();
-            let zk_info = if let ZkContractInfo::Native(info) = zk_info {
-                info
-            } else {
-                panic!("Not native info")
-            };
-            let burn_pk = &zk_info.proving_key;
-
-            // Note from the previous output
-            let note = input.note.clone();
-
-            let (burn_proof, revealed) = create_burn_proof(
-                burn_pk,
-                note.value,
-                note.token_id,
-                value_blind,
-                token_blind,
-                note.serial,
-                note.spend_hook,
-                note.user_data,
-                input.user_data_blind,
-                note.coin_blind,
-                input.secret,
-                input.leaf_position,
-                input.merkle_path.clone(),
-                input.signature_secret,
-            )?;
-            proofs.push(burn_proof);
-
-            let input = Input { revealed };
-            inputs.push(input);
-        }
-
-        let mut outputs = vec![];
-        let mut output_blinds = vec![];
-        // This value_blind calc assumes there will always be at least a single output
-        assert!(!self.outputs.is_empty());
-
-        for (i, output) in self.outputs.iter().enumerate() {
-            let value_blind = if i == self.outputs.len() - 1 {
-                Self::compute_remainder_blind(&clear_inputs, &input_blinds, &output_blinds)
-            } else {
-                DrkValueBlind::random(&mut OsRng)
-            };
-            output_blinds.push(value_blind);
-
-            let serial = output.serial;
-            let coin_blind = output.coin_blind;
-
-            let zk_info = zk_bins.lookup(&"money-transfer-mint".to_string()).unwrap();
-            let zk_info = if let ZkContractInfo::Native(info) = zk_info {
-                info
-            } else {
-                panic!("Not native info")
-            };
-            let mint_pk = &zk_info.proving_key;
-
-            let (mint_proof, revealed) = create_mint_proof(
-                mint_pk,
-                output.value,
-                output.token_id,
-                value_blind,
-                token_blind,
-                serial,
-                output.spend_hook,
-                output.user_data,
-                coin_blind,
-                output.public,
-            )?;
-            proofs.push(mint_proof);
-
-            let note = Note {
-                serial,
-                value: output.value,
-                token_id: output.token_id,
-                spend_hook: output.spend_hook,
-                user_data: output.user_data,
-                coin_blind,
-                value_blind,
-                token_blind,
-            };
-
-            let encrypted_note = note::encrypt(&note, &output.public)?;
-
-            let output = Output { revealed, enc_note: encrypted_note };
-            outputs.push(output);
-        }
-
-        let call_data = CallData { clear_inputs, inputs, outputs };
-
-        Ok(FuncCall {
-            contract_id: *CONTRACT_ID,
-            func_id: *super::FUNC_ID,
-            call_data: Box::new(call_data),
-            proofs,
-        })
-    }
-}

+ 0 - 1328
example/dao/dao.rs

@@ -1,1328 +0,0 @@
-use std::{
-    any::{Any, TypeId},
-    time::Instant,
-};
-
-use incrementalmerkletree::Tree;
-use log::debug;
-use pasta_curves::{
-    arithmetic::CurveAffine,
-    group::{ff::Field, Curve, Group},
-    pallas,
-};
-use rand::rngs::OsRng;
-
-use darkfi::{
-    crypto::{
-        keypair::{Keypair, PublicKey, SecretKey},
-        proof::{ProvingKey, VerifyingKey},
-        types::{DrkSpendHook, DrkUserData, DrkValue},
-        util::{pedersen_commitment_u64, poseidon_hash},
-    },
-    zk::circuit::{BurnContract, MintContract},
-    zkas::decoder::ZkBinary,
-};
-
-mod contract;
-mod note;
-mod util;
-
-use crate::{
-    contract::{dao_contract, example_contract, money_contract},
-    util::{sign, StateRegistry, Transaction, ZkContractTable},
-};
-
-// TODO: Anonymity leaks in this proof of concept:
-//
-// * Vote updates are linked to the proposal_bulla
-// * Nullifier of vote will link vote with the coin when it's spent
-
-// TODO: strategize and cleanup Result/Error usage
-// TODO: fix up code doc
-
-type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
-
-// #[derive(Eq, PartialEq)]
-// pub struct HashableBase(pub pallas::Base);
-
-// impl std::hash::Hash for HashableBase {
-//     fn hash<H: Hasher>(&self, state: &mut H) {
-//         let bytes = self.0.to_repr();
-//         bytes.hash(state);
-//     }
-// }
-
-// pub struct ZkBinaryContractInfo {
-//     pub k_param: u32,
-//     pub bincode: ZkBinary,
-//     pub proving_key: ProvingKey,
-//     pub verifying_key: VerifyingKey,
-// }
-// pub struct ZkNativeContractInfo {
-//     pub proving_key: ProvingKey,
-//     pub verifying_key: VerifyingKey,
-// }
-
-// pub enum ZkContractInfo {
-//     Binary(ZkBinaryContractInfo),
-//     Native(ZkNativeContractInfo),
-// }
-
-// pub struct ZkContractTable {
-//     // Key will be a hash of zk binary contract on chain
-//     table: HashMap<String, ZkContractInfo>,
-// }
-
-// impl ZkContractTable {
-//     fn new() -> Self {
-//         Self { table: HashMap::new() }
-//     }
-
-//     fn add_contract(&mut self, key: String, bincode: ZkBinary, k_param: u32) {
-//         let witnesses = empty_witnesses(&bincode);
-//         let circuit = ZkCircuit::new(witnesses, bincode.clone());
-//         let proving_key = ProvingKey::build(k_param, &circuit);
-//         let verifying_key = VerifyingKey::build(k_param, &circuit);
-//         let info = ZkContractInfo::Binary(ZkBinaryContractInfo {
-//             k_param,
-//             bincode,
-//             proving_key,
-//             verifying_key,
-//         });
-//         self.table.insert(key, info);
-//     }
-
-//     fn add_native(&mut self, key: String, proving_key: ProvingKey, verifying_key: VerifyingKey) {
-//         self.table.insert(
-//             key,
-//             ZkContractInfo::Native(ZkNativeContractInfo { proving_key, verifying_key }),
-//         );
-//     }
-
-//     pub fn lookup(&self, key: &String) -> Option<&ZkContractInfo> {
-//         self.table.get(key)
-//     }
-// }
-
-// pub struct Transaction {
-//     pub func_calls: Vec<FuncCall>,
-//     pub signatures: Vec<Signature>,
-// }
-
-// impl Transaction {
-//     /// Verify ZK contracts for the entire tx
-//     /// In real code, we could parallelize this for loop
-//     /// TODO: fix use of unwrap with Result type stuff
-//     fn zk_verify(&self, zk_bins: &ZkContractTable) {
-//         for func_call in &self.func_calls {
-//             let proofs_public_vals = &func_call.call_data.zk_public_values();
-
-//             assert_eq!(
-//                 proofs_public_vals.len(),
-//                 func_call.proofs.len(),
-//                 "proof_public_vals.len()={} and func_call.proofs.len()={} do not match",
-//                 proofs_public_vals.len(),
-//                 func_call.proofs.len()
-//             );
-//             for (i, (proof, (key, public_vals))) in
-//                 func_call.proofs.iter().zip(proofs_public_vals.iter()).enumerate()
-//             {
-//                 match zk_bins.lookup(key).unwrap() {
-//                     ZkContractInfo::Binary(info) => {
-//                         let verifying_key = &info.verifying_key;
-//                         let verify_result = proof.verify(&verifying_key, public_vals);
-//                         assert!(verify_result.is_ok(), "verify proof[{}]='{}' failed", i, key);
-//                     }
-//                     ZkContractInfo::Native(info) => {
-//                         let verifying_key = &info.verifying_key;
-//                         let verify_result = proof.verify(&verifying_key, public_vals);
-//                         assert!(verify_result.is_ok(), "verify proof[{}]='{}' failed", i, key);
-//                     }
-//                 };
-//                 debug!(target: "demo", "zk_verify({}) passed [i={}]", key, i);
-//             }
-//         }
-//     }
-
-//     fn verify_sigs(&self) {
-//         let mut unsigned_tx_data = vec![];
-//         for (i, (func_call, signature)) in
-//             self.func_calls.iter().zip(self.signatures.clone()).enumerate()
-//         {
-//             func_call.encode(&mut unsigned_tx_data).expect("failed to encode data");
-//             let signature_pub_keys = func_call.call_data.signature_public_keys();
-//             for signature_pub_key in signature_pub_keys {
-//                 let verify_result = signature_pub_key.verify(&unsigned_tx_data[..], &signature);
-//                 assert!(verify_result, "verify sigs[{}] failed", i);
-//             }
-//             debug!(target: "demo", "verify_sigs({}) passed", i);
-//         }
-//     }
-// }
-
-// fn sign(signature_secrets: Vec<SecretKey>, func_calls: &Vec<FuncCall>) -> Vec<Signature> {
-//     let mut signatures = vec![];
-//     let mut unsigned_tx_data = vec![];
-//     for (_i, (signature_secret, func_call)) in
-//         signature_secrets.iter().zip(func_calls.iter()).enumerate()
-//     {
-//         func_call.encode(&mut unsigned_tx_data).expect("failed to encode data");
-//         let signature = signature_secret.sign(&unsigned_tx_data[..]);
-//         signatures.push(signature);
-//     }
-//     signatures
-// }
-
-// type ContractId = pallas::Base;
-// type FuncId = pallas::Base;
-
-// pub struct FuncCall {
-//     pub contract_id: ContractId,
-//     pub func_id: FuncId,
-//     pub call_data: Box<dyn CallDataBase>,
-//     pub proofs: Vec<Proof>,
-// }
-
-// impl Encodable for FuncCall {
-//     fn encode<W: std::io::Write>(&self, mut w: W) -> std::result::Result<usize, darkfi::Error> {
-//         let mut len = 0;
-//         len += self.contract_id.encode(&mut w)?;
-//         len += self.func_id.encode(&mut w)?;
-//         len += self.proofs.encode(&mut w)?;
-//         len += self.call_data.encode_bytes(&mut w)?;
-//         Ok(len)
-//     }
-// }
-
-// pub trait CallDataBase {
-//     // Public values for verifying the proofs
-//     // Needed so we can convert internal types so they can be used in Proof::verify()
-//     fn zk_public_values(&self) -> Vec<(String, Vec<DrkCircuitField>)>;
-
-//     // For upcasting to CallData itself so it can be read in state_transition()
-//     fn as_any(&self) -> &dyn Any;
-
-//     // Public keys we will use to verify transaction signatures.
-//     fn signature_public_keys(&self) -> Vec<PublicKey>;
-
-//     fn encode_bytes(
-//         &self,
-//         writer: &mut dyn std::io::Write,
-//     ) -> std::result::Result<usize, darkfi::Error>;
-// }
-
-// type GenericContractState = Box<dyn Any>;
-
-// pub struct StateRegistry {
-//     pub states: HashMap<HashableBase, GenericContractState>,
-// }
-
-// impl StateRegistry {
-//     fn new() -> Self {
-//         Self { states: HashMap::new() }
-//     }
-
-//     fn register(&mut self, contract_id: ContractId, state: GenericContractState) {
-//         debug!(target: "StateRegistry::register()", "contract_id: {:?}", contract_id);
-//         self.states.insert(HashableBase(contract_id), state);
-//     }
-
-//     pub fn lookup_mut<'a, S: 'static>(&'a mut self, contract_id: ContractId) -> Option<&'a mut S> {
-//         self.states.get_mut(&HashableBase(contract_id)).and_then(|state| state.downcast_mut())
-//     }
-
-//     pub fn lookup<'a, S: 'static>(&'a self, contract_id: ContractId) -> Option<&'a S> {
-//         self.states.get(&HashableBase(contract_id)).and_then(|state| state.downcast_ref())
-//     }
-// }
-
-// pub trait UpdateBase {
-//     fn apply(self: Box<Self>, states: &mut StateRegistry);
-// }
-
-///////////////////////////////////////////////////
-///// Example contract
-///////////////////////////////////////////////////
-pub async fn example() -> Result<()> {
-    debug!(target: "demo", "Stage 0. Example contract");
-    // Lookup table for smart contract states
-    let mut states = StateRegistry::new();
-
-    // Initialize ZK binary table
-    let mut zk_bins = ZkContractTable::new();
-
-    let zk_example_foo_bincode = include_bytes!("proof/foo.zk.bin");
-    let zk_example_foo_bin = ZkBinary::decode(zk_example_foo_bincode)?;
-    zk_bins.add_contract("example-foo".to_string(), zk_example_foo_bin, 13);
-
-    let example_state = example_contract::state::State::new();
-    states.register(*example_contract::CONTRACT_ID, example_state);
-
-    //// Wallet
-
-    let foo = example_contract::foo::wallet::Foo { a: 5, b: 10 };
-    let signature_secret = SecretKey::random(&mut OsRng);
-
-    let builder = example_contract::foo::wallet::Builder { foo, signature_secret };
-    let func_call = builder.build(&zk_bins);
-    let func_calls = vec![func_call];
-
-    let signatures = sign(vec![signature_secret], &func_calls);
-    let tx = Transaction { func_calls, signatures };
-
-    //// Validator
-
-    let mut updates = vec![];
-    // Validate all function calls in the tx
-    for (idx, func_call) in tx.func_calls.iter().enumerate() {
-        if func_call.func_id == *example_contract::foo::FUNC_ID {
-            debug!("example_contract::foo::state_transition()");
-
-            let update = example_contract::foo::validate::state_transition(&states, idx, &tx)
-                .expect("example_contract::foo::validate::state_transition() failed!");
-            updates.push(update);
-        }
-    }
-
-    // Atomically apply all changes
-    for update in updates {
-        update.apply(&mut states);
-    }
-
-    tx.zk_verify(&zk_bins);
-    tx.verify_sigs();
-
-    Ok(())
-}
-
-#[async_std::main]
-async fn main() -> Result<()> {
-    // Example smart contract
-    //// TODO: this will be moved to a different file
-    example().await?;
-
-    // Money parameters
-    let xdrk_supply = 1_000_000;
-    let xdrk_token_id = pallas::Base::random(&mut OsRng);
-
-    // Governance token parameters
-    let gdrk_supply = 1_000_000;
-    let gdrk_token_id = 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;
-
-    // Lookup table for smart contract states
-    let mut states = StateRegistry::new();
-
-    // Initialize ZK binary table
-    let mut zk_bins = ZkContractTable::new();
-
-    debug!(target: "demo", "Loading dao-mint.zk");
-    let zk_dao_mint_bincode = include_bytes!("proof/dao-mint.zk.bin");
-    let zk_dao_mint_bin = ZkBinary::decode(zk_dao_mint_bincode)?;
-    zk_bins.add_contract("dao-mint".to_string(), zk_dao_mint_bin, 13);
-
-    debug!(target: "demo", "Loading money-transfer contracts");
-    {
-        let start = Instant::now();
-        let mint_pk = ProvingKey::build(11, &MintContract::default());
-        debug!("Mint PK: [{:?}]", start.elapsed());
-        let start = Instant::now();
-        let burn_pk = ProvingKey::build(11, &BurnContract::default());
-        debug!("Burn PK: [{:?}]", start.elapsed());
-        let start = Instant::now();
-        let mint_vk = VerifyingKey::build(11, &MintContract::default());
-        debug!("Mint VK: [{:?}]", start.elapsed());
-        let start = Instant::now();
-        let burn_vk = VerifyingKey::build(11, &BurnContract::default());
-        debug!("Burn VK: [{:?}]", start.elapsed());
-
-        zk_bins.add_native("money-transfer-mint".to_string(), mint_pk, mint_vk);
-        zk_bins.add_native("money-transfer-burn".to_string(), burn_pk, burn_vk);
-    }
-    debug!(target: "demo", "Loading dao-propose-main.zk");
-    let zk_dao_propose_main_bincode = include_bytes!("proof/dao-propose-main.zk.bin");
-    let zk_dao_propose_main_bin = ZkBinary::decode(zk_dao_propose_main_bincode)?;
-    zk_bins.add_contract("dao-propose-main".to_string(), zk_dao_propose_main_bin, 13);
-    debug!(target: "demo", "Loading dao-propose-burn.zk");
-    let zk_dao_propose_burn_bincode = include_bytes!("proof/dao-propose-burn.zk.bin");
-    let zk_dao_propose_burn_bin = ZkBinary::decode(zk_dao_propose_burn_bincode)?;
-    zk_bins.add_contract("dao-propose-burn".to_string(), zk_dao_propose_burn_bin, 13);
-    debug!(target: "demo", "Loading dao-vote-main.zk");
-    let zk_dao_vote_main_bincode = include_bytes!("proof/dao-vote-main.zk.bin");
-    let zk_dao_vote_main_bin = ZkBinary::decode(zk_dao_vote_main_bincode)?;
-    zk_bins.add_contract("dao-vote-main".to_string(), zk_dao_vote_main_bin, 13);
-    debug!(target: "demo", "Loading dao-vote-burn.zk");
-    let zk_dao_vote_burn_bincode = include_bytes!("proof/dao-vote-burn.zk.bin");
-    let zk_dao_vote_burn_bin = ZkBinary::decode(zk_dao_vote_burn_bincode)?;
-    zk_bins.add_contract("dao-vote-burn".to_string(), zk_dao_vote_burn_bin, 13);
-    let zk_dao_exec_bincode = include_bytes!("proof/dao-exec.zk.bin");
-    let zk_dao_exec_bin = ZkBinary::decode(zk_dao_exec_bincode)?;
-    zk_bins.add_contract("dao-exec".to_string(), zk_dao_exec_bin, 13);
-
-    // State for money contracts
-    let cashier_signature_secret = SecretKey::random(&mut OsRng);
-    let cashier_signature_public = PublicKey::from_secret(cashier_signature_secret);
-    let faucet_signature_secret = SecretKey::random(&mut OsRng);
-    let faucet_signature_public = PublicKey::from_secret(faucet_signature_secret);
-
-    ///////////////////////////////////////////////////
-
-    let money_state =
-        money_contract::state::State::new(cashier_signature_public, faucet_signature_public);
-    states.register(*money_contract::CONTRACT_ID, money_state);
-
-    /////////////////////////////////////////////////////
-
-    let dao_state = dao_contract::State::new();
-    states.register(*dao_contract::CONTRACT_ID, dao_state);
-
-    /////////////////////////////////////////////////////
-    ////// Create the DAO bulla
-    /////////////////////////////////////////////////////
-    debug!(target: "demo", "Stage 1. Creating DAO bulla");
-
-    //// Wallet
-
-    //// Setup the DAO
-    let dao_keypair = Keypair::random(&mut OsRng);
-    let dao_bulla_blind = pallas::Base::random(&mut OsRng);
-
-    let signature_secret = SecretKey::random(&mut OsRng);
-    // Create DAO mint tx
-    let builder = dao_contract::mint::wallet::Builder {
-        dao_proposer_limit,
-        dao_quorum,
-        dao_approval_ratio_quot,
-        dao_approval_ratio_base,
-        gov_token_id: gdrk_token_id,
-        dao_pubkey: dao_keypair.public,
-        dao_bulla_blind,
-        _signature_secret: signature_secret,
-    };
-    let func_call = builder.build(&zk_bins);
-    let func_calls = vec![func_call];
-
-    let signatures = sign(vec![signature_secret], &func_calls);
-    let tx = Transaction { func_calls, signatures };
-
-    //// Validator
-
-    let mut updates = vec![];
-    // Validate all function calls in the tx
-    for (idx, func_call) in tx.func_calls.iter().enumerate() {
-        // So then the verifier will lookup the corresponding state_transition and apply
-        // functions based off the func_id
-        if func_call.func_id == *dao_contract::mint::FUNC_ID {
-            debug!("dao_contract::mint::state_transition()");
-
-            let update = dao_contract::mint::validate::state_transition(&states, idx, &tx)
-                .expect("dao_contract::mint::validate::state_transition() failed!");
-            updates.push(update);
-        }
-    }
-
-    // Atomically apply all changes
-    for update in updates {
-        update.apply(&mut states);
-    }
-
-    tx.zk_verify(&zk_bins);
-    tx.verify_sigs();
-
-    // Wallet stuff
-
-    // In your wallet, wait until you see the tx confirmed before doing anything below
-    // So for example keep track of tx hash
-    //assert_eq!(tx.hash(), tx_hash);
-
-    // We need to witness() the value in our local merkle tree
-    // Must be called as soon as this DAO bulla is added to the state
-    let dao_leaf_position = {
-        let state = states.lookup_mut::<dao_contract::State>(*dao_contract::CONTRACT_ID).unwrap();
-        state.dao_tree.witness().unwrap()
-    };
-
-    // It might just be easier to hash it ourselves from keypair and blind...
-    let dao_bulla = {
-        assert_eq!(tx.func_calls.len(), 1);
-        let func_call = &tx.func_calls[0];
-        let call_data = func_call.call_data.as_any();
-        assert_eq!((&*call_data).type_id(), TypeId::of::<dao_contract::mint::validate::CallData>());
-        let call_data = call_data.downcast_ref::<dao_contract::mint::validate::CallData>().unwrap();
-        call_data.dao_bulla.clone()
-    };
-    debug!(target: "demo", "Create DAO bulla: {:?}", dao_bulla.0);
-
-    ///////////////////////////////////////////////////
-    //// Mint the initial supply of treasury token
-    //// and send it all to the DAO directly
-    ///////////////////////////////////////////////////
-    debug!(target: "demo", "Stage 2. Minting treasury token");
-
-    let state = states.lookup_mut::<money_contract::State>(*money_contract::CONTRACT_ID).unwrap();
-    state.wallet_cache.track(dao_keypair.secret);
-
-    //// Wallet
-
-    // Address of deployed contract in our example is dao_contract::exec::FUNC_ID
-    // This field is public, you can see it's being sent to a DAO
-    // but nothing else is visible.
-    //
-    // In the python code we wrote:
-    //
-    //   spend_hook = b"0xdao_ruleset"
-    //
-    let spend_hook = *dao_contract::exec::FUNC_ID;
-    // The user_data can be a simple hash of the items passed into the ZK proof
-    // up to corresponding linked ZK proof to interpret however they need.
-    // In out case, it's the bulla for the DAO
-    let user_data = dao_bulla.0;
-
-    let builder = money_contract::transfer::wallet::Builder {
-        clear_inputs: vec![money_contract::transfer::wallet::BuilderClearInputInfo {
-            value: xdrk_supply,
-            token_id: xdrk_token_id,
-            signature_secret: cashier_signature_secret,
-        }],
-        inputs: vec![],
-        outputs: vec![money_contract::transfer::wallet::BuilderOutputInfo {
-            value: xdrk_supply,
-            token_id: xdrk_token_id,
-            public: dao_keypair.public,
-            serial: pallas::Base::random(&mut OsRng),
-            coin_blind: pallas::Base::random(&mut OsRng),
-            spend_hook,
-            user_data,
-        }],
-    };
-
-    let func_call = builder.build(&zk_bins)?;
-    let func_calls = vec![func_call];
-
-    let signatures = sign(vec![cashier_signature_secret], &func_calls);
-    let tx = Transaction { func_calls, signatures };
-
-    //// Validator
-
-    let mut updates = vec![];
-    // Validate all function calls in the tx
-    for (idx, func_call) in tx.func_calls.iter().enumerate() {
-        // So then the verifier will lookup the corresponding state_transition and apply
-        // functions based off the func_id
-        if func_call.func_id == *money_contract::transfer::FUNC_ID {
-            debug!("money_contract::transfer::state_transition()");
-
-            let update = money_contract::transfer::validate::state_transition(&states, idx, &tx)
-                .expect("money_contract::transfer::validate::state_transition() failed!");
-            updates.push(update);
-        }
-    }
-
-    // Atomically apply all changes
-    for update in updates {
-        update.apply(&mut states);
-    }
-
-    tx.zk_verify(&zk_bins);
-    tx.verify_sigs();
-
-    //// Wallet
-    // DAO reads the money received from the encrypted note
-
-    let state = states.lookup_mut::<money_contract::State>(*money_contract::CONTRACT_ID).unwrap();
-    let mut recv_coins = state.wallet_cache.get_received(&dao_keypair.secret);
-    assert_eq!(recv_coins.len(), 1);
-    let dao_recv_coin = recv_coins.pop().unwrap();
-    let treasury_note = dao_recv_coin.note;
-
-    // Check the actual coin received is valid before accepting it
-
-    let coords = dao_keypair.public.0.to_affine().coordinates().unwrap();
-    let coin = poseidon_hash::<8>([
-        *coords.x(),
-        *coords.y(),
-        DrkValue::from(treasury_note.value),
-        treasury_note.token_id,
-        treasury_note.serial,
-        treasury_note.spend_hook,
-        treasury_note.user_data,
-        treasury_note.coin_blind,
-    ]);
-    assert_eq!(coin, dao_recv_coin.coin.0);
-
-    assert_eq!(treasury_note.spend_hook, *dao_contract::exec::FUNC_ID);
-    assert_eq!(treasury_note.user_data, dao_bulla.0);
-
-    debug!("DAO received a coin worth {} xDRK", treasury_note.value);
-
-    ///////////////////////////////////////////////////
-    //// Mint the governance token
-    //// Send it to three hodlers
-    ///////////////////////////////////////////////////
-    debug!(target: "demo", "Stage 3. Minting governance token");
-
-    //// Wallet
-
-    // Hodler 1
-    let gov_keypair_1 = Keypair::random(&mut OsRng);
-    // Hodler 2
-    let gov_keypair_2 = Keypair::random(&mut OsRng);
-    // Hodler 3: the tiebreaker
-    let gov_keypair_3 = Keypair::random(&mut OsRng);
-
-    let state = states.lookup_mut::<money_contract::State>(*money_contract::CONTRACT_ID).unwrap();
-    state.wallet_cache.track(gov_keypair_1.secret);
-    state.wallet_cache.track(gov_keypair_2.secret);
-    state.wallet_cache.track(gov_keypair_3.secret);
-
-    let gov_keypairs = vec![gov_keypair_1, gov_keypair_2, gov_keypair_3];
-
-    // Spend hook and user data disabled
-    let spend_hook = DrkSpendHook::from(0);
-    let user_data = DrkUserData::from(0);
-
-    let output1 = money_contract::transfer::wallet::BuilderOutputInfo {
-        value: 400000,
-        token_id: gdrk_token_id,
-        public: gov_keypair_1.public,
-        serial: pallas::Base::random(&mut OsRng),
-        coin_blind: pallas::Base::random(&mut OsRng),
-        spend_hook,
-        user_data,
-    };
-
-    let output2 = money_contract::transfer::wallet::BuilderOutputInfo {
-        value: 400000,
-        token_id: gdrk_token_id,
-        public: gov_keypair_2.public,
-        serial: pallas::Base::random(&mut OsRng),
-        coin_blind: pallas::Base::random(&mut OsRng),
-        spend_hook,
-        user_data,
-    };
-
-    let output3 = money_contract::transfer::wallet::BuilderOutputInfo {
-        value: 200000,
-        token_id: gdrk_token_id,
-        public: gov_keypair_3.public,
-        serial: pallas::Base::random(&mut OsRng),
-        coin_blind: pallas::Base::random(&mut OsRng),
-        spend_hook,
-        user_data,
-    };
-
-    assert!(2 * 400000 + 200000 == gdrk_supply);
-
-    let builder = money_contract::transfer::wallet::Builder {
-        clear_inputs: vec![money_contract::transfer::wallet::BuilderClearInputInfo {
-            value: gdrk_supply,
-            token_id: gdrk_token_id,
-            signature_secret: cashier_signature_secret,
-        }],
-        inputs: vec![],
-        outputs: vec![output1, output2, output3],
-    };
-
-    let func_call = builder.build(&zk_bins)?;
-    let func_calls = vec![func_call];
-
-    let signatures = sign(vec![cashier_signature_secret], &func_calls);
-    let tx = Transaction { func_calls, signatures };
-
-    //// Validator
-
-    let mut updates = vec![];
-    // Validate all function calls in the tx
-    for (idx, func_call) in tx.func_calls.iter().enumerate() {
-        // So then the verifier will lookup the corresponding state_transition and apply
-        // functions based off the func_id
-        if func_call.func_id == *money_contract::transfer::FUNC_ID {
-            debug!("money_contract::transfer::state_transition()");
-
-            let update = money_contract::transfer::validate::state_transition(&states, idx, &tx)
-                .expect("money_contract::transfer::validate::state_transition() failed!");
-            updates.push(update);
-        }
-    }
-
-    // Atomically apply all changes
-    for update in updates {
-        update.apply(&mut states);
-    }
-
-    tx.zk_verify(&zk_bins);
-    tx.verify_sigs();
-
-    //// Wallet
-
-    let mut gov_recv = vec![None, None, None];
-    // Check that each person received one coin
-    for (i, key) in gov_keypairs.iter().enumerate() {
-        let gov_recv_coin = {
-            let state =
-                states.lookup_mut::<money_contract::State>(*money_contract::CONTRACT_ID).unwrap();
-            let mut recv_coins = state.wallet_cache.get_received(&key.secret);
-            assert_eq!(recv_coins.len(), 1);
-            let recv_coin = recv_coins.pop().unwrap();
-            let note = &recv_coin.note;
-
-            assert_eq!(note.token_id, gdrk_token_id);
-            // Normal payment
-            assert_eq!(note.spend_hook, pallas::Base::from(0));
-            assert_eq!(note.user_data, pallas::Base::from(0));
-
-            let coords = key.public.0.to_affine().coordinates().unwrap();
-            let coin = poseidon_hash::<8>([
-                *coords.x(),
-                *coords.y(),
-                DrkValue::from(note.value),
-                note.token_id,
-                note.serial,
-                note.spend_hook,
-                note.user_data,
-                note.coin_blind,
-            ]);
-            assert_eq!(coin, recv_coin.coin.0);
-
-            debug!("Holder{} received a coin worth {} gDRK", i, note.value);
-
-            recv_coin
-        };
-        gov_recv[i] = Some(gov_recv_coin);
-    }
-    // unwrap them for this demo
-    let gov_recv: Vec<_> = gov_recv.into_iter().map(|r| r.unwrap()).collect();
-
-    ///////////////////////////////////////////////////
-    // DAO rules:
-    // 1. gov token IDs must match on all inputs
-    // 2. proposals must be submitted by minimum amount
-    // 3. all votes >= quorum
-    // 4. outcome > approval_ratio
-    // 5. structure of outputs
-    //   output 0: value and address
-    //   output 1: change address
-    ///////////////////////////////////////////////////
-
-    ///////////////////////////////////////////////////
-    // Propose the vote
-    // In order to make a valid vote, first the proposer must
-    // meet a criteria for a minimum number of gov tokens
-    ///////////////////////////////////////////////////
-    debug!(target: "demo", "Stage 4. Propose the vote");
-
-    //// Wallet
-
-    // TODO: look into proposal expiry once time for voting has finished
-
-    let user_keypair = Keypair::random(&mut OsRng);
-
-    let (money_leaf_position, money_merkle_path) = {
-        let state = states.lookup::<money_contract::State>(*money_contract::CONTRACT_ID).unwrap();
-        let tree = &state.tree;
-        let leaf_position = gov_recv[0].leaf_position.clone();
-        let root = tree.root(0).unwrap();
-        let merkle_path = tree.authentication_path(leaf_position, &root).unwrap();
-        (leaf_position, merkle_path)
-    };
-
-    // TODO: is it possible for an invalid transfer() to be constructed on exec()?
-    //       need to look into this
-    let signature_secret = SecretKey::random(&mut OsRng);
-    let input = dao_contract::propose::wallet::BuilderInput {
-        secret: gov_keypair_1.secret,
-        note: gov_recv[0].note.clone(),
-        leaf_position: money_leaf_position,
-        merkle_path: money_merkle_path,
-        signature_secret,
-    };
-
-    let (dao_merkle_path, dao_merkle_root) = {
-        let state = states.lookup::<dao_contract::State>(*dao_contract::CONTRACT_ID).unwrap();
-        let tree = &state.dao_tree;
-        let root = tree.root(0).unwrap();
-        let merkle_path = tree.authentication_path(dao_leaf_position, &root).unwrap();
-        (merkle_path, root)
-    };
-
-    let dao_params = dao_contract::mint::wallet::DaoParams {
-        proposer_limit: dao_proposer_limit,
-        quorum: dao_quorum,
-        approval_ratio_base: dao_approval_ratio_base,
-        approval_ratio_quot: dao_approval_ratio_quot,
-        gov_token_id: gdrk_token_id,
-        public_key: dao_keypair.public,
-        bulla_blind: dao_bulla_blind,
-    };
-
-    let proposal = dao_contract::propose::wallet::Proposal {
-        dest: user_keypair.public,
-        amount: 1000,
-        serial: pallas::Base::random(&mut OsRng),
-        token_id: xdrk_token_id,
-        blind: pallas::Base::random(&mut OsRng),
-    };
-
-    let builder = dao_contract::propose::wallet::Builder {
-        inputs: vec![input],
-        proposal: proposal.clone(),
-        dao: dao_params.clone(),
-        dao_leaf_position,
-        dao_merkle_path,
-        dao_merkle_root,
-    };
-
-    let func_call = builder.build(&zk_bins);
-    let func_calls = vec![func_call];
-
-    let signatures = sign(vec![signature_secret], &func_calls);
-    let tx = Transaction { func_calls, signatures };
-
-    //// Validator
-
-    let mut updates = vec![];
-    // Validate all function calls in the tx
-    for (idx, func_call) in tx.func_calls.iter().enumerate() {
-        if func_call.func_id == *dao_contract::propose::FUNC_ID {
-            debug!(target: "demo", "dao_contract::propose::state_transition()");
-
-            let update = dao_contract::propose::validate::state_transition(&states, idx, &tx)
-                .expect("dao_contract::propose::validate::state_transition() failed!");
-            updates.push(update);
-        }
-    }
-
-    // Atomically apply all changes
-    for update in updates {
-        update.apply(&mut states);
-    }
-
-    tx.zk_verify(&zk_bins);
-    tx.verify_sigs();
-
-    //// Wallet
-
-    // Read received proposal
-    let (proposal, proposal_bulla) = {
-        assert_eq!(tx.func_calls.len(), 1);
-        let func_call = &tx.func_calls[0];
-        let call_data = func_call.call_data.as_any();
-        assert_eq!(
-            (&*call_data).type_id(),
-            TypeId::of::<dao_contract::propose::validate::CallData>()
-        );
-        let call_data =
-            call_data.downcast_ref::<dao_contract::propose::validate::CallData>().unwrap();
-
-        let header = &call_data.header;
-        let note: dao_contract::propose::wallet::Note =
-            header.enc_note.decrypt(&dao_keypair.secret).unwrap();
-
-        // TODO: check it belongs to DAO bulla
-
-        // Return the proposal info
-        (note.proposal, call_data.header.proposal_bulla)
-    };
-    debug!(target: "demo", "Proposal now active!");
-    debug!(target: "demo", "  destination: {:?}", proposal.dest);
-    debug!(target: "demo", "  amount: {}", proposal.amount);
-    debug!(target: "demo", "  token_id: {:?}", proposal.token_id);
-    debug!(target: "demo", "  dao_bulla: {:?}", dao_bulla.0);
-    debug!(target: "demo", "Proposal bulla: {:?}", proposal_bulla);
-
-    ///////////////////////////////////////////////////
-    // Proposal is accepted!
-    // Start the voting
-    ///////////////////////////////////////////////////
-
-    // Copying these schizo comments from python code:
-    // Lets the voting begin
-    // Voters have access to the proposal and dao data
-    //   vote_state = VoteState()
-    // We don't need to copy nullifier set because it is checked from gov_state
-    // in vote_state_transition() anyway
-    //
-    // TODO: what happens if voters don't unblind their vote
-    // Answer:
-    //   1. there is a time limit
-    //   2. both the MPC or users can unblind
-    //
-    // TODO: bug if I vote then send money, then we can double vote
-    // TODO: all timestamps missing
-    //       - timelock (future voting starts in 2 days)
-    // Fix: use nullifiers from money gov state only from
-    // beginning of gov period
-    // Cannot use nullifiers from before voting period
-
-    debug!(target: "demo", "Stage 5. Start voting");
-
-    // We were previously saving updates here for testing
-    // let mut updates = vec![];
-
-    // User 1: YES
-
-    let (money_leaf_position, money_merkle_path) = {
-        let state = states.lookup::<money_contract::State>(*money_contract::CONTRACT_ID).unwrap();
-        let tree = &state.tree;
-        let leaf_position = gov_recv[0].leaf_position.clone();
-        let root = tree.root(0).unwrap();
-        let merkle_path = tree.authentication_path(leaf_position, &root).unwrap();
-        (leaf_position, merkle_path)
-    };
-
-    let signature_secret = SecretKey::random(&mut OsRng);
-    let input = dao_contract::vote::wallet::BuilderInput {
-        secret: gov_keypair_1.secret,
-        note: gov_recv[0].note.clone(),
-        leaf_position: money_leaf_position,
-        merkle_path: money_merkle_path,
-        signature_secret,
-    };
-
-    let vote_option: bool = true;
-
-    assert!(vote_option == true || vote_option == false);
-
-    // We create a new keypair to encrypt the vote.
-    // For the demo MVP, you can just use the dao_keypair secret
-    let vote_keypair_1 = Keypair::random(&mut OsRng);
-
-    let builder = dao_contract::vote::wallet::Builder {
-        inputs: vec![input],
-        vote: dao_contract::vote::wallet::Vote {
-            vote_option,
-            vote_option_blind: pallas::Scalar::random(&mut OsRng),
-        },
-        vote_keypair: vote_keypair_1,
-        proposal: proposal.clone(),
-        dao: dao_params.clone(),
-    };
-    debug!(target: "demo", "build()...");
-    let func_call = builder.build(&zk_bins);
-    let func_calls = vec![func_call];
-
-    let signatures = sign(vec![signature_secret], &func_calls);
-    let tx = Transaction { func_calls, signatures };
-
-    //// Validator
-
-    let mut updates = vec![];
-    // Validate all function calls in the tx
-    for (idx, func_call) in tx.func_calls.iter().enumerate() {
-        if func_call.func_id == *dao_contract::vote::FUNC_ID {
-            debug!(target: "demo", "dao_contract::vote::state_transition()");
-
-            let update = dao_contract::vote::validate::state_transition(&states, idx, &tx)
-                .expect("dao_contract::vote::validate::state_transition() failed!");
-            updates.push(update);
-        }
-    }
-
-    // Atomically apply all changes
-    for update in updates {
-        update.apply(&mut states);
-    }
-
-    tx.zk_verify(&zk_bins);
-    tx.verify_sigs();
-
-    //// Wallet
-
-    // Secret vote info. Needs to be revealed at some point.
-    // TODO: look into verifiable encryption for notes
-    // TODO: look into timelock puzzle as a possibility
-    let vote_note_1 = {
-        assert_eq!(tx.func_calls.len(), 1);
-        let func_call = &tx.func_calls[0];
-        let call_data = func_call.call_data.as_any();
-        assert_eq!((&*call_data).type_id(), TypeId::of::<dao_contract::vote::validate::CallData>());
-        let call_data = call_data.downcast_ref::<dao_contract::vote::validate::CallData>().unwrap();
-
-        let header = &call_data.header;
-        let note: dao_contract::vote::wallet::Note =
-            header.enc_note.decrypt(&vote_keypair_1.secret).unwrap();
-        note
-    };
-    debug!(target: "demo", "User 1 voted!");
-    debug!(target: "demo", "  vote_option: {}", vote_note_1.vote.vote_option);
-    debug!(target: "demo", "  value: {}", vote_note_1.vote_value);
-
-    // User 2: NO
-
-    let (money_leaf_position, money_merkle_path) = {
-        let state = states.lookup::<money_contract::State>(*money_contract::CONTRACT_ID).unwrap();
-        let tree = &state.tree;
-        let leaf_position = gov_recv[1].leaf_position.clone();
-        let root = tree.root(0).unwrap();
-        let merkle_path = tree.authentication_path(leaf_position, &root).unwrap();
-        (leaf_position, merkle_path)
-    };
-
-    let signature_secret = SecretKey::random(&mut OsRng);
-    let input = dao_contract::vote::wallet::BuilderInput {
-        secret: gov_keypair_2.secret,
-        note: gov_recv[1].note.clone(),
-        leaf_position: money_leaf_position,
-        merkle_path: money_merkle_path,
-        signature_secret,
-    };
-
-    let vote_option: bool = false;
-
-    assert!(vote_option == true || vote_option == false);
-
-    // We create a new keypair to encrypt the vote.
-    let vote_keypair_2 = Keypair::random(&mut OsRng);
-
-    let builder = dao_contract::vote::wallet::Builder {
-        inputs: vec![input],
-        vote: dao_contract::vote::wallet::Vote {
-            vote_option,
-            vote_option_blind: pallas::Scalar::random(&mut OsRng),
-        },
-        vote_keypair: vote_keypair_2,
-        proposal: proposal.clone(),
-        dao: dao_params.clone(),
-    };
-    debug!(target: "demo", "build()...");
-    let func_call = builder.build(&zk_bins);
-    let func_calls = vec![func_call];
-
-    let signatures = sign(vec![signature_secret], &func_calls);
-    let tx = Transaction { func_calls, signatures };
-
-    //// Validator
-
-    let mut updates = vec![];
-    // Validate all function calls in the tx
-    for (idx, func_call) in tx.func_calls.iter().enumerate() {
-        if func_call.func_id == *dao_contract::vote::FUNC_ID {
-            debug!(target: "demo", "dao_contract::vote::state_transition()");
-
-            let update = dao_contract::vote::validate::state_transition(&states, idx, &tx)
-                .expect("dao_contract::vote::validate::state_transition() failed!");
-            updates.push(update);
-        }
-    }
-
-    // Atomically apply all changes
-    for update in updates {
-        update.apply(&mut states);
-    }
-
-    tx.zk_verify(&zk_bins);
-    tx.verify_sigs();
-
-    //// Wallet
-
-    // Secret vote info. Needs to be revealed at some point.
-    // TODO: look into verifiable encryption for notes
-    // TODO: look into timelock puzzle as a possibility
-    let vote_note_2 = {
-        assert_eq!(tx.func_calls.len(), 1);
-        let func_call = &tx.func_calls[0];
-        let call_data = func_call.call_data.as_any();
-        assert_eq!((&*call_data).type_id(), TypeId::of::<dao_contract::vote::validate::CallData>());
-        let call_data = call_data.downcast_ref::<dao_contract::vote::validate::CallData>().unwrap();
-
-        let header = &call_data.header;
-        let note: dao_contract::vote::wallet::Note =
-            header.enc_note.decrypt(&vote_keypair_2.secret).unwrap();
-        note
-    };
-    debug!(target: "demo", "User 2 voted!");
-    debug!(target: "demo", "  vote_option: {}", vote_note_2.vote.vote_option);
-    debug!(target: "demo", "  value: {}", vote_note_2.vote_value);
-
-    // User 3: YES
-
-    let (money_leaf_position, money_merkle_path) = {
-        let state = states.lookup::<money_contract::State>(*money_contract::CONTRACT_ID).unwrap();
-        let tree = &state.tree;
-        let leaf_position = gov_recv[2].leaf_position.clone();
-        let root = tree.root(0).unwrap();
-        let merkle_path = tree.authentication_path(leaf_position, &root).unwrap();
-        (leaf_position, merkle_path)
-    };
-
-    let signature_secret = SecretKey::random(&mut OsRng);
-    let input = dao_contract::vote::wallet::BuilderInput {
-        secret: gov_keypair_3.secret,
-        note: gov_recv[2].note.clone(),
-        leaf_position: money_leaf_position,
-        merkle_path: money_merkle_path,
-        signature_secret,
-    };
-
-    let vote_option: bool = true;
-
-    assert!(vote_option == true || vote_option == false);
-
-    // We create a new keypair to encrypt the vote.
-    let vote_keypair_3 = Keypair::random(&mut OsRng);
-
-    let builder = dao_contract::vote::wallet::Builder {
-        inputs: vec![input],
-        vote: dao_contract::vote::wallet::Vote {
-            vote_option,
-            vote_option_blind: pallas::Scalar::random(&mut OsRng),
-        },
-        vote_keypair: vote_keypair_3,
-        proposal: proposal.clone(),
-        dao: dao_params.clone(),
-    };
-    debug!(target: "demo", "build()...");
-    let func_call = builder.build(&zk_bins);
-    let func_calls = vec![func_call];
-
-    let signatures = sign(vec![signature_secret], &func_calls);
-    let tx = Transaction { func_calls, signatures };
-
-    //// Validator
-
-    let mut updates = vec![];
-    // Validate all function calls in the tx
-    for (idx, func_call) in tx.func_calls.iter().enumerate() {
-        if func_call.func_id == *dao_contract::vote::FUNC_ID {
-            debug!(target: "demo", "dao_contract::vote::state_transition()");
-
-            let update = dao_contract::vote::validate::state_transition(&states, idx, &tx)
-                .expect("dao_contract::vote::validate::state_transition() failed!");
-            updates.push(update);
-        }
-    }
-
-    // Atomically apply all changes
-    for update in updates {
-        update.apply(&mut states);
-    }
-
-    tx.zk_verify(&zk_bins);
-    tx.verify_sigs();
-
-    //// Wallet
-
-    // Secret vote info. Needs to be revealed at some point.
-    // TODO: look into verifiable encryption for notes
-    // TODO: look into timelock puzzle as a possibility
-    let vote_note_3 = {
-        assert_eq!(tx.func_calls.len(), 1);
-        let func_call = &tx.func_calls[0];
-        let call_data = func_call.call_data.as_any();
-        assert_eq!((&*call_data).type_id(), TypeId::of::<dao_contract::vote::validate::CallData>());
-        let call_data = call_data.downcast_ref::<dao_contract::vote::validate::CallData>().unwrap();
-
-        let header = &call_data.header;
-        let note: dao_contract::vote::wallet::Note =
-            header.enc_note.decrypt(&vote_keypair_3.secret).unwrap();
-        note
-    };
-    debug!(target: "demo", "User 3 voted!");
-    debug!(target: "demo", "  vote_option: {}", vote_note_3.vote.vote_option);
-    debug!(target: "demo", "  value: {}", vote_note_3.vote_value);
-
-    // Every votes produces a semi-homomorphic encryption of their vote.
-    // Which is either yes or no
-    // We copy the state tree for the governance token so coins can be used
-    // to vote on other proposals at the same time.
-    // With their vote, they produce a ZK proof + nullifier
-    // The votes are unblinded by MPC to a selected party at the end of the
-    // voting period.
-    // (that's if we want votes to be hidden during voting)
-
-    let mut yes_votes_value = 0;
-    let mut yes_votes_blind = pallas::Scalar::from(0);
-    let mut yes_votes_commit = pallas::Point::identity();
-
-    let mut all_votes_value = 0;
-    let mut all_votes_blind = pallas::Scalar::from(0);
-    let mut all_votes_commit = pallas::Point::identity();
-
-    // We were previously saving votes to a Vec<Update> for testing.
-    // However since Update is now UpdateBase it gets moved into update.apply().
-    // So we need to think of another way to run these tests.
-    //assert!(updates.len() == 3);
-
-    for (i, note /* update*/) in [vote_note_1, vote_note_2, vote_note_3]
-        .iter() /*.zip(updates)*/
-        .enumerate()
-    {
-        let vote_commit = pedersen_commitment_u64(note.vote_value, note.vote_value_blind);
-        //assert!(update.value_commit == all_vote_value_commit);
-        all_votes_commit += vote_commit;
-        all_votes_blind += note.vote_value_blind;
-
-        let yes_vote_commit = pedersen_commitment_u64(
-            note.vote.vote_option as u64 * note.vote_value,
-            note.vote.vote_option_blind,
-        );
-        //assert!(update.yes_vote_commit == yes_vote_commit);
-
-        yes_votes_commit += yes_vote_commit;
-        yes_votes_blind += note.vote.vote_option_blind;
-
-        let vote_option = note.vote.vote_option;
-
-        if vote_option {
-            yes_votes_value += note.vote_value;
-        }
-        all_votes_value += note.vote_value;
-        let vote_result: String = if vote_option { "yes".to_string() } else { "no".to_string() };
-
-        debug!("Voter {} voted {}", i, vote_result);
-    }
-
-    debug!("Outcome = {} / {}", yes_votes_value, all_votes_value);
-
-    assert!(all_votes_commit == pedersen_commitment_u64(all_votes_value, all_votes_blind));
-    assert!(yes_votes_commit == pedersen_commitment_u64(yes_votes_value, yes_votes_blind));
-
-    ///////////////////////////////////////////////////
-    // Execute the vote
-    ///////////////////////////////////////////////////
-
-    //// Wallet
-
-    // Used to export user_data from this coin so it can be accessed by DAO::exec()
-    let user_data_blind = pallas::Base::random(&mut OsRng);
-
-    let user_serial = pallas::Base::random(&mut OsRng);
-    let user_coin_blind = pallas::Base::random(&mut OsRng);
-    let dao_serial = pallas::Base::random(&mut OsRng);
-    let dao_coin_blind = pallas::Base::random(&mut OsRng);
-    let input_value = treasury_note.value;
-    let input_value_blind = pallas::Scalar::random(&mut OsRng);
-    let tx_signature_secret = SecretKey::random(&mut OsRng);
-    let exec_signature_secret = SecretKey::random(&mut OsRng);
-
-    let (treasury_leaf_position, treasury_merkle_path) = {
-        let state = states.lookup::<money_contract::State>(*money_contract::CONTRACT_ID).unwrap();
-        let tree = &state.tree;
-        let leaf_position = dao_recv_coin.leaf_position.clone();
-        let root = tree.root(0).unwrap();
-        let merkle_path = tree.authentication_path(leaf_position, &root).unwrap();
-        (leaf_position, merkle_path)
-    };
-
-    let input = money_contract::transfer::wallet::BuilderInputInfo {
-        leaf_position: treasury_leaf_position,
-        merkle_path: treasury_merkle_path,
-        secret: dao_keypair.secret,
-        note: treasury_note,
-        user_data_blind,
-        value_blind: input_value_blind,
-        signature_secret: tx_signature_secret,
-    };
-
-    let builder = money_contract::transfer::wallet::Builder {
-        clear_inputs: vec![],
-        inputs: vec![input],
-        outputs: vec![
-            // Sending money
-            money_contract::transfer::wallet::BuilderOutputInfo {
-                value: 1000,
-                token_id: xdrk_token_id,
-                public: user_keypair.public,
-                serial: proposal.serial,
-                coin_blind: proposal.blind,
-                spend_hook: pallas::Base::from(0),
-                user_data: pallas::Base::from(0),
-            },
-            // Change back to DAO
-            money_contract::transfer::wallet::BuilderOutputInfo {
-                value: xdrk_supply - 1000,
-                token_id: xdrk_token_id,
-                public: dao_keypair.public,
-                serial: dao_serial,
-                coin_blind: dao_coin_blind,
-                spend_hook: *dao_contract::exec::FUNC_ID,
-                user_data: proposal_bulla,
-            },
-        ],
-    };
-
-    let transfer_func_call = builder.build(&zk_bins)?;
-
-    let builder = dao_contract::exec::wallet::Builder {
-        proposal,
-        dao: dao_params,
-        yes_votes_value,
-        all_votes_value,
-        yes_votes_blind,
-        all_votes_blind,
-        user_serial,
-        user_coin_blind,
-        dao_serial,
-        dao_coin_blind,
-        input_value,
-        input_value_blind,
-        hook_dao_exec: *dao_contract::exec::FUNC_ID,
-        signature_secret: exec_signature_secret,
-    };
-    let exec_func_call = builder.build(&zk_bins);
-    let func_calls = vec![transfer_func_call, exec_func_call];
-
-    let signatures = sign(vec![tx_signature_secret, exec_signature_secret], &func_calls);
-    let tx = Transaction { func_calls, signatures };
-
-    {
-        // Now the spend_hook field specifies the function DAO::exec()
-        // so Money::transfer() must also be combined with DAO::exec()
-
-        assert_eq!(tx.func_calls.len(), 2);
-        let transfer_func_call = &tx.func_calls[0];
-        let transfer_call_data = transfer_func_call.call_data.as_any();
-
-        assert_eq!(
-            (&*transfer_call_data).type_id(),
-            TypeId::of::<money_contract::transfer::validate::CallData>()
-        );
-        let transfer_call_data =
-            transfer_call_data.downcast_ref::<money_contract::transfer::validate::CallData>();
-        let transfer_call_data = transfer_call_data.unwrap();
-        // At least one input has this field value which means DAO::exec() is invoked.
-        assert_eq!(transfer_call_data.inputs.len(), 1);
-        let input = &transfer_call_data.inputs[0];
-        assert_eq!(input.revealed.spend_hook, *dao_contract::exec::FUNC_ID);
-        let user_data_enc = poseidon_hash::<2>([dao_bulla.0, user_data_blind]);
-        assert_eq!(input.revealed.user_data_enc, user_data_enc);
-    }
-
-    //// Validator
-
-    let mut updates = vec![];
-    // Validate all function calls in the tx
-    for (idx, func_call) in tx.func_calls.iter().enumerate() {
-        if func_call.func_id == *dao_contract::exec::FUNC_ID {
-            debug!("dao_contract::exec::state_transition()");
-
-            let update = dao_contract::exec::validate::state_transition(&states, idx, &tx)
-                .expect("dao_contract::exec::validate::state_transition() failed!");
-            updates.push(update);
-        } else if func_call.func_id == *money_contract::transfer::FUNC_ID {
-            debug!("money_contract::transfer::state_transition()");
-
-            let update = money_contract::transfer::validate::state_transition(&states, idx, &tx)
-                .expect("money_contract::transfer::validate::state_transition() failed!");
-            updates.push(update);
-        }
-    }
-
-    // Atomically apply all changes
-    for update in updates {
-        update.apply(&mut states);
-    }
-
-    // Other stuff
-    tx.zk_verify(&zk_bins);
-    tx.verify_sigs();
-
-    //// Wallet
-
-    Ok(())
-}

+ 5 - 4
example/dao/src/contract/dao/propose/validate.rs

@@ -1,5 +1,7 @@
 use std::any::{Any, TypeId};
 
+use darkfi_sdk::crypto::MerkleNode;
+use darkfi_serial::{Encodable, SerialDecodable, SerialEncodable};
 use log::error;
 use pasta_curves::{
     arithmetic::CurveAffine,
@@ -8,10 +10,9 @@ use pasta_curves::{
 };
 
 use darkfi::{
-    crypto::{keypair::PublicKey, merkle_node::MerkleNode, types::DrkCircuitField},
+    crypto::{keypair::PublicKey, types::DrkCircuitField},
     Error as DarkFiError,
 };
-use darkfi_serial::{Encodable, SerialDecodable, SerialEncodable};
 
 use crate::{
     contract::{dao, dao::State as DaoState, money, money::state::State as MoneyState},
@@ -65,7 +66,7 @@ impl CallDataBase for CallData {
                     *value_coords.x(),
                     *value_coords.y(),
                     self.header.token_commit,
-                    input.merkle_root.0,
+                    input.merkle_root.inner(),
                     *sigpub_coords.x(),
                     *sigpub_coords.y(),
                 ],
@@ -77,7 +78,7 @@ impl CallDataBase for CallData {
             "dao-propose-main".to_string(),
             vec![
                 self.header.token_commit,
-                self.header.dao_merkle_root.0,
+                self.header.dao_merkle_root.inner(),
                 self.header.proposal_bulla,
                 *total_funds_coords.x(),
                 *total_funds_coords.y(),

+ 5 - 5
example/dao/src/contract/dao/propose/wallet.rs

@@ -1,3 +1,5 @@
+use darkfi_sdk::crypto::MerkleNode;
+use darkfi_serial::{SerialDecodable, SerialEncodable};
 use halo2_proofs::circuit::Value;
 use incrementalmerkletree::Hashable;
 use pasta_curves::{
@@ -10,13 +12,11 @@ use rand::rngs::OsRng;
 use darkfi::{
     crypto::{
         keypair::{PublicKey, SecretKey},
-        merkle_node::MerkleNode,
         util::{pedersen_commitment_u64, poseidon_hash},
         Proof,
     },
     zk::vm::{Witness, ZkCircuit},
 };
-use darkfi_serial::{SerialDecodable, SerialEncodable};
 
 use crate::{
     contract::{
@@ -122,7 +122,7 @@ impl Builder {
 
             let merkle_root = {
                 let position: u64 = input.leaf_position.into();
-                let mut current = MerkleNode(coin);
+                let mut current = MerkleNode::from(coin);
                 for (level, sibling) in input.merkle_path.iter().enumerate() {
                     let level = level as u8;
                     current = if position & (1 << level) == 0 {
@@ -146,7 +146,7 @@ impl Builder {
                 *value_coords.x(),
                 *value_coords.y(),
                 token_commit,
-                merkle_root.0,
+                merkle_root.inner(),
                 *sigpub_coords.x(),
                 *sigpub_coords.y(),
             ];
@@ -239,7 +239,7 @@ impl Builder {
         ];
         let public_inputs = vec![
             token_commit,
-            self.dao_merkle_root.0,
+            self.dao_merkle_root.inner(),
             proposal_bulla,
             *total_funds_coords.x(),
             *total_funds_coords.y(),

+ 4 - 5
example/dao/src/contract/dao/state.rs

@@ -1,11 +1,10 @@
 use std::{any::Any, collections::HashMap};
 
+use darkfi_sdk::crypto::{constants::MERKLE_DEPTH, MerkleNode, Nullifier};
+use darkfi_serial::{SerialDecodable, SerialEncodable};
 use incrementalmerkletree::{bridgetree::BridgeTree, Tree};
 use pasta_curves::{group::Group, pallas};
 
-use darkfi::crypto::{constants::MERKLE_DEPTH, merkle_node::MerkleNode, nullifier::Nullifier};
-use darkfi_serial::{SerialDecodable, SerialEncodable};
-
 use crate::util::HashableBase;
 
 #[derive(Clone, SerialEncodable, SerialDecodable)]
@@ -55,14 +54,14 @@ impl State {
     }
 
     pub fn add_dao_bulla(&mut self, bulla: DaoBulla) {
-        let node = MerkleNode(bulla.0);
+        let node = MerkleNode::from(bulla.0);
         self.dao_bullas.push(bulla);
         self.dao_tree.append(&node);
         self.dao_roots.push(self.dao_tree.root(0).unwrap());
     }
 
     pub fn add_proposal_bulla(&mut self, bulla: pallas::Base) {
-        let node = MerkleNode(bulla);
+        let node = MerkleNode::from(bulla);
         //self.proposal_bullas.push(bulla);
         self.proposal_tree.append(&node);
         self.proposal_roots.push(self.proposal_tree.root(0).unwrap());

+ 5 - 6
example/dao/src/contract/dao/vote/validate.rs

@@ -1,5 +1,7 @@
 use std::any::{Any, TypeId};
 
+use darkfi_sdk::crypto::{MerkleNode, Nullifier};
+use darkfi_serial::{Encodable, SerialDecodable, SerialEncodable};
 use log::error;
 use pasta_curves::{
     arithmetic::CurveAffine,
@@ -8,12 +10,9 @@ use pasta_curves::{
 };
 
 use darkfi::{
-    crypto::{
-        keypair::PublicKey, merkle_node::MerkleNode, nullifier::Nullifier, types::DrkCircuitField,
-    },
+    crypto::{keypair::PublicKey, types::DrkCircuitField},
     Error as DarkFiError,
 };
-use darkfi_serial::{Encodable, SerialDecodable, SerialEncodable};
 
 use crate::{
     contract::{dao, dao::State as DaoState, money, money::state::State as MoneyState},
@@ -67,11 +66,11 @@ impl CallDataBase for CallData {
             zk_publics.push((
                 "dao-vote-burn".to_string(),
                 vec![
-                    input.nullifier.0,
+                    input.nullifier.inner(),
                     *value_coords.x(),
                     *value_coords.y(),
                     self.header.token_commit,
-                    input.merkle_root.0,
+                    input.merkle_root.inner(),
                     *sigpub_coords.x(),
                     *sigpub_coords.y(),
                 ],

+ 5 - 6
example/dao/src/contract/dao/vote/wallet.rs

@@ -1,3 +1,5 @@
+use darkfi_sdk::crypto::{MerkleNode, Nullifier};
+use darkfi_serial::{SerialDecodable, SerialEncodable};
 use halo2_proofs::circuit::Value;
 use incrementalmerkletree::Hashable;
 use log::debug;
@@ -11,14 +13,11 @@ use rand::rngs::OsRng;
 use darkfi::{
     crypto::{
         keypair::{Keypair, PublicKey, SecretKey},
-        merkle_node::MerkleNode,
-        nullifier::Nullifier,
         util::{pedersen_commitment_u64, poseidon_hash},
         Proof,
     },
     zk::vm::{Witness, ZkCircuit},
 };
-use darkfi_serial::{SerialDecodable, SerialEncodable};
 
 use crate::{
     contract::{
@@ -128,7 +127,7 @@ impl Builder {
 
             let merkle_root = {
                 let position: u64 = input.leaf_position.into();
-                let mut current = MerkleNode(coin);
+                let mut current = MerkleNode::from(coin);
                 for (level, sibling) in input.merkle_path.iter().enumerate() {
                     let level = level as u8;
                     current = if position & (1 << level) == 0 {
@@ -155,7 +154,7 @@ impl Builder {
                 *vote_commit_coords.x(),
                 *vote_commit_coords.y(),
                 token_commit,
-                merkle_root.0,
+                merkle_root.inner(),
                 *sigpub_coords.x(),
                 *sigpub_coords.y(),
             ];
@@ -168,7 +167,7 @@ impl Builder {
             proofs.push(input_proof);
 
             let input = Input {
-                nullifier: Nullifier(nullifier),
+                nullifier: Nullifier::from(nullifier),
                 vote_commit,
                 merkle_root,
                 signature_public,

+ 1 - 3
example/dao/src/contract/money/state.rs

@@ -1,11 +1,9 @@
+use darkfi_sdk::crypto::{constants::MERKLE_DEPTH, MerkleNode, Nullifier};
 use incrementalmerkletree::{bridgetree::BridgeTree, Tree};
 
 use darkfi::crypto::{
     coin::Coin,
-    constants::MERKLE_DEPTH,
     keypair::{PublicKey, SecretKey},
-    merkle_node::MerkleNode,
-    nullifier::Nullifier,
 };
 
 use super::transfer;

+ 3 - 4
example/dao/src/contract/money/transfer/validate.rs

@@ -1,5 +1,7 @@
 use std::any::{Any, TypeId};
 
+use darkfi_sdk::crypto::{MerkleNode, Nullifier};
+use darkfi_serial::{Encodable, SerialDecodable, SerialEncodable};
 use incrementalmerkletree::Tree;
 use log::{debug, error};
 use pasta_curves::{group::Group, pallas};
@@ -8,15 +10,12 @@ use darkfi::{
     crypto::{
         coin::Coin,
         keypair::PublicKey,
-        merkle_node::MerkleNode,
-        nullifier::Nullifier,
         types::{DrkCircuitField, DrkTokenId, DrkValueBlind, DrkValueCommit},
         util::{pedersen_commitment_base, pedersen_commitment_u64},
         BurnRevealedValues, MintRevealedValues,
     },
     Error as DarkFiError,
 };
-use darkfi_serial::{Encodable, SerialDecodable, SerialEncodable};
 
 use crate::{
     contract::{
@@ -51,7 +50,7 @@ impl UpdateBase for Update {
         //// Update merkle tree and witnesses
         for (coin, enc_note) in self.coins.into_iter().zip(self.enc_notes.into_iter()) {
             // Add the new coins to the Merkle tree
-            let node = MerkleNode(coin.0);
+            let node = MerkleNode::from(coin.0);
             state.tree.append(&node);
 
             // Keep track of all Merkle roots that have existed

+ 2 - 2
example/dao/src/contract/money/transfer/wallet.rs

@@ -1,3 +1,5 @@
+use darkfi_sdk::crypto::MerkleNode;
+use darkfi_serial::{SerialDecodable, SerialEncodable};
 use pasta_curves::group::ff::Field;
 use rand::rngs::OsRng;
 
@@ -5,7 +7,6 @@ use darkfi::{
     crypto::{
         burn_proof::create_burn_proof,
         keypair::{PublicKey, SecretKey},
-        merkle_node::MerkleNode,
         mint_proof::create_mint_proof,
         types::{
             DrkCoinBlind, DrkSerial, DrkSpendHook, DrkTokenId, DrkUserData, DrkUserDataBlind,
@@ -14,7 +15,6 @@ use darkfi::{
     },
     Result,
 };
-use darkfi_serial::{SerialDecodable, SerialEncodable};
 
 use crate::{
     contract::money::{

+ 0 - 236
example/dao/util.rs

@@ -1,236 +0,0 @@
-use std::{any::Any, collections::HashMap, hash::Hasher};
-
-use darkfi_serial::Encodable;
-use lazy_static::lazy_static;
-use log::debug;
-use pasta_curves::{
-    group::ff::{Field, PrimeField},
-    pallas,
-};
-use rand::rngs::OsRng;
-
-use darkfi::{
-    crypto::{
-        keypair::{PublicKey, SecretKey},
-        proof::{ProvingKey, VerifyingKey},
-        schnorr::{SchnorrPublic, SchnorrSecret, Signature},
-        types::DrkCircuitField,
-        Proof,
-    },
-    zk::{vm::ZkCircuit, vm_stack::empty_witnesses},
-    zkas::decoder::ZkBinary,
-};
-
-// TODO: base58 encoding/ decoding
-
-lazy_static! {
-    pub static ref XDRK_ID: pallas::Base = pallas::Base::random(&mut OsRng);
-}
-
-lazy_static! {
-    pub static ref GDRK_ID: pallas::Base = pallas::Base::random(&mut OsRng);
-}
-
-#[derive(Eq, PartialEq)]
-pub struct HashableBase(pub pallas::Base);
-
-impl std::hash::Hash for HashableBase {
-    fn hash<H: Hasher>(&self, state: &mut H) {
-        let bytes = self.0.to_repr();
-        bytes.hash(state);
-    }
-}
-
-pub struct ZkBinaryContractInfo {
-    pub k_param: u32,
-    pub bincode: ZkBinary,
-    pub proving_key: ProvingKey,
-    pub verifying_key: VerifyingKey,
-}
-pub struct ZkNativeContractInfo {
-    pub proving_key: ProvingKey,
-    pub verifying_key: VerifyingKey,
-}
-
-pub enum ZkContractInfo {
-    Binary(ZkBinaryContractInfo),
-    Native(ZkNativeContractInfo),
-}
-
-pub struct ZkContractTable {
-    // Key will be a hash of zk binary contract on chain
-    table: HashMap<String, ZkContractInfo>,
-}
-
-impl ZkContractTable {
-    pub fn new() -> Self {
-        Self { table: HashMap::new() }
-    }
-
-    pub fn add_contract(&mut self, key: String, bincode: ZkBinary, k_param: u32) {
-        let witnesses = empty_witnesses(&bincode);
-        let circuit = ZkCircuit::new(witnesses, bincode.clone());
-        let proving_key = ProvingKey::build(k_param, &circuit);
-        let verifying_key = VerifyingKey::build(k_param, &circuit);
-        let info = ZkContractInfo::Binary(ZkBinaryContractInfo {
-            k_param,
-            bincode,
-            proving_key,
-            verifying_key,
-        });
-        self.table.insert(key, info);
-    }
-
-    pub fn add_native(
-        &mut self,
-        key: String,
-        proving_key: ProvingKey,
-        verifying_key: VerifyingKey,
-    ) {
-        self.table.insert(
-            key,
-            ZkContractInfo::Native(ZkNativeContractInfo { proving_key, verifying_key }),
-        );
-    }
-
-    pub fn lookup(&self, key: &String) -> Option<&ZkContractInfo> {
-        self.table.get(key)
-    }
-}
-
-pub struct Transaction {
-    pub func_calls: Vec<FuncCall>,
-    pub signatures: Vec<Signature>,
-}
-
-impl Transaction {
-    /// Verify ZK contracts for the entire tx
-    /// In real code, we could parallelize this for loop
-    /// TODO: fix use of unwrap with Result type stuff
-    pub fn zk_verify(&self, zk_bins: &ZkContractTable) {
-        for func_call in &self.func_calls {
-            let proofs_public_vals = &func_call.call_data.zk_public_values();
-
-            assert_eq!(
-                proofs_public_vals.len(),
-                func_call.proofs.len(),
-                "proof_public_vals.len()={} and func_call.proofs.len()={} do not match",
-                proofs_public_vals.len(),
-                func_call.proofs.len()
-            );
-            for (i, (proof, (key, public_vals))) in
-                func_call.proofs.iter().zip(proofs_public_vals.iter()).enumerate()
-            {
-                match zk_bins.lookup(key).unwrap() {
-                    ZkContractInfo::Binary(info) => {
-                        let verifying_key = &info.verifying_key;
-                        let verify_result = proof.verify(&verifying_key, public_vals);
-                        assert!(verify_result.is_ok(), "verify proof[{}]='{}' failed", i, key);
-                    }
-                    ZkContractInfo::Native(info) => {
-                        let verifying_key = &info.verifying_key;
-                        let verify_result = proof.verify(&verifying_key, public_vals);
-                        assert!(verify_result.is_ok(), "verify proof[{}]='{}' failed", i, key);
-                    }
-                };
-                debug!(target: "demo", "zk_verify({}) passed [i={}]", key, i);
-            }
-        }
-    }
-
-    pub fn verify_sigs(&self) {
-        let mut unsigned_tx_data = vec![];
-        for (i, (func_call, signature)) in
-            self.func_calls.iter().zip(self.signatures.clone()).enumerate()
-        {
-            func_call.encode(&mut unsigned_tx_data).expect("failed to encode data");
-            let signature_pub_keys = func_call.call_data.signature_public_keys();
-            for signature_pub_key in signature_pub_keys {
-                let verify_result = signature_pub_key.verify(&unsigned_tx_data[..], &signature);
-                assert!(verify_result, "verify sigs[{}] failed", i);
-            }
-            debug!(target: "demo", "verify_sigs({}) passed", i);
-        }
-    }
-}
-
-pub fn sign(signature_secrets: Vec<SecretKey>, func_calls: &Vec<FuncCall>) -> Vec<Signature> {
-    let mut signatures = vec![];
-    let mut unsigned_tx_data = vec![];
-    for (_i, (signature_secret, func_call)) in
-        signature_secrets.iter().zip(func_calls.iter()).enumerate()
-    {
-        func_call.encode(&mut unsigned_tx_data).expect("failed to encode data");
-        let signature = signature_secret.sign(&unsigned_tx_data[..]);
-        signatures.push(signature);
-    }
-    signatures
-}
-
-type ContractId = pallas::Base;
-type FuncId = pallas::Base;
-
-pub struct FuncCall {
-    pub contract_id: ContractId,
-    pub func_id: FuncId,
-    pub call_data: Box<dyn CallDataBase + Send + Sync>,
-    pub proofs: Vec<Proof>,
-}
-
-impl Encodable for FuncCall {
-    fn encode<W: std::io::Write>(&self, mut w: W) -> std::result::Result<usize, std::io::Error> {
-        let mut len = 0;
-        len += self.contract_id.encode(&mut w)?;
-        len += self.func_id.encode(&mut w)?;
-        len += self.proofs.encode(&mut w)?;
-        len += self.call_data.encode_bytes(&mut w)?;
-        Ok(len)
-    }
-}
-
-pub trait CallDataBase {
-    // Public values for verifying the proofs
-    // Needed so we can convert internal types so they can be used in Proof::verify()
-    fn zk_public_values(&self) -> Vec<(String, Vec<DrkCircuitField>)>;
-
-    // For upcasting to CallData itself so it can be read in state_transition()
-    fn as_any(&self) -> &dyn Any;
-
-    // Public keys we will use to verify transaction signatures.
-    fn signature_public_keys(&self) -> Vec<PublicKey>;
-
-    fn encode_bytes(
-        &self,
-        writer: &mut dyn std::io::Write,
-    ) -> std::result::Result<usize, std::io::Error>;
-}
-
-//type GenericContractState = Box<dyn Any + Send>;
-type GenericContractState = Box<dyn Any>;
-
-pub struct StateRegistry {
-    pub states: HashMap<HashableBase, GenericContractState>,
-}
-
-impl StateRegistry {
-    pub fn new() -> Self {
-        Self { states: HashMap::new() }
-    }
-
-    pub fn register(&mut self, contract_id: ContractId, state: GenericContractState) {
-        debug!(target: "StateRegistry::register()", "contract_id: {:?}", contract_id);
-        self.states.insert(HashableBase(contract_id), state);
-    }
-
-    pub fn lookup_mut<'a, S: 'static>(&'a mut self, contract_id: ContractId) -> Option<&'a mut S> {
-        self.states.get_mut(&HashableBase(contract_id)).and_then(|state| state.downcast_mut())
-    }
-
-    pub fn lookup<'a, S: 'static>(&'a self, contract_id: ContractId) -> Option<&'a S> {
-        self.states.get(&HashableBase(contract_id)).and_then(|state| state.downcast_ref())
-    }
-}
-
-pub trait UpdateBase {
-    fn apply(self: Box<Self>, states: &mut StateRegistry);
-}