Procházet zdrojové kódy

contract/money: Remove OtcSwap, now works with pure Transfer

skoupidi před 2 měsíci
rodič
revize
c84812df29

+ 0 - 21
bin/drk/src/money.rs

@@ -781,20 +781,6 @@ impl Drk {
                     }
                 }
             }
-            MoneyFunction::OtcSwapV1 => {
-                scan_cache.log(String::from("[parse_money_call] Found Money::OtcSwapV1 call"));
-                let params: MoneyTransferParamsV1 = deserialize_async(&data[1..]).await?;
-
-                for input in params.inputs {
-                    nullifiers.push(input.nullifier);
-                }
-
-                for output in params.outputs {
-                    if !output.tx_local {
-                        coins.push((output.coin, output.note, false));
-                    }
-                }
-            }
             MoneyFunction::AuthTokenMintV1 => {
                 scan_cache
                     .log(String::from("[parse_money_call] Found Money::AuthTokenMintV1 call"));
@@ -1071,13 +1057,6 @@ impl Drk {
                     nullifiers.push(input.nullifier);
                 }
             }
-            MoneyFunction::OtcSwapV1 => {
-                let params: MoneyTransferParamsV1 = deserialize_async(&data[1..]).await?;
-
-                for input in params.inputs {
-                    nullifiers.push(input.nullifier);
-                }
-            }
             _ => { /* Do nothing */ }
         }
 

+ 1 - 1
bin/drk/src/swap.rs

@@ -272,7 +272,7 @@ impl Drk {
             debris.proofs[1].clone(),
         ];
 
-        let mut data = vec![MoneyFunction::OtcSwapV1 as u8];
+        let mut data = vec![MoneyFunction::TransferV1 as u8];
         full_params.encode_async(&mut data).await?;
         let call = ContractCall { contract_id: *MONEY_CONTRACT_ID, data };
         let mut tx_builder =

+ 3 - 2
src/contract/money/src/client/swap_v1.rs

@@ -51,7 +51,8 @@ pub struct SwapCallDebris {
     pub signature_secret: SecretKey,
 }
 
-/// Struct holding necessary information to build a `Money::OtcSwapV1` contract call.
+/// Struct holding necessary information to build a `Money::TransferV1` contract call
+/// for an atomic swap.
 /// This is used to build half of the swap transaction, so both parties have to build
 /// their halves and combine them.
 pub struct SwapCallBuilder {
@@ -94,7 +95,7 @@ pub struct SwapCallBuilder {
 
 impl SwapCallBuilder {
     pub fn build(&self) -> Result<SwapCallDebris> {
-        debug!(target: "contract::money::client::swap", "Building half of Money::OtcSwapV1 contract call");
+        debug!(target: "contract::money::client::swap", "Building half of Money::TransferV1 contract call");
         if self.value_send == 0 {
             error!(target: "contract::money::client::swap", "Error: Value send is 0");
             return Err(ClientFailed::InvalidAmount(self.value_send).into())

+ 0 - 16
src/contract/money/src/entrypoint.rs

@@ -67,13 +67,6 @@ use transfer_v1::{
     money_transfer_process_update_v1,
 };
 
-/// `Money::OtcSwap` functions
-mod swap_v1;
-use swap_v1::{
-    money_otcswap_get_metadata_v1, money_otcswap_process_instruction_v1,
-    money_otcswap_process_update_v1,
-};
-
 /// `Money::AuthTokenMint` functions
 mod auth_token_mint_v1;
 use auth_token_mint_v1::{
@@ -250,7 +243,6 @@ fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult {
         MoneyFunction::GenesisMintV1 => money_genesis_mint_get_metadata_v1(cid, call_idx, calls)?,
         MoneyFunction::PoWRewardV1 => money_pow_reward_get_metadata_v1(cid, call_idx, calls)?,
         MoneyFunction::TransferV1 => money_transfer_get_metadata_v1(cid, call_idx, calls)?,
-        MoneyFunction::OtcSwapV1 => money_otcswap_get_metadata_v1(cid, call_idx, calls)?,
         MoneyFunction::AuthTokenMintV1 => {
             money_auth_token_mint_get_metadata_v1(cid, call_idx, calls)?
         }
@@ -289,7 +281,6 @@ fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
             money_pow_reward_process_instruction_v1(cid, call_idx, calls)?
         }
         MoneyFunction::TransferV1 => money_transfer_process_instruction_v1(cid, call_idx, calls)?,
-        MoneyFunction::OtcSwapV1 => money_otcswap_process_instruction_v1(cid, call_idx, calls)?,
         MoneyFunction::AuthTokenMintV1 => {
             money_auth_token_mint_process_instruction_v1(cid, call_idx, calls)?
         }
@@ -332,13 +323,6 @@ fn process_update(cid: ContractId, update_data: &[u8]) -> ContractResult {
             Ok(money_transfer_process_update_v1(cid, update)?)
         }
 
-        MoneyFunction::OtcSwapV1 => {
-            // For the atomic swaps, we use the same state update like we would
-            // use for `Money::Transfer`.
-            let update: MoneyTransferUpdateV1 = deserialize(&update_data[1..])?;
-            Ok(money_otcswap_process_update_v1(cid, update)?)
-        }
-
         MoneyFunction::AuthTokenMintV1 => {
             let update: MoneyAuthTokenMintUpdateV1 = deserialize(&update_data[1..])?;
             Ok(money_auth_token_mint_process_update_v1(cid, update)?)

+ 0 - 165
src/contract/money/src/entrypoint/swap_v1.rs

@@ -1,165 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2026 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use darkfi_sdk::{
-    crypto::{
-        pasta_prelude::*,
-        smt::{
-            wasmdb::{SmtWasmDbStorage, SmtWasmFp},
-            PoseidonFp, EMPTY_NODES_FP,
-        },
-        ContractId,
-    },
-    dark_tree::DarkLeaf,
-    error::{ContractError, ContractResult},
-    msg,
-    pasta::pallas,
-    wasm, ContractCall,
-};
-use darkfi_serial::{deserialize, serialize};
-
-use super::transfer_v1::{money_transfer_get_metadata_v1, money_transfer_process_update_v1};
-use crate::{
-    error::MoneyError,
-    model::{MoneyTransferParamsV1, MoneyTransferUpdateV1},
-    MONEY_CONTRACT_COINS_TREE, MONEY_CONTRACT_COIN_ROOTS_TREE, MONEY_CONTRACT_NULLIFIERS_TREE,
-};
-
-/// `get_metadata` function for `Money::OtcSwapV1`
-pub(crate) fn money_otcswap_get_metadata_v1(
-    cid: ContractId,
-    call_idx: usize,
-    calls: Vec<DarkLeaf<ContractCall>>,
-) -> Result<Vec<u8>, ContractError> {
-    // In here we can use the same function as we use in `TransferV1`.
-    money_transfer_get_metadata_v1(cid, call_idx, calls)
-}
-
-/// `process_instruction` function for `Money::OtcSwapV1`
-pub(crate) fn money_otcswap_process_instruction_v1(
-    cid: ContractId,
-    call_idx: usize,
-    calls: Vec<DarkLeaf<ContractCall>>,
-) -> Result<Vec<u8>, ContractError> {
-    let self_ = &calls[call_idx].data;
-    let params: MoneyTransferParamsV1 = deserialize(&self_.data[1..])?;
-
-    // The atomic swap is able to use the same parameters as `TransferV1`.
-    // In here we just have a different state transition where we enforce
-    // 2 anonymous inputs and 2 anonymous outputs. This is enforced so that
-    // every atomic swap looks the same on the network, therefore there is
-    // no special anonymity leak for different swaps that are being done,
-    // at least in the scope of this contract call.
-    if params.inputs.len() != 2 {
-        msg!("[OtcSwapV1] Error: Expected 2 inputs");
-        return Err(MoneyError::InvalidNumberOfInputs.into())
-    }
-
-    if params.outputs.len() != 2 {
-        msg!("[OtcSwapV1] Error: Expected 2 outputs");
-        return Err(MoneyError::InvalidNumberOfOutputs.into())
-    }
-
-    // Grab the db handles we'll be using here
-    let coins_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_COINS_TREE)?;
-    let nullifiers_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_NULLIFIERS_TREE)?;
-    let coin_roots_db = wasm::db::db_lookup(cid, MONEY_CONTRACT_COIN_ROOTS_TREE)?;
-
-    // We expect two new nullifiers and two new coins
-    let mut new_nullifiers = Vec::with_capacity(2);
-    let mut new_coins = Vec::with_capacity(2);
-
-    // inputs[0] is being swapped to outputs[1]
-    // inputs[1] is being swapped to outputs[0]
-    // so that's how we check the value and token commitments.
-    if params.inputs[0].value_commit != params.outputs[1].value_commit {
-        msg!("[OtcSwapV1] Error: Value commitments for input 0 and output 1 mismatch");
-        return Err(MoneyError::ValueMismatch.into())
-    }
-
-    if params.inputs[1].value_commit != params.outputs[0].value_commit {
-        msg!("[OtcSwapV1] Error: Value commitments for input 1 and ouptut 0 mismatch");
-        return Err(MoneyError::ValueMismatch.into())
-    }
-
-    if params.inputs[0].token_commit != params.outputs[1].token_commit {
-        msg!("[OtcSwapV1] Error: Token commitments for input 0 and output 1 mismatch");
-        return Err(MoneyError::TokenMismatch.into())
-    }
-
-    if params.inputs[1].token_commit != params.outputs[0].token_commit {
-        msg!("[OtcSwapV1] Error: Token commitments for input 1 and output 0 mismatch");
-        return Err(MoneyError::TokenMismatch.into())
-    }
-
-    let hasher = PoseidonFp::new();
-    let empty_leaf = pallas::Base::ZERO;
-    let smt_store = SmtWasmDbStorage::new(nullifiers_db);
-    let smt = SmtWasmFp::new(smt_store, hasher, &EMPTY_NODES_FP);
-
-    msg!("[OtcSwapV1] Iterating over anonymous inputs");
-    for (i, input) in params.inputs.iter().enumerate() {
-        // The Merkle root is used to know whether this coin
-        // has existed in a previous state.
-        if !wasm::db::db_contains_key(coin_roots_db, &serialize(&input.merkle_root))? {
-            msg!("[OtcSwapV1] Error: Merkle root not found in previous state (input {})", i);
-            return Err(MoneyError::SwapMerkleRootNotFound.into())
-        }
-
-        // The nullifiers should not already exist. It is the double-spend protection.
-        if new_nullifiers.contains(&input.nullifier) ||
-            smt.get_leaf(&input.nullifier.inner()) != empty_leaf
-        {
-            msg!("[OtcSwapV1] Error: Duplicate nullifier found in input {}", i);
-            return Err(MoneyError::DuplicateNullifier.into())
-        }
-
-        new_nullifiers.push(input.nullifier);
-    }
-
-    // Newly created coins for this call are in the outputs
-    for (i, output) in params.outputs.iter().enumerate() {
-        if new_coins.contains(&output.coin) ||
-            wasm::db::db_contains_key(coins_db, &serialize(&output.coin))?
-        {
-            msg!("[OtcSwapV1] Error: Duplicate coin found in output {}", i);
-            return Err(MoneyError::DuplicateCoin.into())
-        }
-
-        new_coins.push(output.coin);
-    }
-
-    // Create a state update. We also use `MoneyTransferUpdateV1` because
-    // they're essentially the same thing, just with a different transition
-    // ruleset.
-    let update = MoneyTransferUpdateV1 {
-        nullifiers: new_nullifiers,
-        global_coins: new_coins,
-        local_coins: vec![],
-    };
-    Ok(serialize(&update))
-}
-
-/// `process_update` function for `Money::OtcSwapV1`
-pub(crate) fn money_otcswap_process_update_v1(
-    cid: ContractId,
-    update: MoneyTransferUpdateV1,
-) -> ContractResult {
-    // In here we can use the same function as we use in `TransferV1`.
-    money_transfer_process_update_v1(cid, update)
-}

+ 18 - 23
src/contract/money/src/error.rs

@@ -58,9 +58,6 @@ pub enum MoneyError {
     #[error("Spend hook is not zero")]
     SpendHookNonZero,
 
-    #[error("Merkle root not found in previous state")]
-    SwapMerkleRootNotFound,
-
     #[error("Token ID does not derive from mint authority")]
     TokenIdDoesNotDeriveFromMint,
 
@@ -103,7 +100,6 @@ pub enum MoneyError {
     #[error("Insufficient fee paid")]
     InsufficientFee,
 
-    // TODO: This should catch-all (TransferMerkle../SwapMerkle...)
     #[error("Coin merkle root not found")]
     CoinMerkleRootNotFound,
 
@@ -132,25 +128,24 @@ impl From<MoneyError> for ContractError {
             MoneyError::InvalidNumberOfInputs => Self::Custom(10),
             MoneyError::InvalidNumberOfOutputs => Self::Custom(11),
             MoneyError::SpendHookNonZero => Self::Custom(12),
-            MoneyError::SwapMerkleRootNotFound => Self::Custom(13),
-            MoneyError::TokenIdDoesNotDeriveFromMint => Self::Custom(14),
-            MoneyError::TokenMintFrozen => Self::Custom(15),
-            MoneyError::ParentCallFunctionMismatch => Self::Custom(16),
-            MoneyError::ParentCallInputMismatch => Self::Custom(17),
-            MoneyError::ChildCallFunctionMismatch => Self::Custom(18),
-            MoneyError::ChildCallInputMismatch => Self::Custom(19),
-            MoneyError::GenesisCallNonGenesisBlock => Self::Custom(20),
-            MoneyError::MissingNullifier => Self::Custom(21),
-            MoneyError::PoWRewardCallOnGenesisBlock => Self::Custom(22),
-            MoneyError::PoWRewardRetrieveLastBlockHeightError => Self::Custom(23),
-            MoneyError::PoWRewardCallNotOnNextBlockHeight => Self::Custom(24),
-            MoneyError::PoWRewardCallMissingFeesAccumulator => Self::Custom(25),
-            MoneyError::FeeMissingInputs => Self::Custom(26),
-            MoneyError::InsufficientFee => Self::Custom(27),
-            MoneyError::CoinMerkleRootNotFound => Self::Custom(28),
-            MoneyError::RootsValueDataMismatch => Self::Custom(29),
-            MoneyError::ChildrenIndexesLengthMismatch => Self::Custom(30),
-            MoneyError::BurnMissingInputs => Self::Custom(31),
+            MoneyError::TokenIdDoesNotDeriveFromMint => Self::Custom(13),
+            MoneyError::TokenMintFrozen => Self::Custom(14),
+            MoneyError::ParentCallFunctionMismatch => Self::Custom(15),
+            MoneyError::ParentCallInputMismatch => Self::Custom(16),
+            MoneyError::ChildCallFunctionMismatch => Self::Custom(17),
+            MoneyError::ChildCallInputMismatch => Self::Custom(18),
+            MoneyError::GenesisCallNonGenesisBlock => Self::Custom(19),
+            MoneyError::MissingNullifier => Self::Custom(20),
+            MoneyError::PoWRewardCallOnGenesisBlock => Self::Custom(21),
+            MoneyError::PoWRewardRetrieveLastBlockHeightError => Self::Custom(22),
+            MoneyError::PoWRewardCallNotOnNextBlockHeight => Self::Custom(23),
+            MoneyError::PoWRewardCallMissingFeesAccumulator => Self::Custom(24),
+            MoneyError::FeeMissingInputs => Self::Custom(25),
+            MoneyError::InsufficientFee => Self::Custom(26),
+            MoneyError::CoinMerkleRootNotFound => Self::Custom(27),
+            MoneyError::RootsValueDataMismatch => Self::Custom(28),
+            MoneyError::ChildrenIndexesLengthMismatch => Self::Custom(29),
+            MoneyError::BurnMissingInputs => Self::Custom(30),
         }
     }
 }

+ 10 - 12
src/contract/money/src/lib.rs

@@ -18,8 +18,8 @@
 
 //! DarkFi Money Contract
 //!
-//! Smart contract implementing money transfers, atomic swaps, token
-//! minting and freezing, and staking/unstaking of consensus tokens.
+//! Smart contract implementing money transfers, token minting and freezing,
+//! and consensus rewards minting.
 
 use darkfi_sdk::error::ContractError;
 
@@ -32,11 +32,10 @@ pub enum MoneyFunction {
     GenesisMintV1 = 0x01,
     PoWRewardV1 = 0x02,
     TransferV1 = 0x03,
-    OtcSwapV1 = 0x04,
-    AuthTokenMintV1 = 0x05,
-    AuthTokenFreezeV1 = 0x06,
-    TokenMintV1 = 0x07,
-    BurnV1 = 0x08,
+    AuthTokenMintV1 = 0x04,
+    AuthTokenFreezeV1 = 0x05,
+    TokenMintV1 = 0x06,
+    BurnV1 = 0x07,
 }
 // ANCHOR_END: money-function
 
@@ -49,11 +48,10 @@ impl TryFrom<u8> for MoneyFunction {
             0x01 => Ok(Self::GenesisMintV1),
             0x02 => Ok(Self::PoWRewardV1),
             0x03 => Ok(Self::TransferV1),
-            0x04 => Ok(Self::OtcSwapV1),
-            0x05 => Ok(Self::AuthTokenMintV1),
-            0x06 => Ok(Self::AuthTokenFreezeV1),
-            0x07 => Ok(Self::TokenMintV1),
-            0x08 => Ok(Self::BurnV1),
+            0x04 => Ok(Self::AuthTokenMintV1),
+            0x05 => Ok(Self::AuthTokenFreezeV1),
+            0x06 => Ok(Self::TokenMintV1),
+            0x07 => Ok(Self::BurnV1),
             _ => Err(ContractError::InvalidFunction),
         }
     }

+ 2 - 2
src/contract/money/src/model/mod.rs

@@ -200,7 +200,7 @@ pub struct MoneyFeeUpdateV1 {
 
 #[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
 // ANCHOR: money-params
-/// Parameters for `Money::Transfer` and `Money::OtcSwap`
+/// Parameters for `Money::Transfer`
 pub struct MoneyTransferParamsV1 {
     /// Anonymous inputs
     pub inputs: Vec<Input>,
@@ -209,7 +209,7 @@ pub struct MoneyTransferParamsV1 {
 }
 // ANCHOR_END: money-params
 
-/// State update for `Money::Transfer` and `Money::OtcSwap`
+/// State update for `Money::Transfer`
 #[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
 pub struct MoneyTransferUpdateV1 {
     /// Revealed nullifiers

+ 2 - 2
src/contract/test-harness/src/money_otc_swap.rs

@@ -39,7 +39,7 @@ use rand::rngs::OsRng;
 use super::{Holder, TestHarness};
 
 impl TestHarness {
-    /// Create a `Money::OtcSwap` transaction with two given [`Holder`]s.
+    /// Create a `Money::TransferV1` transaction with two given [`Holder`]s.
     ///
     /// Returns the [`Transaction`], and the transaction parameters.
     pub async fn otc_swap(
@@ -129,7 +129,7 @@ impl TestHarness {
         ];
 
         // Encode the contract call
-        let mut data = vec![MoneyFunction::OtcSwapV1 as u8];
+        let mut data = vec![MoneyFunction::TransferV1 as u8];
         swap_full_params.encode(&mut data)?;
         let call = ContractCall { contract_id: *MONEY_CONTRACT_ID, data };
         let mut tx_builder =

+ 1 - 1
src/sdk/python/src/contract/money/mod.rs

@@ -82,7 +82,7 @@ pub fn decode_money_function_params(
             let params: money_model::MoneyPoWRewardParamsV1 = deserialize(&data[1..])?;
             Box::new(params)
         }
-        MoneyFunction::TransferV1 | MoneyFunction::OtcSwapV1 => {
+        MoneyFunction::TransferV1 => {
             let params: money_model::MoneyTransferParamsV1 = deserialize(&data[1..])?;
             Box::new(params)
         }

+ 7 - 7
src/sdk/src/tx.rs

@@ -104,23 +104,23 @@ impl ContractCall {
         self.matches_contract_call_type(*MONEY_CONTRACT_ID, 0x03)
     }
 
-    /// Returns true if call is a money over-the-counter swap.
-    pub fn is_money_otc_swap(&self) -> bool {
-        self.matches_contract_call_type(*MONEY_CONTRACT_ID, 0x04)
-    }
-
     /// Returns true if call is a money token mint authorization.
     pub fn is_money_auth_token_mint(&self) -> bool {
-        self.matches_contract_call_type(*MONEY_CONTRACT_ID, 0x05)
+        self.matches_contract_call_type(*MONEY_CONTRACT_ID, 0x04)
     }
 
     /// Returns true if call is a money token freeze authorization.
     pub fn is_money_auth_token_freeze(&self) -> bool {
-        self.matches_contract_call_type(*MONEY_CONTRACT_ID, 0x06)
+        self.matches_contract_call_type(*MONEY_CONTRACT_ID, 0x05)
     }
 
     /// Returns true if call is a money token mint.
     pub fn is_money_token_mint(&self) -> bool {
+        self.matches_contract_call_type(*MONEY_CONTRACT_ID, 0x06)
+    }
+
+    /// Returns true if call is a money burn.
+    pub fn is_money_burn(&self) -> bool {
         self.matches_contract_call_type(*MONEY_CONTRACT_ID, 0x07)
     }