@@ -19,6 +19,7 @@ import (
19
19
"github.com/lightninglabs/loop"
20
20
"github.com/lightninglabs/loop/fsm"
21
21
"github.com/lightninglabs/loop/labels"
22
+ "github.com/lightninglabs/loop/staticaddr/address"
22
23
"github.com/lightninglabs/loop/staticaddr/deposit"
23
24
"github.com/lightninglabs/loop/swapserverrpc"
24
25
"github.com/lightningnetwork/lnd/input"
@@ -324,29 +325,9 @@ func (m *Manager) handleLoopInSweepReq(ctx context.Context,
324
325
// If the user selected an amount that is less than the total deposit
325
326
// amount we'll check that the server sends us the correct change amount
326
327
// back to our static address.
327
- totalDepositAmount := loopIn .TotalDepositAmount ()
328
- changeAmt := totalDepositAmount - loopIn .SelectedAmount
329
- if changeAmt > 0 && changeAmt < totalDepositAmount {
330
- var foundChange bool
331
- changePkScript := loopIn .AddressParams .PkScript
332
-
333
- for _ , out := range sweepTx .TxOut {
334
- if out .Value == int64 (changeAmt ) &&
335
- bytes .Equal (out .PkScript , changePkScript ) {
336
-
337
- foundChange = true
338
- break
339
- }
340
- }
341
-
342
- if ! foundChange {
343
- return fmt .Errorf ("expected change output to our " +
344
- "static address, total_deposit_amount=%v, " +
345
- "selected_amount=%v, " +
346
- "expected_change_amount=%v " ,
347
- totalDepositAmount , loopIn .SelectedAmount ,
348
- changeAmt )
349
- }
328
+ err = m .checkChange (ctx , sweepTx , loopIn .AddressParams )
329
+ if err != nil {
330
+ return err
350
331
}
351
332
352
333
// Check if all the deposits requested are part of the loop-in and
@@ -465,6 +446,73 @@ func (m *Manager) handleLoopInSweepReq(ctx context.Context,
465
446
return err
466
447
}
467
448
449
+ // checkChange ensures that the server sends us the correct change amount
450
+ // back to our static address. An edge case arises if a batch contains two
451
+ // swaps with identical change outputs. The client needs to ensure that any
452
+ // swap referenced by the inputs has a respective change output in the batch.
453
+ func (m * Manager ) checkChange (ctx context.Context ,
454
+ sweepTx * wire.MsgTx , changeAddr * address.Parameters ) error {
455
+
456
+ prevOuts := make ([]string , len (sweepTx .TxIn ))
457
+ for i , in := range sweepTx .TxIn {
458
+ prevOuts [i ] = in .PreviousOutPoint .String ()
459
+ }
460
+
461
+ deposits , err := m .cfg .DepositManager .DepositsForOutpoints (
462
+ ctx , prevOuts ,
463
+ )
464
+ if err != nil {
465
+ return err
466
+ }
467
+
468
+ depositIDs := make ([]deposit.ID , len (deposits ))
469
+ for i , d := range deposits {
470
+ depositIDs [i ] = d .ID
471
+ }
472
+
473
+ swapHashes , err := m .cfg .Store .SwapHashesForDepositIDs (ctx , depositIDs )
474
+ if err != nil {
475
+ return err
476
+ }
477
+
478
+ var expectedChange btcutil.Amount
479
+ for swapHash := range swapHashes {
480
+ loopIn , err := m .cfg .Store .GetLoopInByHash (ctx , swapHash )
481
+ if err != nil {
482
+ return err
483
+ }
484
+
485
+ totalDepositAmount := loopIn .TotalDepositAmount ()
486
+ changeAmt := totalDepositAmount - loopIn .SelectedAmount
487
+ if changeAmt > 0 && changeAmt < totalDepositAmount {
488
+ log .Debugf ("expected change output to our " +
489
+ "static address, total_deposit_amount=%v, " +
490
+ "selected_amount=%v, " +
491
+ "expected_change_amount=%v " ,
492
+ totalDepositAmount , loopIn .SelectedAmount ,
493
+ changeAmt )
494
+
495
+ expectedChange += changeAmt
496
+ }
497
+ }
498
+
499
+ if expectedChange == 0 {
500
+ return nil
501
+ }
502
+
503
+ for _ , out := range sweepTx .TxOut {
504
+ if out .Value == int64 (expectedChange ) &&
505
+ bytes .Equal (out .PkScript , changeAddr .PkScript ) {
506
+
507
+ // We found the expected change output.
508
+ return nil
509
+ }
510
+ }
511
+
512
+ return fmt .Errorf ("couldn't find expected change of %v " +
513
+ "satoshis sent to our static address" , expectedChange )
514
+ }
515
+
468
516
// recover stars a loop-in state machine for each non-final loop-in to pick up
469
517
// work where it was left off before the restart.
470
518
func (m * Manager ) recoverLoopIns (ctx context.Context ) error {
0 commit comments