From 2f4252edbe4fbd605e4f5544809f5d172a5fe15e Mon Sep 17 00:00:00 2001 From: mubarak23 Date: Thu, 21 Nov 2024 20:44:49 +0100 Subject: [PATCH 1/7] feat: melt token with amountless --- crates/cdk-mintd/src/main.rs | 6 ++++++ crates/cdk/src/error.rs | 3 +++ crates/cdk/src/mint/builder.rs | 3 +++ crates/cdk/src/mint/melt.rs | 24 ++++++++++++++++++++++++ crates/cdk/src/nuts/nut05.rs | 8 ++++++++ crates/cdk/src/wallet/melt.rs | 1 + 6 files changed, 45 insertions(+) diff --git a/crates/cdk-mintd/src/main.rs b/crates/cdk-mintd/src/main.rs index 325ddd93..a04f6ed3 100644 --- a/crates/cdk-mintd/src/main.rs +++ b/crates/cdk-mintd/src/main.rs @@ -148,6 +148,7 @@ async fn main() -> anyhow::Result<()> { CurrencyUnit::Sat, PaymentMethod::Bolt11, mint_melt_limits, + Some(false), cln.clone(), ); } @@ -167,6 +168,7 @@ async fn main() -> anyhow::Result<()> { unit, PaymentMethod::Bolt11, mint_melt_limits, + Some(false), Arc::new(strike), ); } @@ -181,6 +183,7 @@ async fn main() -> anyhow::Result<()> { CurrencyUnit::Sat, PaymentMethod::Bolt11, mint_melt_limits, + Some(false), Arc::new(lnbits), ); } @@ -194,6 +197,7 @@ async fn main() -> anyhow::Result<()> { CurrencyUnit::Sat, PaymentMethod::Bolt11, mint_melt_limits, + Some(false), Arc::new(phd), ); } @@ -207,6 +211,7 @@ async fn main() -> anyhow::Result<()> { CurrencyUnit::Sat, PaymentMethod::Bolt11, mint_melt_limits, + Some(false), Arc::new(lnd), ); } @@ -224,6 +229,7 @@ async fn main() -> anyhow::Result<()> { unit.clone(), PaymentMethod::Bolt11, mint_melt_limits, + Some(false), fake.clone(), ); } diff --git a/crates/cdk/src/error.rs b/crates/cdk/src/error.rs index dae63c64..be914821 100644 --- a/crates/cdk/src/error.rs +++ b/crates/cdk/src/error.rs @@ -45,6 +45,9 @@ pub enum Error { /// Amount overflow #[error("Amount Overflow")] AmountOverflow, + /// Amountless Invoice Not supported + #[error("Amount Less Invoice is not allowed")] + AmountLessNotAllowed, // Mint Errors /// Minting is disabled diff --git a/crates/cdk/src/mint/builder.rs b/crates/cdk/src/mint/builder.rs index a71c259c..d598a94d 100644 --- a/crates/cdk/src/mint/builder.rs +++ b/crates/cdk/src/mint/builder.rs @@ -108,12 +108,14 @@ impl MintBuilder { unit: CurrencyUnit, method: PaymentMethod, limits: MintMeltLimits, + support_amount_less: Option, ln_backend: Arc + Send + Sync>, ) -> Self { let ln_key = LnKey { unit: unit.clone(), method, }; + let support_amount_less = support_amount_less.unwrap_or(false); let mut ln = self.ln.unwrap_or_default(); @@ -150,6 +152,7 @@ impl MintBuilder { unit, min_amount: Some(limits.melt_min), max_amount: Some(limits.melt_max), + amount_less: support_amount_less, }; self.mint_info.nuts.nut05.methods.push(melt_method_settings); self.mint_info.nuts.nut05.disabled = false; diff --git a/crates/cdk/src/mint/melt.rs b/crates/cdk/src/mint/melt.rs index 8ac01d69..8571bf0c 100644 --- a/crates/cdk/src/mint/melt.rs +++ b/crates/cdk/src/mint/melt.rs @@ -48,6 +48,27 @@ impl Mint { } } + fn check_amount_less_invoice( + &self, + unit: CurrencyUnit, + method: PaymentMethod, + ) -> Result<(), Error> { + let nut05 = &self.mint_info.nuts.nut05; + + if nut05.disabled { + return Err(Error::MeltingDisabled); + } + let settings = nut05 + .get_settings(&unit, &method) + .ok_or(Error::UnitUnsupported)?; + let amount_less = settings.amount_less; + + if amount_less == true { + return Ok(()); + } + return Err(Error::AmountLessNotAllowed); + } + /// Get melt bolt11 quote #[instrument(skip_all)] pub async fn get_melt_bolt11_quote( @@ -58,6 +79,7 @@ impl Mint { request, unit, options: _, + amount, } = melt_request; let amount = match melt_request.options { @@ -74,6 +96,7 @@ impl Mint { self.check_melt_request_acceptable(amount, unit.clone(), PaymentMethod::Bolt11)?; + self.check_amount_less_invoice(unit.clone(), PaymentMethod::Bolt11)?; let ln = self .ln .get(&LnKey::new(unit.clone(), PaymentMethod::Bolt11)) @@ -93,6 +116,7 @@ impl Mint { Error::UnitUnsupported })?; + // check amountless (amount in meltbolt11reqiest) is equal to payment_quote.amount let quote = MeltQuote::new( request.to_string(), unit.clone(), diff --git a/crates/cdk/src/nuts/nut05.rs b/crates/cdk/src/nuts/nut05.rs index df9064ef..c880afbb 100644 --- a/crates/cdk/src/nuts/nut05.rs +++ b/crates/cdk/src/nuts/nut05.rs @@ -36,6 +36,8 @@ pub struct MeltQuoteBolt11Request { pub request: Bolt11Invoice, /// Unit wallet would like to pay with pub unit: CurrencyUnit, + /// amount for paying amountless bolt11 invoice + pub amount: Option, /// Payment Options pub options: Option, } @@ -264,6 +266,8 @@ pub struct MeltMethodSettings { /// Max Amount #[serde(skip_serializing_if = "Option::is_none")] pub max_amount: Option, + /// Amountless + pub amount_less: bool, } impl Settings { @@ -288,6 +292,9 @@ impl Settings { } } +/// meting with an amount_less invoice +// pub amount_less: Option, + /// Melt Settings #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] #[cfg_attr(feature = "swagger", derive(utoipa::ToSchema), schema(as = nut05::Settings))] @@ -305,6 +312,7 @@ impl Default for Settings { unit: CurrencyUnit::Sat, min_amount: Some(Amount::from(1)), max_amount: Some(Amount::from(1000000)), + amount_less: false, }; Settings { diff --git a/crates/cdk/src/wallet/melt.rs b/crates/cdk/src/wallet/melt.rs index e8a0a0b5..36fe6e11 100644 --- a/crates/cdk/src/wallet/melt.rs +++ b/crates/cdk/src/wallet/melt.rs @@ -63,6 +63,7 @@ impl Wallet { request: Bolt11Invoice::from_str(&request)?, unit: self.unit.clone(), options, + amount: Some(amount), }; let quote_res = self From f672c055c0fe78a729b88e25c98fc927fd7aa1e2 Mon Sep 17 00:00:00 2001 From: mubarak23 Date: Thu, 21 Nov 2024 21:49:02 +0100 Subject: [PATCH 2/7] check the amount in the request match the optional amount in Melt BOLT11 Request --- crates/cdk/src/mint/melt.rs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/crates/cdk/src/mint/melt.rs b/crates/cdk/src/mint/melt.rs index 8571bf0c..74cf1c97 100644 --- a/crates/cdk/src/mint/melt.rs +++ b/crates/cdk/src/mint/melt.rs @@ -50,6 +50,8 @@ impl Mint { fn check_amount_less_invoice( &self, + amount: Amount, + request_amount: Amount, unit: CurrencyUnit, method: PaymentMethod, ) -> Result<(), Error> { @@ -61,12 +63,11 @@ impl Mint { let settings = nut05 .get_settings(&unit, &method) .ok_or(Error::UnitUnsupported)?; - let amount_less = settings.amount_less; - if amount_less == true { - return Ok(()); + if settings.amount_less && amount != request_amount { + return Err(Error::AmountLessNotAllowed); } - return Err(Error::AmountLessNotAllowed); + Ok(()) } /// Get melt bolt11 quote @@ -82,6 +83,9 @@ impl Mint { amount, } = melt_request; + let amount_less_amount = amount.unwrap_or_default(); + // let amount_less_amount = amount.unwrap_or_else(|| Amount::new(0)); + let amount = match melt_request.options { Some(mpp_amount) => mpp_amount.amount, None => { @@ -96,7 +100,6 @@ impl Mint { self.check_melt_request_acceptable(amount, unit.clone(), PaymentMethod::Bolt11)?; - self.check_amount_less_invoice(unit.clone(), PaymentMethod::Bolt11)?; let ln = self .ln .get(&LnKey::new(unit.clone(), PaymentMethod::Bolt11)) @@ -117,6 +120,13 @@ impl Mint { })?; // check amountless (amount in meltbolt11reqiest) is equal to payment_quote.amount + self.check_amount_less_invoice( + amount_less_amount, + payment_quote.amount.clone(), + unit.clone(), + PaymentMethod::Bolt11, + )?; + let quote = MeltQuote::new( request.to_string(), unit.clone(), From c57ef581d7c93da577ca4181e48e20f979efed9f Mon Sep 17 00:00:00 2001 From: mubarak23 Date: Thu, 21 Nov 2024 21:54:33 +0100 Subject: [PATCH 3/7] remove clone on payment_qoute amount --- crates/cdk/src/mint/melt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cdk/src/mint/melt.rs b/crates/cdk/src/mint/melt.rs index 74cf1c97..c7e3eff5 100644 --- a/crates/cdk/src/mint/melt.rs +++ b/crates/cdk/src/mint/melt.rs @@ -122,7 +122,7 @@ impl Mint { // check amountless (amount in meltbolt11reqiest) is equal to payment_quote.amount self.check_amount_less_invoice( amount_less_amount, - payment_quote.amount.clone(), + payment_quote.amount, unit.clone(), PaymentMethod::Bolt11, )?; From 6467fe277d1fc6f48e15db32bb0cc73f0532717c Mon Sep 17 00:00:00 2001 From: mubarak23 Date: Sun, 24 Nov 2024 18:00:47 +0100 Subject: [PATCH 4/7] chore:fix review changes --- crates/cdk/src/mint/builder.rs | 6 +++--- crates/cdk/src/mint/melt.rs | 8 ++++++-- crates/cdk/src/nuts/nut05.rs | 4 ++-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/crates/cdk/src/mint/builder.rs b/crates/cdk/src/mint/builder.rs index d598a94d..7fd3ccc8 100644 --- a/crates/cdk/src/mint/builder.rs +++ b/crates/cdk/src/mint/builder.rs @@ -108,14 +108,14 @@ impl MintBuilder { unit: CurrencyUnit, method: PaymentMethod, limits: MintMeltLimits, - support_amount_less: Option, + support_amountless: Option, ln_backend: Arc + Send + Sync>, ) -> Self { let ln_key = LnKey { unit: unit.clone(), method, }; - let support_amount_less = support_amount_less.unwrap_or(false); + let support_amountless = support_amountless.unwrap_or(false); let mut ln = self.ln.unwrap_or_default(); @@ -152,7 +152,7 @@ impl MintBuilder { unit, min_amount: Some(limits.melt_min), max_amount: Some(limits.melt_max), - amount_less: support_amount_less, + amountless: Some(support_amountless), }; self.mint_info.nuts.nut05.methods.push(melt_method_settings); self.mint_info.nuts.nut05.disabled = false; diff --git a/crates/cdk/src/mint/melt.rs b/crates/cdk/src/mint/melt.rs index c7e3eff5..41feec55 100644 --- a/crates/cdk/src/mint/melt.rs +++ b/crates/cdk/src/mint/melt.rs @@ -64,7 +64,11 @@ impl Mint { .get_settings(&unit, &method) .ok_or(Error::UnitUnsupported)?; - if settings.amount_less && amount != request_amount { + if settings + .amountless + .expect("expect a value for amountless invoice") + && amount != request_amount + { return Err(Error::AmountLessNotAllowed); } Ok(()) @@ -119,7 +123,7 @@ impl Mint { Error::UnitUnsupported })?; - // check amountless (amount in meltbolt11reqiest) is equal to payment_quote.amount + // check amountless (amount in meltbolt11request) is equal to payment_quote.amount self.check_amount_less_invoice( amount_less_amount, payment_quote.amount, diff --git a/crates/cdk/src/nuts/nut05.rs b/crates/cdk/src/nuts/nut05.rs index c880afbb..df9fe4bd 100644 --- a/crates/cdk/src/nuts/nut05.rs +++ b/crates/cdk/src/nuts/nut05.rs @@ -267,7 +267,7 @@ pub struct MeltMethodSettings { #[serde(skip_serializing_if = "Option::is_none")] pub max_amount: Option, /// Amountless - pub amount_less: bool, + pub amountless: Option, } impl Settings { @@ -312,7 +312,7 @@ impl Default for Settings { unit: CurrencyUnit::Sat, min_amount: Some(Amount::from(1)), max_amount: Some(Amount::from(1000000)), - amount_less: false, + amountless: Some(false), }; Settings { From 4025996cd572f5c77b374d67b7b71c00127e97c1 Mon Sep 17 00:00:00 2001 From: mubarak23 Date: Sun, 24 Nov 2024 18:24:13 +0100 Subject: [PATCH 5/7] chore:Some LN by default accept amountless invoice --- crates/cdk-mintd/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cdk-mintd/src/main.rs b/crates/cdk-mintd/src/main.rs index a04f6ed3..1cbceffb 100644 --- a/crates/cdk-mintd/src/main.rs +++ b/crates/cdk-mintd/src/main.rs @@ -229,7 +229,7 @@ async fn main() -> anyhow::Result<()> { unit.clone(), PaymentMethod::Bolt11, mint_melt_limits, - Some(false), + Some(true), fake.clone(), ); } From 2ea655fd99006fd2ef356f3579d75dc9f15a0b68 Mon Sep 17 00:00:00 2001 From: mubarak23 Date: Mon, 25 Nov 2024 11:21:52 +0100 Subject: [PATCH 6/7] chore:turn amountless on LN backend --- crates/cdk-mintd/src/main.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/cdk-mintd/src/main.rs b/crates/cdk-mintd/src/main.rs index 1cbceffb..a55f8174 100644 --- a/crates/cdk-mintd/src/main.rs +++ b/crates/cdk-mintd/src/main.rs @@ -148,7 +148,7 @@ async fn main() -> anyhow::Result<()> { CurrencyUnit::Sat, PaymentMethod::Bolt11, mint_melt_limits, - Some(false), + Some(true), cln.clone(), ); } @@ -168,7 +168,7 @@ async fn main() -> anyhow::Result<()> { unit, PaymentMethod::Bolt11, mint_melt_limits, - Some(false), + Some(true), Arc::new(strike), ); } @@ -183,7 +183,7 @@ async fn main() -> anyhow::Result<()> { CurrencyUnit::Sat, PaymentMethod::Bolt11, mint_melt_limits, - Some(false), + Some(true), Arc::new(lnbits), ); } @@ -197,7 +197,7 @@ async fn main() -> anyhow::Result<()> { CurrencyUnit::Sat, PaymentMethod::Bolt11, mint_melt_limits, - Some(false), + Some(true), Arc::new(phd), ); } @@ -211,7 +211,7 @@ async fn main() -> anyhow::Result<()> { CurrencyUnit::Sat, PaymentMethod::Bolt11, mint_melt_limits, - Some(false), + Some(true), Arc::new(lnd), ); } From e3ea35d79ece1df7f1266d0df2c3989c303575c3 Mon Sep 17 00:00:00 2001 From: mubarak23 Date: Fri, 29 Nov 2024 08:03:57 +0100 Subject: [PATCH 7/7] chore: LN backend support amountless invoice --- crates/cdk-cln/src/lib.rs | 10 +++++++- crates/cdk-fake-wallet/src/lib.rs | 9 ++++++- crates/cdk-lnbits/src/lib.rs | 9 ++++++- crates/cdk-lnd/src/lib.rs | 9 ++++++- crates/cdk-phoenixd/src/lib.rs | 9 ++++++- crates/cdk-strike/src/lib.rs | 8 +++++- crates/cdk/src/mint/melt.rs | 41 +++---------------------------- 7 files changed, 52 insertions(+), 43 deletions(-) diff --git a/crates/cdk-cln/src/lib.rs b/crates/cdk-cln/src/lib.rs index b9ed45ee..64c5f27d 100644 --- a/crates/cdk-cln/src/lib.rs +++ b/crates/cdk-cln/src/lib.rs @@ -201,12 +201,20 @@ impl MintLightning for Cln { .amount_milli_satoshis() .ok_or(Error::UnknownInvoiceAmount)?; - let amount = to_unit( + let mut amount = to_unit( invoice_amount_msat, &CurrencyUnit::Msat, &melt_quote_request.unit, )?; + if melt_quote_request.amount { + amount = to_unit( + melt_quote_request.amount, + &CurrencyUnit::Msat, + &melt_quote_request.unit, + )?; + + } let relative_fee_reserve = (self.fee_reserve.percent_fee_reserve * u64::from(amount) as f32) as u64; diff --git a/crates/cdk-fake-wallet/src/lib.rs b/crates/cdk-fake-wallet/src/lib.rs index 9e287837..73fa9347 100644 --- a/crates/cdk-fake-wallet/src/lib.rs +++ b/crates/cdk-fake-wallet/src/lib.rs @@ -132,12 +132,19 @@ impl MintLightning for FakeWallet { .amount_milli_satoshis() .ok_or(Error::UnknownInvoiceAmount)?; - let amount = to_unit( + let mut amount = to_unit( invoice_amount_msat, &CurrencyUnit::Msat, &melt_quote_request.unit, )?; + if melt_quote_request.amount { + amount = to_unit( + melt_quote_request.amount, + &CurrencyUnit::Msat, + &melt_quote_request.unit, + )?; + let relative_fee_reserve = (self.fee_reserve.percent_fee_reserve * u64::from(amount) as f32) as u64; diff --git a/crates/cdk-lnbits/src/lib.rs b/crates/cdk-lnbits/src/lib.rs index f983847b..8296eb1f 100644 --- a/crates/cdk-lnbits/src/lib.rs +++ b/crates/cdk-lnbits/src/lib.rs @@ -157,12 +157,19 @@ impl MintLightning for LNbits { .amount_milli_satoshis() .ok_or(Error::UnknownInvoiceAmount)?; - let amount = to_unit( + let mut amount = to_unit( invoice_amount_msat, &CurrencyUnit::Msat, &melt_quote_request.unit, )?; + if melt_quote_request.amount { + amount = to_unit( + melt_quote_request.amount, + &CurrencyUnit::Msat, + &melt_quote_request.unit, + )?; + let relative_fee_reserve = (self.fee_reserve.percent_fee_reserve * u64::from(amount) as f32) as u64; diff --git a/crates/cdk-lnd/src/lib.rs b/crates/cdk-lnd/src/lib.rs index 96ce2f4e..17add7db 100644 --- a/crates/cdk-lnd/src/lib.rs +++ b/crates/cdk-lnd/src/lib.rs @@ -169,12 +169,19 @@ impl MintLightning for Lnd { .amount_milli_satoshis() .ok_or(Error::UnknownInvoiceAmount)?; - let amount = to_unit( + let mut amount = to_unit( invoice_amount_msat, &CurrencyUnit::Msat, &melt_quote_request.unit, )?; + if melt_quote_request.amount { + amount = to_unit( + melt_quote_request.amount, + &CurrencyUnit::Msat, + &melt_quote_request.unit, + )?; + let relative_fee_reserve = (self.fee_reserve.percent_fee_reserve * u64::from(amount) as f32) as u64; diff --git a/crates/cdk-phoenixd/src/lib.rs b/crates/cdk-phoenixd/src/lib.rs index 48d0912e..ab754d62 100644 --- a/crates/cdk-phoenixd/src/lib.rs +++ b/crates/cdk-phoenixd/src/lib.rs @@ -166,12 +166,19 @@ impl MintLightning for Phoenixd { .amount_milli_satoshis() .ok_or(Error::UnknownInvoiceAmount)?; - let amount = to_unit( + let mut amount = to_unit( invoice_amount_msat, &CurrencyUnit::Msat, &melt_quote_request.unit, )?; + if melt_quote_request.amount { + amount = to_unit( + melt_quote_request.amount, + &CurrencyUnit::Msat, + &melt_quote_request.unit, + )?; + let relative_fee_reserve = (self.fee_reserve.percent_fee_reserve * u64::from(amount) as f32) as u64; diff --git a/crates/cdk-strike/src/lib.rs b/crates/cdk-strike/src/lib.rs index ddb103cb..b10afcff 100644 --- a/crates/cdk-strike/src/lib.rs +++ b/crates/cdk-strike/src/lib.rs @@ -167,9 +167,15 @@ impl MintLightning for Strike { let fee = from_strike_amount(quote.lightning_network_fee, &melt_quote_request.unit)?; + let mut amount = from_strike_amount(quote.amount, &melt_quote_request.unit)?.into()?; + + if melt_quote_request.amount { + amount = from_strike_amount(melt_quote_request.amount, &melt_quote_request.unit)?.into() + } + Ok(PaymentQuoteResponse { request_lookup_id: quote.payment_quote_id, - amount: from_strike_amount(quote.amount, &melt_quote_request.unit)?.into(), + amount, fee: fee.into(), state: MeltQuoteState::Unpaid, }) diff --git a/crates/cdk/src/mint/melt.rs b/crates/cdk/src/mint/melt.rs index 41feec55..21dc1f80 100644 --- a/crates/cdk/src/mint/melt.rs +++ b/crates/cdk/src/mint/melt.rs @@ -36,6 +36,9 @@ impl Mint { .get_settings(&unit, &method) .ok_or(Error::UnitUnsupported)?; + if !settings.amountless.unwrap_or_default() { + return Err(Error::AmountLessNotAllowed); + } let is_above_max = matches!(settings.max_amount, Some(max) if amount > max); let is_below_min = matches!(settings.min_amount, Some(min) if amount < min); match is_above_max || is_below_min { @@ -48,32 +51,6 @@ impl Mint { } } - fn check_amount_less_invoice( - &self, - amount: Amount, - request_amount: Amount, - unit: CurrencyUnit, - method: PaymentMethod, - ) -> Result<(), Error> { - let nut05 = &self.mint_info.nuts.nut05; - - if nut05.disabled { - return Err(Error::MeltingDisabled); - } - let settings = nut05 - .get_settings(&unit, &method) - .ok_or(Error::UnitUnsupported)?; - - if settings - .amountless - .expect("expect a value for amountless invoice") - && amount != request_amount - { - return Err(Error::AmountLessNotAllowed); - } - Ok(()) - } - /// Get melt bolt11 quote #[instrument(skip_all)] pub async fn get_melt_bolt11_quote( @@ -84,12 +61,9 @@ impl Mint { request, unit, options: _, - amount, + .. } = melt_request; - let amount_less_amount = amount.unwrap_or_default(); - // let amount_less_amount = amount.unwrap_or_else(|| Amount::new(0)); - let amount = match melt_request.options { Some(mpp_amount) => mpp_amount.amount, None => { @@ -123,13 +97,6 @@ impl Mint { Error::UnitUnsupported })?; - // check amountless (amount in meltbolt11request) is equal to payment_quote.amount - self.check_amount_less_invoice( - amount_less_amount, - payment_quote.amount, - unit.clone(), - PaymentMethod::Bolt11, - )?; let quote = MeltQuote::new( request.to_string(),