diff --git a/src/contract/dao/Cargo.toml b/src/contract/dao/Cargo.toml
index 996230e98..99f22ab22 100644
--- a/src/contract/dao/Cargo.toml
+++ b/src/contract/dao/Cargo.toml
@@ -25,7 +25,7 @@ rand = { version = "0.8.5", optional = true }
[dev-dependencies]
async-std = {version = "1.12.0", features = ["attributes"]}
darkfi = {path = "../../../", features = ["tx", "blockchain"]}
-darkfi-money-contract = { path = "../money", features = ["client"] }
+darkfi-money-contract = { path = "../money", features = ["client", "no-entrypoint"] }
simplelog = "0.12.0"
sled = "0.34.7"
sqlx = {version = "0.6.2", features = ["runtime-async-std-native-tls", "sqlite"]}
diff --git a/src/contract/dao/src/client.rs b/src/contract/dao/src/dao_client.rs
similarity index 100%
rename from src/contract/dao/src/client.rs
rename to src/contract/dao/src/dao_client.rs
diff --git a/src/contract/dao/src/lib.rs b/src/contract/dao/src/lib.rs
index be6037a8a..94b7a82cf 100644
--- a/src/contract/dao/src/lib.rs
+++ b/src/contract/dao/src/lib.rs
@@ -27,8 +27,12 @@ pub mod state;
pub mod note;
#[cfg(feature = "client")]
-/// Transaction building API for clients interacting with this contract
-pub mod client;
+/// Transaction building API for clients interacting with DAO contract
+pub mod dao_client;
+
+#[cfg(feature = "client")]
+/// Transaction building API for clients interacting with money contract
+pub mod money_client;
// These are the zkas circuit namespaces
pub const DAO_CONTRACT_ZKAS_DAO_MINT_NS: &str = "DaoMint";
diff --git a/src/contract/dao/src/money_client.rs b/src/contract/dao/src/money_client.rs
new file mode 100644
index 000000000..5e6c17954
--- /dev/null
+++ b/src/contract/dao/src/money_client.rs
@@ -0,0 +1,272 @@
+/* This file is part of DarkFi (https://dark.fi)
+ *
+ * Copyright (C) 2020-2022 Dyne.org foundation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+use chacha20poly1305::{AeadInPlace, ChaCha20Poly1305, KeyInit};
+use darkfi::{
+ consensus::leadcoin::LeadCoin,
+ zk::{
+ proof::{Proof, ProvingKey},
+ vm::ZkCircuit,
+ vm_stack::Witness,
+ },
+ zkas::ZkBinary,
+ ClientFailed, Error, Result,
+};
+use darkfi_sdk::{
+ crypto::{
+ constants::MERKLE_DEPTH,
+ diffie_hellman::{kdf_sapling, sapling_ka_agree},
+ pedersen::{pedersen_commitment_base, pedersen_commitment_u64, ValueBlind, ValueCommit},
+ poseidon_hash, Keypair, MerkleNode, Nullifier, PublicKey, SecretKey, TokenId,
+ },
+ incrementalmerkletree,
+ incrementalmerkletree::{bridgetree::BridgeTree, Hashable, Tree},
+ pasta::{
+ arithmetic::CurveAffine,
+ group::{
+ ff::{Field, PrimeField},
+ Curve,
+ },
+ pallas,
+ },
+};
+use darkfi_serial::{serialize, Decodable, Encodable, SerialDecodable, SerialEncodable};
+use halo2_proofs::circuit::Value;
+use log::{debug, error, info};
+use rand::rngs::OsRng;
+
+use darkfi_money_contract::{
+ client::{create_transfer_burn_proof, create_transfer_mint_proof, Note},
+ state::{ClearInput, Input, MoneyTransferParams, Output},
+};
+
+/*
+use darkfi::{
+ crypto::{
+ burn_proof::create_burn_proof,
+ mint_proof::create_mint_proof,
+ types::{
+ DrkCoinBlind, DrkSerial, DrkSpendHook, DrkUserData, DrkUserDataBlind, DrkValueBlind,
+ },
+ },
+ Result,
+};
+
+use crate::{
+ contract::money::{
+ 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: TokenId,
+ 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,
+ pub inputs: Vec,
+ pub outputs: Vec,
+}
+
+pub struct BuilderClearInputInfo {
+ pub value: u64,
+ pub token_id: TokenId,
+ pub signature_secret: SecretKey,
+}
+
+pub struct BuilderInputInfo {
+ pub leaf_position: incrementalmerkletree::Position,
+ pub merkle_path: Vec,
+ pub secret: SecretKey,
+ pub note: Note,
+ pub user_data_blind: pallas::Base,
+ pub value_blind: ValueBlind,
+ pub signature_secret: SecretKey,
+}
+
+pub struct BuilderOutputInfo {
+ pub value: u64,
+ pub token_id: TokenId,
+ pub public: PublicKey,
+ pub serial: pallas::Base,
+ pub coin_blind: pallas::Base,
+ pub spend_hook: pallas::Base,
+ pub user_data: pallas::Base,
+}
+
+impl Builder {
+ fn compute_remainder_blind(
+ clear_inputs: &[ClearInput],
+ input_blinds: &[ValueBlind],
+ output_blinds: &[ValueBlind],
+ ) -> ValueBlind {
+ let mut total = ValueBlind::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,
+ mint_zkbin: &ZkBinary,
+ mint_pk: &ProvingKey,
+ burn_zkbin: &ZkBinary,
+ burn_pk: &ProvingKey,
+ ) -> Result<(MoneyTransferParams, Vec)> {
+ assert!(self.clear_inputs.len() + self.inputs.len() > 0);
+
+ let mut clear_inputs = vec![];
+ let token_blind = ValueBlind::random(&mut OsRng);
+ for input in &self.clear_inputs {
+ let signature_public = PublicKey::from_secret(input.signature_secret);
+ let value_blind = ValueBlind::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);
+
+ // Note from the previous output
+ let note = input.note.clone();
+
+ let (proof, revealed) = create_transfer_burn_proof(
+ burn_zkbin,
+ 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(proof);
+
+ let input = Input {
+ value_commit: revealed.value_commit,
+ token_commit: revealed.token_commit,
+ nullifier: revealed.nullifier,
+ merkle_root: revealed.merkle_root,
+ spend_hook: revealed.spend_hook,
+ user_data_enc: revealed.user_data_enc,
+ signature_public: revealed.signature_public,
+ };
+ 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 {
+ ValueBlind::random(&mut OsRng)
+ };
+ output_blinds.push(value_blind);
+
+ let serial = output.serial;
+ let coin_blind = output.coin_blind;
+
+ let (proof, revealed) = create_transfer_mint_proof(
+ mint_zkbin,
+ mint_pk,
+ output.value,
+ output.token_id,
+ value_blind,
+ token_blind,
+ serial,
+ output.spend_hook,
+ output.user_data,
+ coin_blind,
+ output.public,
+ )?;
+
+ proofs.push(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,
+ memo: Vec::new(),
+ };
+
+ //let encrypted_note = note.encrypt(&output.public)?;
+ /*
+ let encrypted_note = note::encrypt(¬e, &output.public)?;
+
+ let output = Output { revealed, enc_note: encrypted_note };
+ 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 8f93ca162..7a8a7846f 100644
--- a/src/contract/dao/tests/integration.rs
+++ b/src/contract/dao/tests/integration.rs
@@ -28,7 +28,7 @@ use log::{debug, info};
use rand::rngs::OsRng;
use darkfi_dao_contract::{
- client::{build_dao_mint_tx, MerkleTree},
+ dao_client::{build_dao_mint_tx, MerkleTree},
DaoFunction,
};
@@ -60,11 +60,11 @@ async fn integration_test() -> Result<()> {
let mut th = DaoTestHarness::new().await?;
// Money parameters
- //let xdrk_supply = 1_000_000;
- //let xrdk_token_id = TokenId::from(pallas::Base::random(&mut OsRng));
+ let xdrk_supply = 1_000_000;
+ let xrdk_token_id = TokenId::from(pallas::Base::random(&mut OsRng));
// Governance token parameters
- //let gdrk_supply = 1_000_000;
+ let gdrk_supply = 1_000_000;
let gdrk_token_id = TokenId::from(pallas::Base::random(&mut OsRng));
// DAO parameters
@@ -131,7 +131,11 @@ async fn integration_test() -> Result<()> {
// =======================================================
debug!(target: "demo", "Stage 2. Minting treasury token");
+ // We use this to receive coins
+ //let mut cache = WalletCache::new();
+
let mut th = MoneyTestHarness::new().await?;
+ //let (params, proofs) = builder.build(&zk_bins)?;
Ok(())
}
diff --git a/src/contract/money/src/client.rs b/src/contract/money/src/client.rs
index 56bb48e44..adca60b62 100644
--- a/src/contract/money/src/client.rs
+++ b/src/contract/money/src/client.rs
@@ -47,12 +47,15 @@ use darkfi_sdk::{
incrementalmerkletree::{bridgetree::BridgeTree, Hashable, Tree},
pasta::{
arithmetic::CurveAffine,
- group::{ff::PrimeField, Curve},
+ group::{
+ ff::{Field, PrimeField},
+ Curve,
+ },
pallas,
},
};
use darkfi_serial::{serialize, Decodable, Encodable, SerialDecodable, SerialEncodable};
-use halo2_proofs::{arithmetic::Field, circuit::Value};
+use halo2_proofs::circuit::Value;
use log::{debug, error, info};
use rand::rngs::OsRng;
@@ -143,6 +146,11 @@ pub struct Note {
pub value: u64,
/// Token ID of the coin
pub token_id: TokenId,
+ /// Spend hook used for protocol owned liquidity.
+ /// Specifies which contract owns this coin.
+ pub spend_hook: pallas::Base,
+ /// User data used by protocol when spend hook is enabled.
+ pub user_data: pallas::Base,
/// Blinding factor for the coin bulla
pub coin_blind: pallas::Base,
/// Blinding factor for the value pedersen commitment
@@ -207,6 +215,9 @@ impl EncryptedNote {
}
}
+// TODO: we can put all these in an internal module like:
+// money_transfer::builder::ClearInputInfo
+
struct TransactionBuilderClearInputInfo {
pub value: u64,
pub token_id: TokenId,
@@ -226,7 +237,7 @@ struct TransactionBuilderOutputInfo {
pub public_key: PublicKey,
}
-struct TransferBurnRevealed {
+pub struct TransferBurnRevealed {
pub value_commit: ValueCommit,
pub token_commit: ValueCommit,
pub nullifier: Nullifier,
@@ -321,7 +332,7 @@ impl TransferBurnRevealed {
}
}
-struct TransferMintRevealed {
+pub struct TransferMintRevealed {
pub coin: Coin,
pub value_commit: ValueCommit,
pub token_commit: ValueCommit,
@@ -376,7 +387,7 @@ impl TransferMintRevealed {
}
#[allow(clippy::too_many_arguments)]
-fn create_transfer_mint_proof(
+pub fn create_transfer_mint_proof(
zkbin: &ZkBinary,
pk: &ProvingKey,
value: u64,
@@ -424,7 +435,7 @@ fn create_transfer_mint_proof(
}
#[allow(clippy::too_many_arguments)]
-fn create_transfer_burn_proof(
+pub fn create_transfer_burn_proof(
zkbin: &ZkBinary,
pk: &ProvingKey,
value: u64,
@@ -799,6 +810,8 @@ pub fn build_half_swap_tx(
serial,
value: output.value,
token_id: output.token_id,
+ spend_hook: pallas::Base::zero(),
+ user_data: pallas::Base::zero(),
coin_blind,
value_blind: value_recv_blind,
token_blind: token_recv_blind,
@@ -1025,6 +1038,8 @@ pub fn build_transfer_tx(
serial,
value: output.value,
token_id: output.token_id,
+ spend_hook: pallas::Base::zero(),
+ user_data: pallas::Base::zero(),
coin_blind,
value_blind,
token_blind,
@@ -1236,6 +1251,8 @@ pub fn build_unstake_tx(
serial,
value: coin.value,
token_id: token_id_recv,
+ spend_hook: pallas::Base::zero(),
+ user_data: pallas::Base::zero(),
coin_blind,
value_blind,
token_blind: token_recv_blind,
@@ -1290,6 +1307,8 @@ mod tests {
serial: pallas::Base::random(&mut OsRng),
value: 100,
token_id: TokenId::from(pallas::Base::random(&mut OsRng)),
+ spend_hook: pallas::Base::zero(),
+ user_data: pallas::Base::zero(),
coin_blind: pallas::Base::random(&mut OsRng),
value_blind: pallas::Scalar::random(&mut OsRng),
token_blind: pallas::Scalar::random(&mut OsRng),