@@ -664,26 +664,40 @@ where
664664 }
665665 }
666666
667- fn lsps2_max_total_opening_fee_msat ( payment_metadata : & [ u8 ] , amount_msat : u64 ) -> Option < u64 > {
667+ fn lsps2_max_total_opening_fee_msat (
668+ payment_metadata : & [ u8 ] , amount_msat : u64 , counterparty_skimmed_fee_msat : u64 ,
669+ ) -> Option < u64 > {
668670 let metadata = PaymentMetadata :: read ( & mut & payment_metadata[ ..] ) . ok ( ) ?;
669- Self :: lsps2_max_total_opening_fee_msat_from_metadata ( metadata, amount_msat)
671+ Self :: lsps2_max_total_opening_fee_msat_from_metadata (
672+ metadata,
673+ amount_msat,
674+ counterparty_skimmed_fee_msat,
675+ )
670676 }
671677
672678 fn lsps2_bolt12_max_total_opening_fee_msat (
673679 payment_metadata : & BTreeMap < u64 , Vec < u8 > > , amount_msat : u64 ,
680+ counterparty_skimmed_fee_msat : u64 ,
674681 ) -> Option < u64 > {
675682 let metadata = PaymentMetadata :: decode_from_bolt12_payment_metadata ( payment_metadata) ?;
676- Self :: lsps2_max_total_opening_fee_msat_from_metadata ( metadata, amount_msat)
683+ Self :: lsps2_max_total_opening_fee_msat_from_metadata (
684+ metadata,
685+ amount_msat,
686+ counterparty_skimmed_fee_msat,
687+ )
677688 }
678689
679690 fn lsps2_max_total_opening_fee_msat_from_metadata (
680- metadata : PaymentMetadata , amount_msat : u64 ,
691+ metadata : PaymentMetadata , amount_msat : u64 , counterparty_skimmed_fee_msat : u64 ,
681692 ) -> Option < u64 > {
682693 let lsps2_parameters = metadata. lsps2_parameters ?;
683694 lsps2_parameters. max_total_opening_fee_msat . or_else ( || {
684695 lsps2_parameters. max_proportional_opening_fee_ppm_msat . and_then ( |max_prop_fee| {
685- // If it's a variable amount payment, compute the actual fee.
686- compute_opening_fee ( amount_msat, 0 , max_prop_fee)
696+ // `PaymentClaimable::amount_msat` excludes the fee withheld by the LSP. LSPS2
697+ // proportional fees are calculated from the amount sent by the payer, so add the
698+ // withheld fee back before computing the permitted fee.
699+ let payment_size_msat = amount_msat. checked_add ( counterparty_skimmed_fee_msat) ?;
700+ compute_opening_fee ( payment_size_msat, 0 , max_prop_fee)
687701 } )
688702 } )
689703 }
@@ -873,11 +887,19 @@ where
873887 . as_ref ( )
874888 . and_then ( |fields| fields. payment_metadata . as_ref ( ) )
875889 . and_then ( |metadata| {
876- Self :: lsps2_max_total_opening_fee_msat ( metadata, amount_msat)
890+ Self :: lsps2_max_total_opening_fee_msat (
891+ metadata,
892+ amount_msat,
893+ counterparty_skimmed_fee_msat,
894+ )
877895 } ) ,
878896 PaymentPurpose :: Bolt12OfferPayment { payment_context, .. } => {
879897 payment_context. payment_metadata . as_ref ( ) . and_then ( |metadata| {
880- Self :: lsps2_bolt12_max_total_opening_fee_msat ( metadata, amount_msat)
898+ Self :: lsps2_bolt12_max_total_opening_fee_msat (
899+ metadata,
900+ amount_msat,
901+ counterparty_skimmed_fee_msat,
902+ )
881903 } )
882904 } ,
883905 _ => None ,
@@ -2074,12 +2096,33 @@ mod tests {
20742096 assert_eq ! (
20752097 EventHandler :: <Arc <TestLogger >>:: lsps2_max_total_opening_fee_msat(
20762098 & metadata. encode( ) ,
2077- 100_000
2099+ 100_000 ,
2100+ 0 ,
20782101 ) ,
20792102 Some ( 42_000 )
20802103 ) ;
20812104 }
20822105
2106+ #[ test]
2107+ fn lsps2_proportional_fee_uses_gross_payment_amount ( ) {
2108+ let metadata = PaymentMetadata {
2109+ lsps2_parameters : Some ( LSPS2Parameters {
2110+ max_total_opening_fee_msat : None ,
2111+ max_proportional_opening_fee_ppm_msat : Some ( 10_000 ) ,
2112+ } ) ,
2113+ lsps2_lease_parameters : None ,
2114+ } ;
2115+
2116+ assert_eq ! (
2117+ EventHandler :: <Arc <TestLogger >>:: lsps2_max_total_opening_fee_msat(
2118+ & metadata. encode( ) ,
2119+ 198_000 ,
2120+ 2_000 ,
2121+ ) ,
2122+ Some ( 2_000 )
2123+ ) ;
2124+ }
2125+
20832126 #[ test]
20842127 fn lsps2_payment_metadata_missing_or_malformed_limit_is_rejected ( ) {
20852128 let empty_metadata =
@@ -2096,18 +2139,20 @@ mod tests {
20962139 assert_eq ! (
20972140 EventHandler :: <Arc <TestLogger >>:: lsps2_max_total_opening_fee_msat(
20982141 & empty_metadata,
2099- 100_000
2142+ 100_000 ,
2143+ 0 ,
21002144 ) ,
21012145 None
21022146 ) ;
21032147 assert_eq ! (
2104- EventHandler :: <Arc <TestLogger >>:: lsps2_max_total_opening_fee_msat( & [ 0xff ] , 100_000 ) ,
2148+ EventHandler :: <Arc <TestLogger >>:: lsps2_max_total_opening_fee_msat( & [ 0xff ] , 100_000 , 0 , ) ,
21052149 None
21062150 ) ;
21072151 assert_eq ! (
21082152 EventHandler :: <Arc <TestLogger >>:: lsps2_max_total_opening_fee_msat(
21092153 & metadata_without_fee_limit,
2110- 100_000
2154+ 100_000 ,
2155+ 0 ,
21112156 ) ,
21122157 None
21132158 ) ;
@@ -2126,7 +2171,7 @@ mod tests {
21262171
21272172 assert_eq ! (
21282173 EventHandler :: <Arc <TestLogger >>:: lsps2_bolt12_max_total_opening_fee_msat(
2129- & metadata, 100_000
2174+ & metadata, 100_000 , 0 ,
21302175 ) ,
21312176 Some ( 1_000 )
21322177 ) ;
@@ -2144,7 +2189,7 @@ mod tests {
21442189 for metadata in [ empty_metadata, malformed_metadata, metadata_without_fee_limit] {
21452190 assert_eq ! (
21462191 EventHandler :: <Arc <TestLogger >>:: lsps2_bolt12_max_total_opening_fee_msat(
2147- & metadata, 100_000
2192+ & metadata, 100_000 , 0 ,
21482193 ) ,
21492194 None
21502195 ) ;
0 commit comments