@@ -119,8 +119,6 @@ pub use bitcoin;
119119use bitcoin:: secp256k1:: PublicKey ;
120120#[ cfg( feature = "uniffi" ) ]
121121pub use bitcoin:: FeeRate ;
122- #[ cfg( not( feature = "uniffi" ) ) ]
123- use bitcoin:: FeeRate ;
124122use bitcoin:: { Address , Amount , BlockHash , Network } ;
125123#[ cfg( feature = "uniffi" ) ]
126124pub use builder:: ArcedNodeBuilder as Builder ;
@@ -138,7 +136,9 @@ pub use error::Error as NodeError;
138136use error:: Error ;
139137pub use event:: Event ;
140138use event:: { EventHandler , EventQueue } ;
141- use fee_estimator:: { ConfirmationTarget , FeeEstimator , OnchainFeeEstimator } ;
139+ use fee_estimator:: {
140+ max_funding_feerate, rbf_splice_feerates, ConfirmationTarget , FeeEstimator , OnchainFeeEstimator ,
141+ } ;
142142#[ cfg( feature = "uniffi" ) ]
143143use ffi:: * ;
144144use gossip:: GossipSource ;
@@ -1584,7 +1584,7 @@ impl Node {
15841584 {
15851585 let min_feerate =
15861586 self . fee_estimator . estimate_fee_rate ( ConfirmationTarget :: ChannelFunding ) ;
1587- let max_feerate = FeeRate :: from_sat_per_kwu ( min_feerate. to_sat_per_kwu ( ) * 3 / 2 ) ;
1587+ let max_feerate = max_funding_feerate ( min_feerate) ;
15881588
15891589 let splice_amount_sats = match splice_amount_sats {
15901590 FundingAmount :: Exact { amount_sats } => amount_sats,
@@ -1653,16 +1653,26 @@ impl Node {
16531653 if funding_template. prior_contribution ( ) . is_some ( ) {
16541654 log_error ! (
16551655 self . logger,
1656- "Failed to splice channel: a prior splice contribution is pending"
1656+ "Failed to splice channel: a prior splice contribution is pending; use bump_channel_funding_fee to bump its fee "
16571657 ) ;
16581658 return Err ( Error :: ChannelSplicingFailed ) ;
16591659 }
16601660
1661+ // When contributing to a pending splice, the funding template requires at least the RBF
1662+ // minimum feerate to replace the in-flight transaction. Use it in place of our funding
1663+ // feerate estimate when it's higher, as long as it stays within our max.
1664+ let feerate = match funding_template. min_rbf_feerate ( ) {
1665+ Some ( min_rbf_feerate) if min_rbf_feerate <= max_feerate => {
1666+ min_feerate. max ( min_rbf_feerate)
1667+ } ,
1668+ _ => min_feerate,
1669+ } ;
1670+
16611671 let contribution = self
16621672 . runtime
16631673 . block_on ( funding_template. splice_in (
16641674 Amount :: from_sat ( splice_amount_sats) ,
1665- min_feerate ,
1675+ feerate ,
16661676 max_feerate,
16671677 Arc :: clone ( & self . wallet ) ,
16681678 ) )
@@ -1763,7 +1773,7 @@ impl Node {
17631773
17641774 let min_feerate =
17651775 self . fee_estimator . estimate_fee_rate ( ConfirmationTarget :: ChannelFunding ) ;
1766- let max_feerate = FeeRate :: from_sat_per_kwu ( min_feerate. to_sat_per_kwu ( ) * 3 / 2 ) ;
1776+ let max_feerate = max_funding_feerate ( min_feerate) ;
17671777
17681778 let funding_template = self
17691779 . channel_manager
@@ -1776,17 +1786,27 @@ impl Node {
17761786 if funding_template. prior_contribution ( ) . is_some ( ) {
17771787 log_error ! (
17781788 self . logger,
1779- "Failed to splice channel: a prior splice contribution is pending"
1789+ "Failed to splice channel: a prior splice contribution is pending; use bump_channel_funding_fee to bump its fee "
17801790 ) ;
17811791 return Err ( Error :: ChannelSplicingFailed ) ;
17821792 }
17831793
1794+ // When contributing to a pending splice, the funding template requires at least the RBF
1795+ // minimum feerate to replace the in-flight transaction. Use it in place of our funding
1796+ // feerate estimate when it's higher, as long as it stays within our max.
1797+ let feerate = match funding_template. min_rbf_feerate ( ) {
1798+ Some ( min_rbf_feerate) if min_rbf_feerate <= max_feerate => {
1799+ min_feerate. max ( min_rbf_feerate)
1800+ } ,
1801+ _ => min_feerate,
1802+ } ;
1803+
17841804 let outputs = vec ! [ bitcoin:: TxOut {
17851805 value: Amount :: from_sat( splice_amount_sats) ,
17861806 script_pubkey: address. script_pubkey( ) ,
17871807 } ] ;
17881808 let contribution =
1789- funding_template. splice_out ( outputs, min_feerate , max_feerate) . map_err ( |e| {
1809+ funding_template. splice_out ( outputs, feerate , max_feerate) . map_err ( |e| {
17901810 log_error ! ( self . logger, "Failed to splice channel: {}" , e) ;
17911811 Error :: ChannelSplicingFailed
17921812 } ) ?;
@@ -1813,6 +1833,77 @@ impl Node {
18131833 }
18141834 }
18151835
1836+ /// Fee-bumps the pending splice on a channel by replacing its in-flight funding transaction
1837+ /// (RBF). The splice's amount and destination are preserved; only the fee rate is raised.
1838+ /// Errors if the channel has no pending splice to bump.
1839+ pub fn bump_channel_funding_fee (
1840+ & self , user_channel_id : & UserChannelId , counterparty_node_id : PublicKey ,
1841+ ) -> Result < ( ) , Error > {
1842+ let open_channels =
1843+ self . channel_manager . list_channels_with_counterparty ( & counterparty_node_id) ;
1844+ if let Some ( channel_details) =
1845+ open_channels. iter ( ) . find ( |c| c. user_channel_id == user_channel_id. 0 )
1846+ {
1847+ let min_feerate =
1848+ self . fee_estimator . estimate_fee_rate ( ConfirmationTarget :: ChannelFunding ) ;
1849+
1850+ let funding_template = self
1851+ . channel_manager
1852+ . splice_channel ( & channel_details. channel_id , & counterparty_node_id)
1853+ . map_err ( |e| {
1854+ log_error ! ( self . logger, "Failed to RBF channel: {:?}" , e) ;
1855+ Error :: ChannelSplicingFailed
1856+ } ) ?;
1857+
1858+ let Some ( min_rbf_feerate) = funding_template. min_rbf_feerate ( ) else {
1859+ log_error ! ( self . logger, "Failed to RBF channel: no pending splice to replace" ) ;
1860+ return Err ( Error :: ChannelSplicingFailed ) ;
1861+ } ;
1862+
1863+ let Some ( ( target_feerate, max_feerate) ) =
1864+ rbf_splice_feerates ( min_feerate, min_rbf_feerate)
1865+ else {
1866+ log_error ! (
1867+ self . logger,
1868+ "Failed to RBF channel: the RBF minimum feerate exceeds our maximum"
1869+ ) ;
1870+ return Err ( Error :: ChannelSplicingFailed ) ;
1871+ } ;
1872+
1873+ let contribution = self
1874+ . runtime
1875+ . block_on ( funding_template. rbf_prior_contribution (
1876+ Some ( target_feerate) ,
1877+ max_feerate,
1878+ Arc :: clone ( & self . wallet ) ,
1879+ ) )
1880+ . map_err ( |e| {
1881+ log_error ! ( self . logger, "Failed to RBF channel: {}" , e) ;
1882+ Error :: ChannelSplicingFailed
1883+ } ) ?;
1884+
1885+ self . channel_manager
1886+ . funding_contributed (
1887+ & channel_details. channel_id ,
1888+ & counterparty_node_id,
1889+ contribution,
1890+ None ,
1891+ )
1892+ . map_err ( |e| {
1893+ log_error ! ( self . logger, "Failed to RBF channel: {:?}" , e) ;
1894+ Error :: ChannelSplicingFailed
1895+ } )
1896+ } else {
1897+ log_error ! (
1898+ self . logger,
1899+ "Channel not found for user_channel_id {} and counterparty {}" ,
1900+ user_channel_id,
1901+ counterparty_node_id
1902+ ) ;
1903+ Err ( Error :: ChannelSplicingFailed )
1904+ }
1905+ }
1906+
18161907 /// Manually sync the LDK and BDK wallets with the current chain state and update the fee rate
18171908 /// cache.
18181909 ///
0 commit comments