Skip to content

Commit f26a00d

Browse files
authored
Merge pull request #751 from bhandras/negative-fees-fixup
loopout: fix negative reported fees
2 parents edbbc3f + 5690235 commit f26a00d

File tree

3 files changed

+70
-11
lines changed

3 files changed

+70
-11
lines changed

loopout.go

+23-8
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ func (s *loopOutSwap) executeAndFinalize(globalCtx context.Context) error {
402402
case result := <-s.swapPaymentChan:
403403
s.swapPaymentChan = nil
404404

405-
err := s.handlePaymentResult(result)
405+
err := s.handlePaymentResult(result, true)
406406
if err != nil {
407407
return err
408408
}
@@ -418,7 +418,7 @@ func (s *loopOutSwap) executeAndFinalize(globalCtx context.Context) error {
418418
case result := <-s.prePaymentChan:
419419
s.prePaymentChan = nil
420420

421-
err := s.handlePaymentResult(result)
421+
err := s.handlePaymentResult(result, false)
422422
if err != nil {
423423
return err
424424
}
@@ -448,17 +448,32 @@ func (s *loopOutSwap) executeAndFinalize(globalCtx context.Context) error {
448448
return s.persistState(globalCtx)
449449
}
450450

451-
func (s *loopOutSwap) handlePaymentResult(result paymentResult) error {
451+
// handlePaymentResult processes the result of a payment attempt. If the
452+
// payment was successful and this is the main swap payment, the cost of the
453+
// swap is updated.
454+
func (s *loopOutSwap) handlePaymentResult(result paymentResult,
455+
swapPayment bool) error {
456+
452457
switch {
453458
// If our result has a non-nil error, our status will be nil. In this
454459
// case the payment failed so we do not need to take any action.
455460
case result.err != nil:
456461
return nil
457462

458463
case result.status.State == lnrpc.Payment_SUCCEEDED:
459-
s.cost.Server += result.status.Value.ToSatoshis() -
460-
s.AmountRequested
461-
s.cost.Offchain += result.status.Fee.ToSatoshis()
464+
// Update the cost of the swap if this is the main swap payment.
465+
if swapPayment {
466+
// The client pays for the swap with the swap invoice,
467+
// so we can calculate the total cost of the swap by
468+
// subtracting the amount requested from the amount we
469+
// actually paid.
470+
s.cost.Server += result.status.Value.ToSatoshis() -
471+
s.AmountRequested
472+
473+
// On top of the swap cost we also pay for routing which
474+
// is reflected in the fee.
475+
s.cost.Offchain += result.status.Fee.ToSatoshis()
476+
}
462477

463478
return nil
464479

@@ -917,7 +932,7 @@ func (s *loopOutSwap) waitForConfirmedHtlc(globalCtx context.Context) (
917932
case result := <-s.swapPaymentChan:
918933
s.swapPaymentChan = nil
919934

920-
err := s.handlePaymentResult(result)
935+
err := s.handlePaymentResult(result, true)
921936
if err != nil {
922937
return nil, err
923938
}
@@ -939,7 +954,7 @@ func (s *loopOutSwap) waitForConfirmedHtlc(globalCtx context.Context) (
939954
case result := <-s.prePaymentChan:
940955
s.prePaymentChan = nil
941956

942-
err := s.handlePaymentResult(result)
957+
err := s.handlePaymentResult(result, false)
943958
if err != nil {
944959
return nil, err
945960
}

sweepbatcher/sweep_batch.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -1158,9 +1158,8 @@ func (b *batch) monitorConfirmations(ctx context.Context) error {
11581158
func getFeePortionForSweep(spendTx *wire.MsgTx, numSweeps int,
11591159
totalSweptAmt btcutil.Amount) (btcutil.Amount, btcutil.Amount) {
11601160

1161-
totalFee := spendTx.TxOut[0].Value - int64(totalSweptAmt)
1162-
feePortionPerSweep := (int64(totalSweptAmt) -
1163-
spendTx.TxOut[0].Value) / int64(numSweeps)
1161+
totalFee := int64(totalSweptAmt) - spendTx.TxOut[0].Value
1162+
feePortionPerSweep := totalFee / int64(numSweeps)
11641163
roundingDiff := totalFee - (int64(numSweeps) * feePortionPerSweep)
11651164

11661165
return btcutil.Amount(feePortionPerSweep), btcutil.Amount(roundingDiff)

sweepbatcher/sweep_batcher_test.go

+45
Original file line numberDiff line numberDiff line change
@@ -984,3 +984,48 @@ func TestSweepBatcherComposite(t *testing.T) {
984984
require.True(t, batcherStore.AssertSweepStored(sweepReq5.SwapHash))
985985
require.True(t, batcherStore.AssertSweepStored(sweepReq6.SwapHash))
986986
}
987+
988+
// makeTestTx creates a test transaction with a single output of the given
989+
// value.
990+
func makeTestTx(value int64) *wire.MsgTx {
991+
tx := wire.NewMsgTx(wire.TxVersion)
992+
tx.AddTxOut(wire.NewTxOut(value, nil))
993+
return tx
994+
}
995+
996+
// TestGetFeePortionForSweep tests that the fee portion for a sweep is correctly
997+
// calculated.
998+
func TestGetFeePortionForSweep(t *testing.T) {
999+
tests := []struct {
1000+
name string
1001+
spendTxValue int64
1002+
numSweeps int
1003+
totalSweptAmt btcutil.Amount
1004+
expectedFeePortion btcutil.Amount
1005+
expectedRoundingDiff btcutil.Amount
1006+
}{
1007+
{
1008+
"Even Split",
1009+
100, 5, 200, 20, 0,
1010+
},
1011+
{
1012+
"Single Sweep",
1013+
100, 1, 200, 100, 0,
1014+
},
1015+
{
1016+
"With Rounding Diff",
1017+
200, 4, 350, 37, 2,
1018+
},
1019+
}
1020+
1021+
for _, tt := range tests {
1022+
t.Run(tt.name, func(t *testing.T) {
1023+
spendTx := makeTestTx(tt.spendTxValue)
1024+
feePortion, roundingDiff := getFeePortionForSweep(
1025+
spendTx, tt.numSweeps, tt.totalSweptAmt,
1026+
)
1027+
require.Equal(t, tt.expectedFeePortion, feePortion)
1028+
require.Equal(t, tt.expectedRoundingDiff, roundingDiff)
1029+
})
1030+
}
1031+
}

0 commit comments

Comments
 (0)