@@ -2,20 +2,46 @@ package lndclient
2
2
3
3
import (
4
4
"context"
5
+ "encoding/hex"
6
+ "fmt"
7
+ "time"
5
8
6
9
"github.com/btcsuite/btcd/btcec"
10
+ "github.com/btcsuite/btcd/chaincfg/chainhash"
7
11
"github.com/btcsuite/btcd/wire"
8
12
"github.com/btcsuite/btcutil"
13
+ "github.com/btcsuite/btcwallet/wtxmgr"
9
14
"github.com/lightninglabs/loop/swap"
10
15
"github.com/lightningnetwork/lnd/keychain"
16
+ "github.com/lightningnetwork/lnd/lnrpc"
11
17
"github.com/lightningnetwork/lnd/lnrpc/signrpc"
12
18
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
19
+ "github.com/lightningnetwork/lnd/lnwallet"
13
20
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
14
21
"google.golang.org/grpc"
15
22
)
16
23
17
24
// WalletKitClient exposes wallet functionality.
18
25
type 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
+
19
45
DeriveNextKey (ctx context.Context , family int32 ) (
20
46
* keychain.KeyDescriptor , error )
21
47
@@ -38,6 +64,10 @@ type walletKitClient struct {
38
64
walletKitMac serializedMacaroon
39
65
}
40
66
67
+ // A compile-time constraint to ensure walletKitclient satisfies the
68
+ // WalletKitClient interface.
69
+ var _ WalletKitClient = (* walletKitClient )(nil )
70
+
41
71
func newWalletKitClient (conn * grpc.ClientConn ,
42
72
walletKitMac serializedMacaroon ) * walletKitClient {
43
73
@@ -47,6 +77,107 @@ func newWalletKitClient(conn *grpc.ClientConn,
47
77
}
48
78
}
49
79
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
+
50
181
func (m * walletKitClient ) DeriveNextKey (ctx context.Context , family int32 ) (
51
182
* keychain.KeyDescriptor , error ) {
52
183
0 commit comments