From c5e5d71701a837418463a3b8fb04e02d57d0b13a Mon Sep 17 00:00:00 2001 From: tsk Date: Mon, 6 Oct 2025 14:40:21 +0200 Subject: [PATCH] feat(cdk): add payment request and proof to transaction records (#1155) Add payment_request and payment_proof fields to Transaction model to store Lightning invoice details and payment preimages. Update database migrations and all transaction creation points across wallet operations (mint, melt, send, receive) to populate these fields. --- crates/cdk-common/src/wallet.rs | 4 ++++ crates/cdk-ffi/src/types/transaction.rs | 8 +++++++ ...20000_add_payment_info_to_transactions.sql | 3 +++ ...20000_add_payment_info_to_transactions.sql | 3 +++ crates/cdk-sql-common/src/wallet/mod.rs | 24 ++++++++++++++----- crates/cdk/src/wallet/issue/issue_bolt11.rs | 2 ++ crates/cdk/src/wallet/issue/issue_bolt12.rs | 2 ++ crates/cdk/src/wallet/melt/melt_bolt11.rs | 6 ++++- crates/cdk/src/wallet/melt/mod.rs | 3 +++ crates/cdk/src/wallet/receive.rs | 4 +++- crates/cdk/src/wallet/send.rs | 4 +++- 11 files changed, 54 insertions(+), 9 deletions(-) create mode 100644 crates/cdk-sql-common/src/wallet/migrations/postgres/20251005120000_add_payment_info_to_transactions.sql create mode 100644 crates/cdk-sql-common/src/wallet/migrations/sqlite/20251005120000_add_payment_info_to_transactions.sql diff --git a/crates/cdk-common/src/wallet.rs b/crates/cdk-common/src/wallet.rs index a03d48f2..cf2a5a17 100644 --- a/crates/cdk-common/src/wallet.rs +++ b/crates/cdk-common/src/wallet.rs @@ -204,6 +204,10 @@ pub struct Transaction { pub metadata: HashMap, /// Quote ID if this is a mint or melt transaction pub quote_id: Option, + /// Payment request (e.g., BOLT11 invoice, BOLT12 offer) + pub payment_request: Option, + /// Payment proof (e.g., preimage for Lightning melt transactions) + pub payment_proof: Option, } impl Transaction { diff --git a/crates/cdk-ffi/src/types/transaction.rs b/crates/cdk-ffi/src/types/transaction.rs index 9291c778..9c70c35d 100644 --- a/crates/cdk-ffi/src/types/transaction.rs +++ b/crates/cdk-ffi/src/types/transaction.rs @@ -35,6 +35,10 @@ pub struct Transaction { pub metadata: HashMap, /// Quote ID if this is a mint or melt transaction pub quote_id: Option, + /// Payment request (e.g., BOLT11 invoice, BOLT12 offer) + pub payment_request: Option, + /// Payment proof (e.g., preimage for Lightning melt transactions) + pub payment_proof: Option, } impl From for Transaction { @@ -51,6 +55,8 @@ impl From for Transaction { memo: tx.memo, metadata: tx.metadata, quote_id: tx.quote_id, + payment_request: tx.payment_request, + payment_proof: tx.payment_proof, } } } @@ -75,6 +81,8 @@ impl TryFrom for cdk::wallet::types::Transaction { memo: tx.memo, metadata: tx.metadata, quote_id: tx.quote_id, + payment_request: tx.payment_request, + payment_proof: tx.payment_proof, }) } } diff --git a/crates/cdk-sql-common/src/wallet/migrations/postgres/20251005120000_add_payment_info_to_transactions.sql b/crates/cdk-sql-common/src/wallet/migrations/postgres/20251005120000_add_payment_info_to_transactions.sql new file mode 100644 index 00000000..1b3b933d --- /dev/null +++ b/crates/cdk-sql-common/src/wallet/migrations/postgres/20251005120000_add_payment_info_to_transactions.sql @@ -0,0 +1,3 @@ +-- Add payment_request and payment_proof to transactions table +ALTER TABLE transactions ADD COLUMN payment_request TEXT; +ALTER TABLE transactions ADD COLUMN payment_proof TEXT; diff --git a/crates/cdk-sql-common/src/wallet/migrations/sqlite/20251005120000_add_payment_info_to_transactions.sql b/crates/cdk-sql-common/src/wallet/migrations/sqlite/20251005120000_add_payment_info_to_transactions.sql new file mode 100644 index 00000000..1b3b933d --- /dev/null +++ b/crates/cdk-sql-common/src/wallet/migrations/sqlite/20251005120000_add_payment_info_to_transactions.sql @@ -0,0 +1,3 @@ +-- Add payment_request and payment_proof to transactions table +ALTER TABLE transactions ADD COLUMN payment_request TEXT; +ALTER TABLE transactions ADD COLUMN payment_proof TEXT; diff --git a/crates/cdk-sql-common/src/wallet/mod.rs b/crates/cdk-sql-common/src/wallet/mod.rs index 64371613..fd91ea68 100644 --- a/crates/cdk-sql-common/src/wallet/mod.rs +++ b/crates/cdk-sql-common/src/wallet/mod.rs @@ -969,9 +969,9 @@ ON CONFLICT(id) DO UPDATE SET query( r#" INSERT INTO transactions -(id, mint_url, direction, unit, amount, fee, ys, timestamp, memo, metadata, quote_id) +(id, mint_url, direction, unit, amount, fee, ys, timestamp, memo, metadata, quote_id, payment_request, payment_proof) VALUES -(:id, :mint_url, :direction, :unit, :amount, :fee, :ys, :timestamp, :memo, :metadata, :quote_id) +(:id, :mint_url, :direction, :unit, :amount, :fee, :ys, :timestamp, :memo, :metadata, :quote_id, :payment_request, :payment_proof) ON CONFLICT(id) DO UPDATE SET mint_url = excluded.mint_url, direction = excluded.direction, @@ -982,7 +982,9 @@ ON CONFLICT(id) DO UPDATE SET timestamp = excluded.timestamp, memo = excluded.memo, metadata = excluded.metadata, - quote_id = excluded.quote_id + quote_id = excluded.quote_id, + payment_request = excluded.payment_request, + payment_proof = excluded.payment_proof ; "#, )? @@ -1000,6 +1002,8 @@ ON CONFLICT(id) DO UPDATE SET serde_json::to_string(&transaction.metadata).map_err(Error::from)?, ) .bind("quote_id", transaction.quote_id) + .bind("payment_request", transaction.payment_request) + .bind("payment_proof", transaction.payment_proof) .execute(&*conn) .await?; @@ -1024,7 +1028,9 @@ ON CONFLICT(id) DO UPDATE SET timestamp, memo, metadata, - quote_id + quote_id, + payment_request, + payment_proof FROM transactions WHERE @@ -1059,7 +1065,9 @@ ON CONFLICT(id) DO UPDATE SET timestamp, memo, metadata, - quote_id + quote_id, + payment_request, + payment_proof FROM transactions "#, @@ -1297,7 +1305,9 @@ fn sql_row_to_transaction(row: Vec) -> Result { timestamp, memo, metadata, - quote_id + quote_id, + payment_request, + payment_proof ) = row ); @@ -1321,5 +1331,7 @@ fn sql_row_to_transaction(row: Vec) -> Result { }) .unwrap_or_default(), quote_id: column_as_nullable_string!(quote_id), + payment_request: column_as_nullable_string!(payment_request), + payment_proof: column_as_nullable_string!(payment_proof), }) } diff --git a/crates/cdk/src/wallet/issue/issue_bolt11.rs b/crates/cdk/src/wallet/issue/issue_bolt11.rs index 98ac3780..935c7602 100644 --- a/crates/cdk/src/wallet/issue/issue_bolt11.rs +++ b/crates/cdk/src/wallet/issue/issue_bolt11.rs @@ -329,6 +329,8 @@ impl Wallet { memo: None, metadata: HashMap::new(), quote_id: Some(quote_id.to_string()), + payment_request: Some(quote_info.request), + payment_proof: None, }) .await?; diff --git a/crates/cdk/src/wallet/issue/issue_bolt12.rs b/crates/cdk/src/wallet/issue/issue_bolt12.rs index 470f2582..fd8dc10f 100644 --- a/crates/cdk/src/wallet/issue/issue_bolt12.rs +++ b/crates/cdk/src/wallet/issue/issue_bolt12.rs @@ -232,6 +232,8 @@ impl Wallet { memo: None, metadata: HashMap::new(), quote_id: Some(quote_id.to_string()), + payment_request: Some(quote_info.request), + payment_proof: None, }) .await?; diff --git a/crates/cdk/src/wallet/melt/melt_bolt11.rs b/crates/cdk/src/wallet/melt/melt_bolt11.rs index 96a3f12f..58b23353 100644 --- a/crates/cdk/src/wallet/melt/melt_bolt11.rs +++ b/crates/cdk/src/wallet/melt/melt_bolt11.rs @@ -54,7 +54,7 @@ impl Wallet { let invoice = Bolt11Invoice::from_str(&request)?; let quote_request = MeltQuoteBolt11Request { - request: Bolt11Invoice::from_str(&request)?, + request: invoice.clone(), unit: self.unit.clone(), options, }; @@ -248,6 +248,8 @@ impl Wallet { None => None, }; + let payment_preimage = melt_response.payment_preimage.clone(); + let melted = Melted::from_proofs( melt_response.state, melt_response.payment_preimage, @@ -298,6 +300,8 @@ impl Wallet { memo: None, metadata, quote_id: Some(quote_id.to_string()), + payment_request: Some(quote_info.request), + payment_proof: payment_preimage, }) .await?; diff --git a/crates/cdk/src/wallet/melt/mod.rs b/crates/cdk/src/wallet/melt/mod.rs index 24db4629..c56d18eb 100644 --- a/crates/cdk/src/wallet/melt/mod.rs +++ b/crates/cdk/src/wallet/melt/mod.rs @@ -60,6 +60,7 @@ impl Wallet { let pending_proofs = self.get_pending_proofs().await?; let proofs_total = pending_proofs.total_amount().unwrap_or_default(); let change_total = response.change_amount().unwrap_or_default(); + self.localstore .add_transaction(Transaction { mint_url: self.mint_url.clone(), @@ -75,6 +76,8 @@ impl Wallet { memo: None, metadata: HashMap::new(), quote_id: Some(quote.id.clone()), + payment_request: Some(quote.request.clone()), + payment_proof: response.payment_preimage.clone(), }) .await?; } diff --git a/crates/cdk/src/wallet/receive.rs b/crates/cdk/src/wallet/receive.rs index 2d0334b4..b5fc2c8f 100644 --- a/crates/cdk/src/wallet/receive.rs +++ b/crates/cdk/src/wallet/receive.rs @@ -167,7 +167,9 @@ impl Wallet { timestamp: unix_time(), memo, metadata: opts.metadata, - quote_id: None, // Receive transactions don't have a quote_id + quote_id: None, + payment_request: None, + payment_proof: None, }) .await?; diff --git a/crates/cdk/src/wallet/send.rs b/crates/cdk/src/wallet/send.rs index 0f41f8e9..6b4d4123 100644 --- a/crates/cdk/src/wallet/send.rs +++ b/crates/cdk/src/wallet/send.rs @@ -350,7 +350,9 @@ impl PreparedSend { timestamp: unix_time(), memo: memo.clone(), metadata: self.options.metadata, - quote_id: None, // Send transactions don't have a quote_id + quote_id: None, + payment_request: None, + payment_proof: None, }) .await?;