@@ -110,6 +110,7 @@ use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
110110use crate :: scoring:: setup_background_pathfinding_scores_sync;
111111pub use balance:: { BalanceDetails , LightningBalance , PendingSweepBalance } ;
112112use bitcoin:: secp256k1:: PublicKey ;
113+ use bitcoin:: Amount ;
113114#[ cfg( feature = "uniffi" ) ]
114115pub use builder:: ArcedNodeBuilder as Builder ;
115116pub use builder:: BuildError ;
@@ -132,10 +133,11 @@ use graph::NetworkGraph;
132133pub use io:: utils:: generate_entropy_mnemonic;
133134use io:: utils:: write_node_metrics;
134135use lightning:: chain:: BestBlock ;
135- use lightning:: events:: bump_transaction:: Wallet as LdkWallet ;
136+ use lightning:: events:: bump_transaction:: { Input , Wallet as LdkWallet } ;
136137use lightning:: impl_writeable_tlv_based;
137138use lightning:: ln:: channel_state:: ChannelShutdownState ;
138139use lightning:: ln:: channelmanager:: PaymentId ;
140+ use lightning:: ln:: funding:: SpliceContribution ;
139141use lightning:: ln:: msgs:: SocketAddress ;
140142use lightning:: routing:: gossip:: NodeAlias ;
141143use lightning:: util:: persist:: KVStoreSync ;
@@ -1223,6 +1225,96 @@ impl Node {
12231225 )
12241226 }
12251227
1228+ /// Add funds from the on-chain wallet into an existing channel.
1229+ ///
1230+ /// This provides for increasing a channel's outbound liquidity without re-balancing or closing
1231+ /// it. Once negotiation with the counterparty is complete, the channel remains operational
1232+ /// while waiting for a new funding transaction to confirm.
1233+ pub fn splice_in (
1234+ & self , user_channel_id : & UserChannelId , counterparty_node_id : PublicKey ,
1235+ splice_amount_sats : u64 ,
1236+ ) -> Result < ( ) , Error > {
1237+ let open_channels =
1238+ self . channel_manager . list_channels_with_counterparty ( & counterparty_node_id) ;
1239+ if let Some ( channel_details) =
1240+ open_channels. iter ( ) . find ( |c| c. user_channel_id == user_channel_id. 0 )
1241+ {
1242+ self . check_sufficient_funds_for_channel ( splice_amount_sats, & counterparty_node_id) ?;
1243+
1244+ const EMPTY_SCRIPT_SIG_WEIGHT : u64 =
1245+ 1 /* empty script_sig */ * bitcoin:: constants:: WITNESS_SCALE_FACTOR as u64 ;
1246+ let funding_txo = channel_details. funding_txo . ok_or_else ( || {
1247+ log_error ! ( self . logger, "Failed to splice channel: channel not yet ready" , ) ;
1248+ Error :: ChannelSplicingFailed
1249+ } ) ?;
1250+ let shared_input = Input {
1251+ outpoint : funding_txo. into_bitcoin_outpoint ( ) ,
1252+ previous_utxo : bitcoin:: TxOut {
1253+ value : Amount :: from_sat ( channel_details. channel_value_satoshis ) ,
1254+ script_pubkey : lightning:: ln:: chan_utils:: make_funding_redeemscript (
1255+ & PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) ,
1256+ & PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) ,
1257+ )
1258+ . to_p2wsh ( ) ,
1259+ } ,
1260+ satisfaction_weight : EMPTY_SCRIPT_SIG_WEIGHT
1261+ + lightning:: ln:: chan_utils:: FUNDING_TRANSACTION_WITNESS_WEIGHT ,
1262+ } ;
1263+
1264+ let shared_output = bitcoin:: TxOut {
1265+ value : shared_input. previous_utxo . value + Amount :: from_sat ( splice_amount_sats) ,
1266+ script_pubkey : lightning:: ln:: chan_utils:: make_funding_redeemscript (
1267+ & PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) ,
1268+ & PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) ,
1269+ )
1270+ . to_p2wsh ( ) ,
1271+ } ;
1272+
1273+ let fee_rate = self . wallet . estimate_channel_funding_fee_rate ( ) ;
1274+
1275+ let inputs = self
1276+ . wallet
1277+ . select_confirmed_utxos ( vec ! [ shared_input] , & [ shared_output] , fee_rate)
1278+ . map_err ( |( ) | {
1279+ log_error ! (
1280+ self . logger,
1281+ "Failed to splice channel: insufficient confirmed UTXOs" ,
1282+ ) ;
1283+ Error :: ChannelSplicingFailed
1284+ } ) ?;
1285+
1286+ let contribution = SpliceContribution :: SpliceIn {
1287+ value : Amount :: from_sat ( splice_amount_sats) ,
1288+ inputs,
1289+ change_script : None ,
1290+ } ;
1291+
1292+ let funding_feerate_per_kw = fee_rate. to_sat_per_kwu ( ) . try_into ( ) . unwrap_or ( u32:: MAX ) ;
1293+
1294+ self . channel_manager
1295+ . splice_channel (
1296+ & channel_details. channel_id ,
1297+ & counterparty_node_id,
1298+ contribution,
1299+ funding_feerate_per_kw,
1300+ None ,
1301+ )
1302+ . map_err ( |e| {
1303+ log_error ! ( self . logger, "Failed to splice channel: {:?}" , e) ;
1304+ Error :: ChannelSplicingFailed
1305+ } )
1306+ } else {
1307+ log_error ! (
1308+ self . logger,
1309+ "Channel not found for user_channel_id: {:?} and counterparty: {}" ,
1310+ user_channel_id,
1311+ counterparty_node_id
1312+ ) ;
1313+
1314+ Err ( Error :: ChannelSplicingFailed )
1315+ }
1316+ }
1317+
12261318 /// Manually sync the LDK and BDK wallets with the current chain state and update the fee rate
12271319 /// cache.
12281320 ///
0 commit comments