@@ -109,6 +109,7 @@ use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
109109
110110pub use balance:: { BalanceDetails , LightningBalance , PendingSweepBalance } ;
111111use bitcoin:: secp256k1:: PublicKey ;
112+ use bitcoin:: Amount ;
112113#[ cfg( feature = "uniffi" ) ]
113114pub use builder:: ArcedNodeBuilder as Builder ;
114115pub use builder:: BuildError ;
@@ -124,17 +125,20 @@ pub use error::Error as NodeError;
124125use error:: Error ;
125126pub use event:: Event ;
126127use event:: { EventHandler , EventQueue } ;
128+ use fee_estimator:: { ConfirmationTarget , FeeEstimator , OnchainFeeEstimator } ;
127129#[ cfg( feature = "uniffi" ) ]
128130use ffi:: * ;
129131use gossip:: GossipSource ;
130132use graph:: NetworkGraph ;
131133pub use io:: utils:: generate_entropy_mnemonic;
132134use io:: utils:: write_node_metrics;
133135use lightning:: chain:: BestBlock ;
134- use lightning:: events:: bump_transaction:: Wallet as LdkWallet ;
136+ use lightning:: events:: bump_transaction:: { Input , Wallet as LdkWallet } ;
135137use lightning:: impl_writeable_tlv_based;
138+ use lightning:: ln:: chan_utils:: { make_funding_redeemscript, FUNDING_TRANSACTION_WITNESS_WEIGHT } ;
136139use lightning:: ln:: channel_state:: ChannelShutdownState ;
137140use lightning:: ln:: channelmanager:: PaymentId ;
141+ use lightning:: ln:: funding:: SpliceContribution ;
138142use lightning:: ln:: msgs:: SocketAddress ;
139143use lightning:: routing:: gossip:: NodeAlias ;
140144use lightning:: util:: persist:: KVStoreSync ;
@@ -178,6 +182,7 @@ pub struct Node {
178182 wallet : Arc < Wallet > ,
179183 chain_source : Arc < ChainSource > ,
180184 tx_broadcaster : Arc < Broadcaster > ,
185+ fee_estimator : Arc < OnchainFeeEstimator > ,
181186 event_queue : Arc < EventQueue < Arc < Logger > > > ,
182187 channel_manager : Arc < ChannelManager > ,
183188 chain_monitor : Arc < ChainMonitor > ,
@@ -1223,6 +1228,106 @@ impl Node {
12231228 )
12241229 }
12251230
1231+ /// Add funds from the on-chain wallet into an existing channel.
1232+ ///
1233+ /// This provides for increasing a channel's outbound liquidity without re-balancing or closing
1234+ /// it. Once negotiation with the counterparty is complete, the channel remains operational
1235+ /// while waiting for a new funding transaction to confirm.
1236+ ///
1237+ /// # Experimental API
1238+ ///
1239+ /// This API is experimental. Currently, a splice-in will be marked as an outbound payment, but
1240+ /// this classification may change in the future.
1241+ pub fn splice_in (
1242+ & self , user_channel_id : & UserChannelId , counterparty_node_id : PublicKey ,
1243+ splice_amount_sats : u64 ,
1244+ ) -> Result < ( ) , Error > {
1245+ let open_channels =
1246+ self . channel_manager . list_channels_with_counterparty ( & counterparty_node_id) ;
1247+ if let Some ( channel_details) =
1248+ open_channels. iter ( ) . find ( |c| c. user_channel_id == user_channel_id. 0 )
1249+ {
1250+ self . check_sufficient_funds_for_channel ( splice_amount_sats, & counterparty_node_id) ?;
1251+
1252+ const EMPTY_SCRIPT_SIG_WEIGHT : u64 =
1253+ 1 /* empty script_sig */ * bitcoin:: constants:: WITNESS_SCALE_FACTOR as u64 ;
1254+ let funding_txo = channel_details. funding_txo . ok_or_else ( || {
1255+ log_error ! ( self . logger, "Failed to splice channel: channel not yet ready" , ) ;
1256+ Error :: ChannelSplicingFailed
1257+ } ) ?;
1258+ let shared_input = Input {
1259+ outpoint : funding_txo. into_bitcoin_outpoint ( ) ,
1260+ previous_utxo : bitcoin:: TxOut {
1261+ value : Amount :: from_sat ( channel_details. channel_value_satoshis ) ,
1262+ script_pubkey : make_funding_redeemscript (
1263+ & PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) ,
1264+ & PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) ,
1265+ )
1266+ . to_p2wsh ( ) ,
1267+ } ,
1268+ satisfaction_weight : EMPTY_SCRIPT_SIG_WEIGHT + FUNDING_TRANSACTION_WITNESS_WEIGHT ,
1269+ } ;
1270+
1271+ let shared_output = bitcoin:: TxOut {
1272+ value : shared_input. previous_utxo . value + Amount :: from_sat ( splice_amount_sats) ,
1273+ script_pubkey : make_funding_redeemscript (
1274+ & PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) ,
1275+ & PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) ,
1276+ )
1277+ . to_p2wsh ( ) ,
1278+ } ;
1279+
1280+ let fee_rate = self . fee_estimator . estimate_fee_rate ( ConfirmationTarget :: ChannelFunding ) ;
1281+
1282+ let inputs = self
1283+ . wallet
1284+ . select_confirmed_utxos ( vec ! [ shared_input] , & [ shared_output] , fee_rate)
1285+ . map_err ( |( ) | {
1286+ log_error ! (
1287+ self . logger,
1288+ "Failed to splice channel: insufficient confirmed UTXOs" ,
1289+ ) ;
1290+ Error :: ChannelSplicingFailed
1291+ } ) ?;
1292+
1293+ let contribution = SpliceContribution :: SpliceIn {
1294+ value : Amount :: from_sat ( splice_amount_sats) ,
1295+ inputs,
1296+ change_script : None ,
1297+ } ;
1298+
1299+ let funding_feerate_per_kw: u32 = match fee_rate. to_sat_per_kwu ( ) . try_into ( ) {
1300+ Ok ( fee_rate) => fee_rate,
1301+ Err ( _) => {
1302+ debug_assert ! ( false ) ;
1303+ fee_estimator:: get_fallback_rate_for_target ( ConfirmationTarget :: ChannelFunding )
1304+ } ,
1305+ } ;
1306+
1307+ self . channel_manager
1308+ . splice_channel (
1309+ & channel_details. channel_id ,
1310+ & counterparty_node_id,
1311+ contribution,
1312+ funding_feerate_per_kw,
1313+ None ,
1314+ )
1315+ . map_err ( |e| {
1316+ log_error ! ( self . logger, "Failed to splice channel: {:?}" , e) ;
1317+ Error :: ChannelSplicingFailed
1318+ } )
1319+ } else {
1320+ log_error ! (
1321+ self . logger,
1322+ "Channel not found for user_channel_id: {:?} and counterparty: {}" ,
1323+ user_channel_id,
1324+ counterparty_node_id
1325+ ) ;
1326+
1327+ Err ( Error :: ChannelSplicingFailed )
1328+ }
1329+ }
1330+
12261331 /// Manually sync the LDK and BDK wallets with the current chain state and update the fee rate
12271332 /// cache.
12281333 ///
0 commit comments