6
6
"fmt"
7
7
"sort"
8
8
9
+ "github.com/btcsuite/btcd/btcutil"
9
10
"github.com/btcsuite/btcd/chaincfg/chainhash"
10
11
"github.com/btcsuite/btcd/wire"
11
12
"github.com/lightninglabs/lndclient"
@@ -14,6 +15,7 @@ import (
14
15
"github.com/lightninglabs/loop/staticaddr/script"
15
16
"github.com/lightninglabs/loop/swapserverrpc"
16
17
"github.com/lightningnetwork/lnd/input"
18
+ "github.com/lightningnetwork/lnd/lnwallet"
17
19
)
18
20
19
21
// ToPrevOuts converts a slice of deposits to a map of outpoints to TxOuts.
@@ -66,6 +68,36 @@ func CreateMusig2Sessions(ctx context.Context,
66
68
return musig2Sessions , clientNonces , nil
67
69
}
68
70
71
+ // CreateMusig2SessionsPerDeposit creates a musig2 session for a number of
72
+ // deposits.
73
+ func CreateMusig2SessionsPerDeposit (ctx context.Context ,
74
+ signer lndclient.SignerClient , deposits []* deposit.Deposit ,
75
+ addrParams * address.Parameters ,
76
+ staticAddress * script.StaticAddress ) (
77
+ map [string ]* input.MuSig2SessionInfo , map [string ][]byte , map [string ]int ,
78
+ error ) {
79
+
80
+ sessions := make (map [string ]* input.MuSig2SessionInfo )
81
+ nonces := make (map [string ][]byte )
82
+ depositToIdx := make (map [string ]int )
83
+
84
+ // Create the musig2 sessions for the sweepless sweep tx.
85
+ for i , deposit := range deposits {
86
+ session , err := createMusig2Session (
87
+ ctx , signer , addrParams , staticAddress ,
88
+ )
89
+ if err != nil {
90
+ return nil , nil , nil , err
91
+ }
92
+
93
+ sessions [deposit .String ()] = session
94
+ nonces [deposit .String ()] = session .PublicNonce [:]
95
+ depositToIdx [deposit .String ()] = i
96
+ }
97
+
98
+ return sessions , nonces , depositToIdx , nil
99
+ }
100
+
69
101
// createMusig2Session creates a musig2 session for the deposit.
70
102
func createMusig2Session (ctx context.Context ,
71
103
signer lndclient.SignerClient , addrParams * address.Parameters ,
@@ -132,3 +164,42 @@ func bip69inputLess(input1, input2 *swapserverrpc.PrevoutInfo) bool {
132
164
}
133
165
return bytes .Compare (ihash [:], jhash [:]) == - 1
134
166
}
167
+
168
+ // SelectDeposits sorts the deposits by amount in descending order. It then
169
+ // selects the deposits that are needed to cover the amount requested without
170
+ // leaving a dust change. It returns an error if the sum of deposits minus dust
171
+ // is less than the requested amount.
172
+ func SelectDeposits (deposits []* deposit.Deposit , amount int64 ) (
173
+ []* deposit.Deposit , error ) {
174
+
175
+ // Check that sum of deposits covers the swap amount while leaving no
176
+ // dust change.
177
+ dustLimit := lnwallet .DustLimitForSize (input .P2TRSize )
178
+ var depositSum btcutil.Amount
179
+ for _ , deposit := range deposits {
180
+ depositSum += deposit .Value
181
+ }
182
+ if depositSum - dustLimit < btcutil .Amount (amount ) {
183
+ return nil , fmt .Errorf ("insufficient funds to cover swap " +
184
+ "amount, try manually selecting deposits" )
185
+ }
186
+
187
+ // Sort the deposits by amount in descending order.
188
+ sort .Slice (deposits , func (i , j int ) bool {
189
+ return deposits [i ].Value > deposits [j ].Value
190
+ })
191
+
192
+ // Select the deposits that are needed to cover the swap amount without
193
+ // leaving a dust change.
194
+ var selectedDeposits []* deposit.Deposit
195
+ var selectedAmount btcutil.Amount
196
+ for _ , deposit := range deposits {
197
+ if selectedAmount >= btcutil .Amount (amount )+ dustLimit {
198
+ break
199
+ }
200
+ selectedDeposits = append (selectedDeposits , deposit )
201
+ selectedAmount += deposit .Value
202
+ }
203
+
204
+ return selectedDeposits , nil
205
+ }
0 commit comments