Skip to content

Commit 55e0a11

Browse files
author
b-l-u-e
committed
fix(cdk-cli): parse --unit consistently and scope balance by currency
Signed-off-by: b-l-u-e <8102260+blue@users.noreply.github.com>
1 parent 4cefece commit 55e0a11

3 files changed

Lines changed: 50 additions & 11 deletions

File tree

crates/cdk-cli/src/main.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,10 @@ struct Cli {
5656
/// NWS Proxy
5757
#[arg(short, long)]
5858
proxy: Option<Url>,
59-
/// Currency unit to use for the wallet
60-
#[arg(short, long, default_value = "sat")]
61-
unit: String,
59+
/// Currency unit (default `sat` when omitted). Standard: sat, msat, usd, eur, auth; other values are custom.
60+
/// `cdk --unit usd balance` and `cdk balance --unit usd` are equivalent. `cdk --unit balance` parses `balance` as the unit value, not the subcommand.
61+
#[arg(short, long, global = true)]
62+
unit: Option<String>,
6263
/// NpubCash API URL
6364
#[cfg(feature = "npubcash")]
6465
#[arg(long, default_value = "https://npubx.cash")]
@@ -215,9 +216,10 @@ async fn main() -> Result<()> {
215216
};
216217
let seed = mnemonic.to_seed_normalized("");
217218

218-
// Parse currency unit from args
219-
let currency_unit = CurrencyUnit::from_str(&args.unit)
220-
.unwrap_or_else(|_| CurrencyUnit::Custom(args.unit.clone()));
219+
let currency_unit = match &args.unit {
220+
Some(s) => utils::parse_cli_currency_unit(s)?,
221+
None => CurrencyUnit::Sat,
222+
};
221223

222224
// Create WalletRepository using builder pattern
223225
let wallet_repository = {
@@ -252,7 +254,9 @@ async fn main() -> Result<()> {
252254
Commands::DecodeToken(sub_command_args) => {
253255
sub_commands::decode_token::decode_token(sub_command_args)
254256
}
255-
Commands::Balance => sub_commands::balance::balance(&wallet_repository).await,
257+
Commands::Balance => {
258+
sub_commands::balance::balance(&wallet_repository, &currency_unit).await
259+
}
256260
Commands::Melt(sub_command_args) => {
257261
sub_commands::melt::pay(&wallet_repository, sub_command_args, &currency_unit).await
258262
}

crates/cdk-cli/src/sub_commands/balance.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,13 @@ use cdk::wallet::WalletRepository;
77
use cdk::Amount;
88
use cdk_common::wallet::WalletKey;
99

10-
pub async fn balance(wallet_repository: &WalletRepository) -> Result<()> {
11-
// Show individual mint balances
12-
let mint_balances = mint_balances(wallet_repository).await?;
10+
/// Print balances for each mint for the given [`CurrencyUnit`] (e.g. sat from `cdk balance`, or
11+
/// `--unit usd` for USD-only wallets).
12+
pub async fn balance(
13+
wallet_repository: &WalletRepository,
14+
filter_unit: &CurrencyUnit,
15+
) -> Result<()> {
16+
let mint_balances = mint_balances(wallet_repository, filter_unit).await?;
1317

1418
if !mint_balances.is_empty() {
1519
// Aggregate totals per currency unit
@@ -29,13 +33,16 @@ pub async fn balance(wallet_repository: &WalletRepository) -> Result<()> {
2933
println!(" {} {}", total, unit);
3034
}
3135
}
36+
} else {
37+
println!("No balance for unit {filter_unit}.");
3238
}
3339

3440
Ok(())
3541
}
3642

3743
pub async fn mint_balances(
3844
wallet_repository: &WalletRepository,
45+
filter_unit: &CurrencyUnit,
3946
) -> Result<Vec<(MintUrl, CurrencyUnit, Amount)>> {
4047
let wallets = wallet_repository.get_balances().await?;
4148

@@ -44,6 +51,7 @@ pub async fn mint_balances(
4451
for (i, (wallet_key, amount)) in wallets
4552
.iter()
4653
.filter(|(_, a)| a > &&Amount::ZERO)
54+
.filter(|(wk, _)| wk.unit == *filter_unit)
4755
.enumerate()
4856
{
4957
let WalletKey { mint_url, unit } = wallet_key.clone();

crates/cdk-cli/src/utils.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,38 @@
11
use std::io::{self, Write};
22
use std::str::FromStr;
33

4-
use anyhow::Result;
4+
use anyhow::{bail, Result};
55
use cdk::mint_url::MintUrl;
66
use cdk::nuts::CurrencyUnit;
77
use cdk::wallet::WalletRepository;
88

9+
/// Parse global `--unit`: trim, plural aliases (`sats`→`sat`, …), then [`CurrencyUnit::from_str`].
10+
pub fn parse_cli_currency_unit(s: &str) -> Result<CurrencyUnit> {
11+
let trimmed = s.trim();
12+
if trimmed.is_empty() {
13+
bail!("Currency unit must not be empty (omit `--unit` to use the default `sat`)");
14+
}
15+
16+
if trimmed.eq_ignore_ascii_case("satt") {
17+
bail!("Unknown currency unit '{trimmed}'. Did you mean 'sat'?");
18+
}
19+
20+
let normalized: &str = match trimmed.to_ascii_lowercase().as_str() {
21+
"sats" => "sat",
22+
"msats" => "msat",
23+
"usds" => "usd",
24+
"eurs" => "eur",
25+
"auths" => "auth",
26+
_ => trimmed,
27+
};
28+
29+
let unit = CurrencyUnit::from_str(normalized).map_err(|e| anyhow::anyhow!(e))?;
30+
if let CurrencyUnit::Custom(ref name) = unit {
31+
tracing::info!("Using custom currency unit '{name}' (not one of sat, msat, usd, eur, auth)");
32+
}
33+
Ok(unit)
34+
}
35+
936
/// Helper function to get user input with a prompt
1037
pub fn get_user_input(prompt: &str) -> Result<String> {
1138
println!("{prompt}");

0 commit comments

Comments
 (0)