@@ -4,6 +4,7 @@ use crate::Error;
4
4
5
5
use lightning:: chain:: chaininterface:: { BroadcasterInterface , ConfirmationTarget , FeeEstimator } ;
6
6
7
+ use lightning:: events:: bump_transaction:: { Utxo , WalletSource } ;
7
8
use lightning:: ln:: msgs:: { DecodeError , UnsignedGossipMessage } ;
8
9
use lightning:: ln:: script:: ShutdownScript ;
9
10
use lightning:: sign:: {
@@ -19,8 +20,14 @@ use bdk::wallet::AddressIndex;
19
20
use bdk:: FeeRate ;
20
21
use bdk:: { SignOptions , SyncOptions } ;
21
22
23
+ use bitcoin:: address:: { Payload , WitnessVersion } ;
22
24
use bitcoin:: bech32:: u5;
25
+ use bitcoin:: blockdata:: constants:: WITNESS_SCALE_FACTOR ;
23
26
use bitcoin:: blockdata:: locktime:: absolute:: LockTime ;
27
+ use bitcoin:: hash_types:: WPubkeyHash ;
28
+ use bitcoin:: hashes:: Hash ;
29
+ use bitcoin:: key:: XOnlyPublicKey ;
30
+ use bitcoin:: psbt:: PartiallySignedTransaction ;
24
31
use bitcoin:: secp256k1:: ecdh:: SharedSecret ;
25
32
use bitcoin:: secp256k1:: ecdsa:: { RecoverableSignature , Signature } ;
26
33
use bitcoin:: secp256k1:: { PublicKey , Scalar , Secp256k1 , SecretKey , Signing } ;
@@ -242,6 +249,123 @@ where
242
249
}
243
250
}
244
251
252
+ impl < D , B : Deref , E : Deref , L : Deref > WalletSource for Wallet < D , B , E , L >
253
+ where
254
+ D : BatchDatabase ,
255
+ B :: Target : BroadcasterInterface ,
256
+ E :: Target : FeeEstimator ,
257
+ L :: Target : Logger ,
258
+ {
259
+ fn list_confirmed_utxos ( & self ) -> Result < Vec < Utxo > , ( ) > {
260
+ let locked_wallet = self . inner . lock ( ) . unwrap ( ) ;
261
+ let mut utxos = Vec :: new ( ) ;
262
+ let confirmed_txs: Vec < bdk:: TransactionDetails > = locked_wallet
263
+ . list_transactions ( false )
264
+ . map_err ( |e| {
265
+ log_error ! ( self . logger, "Failed to retrieve transactions from wallet: {}" , e) ;
266
+ } ) ?
267
+ . into_iter ( )
268
+ . filter ( |t| t. confirmation_time . is_some ( ) )
269
+ . collect ( ) ;
270
+ let unspent_confirmed_utxos = locked_wallet
271
+ . list_unspent ( )
272
+ . map_err ( |e| {
273
+ log_error ! (
274
+ self . logger,
275
+ "Failed to retrieve unspent transactions from wallet: {}" ,
276
+ e
277
+ ) ;
278
+ } ) ?
279
+ . into_iter ( )
280
+ . filter ( |u| confirmed_txs. iter ( ) . find ( |t| t. txid == u. outpoint . txid ) . is_some ( ) ) ;
281
+
282
+ for u in unspent_confirmed_utxos {
283
+ let payload = Payload :: from_script ( & u. txout . script_pubkey ) . map_err ( |e| {
284
+ log_error ! ( self . logger, "Failed to retrieve script payload: {}" , e) ;
285
+ } ) ?;
286
+
287
+ match payload {
288
+ Payload :: WitnessProgram ( program) => match program. version ( ) {
289
+ WitnessVersion :: V0 if program. program ( ) . len ( ) == 20 => {
290
+ let wpkh =
291
+ WPubkeyHash :: from_slice ( program. program ( ) . as_bytes ( ) ) . map_err ( |e| {
292
+ log_error ! ( self . logger, "Failed to retrieve script payload: {}" , e) ;
293
+ } ) ?;
294
+ let utxo = Utxo :: new_v0_p2wpkh ( u. outpoint , u. txout . value , & wpkh) ;
295
+ utxos. push ( utxo) ;
296
+ } ,
297
+ WitnessVersion :: V1 => {
298
+ XOnlyPublicKey :: from_slice ( program. program ( ) . as_bytes ( ) ) . map_err ( |e| {
299
+ log_error ! ( self . logger, "Failed to retrieve script payload: {}" , e) ;
300
+ } ) ?;
301
+
302
+ let utxo = Utxo {
303
+ outpoint : u. outpoint ,
304
+ output : TxOut {
305
+ value : u. txout . value ,
306
+ script_pubkey : ScriptBuf :: new_witness_program ( & program) ,
307
+ } ,
308
+ satisfaction_weight : 1 /* empty script_sig */ * WITNESS_SCALE_FACTOR as u64 +
309
+ 1 /* witness items */ + 1 /* schnorr sig len */ + 64 , /* schnorr sig */
310
+ } ;
311
+ utxos. push ( utxo) ;
312
+ } ,
313
+ _ => {
314
+ log_error ! (
315
+ self . logger,
316
+ "Unexpected witness version or length. Version: {}, Length: {}" ,
317
+ program. version( ) ,
318
+ program. program( ) . len( )
319
+ ) ;
320
+ } ,
321
+ } ,
322
+ _ => {
323
+ log_error ! (
324
+ self . logger,
325
+ "Tried to use a non-witness script. This must never happen."
326
+ ) ;
327
+ panic ! ( "Tried to use a non-witness script. This must never happen." ) ;
328
+ } ,
329
+ }
330
+ }
331
+
332
+ Ok ( utxos)
333
+ }
334
+
335
+ fn get_change_script ( & self ) -> Result < ScriptBuf , ( ) > {
336
+ let locked_wallet = self . inner . lock ( ) . unwrap ( ) ;
337
+ let address_info = locked_wallet. get_address ( AddressIndex :: LastUnused ) . map_err ( |e| {
338
+ log_error ! ( self . logger, "Failed to retrieve new address from wallet: {}" , e) ;
339
+ } ) ?;
340
+
341
+ Ok ( address_info. address . script_pubkey ( ) )
342
+ }
343
+
344
+ fn sign_psbt ( & self , mut psbt : PartiallySignedTransaction ) -> Result < Transaction , ( ) > {
345
+ let locked_wallet = self . inner . lock ( ) . unwrap ( ) ;
346
+
347
+ // While BDK populates both `witness_utxo` and `non_witness_utxo` fields, LDK does not. As
348
+ // BDK by default doesn't trust the witness UTXO to account for the Segwit bug, we must
349
+ // disable it here as otherwise we fail to sign.
350
+ let mut sign_options = SignOptions :: default ( ) ;
351
+ sign_options. trust_witness_utxo = true ;
352
+
353
+ match locked_wallet. sign ( & mut psbt, sign_options) {
354
+ Ok ( _finalized) => {
355
+ // BDK will fail to finalize for all LDK-provided inputs of the PSBT. Unfortunately
356
+ // we can't check more fine grained if it succeeded for all the other inputs here,
357
+ // so we just ignore the returned `finalized` bool.
358
+ } ,
359
+ Err ( err) => {
360
+ log_error ! ( self . logger, "Failed to sign transaction: {}" , err) ;
361
+ return Err ( ( ) ) ;
362
+ } ,
363
+ }
364
+
365
+ Ok ( psbt. extract_tx ( ) )
366
+ }
367
+ }
368
+
245
369
/// Similar to [`KeysManager`], but overrides the destination and shutdown scripts so they are
246
370
/// directly spendable by the BDK wallet.
247
371
pub struct WalletKeysManager < D , B : Deref , E : Deref , L : Deref >
@@ -407,11 +531,10 @@ where
407
531
} ) ?;
408
532
409
533
match address. payload {
410
- bitcoin :: address :: Payload :: WitnessProgram ( program) => {
411
- ShutdownScript :: new_witness_program ( & program ) . map_err ( |e| {
534
+ Payload :: WitnessProgram ( program) => ShutdownScript :: new_witness_program ( & program )
535
+ . map_err ( |e| {
412
536
log_error ! ( self . logger, "Invalid shutdown script: {:?}" , e) ;
413
- } )
414
- } ,
537
+ } ) ,
415
538
_ => {
416
539
log_error ! (
417
540
self . logger,
0 commit comments