66 "fmt"
77 "sort"
88
9+ "github.com/btcsuite/btcd/btcutil"
910 "github.com/btcsuite/btcd/chaincfg/chainhash"
1011 "github.com/btcsuite/btcd/wire"
1112 "github.com/lightninglabs/lndclient"
@@ -14,6 +15,7 @@ import (
1415 "github.com/lightninglabs/loop/staticaddr/script"
1516 "github.com/lightninglabs/loop/swapserverrpc"
1617 "github.com/lightningnetwork/lnd/input"
18+ "github.com/lightningnetwork/lnd/lnwallet"
1719)
1820
1921// ToPrevOuts converts a slice of deposits to a map of outpoints to TxOuts.
@@ -66,6 +68,36 @@ func CreateMusig2Sessions(ctx context.Context,
6668 return musig2Sessions , clientNonces , nil
6769}
6870
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+
69101// CreateMusig2Session creates a musig2 session for the deposit.
70102func CreateMusig2Session (ctx context.Context ,
71103 signer lndclient.SignerClient , addrParams * address.Parameters ,
@@ -132,3 +164,42 @@ func bip69inputLess(input1, input2 *swapserverrpc.PrevoutInfo) bool {
132164 }
133165 return bytes .Compare (ihash [:], jhash [:]) == - 1
134166}
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