瀏覽代碼

fix: non sat amounts on melt (#839)

thesimplekid 1 月之前
父節點
當前提交
738202b957

+ 1 - 0
crates/cdk-cln/src/lib.rs

@@ -201,6 +201,7 @@ impl MintPayment for Cln {
         Ok(PaymentQuoteResponse {
             request_lookup_id: bolt11.payment_hash().to_string(),
             amount,
+            unit: unit.clone(),
             fee: fee.into(),
             state: MeltQuoteState::Unpaid,
         })

+ 2 - 0
crates/cdk-common/src/payment.rs

@@ -155,6 +155,8 @@ pub struct PaymentQuoteResponse {
     pub amount: Amount,
     /// Fee required for melt
     pub fee: Amount,
+    /// Currency unit of `amount` and `fee`
+    pub unit: CurrencyUnit,
     /// Status
     pub state: MeltQuoteState,
 }

+ 1 - 0
crates/cdk-fake-wallet/Cargo.toml

@@ -23,3 +23,4 @@ serde.workspace = true
 serde_json.workspace = true
 lightning-invoice.workspace = true
 tokio-stream.workspace = true
+reqwest.workspace = true

+ 23 - 1
crates/cdk-fake-wallet/src/lib.rs

@@ -29,6 +29,7 @@ use error::Error;
 use futures::stream::StreamExt;
 use futures::Stream;
 use lightning_invoice::{Bolt11Invoice, Currency, InvoiceBuilder, PaymentSecret};
+use reqwest::Client;
 use serde::{Deserialize, Serialize};
 use serde_json::Value;
 use tokio::sync::Mutex;
@@ -150,7 +151,27 @@ impl MintPayment for FakeWallet {
                 .into(),
         };
 
-        let amount = to_unit(amount_msat, &CurrencyUnit::Msat, unit)?;
+        let amount = if unit != &CurrencyUnit::Sat && unit != &CurrencyUnit::Msat {
+            let client = Client::new();
+
+            let response: Value = client
+                .get("https://mempool.space/api/v1/prices")
+                .send()
+                .await
+                .map_err(|_| Error::UnknownInvoice)?
+                .json()
+                .await
+                .unwrap();
+
+            let price = response.get(unit.to_string().to_uppercase()).unwrap();
+
+            let bitcoin_amount = u64::from(amount_msat) as f64 / 100_000_000_000.0;
+            let total_price = price.as_f64().unwrap() * bitcoin_amount;
+
+            Amount::from((total_price * 100.0).ceil() as u64)
+        } else {
+            to_unit(amount_msat, &CurrencyUnit::Msat, unit)?
+        };
 
         let relative_fee_reserve =
             (self.fee_reserve.percent_fee_reserve * u64::from(amount) as f32) as u64;
@@ -163,6 +184,7 @@ impl MintPayment for FakeWallet {
             request_lookup_id: bolt11.payment_hash().to_string(),
             amount,
             fee: fee.into(),
+            unit: unit.clone(),
             state: MeltQuoteState::Unpaid,
         })
     }

+ 1 - 0
crates/cdk-lnbits/src/lib.rs

@@ -183,6 +183,7 @@ impl MintPayment for LNbits {
         Ok(PaymentQuoteResponse {
             request_lookup_id: bolt11.payment_hash().to_string(),
             amount,
+            unit: unit.clone(),
             fee: fee.into(),
             state: MeltQuoteState::Unpaid,
         })

+ 1 - 0
crates/cdk-lnd/src/lib.rs

@@ -231,6 +231,7 @@ impl MintPayment for Lnd {
         Ok(PaymentQuoteResponse {
             request_lookup_id: bolt11.payment_hash().to_string(),
             amount,
+            unit: unit.clone(),
             fee: fee.into(),
             state: MeltQuoteState::Unpaid,
         })

+ 2 - 0
crates/cdk-payment-processor/src/proto/mod.rs

@@ -79,6 +79,7 @@ impl From<cdk_common::payment::PaymentQuoteResponse> for PaymentQuoteResponse {
             amount: value.amount.into(),
             fee: value.fee.into(),
             state: QuoteState::from(value.state).into(),
+            unit: value.unit.to_string(),
         }
     }
 }
@@ -121,6 +122,7 @@ impl From<PaymentQuoteResponse> for cdk_common::payment::PaymentQuoteResponse {
         Self {
             request_lookup_id: value.request_lookup_id.clone(),
             amount: value.amount.into(),
+            unit: CurrencyUnit::from_str(&value.unit).unwrap_or_default(),
             fee: value.fee.into(),
             state: value.state().into(),
         }

+ 1 - 0
crates/cdk-payment-processor/src/proto/payment_processor.proto

@@ -68,6 +68,7 @@ message PaymentQuoteResponse {
   uint64 amount = 2;
   uint64 fee = 3;
   QuoteState state = 4;
+  string unit = 5;
 }
 
 message MeltQuote {

+ 10 - 14
crates/cdk/src/mint/melt.rs

@@ -108,19 +108,6 @@ impl Mint {
             ..
         } = melt_request;
 
-        let amount_msats = melt_request.amount_msat()?;
-
-        let amount_quote_unit = to_unit(amount_msats, &CurrencyUnit::Msat, unit)?;
-
-        self.check_melt_request_acceptable(
-            amount_quote_unit,
-            unit.clone(),
-            PaymentMethod::Bolt11,
-            request.to_string(),
-            *options,
-        )
-        .await?;
-
         let ln = self
             .ln
             .get(&PaymentProcessorKey::new(
@@ -150,6 +137,15 @@ impl Mint {
                 Error::UnsupportedUnit
             })?;
 
+        self.check_melt_request_acceptable(
+            payment_quote.amount,
+            unit.clone(),
+            PaymentMethod::Bolt11,
+            request.to_string(),
+            *options,
+        )
+        .await?;
+
         // We only want to set the msats_to_pay of the melt quote if the invoice is amountless
         // or we want to ignore the amount and do an mpp payment
         let msats_to_pay = options.map(|opt| opt.amount_msat());
@@ -169,7 +165,7 @@ impl Mint {
         tracing::debug!(
             "New melt quote {} for {} {} with request id {}",
             quote.id,
-            amount_quote_unit,
+            payment_quote.amount,
             unit,
             payment_quote.request_lookup_id
         );

+ 18 - 16
crates/cdk/src/wallet/melt.rs

@@ -50,33 +50,35 @@ impl Wallet {
     ) -> Result<MeltQuote, Error> {
         let invoice = Bolt11Invoice::from_str(&request)?;
 
-        let amount_msat = options
-            .map(|opt| opt.amount_msat().into())
-            .or_else(|| invoice.amount_milli_satoshis())
-            .ok_or(Error::InvoiceAmountUndefined)?;
-
-        let amount_quote_unit = to_unit(amount_msat, &CurrencyUnit::Msat, &self.unit).unwrap();
-
         let quote_request = MeltQuoteBolt11Request {
             request: Bolt11Invoice::from_str(&request)?,
             unit: self.unit.clone(),
             options,
         };
 
-        let quote_res = self.client.post_melt_quote(quote_request).await.unwrap();
+        let quote_res = self.client.post_melt_quote(quote_request).await?;
+
+        if self.unit == CurrencyUnit::Msat || self.unit == CurrencyUnit::Sat {
+            let amount_msat = options
+                .map(|opt| opt.amount_msat().into())
+                .or_else(|| invoice.amount_milli_satoshis())
+                .ok_or(Error::InvoiceAmountUndefined)?;
 
-        if quote_res.amount != amount_quote_unit {
-            tracing::warn!(
-                "Mint returned incorrect quote amount. Expected {}, got {}",
-                amount_quote_unit,
-                quote_res.amount
-            );
-            return Err(Error::IncorrectQuoteAmount);
+            let amount_quote_unit = to_unit(amount_msat, &CurrencyUnit::Msat, &self.unit)?;
+
+            if quote_res.amount != amount_quote_unit {
+                tracing::warn!(
+                    "Mint returned incorrect quote amount. Expected {}, got {}",
+                    amount_quote_unit,
+                    quote_res.amount
+                );
+                return Err(Error::IncorrectQuoteAmount);
+            }
         }
 
         let quote = MeltQuote {
             id: quote_res.quote,
-            amount: amount_quote_unit,
+            amount: quote_res.amount,
             request,
             unit: self.unit.clone(),
             fee_reserve: quote_res.fee_reserve,