Bladeren bron

fix: show ammounts (#1136)

thesimplekid 1 maand geleden
bovenliggende
commit
5e93529398
2 gewijzigde bestanden met toevoegingen van 143 en 102 verwijderingen
  1. 76 67
      crates/cdk-cli/src/sub_commands/melt.rs
  2. 67 35
      crates/cdk-cli/src/sub_commands/send.rs

+ 76 - 67
crates/cdk-cli/src/sub_commands/melt.rs

@@ -71,6 +71,50 @@ pub async fn pay(
         bail!("No funds available");
     }
 
+    // Determine which mint to use for melting BEFORE processing payment (unless using MPP)
+    let selected_mint = if sub_command_args.mpp {
+        None // MPP mode handles mint selection differently
+    } else if let Some(mint_url) = &sub_command_args.mint_url {
+        Some(MintUrl::from_str(mint_url)?)
+    } else {
+        // Display all mints with their balances and let user select
+        let balances_map = multi_mint_wallet.get_balances().await?;
+        if balances_map.is_empty() {
+            bail!("No mints available in the wallet");
+        }
+
+        let balances_vec: Vec<(MintUrl, Amount)> = balances_map.into_iter().collect();
+
+        println!("\nAvailable mints and balances:");
+        for (index, (mint_url, balance)) in balances_vec.iter().enumerate() {
+            println!(
+                "  {}: {} - {} {}",
+                index,
+                mint_url,
+                balance,
+                multi_mint_wallet.unit()
+            );
+        }
+        println!("  {}: Any mint (auto-select best)", balances_vec.len());
+
+        let selection = loop {
+            let selection: usize =
+                get_number_input("Enter mint number to melt from (or select Any)")?;
+
+            if selection == balances_vec.len() {
+                break None; // "Any" option selected
+            }
+
+            if let Some((mint_url, _)) = balances_vec.get(selection) {
+                break Some(mint_url.clone());
+            }
+
+            println!("Invalid selection, please try again.");
+        };
+
+        selection
+    };
+
     if sub_command_args.mpp {
         // Manual MPP - user specifies which mints and amounts to use
         if !matches!(sub_command_args.method, PaymentType::Bolt11) {
@@ -180,12 +224,9 @@ pub async fn pay(
                 let options =
                     create_melt_options(available_funds, bolt11.amount_milli_satoshis(), &prompt)?;
 
-                // Use mint-specific functions or auto-select
-                let melted = if let Some(mint_url) = &sub_command_args.mint_url {
-                    // User specified a mint - use the new mint-specific functions
-                    let mint_url = MintUrl::from_str(mint_url)?;
-
-                    // Create a melt quote for the specific mint
+                // Use selected mint or auto-select
+                let melted = if let Some(mint_url) = selected_mint {
+                    // User selected a specific mint - use the new mint-specific functions
                     let quote = multi_mint_wallet
                         .melt_quote(&mint_url, bolt11_str.clone(), options)
                         .await?;
@@ -200,7 +241,7 @@ pub async fn pay(
                         .melt_with_mint(&mint_url, &quote.id)
                         .await?
                 } else {
-                    // Let the wallet automatically select the best mint
+                    // User selected "Any" - let the wallet auto-select the best mint
                     multi_mint_wallet.melt(&bolt11_str, options, None).await?
                 };
 
@@ -227,41 +268,25 @@ pub async fn pay(
 
                 let options = create_melt_options(available_funds, amount_msat, &prompt)?;
 
-                // Get wallet for BOLT12
-                let wallet = if let Some(mint_url) = &sub_command_args.mint_url {
-                    // User specified a mint
-                    let mint_url = MintUrl::from_str(mint_url)?;
-                    multi_mint_wallet
-                        .get_wallet(&mint_url)
-                        .await
-                        .ok_or_else(|| anyhow::anyhow!("Mint {} not found", mint_url))?
+                // Get wallet for BOLT12 using the selected mint
+                let mint_url = if let Some(specific_mint) = selected_mint {
+                    specific_mint
                 } else {
-                    // Show available mints and let user select
+                    // User selected "Any" - just pick the first mint with any balance
                     let balances = multi_mint_wallet.get_balances().await?;
-                    println!("\nAvailable mints:");
-                    for (i, (mint_url, balance)) in balances.iter().enumerate() {
-                        println!(
-                            "  {}: {} - {} {}",
-                            i,
-                            mint_url,
-                            balance,
-                            multi_mint_wallet.unit()
-                        );
-                    }
-
-                    let mint_number: usize = get_number_input("Enter mint number to melt from")?;
-                    let selected_mint = balances
-                        .iter()
-                        .nth(mint_number)
-                        .map(|(url, _)| url)
-                        .ok_or_else(|| anyhow::anyhow!("Invalid mint number"))?;
 
-                    multi_mint_wallet
-                        .get_wallet(selected_mint)
-                        .await
-                        .ok_or_else(|| anyhow::anyhow!("Mint {} not found", selected_mint))?
+                    balances
+                        .into_iter()
+                        .find(|(_, balance)| *balance > Amount::ZERO)
+                        .map(|(mint_url, _)| mint_url)
+                        .ok_or_else(|| anyhow::anyhow!("No mint available for BOLT12 payment"))?
                 };
 
+                let wallet = multi_mint_wallet
+                    .get_wallet(&mint_url)
+                    .await
+                    .ok_or_else(|| anyhow::anyhow!("Mint {} not found", mint_url))?;
+
                 // Get melt quote for BOLT12
                 let quote = wallet.melt_bolt12_quote(offer_str, options).await?;
 
@@ -293,41 +318,25 @@ pub async fn pay(
                 // BIP353 payments are always amountless for now
                 let options = create_melt_options(available_funds, None, &prompt)?;
 
-                // Get wallet for BIP353
-                let wallet = if let Some(mint_url) = &sub_command_args.mint_url {
-                    // User specified a mint
-                    let mint_url = MintUrl::from_str(mint_url)?;
-                    multi_mint_wallet
-                        .get_wallet(&mint_url)
-                        .await
-                        .ok_or_else(|| anyhow::anyhow!("Mint {} not found", mint_url))?
+                // Get wallet for BIP353 using the selected mint
+                let mint_url = if let Some(specific_mint) = selected_mint {
+                    specific_mint
                 } else {
-                    // Show available mints and let user select
+                    // User selected "Any" - just pick the first mint with any balance
                     let balances = multi_mint_wallet.get_balances().await?;
-                    println!("\nAvailable mints:");
-                    for (i, (mint_url, balance)) in balances.iter().enumerate() {
-                        println!(
-                            "  {}: {} - {} {}",
-                            i,
-                            mint_url,
-                            balance,
-                            multi_mint_wallet.unit()
-                        );
-                    }
-
-                    let mint_number: usize = get_number_input("Enter mint number to melt from")?;
-                    let selected_mint = balances
-                        .iter()
-                        .nth(mint_number)
-                        .map(|(url, _)| url)
-                        .ok_or_else(|| anyhow::anyhow!("Invalid mint number"))?;
 
-                    multi_mint_wallet
-                        .get_wallet(selected_mint)
-                        .await
-                        .ok_or_else(|| anyhow::anyhow!("Mint {} not found", selected_mint))?
+                    balances
+                        .into_iter()
+                        .find(|(_, balance)| *balance > Amount::ZERO)
+                        .map(|(mint_url, _)| mint_url)
+                        .ok_or_else(|| anyhow::anyhow!("No mint available for BIP353 payment"))?
                 };
 
+                let wallet = multi_mint_wallet
+                    .get_wallet(&mint_url)
+                    .await
+                    .ok_or_else(|| anyhow::anyhow!("Mint {} not found", mint_url))?;
+
                 // Get melt quote for BIP353 address (internally resolves and gets BOLT12 quote)
                 let quote = wallet
                     .melt_bip353_quote(

+ 67 - 35
crates/cdk-cli/src/sub_commands/send.rs

@@ -54,9 +54,7 @@ pub struct SendSubCommand {
     /// Maximum amount to transfer from other mints
     #[arg(long)]
     max_transfer_amount: Option<u64>,
-    /// Specific mints allowed for transfers (can be specified multiple times)
-    #[arg(long, action = clap::ArgAction::Append)]
-    allowed_mints: Vec<String>,
+
     /// Specific mints to exclude from transfers (can be specified multiple times)
     #[arg(long, action = clap::ArgAction::Append)]
     excluded_mints: Vec<String>,
@@ -66,6 +64,48 @@ pub async fn send(
     multi_mint_wallet: &MultiMintWallet,
     sub_command_args: &SendSubCommand,
 ) -> Result<()> {
+    // Determine which mint to use for sending BEFORE asking for amount
+    let selected_mint = if let Some(mint_url) = &sub_command_args.mint_url {
+        Some(MintUrl::from_str(mint_url)?)
+    } else {
+        // Display all mints with their balances and let user select
+        let balances_map = multi_mint_wallet.get_balances().await?;
+        if balances_map.is_empty() {
+            return Err(anyhow!("No mints available in the wallet"));
+        }
+
+        let balances_vec: Vec<(MintUrl, Amount)> = balances_map.into_iter().collect();
+
+        println!("\nAvailable mints and balances:");
+        for (index, (mint_url, balance)) in balances_vec.iter().enumerate() {
+            println!(
+                "  {}: {} - {} {}",
+                index,
+                mint_url,
+                balance,
+                multi_mint_wallet.unit()
+            );
+        }
+        println!("  {}: Any mint (auto-select best)", balances_vec.len());
+
+        let selection = loop {
+            let selection: usize =
+                get_number_input("Enter mint number to send from (or select Any)")?;
+
+            if selection == balances_vec.len() {
+                break None; // "Any" option selected
+            }
+
+            if let Some((mint_url, _)) = balances_vec.get(selection) {
+                break Some(mint_url.clone());
+            }
+
+            println!("Invalid selection, please try again.");
+        };
+
+        selection
+    };
+
     let token_amount = Amount::from(get_number_input::<u64>(&format!(
         "Enter value of token in {}",
         multi_mint_wallet.unit()
@@ -214,14 +254,7 @@ pub async fn send(
         ..Default::default()
     };
 
-    // Parse allowed and excluded mints from CLI arguments
-    let allowed_mints: Result<Vec<MintUrl>, _> = sub_command_args
-        .allowed_mints
-        .iter()
-        .map(|url| MintUrl::from_str(url))
-        .collect();
-    let allowed_mints = allowed_mints?;
-
+    // Parse excluded mints from CLI arguments
     let excluded_mints: Result<Vec<MintUrl>, _> = sub_command_args
         .excluded_mints
         .iter()
@@ -229,45 +262,44 @@ pub async fn send(
         .collect();
     let excluded_mints = excluded_mints?;
 
-    // Create MultiMintSendOptions from CLI arguments
-    let multi_mint_options = cdk::wallet::multi_mint_wallet::MultiMintSendOptions {
-        allow_transfer: sub_command_args.allow_transfer,
-        max_transfer_amount: sub_command_args.max_transfer_amount.map(Amount::from),
-        allowed_mints,
-        excluded_mints,
-        send_options: send_options.clone(),
-    };
+    // Prepare and confirm the send based on mint selection
+    let token = if let Some(specific_mint) = selected_mint {
+        // User selected a specific mint
+        let multi_mint_options = cdk::wallet::multi_mint_wallet::MultiMintSendOptions {
+            allow_transfer: sub_command_args.allow_transfer,
+            max_transfer_amount: sub_command_args.max_transfer_amount.map(Amount::from),
+            allowed_mints: vec![specific_mint.clone()], // Use selected mint as the only allowed mint
+            excluded_mints,
+            send_options: send_options.clone(),
+        };
 
-    // Use the new unified interface
-    let token = if let Some(mint_url) = &sub_command_args.mint_url {
-        // User specified a mint, use that specific wallet
-        let mint_url = cdk::mint_url::MintUrl::from_str(mint_url)?;
         let prepared = multi_mint_wallet
-            .prepare_send(mint_url, token_amount, multi_mint_options)
+            .prepare_send(specific_mint, token_amount, multi_mint_options)
             .await?;
 
-        // Confirm the prepared send (single mint)
         let memo = send_options.memo.clone();
         prepared.confirm(memo).await?
     } else {
-        // Let the wallet automatically select the best mint
-        // First, get balances to find a mint with sufficient funds
+        // User selected "Any" - find the first mint with sufficient balance
         let balances = multi_mint_wallet.get_balances().await?;
-
-        // Find a mint with sufficient balance
-        let mint_url = balances
+        let best_mint = balances
             .into_iter()
             .find(|(_, balance)| *balance >= token_amount)
             .map(|(mint_url, _)| mint_url)
-            .ok_or_else(|| {
-                anyhow::anyhow!("No mint has sufficient balance for the requested amount")
-            })?;
+            .ok_or_else(|| anyhow!("No mint has sufficient balance for the requested amount"))?;
+
+        let multi_mint_options = cdk::wallet::multi_mint_wallet::MultiMintSendOptions {
+            allow_transfer: sub_command_args.allow_transfer,
+            max_transfer_amount: sub_command_args.max_transfer_amount.map(Amount::from),
+            allowed_mints: vec![best_mint.clone()], // Use the best mint as the only allowed mint
+            excluded_mints,
+            send_options: send_options.clone(),
+        };
 
         let prepared = multi_mint_wallet
-            .prepare_send(mint_url, token_amount, multi_mint_options)
+            .prepare_send(best_mint, token_amount, multi_mint_options)
             .await?;
 
-        // Confirm the prepared send (multi mint)
         let memo = send_options.memo.clone();
         prepared.confirm(memo).await?
     };