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}