@@ -7,19 +7,20 @@ use crate::{Event, EventQueue, InitFailure, Seed, WalletConfig};
77
88use ldk_node:: bitcoin:: hashes:: Hash ;
99use ldk_node:: bitcoin:: hashes:: sha256:: Hash as Sha256 ;
10+ use ldk_node:: bitcoin:: hex:: FromHex ;
1011use ldk_node:: lightning:: util:: logger:: Logger as _;
1112use ldk_node:: lightning:: util:: persist:: KVStore ;
1213use ldk_node:: lightning:: { log_error, log_info} ;
1314use ldk_node:: lightning_invoice:: Bolt11Invoice ;
14- use ldk_node:: lightning_types:: payment:: PaymentHash ;
15+ use ldk_node:: lightning_types:: payment:: { PaymentHash , PaymentPreimage } ;
1516
1617use bitcoin_payment_instructions:: PaymentMethod ;
1718use bitcoin_payment_instructions:: amount:: Amount ;
1819
1920use cdk:: amount:: SplitTarget ;
20- use cdk:: nuts:: CurrencyUnit ;
2121use cdk:: nuts:: MeltOptions ;
2222use cdk:: nuts:: nut23:: Amountless ;
23+ use cdk:: nuts:: { CurrencyUnit , MeltQuoteState } ;
2324use cdk:: wallet:: MintQuote ;
2425use cdk:: wallet:: Wallet ;
2526use cdk:: wallet:: types:: { Transaction , TransactionDirection } ;
@@ -55,6 +56,7 @@ pub struct Cashu {
5556 logger : Arc < Logger > ,
5657 supports_bolt12 : bool ,
5758 mint_quote_sender : mpsc:: Sender < MintQuote > ,
59+ event_queue : Arc < EventQueue > ,
5860}
5961
6062impl TrustedWalletInterface for Cashu {
@@ -210,8 +212,11 @@ impl TrustedWalletInterface for Cashu {
210212 amountless : Amountless { amount_msat : amount. milli_sats ( ) . into ( ) } ,
211213 } ) ;
212214
215+ let mut payment_hash: Option < PaymentHash > = None ;
216+
213217 let quote = match method {
214218 PaymentMethod :: LightningBolt11 ( invoice) => {
219+ payment_hash = Some ( PaymentHash ( * invoice. payment_hash ( ) . as_byte_array ( ) ) ) ;
215220 // Create a melt quote
216221 self . cashu_wallet . melt_quote ( invoice. to_string ( ) , melt_options) . await . map_err (
217222 |e| {
@@ -244,26 +249,104 @@ impl TrustedWalletInterface for Cashu {
244249 } ,
245250 } ;
246251
252+ // Convert quote ID to a 32-byte array for consistency
253+ // We'll use the quote ID as the payment identifier
254+ let payment_id = Self :: id_to_32_byte_array ( & quote. id ) ;
255+
247256 // Execute the melt in separate thread, do not block on it being successful/failed
248257 let cashu_wallet = Arc :: clone ( & self . cashu_wallet ) ;
249258 let logger = Arc :: clone ( & self . logger ) ;
259+ let event_queue = Arc :: clone ( & self . event_queue ) ;
250260 let quote_id = quote. id . clone ( ) ;
251261 tokio:: spawn ( async move {
252262 // todo react with events too
253263 match cashu_wallet. melt ( & quote_id) . await {
254- Ok ( _) => {
255- log_info ! ( logger, "Successfully sent for quote: {quote_id}" ) ;
264+ Ok ( res) => {
265+ match res. state {
266+ MeltQuoteState :: Paid => {
267+ log_info ! ( logger, "Successfully sent for quote: {quote_id}" ) ;
268+
269+ let preimage: Option < PaymentPreimage > = match & res. preimage {
270+ Some ( str) => match FromHex :: from_hex ( str) {
271+ Ok ( b) => Some ( PaymentPreimage ( b) ) ,
272+ Err ( e) => {
273+ log_error ! (
274+ logger,
275+ "Failed to decode preimage ({:?}) for quote {quote_id}: {e}" ,
276+ res. preimage
277+ ) ;
278+ None
279+ } ,
280+ } ,
281+ None => {
282+ debug_assert ! (
283+ false ,
284+ "Melt succeeded but no preimage for quote: {quote_id}"
285+ ) ;
286+ log_error ! (
287+ logger,
288+ "Melt succeeded but no preimage for quote: {quote_id}"
289+ ) ;
290+ None // Placeholder, should not happen
291+ } ,
292+ } ;
293+
294+ let hash = match payment_hash {
295+ Some ( hash) => hash,
296+ None => {
297+ match preimage {
298+ Some ( pre) => {
299+ let hash = Sha256 :: hash ( & pre. 0 ) ;
300+ PaymentHash ( hash. to_byte_array ( ) )
301+ } ,
302+ None => {
303+ log_error ! (
304+ logger,
305+ "Melt succeeded but no payment hash or preimage for quote: {quote_id}"
306+ ) ;
307+ PaymentHash ( [ 0u8 ; 32 ] ) // Placeholder, should not happen
308+ } ,
309+ }
310+ } ,
311+ } ;
312+
313+ let fee_paid_sat: u64 = res. fee_paid . into ( ) ;
314+ let _ = event_queue. add_event ( Event :: PaymentSuccessful {
315+ payment_id : PaymentId :: Trusted ( payment_id) ,
316+ payment_hash : hash,
317+ payment_preimage : preimage
318+ . unwrap_or ( PaymentPreimage ( [ 0u8 ; 32 ] ) ) ,
319+ fee_paid_msat : Some ( fee_paid_sat * 1_000 ) , // convert to msats
320+ } ) ;
321+ } ,
322+ MeltQuoteState :: Failed => {
323+ log_error ! ( logger, "Melt failed for quote: {quote_id}" ) ;
324+ let _ = event_queue. add_event ( Event :: PaymentFailed {
325+ payment_id : PaymentId :: Trusted ( payment_id) ,
326+ payment_hash,
327+ reason : None ,
328+ } ) ;
329+ } ,
330+ state => {
331+ log_error ! (
332+ logger,
333+ "Melt in unknown state {state} for quote: {quote_id}"
334+ ) ;
335+ // todo should we watch for it to complete?
336+ } ,
337+ }
256338 } ,
257339 Err ( e) => {
258- log_error ! ( logger, "Failed to melt quote {quote_id}: {e}" , ) ;
340+ log_error ! ( logger, "Failed to melt quote {quote_id}: {e}" ) ;
341+ let _ = event_queue. add_event ( Event :: PaymentFailed {
342+ payment_id : PaymentId :: Trusted ( payment_id) ,
343+ payment_hash,
344+ reason : None ,
345+ } ) ;
259346 } ,
260347 }
261348 } ) ;
262349
263- // Convert quote ID to a 32-byte array for consistency
264- // We'll use the quote ID as the payment identifier
265- let payment_id = Self :: id_to_32_byte_array ( & quote. id ) ;
266-
267350 Ok ( payment_id)
268351 } )
269352 }
@@ -333,6 +416,7 @@ impl Cashu {
333416 // Start mint quote monitoring task
334417 let wallet_for_monitoring = Arc :: clone ( & cashu_wallet) ;
335418 let logger_for_monitoring = Arc :: clone ( & logger) ;
419+ let eq_for_monitoring = Arc :: clone ( & event_queue) ;
336420 tokio:: spawn ( async move {
337421 loop {
338422 tokio:: select! {
@@ -345,7 +429,7 @@ impl Cashu {
345429
346430 // Start monitoring this quote
347431 let wallet = Arc :: clone( & wallet_for_monitoring) ;
348- let event_queue = Arc :: clone( & event_queue ) ;
432+ let event_queue = Arc :: clone( & eq_for_monitoring ) ;
349433 let logger = Arc :: clone( & logger_for_monitoring) ;
350434 tokio:: spawn( async move {
351435 if let Err ( e) = Self :: monitor_mint_quote( wallet, event_queue, & logger, mint_quote) . await {
@@ -369,7 +453,14 @@ impl Cashu {
369453 }
370454 }
371455
372- Ok ( Cashu { cashu_wallet, shutdown_sender, logger, supports_bolt12, mint_quote_sender } )
456+ Ok ( Cashu {
457+ cashu_wallet,
458+ shutdown_sender,
459+ logger,
460+ supports_bolt12,
461+ mint_quote_sender,
462+ event_queue,
463+ } )
373464 }
374465
375466 /// Convert an ID string to a 32-byte array
0 commit comments