mirror of
https://github.com/lightninglabs/loop.git
synced 2026-08-13 12:33:03 +02:00
Merge pull request #581 from GeorgeTsagk/fee-percentage-miner
liquidity: differentiate autoloop expected vs max miner fees
This commit is contained in:
commit
0a19485409
2 changed files with 64 additions and 28 deletions
|
|
@ -38,10 +38,14 @@ const (
|
|||
// sweep fees, (750 * 4 /1000 = 3 sat/vByte).
|
||||
defaultSweepFeeRateLimit = chainfee.SatPerKWeight(750)
|
||||
|
||||
// minerMultiplier is a multiplier we use to scale our miner fee to
|
||||
// ensure that we will still be able to complete our swap in the case
|
||||
// of a severe fee spike.
|
||||
minerMultiplier = 100
|
||||
// minerMultiplier is a multiplier we use to predict the average chain
|
||||
// costs towards miner fees.
|
||||
minerMultiplier = 2
|
||||
|
||||
// maxMinerMultiplier is the maximum multiplier we use to scale our
|
||||
// miner fee to ensure that we will still be able to complete our swap
|
||||
// in the case of a severe fee spike.
|
||||
maxMinerMultiplier = 50
|
||||
|
||||
// defaultFeePPM is the default percentage of swap amount that we
|
||||
// allocate to fees, 2%.
|
||||
|
|
@ -341,6 +345,12 @@ func (f *FeePortion) loopOutLimits(swapAmt btcutil.Amount,
|
|||
|
||||
prepay, route, miner := f.loopOutFees(swapAmt, quote)
|
||||
|
||||
// Before checking our fees against our budget we remove the large
|
||||
// multiplier from the miner fees. We do this because we want to
|
||||
// consider the average case for our budget calculations and not the
|
||||
// severe edge-case miner fees.
|
||||
miner = miner / maxMinerMultiplier
|
||||
|
||||
// Calculate the worst case fees that we could pay for this swap,
|
||||
// ensuring that we are within our fee limit even if the swap fails.
|
||||
fees := worstCaseOutFees(
|
||||
|
|
@ -370,6 +380,8 @@ func (f *FeePortion) loopOutFees(amount btcutil.Amount,
|
|||
// amounts provided by the quote to get the total available for
|
||||
// off-chain fees.
|
||||
feeLimit := ppmToSat(amount, f.PartsPerMillion)
|
||||
|
||||
// Apply the small miner multiplier for the fee budget calculations.
|
||||
minerFee := scaleMinerFee(quote.MinerFee)
|
||||
|
||||
available := feeLimit - minerFee - quote.SwapFee
|
||||
|
|
@ -378,6 +390,9 @@ func (f *FeePortion) loopOutFees(amount btcutil.Amount,
|
|||
available, quote.PrepayAmount, amount,
|
||||
)
|
||||
|
||||
// Apply the big miner multiplier to get the worst case miner fees.
|
||||
minerFee = scaleMaxMinerFee(minerFee)
|
||||
|
||||
return prepayMaxFee, routeMaxFee, minerFee
|
||||
}
|
||||
|
||||
|
|
@ -394,11 +409,20 @@ func splitOffChain(available, prepayAmt,
|
|||
return prepayMaxFee, routeMaxFee
|
||||
}
|
||||
|
||||
// scaleMinerFee scales our miner fee by our constant multiplier.
|
||||
// scaleMinerFee scales our miner fee by a smaller multiplier. This scale does
|
||||
// not represent the worst-case maximum miner fees, but the average expected
|
||||
// fees.
|
||||
func scaleMinerFee(estimate btcutil.Amount) btcutil.Amount {
|
||||
return estimate * btcutil.Amount(minerMultiplier)
|
||||
}
|
||||
|
||||
// scaleMaxMinerFee scales our miner fee by a big multiplier. The returned value
|
||||
// represents the maximum amount that we consider spending for miner fees in
|
||||
// worst-case scenarios (fee-spikes).
|
||||
func scaleMaxMinerFee(estimate btcutil.Amount) btcutil.Amount {
|
||||
return estimate * btcutil.Amount(maxMinerMultiplier)
|
||||
}
|
||||
|
||||
func (f *FeePortion) loopInLimits(amount btcutil.Amount,
|
||||
quote *loop.LoopInQuote) error {
|
||||
|
||||
|
|
|
|||
|
|
@ -73,11 +73,13 @@ var (
|
|||
OutgoingChanSet: loopdb.ChannelSet{chanID1.ToUint64()},
|
||||
MaxPrepayRoutingFee: prepayFee,
|
||||
MaxSwapRoutingFee: routingFee,
|
||||
MaxMinerFee: scaleMinerFee(testQuote.MinerFee),
|
||||
MaxSwapFee: testQuote.SwapFee,
|
||||
MaxPrepayAmount: testQuote.PrepayAmount,
|
||||
SweepConfTarget: defaultConfTarget,
|
||||
Initiator: autoloopSwapInitiator,
|
||||
MaxMinerFee: scaleMaxMinerFee(
|
||||
scaleMinerFee(testQuote.MinerFee),
|
||||
),
|
||||
MaxSwapFee: testQuote.SwapFee,
|
||||
MaxPrepayAmount: testQuote.PrepayAmount,
|
||||
SweepConfTarget: defaultConfTarget,
|
||||
Initiator: autoloopSwapInitiator,
|
||||
}
|
||||
|
||||
// chan2Rec is the suggested swap for channel 2 when we use chanRule.
|
||||
|
|
@ -86,11 +88,13 @@ var (
|
|||
OutgoingChanSet: loopdb.ChannelSet{chanID2.ToUint64()},
|
||||
MaxPrepayRoutingFee: prepayFee,
|
||||
MaxSwapRoutingFee: routingFee,
|
||||
MaxMinerFee: scaleMinerFee(testQuote.MinerFee),
|
||||
MaxPrepayAmount: testQuote.PrepayAmount,
|
||||
MaxSwapFee: testQuote.SwapFee,
|
||||
SweepConfTarget: defaultConfTarget,
|
||||
Initiator: autoloopSwapInitiator,
|
||||
MaxMinerFee: scaleMaxMinerFee(
|
||||
scaleMinerFee(testQuote.MinerFee),
|
||||
),
|
||||
MaxPrepayAmount: testQuote.PrepayAmount,
|
||||
MaxSwapFee: testQuote.SwapFee,
|
||||
SweepConfTarget: defaultConfTarget,
|
||||
Initiator: autoloopSwapInitiator,
|
||||
}
|
||||
|
||||
// chan1Out is a contract that uses channel 1, used to represent on
|
||||
|
|
@ -771,11 +775,13 @@ func TestSuggestSwaps(t *testing.T) {
|
|||
},
|
||||
MaxPrepayRoutingFee: prepay,
|
||||
MaxSwapRoutingFee: routing,
|
||||
MaxMinerFee: scaleMinerFee(testQuote.MinerFee),
|
||||
MaxSwapFee: testQuote.SwapFee,
|
||||
MaxPrepayAmount: testQuote.PrepayAmount,
|
||||
SweepConfTarget: defaultConfTarget,
|
||||
Initiator: autoloopSwapInitiator,
|
||||
MaxMinerFee: scaleMaxMinerFee(
|
||||
scaleMinerFee(testQuote.MinerFee),
|
||||
),
|
||||
MaxSwapFee: testQuote.SwapFee,
|
||||
MaxPrepayAmount: testQuote.PrepayAmount,
|
||||
SweepConfTarget: defaultConfTarget,
|
||||
Initiator: autoloopSwapInitiator,
|
||||
},
|
||||
},
|
||||
DisqualifiedChans: noneDisqualified,
|
||||
|
|
@ -1330,11 +1336,13 @@ func TestSizeRestrictions(t *testing.T) {
|
|||
OutgoingChanSet: loopdb.ChannelSet{chanID1.ToUint64()},
|
||||
MaxPrepayRoutingFee: prepay,
|
||||
MaxSwapRoutingFee: routing,
|
||||
MaxMinerFee: scaleMinerFee(testQuote.MinerFee),
|
||||
MaxSwapFee: testQuote.SwapFee,
|
||||
MaxPrepayAmount: testQuote.PrepayAmount,
|
||||
SweepConfTarget: defaultConfTarget,
|
||||
Initiator: autoloopSwapInitiator,
|
||||
MaxMinerFee: scaleMaxMinerFee(
|
||||
scaleMinerFee(testQuote.MinerFee),
|
||||
),
|
||||
MaxSwapFee: testQuote.SwapFee,
|
||||
MaxPrepayAmount: testQuote.PrepayAmount,
|
||||
SweepConfTarget: defaultConfTarget,
|
||||
Initiator: autoloopSwapInitiator,
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -1487,7 +1495,9 @@ func TestFeePercentage(t *testing.T) {
|
|||
rec = loop.OutRequest{
|
||||
Amount: 7500,
|
||||
OutgoingChanSet: loopdb.ChannelSet{chanID1.ToUint64()},
|
||||
MaxMinerFee: scaleMinerFee(okQuote.MinerFee),
|
||||
MaxMinerFee: scaleMaxMinerFee(
|
||||
scaleMinerFee(testQuote.MinerFee),
|
||||
),
|
||||
MaxSwapFee: okQuote.SwapFee,
|
||||
MaxPrepayAmount: okQuote.PrepayAmount,
|
||||
SweepConfTarget: defaultConfTarget,
|
||||
|
|
@ -1555,7 +1565,7 @@ func TestFeePercentage(t *testing.T) {
|
|||
quote: &loop.LoopOutQuote{
|
||||
SwapFee: 60,
|
||||
PrepayAmount: 30,
|
||||
MinerFee: 1,
|
||||
MinerFee: 50,
|
||||
},
|
||||
suggestions: &Suggestions{
|
||||
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
|
||||
|
|
@ -1650,7 +1660,9 @@ func TestBudgetWithLoopin(t *testing.T) {
|
|||
rec = loop.OutRequest{
|
||||
Amount: 7500,
|
||||
OutgoingChanSet: loopdb.ChannelSet{chanID1.ToUint64()},
|
||||
MaxMinerFee: scaleMinerFee(okQuote.MinerFee),
|
||||
MaxMinerFee: scaleMaxMinerFee(
|
||||
scaleMinerFee(testQuote.MinerFee),
|
||||
),
|
||||
MaxSwapFee: okQuote.SwapFee,
|
||||
MaxPrepayAmount: okQuote.PrepayAmount,
|
||||
SweepConfTarget: defaultConfTarget,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue