mirror of
https://github.com/lightninglabs/loop.git
synced 2026-08-13 12:33:03 +02:00
liquidity: update default fee setting to flat percentage
This commit is contained in:
parent
299a0a4ff9
commit
d4b7f9a378
3 changed files with 113 additions and 41 deletions
|
|
@ -42,6 +42,10 @@ const (
|
|||
// ensure that we will still be able to complete our swap in the case
|
||||
// of a severe fee spike.
|
||||
minerMultiplier = 100
|
||||
|
||||
// defaultFeePPM is the default percentage of swap amount that we
|
||||
// allocate to fees, 2%.
|
||||
defaultFeePPM = 20000
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -245,6 +249,12 @@ type FeePortion struct {
|
|||
PartsPerMillion uint64
|
||||
}
|
||||
|
||||
func defaultFeePortion() *FeePortion {
|
||||
return &FeePortion{
|
||||
PartsPerMillion: defaultFeePPM,
|
||||
}
|
||||
}
|
||||
|
||||
// NewFeePortion creates a fee limit based on a flat percentage of swap amount.
|
||||
func NewFeePortion(ppm uint64) *FeePortion {
|
||||
return &FeePortion{
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ var (
|
|||
PeerRules: make(map[route.Vertex]*ThresholdRule),
|
||||
FailureBackOff: defaultFailureBackoff,
|
||||
SweepConfTarget: loop.DefaultSweepConfTarget,
|
||||
FeeLimit: defaultFeeCategoryLimit(),
|
||||
FeeLimit: defaultFeePortion(),
|
||||
}
|
||||
|
||||
// ErrZeroChannelID is returned if we get a rule for a 0 channel ID.
|
||||
|
|
|
|||
|
|
@ -50,15 +50,12 @@ var (
|
|||
chanRule = NewThresholdRule(50, 0)
|
||||
|
||||
testQuote = &loop.LoopOutQuote{
|
||||
SwapFee: btcutil.Amount(1),
|
||||
PrepayAmount: btcutil.Amount(500),
|
||||
MinerFee: btcutil.Amount(50),
|
||||
SwapFee: btcutil.Amount(5),
|
||||
PrepayAmount: btcutil.Amount(50),
|
||||
MinerFee: btcutil.Amount(1),
|
||||
}
|
||||
|
||||
prepayFee = ppmToSat(
|
||||
testQuote.PrepayAmount, defaultPrepayRoutingFeePPM,
|
||||
)
|
||||
routingFee = ppmToSat(7500, defaultRoutingFeePPM)
|
||||
prepayFee, routingFee = testPPMFees(defaultFeePPM, testQuote, 7500)
|
||||
|
||||
// chan1Rec is the suggested swap for channel 1 when we use chanRule.
|
||||
chan1Rec = loop.OutRequest{
|
||||
|
|
@ -66,7 +63,7 @@ var (
|
|||
OutgoingChanSet: loopdb.ChannelSet{chanID1.ToUint64()},
|
||||
MaxPrepayRoutingFee: prepayFee,
|
||||
MaxSwapRoutingFee: routingFee,
|
||||
MaxMinerFee: defaultMaximumMinerFee,
|
||||
MaxMinerFee: scaleMinerFee(testQuote.MinerFee),
|
||||
MaxSwapFee: testQuote.SwapFee,
|
||||
MaxPrepayAmount: testQuote.PrepayAmount,
|
||||
SweepConfTarget: loop.DefaultSweepConfTarget,
|
||||
|
|
@ -79,7 +76,7 @@ var (
|
|||
OutgoingChanSet: loopdb.ChannelSet{chanID2.ToUint64()},
|
||||
MaxPrepayRoutingFee: prepayFee,
|
||||
MaxSwapRoutingFee: routingFee,
|
||||
MaxMinerFee: defaultMaximumMinerFee,
|
||||
MaxMinerFee: scaleMinerFee(testQuote.MinerFee),
|
||||
MaxPrepayAmount: testQuote.PrepayAmount,
|
||||
MaxSwapFee: testQuote.SwapFee,
|
||||
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.
|
||||
func TestParameters(t *testing.T) {
|
||||
cfg, _ := newTestConfig()
|
||||
|
|
@ -547,6 +559,12 @@ func TestRestrictedSuggestions(t *testing.T) {
|
|||
// TestSweepFeeLimit tests getting of swap suggestions when our estimated sweep
|
||||
// fee is above and below the configured limit.
|
||||
func TestSweepFeeLimit(t *testing.T) {
|
||||
quote := &loop.LoopOutQuote{
|
||||
SwapFee: btcutil.Amount(1),
|
||||
PrepayAmount: btcutil.Amount(500),
|
||||
MinerFee: btcutil.Amount(50),
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
feeRate chainfee.SatPerKWeight
|
||||
|
|
@ -557,7 +575,11 @@ func TestSweepFeeLimit(t *testing.T) {
|
|||
feeRate: defaultSweepFeeRateLimit,
|
||||
suggestions: &Suggestions{
|
||||
OutSwaps: []loop.OutRequest{
|
||||
chan1Rec,
|
||||
applyFeeCategoryQuote(
|
||||
chan1Rec, defaultMaximumMinerFee,
|
||||
defaultPrepayRoutingFeePPM,
|
||||
defaultRoutingFeePPM, *quote,
|
||||
),
|
||||
},
|
||||
DisqualifiedChans: noneDisqualified,
|
||||
DisqualifiedPeers: noPeersDisqualified,
|
||||
|
|
@ -581,6 +603,13 @@ func TestSweepFeeLimit(t *testing.T) {
|
|||
t.Run(testCase.name, func(t *testing.T) {
|
||||
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.
|
||||
lnd.SetFeeEstimate(
|
||||
loop.DefaultSweepConfTarget, testCase.feeRate,
|
||||
|
|
@ -591,6 +620,8 @@ func TestSweepFeeLimit(t *testing.T) {
|
|||
}
|
||||
|
||||
params := defaultParameters
|
||||
params.FeeLimit = defaultFeeCategoryLimit()
|
||||
|
||||
params.ChannelRules = map[lnwire.ShortChannelID]*ThresholdRule{
|
||||
chanID1: chanRule,
|
||||
}
|
||||
|
|
@ -610,6 +641,9 @@ func TestSuggestSwaps(t *testing.T) {
|
|||
channel1,
|
||||
}
|
||||
|
||||
expectedAmt := btcutil.Amount(10000)
|
||||
prepay, routing := testPPMFees(defaultFeePPM, testQuote, expectedAmt)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
channels []lndclient.ChannelInfo
|
||||
|
|
@ -681,24 +715,18 @@ func TestSuggestSwaps(t *testing.T) {
|
|||
suggestions: &Suggestions{
|
||||
OutSwaps: []loop.OutRequest{
|
||||
{
|
||||
Amount: 10000,
|
||||
Amount: expectedAmt,
|
||||
OutgoingChanSet: loopdb.ChannelSet{
|
||||
chanID1.ToUint64(),
|
||||
chanID2.ToUint64(),
|
||||
},
|
||||
MaxPrepayRoutingFee: ppmToSat(
|
||||
testQuote.PrepayAmount,
|
||||
defaultPrepayRoutingFeePPM,
|
||||
),
|
||||
MaxSwapRoutingFee: ppmToSat(
|
||||
10000,
|
||||
defaultRoutingFeePPM,
|
||||
),
|
||||
MaxMinerFee: defaultMaximumMinerFee,
|
||||
MaxSwapFee: testQuote.SwapFee,
|
||||
MaxPrepayAmount: testQuote.PrepayAmount,
|
||||
SweepConfTarget: loop.DefaultSweepConfTarget,
|
||||
Initiator: autoloopSwapInitiator,
|
||||
MaxPrepayRoutingFee: prepay,
|
||||
MaxSwapRoutingFee: routing,
|
||||
MaxMinerFee: scaleMinerFee(testQuote.MinerFee),
|
||||
MaxSwapFee: testQuote.SwapFee,
|
||||
MaxPrepayAmount: testQuote.PrepayAmount,
|
||||
SweepConfTarget: loop.DefaultSweepConfTarget,
|
||||
Initiator: autoloopSwapInitiator,
|
||||
},
|
||||
},
|
||||
DisqualifiedChans: noneDisqualified,
|
||||
|
|
@ -736,6 +764,12 @@ func TestSuggestSwaps(t *testing.T) {
|
|||
|
||||
// TestFeeLimits tests limiting of swap suggestions by fees.
|
||||
func TestFeeLimits(t *testing.T) {
|
||||
quote := &loop.LoopOutQuote{
|
||||
SwapFee: btcutil.Amount(1),
|
||||
PrepayAmount: btcutil.Amount(500),
|
||||
MinerFee: btcutil.Amount(50),
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
quote *loop.LoopOutQuote
|
||||
|
|
@ -743,10 +777,14 @@ func TestFeeLimits(t *testing.T) {
|
|||
}{
|
||||
{
|
||||
name: "fees ok",
|
||||
quote: testQuote,
|
||||
quote: quote,
|
||||
suggestions: &Suggestions{
|
||||
OutSwaps: []loop.OutRequest{
|
||||
chan1Rec,
|
||||
applyFeeCategoryQuote(
|
||||
chan1Rec, defaultMaximumMinerFee,
|
||||
defaultPrepayRoutingFeePPM,
|
||||
defaultRoutingFeePPM, *quote,
|
||||
),
|
||||
},
|
||||
DisqualifiedChans: noneDisqualified,
|
||||
DisqualifiedPeers: noPeersDisqualified,
|
||||
|
|
@ -813,7 +851,10 @@ func TestFeeLimits(t *testing.T) {
|
|||
channel1,
|
||||
}
|
||||
|
||||
// Set our params to use individual fee limits.
|
||||
params := defaultParameters
|
||||
params.FeeLimit = defaultFeeCategoryLimit()
|
||||
|
||||
params.ChannelRules = map[lnwire.ShortChannelID]*ThresholdRule{
|
||||
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
|
||||
// our budget, fixing our other fees at 114 sat for simplicity.
|
||||
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 {
|
||||
name string
|
||||
|
||||
|
|
@ -862,7 +918,7 @@ func TestFeeBudget(t *testing.T) {
|
|||
maxMinerFee: 5000,
|
||||
suggestions: &Suggestions{
|
||||
OutSwaps: []loop.OutRequest{
|
||||
chan1Rec, chan2Rec,
|
||||
chan1, chan2,
|
||||
},
|
||||
DisqualifiedChans: noneDisqualified,
|
||||
DisqualifiedPeers: noPeersDisqualified,
|
||||
|
|
@ -876,7 +932,7 @@ func TestFeeBudget(t *testing.T) {
|
|||
maxMinerFee: 5000,
|
||||
suggestions: &Suggestions{
|
||||
OutSwaps: []loop.OutRequest{
|
||||
chan1Rec,
|
||||
chan1,
|
||||
},
|
||||
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
|
||||
chanID2: ReasonBudgetInsufficient,
|
||||
|
|
@ -895,7 +951,7 @@ func TestFeeBudget(t *testing.T) {
|
|||
},
|
||||
suggestions: &Suggestions{
|
||||
OutSwaps: []loop.OutRequest{
|
||||
chan1Rec, chan2Rec,
|
||||
chan1, chan2,
|
||||
},
|
||||
DisqualifiedChans: noneDisqualified,
|
||||
DisqualifiedPeers: noPeersDisqualified,
|
||||
|
|
@ -912,7 +968,7 @@ func TestFeeBudget(t *testing.T) {
|
|||
},
|
||||
suggestions: &Suggestions{
|
||||
OutSwaps: []loop.OutRequest{
|
||||
chan1Rec,
|
||||
chan1,
|
||||
},
|
||||
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
|
||||
chanID2: ReasonBudgetInsufficient,
|
||||
|
|
@ -977,6 +1033,13 @@ func TestFeeBudget(t *testing.T) {
|
|||
return swaps, nil
|
||||
}
|
||||
|
||||
cfg.LoopOutQuote = func(_ context.Context,
|
||||
_ *loop.LoopOutQuoteRequest) (*loop.LoopOutQuote,
|
||||
error) {
|
||||
|
||||
return quote, nil
|
||||
}
|
||||
|
||||
// Set two channels that need swaps.
|
||||
lnd.Channels = []lndclient.ChannelInfo{
|
||||
channel1,
|
||||
|
|
@ -1141,18 +1204,17 @@ func TestSizeRestrictions(t *testing.T) {
|
|||
Maximum: 10000,
|
||||
}
|
||||
|
||||
outSwap = loop.OutRequest{
|
||||
prepay, routing = testPPMFees(defaultFeePPM, testQuote, 7000)
|
||||
outSwap = loop.OutRequest{
|
||||
Amount: 7000,
|
||||
OutgoingChanSet: loopdb.ChannelSet{chanID1.ToUint64()},
|
||||
MaxPrepayRoutingFee: prepayFee,
|
||||
MaxSwapRoutingFee: ppmToSat(
|
||||
7000, defaultRoutingFeePPM,
|
||||
),
|
||||
MaxMinerFee: defaultMaximumMinerFee,
|
||||
MaxSwapFee: testQuote.SwapFee,
|
||||
MaxPrepayAmount: testQuote.PrepayAmount,
|
||||
SweepConfTarget: loop.DefaultSweepConfTarget,
|
||||
Initiator: autoloopSwapInitiator,
|
||||
MaxPrepayRoutingFee: prepay,
|
||||
MaxSwapRoutingFee: routing,
|
||||
MaxMinerFee: scaleMinerFee(testQuote.MinerFee),
|
||||
MaxSwapFee: testQuote.SwapFee,
|
||||
MaxPrepayAmount: testQuote.PrepayAmount,
|
||||
SweepConfTarget: loop.DefaultSweepConfTarget,
|
||||
Initiator: autoloopSwapInitiator,
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue