darkfi_money_contract/model/
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
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    /// Marker if the input used is transaction-local
152    pub tx_local: bool,
153}
154// ANCHOR_END: money-input
155
156#[derive(Clone, Debug, PartialEq, SerialEncodable, SerialDecodable)]
157// ANCHOR: money-output
158/// A contract call's anonymous output
159pub struct Output {
160    /// Pedersen commitment for the output's value
161    pub value_commit: pallas::Point,
162    /// Commitment for the output's token ID
163    pub token_commit: pallas::Base,
164    /// Minted coin
165    pub coin: Coin,
166    /// AEAD encrypted note
167    pub note: AeadEncryptedNote,
168    /// Marker if the output used is transaction-local
169    pub tx_local: bool,
170}
171// ANCHOR_END: money-output
172
173/// Parameters for `Money::Fee`
174#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
175pub struct MoneyFeeParamsV1 {
176    /// Anonymous input
177    pub input: Input,
178    /// Anonymous outputs
179    pub output: Output,
180    /// Fee value blind
181    pub fee_value_blind: ScalarBlind,
182    /// Token ID blind
183    pub token_blind: BaseBlind,
184}
185
186/// State update for `Money::Fee`
187#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
188pub struct MoneyFeeUpdateV1 {
189    /// Revealed nullifier
190    pub nullifier: Nullifier,
191    /// Minted coin
192    pub coin: Coin,
193    /// Marker whether the output will be used tx-local
194    pub tx_local: bool,
195    /// Block height the fee was verified against
196    pub height: u32,
197    /// Height accumulated fee paid
198    pub fee: u64,
199}
200
201#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
202// ANCHOR: money-params
203/// Parameters for `Money::Transfer` and `Money::OtcSwap`
204pub struct MoneyTransferParamsV1 {
205    /// Anonymous inputs
206    pub inputs: Vec<Input>,
207    /// Anonymous outputs
208    pub outputs: Vec<Output>,
209}
210// ANCHOR_END: money-params
211
212/// State update for `Money::Transfer` and `Money::OtcSwap`
213#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
214pub struct MoneyTransferUpdateV1 {
215    /// Revealed nullifiers
216    pub nullifiers: Vec<Nullifier>,
217    /// Minted global-state coins
218    pub global_coins: Vec<Coin>,
219    /// Minted transaction-local-state coins
220    pub local_coins: Vec<Coin>,
221}
222
223/// Parameters for `Money::GenesisMint`
224#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
225pub struct MoneyGenesisMintParamsV1 {
226    /// Clear input
227    pub input: ClearInput,
228    /// Anonymous outputs
229    pub outputs: Vec<Output>,
230}
231
232/// State update for `Money::GenesisMint`
233#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
234pub struct MoneyGenesisMintUpdateV1 {
235    /// The newly minted coins
236    pub coins: Vec<Coin>,
237}
238
239/// Parameters for `Money::TokenMint`
240#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
241pub struct MoneyTokenMintParamsV1 {
242    /// The newly minted coin
243    pub coin: Coin,
244}
245
246/// State update for `Money::TokenMint`
247#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
248pub struct MoneyTokenMintUpdateV1 {
249    /// The newly minted coin
250    pub coin: Coin,
251}
252
253/// Parameters for `Money::AuthTokenMint`
254#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
255pub struct MoneyAuthTokenMintParamsV1 {
256    pub token_id: TokenId,
257    pub enc_note: AeadEncryptedNote,
258    pub mint_pubkey: PublicKey,
259}
260
261/// State update for `Money::AuthTokenMint`
262#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
263pub struct MoneyAuthTokenMintUpdateV1 {}
264
265/// Parameters for `Money::AuthTokenFreeze`
266#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
267pub struct MoneyAuthTokenFreezeParamsV1 {
268    /// Mint authority public key
269    ///
270    /// We use this to derive the token ID and verify the signature.
271    pub mint_public: PublicKey,
272    pub token_id: TokenId,
273}
274
275/// State update for `Money::AuthTokenFreeze`
276#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
277pub struct MoneyAuthTokenFreezeUpdateV1 {
278    pub token_id: TokenId,
279}
280
281/// Parameters for `Money::BurnV1`
282///
283/// Burns (destroys) coins, removing value from circulation permanently.
284/// The call has inputs but no outputs; the value committed in the inputs
285/// is destroyed. All inputs must use the same token commitment.
286#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
287pub struct MoneyBurnParamsV1 {
288    /// Anonymous inputs
289    pub inputs: Vec<Input>,
290}
291
292/// State update for `Money::BurnV1`
293#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
294pub struct MoneyBurnUpdateV1 {
295    /// Revealed nullifiers from the burned coins
296    pub nullifiers: Vec<Nullifier>,
297}
298
299/// Parameters for `Money::PoWReward`
300#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
301pub struct MoneyPoWRewardParamsV1 {
302    /// Clear input
303    pub input: ClearInput,
304    /// Anonymous output
305    pub output: Output,
306}
307
308/// State update for `Money::PoWReward`
309#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
310pub struct MoneyPoWRewardUpdateV1 {
311    /// The newly minted coin
312    pub coin: Coin,
313    /// Block height the call was verified against
314    pub height: u32,
315}