Skip to content

Commit 0769945

Browse files
committed
staticaddr: arbitrary loop-in amount
In this commit we add a new function SelectDeposits to the loop-in manager. It coin-selects deposits that meet an arbitrary swap amount provided by the client. We have to ensure that the server creates the correct change outputs for the htlc- and sweepless sweep transactions.
1 parent 2a3c6da commit 0769945

File tree

7 files changed

+392
-33
lines changed

7 files changed

+392
-33
lines changed

interface.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,11 @@ type StaticAddressLoopInRequest struct {
338338
// swap payment. If the timeout is reached the swap will be aborted and
339339
// the client can retry the swap if desired with different parameters.
340340
PaymentTimeoutSeconds uint32
341+
342+
// SelectedAmount is the amount that the user selected for the swap. If
343+
// the user did not select an amount, the amount of the selected
344+
// deposits is used.
345+
SelectedAmount btcutil.Amount
341346
}
342347

343348
// LoopInTerms are the server terms on which it executes loop in swaps.

staticaddr/loopin/actions.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,14 @@ func (f *FSM) InitHtlcAction(ctx context.Context,
6868
}
6969

7070
// Calculate the swap invoice amount. The server needs to pay us the
71-
// sum of all deposits minus the fees that the server charges for the
72-
// swap.
73-
swapInvoiceAmt := f.loopIn.TotalDepositAmount() - f.loopIn.QuotedSwapFee
71+
// swap amount minus the fees that the server charges for the swap. The
72+
// swap amount is either the total value of the selected deposits, or
73+
// the selected amount if a specific amount was requested.
74+
swapAmount := f.loopIn.TotalDepositAmount()
75+
if f.loopIn.SelectedAmount > 0 {
76+
swapAmount = f.loopIn.SelectedAmount
77+
}
78+
swapInvoiceAmt := swapAmount - f.loopIn.QuotedSwapFee
7479

7580
// Generate random preimage.
7681
var swapPreimage lntypes.Preimage
@@ -120,6 +125,7 @@ func (f *FSM) InitHtlcAction(ctx context.Context,
120125
loopInReq := &swapserverrpc.ServerStaticAddressLoopInRequest{
121126
SwapHash: f.loopIn.SwapHash[:],
122127
DepositOutpoints: f.loopIn.DepositOutpoints,
128+
Amount: uint64(f.loopIn.SelectedAmount),
123129
HtlcClientPubKey: f.loopIn.ClientPubkey.SerializeCompressed(),
124130
SwapInvoice: f.loopIn.SwapInvoice,
125131
ProtocolVersion: version.CurrentRPCProtocolVersion(),
@@ -204,7 +210,7 @@ func (f *FSM) InitHtlcAction(ctx context.Context,
204210
// We need to defend against the server setting high fees for the htlc
205211
// tx since we might have to sweep the timeout path. We maximally allow
206212
// a configured percentage of the swap value to be spent on fees.
207-
amt := float64(f.loopIn.TotalDepositAmount())
213+
amt := float64(swapAmount)
208214
maxHtlcTxFee := btcutil.Amount(amt *
209215
f.cfg.MaxStaticAddrHtlcFeePercentage)
210216

staticaddr/loopin/interface.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ type DepositManager interface {
5353
// outpoints.
5454
DepositsForOutpoints(ctx context.Context, outpoints []string) (
5555
[]*deposit.Deposit, error)
56+
57+
// GetActiveDepositsInState returns all active deposits in the given
58+
// state.
59+
GetActiveDepositsInState(stateFilter fsm.StateType) ([]*deposit.Deposit,
60+
error)
5661
}
5762

5863
// StaticAddressLoopInStore provides access to the static address loop-in DB.

staticaddr/loopin/loopin.go

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package loopin
22

33
import (
4+
"bytes"
45
"context"
56
"errors"
67
"fmt"
@@ -93,6 +94,11 @@ type StaticAddressLoopIn struct {
9394
// swap.
9495
DepositOutpoints []string
9596

97+
// SelectedAmount is the amount that the user selected for the swap. If
98+
// the user did not select an amount, the amount of all deposits is
99+
// used.
100+
SelectedAmount btcutil.Amount
101+
96102
// state is the current state of the swap.
97103
state fsm.StateType
98104

@@ -287,10 +293,20 @@ func (l *StaticAddressLoopIn) createHtlcTx(chainParams *chaincfg.Params,
287293
weight := l.htlcWeight()
288294
fee := feeRate.FeeForWeight(weight)
289295

290-
// Check if the server breaches our fee limits.
291-
amt := float64(l.TotalDepositAmount())
292-
feeLimit := btcutil.Amount(amt * maxFeePercentage)
296+
// Determine the swap amount. If the user selected a specific amount, we
297+
// use that and use the difference to the total deposit amount as the
298+
// change.
299+
var (
300+
swapAmt = l.TotalDepositAmount()
301+
changeAmount btcutil.Amount
302+
)
303+
if l.SelectedAmount > 0 {
304+
swapAmt = l.SelectedAmount
305+
changeAmount = l.TotalDepositAmount() - l.SelectedAmount
306+
}
293307

308+
// Check if the server breaches our fee limits.
309+
feeLimit := btcutil.Amount(float64(swapAmt) * maxFeePercentage)
294310
if fee > feeLimit {
295311
return nil, fmt.Errorf("htlc tx fee %v exceeds max fee %v",
296312
fee, feeLimit)
@@ -308,12 +324,20 @@ func (l *StaticAddressLoopIn) createHtlcTx(chainParams *chaincfg.Params,
308324

309325
// Create the sweep output
310326
sweepOutput := &wire.TxOut{
311-
Value: int64(l.TotalDepositAmount()) - int64(fee),
327+
Value: int64(swapAmt - fee),
312328
PkScript: pkscript,
313329
}
314330

315331
msgTx.AddTxOut(sweepOutput)
316332

333+
// We expect change to be sent back to our static address output script.
334+
if changeAmount > 0 {
335+
msgTx.AddTxOut(&wire.TxOut{
336+
Value: int64(changeAmount),
337+
PkScript: l.AddressParams.PkScript,
338+
})
339+
}
340+
317341
return msgTx, nil
318342
}
319343

@@ -373,11 +397,25 @@ func (l *StaticAddressLoopIn) createHtlcSweepTx(ctx context.Context,
373397
return nil, err
374398
}
375399

400+
// Check if the htlc tx has a change output. If so we need to select the
401+
// non-change output index to construct the sweep with.
402+
htlcInputIndex := uint32(0)
403+
if len(htlcTx.TxOut) == 2 {
404+
// If the first htlc tx output matches our static address
405+
// script we need to select the second output to sweep from.
406+
if bytes.Equal(
407+
htlcTx.TxOut[0].PkScript, l.AddressParams.PkScript,
408+
) {
409+
410+
htlcInputIndex = 1
411+
}
412+
}
413+
376414
// Add the htlc input.
377415
sweepTx.AddTxIn(&wire.TxIn{
378416
PreviousOutPoint: wire.OutPoint{
379417
Hash: htlcTx.TxHash(),
380-
Index: 0,
418+
Index: htlcInputIndex,
381419
},
382420
SignatureScript: htlc.SigScript,
383421
Sequence: htlc.SuccessSequence(),

0 commit comments

Comments
 (0)