parazyd 3 лет назад
Родитель
Сommit
6c2dc8f9bc
3 измененных файлов с 140 добавлено и 4 удалено
  1. 22 1
      bin/drk/src/main.rs
  2. 106 0
      bin/drk/src/rpc_token.rs
  3. 12 3
      bin/drk/src/wallet_money.rs

+ 22 - 1
bin/drk/src/main.rs

@@ -60,6 +60,9 @@ use rpc_swap::PartialSwapData;
 /// DAO methods
 mod rpc_dao;
 
+/// Token methods
+mod rpc_token;
+
 /// Blockchain methods
 mod rpc_blockchain;
 
@@ -1184,7 +1187,25 @@ async fn main() -> Result<()> {
 
                 Ok(())
             }
-            TokenSubcmd::Mint { token, amount, recipient } => todo!(),
+
+            // TODO: Mint directly into DAO treasury
+            TokenSubcmd::Mint { token, amount, recipient } => {
+                let _ = f64::from_str(&amount).with_context(|| "Invalid amount")?;
+                let rcpt = PublicKey::from_str(&recipient).with_context(|| "Invalid recipient")?;
+                let token_id =
+                    TokenId::try_from(token.as_str()).with_context(|| "Invalid token ID")?;
+
+                let drk = Drk::new(args.endpoint).await?;
+
+                let tx = drk
+                    .mint_token(&amount, rcpt, token_id)
+                    .await
+                    .with_context(|| "Failed to create token mint transaction")?;
+
+                println!("{}", bs58::encode(&serialize(&tx)).into_string());
+
+                Ok(())
+            }
             TokenSubcmd::Freeze { token } => todo!(),
         },
     }

+ 106 - 0
bin/drk/src/rpc_token.rs

@@ -0,0 +1,106 @@
+/* This file is part of DarkFi (https://dark.fi)
+ *
+ * Copyright (C) 2020-2023 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 anyhow::{anyhow, Result};
+use darkfi::{
+    tx::Transaction,
+    util::parse::decode_base10,
+    zk::{proof::ProvingKey, vm::ZkCircuit, vm_stack::empty_witnesses},
+    zkas::ZkBinary,
+};
+use darkfi_money_contract::{
+    client::mint_v1::MintCallBuilder, MoneyFunction, MONEY_CONTRACT_ZKAS_TOKEN_MINT_NS_V1,
+};
+use darkfi_sdk::{
+    crypto::{contract_id::MONEY_CONTRACT_ID, Keypair, PublicKey, TokenId},
+    pasta::pallas,
+    tx::ContractCall,
+};
+use darkfi_serial::Encodable;
+use rand::rngs::OsRng;
+
+use super::Drk;
+
+impl Drk {
+    /// Create a payment transaction. Returns the transaction object on success.
+    pub async fn mint_token(
+        &self,
+        amount: &str,
+        recipient: PublicKey,
+        token_id: TokenId,
+    ) -> Result<Transaction> {
+        // TODO: Mint directly into DAO treasury
+        let spend_hook = pallas::Base::zero();
+        let user_data = pallas::Base::zero();
+
+        let amount = decode_base10(amount, 8, false)?;
+
+        let mut tokens = self.list_tokens().await?;
+        tokens.retain(|x| x.0 == token_id);
+        if tokens.is_empty() {
+            return Err(anyhow!("Did not find mint authority for token ID {}", token_id))
+        }
+        assert!(tokens.len() == 1);
+
+        let mint_authority = Keypair::new(tokens[0].1);
+
+        if tokens[0].2 {
+            return Err(anyhow!("This token mint is marked as frozen in the wallet"))
+        }
+
+        // Now we need to do a lookup for the zkas proof bincodes, and create
+        // the circuit objects and proving keys so we can build the transaction.
+        // We also do this through the RPC.
+        let zkas_bins = self.lookup_zkas(&MONEY_CONTRACT_ID).await?;
+        let zkas_ns = MONEY_CONTRACT_ZKAS_TOKEN_MINT_NS_V1;
+
+        let Some(token_mint_zkbin) = zkas_bins.iter().find(|x| x.0 == zkas_ns) else {
+            return Err(anyhow!("Token mint circuit not found"))
+        };
+
+        let k = 13;
+        let token_mint_zkbin = ZkBinary::decode(&token_mint_zkbin.1)?;
+        let token_mint_circuit =
+            ZkCircuit::new(empty_witnesses(&token_mint_zkbin), token_mint_zkbin.clone());
+
+        eprintln!("Creating token mint circuit proving keys");
+        let mint_builder = MintCallBuilder {
+            mint_authority,
+            recipient,
+            amount,
+            spend_hook,
+            user_data,
+            token_mint_zkbin,
+            token_mint_pk: ProvingKey::build(k, &token_mint_circuit),
+        };
+
+        eprintln!("Building transaction parameters");
+        let debris = mint_builder.build()?;
+
+        // Encode and sign the transaction
+        let mut data = vec![MoneyFunction::MintV1 as u8];
+        debris.params.encode(&mut data)?;
+        let calls = vec![ContractCall { contract_id: *MONEY_CONTRACT_ID, data }];
+        let proofs = vec![debris.proofs];
+        let mut tx = Transaction { calls, proofs, signatures: vec![] };
+        let sigs = tx.create_sigs(&mut OsRng, &[mint_authority.secret])?;
+        tx.signatures = vec![sigs];
+
+        Ok(tx)
+    }
+}

+ 12 - 3
bin/drk/src/wallet_money.rs

@@ -31,7 +31,7 @@ use darkfi_money_contract::{
         MONEY_KEYS_COL_IS_DEFAULT, MONEY_KEYS_COL_KEY_ID, MONEY_KEYS_COL_PUBLIC,
         MONEY_KEYS_COL_SECRET, MONEY_KEYS_TABLE, MONEY_TREE_COL_TREE, MONEY_TREE_TABLE,
     },
-    model::{MoneyTransferParamsV1, Output},
+    model::{MoneyMintParamsV1, MoneyTransferParamsV1, Output},
     MoneyFunction,
 };
 use darkfi_sdk::{
@@ -489,7 +489,7 @@ impl Drk {
 
         for (i, call) in tx.calls.iter().enumerate() {
             if call.contract_id == cid && call.data[0] == MoneyFunction::TransferV1 as u8 {
-                eprintln!("Found Money::Transfer in call {}", i);
+                eprintln!("Found Money::TransferV1 in call {}", i);
                 let params: MoneyTransferParamsV1 = deserialize(&call.data[1..])?;
 
                 for input in params.inputs {
@@ -504,7 +504,7 @@ impl Drk {
             }
 
             if call.contract_id == cid && call.data[0] == MoneyFunction::OtcSwapV1 as u8 {
-                eprintln!("Found Money::OtcSwap in call {}", i);
+                eprintln!("Found Money::OtcSwapV1 in call {}", i);
                 let params: MoneyTransferParamsV1 = deserialize(&call.data[1..])?;
 
                 for input in params.inputs {
@@ -517,6 +517,15 @@ impl Drk {
 
                 continue
             }
+
+            if call.contract_id == cid && call.data[0] == MoneyFunction::MintV1 as u8 {
+                eprintln!("Found Money::MintV1 in call {}", i);
+                let params: MoneyMintParamsV1 = deserialize(&call.data[1..])?;
+
+                outputs.push(params.output);
+
+                continue
+            }
         }
 
         let secrets = self.get_money_secrets().await?;