1/* This file is part of DarkFi (https://dark.fi)
2 *
3 * Copyright (C) 2020-2025 Dyne.org foundation
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as
7 * published by the Free Software Foundation, either version 3 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 */
1819use darkfi::{
20 tx::{ContractCallLeaf, Transaction, TransactionBuilder},
21Result,
22};
23use darkfi_money_contract::{
24 client::{genesis_mint_v1::GenesisMintCallBuilder, MoneyNote, OwnCoin},
25 model::MoneyGenesisMintParamsV1,
26 MoneyFunction, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
27};
28use darkfi_sdk::{
29 crypto::{contract_id::MONEY_CONTRACT_ID, FuncId, MerkleNode},
30 pasta::pallas,
31 ContractCall,
32};
33use darkfi_serial::AsyncEncodable;
34use log::debug;
3536use super::{Holder, TestHarness};
3738impl TestHarness {
39/// Create a `Money::GenesisMint` transaction for a given [`Holder`].
40 ///
41 /// Returns the created [`Transaction`] and its parameters.
42pub async fn genesis_mint(
43&mut self,
44 holder: &Holder,
45 amounts: &[u64],
46 spend_hook: Option<FuncId>,
47 user_data: Option<pallas::Base>,
48 ) -> Result<(Transaction, MoneyGenesisMintParamsV1)> {
49let wallet = self.holders.get(holder).unwrap();
5051let (mint_pk, mint_zkbin) = self.proving_keys.get(MONEY_CONTRACT_ZKAS_MINT_NS_V1).unwrap();
5253// Build the contract call
54let builder = GenesisMintCallBuilder {
55 signature_public: wallet.keypair.public,
56 amounts: amounts.to_vec(),
57 recipient: None,
58 spend_hook,
59 user_data,
60 mint_zkbin: mint_zkbin.clone(),
61 mint_pk: mint_pk.clone(),
62 };
6364let debris = builder.build()?;
6566// Encode and build the transaction
67let mut data = vec![MoneyFunction::GenesisMintV1 as u8];
68 debris.params.encode_async(&mut data).await?;
69let call = ContractCall { contract_id: *MONEY_CONTRACT_ID, data };
70let mut tx_builder =
71 TransactionBuilder::new(ContractCallLeaf { call, proofs: debris.proofs }, vec![])?;
72let mut tx = tx_builder.build()?;
73let sigs = tx.create_sigs(&[wallet.keypair.secret])?;
74 tx.signatures = vec![sigs];
7576Ok((tx, debris.params))
77 }
7879/// Execute the [`Transaction`] created by `genesis_mint()`.
80 ///
81 /// Returns any found [`OwnCoin`]s.
82pub async fn execute_genesis_mint_tx(
83&mut self,
84 holder: &Holder,
85 tx: Transaction,
86 params: &MoneyGenesisMintParamsV1,
87 block_height: u32,
88 append: bool,
89 ) -> Result<Vec<OwnCoin>> {
90let wallet = self.holders.get_mut(holder).unwrap();
9192// Execute the transaction
93wallet.add_transaction("money::genesis_mint", tx, block_height).await?;
9495if !append {
96return Ok(vec![])
97 }
9899// Iterate over call outputs to find any new OwnCoins
100let mut found_owncoins = vec![];
101for output in ¶ms.outputs {
102 wallet.money_merkle_tree.append(MerkleNode::from(output.coin.inner()));
103104// Attempt to decrypt the output note to see if this is a coin for the holder.
105let Ok(note) = output.note.decrypt::<MoneyNote>(&wallet.keypair.secret) else {
106continue
107};
108109let owncoin = OwnCoin {
110 coin: output.coin,
111 note: note.clone(),
112 secret: wallet.keypair.secret,
113 leaf_position: wallet.money_merkle_tree.mark().unwrap(),
114 };
115116debug!("Found new OwnCoin({}) for {:?}", owncoin.coin, holder);
117 wallet.unspent_money_coins.push(owncoin.clone());
118 found_owncoins.push(owncoin);
119 }
120121Ok(found_owncoins)
122 }
123}