@@ -20,7 +20,9 @@ import (
20
20
"github.com/lightninglabs/loop/staticaddr/deposit"
21
21
"github.com/lightninglabs/loop/swapserverrpc"
22
22
looprpc "github.com/lightninglabs/loop/swapserverrpc"
23
+ "github.com/lightningnetwork/lnd/input"
23
24
"github.com/lightningnetwork/lnd/lntypes"
25
+ "github.com/lightningnetwork/lnd/lnwallet"
24
26
"github.com/lightningnetwork/lnd/routing/route"
25
27
)
26
28
@@ -206,8 +208,8 @@ func (m *Manager) Run(ctx context.Context) error {
206
208
case request .respChan <- resp :
207
209
208
210
case <- ctx .Done ():
209
- // Noify subroutines that the main loop has been
210
- // canceled.
211
+ // Notify subroutines that the main loop has
212
+ // been canceled.
211
213
close (m .exitChan )
212
214
213
215
return ctx .Err ()
@@ -272,6 +274,14 @@ func (m *Manager) handleLoopInSweepReq(ctx context.Context,
272
274
return err
273
275
}
274
276
277
+ deposits , err := m .cfg .DepositManager .DepositsForOutpoints (
278
+ ctx , loopIn .DepositOutpoints ,
279
+ )
280
+ if err != nil {
281
+ return err
282
+ }
283
+ loopIn .Deposits = deposits
284
+
275
285
reader := bytes .NewReader (req .SweepTxPsbt )
276
286
sweepPacket , err := psbt .NewFromRawBytes (reader , false )
277
287
if err != nil {
@@ -297,6 +307,33 @@ func (m *Manager) handleLoopInSweepReq(ctx context.Context,
297
307
len (req .PrevoutInfo ), len (sweepTx .TxIn ))
298
308
}
299
309
310
+ // If the user selected an amount we'll check that the server sends us
311
+ // the correct change amount back to our static address.
312
+ if loopIn .SelectedAmount > 0 {
313
+ var foundChange bool
314
+ totalDepositAmount := loopIn .TotalDepositAmount ()
315
+ changeAmt := totalDepositAmount - loopIn .SelectedAmount
316
+ changePkScript := loopIn .AddressParams .PkScript
317
+
318
+ for _ , out := range sweepTx .TxOut {
319
+ if out .Value == int64 (changeAmt ) &&
320
+ bytes .Equal (out .PkScript , changePkScript ) {
321
+
322
+ foundChange = true
323
+ break
324
+ }
325
+ }
326
+
327
+ if ! foundChange {
328
+ return fmt .Errorf ("expected change output to our " +
329
+ "static address, total_deposit_amount=%v, " +
330
+ "selected_amount=%v, " +
331
+ "expected_change_amount=%v " ,
332
+ totalDepositAmount , loopIn .SelectedAmount ,
333
+ changeAmt )
334
+ }
335
+ }
336
+
300
337
// Check if all the deposits requested are part of the loop-in and
301
338
// find them in the requested sweep.
302
339
depositToIdxMap , err := mapDepositsToIndices (req , loopIn , sweepTx )
@@ -531,14 +568,20 @@ func (m *Manager) initiateLoopIn(ctx context.Context,
531
568
req * loop.StaticAddressLoopInRequest ) (* StaticAddressLoopIn , error ) {
532
569
533
570
// Validate the loop-in request.
534
- if len (req .DepositOutpoints ) == 0 {
535
- return nil , fmt .Errorf ("no deposit outpoints provided" )
571
+ if len (req .DepositOutpoints ) == 0 && req .SelectedAmount == 0 {
572
+ return nil , fmt .Errorf ("no deposit outpoints provided and no " +
573
+ "amount selected" )
536
574
}
537
575
576
+ var (
577
+ err error
578
+ selectedOutpoints = req .DepositOutpoints
579
+ )
580
+
538
581
// Retrieve all deposits referenced by the outpoints and ensure that
539
582
// they are in state Deposited.
540
583
deposits , active := m .cfg .DepositManager .AllStringOutpointsActiveDeposits ( //nolint:lll
541
- req . DepositOutpoints , deposit .Deposited ,
584
+ selectedOutpoints , deposit .Deposited ,
542
585
)
543
586
if ! active {
544
587
return nil , fmt .Errorf ("one or more deposits are not in " +
@@ -551,8 +594,22 @@ func (m *Manager) initiateLoopIn(ctx context.Context,
551
594
}
552
595
totalDepositAmount := tmp .TotalDepositAmount ()
553
596
597
+ // If the selected amount would leave a dust change output or exceeds
598
+ // the total deposits value, we return an error.
599
+ dustLimit := lnwallet .DustLimitForSize (input .P2TRSize )
600
+ if totalDepositAmount - req .SelectedAmount < dustLimit {
601
+ return nil , fmt .Errorf ("selected amount %v leaves " +
602
+ "dust or exceeds total deposit value %v" ,
603
+ req .SelectedAmount , totalDepositAmount )
604
+ }
605
+
606
+ swapAmount := totalDepositAmount
607
+ if req .SelectedAmount > 0 {
608
+ swapAmount = req .SelectedAmount
609
+ }
610
+
554
611
// Check that the label is valid.
555
- err : = labels .Validate (req .Label )
612
+ err = labels .Validate (req .Label )
556
613
if err != nil {
557
614
return nil , fmt .Errorf ("invalid label: %w" , err )
558
615
}
@@ -576,7 +633,7 @@ func (m *Manager) initiateLoopIn(ctx context.Context,
576
633
// Because the Private flag is set, we'll generate our own set
577
634
// of hop hints.
578
635
req .RouteHints , err = loop .SelectHopHints (
579
- ctx , m .cfg .LndClient , totalDepositAmount ,
636
+ ctx , m .cfg .LndClient , swapAmount ,
580
637
loop .DefaultMaxHopHints , includeNodes ,
581
638
)
582
639
if err != nil {
@@ -593,11 +650,11 @@ func (m *Manager) initiateLoopIn(ctx context.Context,
593
650
// directly anyway and there they have the option to add specific route
594
651
// hints.
595
652
// The quote call will also request a probe from the server to ensure
596
- // feasibility of a loop-in for the totalDepositAmount .
653
+ // feasibility of a loop-in for the selected .
597
654
numDeposits := uint32 (len (deposits ))
598
655
quote , err := m .cfg .QuoteGetter .GetLoopInQuote (
599
- ctx , totalDepositAmount , m .cfg .NodePubkey , req .LastHop ,
600
- req .RouteHints , req . Initiator , numDeposits ,
656
+ ctx , swapAmount , m .cfg .NodePubkey , req .LastHop , req . RouteHints ,
657
+ req .Initiator , numDeposits ,
601
658
)
602
659
if err != nil {
603
660
return nil , fmt .Errorf ("unable to get loop in quote: %w" , err )
@@ -618,6 +675,7 @@ func (m *Manager) initiateLoopIn(ctx context.Context,
618
675
}
619
676
620
677
swap := & StaticAddressLoopIn {
678
+ SelectedAmount : req .SelectedAmount ,
621
679
DepositOutpoints : req .DepositOutpoints ,
622
680
Deposits : deposits ,
623
681
Label : req .Label ,
0 commit comments