2
0
mirror of https://github.com/lightninglabs/loop synced 2024-11-09 19:10:47 +00:00

liquidity: update default fee setting to flat percentage

This commit is contained in:
carla 2021-03-02 14:42:06 +02:00
parent 299a0a4ff9
commit d4b7f9a378
No known key found for this signature in database
GPG Key ID: 4CA7FE54A6213C91
3 changed files with 113 additions and 41 deletions

View File

@ -42,6 +42,10 @@ const (
// ensure that we will still be able to complete our swap in the case // ensure that we will still be able to complete our swap in the case
// of a severe fee spike. // of a severe fee spike.
minerMultiplier = 100 minerMultiplier = 100
// defaultFeePPM is the default percentage of swap amount that we
// allocate to fees, 2%.
defaultFeePPM = 20000
) )
var ( var (
@ -245,6 +249,12 @@ type FeePortion struct {
PartsPerMillion uint64 PartsPerMillion uint64
} }
func defaultFeePortion() *FeePortion {
return &FeePortion{
PartsPerMillion: defaultFeePPM,
}
}
// NewFeePortion creates a fee limit based on a flat percentage of swap amount. // NewFeePortion creates a fee limit based on a flat percentage of swap amount.
func NewFeePortion(ppm uint64) *FeePortion { func NewFeePortion(ppm uint64) *FeePortion {
return &FeePortion{ return &FeePortion{

View File

@ -99,7 +99,7 @@ var (
PeerRules: make(map[route.Vertex]*ThresholdRule), PeerRules: make(map[route.Vertex]*ThresholdRule),
FailureBackOff: defaultFailureBackoff, FailureBackOff: defaultFailureBackoff,
SweepConfTarget: loop.DefaultSweepConfTarget, SweepConfTarget: loop.DefaultSweepConfTarget,
FeeLimit: defaultFeeCategoryLimit(), FeeLimit: defaultFeePortion(),
} }
// ErrZeroChannelID is returned if we get a rule for a 0 channel ID. // ErrZeroChannelID is returned if we get a rule for a 0 channel ID.

View File

@ -50,15 +50,12 @@ var (
chanRule = NewThresholdRule(50, 0) chanRule = NewThresholdRule(50, 0)
testQuote = &loop.LoopOutQuote{ testQuote = &loop.LoopOutQuote{
SwapFee: btcutil.Amount(1), SwapFee: btcutil.Amount(5),
PrepayAmount: btcutil.Amount(500), PrepayAmount: btcutil.Amount(50),
MinerFee: btcutil.Amount(50), MinerFee: btcutil.Amount(1),
} }
prepayFee = ppmToSat( prepayFee, routingFee = testPPMFees(defaultFeePPM, testQuote, 7500)
testQuote.PrepayAmount, defaultPrepayRoutingFeePPM,
)
routingFee = ppmToSat(7500, defaultRoutingFeePPM)
// chan1Rec is the suggested swap for channel 1 when we use chanRule. // chan1Rec is the suggested swap for channel 1 when we use chanRule.
chan1Rec = loop.OutRequest{ chan1Rec = loop.OutRequest{
@ -66,7 +63,7 @@ var (
OutgoingChanSet: loopdb.ChannelSet{chanID1.ToUint64()}, OutgoingChanSet: loopdb.ChannelSet{chanID1.ToUint64()},
MaxPrepayRoutingFee: prepayFee, MaxPrepayRoutingFee: prepayFee,
MaxSwapRoutingFee: routingFee, MaxSwapRoutingFee: routingFee,
MaxMinerFee: defaultMaximumMinerFee, MaxMinerFee: scaleMinerFee(testQuote.MinerFee),
MaxSwapFee: testQuote.SwapFee, MaxSwapFee: testQuote.SwapFee,
MaxPrepayAmount: testQuote.PrepayAmount, MaxPrepayAmount: testQuote.PrepayAmount,
SweepConfTarget: loop.DefaultSweepConfTarget, SweepConfTarget: loop.DefaultSweepConfTarget,
@ -79,7 +76,7 @@ var (
OutgoingChanSet: loopdb.ChannelSet{chanID2.ToUint64()}, OutgoingChanSet: loopdb.ChannelSet{chanID2.ToUint64()},
MaxPrepayRoutingFee: prepayFee, MaxPrepayRoutingFee: prepayFee,
MaxSwapRoutingFee: routingFee, MaxSwapRoutingFee: routingFee,
MaxMinerFee: defaultMaximumMinerFee, MaxMinerFee: scaleMinerFee(testQuote.MinerFee),
MaxPrepayAmount: testQuote.PrepayAmount, MaxPrepayAmount: testQuote.PrepayAmount,
MaxSwapFee: testQuote.SwapFee, MaxSwapFee: testQuote.SwapFee,
SweepConfTarget: loop.DefaultSweepConfTarget, SweepConfTarget: loop.DefaultSweepConfTarget,
@ -164,6 +161,21 @@ func testPPMFees(ppm uint64, quote *loop.LoopOutQuote,
) )
} }
// applyFeeCategoryQuote returns a copy of the loop out request provided with
// fee categories updated to the quote and routing settings provided.
// nolint:unparam
func applyFeeCategoryQuote(req loop.OutRequest, minerFee btcutil.Amount,
prepayPPM, routingPPM uint64, quote loop.LoopOutQuote) loop.OutRequest {
req.MaxPrepayRoutingFee = ppmToSat(quote.PrepayAmount, prepayPPM)
req.MaxSwapRoutingFee = ppmToSat(req.Amount, routingPPM)
req.MaxSwapFee = quote.SwapFee
req.MaxPrepayAmount = quote.PrepayAmount
req.MaxMinerFee = minerFee
return req
}
// TestParameters tests getting and setting of parameters for our manager. // TestParameters tests getting and setting of parameters for our manager.
func TestParameters(t *testing.T) { func TestParameters(t *testing.T) {
cfg, _ := newTestConfig() cfg, _ := newTestConfig()
@ -547,6 +559,12 @@ func TestRestrictedSuggestions(t *testing.T) {
// TestSweepFeeLimit tests getting of swap suggestions when our estimated sweep // TestSweepFeeLimit tests getting of swap suggestions when our estimated sweep
// fee is above and below the configured limit. // fee is above and below the configured limit.
func TestSweepFeeLimit(t *testing.T) { func TestSweepFeeLimit(t *testing.T) {
quote := &loop.LoopOutQuote{
SwapFee: btcutil.Amount(1),
PrepayAmount: btcutil.Amount(500),
MinerFee: btcutil.Amount(50),
}
tests := []struct { tests := []struct {
name string name string
feeRate chainfee.SatPerKWeight feeRate chainfee.SatPerKWeight
@ -557,7 +575,11 @@ func TestSweepFeeLimit(t *testing.T) {
feeRate: defaultSweepFeeRateLimit, feeRate: defaultSweepFeeRateLimit,
suggestions: &Suggestions{ suggestions: &Suggestions{
OutSwaps: []loop.OutRequest{ OutSwaps: []loop.OutRequest{
chan1Rec, applyFeeCategoryQuote(
chan1Rec, defaultMaximumMinerFee,
defaultPrepayRoutingFeePPM,
defaultRoutingFeePPM, *quote,
),
}, },
DisqualifiedChans: noneDisqualified, DisqualifiedChans: noneDisqualified,
DisqualifiedPeers: noPeersDisqualified, DisqualifiedPeers: noPeersDisqualified,
@ -581,6 +603,13 @@ func TestSweepFeeLimit(t *testing.T) {
t.Run(testCase.name, func(t *testing.T) { t.Run(testCase.name, func(t *testing.T) {
cfg, lnd := newTestConfig() cfg, lnd := newTestConfig()
cfg.LoopOutQuote = func(_ context.Context,
_ *loop.LoopOutQuoteRequest) (*loop.LoopOutQuote,
error) {
return quote, nil
}
// Set our test case's fee rate for our mock lnd. // Set our test case's fee rate for our mock lnd.
lnd.SetFeeEstimate( lnd.SetFeeEstimate(
loop.DefaultSweepConfTarget, testCase.feeRate, loop.DefaultSweepConfTarget, testCase.feeRate,
@ -591,6 +620,8 @@ func TestSweepFeeLimit(t *testing.T) {
} }
params := defaultParameters params := defaultParameters
params.FeeLimit = defaultFeeCategoryLimit()
params.ChannelRules = map[lnwire.ShortChannelID]*ThresholdRule{ params.ChannelRules = map[lnwire.ShortChannelID]*ThresholdRule{
chanID1: chanRule, chanID1: chanRule,
} }
@ -610,6 +641,9 @@ func TestSuggestSwaps(t *testing.T) {
channel1, channel1,
} }
expectedAmt := btcutil.Amount(10000)
prepay, routing := testPPMFees(defaultFeePPM, testQuote, expectedAmt)
tests := []struct { tests := []struct {
name string name string
channels []lndclient.ChannelInfo channels []lndclient.ChannelInfo
@ -681,20 +715,14 @@ func TestSuggestSwaps(t *testing.T) {
suggestions: &Suggestions{ suggestions: &Suggestions{
OutSwaps: []loop.OutRequest{ OutSwaps: []loop.OutRequest{
{ {
Amount: 10000, Amount: expectedAmt,
OutgoingChanSet: loopdb.ChannelSet{ OutgoingChanSet: loopdb.ChannelSet{
chanID1.ToUint64(), chanID1.ToUint64(),
chanID2.ToUint64(), chanID2.ToUint64(),
}, },
MaxPrepayRoutingFee: ppmToSat( MaxPrepayRoutingFee: prepay,
testQuote.PrepayAmount, MaxSwapRoutingFee: routing,
defaultPrepayRoutingFeePPM, MaxMinerFee: scaleMinerFee(testQuote.MinerFee),
),
MaxSwapRoutingFee: ppmToSat(
10000,
defaultRoutingFeePPM,
),
MaxMinerFee: defaultMaximumMinerFee,
MaxSwapFee: testQuote.SwapFee, MaxSwapFee: testQuote.SwapFee,
MaxPrepayAmount: testQuote.PrepayAmount, MaxPrepayAmount: testQuote.PrepayAmount,
SweepConfTarget: loop.DefaultSweepConfTarget, SweepConfTarget: loop.DefaultSweepConfTarget,
@ -736,6 +764,12 @@ func TestSuggestSwaps(t *testing.T) {
// TestFeeLimits tests limiting of swap suggestions by fees. // TestFeeLimits tests limiting of swap suggestions by fees.
func TestFeeLimits(t *testing.T) { func TestFeeLimits(t *testing.T) {
quote := &loop.LoopOutQuote{
SwapFee: btcutil.Amount(1),
PrepayAmount: btcutil.Amount(500),
MinerFee: btcutil.Amount(50),
}
tests := []struct { tests := []struct {
name string name string
quote *loop.LoopOutQuote quote *loop.LoopOutQuote
@ -743,10 +777,14 @@ func TestFeeLimits(t *testing.T) {
}{ }{
{ {
name: "fees ok", name: "fees ok",
quote: testQuote, quote: quote,
suggestions: &Suggestions{ suggestions: &Suggestions{
OutSwaps: []loop.OutRequest{ OutSwaps: []loop.OutRequest{
chan1Rec, applyFeeCategoryQuote(
chan1Rec, defaultMaximumMinerFee,
defaultPrepayRoutingFeePPM,
defaultRoutingFeePPM, *quote,
),
}, },
DisqualifiedChans: noneDisqualified, DisqualifiedChans: noneDisqualified,
DisqualifiedPeers: noPeersDisqualified, DisqualifiedPeers: noPeersDisqualified,
@ -813,7 +851,10 @@ func TestFeeLimits(t *testing.T) {
channel1, channel1,
} }
// Set our params to use individual fee limits.
params := defaultParameters params := defaultParameters
params.FeeLimit = defaultFeeCategoryLimit()
params.ChannelRules = map[lnwire.ShortChannelID]*ThresholdRule{ params.ChannelRules = map[lnwire.ShortChannelID]*ThresholdRule{
chanID1: chanRule, chanID1: chanRule,
} }
@ -838,6 +879,21 @@ func TestFeeLimits(t *testing.T) {
// amounts, we use our max miner fee to shift swap cost to values above/below // amounts, we use our max miner fee to shift swap cost to values above/below
// our budget, fixing our other fees at 114 sat for simplicity. // our budget, fixing our other fees at 114 sat for simplicity.
func TestFeeBudget(t *testing.T) { func TestFeeBudget(t *testing.T) {
quote := &loop.LoopOutQuote{
SwapFee: btcutil.Amount(1),
PrepayAmount: btcutil.Amount(500),
MinerFee: btcutil.Amount(50),
}
chan1 := applyFeeCategoryQuote(
chan1Rec, 5000, defaultPrepayRoutingFeePPM,
defaultRoutingFeePPM, *quote,
)
chan2 := applyFeeCategoryQuote(
chan2Rec, 5000, defaultPrepayRoutingFeePPM,
defaultRoutingFeePPM, *quote,
)
tests := []struct { tests := []struct {
name string name string
@ -862,7 +918,7 @@ func TestFeeBudget(t *testing.T) {
maxMinerFee: 5000, maxMinerFee: 5000,
suggestions: &Suggestions{ suggestions: &Suggestions{
OutSwaps: []loop.OutRequest{ OutSwaps: []loop.OutRequest{
chan1Rec, chan2Rec, chan1, chan2,
}, },
DisqualifiedChans: noneDisqualified, DisqualifiedChans: noneDisqualified,
DisqualifiedPeers: noPeersDisqualified, DisqualifiedPeers: noPeersDisqualified,
@ -876,7 +932,7 @@ func TestFeeBudget(t *testing.T) {
maxMinerFee: 5000, maxMinerFee: 5000,
suggestions: &Suggestions{ suggestions: &Suggestions{
OutSwaps: []loop.OutRequest{ OutSwaps: []loop.OutRequest{
chan1Rec, chan1,
}, },
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{ DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
chanID2: ReasonBudgetInsufficient, chanID2: ReasonBudgetInsufficient,
@ -895,7 +951,7 @@ func TestFeeBudget(t *testing.T) {
}, },
suggestions: &Suggestions{ suggestions: &Suggestions{
OutSwaps: []loop.OutRequest{ OutSwaps: []loop.OutRequest{
chan1Rec, chan2Rec, chan1, chan2,
}, },
DisqualifiedChans: noneDisqualified, DisqualifiedChans: noneDisqualified,
DisqualifiedPeers: noPeersDisqualified, DisqualifiedPeers: noPeersDisqualified,
@ -912,7 +968,7 @@ func TestFeeBudget(t *testing.T) {
}, },
suggestions: &Suggestions{ suggestions: &Suggestions{
OutSwaps: []loop.OutRequest{ OutSwaps: []loop.OutRequest{
chan1Rec, chan1,
}, },
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{ DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
chanID2: ReasonBudgetInsufficient, chanID2: ReasonBudgetInsufficient,
@ -977,6 +1033,13 @@ func TestFeeBudget(t *testing.T) {
return swaps, nil return swaps, nil
} }
cfg.LoopOutQuote = func(_ context.Context,
_ *loop.LoopOutQuoteRequest) (*loop.LoopOutQuote,
error) {
return quote, nil
}
// Set two channels that need swaps. // Set two channels that need swaps.
lnd.Channels = []lndclient.ChannelInfo{ lnd.Channels = []lndclient.ChannelInfo{
channel1, channel1,
@ -1141,14 +1204,13 @@ func TestSizeRestrictions(t *testing.T) {
Maximum: 10000, Maximum: 10000,
} }
prepay, routing = testPPMFees(defaultFeePPM, testQuote, 7000)
outSwap = loop.OutRequest{ outSwap = loop.OutRequest{
Amount: 7000, Amount: 7000,
OutgoingChanSet: loopdb.ChannelSet{chanID1.ToUint64()}, OutgoingChanSet: loopdb.ChannelSet{chanID1.ToUint64()},
MaxPrepayRoutingFee: prepayFee, MaxPrepayRoutingFee: prepay,
MaxSwapRoutingFee: ppmToSat( MaxSwapRoutingFee: routing,
7000, defaultRoutingFeePPM, MaxMinerFee: scaleMinerFee(testQuote.MinerFee),
),
MaxMinerFee: defaultMaximumMinerFee,
MaxSwapFee: testQuote.SwapFee, MaxSwapFee: testQuote.SwapFee,
MaxPrepayAmount: testQuote.PrepayAmount, MaxPrepayAmount: testQuote.PrepayAmount,
SweepConfTarget: loop.DefaultSweepConfTarget, SweepConfTarget: loop.DefaultSweepConfTarget,