Set extra skimmed fee on intercepted forward
[rust-lightning] / lightning / src / util / config.rs
index 1e678152cccd9d3cfa4bdcc1d40dd441b739913e..b948a13835708db4ee3cb6328b5951f733f1b1a1 100644 (file)
@@ -397,6 +397,55 @@ pub struct ChannelConfig {
        /// [`Normal`]: crate::chain::chaininterface::ConfirmationTarget::Normal
        /// [`Background`]: crate::chain::chaininterface::ConfirmationTarget::Background
        pub force_close_avoidance_max_fee_satoshis: u64,
+       /// If set, allows this channel's counterparty to skim an additional fee off this node's inbound
+       /// HTLCs. Useful for liquidity providers to offload on-chain channel costs to end users.
+       ///
+       /// Usage:
+       /// - The payee will set this option and set its invoice route hints to use [intercept scids]
+       ///   generated by this channel's counterparty.
+       /// - The counterparty will get an [`HTLCIntercepted`] event upon payment forward, and call
+       ///   [`forward_intercepted_htlc`] with less than the amount provided in
+       ///   [`HTLCIntercepted::expected_outbound_amount_msat`]. The difference between the expected and
+       ///   actual forward amounts is their fee.
+       // TODO: link to LSP JIT channel invoice generation spec when it's merged
+       ///
+       /// # Note
+       /// It's important for payee wallet software to verify that [`PaymentClaimable::amount_msat`] is
+       /// as-expected if this feature is activated, otherwise they may lose money!
+       ///
+       /// # Note
+       /// Switching this config flag on may break compatibility with versions of LDK prior to 0.0.116.
+       ///
+       /// Default value: false.
+       ///
+       /// [intercept scids]: crate::ln::channelmanager::ChannelManager::get_intercept_scid
+       /// [`forward_intercepted_htlc`]: crate::ln::channelmanager::ChannelManager::forward_intercepted_htlc
+       /// [`HTLCIntercepted`]: crate::events::Event::HTLCIntercepted
+       /// [`HTLCIntercepted::expected_outbound_amount_msat`]: crate::events::Event::HTLCIntercepted::expected_outbound_amount_msat
+       /// [`PaymentClaimable::amount_msat`]: crate::events::Event::PaymentClaimable::amount_msat
+       //  TODO: link to bLIP when it's merged
+       pub accept_underpaying_htlcs: bool,
+}
+
+impl ChannelConfig {
+       /// Applies the given [`ChannelConfigUpdate`] as a partial update to the [`ChannelConfig`].
+       pub fn apply(&mut self, update: &ChannelConfigUpdate) {
+               if let Some(forwarding_fee_proportional_millionths) = update.forwarding_fee_proportional_millionths {
+                       self.forwarding_fee_proportional_millionths = forwarding_fee_proportional_millionths;
+               }
+               if let Some(forwarding_fee_base_msat) = update.forwarding_fee_base_msat {
+                       self.forwarding_fee_base_msat = forwarding_fee_base_msat;
+               }
+               if let Some(cltv_expiry_delta) = update.cltv_expiry_delta {
+                       self.cltv_expiry_delta = cltv_expiry_delta;
+               }
+               if let Some(max_dust_htlc_exposure_msat) = update.max_dust_htlc_exposure_msat {
+                       self.max_dust_htlc_exposure_msat = max_dust_htlc_exposure_msat;
+               }
+               if let Some(force_close_avoidance_max_fee_satoshis) = update.force_close_avoidance_max_fee_satoshis {
+                       self.force_close_avoidance_max_fee_satoshis = force_close_avoidance_max_fee_satoshis;
+               }
+       }
 }
 
 impl Default for ChannelConfig {
@@ -408,12 +457,14 @@ impl Default for ChannelConfig {
                        cltv_expiry_delta: 6 * 12, // 6 blocks/hour * 12 hours
                        max_dust_htlc_exposure_msat: 5_000_000,
                        force_close_avoidance_max_fee_satoshis: 1000,
+                       accept_underpaying_htlcs: false,
                }
        }
 }
 
 impl_writeable_tlv_based!(ChannelConfig, {
        (0, forwarding_fee_proportional_millionths, required),
+       (1, accept_underpaying_htlcs, (default_value, false)),
        (2, forwarding_fee_base_msat, required),
        (4, cltv_expiry_delta, required),
        (6, max_dust_htlc_exposure_msat, required),
@@ -423,6 +474,40 @@ impl_writeable_tlv_based!(ChannelConfig, {
        (10, force_close_avoidance_max_fee_satoshis, required),
 });
 
+/// A parallel struct to [`ChannelConfig`] to define partial updates.
+#[allow(missing_docs)]
+pub struct ChannelConfigUpdate {
+       pub forwarding_fee_proportional_millionths: Option<u32>,
+       pub forwarding_fee_base_msat: Option<u32>,
+       pub cltv_expiry_delta: Option<u16>,
+       pub max_dust_htlc_exposure_msat: Option<u64>,
+       pub force_close_avoidance_max_fee_satoshis: Option<u64>,
+}
+
+impl Default for ChannelConfigUpdate {
+       fn default() -> ChannelConfigUpdate {
+               ChannelConfigUpdate {
+                       forwarding_fee_proportional_millionths: None,
+                       forwarding_fee_base_msat: None,
+                       cltv_expiry_delta: None,
+                       max_dust_htlc_exposure_msat: None,
+                       force_close_avoidance_max_fee_satoshis: None,
+               }
+       }
+}
+
+impl From<ChannelConfig> for ChannelConfigUpdate {
+       fn from(config: ChannelConfig) -> ChannelConfigUpdate {
+               ChannelConfigUpdate {
+                       forwarding_fee_proportional_millionths: Some(config.forwarding_fee_proportional_millionths),
+                       forwarding_fee_base_msat: Some(config.forwarding_fee_base_msat),
+                       cltv_expiry_delta: Some(config.cltv_expiry_delta),
+                       max_dust_htlc_exposure_msat: Some(config.max_dust_htlc_exposure_msat),
+                       force_close_avoidance_max_fee_satoshis: Some(config.force_close_avoidance_max_fee_satoshis),
+               }
+       }
+}
+
 /// Legacy version of [`ChannelConfig`] that stored the static
 /// [`ChannelHandshakeConfig::announced_channel`] and
 /// [`ChannelHandshakeConfig::commit_upfront_shutdown_pubkey`] fields.
@@ -488,6 +573,7 @@ impl crate::util::ser::Readable for LegacyChannelConfig {
                                cltv_expiry_delta,
                                force_close_avoidance_max_fee_satoshis,
                                forwarding_fee_base_msat,
+                               accept_underpaying_htlcs: false,
                        },
                        announced_channel,
                        commit_upfront_shutdown_pubkey,
@@ -552,6 +638,17 @@ pub struct UserConfig {
        /// [`ChannelManager::get_intercept_scid`]: crate::ln::channelmanager::ChannelManager::get_intercept_scid
        /// [`Event::HTLCIntercepted`]: crate::events::Event::HTLCIntercepted
        pub accept_intercept_htlcs: bool,
+       /// If this is set to false, when receiving a keysend payment we'll fail it if it has multiple
+       /// parts. If this is set to true, we'll accept the payment.
+       ///
+       /// Setting this to true will break backwards compatibility upon downgrading to an LDK
+       /// version < 0.0.116 while receiving an MPP keysend. If we have already received an MPP
+       /// keysend, downgrading will cause us to fail to deserialize [`ChannelManager`].
+       ///
+       /// Default value: false.
+       ///
+       /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
+       pub accept_mpp_keysend: bool,
 }
 
 impl Default for UserConfig {
@@ -564,6 +661,7 @@ impl Default for UserConfig {
                        accept_inbound_channels: true,
                        manually_accept_inbound_channels: false,
                        accept_intercept_htlcs: false,
+                       accept_mpp_keysend: false,
                }
        }
 }