@@ -11,6 +11,7 @@ use std::str::FromStr;
1111use std:: sync:: { Arc , Mutex } ;
1212
1313use bdk_chain:: spk_client:: { FullScanRequest , SyncRequest } ;
14+ use bdk_wallet:: descriptor:: ExtendedDescriptor ;
1415use bdk_wallet:: event:: WalletEvent ;
1516#[ allow( deprecated) ]
1617use bdk_wallet:: SignOptions ;
@@ -20,20 +21,23 @@ use bitcoin::blockdata::constants::WITNESS_SCALE_FACTOR;
2021use bitcoin:: blockdata:: locktime:: absolute:: LockTime ;
2122use bitcoin:: hashes:: Hash ;
2223use bitcoin:: key:: XOnlyPublicKey ;
23- use bitcoin:: psbt:: Psbt ;
24+ use bitcoin:: psbt:: { self , Psbt } ;
2425use bitcoin:: secp256k1:: ecdh:: SharedSecret ;
2526use bitcoin:: secp256k1:: ecdsa:: { RecoverableSignature , Signature } ;
2627use bitcoin:: secp256k1:: { All , PublicKey , Scalar , Secp256k1 , SecretKey } ;
2728use bitcoin:: transaction:: Sequence ;
2829use bitcoin:: {
29- Address , Amount , FeeRate , OutPoint , ScriptBuf , Transaction , TxOut , Txid , WPubkeyHash ,
30+ Address , Amount , FeeRate , OutPoint , ScriptBuf , Transaction , TxOut , Txid , WPubkeyHash , Weight ,
3031 WitnessProgram , WitnessVersion ,
3132} ;
3233use lightning:: chain:: chaininterface:: BroadcasterInterface ;
3334use lightning:: chain:: channelmonitor:: ANTI_REORG_DELAY ;
34- use lightning:: chain:: { BestBlock , Listen } ;
35- use lightning:: events:: bump_transaction:: { Utxo , WalletSource } ;
35+ use lightning:: chain:: { BestBlock , ClaimId , Listen } ;
36+ use lightning:: events:: bump_transaction:: {
37+ CoinSelection , CoinSelectionSource , Input , Utxo , WalletSource ,
38+ } ;
3639use lightning:: ln:: channelmanager:: PaymentId ;
40+ use lightning:: ln:: funding:: FundingTxInput ;
3741use lightning:: ln:: inbound_payment:: ExpandedKey ;
3842use lightning:: ln:: msgs:: UnsignedGossipMessage ;
3943use lightning:: ln:: script:: ShutdownScript ;
@@ -444,16 +448,6 @@ impl Wallet {
444448 Ok ( ( ) )
445449 }
446450
447- pub ( crate ) fn persist ( & self ) -> Result < ( ) , Error > {
448- let mut locked_wallet = self . inner . lock ( ) . unwrap ( ) ;
449- let mut locked_persister = self . persister . lock ( ) . unwrap ( ) ;
450- locked_wallet. persist ( & mut locked_persister) . map_err ( |e| {
451- log_error ! ( self . logger, "Failed to persist wallet: {}" , e) ;
452- Error :: PersistenceFailed
453- } ) ?;
454- Ok ( ( ) )
455- }
456-
457451 pub ( crate ) fn get_balances (
458452 & self , total_anchor_channels_reserve_sats : u64 ,
459453 ) -> Result < ( u64 , u64 ) , Error > {
@@ -717,6 +711,82 @@ impl Wallet {
717711 Ok ( txid)
718712 }
719713
714+ pub ( crate ) fn select_confirmed_utxos (
715+ & self , must_spend : Vec < Input > , must_pay_to : & [ TxOut ] , fee_rate : FeeRate ,
716+ ) -> Result < CoinSelection , ( ) > {
717+ let mut locked_wallet = self . inner . lock ( ) . unwrap ( ) ;
718+ let mut locked_persister = self . persister . lock ( ) . unwrap ( ) ;
719+
720+ debug_assert ! ( matches!(
721+ locked_wallet. public_descriptor( KeychainKind :: External ) ,
722+ ExtendedDescriptor :: Wpkh ( _)
723+ ) ) ;
724+ debug_assert ! ( matches!(
725+ locked_wallet. public_descriptor( KeychainKind :: Internal ) ,
726+ ExtendedDescriptor :: Wpkh ( _)
727+ ) ) ;
728+
729+ let mut tx_builder = locked_wallet. build_tx ( ) ;
730+ tx_builder. only_witness_utxo ( ) ;
731+
732+ for input in & must_spend {
733+ let psbt_input = psbt:: Input {
734+ witness_utxo : Some ( input. previous_utxo . clone ( ) ) ,
735+ ..Default :: default ( )
736+ } ;
737+ let weight = Weight :: from_wu ( input. satisfaction_weight ) ;
738+ tx_builder. add_foreign_utxo ( input. outpoint , psbt_input, weight) . map_err ( |_| ( ) ) ?;
739+ }
740+
741+ for output in must_pay_to {
742+ tx_builder. add_recipient ( output. script_pubkey . clone ( ) , output. value ) ;
743+ }
744+
745+ tx_builder. fee_rate ( fee_rate) ;
746+ tx_builder. exclude_unconfirmed ( ) ;
747+
748+ let unsigned_tx = tx_builder
749+ . finish ( )
750+ . map_err ( |e| {
751+ log_error ! ( self . logger, "Failed to select confirmed UTXOs: {}" , e) ;
752+ } ) ?
753+ . unsigned_tx ;
754+
755+ let confirmed_utxos = unsigned_tx
756+ . input
757+ . iter ( )
758+ . filter ( |txin| must_spend. iter ( ) . all ( |input| input. outpoint != txin. previous_output ) )
759+ . filter_map ( |txin| {
760+ locked_wallet
761+ . tx_details ( txin. previous_output . txid )
762+ . map ( |tx_details| tx_details. tx . deref ( ) . clone ( ) )
763+ . map ( |prevtx| FundingTxInput :: new_p2wpkh ( prevtx, txin. previous_output . vout ) )
764+ } )
765+ . collect :: < Result < Vec < _ > , ( ) > > ( ) ?;
766+
767+ if unsigned_tx. output . len ( ) > must_pay_to. len ( ) + 1 {
768+ log_error ! (
769+ self . logger,
770+ "Unexpected number of change outputs during coin selection: {}" ,
771+ unsigned_tx. output. len( ) - must_pay_to. len( ) ,
772+ ) ;
773+ return Err ( ( ) ) ;
774+ }
775+
776+ let change_output = unsigned_tx
777+ . output
778+ . into_iter ( )
779+ . filter ( |txout| must_pay_to. iter ( ) . all ( |output| output != txout) )
780+ . next ( ) ;
781+
782+ locked_wallet. persist ( & mut locked_persister) . map_err ( |e| {
783+ log_error ! ( self . logger, "Failed to persist wallet: {}" , e) ;
784+ ( )
785+ } ) ?;
786+
787+ Ok ( CoinSelection { confirmed_utxos, change_output } )
788+ }
789+
720790 fn list_confirmed_utxos_inner ( & self ) -> Result < Vec < Utxo > , ( ) > {
721791 let locked_wallet = self . inner . lock ( ) . unwrap ( ) ;
722792 let mut utxos = Vec :: new ( ) ;
@@ -1079,6 +1149,26 @@ impl WalletSource for Wallet {
10791149 }
10801150}
10811151
1152+ // Anchor bumping uses LdkWallet for coin selection, which wraps a WalletSource to implement
1153+ // CoinSelectionSource. Splicing uses this implementation of coin selection instead.
1154+ impl CoinSelectionSource for Wallet {
1155+ fn select_confirmed_utxos < ' a > (
1156+ & ' a self , claim_id : Option < ClaimId > , must_spend : Vec < Input > , must_pay_to : & ' a [ TxOut ] ,
1157+ target_feerate_sat_per_1000_weight : u32 , _max_tx_weight : u64 ,
1158+ ) -> impl Future < Output = Result < CoinSelection , ( ) > > + Send + ' a {
1159+ debug_assert ! ( claim_id. is_none( ) ) ;
1160+ let fee_rate = FeeRate :: from_sat_per_kwu ( target_feerate_sat_per_1000_weight as u64 ) ;
1161+ async move { self . select_confirmed_utxos ( must_spend, must_pay_to, fee_rate) }
1162+ }
1163+
1164+ fn sign_psbt < ' a > (
1165+ & ' a self , psbt : Psbt ,
1166+ ) -> impl Future < Output = Result < Transaction , ( ) > > + Send + ' a {
1167+ debug_assert ! ( false ) ;
1168+ async move { self . sign_psbt_inner ( psbt) }
1169+ }
1170+ }
1171+
10821172/// Similar to [`KeysManager`], but overrides the destination and shutdown scripts so they are
10831173/// directly spendable by the BDK wallet.
10841174pub ( crate ) struct WalletKeysManager {
0 commit comments