From ef6627355413576d7b362a8e63113751d622740b Mon Sep 17 00:00:00 2001 From: thesimplekid Date: Mon, 15 Jul 2024 22:07:56 +0100 Subject: [PATCH] refactor: cdk-cli use multimint wallet --- CHANGELOG.md | 1 + crates/cdk-cli/src/main.rs | 42 ++++++++-------- crates/cdk-cli/src/sub_commands/balance.rs | 21 ++++---- crates/cdk-cli/src/sub_commands/burn.rs | 15 +++--- .../cdk-cli/src/sub_commands/check_spent.rs | 9 ++-- crates/cdk-cli/src/sub_commands/melt.rs | 16 ++++--- crates/cdk-cli/src/sub_commands/mint.rs | 30 +++++++----- .../cdk-cli/src/sub_commands/pending_mints.rs | 18 +++---- crates/cdk-cli/src/sub_commands/receive.rs | 48 +++++-------------- crates/cdk-cli/src/sub_commands/restore.rs | 16 ++++--- crates/cdk-cli/src/sub_commands/send.rs | 16 ++++--- .../src/sub_commands/update_mint_url.rs | 16 ++++--- crates/cdk/src/wallet/mod.rs | 1 + 13 files changed, 126 insertions(+), 123 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38554d36..847c23a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ ### Changed - cdk(wallet): `fn send` returns `Token` so the user can use the struct of convert it to a v3 or v4 string. +- cdk(wallet): Publicly export `MultiMintWallet` ([thesimplekid]). ### Added - cdk(NUT-11): Add `Copy` on `SigFlag` ([thesimplekid]). diff --git a/crates/cdk-cli/src/main.rs b/crates/cdk-cli/src/main.rs index 655d17d0..3259f9c0 100644 --- a/crates/cdk-cli/src/main.rs +++ b/crates/cdk-cli/src/main.rs @@ -1,4 +1,3 @@ -use std::collections::HashMap; use std::fs; use std::path::PathBuf; use std::str::FromStr; @@ -6,9 +5,9 @@ use std::sync::Arc; use anyhow::{bail, Result}; use bip39::Mnemonic; +use cdk::cdk_database; use cdk::cdk_database::WalletDatabase; -use cdk::wallet::Wallet; -use cdk::{cdk_database, UncheckedUrl}; +use cdk::wallet::{MultiMintWallet, Wallet}; use cdk_redb::WalletRedbDatabase; use cdk_sqlite::WalletSqliteDatabase; use clap::{Parser, Subcommand}; @@ -126,7 +125,7 @@ async fn main() -> Result<()> { } }; - let mut wallets: HashMap = HashMap::new(); + let mut wallets: Vec = Vec::new(); let mints = localstore.get_mints().await?; @@ -139,49 +138,50 @@ async fn main() -> Result<()> { None, ); - wallets.insert(mint, wallet); + wallets.push(wallet); } + let multi_mint_wallet = MultiMintWallet::new(wallets); + match &args.command { Commands::DecodeToken(sub_command_args) => { sub_commands::decode_token::decode_token(sub_command_args) } - Commands::Balance => sub_commands::balance::balance(wallets).await, - Commands::Pay => sub_commands::melt::pay(wallets).await, + Commands::Balance => sub_commands::balance::balance(&multi_mint_wallet).await, + Commands::Pay => sub_commands::melt::pay(multi_mint_wallet).await, Commands::Receive(sub_command_args) => { - sub_commands::receive::receive( - wallets, - &mnemonic.to_seed_normalized(""), - localstore, - sub_command_args, - ) - .await + sub_commands::receive::receive(&multi_mint_wallet, localstore, sub_command_args).await } Commands::Send(sub_command_args) => { - sub_commands::send::send(wallets, sub_command_args).await + sub_commands::send::send(&multi_mint_wallet, sub_command_args).await + } + Commands::CheckSpendable => { + sub_commands::check_spent::check_spent(&multi_mint_wallet).await } - Commands::CheckSpendable => sub_commands::check_spent::check_spent(wallets).await, Commands::MintInfo(sub_command_args) => { sub_commands::mint_info::mint_info(sub_command_args).await } Commands::Mint(sub_command_args) => { sub_commands::mint::mint( - wallets, + &multi_mint_wallet, &mnemonic.to_seed_normalized(""), localstore, sub_command_args, ) .await } - Commands::MintPending => sub_commands::pending_mints::mint_pending(wallets).await, + Commands::MintPending => { + sub_commands::pending_mints::mint_pending(&multi_mint_wallet).await + } Commands::Burn(sub_command_args) => { - sub_commands::burn::burn(wallets, sub_command_args).await + sub_commands::burn::burn(&multi_mint_wallet, sub_command_args).await } Commands::Restore(sub_command_args) => { - sub_commands::restore::restore(wallets, sub_command_args).await + sub_commands::restore::restore(&multi_mint_wallet, sub_command_args).await } Commands::UpdateMintUrl(sub_command_args) => { - sub_commands::update_mint_url::update_mint_url(wallets, sub_command_args).await + sub_commands::update_mint_url::update_mint_url(&multi_mint_wallet, sub_command_args) + .await } } } diff --git a/crates/cdk-cli/src/sub_commands/balance.rs b/crates/cdk-cli/src/sub_commands/balance.rs index 51aec539..a6f8d7da 100644 --- a/crates/cdk-cli/src/sub_commands/balance.rs +++ b/crates/cdk-cli/src/sub_commands/balance.rs @@ -1,25 +1,28 @@ use std::collections::HashMap; use anyhow::Result; +use cdk::nuts::CurrencyUnit; use cdk::url::UncheckedUrl; -use cdk::wallet::Wallet; +use cdk::wallet::multi_mint_wallet::MultiMintWallet; use cdk::Amount; -pub async fn balance(wallets: HashMap) -> Result<()> { - mint_balances(wallets).await?; +pub async fn balance(multi_mint_wallet: &MultiMintWallet) -> Result<()> { + mint_balances(multi_mint_wallet).await?; Ok(()) } pub async fn mint_balances( - wallets: HashMap, -) -> Result> { - let mut wallets_vec: Vec<(Wallet, Amount)> = Vec::with_capacity(wallets.capacity()); + multi_mint_wallet: &MultiMintWallet, +) -> Result> { + let wallets: HashMap = + multi_mint_wallet.get_balances(&CurrencyUnit::Sat).await?; - for (i, (mint_url, wallet)) in wallets.iter().enumerate() { + let mut wallets_vec = Vec::with_capacity(wallets.capacity()); + + for (i, (mint_url, amount)) in wallets.iter().enumerate() { let mint_url = mint_url.clone(); - let amount = wallet.total_balance().await?; println!("{i}: {mint_url} {amount}"); - wallets_vec.push((wallet.clone(), amount)); + wallets_vec.push((mint_url, *amount)) } Ok(wallets_vec) } diff --git a/crates/cdk-cli/src/sub_commands/burn.rs b/crates/cdk-cli/src/sub_commands/burn.rs index 0cc6e37e..c05b7207 100644 --- a/crates/cdk-cli/src/sub_commands/burn.rs +++ b/crates/cdk-cli/src/sub_commands/burn.rs @@ -1,7 +1,7 @@ -use std::collections::HashMap; - use anyhow::Result; -use cdk::wallet::Wallet; +use cdk::nuts::CurrencyUnit; +use cdk::wallet::multi_mint_wallet::WalletKey; +use cdk::wallet::MultiMintWallet; use cdk::{Amount, UncheckedUrl}; use clap::Args; @@ -12,17 +12,20 @@ pub struct BurnSubCommand { } pub async fn burn( - wallets: HashMap, + multi_mint_wallet: &MultiMintWallet, sub_command_args: &BurnSubCommand, ) -> Result<()> { let mut total_burnt = Amount::ZERO; match &sub_command_args.mint_url { Some(mint_url) => { - let wallet = wallets.get(mint_url).unwrap(); + let wallet = multi_mint_wallet + .get_wallet(&WalletKey::new(mint_url.clone(), CurrencyUnit::Sat)) + .await + .unwrap(); total_burnt = wallet.check_all_pending_proofs().await?; } None => { - for wallet in wallets.values() { + for wallet in multi_mint_wallet.get_wallets().await { let amount_burnt = wallet.check_all_pending_proofs().await?; total_burnt += amount_burnt; } diff --git a/crates/cdk-cli/src/sub_commands/check_spent.rs b/crates/cdk-cli/src/sub_commands/check_spent.rs index 43d9cdea..4cd8406c 100644 --- a/crates/cdk-cli/src/sub_commands/check_spent.rs +++ b/crates/cdk-cli/src/sub_commands/check_spent.rs @@ -1,11 +1,8 @@ -use std::collections::HashMap; - use anyhow::Result; -use cdk::url::UncheckedUrl; -use cdk::wallet::Wallet; +use cdk::wallet::MultiMintWallet; -pub async fn check_spent(wallets: HashMap) -> Result<()> { - for wallet in wallets.values() { +pub async fn check_spent(multi_mint_wallet: &MultiMintWallet) -> Result<()> { + for wallet in multi_mint_wallet.get_wallets().await { let amount = wallet.check_all_pending_proofs().await?; println!("Amount marked as spent: {}", amount); diff --git a/crates/cdk-cli/src/sub_commands/melt.rs b/crates/cdk-cli/src/sub_commands/melt.rs index c0e876ed..3dfe0149 100644 --- a/crates/cdk-cli/src/sub_commands/melt.rs +++ b/crates/cdk-cli/src/sub_commands/melt.rs @@ -1,16 +1,16 @@ -use std::collections::HashMap; +use std::io; use std::io::Write; use std::str::FromStr; -use std::{io, println}; use anyhow::{bail, Result}; -use cdk::wallet::Wallet; -use cdk::{Bolt11Invoice, UncheckedUrl}; +use cdk::nuts::CurrencyUnit; +use cdk::wallet::multi_mint_wallet::{MultiMintWallet, WalletKey}; +use cdk::Bolt11Invoice; use crate::sub_commands::balance::mint_balances; -pub async fn pay(wallets: HashMap) -> Result<()> { - let mints_amounts = mint_balances(wallets).await?; +pub async fn pay(multi_mint_wallet: MultiMintWallet) -> Result<()> { + let mints_amounts = mint_balances(&multi_mint_wallet).await?; println!("Enter mint number to melt from"); @@ -26,6 +26,10 @@ pub async fn pay(wallets: HashMap) -> Result<()> { } let wallet = mints_amounts[mint_number].0.clone(); + let wallet = multi_mint_wallet + .get_wallet(&WalletKey::new(wallet, CurrencyUnit::Sat)) + .await + .expect("Known wallet"); println!("Enter bolt11 invoice request"); diff --git a/crates/cdk-cli/src/sub_commands/mint.rs b/crates/cdk-cli/src/sub_commands/mint.rs index 9f56f8ed..c595bb25 100644 --- a/crates/cdk-cli/src/sub_commands/mint.rs +++ b/crates/cdk-cli/src/sub_commands/mint.rs @@ -1,4 +1,3 @@ -use std::collections::HashMap; use std::sync::Arc; use std::time::Duration; @@ -7,7 +6,8 @@ use cdk::amount::SplitTarget; use cdk::cdk_database::{Error, WalletDatabase}; use cdk::nuts::{CurrencyUnit, MintQuoteState}; use cdk::url::UncheckedUrl; -use cdk::wallet::Wallet; +use cdk::wallet::multi_mint_wallet::WalletKey; +use cdk::wallet::{MultiMintWallet, Wallet}; use cdk::Amount; use clap::Args; use tokio::time::sleep; @@ -24,21 +24,29 @@ pub struct MintSubCommand { } pub async fn mint( - wallets: HashMap, + multi_mint_wallet: &MultiMintWallet, seed: &[u8], localstore: Arc + Sync + Send>, sub_command_args: &MintSubCommand, ) -> Result<()> { let mint_url = sub_command_args.mint_url.clone(); - let wallet = match wallets.get(&mint_url) { + let wallet = match multi_mint_wallet + .get_wallet(&WalletKey::new(mint_url.clone(), CurrencyUnit::Sat)) + .await + { Some(wallet) => wallet.clone(), - None => Wallet::new( - &mint_url.to_string(), - CurrencyUnit::Sat, - localstore, - seed, - None, - ), + None => { + let wallet = Wallet::new( + &mint_url.to_string(), + CurrencyUnit::Sat, + localstore, + seed, + None, + ); + + multi_mint_wallet.add_wallet(wallet.clone()).await; + wallet + } }; let quote = wallet diff --git a/crates/cdk-cli/src/sub_commands/pending_mints.rs b/crates/cdk-cli/src/sub_commands/pending_mints.rs index d3464de9..91d35a72 100644 --- a/crates/cdk-cli/src/sub_commands/pending_mints.rs +++ b/crates/cdk-cli/src/sub_commands/pending_mints.rs @@ -1,16 +1,12 @@ -use std::collections::HashMap; - use anyhow::Result; -use cdk::wallet::Wallet; -use cdk::{Amount, UncheckedUrl}; +use cdk::wallet::MultiMintWallet; +use cdk::Amount; -pub async fn mint_pending(wallets: HashMap) -> Result<()> { - let mut amount_claimed = Amount::ZERO; - for wallet in wallets.values() { - let claimed = wallet.check_all_mint_quotes().await?; - amount_claimed += claimed; - } +pub async fn mint_pending(multi_mint_wallet: &MultiMintWallet) -> Result<()> { + let amounts = multi_mint_wallet.check_all_mint_quotes(None).await?; - println!("Amount minted: {amount_claimed}"); + let amount = amounts.into_values().sum::(); + + println!("Amount minted: {amount}"); Ok(()) } diff --git a/crates/cdk-cli/src/sub_commands/receive.rs b/crates/cdk-cli/src/sub_commands/receive.rs index 7cae2aea..4fac0c17 100644 --- a/crates/cdk-cli/src/sub_commands/receive.rs +++ b/crates/cdk-cli/src/sub_commands/receive.rs @@ -1,14 +1,13 @@ -use std::collections::{HashMap, HashSet}; +use std::collections::HashSet; use std::str::FromStr; use std::sync::Arc; use anyhow::{anyhow, Result}; -use cdk::amount::SplitTarget; -use cdk::cdk_database::{Error, WalletDatabase}; -use cdk::nuts::{CurrencyUnit, SecretKey, Token}; +use cdk::cdk_database::{self, WalletDatabase}; +use cdk::nuts::SecretKey; use cdk::util::unix_time; -use cdk::wallet::Wallet; -use cdk::{Amount, UncheckedUrl}; +use cdk::wallet::multi_mint_wallet::MultiMintWallet; +use cdk::Amount; use clap::Args; use nostr_sdk::nips::nip04; use nostr_sdk::{Filter, Keys, Kind, Timestamp}; @@ -35,9 +34,8 @@ pub struct ReceiveSubCommand { } pub async fn receive( - wallets: HashMap, - seed: &[u8], - localstore: Arc + Sync + Send>, + multi_mint_wallet: &MultiMintWallet, + localstore: Arc + Send + Sync>, sub_command_args: &ReceiveSubCommand, ) -> Result<()> { let mut signing_keys = Vec::new(); @@ -62,10 +60,8 @@ pub async fn receive( let amount = match &sub_command_args.token { Some(token_str) => { receive_token( + multi_mint_wallet, token_str, - wallets, - seed, - &localstore, &signing_keys, &sub_command_args.preimage, ) @@ -97,10 +93,8 @@ pub async fn receive( let mut total_amount = Amount::ZERO; for token_str in &tokens { match receive_token( + multi_mint_wallet, token_str, - wallets.clone(), - seed, - &localstore, &signing_keys, &sub_command_args.preimage, ) @@ -128,29 +122,13 @@ pub async fn receive( } async fn receive_token( - token_str: &str, - wallets: HashMap, - seed: &[u8], - localstore: &Arc + Sync + Send>, + multi_mint_wallet: &MultiMintWallet, + token: &str, signing_keys: &[SecretKey], preimage: &[String], ) -> Result { - let token = Token::from_str(token_str)?; - let mint_url = token.proofs().iter().next().unwrap().0.clone(); - - let wallet = match wallets.get(&mint_url) { - Some(wallet) => wallet.clone(), - None => Wallet::new( - &mint_url.to_string(), - CurrencyUnit::Sat, - Arc::clone(localstore), - seed, - None, - ), - }; - - let amount = wallet - .receive(token_str, SplitTarget::default(), signing_keys, preimage) + let amount = multi_mint_wallet + .receive(token, signing_keys, preimage) .await?; Ok(amount) } diff --git a/crates/cdk-cli/src/sub_commands/restore.rs b/crates/cdk-cli/src/sub_commands/restore.rs index 6d4508dc..9b8b15ba 100644 --- a/crates/cdk-cli/src/sub_commands/restore.rs +++ b/crates/cdk-cli/src/sub_commands/restore.rs @@ -1,8 +1,8 @@ -use std::collections::HashMap; - use anyhow::{anyhow, Result}; +use cdk::nuts::CurrencyUnit; use cdk::url::UncheckedUrl; -use cdk::wallet::Wallet; +use cdk::wallet::multi_mint_wallet::WalletKey; +use cdk::wallet::MultiMintWallet; use clap::Args; #[derive(Args)] @@ -12,11 +12,15 @@ pub struct RestoreSubCommand { } pub async fn restore( - wallets: HashMap, + multi_mint_wallet: &MultiMintWallet, sub_command_args: &RestoreSubCommand, ) -> Result<()> { - let wallet = wallets - .get(&sub_command_args.mint_url) + let wallet = multi_mint_wallet + .get_wallet(&WalletKey::new( + sub_command_args.mint_url.clone(), + CurrencyUnit::Sat, + )) + .await .ok_or(anyhow!("Unknown mint url"))?; let amount = wallet.restore().await?; diff --git a/crates/cdk-cli/src/sub_commands/send.rs b/crates/cdk-cli/src/sub_commands/send.rs index 5d006e56..92a1206a 100644 --- a/crates/cdk-cli/src/sub_commands/send.rs +++ b/crates/cdk-cli/src/sub_commands/send.rs @@ -1,14 +1,14 @@ -use std::collections::HashMap; use std::io; use std::io::Write; use std::str::FromStr; use anyhow::{bail, Result}; use cdk::amount::SplitTarget; -use cdk::nuts::{Conditions, PublicKey, SpendingConditions}; +use cdk::nuts::{Conditions, CurrencyUnit, PublicKey, SpendingConditions}; +use cdk::wallet::multi_mint_wallet::WalletKey; use cdk::wallet::types::SendKind; -use cdk::wallet::Wallet; -use cdk::{Amount, UncheckedUrl}; +use cdk::wallet::MultiMintWallet; +use cdk::Amount; use clap::Args; use crate::sub_commands::balance::mint_balances; @@ -48,10 +48,10 @@ pub struct SendSubCommand { } pub async fn send( - wallets: HashMap, + multi_mint_wallet: &MultiMintWallet, sub_command_args: &SendSubCommand, ) -> Result<()> { - let mints_amounts = mint_balances(wallets).await?; + let mints_amounts = mint_balances(multi_mint_wallet).await?; println!("Enter mint number to create token"); @@ -155,6 +155,10 @@ pub async fn send( }; let wallet = mints_amounts[mint_number].0.clone(); + let wallet = multi_mint_wallet + .get_wallet(&WalletKey::new(wallet, CurrencyUnit::Sat)) + .await + .expect("Known wallet"); let send_kind = match (sub_command_args.offline, sub_command_args.tolerance) { (true, Some(amount)) => SendKind::OfflineTolerance(Amount::from(amount)), diff --git a/crates/cdk-cli/src/sub_commands/update_mint_url.rs b/crates/cdk-cli/src/sub_commands/update_mint_url.rs index f2601c77..0a30063e 100644 --- a/crates/cdk-cli/src/sub_commands/update_mint_url.rs +++ b/crates/cdk-cli/src/sub_commands/update_mint_url.rs @@ -1,8 +1,8 @@ -use std::collections::HashMap; - use anyhow::{anyhow, Result}; +use cdk::nuts::CurrencyUnit; use cdk::url::UncheckedUrl; -use cdk::wallet::Wallet; +use cdk::wallet::multi_mint_wallet::WalletKey; +use cdk::wallet::MultiMintWallet; use clap::Args; #[derive(Args)] @@ -14,7 +14,7 @@ pub struct UpdateMintUrlSubCommand { } pub async fn update_mint_url( - wallets: HashMap, + multi_mint_wallet: &MultiMintWallet, sub_command_args: &UpdateMintUrlSubCommand, ) -> Result<()> { let UpdateMintUrlSubCommand { @@ -22,8 +22,12 @@ pub async fn update_mint_url( new_mint_url, } = sub_command_args; - let mut wallet = wallets - .get(old_mint_url) + let mut wallet = multi_mint_wallet + .get_wallet(&WalletKey::new( + sub_command_args.old_mint_url.clone(), + CurrencyUnit::Sat, + )) + .await .ok_or(anyhow!("Unknown mint url"))? .clone(); diff --git a/crates/cdk/src/wallet/mod.rs b/crates/cdk/src/wallet/mod.rs index 0b0d8a33..6ef28d30 100644 --- a/crates/cdk/src/wallet/mod.rs +++ b/crates/cdk/src/wallet/mod.rs @@ -35,6 +35,7 @@ pub mod multi_mint_wallet; pub mod types; pub mod util; +pub use multi_mint_wallet::MultiMintWallet; pub use types::{MeltQuote, MintQuote, SendKind}; /// CDK Wallet