darkfi_money_contract/client/
mod.rs

1/* This file is part of DarkFi (https://dark.fi)
2 *
3 * Copyright (C) 2020-2026 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/// `Money::BurnV1` API
70pub mod burn_v1;
71
72/// `MoneyNote` holds the inner attributes of a `Coin`.
73///
74/// It does not store the public key since it's encrypted for that key,
75/// and so is not needed to infer the coin attributes.
76/// All other coin attributes must be present.
77#[derive(Debug, Clone, Eq, PartialEq, SerialEncodable, SerialDecodable)]
78pub struct MoneyNote {
79    /// Value of the coin
80    pub value: u64,
81    /// Token ID of the coin
82    pub token_id: TokenId,
83    /// Spend hook used for protocol-owned liquidity.
84    /// Specifies which contract owns this coin.
85    pub spend_hook: FuncId,
86    /// User data used by protocol when spend hook is enabled
87    pub user_data: pallas::Base,
88    /// Blinding factor for the coin
89    pub coin_blind: BaseBlind,
90    // TODO: look into removing these fields. We potentially don't need them [
91    /// Blinding factor for the value pedersen commitment
92    pub value_blind: ScalarBlind,
93    /// Blinding factor for the token ID pedersen commitment
94    pub token_blind: BaseBlind,
95    // ] ^ the receiver is not interested in the value commit / token commits.
96    // we just want to examine the coins in the outputs. The money::transfer() contract
97    // should ensure everything else is correct.
98    /// Attached memo (arbitrary data)
99    pub memo: Vec<u8>,
100}
101
102/// `OwnCoin` is a representation of `Coin` with its respective metadata.
103#[derive(Debug, Clone, Eq, PartialEq, SerialEncodable, SerialDecodable)]
104pub struct OwnCoin {
105    /// The coin hash
106    pub coin: Coin,
107    /// The attached `MoneyNote`
108    pub note: MoneyNote,
109    /// Coin's secret key
110    pub secret: SecretKey,
111    /// Coin's leaf position in the Merkle tree of coins
112    pub leaf_position: bridgetree::Position,
113}
114
115impl OwnCoin {
116    /// Derive the [`Nullifier`] for this [`OwnCoin`]
117    pub fn nullifier(&self) -> Nullifier {
118        Nullifier::from(poseidon_hash([self.secret.inner(), self.coin.inner()]))
119    }
120}
121
122impl Hash for OwnCoin {
123    fn hash<H: Hasher>(&self, state: &mut H) {
124        self.coin.inner().to_repr().hash(state);
125    }
126}
127
128pub fn compute_remainder_blind(
129    input_blinds: &[ScalarBlind],
130    output_blinds: &[ScalarBlind],
131) -> ScalarBlind {
132    let mut total = pallas::Scalar::ZERO;
133
134    for input_blind in input_blinds {
135        total += input_blind.inner();
136    }
137
138    for output_blind in output_blinds {
139        total -= output_blind.inner();
140    }
141
142    Blind(total)
143}