浏览代码

fix: cdk melt quote track payment method (#1021)

Add payment_method field to MeltQuote struct to track whether quotes use BOLT11 or BOLT12 payment methods. Include database migrations for both SQLite and PostgreSQL to support the new field. Update melt operations to set and use the payment method for proper routing between BOLT11 and BOLT12 endpoints.
thesimplekid 2 月之前
父节点
当前提交
6067242793

+ 5 - 0
CHANGELOG.md

@@ -8,6 +8,8 @@
 
 
 ### Added
 ### Added
 - cdk-common: New `Event` enum for payment event handling with `PaymentReceived` variant ([thesimplekid]).
 - cdk-common: New `Event` enum for payment event handling with `PaymentReceived` variant ([thesimplekid]).
+- cdk-common: Added `payment_method` field to `MeltQuote` struct for tracking payment method type ([thesimplekid]).
+- cdk-sql-common: Database migration to add `payment_method` column to melt_quote table for SQLite and PostgreSQL ([thesimplekid]).
 
 
 ### Changed
 ### Changed
 - cdk-common: Refactored `MintPayment` trait method `wait_any_incoming_payment` to `wait_payment_event` with event-driven architecture ([thesimplekid]).
 - cdk-common: Refactored `MintPayment` trait method `wait_any_incoming_payment` to `wait_payment_event` with event-driven architecture ([thesimplekid]).
@@ -16,6 +18,9 @@
 - cashu: Updated BOLT12 payment method specification from NUT-24 to NUT-25 ([thesimplekid]).
 - cashu: Updated BOLT12 payment method specification from NUT-24 to NUT-25 ([thesimplekid]).
 - cdk: Updated BOLT12 import references from nut24 to nut25 module ([thesimplekid]).
 - cdk: Updated BOLT12 import references from nut24 to nut25 module ([thesimplekid]).
 
 
+### Fixied
+- cdk: Wallet melt track and use payment method from quote for BOLT11/BOLT12 routing ([thesimplekid]).
+
 ## [0.12.0](https://github.com/cashubtc/cdk/releases/tag/v0.12.0)
 ## [0.12.0](https://github.com/cashubtc/cdk/releases/tag/v0.12.0)
 
 
 ### Summary
 ### Summary

+ 3 - 0
crates/cdk-common/src/wallet.rs

@@ -84,6 +84,9 @@ pub struct MeltQuote {
     pub expiry: u64,
     pub expiry: u64,
     /// Payment preimage
     /// Payment preimage
     pub payment_preimage: Option<String>,
     pub payment_preimage: Option<String>,
+    /// Payment method
+    #[serde(default)]
+    pub payment_method: PaymentMethod,
 }
 }
 
 
 impl MintQuote {
 impl MintQuote {

+ 2 - 0
crates/cdk-sql-common/src/wallet/migrations.rs

@@ -2,6 +2,7 @@
 /// Auto-generated by build.rs
 /// Auto-generated by build.rs
 pub static MIGRATIONS: &[(&str, &str, &str)] = &[
 pub static MIGRATIONS: &[(&str, &str, &str)] = &[
     ("postgres", "1_initial.sql", include_str!(r#"./migrations/postgres/1_initial.sql"#)),
     ("postgres", "1_initial.sql", include_str!(r#"./migrations/postgres/1_initial.sql"#)),
+    ("postgres", "20250831215438_melt_quote_method.sql", include_str!(r#"./migrations/postgres/20250831215438_melt_quote_method.sql"#)),
     ("sqlite", "1_fix_sqlx_migration.sql", include_str!(r#"./migrations/sqlite/1_fix_sqlx_migration.sql"#)),
     ("sqlite", "1_fix_sqlx_migration.sql", include_str!(r#"./migrations/sqlite/1_fix_sqlx_migration.sql"#)),
     ("sqlite", "20240612132920_init.sql", include_str!(r#"./migrations/sqlite/20240612132920_init.sql"#)),
     ("sqlite", "20240612132920_init.sql", include_str!(r#"./migrations/sqlite/20240612132920_init.sql"#)),
     ("sqlite", "20240618200350_quote_state.sql", include_str!(r#"./migrations/sqlite/20240618200350_quote_state.sql"#)),
     ("sqlite", "20240618200350_quote_state.sql", include_str!(r#"./migrations/sqlite/20240618200350_quote_state.sql"#)),
@@ -22,4 +23,5 @@ pub static MIGRATIONS: &[(&str, &str, &str)] = &[
     ("sqlite", "20250707093445_bolt12.sql", include_str!(r#"./migrations/sqlite/20250707093445_bolt12.sql"#)),
     ("sqlite", "20250707093445_bolt12.sql", include_str!(r#"./migrations/sqlite/20250707093445_bolt12.sql"#)),
     ("sqlite", "20250729111701_keyset_v2_u32.sql", include_str!(r#"./migrations/sqlite/20250729111701_keyset_v2_u32.sql"#)),
     ("sqlite", "20250729111701_keyset_v2_u32.sql", include_str!(r#"./migrations/sqlite/20250729111701_keyset_v2_u32.sql"#)),
     ("sqlite", "20250812084621_keyset_plus_one.sql", include_str!(r#"./migrations/sqlite/20250812084621_keyset_plus_one.sql"#)),
     ("sqlite", "20250812084621_keyset_plus_one.sql", include_str!(r#"./migrations/sqlite/20250812084621_keyset_plus_one.sql"#)),
+    ("sqlite", "20250831215438_melt_quote_method.sql", include_str!(r#"./migrations/sqlite/20250831215438_melt_quote_method.sql"#)),
 ];
 ];

+ 1 - 0
crates/cdk-sql-common/src/wallet/migrations/postgres/20250831215438_melt_quote_method.sql

@@ -0,0 +1 @@
+ALTER TABLE melt_quote ADD COLUMN payment_method TEXT NOT NULL DEFAULT 'bolt11';

+ 1 - 0
crates/cdk-sql-common/src/wallet/migrations/sqlite/20250831215438_melt_quote_method.sql

@@ -0,0 +1 @@
+ALTER TABLE melt_quote ADD COLUMN payment_method TEXT NOT NULL DEFAULT 'bolt11';

+ 15 - 6
crates/cdk-sql-common/src/wallet/mod.rs

@@ -156,7 +156,8 @@ where
                   fee_reserve,
                   fee_reserve,
                   state,
                   state,
                   expiry,
                   expiry,
-                  payment_preimage
+                  payment_preimage,
+                  payment_method
               FROM
               FROM
                   melt_quote
                   melt_quote
               "#,
               "#,
@@ -579,16 +580,17 @@ ON CONFLICT(id) DO UPDATE SET
         query(
         query(
             r#"
             r#"
 INSERT INTO melt_quote
 INSERT INTO melt_quote
-(id, unit, amount, request, fee_reserve, state, expiry)
+(id, unit, amount, request, fee_reserve, state, expiry, payment_method)
 VALUES
 VALUES
-(:id, :unit, :amount, :request, :fee_reserve, :state, :expiry)
+(:id, :unit, :amount, :request, :fee_reserve, :state, :expiry, :payment_method)
 ON CONFLICT(id) DO UPDATE SET
 ON CONFLICT(id) DO UPDATE SET
     unit = excluded.unit,
     unit = excluded.unit,
     amount = excluded.amount,
     amount = excluded.amount,
     request = excluded.request,
     request = excluded.request,
     fee_reserve = excluded.fee_reserve,
     fee_reserve = excluded.fee_reserve,
     state = excluded.state,
     state = excluded.state,
-    expiry = excluded.expiry
+    expiry = excluded.expiry,
+    payment_method = excluded.payment_method
 ;
 ;
         "#,
         "#,
         )?
         )?
@@ -599,6 +601,7 @@ ON CONFLICT(id) DO UPDATE SET
         .bind("fee_reserve", u64::from(quote.fee_reserve) as i64)
         .bind("fee_reserve", u64::from(quote.fee_reserve) as i64)
         .bind("state", quote.state.to_string())
         .bind("state", quote.state.to_string())
         .bind("expiry", quote.expiry as i64)
         .bind("expiry", quote.expiry as i64)
+        .bind("payment_method", quote.payment_method.to_string())
         .execute(&*conn)
         .execute(&*conn)
         .await?;
         .await?;
 
 
@@ -618,7 +621,8 @@ ON CONFLICT(id) DO UPDATE SET
                 fee_reserve,
                 fee_reserve,
                 state,
                 state,
                 expiry,
                 expiry,
-                payment_preimage
+                payment_preimage,
+                payment_method
             FROM
             FROM
                 melt_quote
                 melt_quote
             WHERE
             WHERE
@@ -1124,13 +1128,17 @@ fn sql_row_to_melt_quote(row: Vec<Column>) -> Result<wallet::MeltQuote, Error> {
             fee_reserve,
             fee_reserve,
             state,
             state,
             expiry,
             expiry,
-            payment_preimage
+            payment_preimage,
+            row_method
         ) = row
         ) = row
     );
     );
 
 
     let amount: u64 = column_as_number!(amount);
     let amount: u64 = column_as_number!(amount);
     let fee_reserve: u64 = column_as_number!(fee_reserve);
     let fee_reserve: u64 = column_as_number!(fee_reserve);
 
 
+    let payment_method =
+        PaymentMethod::from_str(&column_as_string!(row_method)).map_err(Error::from)?;
+
     Ok(wallet::MeltQuote {
     Ok(wallet::MeltQuote {
         id: column_as_string!(id),
         id: column_as_string!(id),
         amount: Amount::from(amount),
         amount: Amount::from(amount),
@@ -1140,6 +1148,7 @@ fn sql_row_to_melt_quote(row: Vec<Column>) -> Result<wallet::MeltQuote, Error> {
         state: column_as_string!(state, MeltQuoteState::from_str),
         state: column_as_string!(state, MeltQuoteState::from_str),
         expiry: column_as_number!(expiry),
         expiry: column_as_number!(expiry),
         payment_preimage: column_as_nullable_string!(payment_preimage),
         payment_preimage: column_as_nullable_string!(payment_preimage),
+        payment_method,
     })
     })
 }
 }
 
 

+ 9 - 1
crates/cdk/src/wallet/melt/melt_bolt11.rs

@@ -3,6 +3,7 @@ use std::str::FromStr;
 
 
 use cdk_common::amount::SplitTarget;
 use cdk_common::amount::SplitTarget;
 use cdk_common::wallet::{Transaction, TransactionDirection};
 use cdk_common::wallet::{Transaction, TransactionDirection};
+use cdk_common::PaymentMethod;
 use lightning_invoice::Bolt11Invoice;
 use lightning_invoice::Bolt11Invoice;
 use tracing::instrument;
 use tracing::instrument;
 
 
@@ -87,6 +88,7 @@ impl Wallet {
             state: quote_res.state,
             state: quote_res.state,
             expiry: quote_res.expiry,
             expiry: quote_res.expiry,
             payment_preimage: quote_res.payment_preimage,
             payment_preimage: quote_res.payment_preimage,
+            payment_method: PaymentMethod::Bolt11,
         };
         };
 
 
         self.localstore.add_melt_quote(quote.clone()).await?;
         self.localstore.add_melt_quote(quote.clone()).await?;
@@ -183,7 +185,13 @@ impl Wallet {
             Some(premint_secrets.blinded_messages()),
             Some(premint_secrets.blinded_messages()),
         );
         );
 
 
-        let melt_response = self.client.post_melt(request).await;
+        let melt_response = match quote_info.payment_method {
+            cdk_common::PaymentMethod::Bolt11 => self.client.post_melt(request).await,
+            cdk_common::PaymentMethod::Bolt12 => self.client.post_melt_bolt12(request).await,
+            cdk_common::PaymentMethod::Custom(_) => {
+                return Err(Error::UnsupportedPaymentMethod);
+            }
+        };
 
 
         let melt_response = match melt_response {
         let melt_response = match melt_response {
             Ok(melt_response) => melt_response,
             Ok(melt_response) => melt_response,

+ 2 - 0
crates/cdk/src/wallet/melt/melt_bolt12.rs

@@ -6,6 +6,7 @@ use std::str::FromStr;
 
 
 use cdk_common::amount::amount_for_offer;
 use cdk_common::amount::amount_for_offer;
 use cdk_common::wallet::MeltQuote;
 use cdk_common::wallet::MeltQuote;
+use cdk_common::PaymentMethod;
 use lightning::offers::offer::Offer;
 use lightning::offers::offer::Offer;
 use tracing::instrument;
 use tracing::instrument;
 
 
@@ -57,6 +58,7 @@ impl Wallet {
             state: quote_res.state,
             state: quote_res.state,
             expiry: quote_res.expiry,
             expiry: quote_res.expiry,
             payment_preimage: quote_res.payment_preimage,
             payment_preimage: quote_res.payment_preimage,
+            payment_method: PaymentMethod::Bolt12,
         };
         };
 
 
         self.localstore.add_melt_quote(quote.clone()).await?;
         self.localstore.add_melt_quote(quote.clone()).await?;