darkfi_money_contract/client/
mod.rs

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 */
18
19//! Contract Client API
20//!
21//! This module implements the client-side API for this contract's interaction.
22//! What we basically do here is implement an API that creates the necessary
23//! structures and is able to export them to create a DarkFi transaction
24//! object that can be broadcasted to the network when we want to make a
25//! payment with some coins in our wallet.
26//!
27//! Note that this API does not involve any wallet interaction, but only takes
28//! the necessary objects provided by the caller. This is intentional, so we
29//! are able to abstract away any wallet interfaces to client implementations.
30
31use std::hash::{Hash, Hasher};
32
33use darkfi_sdk::{
34    bridgetree,
35    crypto::{
36        pasta_prelude::{Field, PrimeField},
37        poseidon_hash, BaseBlind, Blind, FuncId, ScalarBlind, SecretKey,
38    },
39    pasta::pallas,
40};
41use darkfi_serial::{async_trait, SerialDecodable, SerialEncodable};
42
43use crate::model::{Coin, Nullifier, TokenId};
44
45/// `Money::FeeV1` API
46pub mod fee_v1;
47
48/// `Money::GenesisMintV1` API
49pub mod genesis_mint_v1;
50
51/// `Money::PoWRewardV1` API
52pub mod pow_reward_v1;
53
54/// `Money::TransferV1` API
55pub mod transfer_v1;
56
57/// `Money::OtcSwapV1` API
58pub mod swap_v1;
59
60/// `Money::AuthTokenMintV1` API
61pub mod auth_token_mint_v1;
62
63/// `Money::AuthTokenFreezeV1` API
64pub mod auth_token_freeze_v1;
65
66/// `Money::TokenMintV1` API
67pub mod token_mint_v1;
68
69/// `MoneyNote` holds the inner attributes of a `Coin`.
70///
71/// It does not store the public key since it's encrypted for that key,
72/// and so is not needed to infer the coin attributes.
73/// All other coin attributes must be present.
74#[derive(Debug, Clone, Eq, PartialEq, SerialEncodable, SerialDecodable)]
75pub struct MoneyNote {
76    /// Value of the coin
77    pub value: u64,
78    /// Token ID of the coin
79    pub token_id: TokenId,
80    /// Spend hook used for protocol-owned liquidity.
81    /// Specifies which contract owns this coin.
82    pub spend_hook: FuncId,
83    /// User data used by protocol when spend hook is enabled
84    pub user_data: pallas::Base,
85    /// Blinding factor for the coin
86    pub coin_blind: BaseBlind,
87    // TODO: look into removing these fields. We potentially don't need them [
88    /// Blinding factor for the value pedersen commitment
89    pub value_blind: ScalarBlind,
90    /// Blinding factor for the token ID pedersen commitment
91    pub token_blind: BaseBlind,
92    // ] ^ the receiver is not interested in the value commit / token commits.
93    // we just want to examine the coins in the outputs. The money::transfer() contract
94    // should ensure everything else is correct.
95    /// Attached memo (arbitrary data)
96    pub memo: Vec<u8>,
97}
98
99/// `OwnCoin` is a representation of `Coin` with its respective metadata.
100#[derive(Debug, Clone, Eq, PartialEq, SerialEncodable, SerialDecodable)]
101pub struct OwnCoin {
102    /// The coin hash
103    pub coin: Coin,
104    /// The attached `MoneyNote`
105    pub note: MoneyNote,
106    /// Coin's secret key
107    pub secret: SecretKey,
108    /// Coin's leaf position in the Merkle tree of coins
109    pub leaf_position: bridgetree::Position,
110}
111
112impl OwnCoin {
113    /// Derive the [`Nullifier`] for this [`OwnCoin`]
114    pub fn nullifier(&self) -> Nullifier {
115        Nullifier::from(poseidon_hash([self.secret.inner(), self.coin.inner()]))
116    }
117}
118
119impl Hash for OwnCoin {
120    fn hash<H: Hasher>(&self, state: &mut H) {
121        self.coin.inner().to_repr().hash(state);
122    }
123}
124
125pub fn compute_remainder_blind(
126    input_blinds: &[ScalarBlind],
127    output_blinds: &[ScalarBlind],
128) -> ScalarBlind {
129    let mut total = pallas::Scalar::ZERO;
130
131    for input_blind in input_blinds {
132        total += input_blind.inner();
133    }
134
135    for output_blind in output_blinds {
136        total -= output_blind.inner();
137    }
138
139    Blind(total)
140}