@@ -34,7 +34,7 @@ use lightning_net_tokio::SocketDescriptor;
3434
3535use crate :: chain:: bitcoind:: UtxoSourceClient ;
3636use crate :: chain:: ChainSource ;
37- use crate :: config:: ChannelConfig ;
37+ use crate :: config:: { AnchorChannelsConfig , ChannelConfig } ;
3838use crate :: data_store:: DataStore ;
3939use crate :: fee_estimator:: OnchainFeeEstimator ;
4040use crate :: logger:: Logger ;
@@ -428,6 +428,47 @@ pub struct ChannelCounterparty {
428428 pub outbound_htlc_maximum_msat : Option < u64 > ,
429429}
430430
431+ /// Describes the reserve behavior of a channel based on its type and trust configuration.
432+ ///
433+ /// This captures the combination of the channel's on-chain construction (anchor outputs vs legacy
434+ /// static_remote_key) and whether the counterparty is in our trusted peers list. It tells the
435+ /// user what reserve obligations exist for this channel without exposing internal protocol details.
436+ ///
437+ /// See [`AnchorChannelsConfig`] for how reserve behavior is configured.
438+ ///
439+ /// [`AnchorChannelsConfig`]: crate::config::AnchorChannelsConfig
440+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
441+ #[ cfg_attr( feature = "uniffi" , derive( uniffi:: Enum ) ) ]
442+ pub enum ReserveType {
443+ /// An anchor outputs channel where we maintain a per-channel on-chain reserve for fee
444+ /// bumping force-close transactions.
445+ ///
446+ /// Anchor channels allow either party to fee-bump commitment transactions via CPFP
447+ /// at broadcast time. Because the pre-signed commitment fee may be insufficient under
448+ /// current fee conditions, the broadcaster must supply additional funds (hence adaptive)
449+ /// through an anchor output spend. The reserve ensures sufficient on-chain funds are
450+ /// available to cover this.
451+ ///
452+ /// This is the default for anchor channels when the counterparty is not in
453+ /// [`trusted_peers_no_reserve`].
454+ ///
455+ /// [`trusted_peers_no_reserve`]: crate::config::AnchorChannelsConfig::trusted_peers_no_reserve
456+ Adaptive ,
457+ /// An anchor outputs channel where we do not maintain any reserve, because the counterparty
458+ /// is in our [`trusted_peers_no_reserve`] list.
459+ ///
460+ /// In this mode, we trust the counterparty to broadcast a valid commitment transaction on
461+ /// our behalf and do not set aside funds for fee bumping.
462+ ///
463+ /// [`trusted_peers_no_reserve`]: crate::config::AnchorChannelsConfig::trusted_peers_no_reserve
464+ TrustedPeersNoReserve ,
465+ /// A legacy (pre-anchor) channel using only `option_static_remotekey`.
466+ ///
467+ /// These channels do not use anchor outputs and therefore do not require an on-chain reserve
468+ /// for fee bumping. Commitment transaction fees are pre-committed at channel open time.
469+ Legacy ,
470+ }
471+
431472/// Details of a channel as returned by [`Node::list_channels`].
432473///
433474/// When a channel is spliced, most fields continue to refer to the original pre-splice channel
@@ -588,10 +629,32 @@ pub struct ChannelDetails {
588629 pub inbound_htlc_maximum_msat : Option < u64 > ,
589630 /// Set of configurable parameters that affect channel operation.
590631 pub config : ChannelConfig ,
632+ /// The type of on-chain reserve maintained for this channel.
633+ ///
634+ /// See [`ReserveType`] for details on how reserves differ between anchor and legacy channels.
635+ pub reserve_type : ReserveType ,
591636}
592637
593- impl From < LdkChannelDetails > for ChannelDetails {
594- fn from ( value : LdkChannelDetails ) -> Self {
638+ impl ChannelDetails {
639+ pub ( crate ) fn from_ldk (
640+ value : LdkChannelDetails , anchor_channels_config : Option < & AnchorChannelsConfig > ,
641+ ) -> Self {
642+ let is_anchor_channel =
643+ value. channel_type . as_ref ( ) . map_or ( false , |ct| ct. supports_anchors_zero_fee_htlc_tx ( ) ) ;
644+
645+ let reserve_type = if is_anchor_channel {
646+ let is_trusted = anchor_channels_config. map_or ( false , |c| {
647+ c. trusted_peers_no_reserve . contains ( & value. counterparty . node_id )
648+ } ) ;
649+ if is_trusted {
650+ ReserveType :: TrustedPeersNoReserve
651+ } else {
652+ ReserveType :: Adaptive
653+ }
654+ } else {
655+ ReserveType :: Legacy
656+ } ;
657+
595658 ChannelDetails {
596659 channel_id : value. channel_id ,
597660 counterparty : ChannelCounterparty {
@@ -630,6 +693,7 @@ impl From<LdkChannelDetails> for ChannelDetails {
630693 inbound_htlc_maximum_msat : value. inbound_htlc_maximum_msat ,
631694 // unwrap safety: `config` is only `None` for LDK objects serialized prior to 0.0.109.
632695 config : value. config . map ( |c| c. into ( ) ) . unwrap ( ) ,
696+ reserve_type,
633697 }
634698 }
635699}
0 commit comments