@@ -304,6 +304,101 @@ async fn multi_hop_sending() {
304304 expect_payment_successful_event ! ( nodes[ 0 ] , payment_id, Some ( fee_paid_msat) ) ;
305305}
306306
307+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
308+ async fn split_underpaid_bolt11_payment ( ) {
309+ let ( bitcoind, electrsd) = setup_bitcoind_and_electrsd ( ) ;
310+ let chain_source = random_chain_source ( & bitcoind, & electrsd) ;
311+ let ( node_a, node_b) = setup_two_nodes ( & chain_source, false , true , false ) ;
312+ let node_c = setup_node ( & chain_source, random_config ( true ) ) ;
313+
314+ let addr_a = node_a. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
315+ let addr_b = node_b. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
316+ let addr_c = node_c. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
317+ let premine_amount_sat = 5_000_000 ;
318+ premine_and_distribute_funds (
319+ & bitcoind. client ,
320+ & electrsd. client ,
321+ vec ! [ addr_a, addr_b, addr_c] ,
322+ Amount :: from_sat ( premine_amount_sat) ,
323+ )
324+ . await ;
325+
326+ for node in [ & node_a, & node_b, & node_c] {
327+ node. sync_wallets ( ) . unwrap ( ) ;
328+ assert_eq ! ( node. list_balances( ) . spendable_onchain_balance_sats, premine_amount_sat) ;
329+ }
330+
331+ // The receiver opens both channels and pushes liquidity to both payers so each payer can send
332+ // half of the invoice back.
333+ let channel_amount_sat = 1_000_000 ;
334+ let push_amount_msat = Some ( 500_000_000 ) ;
335+ for payer in [ & node_a, & node_b] {
336+ node_c
337+ . open_channel (
338+ payer. node_id ( ) ,
339+ payer. listening_addresses ( ) . unwrap ( ) . first ( ) . unwrap ( ) . clone ( ) ,
340+ channel_amount_sat,
341+ push_amount_msat,
342+ None ,
343+ )
344+ . unwrap ( ) ;
345+
346+ let funding_txo_c = expect_channel_pending_event ! ( node_c, payer. node_id( ) ) ;
347+ let funding_txo_payer = expect_channel_pending_event ! ( payer, node_c. node_id( ) ) ;
348+ assert_eq ! ( funding_txo_c, funding_txo_payer) ;
349+ wait_for_tx ( & electrsd. client , funding_txo_c. txid ) . await ;
350+
351+ node_c. sync_wallets ( ) . unwrap ( ) ;
352+ }
353+
354+ generate_blocks_and_wait ( & bitcoind. client , & electrsd. client , 6 ) . await ;
355+
356+ for node in [ & node_a, & node_b, & node_c] {
357+ node. sync_wallets ( ) . unwrap ( ) ;
358+ }
359+
360+ expect_channel_ready_events ! ( node_c, node_a. node_id( ) , node_b. node_id( ) ) ;
361+ expect_channel_ready_event ! ( node_a, node_c. node_id( ) ) ;
362+ expect_channel_ready_event ! ( node_b, node_c. node_id( ) ) ;
363+
364+ let amount_msat = 100_000_000 ;
365+ let half_amount_msat = amount_msat / 2 ;
366+ let invoice_description =
367+ Bolt11InvoiceDescription :: Direct ( Description :: new ( String :: from ( "split" ) ) . unwrap ( ) ) ;
368+ let invoice =
369+ node_c. bolt11_payment ( ) . receive ( amount_msat, & invoice_description. into ( ) , 3600 ) . unwrap ( ) ;
370+
371+ // Each payer sends only half the invoice amount, while declaring the full invoice amount as
372+ // the total MPP value. The receiver should claim only once both HTLCs arrive.
373+ let payment_id_a = node_a
374+ . bolt11_payment ( )
375+ . send_using_amount_underpaying ( & invoice, half_amount_msat, None )
376+ . unwrap ( ) ;
377+ let payment_id_b = node_b
378+ . bolt11_payment ( )
379+ . send_using_amount_underpaying ( & invoice, half_amount_msat, None )
380+ . unwrap ( ) ;
381+
382+ let receiver_payment_id = expect_payment_received_event ! ( node_c, amount_msat) ;
383+ assert_eq ! ( receiver_payment_id, Some ( PaymentId ( invoice. payment_hash( ) . 0 ) ) ) ;
384+ expect_payment_successful_event ! ( node_a, Some ( payment_id_a) , None ) ;
385+ expect_payment_successful_event ! ( node_b, Some ( payment_id_b) , None ) ;
386+
387+ // The receiver records the full invoice amount; each payer records only its own half.
388+ let receiver_payments =
389+ node_c. list_payments_with_filter ( |p| p. id == receiver_payment_id. unwrap ( ) ) ;
390+ assert_eq ! ( receiver_payments. len( ) , 1 ) ;
391+ assert_eq ! ( receiver_payments. first( ) . unwrap( ) . amount_msat, Some ( amount_msat) ) ;
392+
393+ let node_a_payments = node_a. list_payments_with_filter ( |p| p. id == payment_id_a) ;
394+ assert_eq ! ( node_a_payments. len( ) , 1 ) ;
395+ assert_eq ! ( node_a_payments. first( ) . unwrap( ) . amount_msat, Some ( half_amount_msat) ) ;
396+
397+ let node_b_payments = node_b. list_payments_with_filter ( |p| p. id == payment_id_b) ;
398+ assert_eq ! ( node_b_payments. len( ) , 1 ) ;
399+ assert_eq ! ( node_b_payments. first( ) . unwrap( ) . amount_msat, Some ( half_amount_msat) ) ;
400+ }
401+
307402#[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
308403async fn start_stop_reinit ( ) {
309404 let ( bitcoind, electrsd) = setup_bitcoind_and_electrsd ( ) ;
0 commit comments