diff --git a/wallet/README.md b/wallet/README.md index d12ace1af..16db6e8e3 100644 --- a/wallet/README.md +++ b/wallet/README.md @@ -218,6 +218,27 @@ Balance Summary total : 80 ``` +It is possible to create new coins using the wallet. Let's explore how to do it. + +### Minting coins + +We can optionally pass the amount and public key of the owner as arguments to mint_coins. +If optional arguments are not passed below are the default values: +Amount is `100` and Public key of owner is Shawn key. + +```sh +$ tuxedo-template-wallet mint-coins \ + --owner 0xdeba7f5d5088cda3e32ccaf479056dd934d87fa8129987ca6db57c122bd73341 \ + --amount 200 \ + +[2024-01-18T14:22:19Z INFO tuxedo_template_wallet] Number of blocks in the db: 6 +[2024-01-18T14:22:19Z INFO tuxedo_template_wallet] Wallet database synchronized with node to height 14 +[2024-01-18T14:22:19Z INFO tuxedo_template_wallet::money] Node's response to mint-coin transaction: Ok("0xaff830b7755fee67c288afe18dfa6eabffe06286005b0fd6cb8e57b246c08df6") +Created "f76373909591d85f796c36ed4b265e46efabdf5b5c493b94246d590823cc42a500000000" worth 200. owned by 0xdeba…3341 +``` +It is possible to verify a newly minted coin exists in both chain storage and the local database using verify-coin command. + + ### Manually Selecting Inputs So far, we have let the wallet select which inputs to spend on our behalf. diff --git a/wallet/src/cli.rs b/wallet/src/cli.rs index 143243c3f..df3afa227 100644 --- a/wallet/src/cli.rs +++ b/wallet/src/cli.rs @@ -10,6 +10,9 @@ use tuxedo_core::types::OutputRef; use crate::{h256_from_string, keystore::SHAWN_PUB_KEY, output_ref_from_string, DEFAULT_ENDPOINT}; +/// The default number of coins to be minted. +pub const DEFAULT_MINT_VALUE: &str = "100"; + /// The wallet's main CLI struct #[derive(Debug, Parser)] #[command(about, version)] @@ -47,6 +50,12 @@ pub enum Command { /// Demonstrate creating an amoeba and performing mitosis on it. AmoebaDemo, + /// Mint coins , optionally amount and publicKey of owner can be passed + /// if amount is not passed , 100 coins are minted + /// If publickKey of owner is not passed , then by default SHAWN_PUB_KEY is used. + #[command(verbatim_doc_comment)] + MintCoins(MintCoinArgs), + /// Verify that a particular coin exists. /// Show its value and owner from both chain storage and the local database. #[command(verbatim_doc_comment)] @@ -103,6 +112,19 @@ pub enum Command { ShowTimestamp, } +#[derive(Debug, Args)] +pub struct MintCoinArgs { + /// Pass the amount to be minted. + #[arg(long, short, verbatim_doc_comment, action = Append,default_value = DEFAULT_MINT_VALUE)] + pub amount: u128, + + // https://docs.rs/clap/latest/clap/_derive/_cookbook/typed_derive/index.html + // shows how to specify a custom parsing function + /// Hex encoded address (sr25519 pubkey) of the owner. + #[arg(long, short, verbatim_doc_comment, value_parser = h256_from_string, default_value = SHAWN_PUB_KEY)] + pub owner: H256, +} + #[derive(Debug, Args)] pub struct SpendArgs { /// An input to be consumed by this transaction. This argument may be specified multiple times. diff --git a/wallet/src/main.rs b/wallet/src/main.rs index 044c4dddc..5cf962bab 100644 --- a/wallet/src/main.rs +++ b/wallet/src/main.rs @@ -99,6 +99,7 @@ async fn main() -> anyhow::Result<()> { match cli.command { Some(Command::AmoebaDemo) => amoeba::amoeba_demo(&client).await, // Command::MultiSigDemo => multi_sig::multi_sig_demo(&client).await, + Some(Command::MintCoins(args)) => money::mint_coins(&client, args).await, Some(Command::VerifyCoin { output_ref }) => { println!("Details of coin {}:", hex::encode(output_ref.encode())); diff --git a/wallet/src/money.rs b/wallet/src/money.rs index 7b0558034..df983221b 100644 --- a/wallet/src/money.rs +++ b/wallet/src/money.rs @@ -1,6 +1,6 @@ //! Wallet features related to spending money and checking balances. -use crate::{cli::SpendArgs, rpc::fetch_storage, sync}; +use crate::{cli::MintCoinArgs, cli::SpendArgs, rpc::fetch_storage, sync}; use anyhow::anyhow; use jsonrpsee::{core::client::ClientT, http_client::HttpClient, rpc_params}; @@ -18,6 +18,47 @@ use tuxedo_core::{ verifier::Sr25519Signature, }; +/// Create and send a transaction that mints the coins on the network +pub async fn mint_coins(client: &HttpClient, args: MintCoinArgs) -> anyhow::Result<()> { + log::debug!("The args are:: {:?}", args); + + let transaction = Transaction { + inputs: Vec::new(), + peeks: Vec::new(), + outputs: vec![( + Coin::<0>::new(args.amount), + OuterVerifier::Sr25519Signature(Sr25519Signature { + owner_pubkey: args.owner, + }), + ) + .into()], + checker: OuterConstraintChecker::Money(MoneyConstraintChecker::Mint), + }; + + let spawn_hex = hex::encode(transaction.encode()); + let params = rpc_params![spawn_hex]; + let _spawn_response: Result = client.request("author_submitExtrinsic", params).await; + + log::info!( + "Node's response to mint-coin transaction: {:?}", + _spawn_response + ); + + let minted_coin_ref = OutputRef { + tx_hash: ::hash_of(&transaction.encode()), + index: 0, + }; + let output = &transaction.outputs[0]; + let amount = output.payload.extract::>()?.0; + print!( + "Minted {:?} worth {amount}. ", + hex::encode(minted_coin_ref.encode()) + ); + crate::pretty_print_verifier(&output.verifier); + + Ok(()) +} + /// Create and send a transaction that spends coins on the network pub async fn spend_coins( db: &Db,