@@ -33,7 +33,7 @@ use lightning_net_tokio::SocketDescriptor;
3333
3434use crate :: chain:: bitcoind:: UtxoSourceClient ;
3535use crate :: chain:: ChainSource ;
36- use crate :: config:: ChannelConfig ;
36+ use crate :: config:: { AnchorChannelsConfig , ChannelConfig } ;
3737use crate :: data_store:: DataStore ;
3838use crate :: fee_estimator:: OnchainFeeEstimator ;
3939use crate :: ffi:: maybe_wrap;
@@ -411,6 +411,47 @@ pub struct ChannelCounterparty {
411411 pub outbound_htlc_maximum_msat : Option < u64 > ,
412412}
413413
414+ /// Describes the reserve behavior of a channel based on its type and trust configuration.
415+ ///
416+ /// This captures the combination of the channel's on-chain construction (anchor outputs vs legacy
417+ /// static_remote_key) and whether the counterparty is in our trusted peers list. It tells the
418+ /// user what reserve obligations exist for this channel without exposing internal protocol details.
419+ ///
420+ /// See [`AnchorChannelsConfig`] for how reserve behavior is configured.
421+ ///
422+ /// [`AnchorChannelsConfig`]: crate::config::AnchorChannelsConfig
423+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
424+ #[ cfg_attr( feature = "uniffi" , derive( uniffi:: Enum ) ) ]
425+ pub enum ReserveType {
426+ /// An anchor outputs channel where we maintain a per-channel on-chain reserve for fee
427+ /// bumping force-close transactions.
428+ ///
429+ /// Anchor channels allow either party to fee-bump commitment transactions via CPFP
430+ /// at broadcast time. Because the pre-signed commitment fee may be insufficient under
431+ /// current fee conditions, the broadcaster must supply additional funds (hence adaptive)
432+ /// through an anchor output spend. The reserve ensures sufficient on-chain funds are
433+ /// available to cover this.
434+ ///
435+ /// This is the default for anchor channels when the counterparty is not in
436+ /// [`trusted_peers_no_reserve`].
437+ ///
438+ /// [`trusted_peers_no_reserve`]: crate::config::AnchorChannelsConfig::trusted_peers_no_reserve
439+ Adaptive ,
440+ /// An anchor outputs channel where we do not maintain any reserve, because the counterparty
441+ /// is in our [`trusted_peers_no_reserve`] list.
442+ ///
443+ /// In this mode, we trust the counterparty to broadcast a valid commitment transaction on
444+ /// our behalf and do not set aside funds for fee bumping.
445+ ///
446+ /// [`trusted_peers_no_reserve`]: crate::config::AnchorChannelsConfig::trusted_peers_no_reserve
447+ TrustedPeersNoReserve ,
448+ /// A legacy (pre-anchor) channel using only `option_static_remotekey`.
449+ ///
450+ /// These channels do not use anchor outputs and therefore do not require an on-chain reserve
451+ /// for fee bumping. Commitment transaction fees are pre-committed at channel open time.
452+ Legacy ,
453+ }
454+
414455/// Details of a channel as returned by [`Node::list_channels`].
415456///
416457/// When a channel is spliced, most fields continue to refer to the original pre-splice channel
@@ -571,10 +612,32 @@ pub struct ChannelDetails {
571612 pub inbound_htlc_maximum_msat : Option < u64 > ,
572613 /// Set of configurable parameters that affect channel operation.
573614 pub config : ChannelConfig ,
615+ /// The type of on-chain reserve maintained for this channel.
616+ ///
617+ /// See [`ReserveType`] for details on how reserves differ between anchor and legacy channels.
618+ pub reserve_type : ReserveType ,
574619}
575620
576- impl From < LdkChannelDetails > for ChannelDetails {
577- fn from ( value : LdkChannelDetails ) -> Self {
621+ impl ChannelDetails {
622+ pub ( crate ) fn from_ldk (
623+ value : LdkChannelDetails , anchor_channels_config : Option < & AnchorChannelsConfig > ,
624+ ) -> Self {
625+ let reserve_type =
626+ if value. channel_type . as_ref ( ) . is_some_and ( |ct| ct. supports_anchors_zero_fee_htlc_tx ( ) )
627+ {
628+ if let Some ( config) = anchor_channels_config {
629+ if config. trusted_peers_no_reserve . contains ( & value. counterparty . node_id ) {
630+ ReserveType :: TrustedPeersNoReserve
631+ } else {
632+ ReserveType :: Adaptive
633+ }
634+ } else {
635+ ReserveType :: Adaptive
636+ }
637+ } else {
638+ ReserveType :: Legacy
639+ } ;
640+
578641 ChannelDetails {
579642 channel_id : value. channel_id ,
580643 counterparty : ChannelCounterparty {
@@ -615,6 +678,7 @@ impl From<LdkChannelDetails> for ChannelDetails {
615678 inbound_htlc_maximum_msat : value. inbound_htlc_maximum_msat ,
616679 // unwrap safety: `config` is only `None` for LDK objects serialized prior to 0.0.109.
617680 config : value. config . map ( |c| c. into ( ) ) . unwrap ( ) ,
681+ reserve_type,
618682 }
619683 }
620684}
0 commit comments