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}