@@ -10,7 +10,9 @@ import (
1010 "github.com/btcsuite/btcd/btcec/v2"
1111 "github.com/btcsuite/btcd/btcutil"
1212 "github.com/btcsuite/btcd/btcutil/psbt"
13+ "github.com/btcsuite/btcd/chaincfg"
1314 "github.com/btcsuite/btcd/chaincfg/chainhash"
15+ "github.com/btcsuite/btcd/txscript"
1416 "github.com/btcsuite/btcd/wire"
1517 "github.com/btcsuite/btcwallet/wtxmgr"
1618 "github.com/lightningnetwork/lnd/keychain"
@@ -69,6 +71,11 @@ type WalletKitClient interface {
6971 // query our wallet for the full set of transactions.
7072 ListSweeps (ctx context.Context ) ([]string , error )
7173
74+ // ListSweepsVerbose returns a list of sweep transactions known to our
75+ // node with verbose information about each sweep.
76+ ListSweepsVerbose (ctx context.Context ) ([]lnwallet.TransactionDetail ,
77+ error )
78+
7279 // BumpFee attempts to bump the fee of a transaction by spending one of
7380 // its outputs at the given fee rate. This essentially results in a
7481 // child-pays-for-parent (CPFP) scenario. If the given output has been
@@ -140,19 +147,22 @@ type walletKitClient struct {
140147 client walletrpc.WalletKitClient
141148 walletKitMac serializedMacaroon
142149 timeout time.Duration
150+ chainParams * chaincfg.Params
143151}
144152
145153// A compile-time constraint to ensure walletKitclient satisfies the
146154// WalletKitClient interface.
147155var _ WalletKitClient = (* walletKitClient )(nil )
148156
149157func newWalletKitClient (conn grpc.ClientConnInterface ,
150- walletKitMac serializedMacaroon , timeout time.Duration ) * walletKitClient {
158+ walletKitMac serializedMacaroon , timeout time.Duration ,
159+ chainParams * chaincfg.Params ) * walletKitClient {
151160
152161 return & walletKitClient {
153162 client : walletrpc .NewWalletKitClient (conn ),
154163 walletKitMac : walletKitMac ,
155164 timeout : timeout ,
165+ chainParams : chainParams ,
156166 }
157167}
158168
@@ -424,6 +434,155 @@ func (m *walletKitClient) ListSweeps(ctx context.Context) ([]string, error) {
424434 return sweeps .TransactionIds , nil
425435}
426436
437+ // unmarshallOutputType translates a lnrpc.OutputScriptType into a
438+ // txscript.ScriptClass.
439+ func unmarshallOutputType (o lnrpc.OutputScriptType ) txscript.ScriptClass {
440+ switch o {
441+ case lnrpc .OutputScriptType_SCRIPT_TYPE_SCRIPT_HASH :
442+ return txscript .ScriptHashTy
443+
444+ case lnrpc .OutputScriptType_SCRIPT_TYPE_WITNESS_V0_PUBKEY_HASH :
445+ return txscript .WitnessV0PubKeyHashTy
446+
447+ case lnrpc .OutputScriptType_SCRIPT_TYPE_WITNESS_V0_SCRIPT_HASH :
448+ return txscript .WitnessV0ScriptHashTy
449+
450+ case lnrpc .OutputScriptType_SCRIPT_TYPE_PUBKEY :
451+ return txscript .PubKeyTy
452+
453+ case lnrpc .OutputScriptType_SCRIPT_TYPE_MULTISIG :
454+ return txscript .MultiSigTy
455+
456+ case lnrpc .OutputScriptType_SCRIPT_TYPE_NULLDATA :
457+ return txscript .NullDataTy
458+
459+ case lnrpc .OutputScriptType_SCRIPT_TYPE_NON_STANDARD :
460+ return txscript .NonStandardTy
461+
462+ case lnrpc .OutputScriptType_SCRIPT_TYPE_WITNESS_UNKNOWN :
463+ return txscript .WitnessUnknownTy
464+
465+ case lnrpc .OutputScriptType_SCRIPT_TYPE_WITNESS_V1_TAPROOT :
466+ return txscript .WitnessV1TaprootTy
467+
468+ default :
469+ return txscript .NonStandardTy
470+ }
471+ }
472+
473+ // RPCTransaction returns a rpc transaction.
474+ func UnmarshalTransactionDetail (tx * lnrpc.Transaction ,
475+ chainParams * chaincfg.Params ) (* lnwallet.TransactionDetail , error ) {
476+
477+ var outputDetails []lnwallet.OutputDetail
478+ for _ , o := range tx .OutputDetails {
479+ address , err := btcutil .DecodeAddress (o .Address , chainParams )
480+ if err != nil {
481+ return nil , err
482+ }
483+
484+ pkScript , err := hex .DecodeString (o .PkScript )
485+ if err != nil {
486+ return nil , err
487+ }
488+
489+ outputDetails = append (outputDetails , lnwallet.OutputDetail {
490+ OutputType : unmarshallOutputType (o .OutputType ),
491+ Addresses : []btcutil.Address {address },
492+ PkScript : pkScript ,
493+ OutputIndex : int (o .OutputIndex ),
494+ Value : btcutil .Amount (o .Amount ),
495+ IsOurAddress : o .IsOurAddress ,
496+ })
497+ }
498+
499+ previousOutpoints := make (
500+ []lnwallet.PreviousOutPoint , len (tx .PreviousOutpoints ),
501+ )
502+ for idx , previousOutPoint := range tx .PreviousOutpoints {
503+ previousOutpoints [idx ] = lnwallet.PreviousOutPoint {
504+ OutPoint : previousOutPoint .Outpoint ,
505+ IsOurOutput : previousOutPoint .IsOurOutput ,
506+ }
507+ }
508+
509+ // We also get unconfirmed transactions, so BlockHash can be empty.
510+ var (
511+ blockHash * chainhash.Hash
512+ err error
513+ )
514+
515+ if tx .BlockHash != "" {
516+ blockHash , err = chainhash .NewHashFromStr (tx .BlockHash )
517+ if err != nil {
518+ return nil , err
519+ }
520+ }
521+
522+ txHash , err := chainhash .NewHashFromStr (tx .TxHash )
523+ if err != nil {
524+ return nil , err
525+ }
526+
527+ rawTx , err := hex .DecodeString (tx .RawTxHex )
528+ if err != nil {
529+ return nil , err
530+ }
531+
532+ return & lnwallet.TransactionDetail {
533+ Hash : * txHash ,
534+ Value : btcutil .Amount (tx .Amount ),
535+ NumConfirmations : tx .NumConfirmations ,
536+ BlockHash : blockHash ,
537+ BlockHeight : tx .BlockHeight ,
538+ Timestamp : tx .TimeStamp ,
539+ TotalFees : tx .TotalFees ,
540+ OutputDetails : outputDetails ,
541+ RawTx : rawTx ,
542+ Label : tx .Label ,
543+ PreviousOutpoints : previousOutpoints ,
544+ }, nil
545+ }
546+
547+ // ListSweepsVerbose returns a list of sweep transactions known to our node
548+ // with verbose information about each sweep.
549+ func (m * walletKitClient ) ListSweepsVerbose (ctx context.Context ) (
550+ []lnwallet.TransactionDetail , error ) {
551+
552+ rpcCtx , cancel := context .WithTimeout (ctx , m .timeout )
553+ defer cancel ()
554+
555+ resp , err := m .client .ListSweeps (
556+ m .walletKitMac .WithMacaroonAuth (rpcCtx ),
557+ & walletrpc.ListSweepsRequest {
558+ Verbose : true ,
559+ },
560+ )
561+ if err != nil {
562+ return nil , err
563+ }
564+
565+ // Since we have requested the verbose response from LND, we need to
566+ // unmarshal transaction details for each individual sweep.
567+ rpcDetails := resp .GetTransactionDetails ()
568+ if rpcDetails == nil {
569+ return nil , fmt .Errorf ("invalid transaction details" )
570+ }
571+
572+ var result []lnwallet.TransactionDetail
573+ for _ , txDetail := range rpcDetails .Transactions {
574+ tx , err := UnmarshalTransactionDetail (
575+ txDetail , m .chainParams ,
576+ )
577+ if err != nil {
578+ return nil , err
579+ }
580+ result = append (result , * tx )
581+ }
582+
583+ return result , nil
584+ }
585+
427586// BumpFee attempts to bump the fee of a transaction by spending one of its
428587// outputs at the given fee rate. This essentially results in a
429588// child-pays-for-parent (CPFP) scenario. If the given output has been used in a
0 commit comments