darkfi_money_contract/model/
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
19use darkfi_sdk::{
20    crypto::{
21        note::AeadEncryptedNote, pasta_prelude::PrimeField, poseidon_hash, BaseBlind, FuncId,
22        MerkleNode, PublicKey, ScalarBlind,
23    },
24    error::ContractError,
25    pasta::pallas,
26};
27use darkfi_serial::{SerialDecodable, SerialEncodable};
28
29#[cfg(feature = "client")]
30use darkfi_serial::async_trait;
31
32/// Nullifier definitions
33pub mod nullifier;
34pub use nullifier::Nullifier;
35
36/// Token ID definitions and methods
37pub mod token_id;
38pub use token_id::{TokenId, DARK_TOKEN_ID};
39
40/// A `Coin` represented in the Money state
41#[derive(Debug, Clone, Copy, Eq, PartialEq, SerialEncodable, SerialDecodable)]
42pub struct Coin(pallas::Base);
43
44impl Coin {
45    /// Reference the raw inner base field element
46    pub fn inner(&self) -> pallas::Base {
47        self.0
48    }
49
50    /// Create a `Coin` object from given bytes, erroring if the input
51    /// bytes are noncanonical.
52    pub fn from_bytes(x: [u8; 32]) -> Result<Self, ContractError> {
53        match pallas::Base::from_repr(x).into() {
54            Some(v) => Ok(Self(v)),
55            None => {
56                Err(ContractError::IoError("Failed to instantiate Coin from bytes".to_string()))
57            }
58        }
59    }
60
61    /// Convert the `Coin` type into 32 raw bytes
62    pub fn to_bytes(&self) -> [u8; 32] {
63        self.0.to_repr()
64    }
65}
66
67use core::str::FromStr;
68darkfi_sdk::fp_from_bs58!(Coin);
69darkfi_sdk::fp_to_bs58!(Coin);
70darkfi_sdk::ty_from_fp!(Coin);
71
72#[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
73// ANCHOR: coin-attributes
74pub struct CoinAttributes {
75    pub public_key: PublicKey,
76    pub value: u64,
77    pub token_id: TokenId,
78    pub spend_hook: FuncId,
79    pub user_data: pallas::Base,
80    /// Simultaneously blinds the coin and ensures uniqueness
81    pub blind: BaseBlind,
82}
83// ANCHOR_END: coin-attributes
84
85impl CoinAttributes {
86    pub fn to_coin(&self) -> Coin {
87        let (pub_x, pub_y) = self.public_key.xy();
88        let coin = poseidon_hash([
89            pub_x,
90            pub_y,
91            pallas::Base::from(self.value),
92            self.token_id.inner(),
93            self.spend_hook.inner(),
94            self.user_data,
95            self.blind.inner(),
96        ]);
97        Coin(coin)
98    }
99}
100
101#[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
102pub struct TokenAttributes {
103    pub auth_parent: FuncId,
104    pub user_data: pallas::Base,
105    pub blind: BaseBlind,
106}
107
108impl TokenAttributes {
109    pub fn to_token_id(&self) -> TokenId {
110        let token_id =
111            poseidon_hash([self.auth_parent.inner(), self.user_data, self.blind.inner()]);
112        TokenId::from(token_id)
113    }
114}
115
116#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
117// ANCHOR: money-clear-input
118/// A contract call's clear input
119pub struct ClearInput {
120    /// Input's value (amount)
121    pub value: u64,
122    /// Input's token ID
123    pub token_id: TokenId,
124    /// Blinding factor for `value`
125    pub value_blind: ScalarBlind,
126    /// Blinding factor for `token_id`
127    pub token_blind: BaseBlind,
128    /// Public key for the signature
129    pub signature_public: PublicKey,
130}
131// ANCHOR_END: money-clear-input
132
133#[derive(Clone, Debug, PartialEq, SerialEncodable, SerialDecodable)]
134// ANCHOR: money-input
135/// A contract call's anonymous input
136pub struct Input {
137    /// Pedersen commitment for the input's value
138    pub value_commit: pallas::Point,
139    /// Commitment for the input's token ID
140    pub token_commit: pallas::Base,
141    /// Revealed nullifier
142    pub nullifier: Nullifier,
143    /// Revealed Merkle root
144    pub merkle_root: MerkleNode,
145    /// Encrypted user data field. An encrypted commitment to arbitrary data.
146    /// When spend hook is nonzero, then this field may be used to pass data
147    /// to the invoked contract.
148    pub user_data_enc: pallas::Base,
149    /// Public key for the signature
150    pub signature_public: PublicKey,
151}
152// ANCHOR_END: money-input
153
154#[derive(Clone, Debug, PartialEq, SerialEncodable, SerialDecodable)]
155// ANCHOR: money-output
156/// A contract call's anonymous output
157pub struct Output {
158    /// Pedersen commitment for the output's value
159    pub value_commit: pallas::Point,
160    /// Commitment for the output's token ID
161    pub token_commit: pallas::Base,
162    /// Minted coin
163    pub coin: Coin,
164    /// AEAD encrypted note
165    pub note: AeadEncryptedNote,
166}
167// ANCHOR_END: money-output
168
169/// Parameters for `Money::Fee`
170#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
171pub struct MoneyFeeParamsV1 {
172    /// Anonymous input
173    pub input: Input,
174    /// Anonymous outputs
175    pub output: Output,
176    /// Fee value blind
177    pub fee_value_blind: ScalarBlind,
178    /// Token ID blind
179    pub token_blind: BaseBlind,
180}
181
182/// State update for `Money::Fee`
183#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
184pub struct MoneyFeeUpdateV1 {
185    /// Revealed nullifier
186    pub nullifier: Nullifier,
187    /// Minted coin
188    pub coin: Coin,
189    /// Block height the fee was verified against
190    pub height: u32,
191    /// Height accumulated fee paid
192    pub fee: u64,
193}
194
195#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
196// ANCHOR: money-params
197/// Parameters for `Money::Transfer` and `Money::OtcSwap`
198pub struct MoneyTransferParamsV1 {
199    /// Anonymous inputs
200    pub inputs: Vec<Input>,
201    /// Anonymous outputs
202    pub outputs: Vec<Output>,
203}
204// ANCHOR_END: money-params
205
206/// State update for `Money::Transfer` and `Money::OtcSwap`
207#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
208pub struct MoneyTransferUpdateV1 {
209    /// Revealed nullifiers
210    pub nullifiers: Vec<Nullifier>,
211    /// Minted coins
212    pub coins: Vec<Coin>,
213}
214
215/// Parameters for `Money::GenesisMint`
216#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
217pub struct MoneyGenesisMintParamsV1 {
218    /// Clear input
219    pub input: ClearInput,
220    /// Anonymous outputs
221    pub outputs: Vec<Output>,
222}
223
224/// State update for `Money::GenesisMint`
225#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
226pub struct MoneyGenesisMintUpdateV1 {
227    /// The newly minted coins
228    pub coins: Vec<Coin>,
229}
230
231/// Parameters for `Money::TokenMint`
232#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
233pub struct MoneyTokenMintParamsV1 {
234    /// The newly minted coin
235    pub coin: Coin,
236}
237
238/// State update for `Money::TokenMint`
239#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
240pub struct MoneyTokenMintUpdateV1 {
241    /// The newly minted coin
242    pub coin: Coin,
243}
244
245/// Parameters for `Money::AuthTokenMint`
246#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
247pub struct MoneyAuthTokenMintParamsV1 {
248    pub token_id: TokenId,
249    pub enc_note: AeadEncryptedNote,
250    pub mint_pubkey: PublicKey,
251}
252
253/// State update for `Money::AuthTokenMint`
254#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
255pub struct MoneyAuthTokenMintUpdateV1 {}
256
257/// Parameters for `Money::AuthTokenFreeze`
258#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
259pub struct MoneyAuthTokenFreezeParamsV1 {
260    /// Mint authority public key
261    ///
262    /// We use this to derive the token ID and verify the signature.
263    pub mint_public: PublicKey,
264    pub token_id: TokenId,
265}
266
267/// State update for `Money::AuthTokenFreeze`
268#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
269pub struct MoneyAuthTokenFreezeUpdateV1 {
270    pub token_id: TokenId,
271}
272
273/// Parameters for `Money::PoWReward`
274#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
275pub struct MoneyPoWRewardParamsV1 {
276    /// Clear input
277    pub input: ClearInput,
278    /// Anonymous output
279    pub output: Output,
280}
281
282/// State update for `Money::PoWReward`
283#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
284pub struct MoneyPoWRewardUpdateV1 {
285    /// The newly minted coin
286    pub coin: Coin,
287    /// Block height the call was verified against
288    pub height: u32,
289}