use log::debug; use rand::rngs::OsRng; use halo2_proofs::circuit::Value; use pasta_curves::{arithmetic::CurveAffine, group::Curve, pallas}; use darkfi::{ crypto::{ keypair::SecretKey, util::{pedersen_commitment_u64, poseidon_hash}, Proof, }, zk::vm::{Witness, ZkCircuit}, }; use crate::{ contract::dao_contract::{ exec::validate::CallData, mint::wallet::DaoParams, propose::wallet::Proposal, CONTRACT_ID, }, util::{FuncCall, ZkContractInfo, ZkContractTable}, }; pub struct Builder { pub proposal: Proposal, pub dao: DaoParams, pub yes_votes_value: u64, pub all_votes_value: u64, pub yes_votes_blind: pallas::Scalar, pub all_votes_blind: pallas::Scalar, pub user_serial: pallas::Base, pub user_coin_blind: pallas::Base, pub dao_serial: pallas::Base, pub dao_coin_blind: pallas::Base, pub input_value: u64, pub input_value_blind: pallas::Scalar, pub hook_dao_exec: pallas::Base, pub signature_secret: SecretKey, } impl Builder { pub fn build(self, zk_bins: &ZkContractTable) -> FuncCall { debug!(target: "dao_contract::exec::wallet::Builder", "build()"); debug!(target: "dao_contract::exec::wallet", "proposalserial{:?}", self.proposal.serial); let mut proofs = vec![]; 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 user_spend_hook = pallas::Base::from(0); let user_data = pallas::Base::from(0); let input_value = pallas::Base::from(self.input_value); let change = input_value - proposal_amount; 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 coin_0 = poseidon_hash::<8>([ *proposal_dest_coords.x(), *proposal_dest_coords.y(), proposal_amount, self.proposal.token_id, self.proposal.serial, user_spend_hook, user_data, self.proposal.blind, ]); let coin_1 = poseidon_hash::<8>([ *dao_pubkey_coords.x(), *dao_pubkey_coords.y(), change, self.proposal.token_id, self.dao_serial, self.hook_dao_exec, proposal_bulla, self.dao_coin_blind, ]); let yes_votes_commit = pedersen_commitment_u64(self.yes_votes_value, self.yes_votes_blind); let yes_votes_commit_coords = yes_votes_commit.to_affine().coordinates().unwrap(); let all_votes_commit = pedersen_commitment_u64(self.all_votes_value, self.all_votes_blind); let all_votes_commit_coords = all_votes_commit.to_affine().coordinates().unwrap(); let input_value_commit = pedersen_commitment_u64(self.input_value, self.input_value_blind); let input_value_commit_coords = input_value_commit.to_affine().coordinates().unwrap(); let zk_info = zk_bins.lookup(&"dao-exec".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)), // votes Witness::Base(Value::known(pallas::Base::from(self.yes_votes_value))), Witness::Base(Value::known(pallas::Base::from(self.all_votes_value))), Witness::Scalar(Value::known(self.yes_votes_blind)), Witness::Scalar(Value::known(self.all_votes_blind)), // outputs + inputs Witness::Base(Value::known(self.user_serial)), Witness::Base(Value::known(self.user_coin_blind)), Witness::Base(Value::known(self.dao_serial)), Witness::Base(Value::known(self.dao_coin_blind)), Witness::Base(Value::known(input_value)), Witness::Scalar(Value::known(self.input_value_blind)), // misc Witness::Base(Value::known(self.hook_dao_exec)), Witness::Base(Value::known(user_spend_hook)), Witness::Base(Value::known(user_data)), ]; let public_inputs = vec![ proposal_bulla, coin_0, coin_1, *yes_votes_commit_coords.x(), *yes_votes_commit_coords.y(), *all_votes_commit_coords.x(), *all_votes_commit_coords.y(), *input_value_commit_coords.x(), *input_value_commit_coords.y(), self.hook_dao_exec, user_spend_hook, user_data, ]; let circuit = ZkCircuit::new(prover_witnesses, zk_bin); debug!(target: "example_contract::foo::wallet::Builder", "input_proof Proof::create()"); let proving_key = &zk_info.proving_key; let input_proof = Proof::create(proving_key, &[circuit], &public_inputs, &mut OsRng) .expect("DAO::exec() proving error!)"); proofs.push(input_proof); let call_data = CallData { proposal: proposal_bulla, coin_0, coin_1, yes_votes_commit, all_votes_commit, input_value_commit, }; FuncCall { contract_id: *CONTRACT_ID, func_id: *super::FUNC_ID, call_data: Box::new(call_data), proofs, } } }