Skip to content

Commit d4b7f9a

Browse files
committed
liquidity: update default fee setting to flat percentage
1 parent 299a0a4 commit d4b7f9a

File tree

3 files changed

+113
-41
lines changed

3 files changed

+113
-41
lines changed

liquidity/fees.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ const (
4242
// ensure that we will still be able to complete our swap in the case
4343
// of a severe fee spike.
4444
minerMultiplier = 100
45+
46+
// defaultFeePPM is the default percentage of swap amount that we
47+
// allocate to fees, 2%.
48+
defaultFeePPM = 20000
4549
)
4650

4751
var (
@@ -245,6 +249,12 @@ type FeePortion struct {
245249
PartsPerMillion uint64
246250
}
247251

252+
func defaultFeePortion() *FeePortion {
253+
return &FeePortion{
254+
PartsPerMillion: defaultFeePPM,
255+
}
256+
}
257+
248258
// NewFeePortion creates a fee limit based on a flat percentage of swap amount.
249259
func NewFeePortion(ppm uint64) *FeePortion {
250260
return &FeePortion{

liquidity/liquidity.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ var (
9999
PeerRules: make(map[route.Vertex]*ThresholdRule),
100100
FailureBackOff: defaultFailureBackoff,
101101
SweepConfTarget: loop.DefaultSweepConfTarget,
102-
FeeLimit: defaultFeeCategoryLimit(),
102+
FeeLimit: defaultFeePortion(),
103103
}
104104

105105
// ErrZeroChannelID is returned if we get a rule for a 0 channel ID.

liquidity/liquidity_test.go

Lines changed: 102 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -50,23 +50,20 @@ var (
5050
chanRule = NewThresholdRule(50, 0)
5151

5252
testQuote = &loop.LoopOutQuote{
53-
SwapFee: btcutil.Amount(1),
54-
PrepayAmount: btcutil.Amount(500),
55-
MinerFee: btcutil.Amount(50),
53+
SwapFee: btcutil.Amount(5),
54+
PrepayAmount: btcutil.Amount(50),
55+
MinerFee: btcutil.Amount(1),
5656
}
5757

58-
prepayFee = ppmToSat(
59-
testQuote.PrepayAmount, defaultPrepayRoutingFeePPM,
60-
)
61-
routingFee = ppmToSat(7500, defaultRoutingFeePPM)
58+
prepayFee, routingFee = testPPMFees(defaultFeePPM, testQuote, 7500)
6259

6360
// chan1Rec is the suggested swap for channel 1 when we use chanRule.
6461
chan1Rec = loop.OutRequest{
6562
Amount: 7500,
6663
OutgoingChanSet: loopdb.ChannelSet{chanID1.ToUint64()},
6764
MaxPrepayRoutingFee: prepayFee,
6865
MaxSwapRoutingFee: routingFee,
69-
MaxMinerFee: defaultMaximumMinerFee,
66+
MaxMinerFee: scaleMinerFee(testQuote.MinerFee),
7067
MaxSwapFee: testQuote.SwapFee,
7168
MaxPrepayAmount: testQuote.PrepayAmount,
7269
SweepConfTarget: loop.DefaultSweepConfTarget,
@@ -79,7 +76,7 @@ var (
7976
OutgoingChanSet: loopdb.ChannelSet{chanID2.ToUint64()},
8077
MaxPrepayRoutingFee: prepayFee,
8178
MaxSwapRoutingFee: routingFee,
82-
MaxMinerFee: defaultMaximumMinerFee,
79+
MaxMinerFee: scaleMinerFee(testQuote.MinerFee),
8380
MaxPrepayAmount: testQuote.PrepayAmount,
8481
MaxSwapFee: testQuote.SwapFee,
8582
SweepConfTarget: loop.DefaultSweepConfTarget,
@@ -164,6 +161,21 @@ func testPPMFees(ppm uint64, quote *loop.LoopOutQuote,
164161
)
165162
}
166163

164+
// applyFeeCategoryQuote returns a copy of the loop out request provided with
165+
// fee categories updated to the quote and routing settings provided.
166+
// nolint:unparam
167+
func applyFeeCategoryQuote(req loop.OutRequest, minerFee btcutil.Amount,
168+
prepayPPM, routingPPM uint64, quote loop.LoopOutQuote) loop.OutRequest {
169+
170+
req.MaxPrepayRoutingFee = ppmToSat(quote.PrepayAmount, prepayPPM)
171+
req.MaxSwapRoutingFee = ppmToSat(req.Amount, routingPPM)
172+
req.MaxSwapFee = quote.SwapFee
173+
req.MaxPrepayAmount = quote.PrepayAmount
174+
req.MaxMinerFee = minerFee
175+
176+
return req
177+
}
178+
167179
// TestParameters tests getting and setting of parameters for our manager.
168180
func TestParameters(t *testing.T) {
169181
cfg, _ := newTestConfig()
@@ -547,6 +559,12 @@ func TestRestrictedSuggestions(t *testing.T) {
547559
// TestSweepFeeLimit tests getting of swap suggestions when our estimated sweep
548560
// fee is above and below the configured limit.
549561
func TestSweepFeeLimit(t *testing.T) {
562+
quote := &loop.LoopOutQuote{
563+
SwapFee: btcutil.Amount(1),
564+
PrepayAmount: btcutil.Amount(500),
565+
MinerFee: btcutil.Amount(50),
566+
}
567+
550568
tests := []struct {
551569
name string
552570
feeRate chainfee.SatPerKWeight
@@ -557,7 +575,11 @@ func TestSweepFeeLimit(t *testing.T) {
557575
feeRate: defaultSweepFeeRateLimit,
558576
suggestions: &Suggestions{
559577
OutSwaps: []loop.OutRequest{
560-
chan1Rec,
578+
applyFeeCategoryQuote(
579+
chan1Rec, defaultMaximumMinerFee,
580+
defaultPrepayRoutingFeePPM,
581+
defaultRoutingFeePPM, *quote,
582+
),
561583
},
562584
DisqualifiedChans: noneDisqualified,
563585
DisqualifiedPeers: noPeersDisqualified,
@@ -581,6 +603,13 @@ func TestSweepFeeLimit(t *testing.T) {
581603
t.Run(testCase.name, func(t *testing.T) {
582604
cfg, lnd := newTestConfig()
583605

606+
cfg.LoopOutQuote = func(_ context.Context,
607+
_ *loop.LoopOutQuoteRequest) (*loop.LoopOutQuote,
608+
error) {
609+
610+
return quote, nil
611+
}
612+
584613
// Set our test case's fee rate for our mock lnd.
585614
lnd.SetFeeEstimate(
586615
loop.DefaultSweepConfTarget, testCase.feeRate,
@@ -591,6 +620,8 @@ func TestSweepFeeLimit(t *testing.T) {
591620
}
592621

593622
params := defaultParameters
623+
params.FeeLimit = defaultFeeCategoryLimit()
624+
594625
params.ChannelRules = map[lnwire.ShortChannelID]*ThresholdRule{
595626
chanID1: chanRule,
596627
}
@@ -610,6 +641,9 @@ func TestSuggestSwaps(t *testing.T) {
610641
channel1,
611642
}
612643

644+
expectedAmt := btcutil.Amount(10000)
645+
prepay, routing := testPPMFees(defaultFeePPM, testQuote, expectedAmt)
646+
613647
tests := []struct {
614648
name string
615649
channels []lndclient.ChannelInfo
@@ -681,24 +715,18 @@ func TestSuggestSwaps(t *testing.T) {
681715
suggestions: &Suggestions{
682716
OutSwaps: []loop.OutRequest{
683717
{
684-
Amount: 10000,
718+
Amount: expectedAmt,
685719
OutgoingChanSet: loopdb.ChannelSet{
686720
chanID1.ToUint64(),
687721
chanID2.ToUint64(),
688722
},
689-
MaxPrepayRoutingFee: ppmToSat(
690-
testQuote.PrepayAmount,
691-
defaultPrepayRoutingFeePPM,
692-
),
693-
MaxSwapRoutingFee: ppmToSat(
694-
10000,
695-
defaultRoutingFeePPM,
696-
),
697-
MaxMinerFee: defaultMaximumMinerFee,
698-
MaxSwapFee: testQuote.SwapFee,
699-
MaxPrepayAmount: testQuote.PrepayAmount,
700-
SweepConfTarget: loop.DefaultSweepConfTarget,
701-
Initiator: autoloopSwapInitiator,
723+
MaxPrepayRoutingFee: prepay,
724+
MaxSwapRoutingFee: routing,
725+
MaxMinerFee: scaleMinerFee(testQuote.MinerFee),
726+
MaxSwapFee: testQuote.SwapFee,
727+
MaxPrepayAmount: testQuote.PrepayAmount,
728+
SweepConfTarget: loop.DefaultSweepConfTarget,
729+
Initiator: autoloopSwapInitiator,
702730
},
703731
},
704732
DisqualifiedChans: noneDisqualified,
@@ -736,17 +764,27 @@ func TestSuggestSwaps(t *testing.T) {
736764

737765
// TestFeeLimits tests limiting of swap suggestions by fees.
738766
func TestFeeLimits(t *testing.T) {
767+
quote := &loop.LoopOutQuote{
768+
SwapFee: btcutil.Amount(1),
769+
PrepayAmount: btcutil.Amount(500),
770+
MinerFee: btcutil.Amount(50),
771+
}
772+
739773
tests := []struct {
740774
name string
741775
quote *loop.LoopOutQuote
742776
suggestions *Suggestions
743777
}{
744778
{
745779
name: "fees ok",
746-
quote: testQuote,
780+
quote: quote,
747781
suggestions: &Suggestions{
748782
OutSwaps: []loop.OutRequest{
749-
chan1Rec,
783+
applyFeeCategoryQuote(
784+
chan1Rec, defaultMaximumMinerFee,
785+
defaultPrepayRoutingFeePPM,
786+
defaultRoutingFeePPM, *quote,
787+
),
750788
},
751789
DisqualifiedChans: noneDisqualified,
752790
DisqualifiedPeers: noPeersDisqualified,
@@ -813,7 +851,10 @@ func TestFeeLimits(t *testing.T) {
813851
channel1,
814852
}
815853

854+
// Set our params to use individual fee limits.
816855
params := defaultParameters
856+
params.FeeLimit = defaultFeeCategoryLimit()
857+
817858
params.ChannelRules = map[lnwire.ShortChannelID]*ThresholdRule{
818859
chanID1: chanRule,
819860
}
@@ -838,6 +879,21 @@ func TestFeeLimits(t *testing.T) {
838879
// amounts, we use our max miner fee to shift swap cost to values above/below
839880
// our budget, fixing our other fees at 114 sat for simplicity.
840881
func TestFeeBudget(t *testing.T) {
882+
quote := &loop.LoopOutQuote{
883+
SwapFee: btcutil.Amount(1),
884+
PrepayAmount: btcutil.Amount(500),
885+
MinerFee: btcutil.Amount(50),
886+
}
887+
888+
chan1 := applyFeeCategoryQuote(
889+
chan1Rec, 5000, defaultPrepayRoutingFeePPM,
890+
defaultRoutingFeePPM, *quote,
891+
)
892+
chan2 := applyFeeCategoryQuote(
893+
chan2Rec, 5000, defaultPrepayRoutingFeePPM,
894+
defaultRoutingFeePPM, *quote,
895+
)
896+
841897
tests := []struct {
842898
name string
843899

@@ -862,7 +918,7 @@ func TestFeeBudget(t *testing.T) {
862918
maxMinerFee: 5000,
863919
suggestions: &Suggestions{
864920
OutSwaps: []loop.OutRequest{
865-
chan1Rec, chan2Rec,
921+
chan1, chan2,
866922
},
867923
DisqualifiedChans: noneDisqualified,
868924
DisqualifiedPeers: noPeersDisqualified,
@@ -876,7 +932,7 @@ func TestFeeBudget(t *testing.T) {
876932
maxMinerFee: 5000,
877933
suggestions: &Suggestions{
878934
OutSwaps: []loop.OutRequest{
879-
chan1Rec,
935+
chan1,
880936
},
881937
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
882938
chanID2: ReasonBudgetInsufficient,
@@ -895,7 +951,7 @@ func TestFeeBudget(t *testing.T) {
895951
},
896952
suggestions: &Suggestions{
897953
OutSwaps: []loop.OutRequest{
898-
chan1Rec, chan2Rec,
954+
chan1, chan2,
899955
},
900956
DisqualifiedChans: noneDisqualified,
901957
DisqualifiedPeers: noPeersDisqualified,
@@ -912,7 +968,7 @@ func TestFeeBudget(t *testing.T) {
912968
},
913969
suggestions: &Suggestions{
914970
OutSwaps: []loop.OutRequest{
915-
chan1Rec,
971+
chan1,
916972
},
917973
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
918974
chanID2: ReasonBudgetInsufficient,
@@ -977,6 +1033,13 @@ func TestFeeBudget(t *testing.T) {
9771033
return swaps, nil
9781034
}
9791035

1036+
cfg.LoopOutQuote = func(_ context.Context,
1037+
_ *loop.LoopOutQuoteRequest) (*loop.LoopOutQuote,
1038+
error) {
1039+
1040+
return quote, nil
1041+
}
1042+
9801043
// Set two channels that need swaps.
9811044
lnd.Channels = []lndclient.ChannelInfo{
9821045
channel1,
@@ -1141,18 +1204,17 @@ func TestSizeRestrictions(t *testing.T) {
11411204
Maximum: 10000,
11421205
}
11431206

1144-
outSwap = loop.OutRequest{
1207+
prepay, routing = testPPMFees(defaultFeePPM, testQuote, 7000)
1208+
outSwap = loop.OutRequest{
11451209
Amount: 7000,
11461210
OutgoingChanSet: loopdb.ChannelSet{chanID1.ToUint64()},
1147-
MaxPrepayRoutingFee: prepayFee,
1148-
MaxSwapRoutingFee: ppmToSat(
1149-
7000, defaultRoutingFeePPM,
1150-
),
1151-
MaxMinerFee: defaultMaximumMinerFee,
1152-
MaxSwapFee: testQuote.SwapFee,
1153-
MaxPrepayAmount: testQuote.PrepayAmount,
1154-
SweepConfTarget: loop.DefaultSweepConfTarget,
1155-
Initiator: autoloopSwapInitiator,
1211+
MaxPrepayRoutingFee: prepay,
1212+
MaxSwapRoutingFee: routing,
1213+
MaxMinerFee: scaleMinerFee(testQuote.MinerFee),
1214+
MaxSwapFee: testQuote.SwapFee,
1215+
MaxPrepayAmount: testQuote.PrepayAmount,
1216+
SweepConfTarget: loop.DefaultSweepConfTarget,
1217+
Initiator: autoloopSwapInitiator,
11561218
}
11571219
)
11581220

0 commit comments

Comments
 (0)