@@ -2,20 +2,46 @@ package lndclient
22
33import (
44 "context"
5+ "encoding/hex"
6+ "fmt"
7+ "time"
58
69 "github.com/btcsuite/btcd/btcec"
10+ "github.com/btcsuite/btcd/chaincfg/chainhash"
711 "github.com/btcsuite/btcd/wire"
812 "github.com/btcsuite/btcutil"
13+ "github.com/btcsuite/btcwallet/wtxmgr"
914 "github.com/lightninglabs/loop/swap"
1015 "github.com/lightningnetwork/lnd/keychain"
16+ "github.com/lightningnetwork/lnd/lnrpc"
1117 "github.com/lightningnetwork/lnd/lnrpc/signrpc"
1218 "github.com/lightningnetwork/lnd/lnrpc/walletrpc"
19+ "github.com/lightningnetwork/lnd/lnwallet"
1320 "github.com/lightningnetwork/lnd/lnwallet/chainfee"
1421 "google.golang.org/grpc"
1522)
1623
1724// WalletKitClient exposes wallet functionality.
1825type WalletKitClient interface {
26+ // ListUnspent returns a list of all utxos spendable by the wallet with
27+ // a number of confirmations between the specified minimum and maximum.
28+ ListUnspent (ctx context.Context , minConfs , maxConfs int32 ) (
29+ []* lnwallet.Utxo , error )
30+
31+ // LeaseOutput locks an output to the given ID, preventing it from being
32+ // available for any future coin selection attempts. The absolute time
33+ // of the lock's expiration is returned. The expiration of the lock can
34+ // be extended by successive invocations of this call. Outputs can be
35+ // unlocked before their expiration through `ReleaseOutput`.
36+ LeaseOutput (ctx context.Context , lockID wtxmgr.LockID ,
37+ op wire.OutPoint ) (time.Time , error )
38+
39+ // ReleaseOutput unlocks an output, allowing it to be available for coin
40+ // selection if it remains unspent. The ID should match the one used to
41+ // originally lock the output.
42+ ReleaseOutput (ctx context.Context , lockID wtxmgr.LockID ,
43+ op wire.OutPoint ) error
44+
1945 DeriveNextKey (ctx context.Context , family int32 ) (
2046 * keychain.KeyDescriptor , error )
2147
@@ -38,6 +64,10 @@ type walletKitClient struct {
3864 walletKitMac serializedMacaroon
3965}
4066
67+ // A compile-time constraint to ensure walletKitclient satisfies the
68+ // WalletKitClient interface.
69+ var _ WalletKitClient = (* walletKitClient )(nil )
70+
4171func newWalletKitClient (conn * grpc.ClientConn ,
4272 walletKitMac serializedMacaroon ) * walletKitClient {
4373
@@ -47,6 +77,107 @@ func newWalletKitClient(conn *grpc.ClientConn,
4777 }
4878}
4979
80+ // ListUnspent returns a list of all utxos spendable by the wallet with a number
81+ // of confirmations between the specified minimum and maximum.
82+ func (m * walletKitClient ) ListUnspent (ctx context.Context , minConfs ,
83+ maxConfs int32 ) ([]* lnwallet.Utxo , error ) {
84+
85+ rpcCtx , cancel := context .WithTimeout (ctx , rpcTimeout )
86+ defer cancel ()
87+
88+ rpcCtx = m .walletKitMac .WithMacaroonAuth (rpcCtx )
89+ resp , err := m .client .ListUnspent (rpcCtx , & walletrpc.ListUnspentRequest {
90+ MinConfs : minConfs ,
91+ MaxConfs : maxConfs ,
92+ })
93+ if err != nil {
94+ return nil , err
95+ }
96+
97+ utxos := make ([]* lnwallet.Utxo , 0 , len (resp .Utxos ))
98+ for _ , utxo := range resp .Utxos {
99+ var addrType lnwallet.AddressType
100+ switch utxo .AddressType {
101+ case lnrpc .AddressType_WITNESS_PUBKEY_HASH :
102+ addrType = lnwallet .WitnessPubKey
103+ case lnrpc .AddressType_NESTED_PUBKEY_HASH :
104+ addrType = lnwallet .NestedWitnessPubKey
105+ default :
106+ return nil , fmt .Errorf ("invalid utxo address type %v" ,
107+ utxo .AddressType )
108+ }
109+
110+ pkScript , err := hex .DecodeString (utxo .PkScript )
111+ if err != nil {
112+ return nil , err
113+ }
114+
115+ opHash , err := chainhash .NewHash (utxo .Outpoint .TxidBytes )
116+ if err != nil {
117+ return nil , err
118+ }
119+
120+ utxos = append (utxos , & lnwallet.Utxo {
121+ AddressType : addrType ,
122+ Value : btcutil .Amount (utxo .AmountSat ),
123+ Confirmations : utxo .Confirmations ,
124+ PkScript : pkScript ,
125+ OutPoint : wire.OutPoint {
126+ Hash : * opHash ,
127+ Index : utxo .Outpoint .OutputIndex ,
128+ },
129+ })
130+ }
131+
132+ return utxos , nil
133+ }
134+
135+ // LeaseOutput locks an output to the given ID, preventing it from being
136+ // available for any future coin selection attempts. The absolute time of the
137+ // lock's expiration is returned. The expiration of the lock can be extended by
138+ // successive invocations of this call. Outputs can be unlocked before their
139+ // expiration through `ReleaseOutput`.
140+ func (m * walletKitClient ) LeaseOutput (ctx context.Context , lockID wtxmgr.LockID ,
141+ op wire.OutPoint ) (time.Time , error ) {
142+
143+ rpcCtx , cancel := context .WithTimeout (ctx , rpcTimeout )
144+ defer cancel ()
145+
146+ rpcCtx = m .walletKitMac .WithMacaroonAuth (rpcCtx )
147+ resp , err := m .client .LeaseOutput (rpcCtx , & walletrpc.LeaseOutputRequest {
148+ Id : lockID [:],
149+ Outpoint : & lnrpc.OutPoint {
150+ TxidBytes : op .Hash [:],
151+ OutputIndex : op .Index ,
152+ },
153+ })
154+ if err != nil {
155+ return time.Time {}, err
156+ }
157+
158+ return time .Unix (int64 (resp .Expiration ), 0 ), nil
159+ }
160+
161+ // ReleaseOutput unlocks an output, allowing it to be available for coin
162+ // selection if it remains unspent. The ID should match the one used to
163+ // originally lock the output.
164+ func (m * walletKitClient ) ReleaseOutput (ctx context.Context ,
165+ lockID wtxmgr.LockID , op wire.OutPoint ) error {
166+
167+ rpcCtx , cancel := context .WithTimeout (ctx , rpcTimeout )
168+ defer cancel ()
169+
170+ rpcCtx = m .walletKitMac .WithMacaroonAuth (rpcCtx )
171+ _ , err := m .client .ReleaseOutput (rpcCtx , & walletrpc.ReleaseOutputRequest {
172+ Id : lockID [:],
173+ Outpoint : & lnrpc.OutPoint {
174+ TxidBytes : op .Hash [:],
175+ OutputIndex : op .Index ,
176+ },
177+ })
178+ return err
179+ }
180+
50181func (m * walletKitClient ) DeriveNextKey (ctx context.Context , family int32 ) (
51182 * keychain.KeyDescriptor , error ) {
52183
0 commit comments