@@ -35,6 +35,7 @@ use bitcoin::{OutPoint, PubkeyHash, Sequence, ScriptBuf, Transaction, TxIn, TxOu
35
35
use bitcoin:: blockdata:: constants:: WITNESS_SCALE_FACTOR ;
36
36
use bitcoin:: blockdata:: locktime:: absolute:: LockTime ;
37
37
use bitcoin:: consensus:: Encodable ;
38
+ use bitcoin:: psbt:: PartiallySignedTransaction ;
38
39
use bitcoin:: secp256k1;
39
40
use bitcoin:: secp256k1:: Secp256k1 ;
40
41
use bitcoin:: secp256k1:: ecdsa:: Signature ;
@@ -343,7 +344,10 @@ pub trait CoinSelectionSource {
343
344
) -> Result < CoinSelection , ( ) > ;
344
345
/// Signs and provides the full witness for all inputs within the transaction known to the
345
346
/// trait (i.e., any provided via [`CoinSelectionSource::select_confirmed_utxos`]).
346
- fn sign_tx ( & self , tx : Transaction ) -> Result < Transaction , ( ) > ;
347
+ ///
348
+ /// If your wallet does not support signing PSBTs you can call `psbt.extract_tx()` to get the
349
+ /// unsigned transaction and then sign it with your wallet.
350
+ fn sign_psbt ( & self , tx : PartiallySignedTransaction ) -> Result < Transaction , ( ) > ;
347
351
}
348
352
349
353
/// An alternative to [`CoinSelectionSource`] that can be implemented and used along [`Wallet`] to
@@ -357,7 +361,10 @@ pub trait WalletSource {
357
361
/// Signs and provides the full [`TxIn::script_sig`] and [`TxIn::witness`] for all inputs within
358
362
/// the transaction known to the wallet (i.e., any provided via
359
363
/// [`WalletSource::list_confirmed_utxos`]).
360
- fn sign_tx ( & self , tx : Transaction ) -> Result < Transaction , ( ) > ;
364
+ ///
365
+ /// If your wallet does not support signing PSBTs you can call `psbt.extract_tx()` to get the
366
+ /// unsigned transaction and then sign it with your wallet.
367
+ fn sign_psbt ( & self , psbt : PartiallySignedTransaction ) -> Result < Transaction , ( ) > ;
361
368
}
362
369
363
370
/// A wrapper over [`WalletSource`] that implements [`CoinSelection`] by preferring UTXOs that would
@@ -504,8 +511,8 @@ where
504
511
. or_else ( |_| do_coin_selection ( true , true ) )
505
512
}
506
513
507
- fn sign_tx ( & self , tx : Transaction ) -> Result < Transaction , ( ) > {
508
- self . source . sign_tx ( tx )
514
+ fn sign_psbt ( & self , psbt : PartiallySignedTransaction ) -> Result < Transaction , ( ) > {
515
+ self . source . sign_psbt ( psbt )
509
516
}
510
517
}
511
518
@@ -549,16 +556,16 @@ where
549
556
}
550
557
551
558
/// Updates a transaction with the result of a successful coin selection attempt.
552
- fn process_coin_selection ( & self , tx : & mut Transaction , mut coin_selection : CoinSelection ) {
553
- for utxo in coin_selection. confirmed_utxos . drain ( .. ) {
559
+ fn process_coin_selection ( & self , tx : & mut Transaction , coin_selection : & CoinSelection ) {
560
+ for utxo in coin_selection. confirmed_utxos . iter ( ) {
554
561
tx. input . push ( TxIn {
555
562
previous_output : utxo. outpoint ,
556
563
script_sig : ScriptBuf :: new ( ) ,
557
564
sequence : Sequence :: ZERO ,
558
565
witness : Witness :: new ( ) ,
559
566
} ) ;
560
567
}
561
- if let Some ( change_output) = coin_selection. change_output . take ( ) {
568
+ if let Some ( change_output) = coin_selection. change_output . clone ( ) {
562
569
tx. output . push ( change_output) ;
563
570
} else if tx. output . is_empty ( ) {
564
571
// We weren't provided a change output, likely because the input set was a perfect
@@ -613,15 +620,28 @@ where
613
620
let total_input_amount = must_spend_amount +
614
621
coin_selection. confirmed_utxos . iter ( ) . map ( |utxo| utxo. output . value ) . sum :: < u64 > ( ) ;
615
622
616
- self . process_coin_selection ( & mut anchor_tx, coin_selection) ;
623
+ self . process_coin_selection ( & mut anchor_tx, & coin_selection) ;
617
624
let anchor_txid = anchor_tx. txid ( ) ;
618
625
626
+ // construct psbt
627
+ let mut anchor_psbt = PartiallySignedTransaction :: from_unsigned_tx ( anchor_tx. clone ( ) ) . unwrap ( ) ;
628
+ // add witness_utxo to anchor input
629
+ anchor_psbt. inputs [ 0 ] . witness_utxo = Some ( anchor_descriptor. previous_utxo ( ) ) ;
630
+ // add witness_utxo to remaining inputs
631
+ for ( idx, utxo) in coin_selection. confirmed_utxos . into_iter ( ) . enumerate ( ) {
632
+ // add 1 to skip the anchor input
633
+ let index = idx + 1 ;
634
+ debug_assert_eq ! ( anchor_psbt. unsigned_tx. input[ index] . previous_output, utxo. outpoint) ;
635
+ anchor_psbt. inputs [ index] . witness_utxo = Some ( utxo. output ) ;
636
+ }
637
+
619
638
debug_assert_eq ! ( anchor_tx. output. len( ) , 1 ) ;
620
639
#[ cfg( debug_assertions) ]
621
640
let unsigned_tx_weight = anchor_tx. weight ( ) . to_wu ( ) - ( anchor_tx. input . len ( ) as u64 * EMPTY_SCRIPT_SIG_WEIGHT ) ;
622
641
623
642
log_debug ! ( self . logger, "Signing anchor transaction {}" , anchor_txid) ;
624
- anchor_tx = self . utxo_source . sign_tx ( anchor_tx) ?;
643
+ debug_assert ! ( anchor_psbt. inputs. iter( ) . all( |i| i. witness_utxo. is_some( ) ) ) ;
644
+ anchor_tx = self . utxo_source . sign_psbt ( anchor_psbt) ?;
625
645
626
646
let signer = anchor_descriptor. derive_channel_signer ( & self . signer_provider ) ;
627
647
let anchor_sig = signer. sign_holder_anchor_input ( & anchor_tx, 0 , & self . secp ) ?;
@@ -701,13 +721,29 @@ where
701
721
let total_input_amount = must_spend_amount +
702
722
coin_selection. confirmed_utxos . iter ( ) . map ( |utxo| utxo. output . value ) . sum :: < u64 > ( ) ;
703
723
704
- self . process_coin_selection ( & mut htlc_tx, coin_selection) ;
724
+ self . process_coin_selection ( & mut htlc_tx, & coin_selection) ;
725
+
726
+ // construct psbt
727
+ let mut htlc_psbt = PartiallySignedTransaction :: from_unsigned_tx ( htlc_tx. clone ( ) ) . unwrap ( ) ;
728
+ // add witness_utxo to htlc inputs
729
+ for ( i, htlc_descriptor) in htlc_descriptors. iter ( ) . enumerate ( ) {
730
+ debug_assert_eq ! ( htlc_psbt. unsigned_tx. input[ i] . previous_output, htlc_descriptor. outpoint( ) ) ;
731
+ htlc_psbt. inputs [ i] . witness_utxo = Some ( htlc_descriptor. previous_utxo ( & self . secp ) ) ;
732
+ }
733
+ // add witness_utxo to remaining inputs
734
+ for ( idx, utxo) in coin_selection. confirmed_utxos . into_iter ( ) . enumerate ( ) {
735
+ // offset to skip the htlc inputs
736
+ let index = idx + htlc_descriptors. len ( ) ;
737
+ debug_assert_eq ! ( htlc_psbt. unsigned_tx. input[ index] . previous_output, utxo. outpoint) ;
738
+ htlc_psbt. inputs [ index] . witness_utxo = Some ( utxo. output ) ;
739
+ }
705
740
706
741
#[ cfg( debug_assertions) ]
707
742
let unsigned_tx_weight = htlc_tx. weight ( ) . to_wu ( ) - ( htlc_tx. input . len ( ) as u64 * EMPTY_SCRIPT_SIG_WEIGHT ) ;
708
743
709
744
log_debug ! ( self . logger, "Signing HTLC transaction {}" , htlc_tx. txid( ) ) ;
710
- htlc_tx = self . utxo_source . sign_tx ( htlc_tx) ?;
745
+ debug_assert ! ( htlc_psbt. inputs. iter( ) . all( |i| i. witness_utxo. is_some( ) ) ) ;
746
+ htlc_tx = self . utxo_source . sign_psbt ( htlc_psbt) ?;
711
747
712
748
let mut signers = BTreeMap :: new ( ) ;
713
749
for ( idx, htlc_descriptor) in htlc_descriptors. iter ( ) . enumerate ( ) {
0 commit comments