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:
parent
299a0a4ff9
commit
d4b7f9a378
@ -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{
|
||||||
|
@ -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.
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user