diff --git a/crates/cdk-cli/src/sub_commands/mint.rs b/crates/cdk-cli/src/sub_commands/mint.rs index 46ce6a27c..ea7c76a72 100644 --- a/crates/cdk-cli/src/sub_commands/mint.rs +++ b/crates/cdk-cli/src/sub_commands/mint.rs @@ -6,7 +6,7 @@ use anyhow::Result; use cdk::amount::SplitTarget; use cdk::cdk_database::{Error, WalletDatabase}; use cdk::mint_url::MintUrl; -use cdk::nuts::{CurrencyUnit, MintQuoteState}; +use cdk::nuts::{CurrencyUnit, MintQuoteState, PaymentMethod}; use cdk::wallet::multi_mint_wallet::WalletKey; use cdk::wallet::{MultiMintWallet, Wallet}; use cdk::Amount; @@ -23,6 +23,9 @@ pub struct MintSubCommand { /// Currency unit e.g. sat #[arg(default_value = "sat")] unit: String, + /// Payment method + #[arg(short, long, default_value = "bolt11")] + method: String, /// Quote description #[serde(skip_serializing_if = "Option::is_none")] description: Option, @@ -51,9 +54,21 @@ pub async fn mint( } }; - let quote = wallet - .mint_quote(Amount::from(sub_command_args.amount), description) - .await?; + let method = PaymentMethod::from_str(&sub_command_args.method)?; + + let quote = match method { + PaymentMethod::Bolt11 => { + wallet + .mint_quote(Amount::from(sub_command_args.amount), description) + .await? + } + PaymentMethod::Bolt12 => { + wallet + .mint_bolt12_quote(Amount::from(sub_command_args.amount), description) + .await? + } + _ => panic!("Unsupported unit"), + }; println!("Quote: {:#?}", quote); diff --git a/crates/cdk/src/wallet/client.rs b/crates/cdk/src/wallet/client.rs index 63d49db69..37a271c3b 100644 --- a/crates/cdk/src/wallet/client.rs +++ b/crates/cdk/src/wallet/client.rs @@ -156,6 +156,41 @@ impl HttpClient { } } + /// Mint Quote [NUT-04] + #[instrument(skip(self), fields(mint_url = %mint_url))] + pub async fn post_mint_bolt12_quote( + &self, + mint_url: Url, + amount: Amount, + unit: CurrencyUnit, + description: Option, + ) -> Result { + let url = join_url(mint_url, &["v1", "mint", "quote", "bolt12"])?; + + let request = MintQuoteBolt11Request { + amount, + unit, + description, + }; + + let res = self + .inner + .post(url) + .json(&request) + .send() + .await? + .json::() + .await?; + + match serde_json::from_value::(res.clone()) { + Ok(mint_quote_response) => Ok(mint_quote_response), + Err(err) => { + tracing::warn!("{}", err); + Err(ErrorResponse::from_value(res)?.into()) + } + } + } + /// Mint Quote status #[instrument(skip(self), fields(mint_url = %mint_url))] pub async fn get_mint_quote_status( diff --git a/crates/cdk/src/wallet/mint.rs b/crates/cdk/src/wallet/mint.rs index 6b2414529..3311886ca 100644 --- a/crates/cdk/src/wallet/mint.rs +++ b/crates/cdk/src/wallet/mint.rs @@ -84,6 +84,54 @@ impl Wallet { Ok(quote) } + /// Mint Bolt12 + #[instrument(skip(self))] + pub async fn mint_bolt12_quote( + &self, + amount: Amount, + description: Option, + ) -> Result { + let mint_url = self.mint_url.clone(); + let unit = self.unit; + + // If we have a description, we check that the mint supports it. + // If we have a description, we check that the mint supports it. + if description.is_some() { + let mint_method_settings = self + .localstore + .get_mint(mint_url.clone()) + .await? + .ok_or(Error::IncorrectMint)? + .nuts + .nut04 + .get_settings(&unit, &crate::nuts::PaymentMethod::Bolt11) + .ok_or(Error::UnsupportedUnit)?; + + if !mint_method_settings.description { + return Err(Error::InvoiceDescriptionUnsupported); + } + } + + let quote_res = self + .client + .post_mint_bolt12_quote(mint_url.clone().try_into()?, amount, unit, description) + .await?; + + let quote = MintQuote { + mint_url, + id: quote_res.quote.clone(), + amount, + unit, + request: quote_res.request, + state: quote_res.state, + expiry: quote_res.expiry.unwrap_or(0), + }; + + self.localstore.add_mint_quote(quote.clone()).await?; + + Ok(quote) + } + /// Check mint quote status #[instrument(skip(self, quote_id))] pub async fn mint_quote_state(&self, quote_id: &str) -> Result { diff --git a/crates/cdk/src/wallet/multi_mint_wallet.rs b/crates/cdk/src/wallet/multi_mint_wallet.rs index c20336050..13626d268 100644 --- a/crates/cdk/src/wallet/multi_mint_wallet.rs +++ b/crates/cdk/src/wallet/multi_mint_wallet.rs @@ -16,7 +16,7 @@ use super::types::SendKind; use super::Error; use crate::amount::SplitTarget; use crate::mint_url::MintUrl; -use crate::nuts::{CurrencyUnit, SecretKey, SpendingConditions, Token}; +use crate::nuts::{CurrencyUnit, PaymentMethod, SecretKey, SpendingConditions, Token}; use crate::types::Melted; use crate::wallet::types::MintQuote; use crate::{Amount, Wallet}; @@ -152,6 +152,7 @@ impl MultiMintWallet { wallet_key: &WalletKey, amount: Amount, description: Option, + payment_method: PaymentMethod, ) -> Result { let wallet = self .get_wallet(wallet_key)