mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
drk: Arbitrary token minting.
This commit is contained in:
@@ -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
bin/drk/src/rpc_token.rs
Normal file
106
bin/drk/src/rpc_token.rs
Normal file
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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?;
|
||||
|
||||
Reference in New Issue
Block a user