Browse Source

NUT-04 Mint Quote Description (#337)

lollerfirst 7 months ago
parent
commit
7e860c71f2

+ 6 - 2
bindings/cdk-js/src/wallet.rs

@@ -86,10 +86,14 @@ impl JsWallet {
     }
 
     #[wasm_bindgen(js_name = mintQuote)]
-    pub async fn mint_quote(&mut self, amount: u64) -> Result<JsMintQuote> {
+    pub async fn mint_quote(
+        &mut self,
+        amount: u64,
+        description: Option<String>,
+    ) -> Result<JsMintQuote> {
         let quote = self
             .inner
-            .mint_quote(amount.into())
+            .mint_quote(amount.into(), description)
             .await
             .map_err(into_err)?;
 

+ 11 - 3
crates/cdk-axum/src/router_handlers.rs

@@ -64,14 +64,22 @@ pub async fn get_mint_bolt11_quote(
 
     let amount =
         to_unit(payload.amount, &payload.unit, &ln.get_settings().unit).map_err(|err| {
-            tracing::error!("Backed does not support unit: {}", err);
+            tracing::error!("Backend does not support unit: {}", err);
             into_response(Error::UnitUnsupported)
         })?;
 
     let quote_expiry = unix_time() + state.quote_ttl;
-
+    if payload.description.is_some() && !ln.get_settings().invoice_description {
+        tracing::error!("Backend does not support invoice description");
+        return Err(into_response(Error::InvoiceDescriptionUnsupported));
+    }
     let create_invoice_response = ln
-        .create_invoice(amount, &payload.unit, "".to_string(), quote_expiry)
+        .create_invoice(
+            amount,
+            &payload.unit,
+            payload.description.unwrap_or("".to_string()),
+            quote_expiry,
+        )
         .await
         .map_err(|err| {
             tracing::error!("Could not create invoice: {}", err);

+ 7 - 2
crates/cdk-cli/src/sub_commands/mint.rs

@@ -11,9 +11,10 @@ use cdk::wallet::multi_mint_wallet::WalletKey;
 use cdk::wallet::{MultiMintWallet, Wallet};
 use cdk::Amount;
 use clap::Args;
+use serde::{Deserialize, Serialize};
 use tokio::time::sleep;
 
-#[derive(Args)]
+#[derive(Args, Serialize, Deserialize)]
 pub struct MintSubCommand {
     /// Mint url
     mint_url: MintUrl,
@@ -22,6 +23,9 @@ pub struct MintSubCommand {
     /// Currency unit e.g. sat
     #[arg(default_value = "sat")]
     unit: String,
+    /// Quote description
+    #[serde(skip_serializing_if = "Option::is_none")]
+    description: Option<String>,
 }
 
 pub async fn mint(
@@ -32,6 +36,7 @@ pub async fn mint(
 ) -> Result<()> {
     let mint_url = sub_command_args.mint_url.clone();
     let unit = CurrencyUnit::from_str(&sub_command_args.unit)?;
+    let description: Option<String> = sub_command_args.description.clone();
 
     let wallet = match multi_mint_wallet
         .get_wallet(&WalletKey::new(mint_url.clone(), CurrencyUnit::Sat))
@@ -47,7 +52,7 @@ pub async fn mint(
     };
 
     let quote = wallet
-        .mint_quote(Amount::from(sub_command_args.amount))
+        .mint_quote(Amount::from(sub_command_args.amount), description)
         .await?;
 
     println!("Quote: {:#?}", quote);

+ 13 - 9
crates/cdk-cln/src/lib.rs

@@ -12,11 +12,14 @@ use std::time::Duration;
 use async_trait::async_trait;
 use cdk::amount::Amount;
 use cdk::cdk_lightning::{
-    self, to_unit, CreateInvoiceResponse, MintLightning, MintMeltSettings, PayInvoiceResponse,
-    PaymentQuoteResponse, Settings,
+    self, to_unit, CreateInvoiceResponse, MintLightning, PayInvoiceResponse, PaymentQuoteResponse,
+    Settings,
 };
 use cdk::mint::FeeReserve;
-use cdk::nuts::{CurrencyUnit, MeltQuoteBolt11Request, MeltQuoteState, MintQuoteState};
+use cdk::nuts::{
+    CurrencyUnit, MeltMethodSettings, MeltQuoteBolt11Request, MeltQuoteState, MintMethodSettings,
+    MintQuoteState,
+};
 use cdk::util::{hex, unix_time};
 use cdk::{mint, Bolt11Invoice};
 use cln_rpc::model::requests::{
@@ -40,8 +43,8 @@ pub struct Cln {
     rpc_socket: PathBuf,
     cln_client: Arc<Mutex<cln_rpc::ClnRpc>>,
     fee_reserve: FeeReserve,
-    mint_settings: MintMeltSettings,
-    melt_settings: MintMeltSettings,
+    mint_settings: MintMethodSettings,
+    melt_settings: MeltMethodSettings,
 }
 
 impl Cln {
@@ -49,8 +52,8 @@ impl Cln {
     pub async fn new(
         rpc_socket: PathBuf,
         fee_reserve: FeeReserve,
-        mint_settings: MintMeltSettings,
-        melt_settings: MintMeltSettings,
+        mint_settings: MintMethodSettings,
+        melt_settings: MeltMethodSettings,
     ) -> Result<Self, Error> {
         let cln_client = cln_rpc::ClnRpc::new(&rpc_socket).await?;
 
@@ -72,8 +75,9 @@ impl MintLightning for Cln {
         Settings {
             mpp: true,
             unit: CurrencyUnit::Msat,
-            mint_settings: self.mint_settings,
-            melt_settings: self.melt_settings,
+            mint_settings: self.mint_settings.clone(),
+            melt_settings: self.melt_settings.clone(),
+            invoice_description: true,
         }
     }
 

+ 13 - 9
crates/cdk-fake-wallet/src/lib.rs

@@ -13,12 +13,15 @@ use bitcoin::hashes::{sha256, Hash};
 use bitcoin::secp256k1::{Secp256k1, SecretKey};
 use cdk::amount::Amount;
 use cdk::cdk_lightning::{
-    self, to_unit, CreateInvoiceResponse, MintLightning, MintMeltSettings, PayInvoiceResponse,
-    PaymentQuoteResponse, Settings,
+    self, to_unit, CreateInvoiceResponse, MintLightning, PayInvoiceResponse, PaymentQuoteResponse,
+    Settings,
 };
 use cdk::mint;
 use cdk::mint::FeeReserve;
-use cdk::nuts::{CurrencyUnit, MeltQuoteBolt11Request, MeltQuoteState, MintQuoteState};
+use cdk::nuts::{
+    CurrencyUnit, MeltMethodSettings, MeltQuoteBolt11Request, MeltQuoteState, MintMethodSettings,
+    MintQuoteState,
+};
 use cdk::util::unix_time;
 use error::Error;
 use futures::stream::StreamExt;
@@ -37,16 +40,16 @@ pub struct FakeWallet {
     fee_reserve: FeeReserve,
     sender: tokio::sync::mpsc::Sender<String>,
     receiver: Arc<Mutex<Option<tokio::sync::mpsc::Receiver<String>>>>,
-    mint_settings: MintMeltSettings,
-    melt_settings: MintMeltSettings,
+    mint_settings: MintMethodSettings,
+    melt_settings: MeltMethodSettings,
 }
 
 impl FakeWallet {
     /// Creat new [`FakeWallet`]
     pub fn new(
         fee_reserve: FeeReserve,
-        mint_settings: MintMeltSettings,
-        melt_settings: MintMeltSettings,
+        mint_settings: MintMethodSettings,
+        melt_settings: MeltMethodSettings,
     ) -> Self {
         let (sender, receiver) = tokio::sync::mpsc::channel(8);
 
@@ -68,8 +71,9 @@ impl MintLightning for FakeWallet {
         Settings {
             mpp: true,
             unit: CurrencyUnit::Msat,
-            melt_settings: self.melt_settings,
-            mint_settings: self.mint_settings,
+            melt_settings: self.melt_settings.clone(),
+            mint_settings: self.mint_settings.clone(),
+            invoice_description: true,
         }
     }
 

+ 9 - 6
crates/cdk-integration-tests/src/lib.rs

@@ -7,11 +7,12 @@ use axum::Router;
 use bip39::Mnemonic;
 use cdk::amount::{Amount, SplitTarget};
 use cdk::cdk_database::mint_memory::MintMemoryDatabase;
-use cdk::cdk_lightning::{MintLightning, MintMeltSettings};
+use cdk::cdk_lightning::MintLightning;
 use cdk::dhke::construct_proofs;
 use cdk::mint::FeeReserve;
 use cdk::nuts::{
-    CurrencyUnit, Id, KeySet, MintInfo, MintQuoteState, Nuts, PaymentMethod, PreMintSecrets, Proofs,
+    CurrencyUnit, Id, KeySet, MeltMethodSettings, MintInfo, MintMethodSettings, MintQuoteState,
+    Nuts, PaymentMethod, PreMintSecrets, Proofs,
 };
 use cdk::wallet::client::HttpClient;
 use cdk::{Mint, Wallet};
@@ -39,8 +40,8 @@ pub fn create_backends_fake_wallet(
 
     let wallet = Arc::new(FakeWallet::new(
         fee_reserve.clone(),
-        MintMeltSettings::default(),
-        MintMeltSettings::default(),
+        MintMethodSettings::default(),
+        MeltMethodSettings::default(),
     ));
 
     ln_backends.insert(ln_key, wallet.clone());
@@ -152,8 +153,9 @@ pub async fn wallet_mint(
     wallet: Arc<Wallet>,
     amount: Amount,
     split_target: SplitTarget,
+    description: Option<String>,
 ) -> Result<()> {
-    let quote = wallet.mint_quote(amount).await?;
+    let quote = wallet.mint_quote(amount, description).await?;
 
     loop {
         let status = wallet.mint_quote_state(&quote.id).await?;
@@ -178,6 +180,7 @@ pub async fn mint_proofs(
     amount: Amount,
     keyset_id: Id,
     mint_keys: &KeySet,
+    description: Option<String>,
 ) -> anyhow::Result<Proofs> {
     println!("Minting for ecash");
     println!();
@@ -185,7 +188,7 @@ pub async fn mint_proofs(
     let wallet_client = HttpClient::new();
 
     let mint_quote = wallet_client
-        .post_mint_quote(mint_url.parse()?, 1.into(), CurrencyUnit::Sat)
+        .post_mint_quote(mint_url.parse()?, 1.into(), CurrencyUnit::Sat, description)
         .await?;
 
     println!("Please pay: {}", mint_quote.request);

+ 13 - 9
crates/cdk-lnbits/src/lib.rs

@@ -11,11 +11,14 @@ use async_trait::async_trait;
 use axum::Router;
 use cdk::amount::Amount;
 use cdk::cdk_lightning::{
-    self, to_unit, CreateInvoiceResponse, MintLightning, MintMeltSettings, PayInvoiceResponse,
-    PaymentQuoteResponse, Settings,
+    self, to_unit, CreateInvoiceResponse, MintLightning, PayInvoiceResponse, PaymentQuoteResponse,
+    Settings,
 };
 use cdk::mint::FeeReserve;
-use cdk::nuts::{CurrencyUnit, MeltQuoteBolt11Request, MeltQuoteState, MintQuoteState};
+use cdk::nuts::{
+    CurrencyUnit, MeltMethodSettings, MeltQuoteBolt11Request, MeltQuoteState, MintMethodSettings,
+    MintQuoteState,
+};
 use cdk::util::unix_time;
 use cdk::{mint, Bolt11Invoice};
 use error::Error;
@@ -31,8 +34,8 @@ pub mod error;
 #[derive(Clone)]
 pub struct LNbits {
     lnbits_api: LNBitsClient,
-    mint_settings: MintMeltSettings,
-    melt_settings: MintMeltSettings,
+    mint_settings: MintMethodSettings,
+    melt_settings: MeltMethodSettings,
     fee_reserve: FeeReserve,
     receiver: Arc<Mutex<Option<tokio::sync::mpsc::Receiver<String>>>>,
     webhook_url: String,
@@ -45,8 +48,8 @@ impl LNbits {
         admin_api_key: String,
         invoice_api_key: String,
         api_url: String,
-        mint_settings: MintMeltSettings,
-        melt_settings: MintMeltSettings,
+        mint_settings: MintMethodSettings,
+        melt_settings: MeltMethodSettings,
         fee_reserve: FeeReserve,
         receiver: Arc<Mutex<Option<tokio::sync::mpsc::Receiver<String>>>>,
         webhook_url: String,
@@ -72,8 +75,9 @@ impl MintLightning for LNbits {
         Settings {
             mpp: false,
             unit: CurrencyUnit::Sat,
-            mint_settings: self.mint_settings,
-            melt_settings: self.melt_settings,
+            mint_settings: self.mint_settings.clone(),
+            melt_settings: self.melt_settings.clone(),
+            invoice_description: true,
         }
     }
 

+ 13 - 9
crates/cdk-lnd/src/lib.rs

@@ -14,11 +14,14 @@ use anyhow::anyhow;
 use async_trait::async_trait;
 use cdk::amount::Amount;
 use cdk::cdk_lightning::{
-    self, to_unit, CreateInvoiceResponse, MintLightning, MintMeltSettings, PayInvoiceResponse,
-    PaymentQuoteResponse, Settings, MSAT_IN_SAT,
+    self, to_unit, CreateInvoiceResponse, MintLightning, PayInvoiceResponse, PaymentQuoteResponse,
+    Settings, MSAT_IN_SAT,
 };
 use cdk::mint::FeeReserve;
-use cdk::nuts::{CurrencyUnit, MeltQuoteBolt11Request, MeltQuoteState, MintQuoteState};
+use cdk::nuts::{
+    CurrencyUnit, MeltMethodSettings, MeltQuoteBolt11Request, MeltQuoteState, MintMethodSettings,
+    MintQuoteState,
+};
 use cdk::util::{hex, unix_time};
 use cdk::{mint, Bolt11Invoice};
 use error::Error;
@@ -38,8 +41,8 @@ pub struct Lnd {
     macaroon_file: PathBuf,
     client: Arc<Mutex<Client>>,
     fee_reserve: FeeReserve,
-    mint_settings: MintMeltSettings,
-    melt_settings: MintMeltSettings,
+    mint_settings: MintMethodSettings,
+    melt_settings: MeltMethodSettings,
 }
 
 impl Lnd {
@@ -49,8 +52,8 @@ impl Lnd {
         cert_file: PathBuf,
         macaroon_file: PathBuf,
         fee_reserve: FeeReserve,
-        mint_settings: MintMeltSettings,
-        melt_settings: MintMeltSettings,
+        mint_settings: MintMethodSettings,
+        melt_settings: MeltMethodSettings,
     ) -> Result<Self, Error> {
         let client = fedimint_tonic_lnd::connect(address.to_string(), &cert_file, &macaroon_file)
             .await
@@ -79,8 +82,9 @@ impl MintLightning for Lnd {
         Settings {
             mpp: true,
             unit: CurrencyUnit::Msat,
-            mint_settings: self.mint_settings,
-            melt_settings: self.melt_settings,
+            mint_settings: self.mint_settings.clone(),
+            melt_settings: self.melt_settings.clone(),
+            invoice_description: true,
         }
     }
 

+ 18 - 17
crates/cdk-mintd/src/main.rs

@@ -13,7 +13,7 @@ use axum::Router;
 use bip39::Mnemonic;
 use cdk::cdk_database::{self, MintDatabase};
 use cdk::cdk_lightning;
-use cdk::cdk_lightning::{MintLightning, MintMeltSettings};
+use cdk::cdk_lightning::MintLightning;
 use cdk::mint::{FeeReserve, Mint};
 use cdk::mint_url::MintUrl;
 use cdk::nuts::{
@@ -150,8 +150,8 @@ async fn main() -> anyhow::Result<()> {
                 Cln::new(
                     cln_socket,
                     fee_reserve,
-                    MintMeltSettings::default(),
-                    MintMeltSettings::default(),
+                    MintMethodSettings::default(),
+                    MeltMethodSettings::default(),
                 )
                 .await?,
             );
@@ -179,8 +179,8 @@ async fn main() -> anyhow::Result<()> {
 
                 let strike = Strike::new(
                     api_key.clone(),
-                    MintMeltSettings::default(),
-                    MintMeltSettings::default(),
+                    MintMethodSettings::default(),
+                    MeltMethodSettings::default(),
                     unit,
                     Arc::new(Mutex::new(Some(receiver))),
                     webhook_url.to_string(),
@@ -216,8 +216,8 @@ async fn main() -> anyhow::Result<()> {
                 admin_api_key,
                 invoice_api_key,
                 lnbits_settings.lnbits_api,
-                MintMeltSettings::default(),
-                MintMeltSettings::default(),
+                MintMethodSettings::default(),
+                MeltMethodSettings::default(),
                 fee_reserve,
                 Arc::new(Mutex::new(Some(receiver))),
                 webhook_url.to_string(),
@@ -265,8 +265,8 @@ async fn main() -> anyhow::Result<()> {
             let phoenixd = Phoenixd::new(
                 api_password.to_string(),
                 api_url.to_string(),
-                MintMeltSettings::default(),
-                MintMeltSettings::default(),
+                MintMethodSettings::default(),
+                MeltMethodSettings::default(),
                 fee_reserve,
                 Arc::new(Mutex::new(Some(receiver))),
                 webhook_url,
@@ -299,8 +299,8 @@ async fn main() -> anyhow::Result<()> {
                 cert_file,
                 macaroon_file,
                 fee_reserve,
-                MintMeltSettings::default(),
-                MintMeltSettings::default(),
+                MintMethodSettings::default(),
+                MeltMethodSettings::default(),
             )
             .await?;
 
@@ -323,8 +323,8 @@ async fn main() -> anyhow::Result<()> {
 
                 let wallet = Arc::new(FakeWallet::new(
                     fee_reserve.clone(),
-                    MintMeltSettings::default(),
-                    MintMeltSettings::default(),
+                    MintMethodSettings::default(),
+                    MeltMethodSettings::default(),
                 ));
 
                 ln_backends.insert(ln_key, wallet);
@@ -358,15 +358,16 @@ async fn main() -> anyhow::Result<()> {
             let n4 = MintMethodSettings {
                 method: key.method.clone(),
                 unit: key.unit,
-                min_amount: Some(settings.mint_settings.min_amount),
-                max_amount: Some(settings.mint_settings.max_amount),
+                min_amount: settings.mint_settings.min_amount,
+                max_amount: settings.mint_settings.max_amount,
+                description: settings.invoice_description,
             };
 
             let n5 = MeltMethodSettings {
                 method: key.method.clone(),
                 unit: key.unit,
-                min_amount: Some(settings.melt_settings.min_amount),
-                max_amount: Some(settings.melt_settings.max_amount),
+                min_amount: settings.melt_settings.min_amount,
+                max_amount: settings.melt_settings.max_amount,
             };
 
             nut_04.methods.push(n4);

+ 13 - 9
crates/cdk-phoenixd/src/lib.rs

@@ -11,11 +11,14 @@ use async_trait::async_trait;
 use axum::Router;
 use cdk::amount::Amount;
 use cdk::cdk_lightning::{
-    self, to_unit, CreateInvoiceResponse, MintLightning, MintMeltSettings, PayInvoiceResponse,
-    PaymentQuoteResponse, Settings, MSAT_IN_SAT,
+    self, to_unit, CreateInvoiceResponse, MintLightning, PayInvoiceResponse, PaymentQuoteResponse,
+    Settings, MSAT_IN_SAT,
 };
 use cdk::mint::FeeReserve;
-use cdk::nuts::{CurrencyUnit, MeltQuoteBolt11Request, MeltQuoteState, MintQuoteState};
+use cdk::nuts::{
+    CurrencyUnit, MeltMethodSettings, MeltQuoteBolt11Request, MeltQuoteState, MintMethodSettings,
+    MintQuoteState,
+};
 use cdk::{mint, Bolt11Invoice};
 use error::Error;
 use futures::{Stream, StreamExt};
@@ -28,8 +31,8 @@ pub mod error;
 /// Phoenixd
 #[derive(Clone)]
 pub struct Phoenixd {
-    mint_settings: MintMeltSettings,
-    melt_settings: MintMeltSettings,
+    mint_settings: MintMethodSettings,
+    melt_settings: MeltMethodSettings,
     phoenixd_api: PhoenixdApi,
     fee_reserve: FeeReserve,
     receiver: Arc<Mutex<Option<tokio::sync::mpsc::Receiver<WebhookResponse>>>>,
@@ -41,8 +44,8 @@ impl Phoenixd {
     pub fn new(
         api_password: String,
         api_url: String,
-        mint_settings: MintMeltSettings,
-        melt_settings: MintMeltSettings,
+        mint_settings: MintMethodSettings,
+        melt_settings: MeltMethodSettings,
         fee_reserve: FeeReserve,
         receiver: Arc<Mutex<Option<tokio::sync::mpsc::Receiver<WebhookResponse>>>>,
         webhook_url: String,
@@ -78,8 +81,9 @@ impl MintLightning for Phoenixd {
         Settings {
             mpp: false,
             unit: CurrencyUnit::Sat,
-            mint_settings: self.mint_settings,
-            melt_settings: self.melt_settings,
+            mint_settings: self.mint_settings.clone(),
+            melt_settings: self.melt_settings.clone(),
+            invoice_description: true,
         }
     }
 

+ 12 - 9
crates/cdk-strike/src/lib.rs

@@ -11,10 +11,12 @@ use async_trait::async_trait;
 use axum::Router;
 use cdk::amount::Amount;
 use cdk::cdk_lightning::{
-    self, CreateInvoiceResponse, MintLightning, MintMeltSettings, PayInvoiceResponse,
-    PaymentQuoteResponse, Settings,
+    self, CreateInvoiceResponse, MintLightning, PayInvoiceResponse, PaymentQuoteResponse, Settings,
+};
+use cdk::nuts::{
+    CurrencyUnit, MeltMethodSettings, MeltQuoteBolt11Request, MeltQuoteState, MintMethodSettings,
+    MintQuoteState,
 };
-use cdk::nuts::{CurrencyUnit, MeltQuoteBolt11Request, MeltQuoteState, MintQuoteState};
 use cdk::util::unix_time;
 use cdk::{mint, Bolt11Invoice};
 use error::Error;
@@ -33,8 +35,8 @@ pub mod error;
 #[derive(Clone)]
 pub struct Strike {
     strike_api: StrikeApi,
-    mint_settings: MintMeltSettings,
-    melt_settings: MintMeltSettings,
+    mint_settings: MintMethodSettings,
+    melt_settings: MeltMethodSettings,
     unit: CurrencyUnit,
     receiver: Arc<Mutex<Option<tokio::sync::mpsc::Receiver<String>>>>,
     webhook_url: String,
@@ -44,8 +46,8 @@ impl Strike {
     /// Create new [`Strike`] wallet
     pub async fn new(
         api_key: String,
-        mint_settings: MintMeltSettings,
-        melt_settings: MintMeltSettings,
+        mint_settings: MintMethodSettings,
+        melt_settings: MeltMethodSettings,
         unit: CurrencyUnit,
         receiver: Arc<Mutex<Option<tokio::sync::mpsc::Receiver<String>>>>,
         webhook_url: String,
@@ -70,8 +72,9 @@ impl MintLightning for Strike {
         Settings {
             mpp: false,
             unit: self.unit,
-            mint_settings: self.mint_settings,
-            melt_settings: self.melt_settings,
+            mint_settings: self.mint_settings.clone(),
+            melt_settings: self.melt_settings.clone(),
+            invoice_description: true,
         }
     }
 

+ 1 - 1
crates/cdk/examples/mint-token.rs

@@ -22,7 +22,7 @@ async fn main() -> Result<(), Error> {
 
     let wallet = Wallet::new(mint_url, unit, Arc::new(localstore), &seed, None).unwrap();
 
-    let quote = wallet.mint_quote(amount).await.unwrap();
+    let quote = wallet.mint_quote(amount, None).await.unwrap();
 
     println!("Quote: {:#?}", quote);
 

+ 1 - 1
crates/cdk/examples/p2pk.rs

@@ -22,7 +22,7 @@ async fn main() -> Result<(), Error> {
 
     let wallet = Wallet::new(mint_url, unit, Arc::new(localstore), &seed, None).unwrap();
 
-    let quote = wallet.mint_quote(amount).await.unwrap();
+    let quote = wallet.mint_quote(amount, None).await.unwrap();
 
     println!("Minting nuts ...");
 

+ 1 - 1
crates/cdk/examples/proof-selection.rs

@@ -24,7 +24,7 @@ async fn main() {
 
     for amount in [64] {
         let amount = Amount::from(amount);
-        let quote = wallet.mint_quote(amount).await.unwrap();
+        let quote = wallet.mint_quote(amount, None).await.unwrap();
 
         println!("Pay request: {}", quote.request);
 

+ 1 - 1
crates/cdk/examples/wallet.rs

@@ -24,7 +24,7 @@ async fn main() {
 
     let wallet = Wallet::new(mint_url, unit, Arc::new(localstore), &seed, None).unwrap();
 
-    let quote = wallet.mint_quote(amount).await.unwrap();
+    let quote = wallet.mint_quote(amount, None).await.unwrap();
 
     println!("Pay request: {}", quote.request);
 

+ 9 - 25
crates/cdk/src/cdk_lightning/mod.rs

@@ -8,7 +8,10 @@ use lightning_invoice::{Bolt11Invoice, ParseOrSemanticError};
 use serde::{Deserialize, Serialize};
 use thiserror::Error;
 
-use crate::nuts::{CurrencyUnit, MeltQuoteBolt11Request, MeltQuoteState, MintQuoteState};
+use crate::nuts::{
+    CurrencyUnit, MeltMethodSettings, MeltQuoteBolt11Request, MeltQuoteState, MintMethodSettings,
+    MintQuoteState,
+};
 use crate::{mint, Amount};
 
 /// CDK Lightning Error
@@ -121,37 +124,18 @@ pub struct PaymentQuoteResponse {
 }
 
 /// Ln backend settings
-#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
 pub struct Settings {
     /// MPP supported
     pub mpp: bool,
     /// Min amount to mint
-    pub mint_settings: MintMeltSettings,
+    pub mint_settings: MintMethodSettings,
     /// Max amount to mint
-    pub melt_settings: MintMeltSettings,
+    pub melt_settings: MeltMethodSettings,
     /// Base unit of backend
     pub unit: CurrencyUnit,
-}
-
-/// Mint or melt settings
-#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)]
-pub struct MintMeltSettings {
-    /// Min Amount
-    pub min_amount: Amount,
-    /// Max Amount
-    pub max_amount: Amount,
-    /// Enabled
-    pub enabled: bool,
-}
-
-impl Default for MintMeltSettings {
-    fn default() -> Self {
-        Self {
-            min_amount: Amount::from(1),
-            max_amount: Amount::from(500000),
-            enabled: true,
-        }
-    }
+    /// Invoice Description supported
+    pub invoice_description: bool,
 }
 
 /// Msats in sat

+ 3 - 0
crates/cdk/src/error.rs

@@ -151,6 +151,9 @@ pub enum Error {
     /// Incorrect quote amount
     #[error("Incorrect quote amount")]
     IncorrectQuoteAmount,
+    /// Invoice Description not supported
+    #[error("Invoice Description not supported")]
+    InvoiceDescriptionUnsupported,
     /// Custom Error
     #[error("`{0}`")]
     Custom(String),

+ 5 - 0
crates/cdk/src/nuts/nut04.rs

@@ -31,6 +31,8 @@ pub struct MintQuoteBolt11Request {
     pub amount: Amount,
     /// Unit wallet would like to pay with
     pub unit: CurrencyUnit,
+    /// Memo to create the invoice with
+    pub description: Option<String>,
 }
 
 /// Possible states of a quote
@@ -212,6 +214,8 @@ pub struct MintMethodSettings {
     /// Max Amount
     #[serde(skip_serializing_if = "Option::is_none")]
     pub max_amount: Option<Amount>,
+    /// Quote Description
+    pub description: bool,
 }
 
 /// Mint Settings
@@ -252,6 +256,7 @@ impl Default for Settings {
             unit: CurrencyUnit::Sat,
             min_amount: Some(Amount::from(1)),
             max_amount: Some(Amount::from(1000000)),
+            description: true,
         };
 
         Settings {

+ 6 - 4
crates/cdk/src/nuts/nut06.rs

@@ -360,8 +360,8 @@ mod tests {
     "nuts": {
         "4": {
             "methods": [
-                {"method": "bolt11", "unit": "sat"},
-                {"method": "bolt11", "unit": "usd"}
+                {"method": "bolt11", "unit": "sat", "description": true},
+                {"method": "bolt11", "unit": "usd", "description": true}
             ],
             "disabled": false
         },
@@ -425,7 +425,8 @@ mod tests {
         "method": "bolt11",
         "unit": "sat",
         "min_amount": 0,
-        "max_amount": 10000
+        "max_amount": 10000,
+        "description": true
         }
       ],
       "disabled": false
@@ -468,7 +469,8 @@ mod tests {
         "method": "bolt11",
         "unit": "sat",
         "min_amount": 0,
-        "max_amount": 10000
+        "max_amount": 10000,
+        "description": true
         }
       ],
       "disabled": false

+ 6 - 1
crates/cdk/src/wallet/client.rs

@@ -129,10 +129,15 @@ impl HttpClient {
         mint_url: Url,
         amount: Amount,
         unit: CurrencyUnit,
+        description: Option<String>,
     ) -> Result<MintQuoteBolt11Response, Error> {
         let url = join_url(mint_url, &["v1", "mint", "quote", "bolt11"])?;
 
-        let request = MintQuoteBolt11Request { amount, unit };
+        let request = MintQuoteBolt11Request {
+            amount,
+            unit,
+            description,
+        };
 
         let res = self
             .inner

+ 30 - 7
crates/cdk/src/wallet/mod.rs

@@ -20,9 +20,9 @@ use crate::mint_url::MintUrl;
 use crate::nuts::nut00::token::Token;
 use crate::nuts::{
     nut10, nut12, Conditions, CurrencyUnit, Id, KeySetInfo, Keys, Kind, MeltQuoteBolt11Response,
-    MeltQuoteState, MintInfo, MintQuoteBolt11Response, MintQuoteState, PreMintSecrets, PreSwap,
-    Proof, ProofState, Proofs, PublicKey, RestoreRequest, SecretKey, SigFlag, SpendingConditions,
-    State, SwapRequest,
+    MeltQuoteState, MintInfo, MintQuoteBolt11Response, MintQuoteState, PaymentMethod,
+    PreMintSecrets, PreSwap, Proof, ProofState, Proofs, PublicKey, RestoreRequest, SecretKey,
+    SigFlag, SpendingConditions, State, SwapRequest,
 };
 use crate::types::{Melted, ProofInfo};
 use crate::util::{hex, unix_time};
@@ -500,17 +500,40 @@ impl Wallet {
     ///     let wallet = Wallet::new(mint_url, unit, Arc::new(localstore), &seed, None)?;
     ///     let amount = Amount::from(100);
     ///
-    ///     let quote = wallet.mint_quote(amount).await?;
+    ///     let quote = wallet.mint_quote(amount, None).await?;
     ///     Ok(())
     /// }
     /// ```
     #[instrument(skip(self))]
-    pub async fn mint_quote(&self, amount: Amount) -> Result<MintQuote, Error> {
+    pub async fn mint_quote(
+        &self,
+        amount: Amount,
+        description: Option<String>,
+    ) -> Result<MintQuote, Error> {
         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, &PaymentMethod::Bolt11)
+                .ok_or(Error::UnsupportedUnit)?;
+
+            if !mint_method_settings.description {
+                return Err(Error::InvoiceDescriptionUnsupported);
+            }
+        }
+
         let quote_res = self
             .client
-            .post_mint_quote(mint_url.clone().try_into()?, amount, unit)
+            .post_mint_quote(mint_url.clone().try_into()?, amount, unit, description)
             .await?;
 
         let quote = MintQuote {
@@ -594,7 +617,7 @@ impl Wallet {
     ///     let wallet = Wallet::new(mint_url, unit, Arc::new(localstore), &seed, None).unwrap();
     ///     let amount = Amount::from(100);
     ///
-    ///     let quote = wallet.mint_quote(amount).await?;
+    ///     let quote = wallet.mint_quote(amount, None).await?;
     ///     let quote_id = quote.id;
     ///     // To be called after quote request is paid
     ///     let amount_minted = wallet.mint(&quote_id, SplitTarget::default(), None).await?;

+ 2 - 1
crates/cdk/src/wallet/multi_mint_wallet.rs

@@ -151,13 +151,14 @@ impl MultiMintWallet {
         &self,
         wallet_key: &WalletKey,
         amount: Amount,
+        description: Option<String>,
     ) -> Result<MintQuote, Error> {
         let wallet = self
             .get_wallet(wallet_key)
             .await
             .ok_or(Error::UnknownWallet(wallet_key.clone()))?;
 
-        wallet.mint_quote(amount).await
+        wallet.mint_quote(amount, description).await
     }
 
     /// Check all mint quotes