diff --git a/src/contract/dao/src/dao_client.rs b/src/contract/dao/src/dao_client.rs index d0a53a0d1..aac087707 100644 --- a/src/contract/dao/src/dao_client.rs +++ b/src/contract/dao/src/dao_client.rs @@ -26,6 +26,7 @@ use darkfi_sdk::{ coin::Coin, constants::MERKLE_DEPTH, poseidon_hash, MerkleNode, PublicKey, SecretKey, TokenId, }, + incrementalmerkletree, incrementalmerkletree::{bridgetree::BridgeTree, Tree}, pasta::pallas, }; @@ -33,17 +34,15 @@ use halo2_proofs::circuit::Value; use log::debug; use rand::rngs::OsRng; -use crate::{ - note::EncryptedNote2, - state::{DaoBulla, DaoMintParams}, -}; +use darkfi_money_contract::client::{EncryptedNote, Note}; + +use crate::state::{DaoBulla, DaoMintParams}; pub type MerkleTree = BridgeTree; -/* pub struct OwnCoin { pub coin: Coin, - pub note: money::transfer::wallet::Note, + pub note: Note, pub leaf_position: incrementalmerkletree::Position, } @@ -83,7 +82,7 @@ impl WalletCache { panic!("you forget to track() this secret!"); } - pub fn try_decrypt_note(&mut self, coin: Coin, ciphertext: &EncryptedNote2) { + pub fn try_decrypt_note(&mut self, coin: Coin, ciphertext: &EncryptedNote) { // Add the new coins to the Merkle tree let node = MerkleNode::from(coin.inner()); self.tree.append(&node); @@ -98,7 +97,6 @@ impl WalletCache { } } } -*/ struct DaoMintRevealed { pub bulla: DaoBulla, diff --git a/src/contract/dao/src/money_client.rs b/src/contract/dao/src/money_client.rs index 5e6c17954..19ff65e66 100644 --- a/src/contract/dao/src/money_client.rs +++ b/src/contract/dao/src/money_client.rs @@ -258,13 +258,16 @@ impl Builder { memo: Vec::new(), }; - //let encrypted_note = note.encrypt(&output.public)?; - /* - let encrypted_note = note::encrypt(¬e, &output.public)?; + let encrypted_note = note.encrypt(&output.public)?; - let output = Output { revealed, enc_note: encrypted_note }; + let output = Output { + value_commit: revealed.value_commit, + token_commit: revealed.token_commit, + coin: revealed.coin.inner(), + ciphertext: encrypted_note.ciphertext, + ephem_public: encrypted_note.ephem_public, + }; outputs.push(output); - */ } Ok((MoneyTransferParams { clear_inputs, inputs, outputs }, proofs)) diff --git a/src/contract/dao/tests/integration.rs b/src/contract/dao/tests/integration.rs index 7a8a7846f..89019717a 100644 --- a/src/contract/dao/tests/integration.rs +++ b/src/contract/dao/tests/integration.rs @@ -18,22 +18,29 @@ use darkfi::{tx::Transaction, Result}; use darkfi_sdk::{ - crypto::{constants::MERKLE_DEPTH, MerkleNode, TokenId}, + crypto::{ + coin::Coin, constants::MERKLE_DEPTH, contract_id::MONEY_CONTRACT_ID, poseidon_hash, + MerkleNode, TokenId, + }, incrementalmerkletree::{bridgetree::BridgeTree, Tree}, - pasta::{group::ff::Field, pallas}, + pasta::{ + arithmetic::CurveAffine, + group::{ff::Field, Curve}, + pallas, + }, tx::ContractCall, }; -use darkfi_serial::Encodable; +use darkfi_serial::{Decodable, Encodable}; use log::{debug, info}; use rand::rngs::OsRng; use darkfi_dao_contract::{ - dao_client::{build_dao_mint_tx, MerkleTree}, - DaoFunction, + dao_client::{build_dao_mint_tx, MerkleTree, WalletCache}, + money_client, DaoFunction, }; use darkfi_money_contract::{ - client::{build_half_swap_tx, build_transfer_tx, Coin, EncryptedNote, OwnCoin}, + client::{build_half_swap_tx, build_transfer_tx, EncryptedNote, OwnCoin}, state::MoneyTransferParams, MoneyFunction, }; @@ -57,11 +64,12 @@ use money_harness::{init_logger, MoneyTestHarness}; async fn integration_test() -> Result<()> { init_logger()?; - let mut th = DaoTestHarness::new().await?; + let mut dao_th = DaoTestHarness::new().await?; + let mut money_th = MoneyTestHarness::new().await?; // Money parameters let xdrk_supply = 1_000_000; - let xrdk_token_id = TokenId::from(pallas::Base::random(&mut OsRng)); + let xdrk_token_id = TokenId::from(pallas::Base::random(&mut OsRng)); // Governance token parameters let gdrk_supply = 1_000_000; @@ -73,6 +81,9 @@ async fn integration_test() -> Result<()> { let dao_approval_ratio_quot = 1; let dao_approval_ratio_base = 2; + // We use this to receive coins + let mut cache = WalletCache::new(); + // ======================================================= // Dao::Mint // @@ -91,11 +102,11 @@ async fn integration_test() -> Result<()> { dao_approval_ratio_quot, dao_approval_ratio_base, gdrk_token_id, - &th.dao_kp.public, + &dao_th.dao_kp.public, dao_bulla_blind, - &th.dao_kp.secret, - &th.dao_mint_zkbin, - &th.dao_mint_pk, + &dao_th.dao_kp.secret, + &dao_th.dao_mint_zkbin, + &dao_th.dao_mint_pk, )?; info!("[Alice] =========================================="); @@ -103,7 +114,7 @@ async fn integration_test() -> Result<()> { info!("[Alice] =========================================="); let mut data = vec![DaoFunction::Mint as u8]; params.encode(&mut data)?; - let calls = vec![ContractCall { contract_id: th.dao_contract_id, data }]; + let calls = vec![ContractCall { contract_id: dao_th.dao_contract_id, data }]; let proofs = vec![proofs]; let mut tx = Transaction { calls, proofs, signatures: vec![] }; let sigs = tx.create_sigs(&mut OsRng, &[])?; @@ -112,7 +123,7 @@ async fn integration_test() -> Result<()> { info!("[Alice] ==============================="); info!("[Alice] Executing Dao::Mint transaction"); info!("[Alice] ==============================="); - th.alice_state.read().await.verify_transactions(&[tx.clone()], true).await?; + dao_th.alice_state.read().await.verify_transactions(&[tx.clone()], true).await?; // TODO: Witness and add to wallet merkle tree? let mut dao_tree = MerkleTree::new(100); @@ -121,7 +132,8 @@ async fn integration_test() -> Result<()> { dao_tree.append(&node); dao_tree.witness().unwrap() }; - debug!(target: "demo", "Created DAO bulla: {:?}", params.dao_bulla.inner()); + let dao_bulla = params.dao_bulla; + debug!(target: "demo", "Created DAO bulla: {:?}", dao_bulla.inner()); // ======================================================= // Money::Transfer @@ -131,11 +143,98 @@ async fn integration_test() -> Result<()> { // ======================================================= debug!(target: "demo", "Stage 2. Minting treasury token"); + cache.track(dao_th.dao_kp.secret); + // We use this to receive coins //let mut cache = WalletCache::new(); - let mut th = MoneyTestHarness::new().await?; //let (params, proofs) = builder.build(&zk_bins)?; + // TODO: this should be the contract/func ID + let spend_hook = pallas::Base::from(110); + let user_data = dao_bulla.inner(); + + let builder = money_client::Builder { + clear_inputs: vec![money_client::BuilderClearInputInfo { + value: xdrk_supply, + token_id: xdrk_token_id, + signature_secret: money_th.faucet_kp.secret, + }], + inputs: vec![], + outputs: vec![money_client::BuilderOutputInfo { + value: xdrk_supply, + token_id: xdrk_token_id, + public: dao_th.dao_kp.public, + serial: pallas::Base::random(&mut OsRng), + coin_blind: pallas::Base::random(&mut OsRng), + spend_hook, + user_data, + }], + }; + let (params, proofs) = builder.build( + &money_th.mint_zkbin, + &money_th.mint_pk, + &money_th.burn_zkbin, + &money_th.burn_pk, + )?; + + let contract_id = *MONEY_CONTRACT_ID; + + let mut data = vec![MoneyFunction::Transfer as u8]; + params.encode(&mut data)?; + let calls = vec![ContractCall { contract_id, data }]; + let proofs = vec![proofs]; + let mut tx = Transaction { calls, proofs, signatures: vec![] }; + let sigs = tx.create_sigs(&mut OsRng, &vec![money_th.faucet_kp.secret])?; + tx.signatures = vec![sigs]; + + money_th.faucet_state.read().await.verify_transactions(&[tx.clone()], true).await?; + money_th.faucet_merkle_tree.append(&MerkleNode::from(params.outputs[0].coin)); + + // Wallet stuff + + // DAO reads the money received from the encrypted note + { + assert_eq!(tx.calls.len(), 1); + let calldata = &tx.calls[0].data; + let params_data = &calldata[1..]; + let params: MoneyTransferParams = Decodable::decode(params_data)?; + + for output in params.outputs { + let coin = output.coin; + let enc_note = + EncryptedNote { ciphertext: output.ciphertext, ephem_public: output.ephem_public }; + + let coin = Coin(coin); + cache.try_decrypt_note(coin, &enc_note); + } + } + + let mut recv_coins = cache.get_received(&dao_th.dao_kp.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_th.dao_kp.public.inner().to_affine().coordinates().unwrap(); + let coin = poseidon_hash::<8>([ + *coords.x(), + *coords.y(), + pallas::Base::from(treasury_note.value), + treasury_note.token_id.inner(), + 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, spend_hook); + assert_eq!(treasury_note.user_data, dao_bulla.inner()); + + debug!("DAO received a coin worth {} xDRK", treasury_note.value); + + /////////////////////////////////////////////////// Ok(()) } diff --git a/src/contract/dao/tests/money_harness.rs b/src/contract/dao/tests/money_harness.rs new file mode 120000 index 000000000..ad52e82a8 --- /dev/null +++ b/src/contract/dao/tests/money_harness.rs @@ -0,0 +1 @@ +../../money/tests/harness.rs \ No newline at end of file diff --git a/src/contract/money/src/client.rs b/src/contract/money/src/client.rs index adca60b62..56011db08 100644 --- a/src/contract/money/src/client.rs +++ b/src/contract/money/src/client.rs @@ -98,7 +98,7 @@ pub const AEAD_TAG_SIZE: usize = 16; /// The `Coin` is represented as a base field element. #[derive(Debug, Clone, Copy, Eq, PartialEq, SerialEncodable, SerialDecodable)] -pub struct Coin(pallas::Base); +pub struct Coin(pub pallas::Base); impl Coin { /// Reference the raw inner base field element diff --git a/src/sdk/src/crypto/coin.rs b/src/sdk/src/crypto/coin.rs index 27f825bbf..150edaf61 100644 --- a/src/sdk/src/crypto/coin.rs +++ b/src/sdk/src/crypto/coin.rs @@ -25,7 +25,7 @@ use pasta_curves::{group::ff::PrimeField, pallas}; /// The `Coin` is represented as a base field element. #[repr(C)] #[derive(Debug, Clone, Copy, Eq, PartialEq, SerialEncodable, SerialDecodable)] -pub struct Coin(pallas::Base); +pub struct Coin(pub pallas::Base); impl Coin { /// Reference the raw inner base field element