@@ -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:: { ChannelDetails as LdkChannelDetails , 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 ;
@@ -179,6 +183,7 @@ pub struct Node {
179183 wallet : Arc < Wallet > ,
180184 chain_source : Arc < ChainSource > ,
181185 tx_broadcaster : Arc < Broadcaster > ,
186+ fee_estimator : Arc < OnchainFeeEstimator > ,
182187 event_queue : Arc < EventQueue < Arc < Logger > > > ,
183188 channel_manager : Arc < ChannelManager > ,
184189 chain_monitor : Arc < ChainMonitor > ,
@@ -1236,6 +1241,120 @@ impl Node {
12361241 )
12371242 }
12381243
1244+ /// Add funds from the on-chain wallet into an existing channel.
1245+ ///
1246+ /// This provides for increasing a channel's outbound liquidity without re-balancing or closing
1247+ /// it. Once negotiation with the counterparty is complete, the channel remains operational
1248+ /// while waiting for a new funding transaction to confirm.
1249+ ///
1250+ /// # Experimental API
1251+ ///
1252+ /// This API is experimental. Currently, a splice-in will be marked as an outbound payment, but
1253+ /// this classification may change in the future.
1254+ pub fn splice_in (
1255+ & self , user_channel_id : & UserChannelId , counterparty_node_id : PublicKey ,
1256+ splice_amount_sats : u64 ,
1257+ ) -> Result < ( ) , Error > {
1258+ let open_channels =
1259+ self . channel_manager . list_channels_with_counterparty ( & counterparty_node_id) ;
1260+ if let Some ( channel_details) =
1261+ open_channels. iter ( ) . find ( |c| c. user_channel_id == user_channel_id. 0 )
1262+ {
1263+ self . check_sufficient_funds_for_channel ( splice_amount_sats, & counterparty_node_id) ?;
1264+
1265+ const EMPTY_SCRIPT_SIG_WEIGHT : u64 =
1266+ 1 /* empty script_sig */ * bitcoin:: constants:: WITNESS_SCALE_FACTOR as u64 ;
1267+
1268+ // Used for creating a redeem script for the previous funding txo and the new funding
1269+ // txo. Only needed when selecting which UTXOs to include in the funding tx that would
1270+ // be sufficient to pay for fees. Hence, the value does not matter.
1271+ let dummy_pubkey = PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) ;
1272+
1273+ let funding_txo = channel_details. funding_txo . ok_or_else ( || {
1274+ log_error ! ( self . logger, "Failed to splice channel: channel not yet ready" , ) ;
1275+ Error :: ChannelSplicingFailed
1276+ } ) ?;
1277+
1278+ let shared_input = Input {
1279+ outpoint : funding_txo. into_bitcoin_outpoint ( ) ,
1280+ previous_utxo : bitcoin:: TxOut {
1281+ value : Amount :: from_sat ( channel_details. channel_value_satoshis ) ,
1282+ script_pubkey : make_funding_redeemscript ( & dummy_pubkey, & dummy_pubkey)
1283+ . to_p2wsh ( ) ,
1284+ } ,
1285+ satisfaction_weight : EMPTY_SCRIPT_SIG_WEIGHT + FUNDING_TRANSACTION_WITNESS_WEIGHT ,
1286+ } ;
1287+
1288+ let shared_output = bitcoin:: TxOut {
1289+ value : shared_input. previous_utxo . value + Amount :: from_sat ( splice_amount_sats) ,
1290+ script_pubkey : make_funding_redeemscript ( & dummy_pubkey, & dummy_pubkey) . to_p2wsh ( ) ,
1291+ } ;
1292+
1293+ let fee_rate = self . fee_estimator . estimate_fee_rate ( ConfirmationTarget :: ChannelFunding ) ;
1294+
1295+ let inputs = self
1296+ . wallet
1297+ . select_confirmed_utxos ( vec ! [ shared_input] , & [ shared_output] , fee_rate)
1298+ . map_err ( |( ) | {
1299+ log_error ! (
1300+ self . logger,
1301+ "Failed to splice channel: insufficient confirmed UTXOs" ,
1302+ ) ;
1303+ Error :: ChannelSplicingFailed
1304+ } ) ?;
1305+
1306+ let change_address = self . wallet . get_new_internal_address ( ) ?;
1307+
1308+ let contribution = SpliceContribution :: SpliceIn {
1309+ value : Amount :: from_sat ( splice_amount_sats) ,
1310+ inputs,
1311+ change_script : Some ( change_address. script_pubkey ( ) ) ,
1312+ } ;
1313+
1314+ let funding_feerate_per_kw: u32 = match fee_rate. to_sat_per_kwu ( ) . try_into ( ) {
1315+ Ok ( fee_rate) => fee_rate,
1316+ Err ( _) => {
1317+ debug_assert ! ( false ) ;
1318+ fee_estimator:: get_fallback_rate_for_target ( ConfirmationTarget :: ChannelFunding )
1319+ } ,
1320+ } ;
1321+
1322+ self . channel_manager
1323+ . splice_channel (
1324+ & channel_details. channel_id ,
1325+ & counterparty_node_id,
1326+ contribution,
1327+ funding_feerate_per_kw,
1328+ None ,
1329+ )
1330+ . map_err ( |e| {
1331+ log_error ! ( self . logger, "Failed to splice channel: {:?}" , e) ;
1332+ let tx = bitcoin:: Transaction {
1333+ version : bitcoin:: transaction:: Version :: TWO ,
1334+ lock_time : bitcoin:: absolute:: LockTime :: ZERO ,
1335+ input : vec ! [ ] ,
1336+ output : vec ! [ bitcoin:: TxOut {
1337+ value: Amount :: ZERO ,
1338+ script_pubkey: change_address. script_pubkey( ) ,
1339+ } ] ,
1340+ } ;
1341+ match self . wallet . cancel_tx ( & tx) {
1342+ Ok ( ( ) ) => Error :: ChannelSplicingFailed ,
1343+ Err ( e) => e,
1344+ }
1345+ } )
1346+ } else {
1347+ log_error ! (
1348+ self . logger,
1349+ "Channel not found for user_channel_id {} and counterparty {}" ,
1350+ user_channel_id,
1351+ counterparty_node_id
1352+ ) ;
1353+
1354+ Err ( Error :: ChannelSplicingFailed )
1355+ }
1356+ }
1357+
12391358 /// Manually sync the LDK and BDK wallets with the current chain state and update the fee rate
12401359 /// cache.
12411360 ///
0 commit comments