2020-09-01 07:58:08 +00:00
|
|
|
package liquidity
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"testing"
|
2020-09-30 10:34:05 +00:00
|
|
|
"time"
|
2020-09-01 07:58:08 +00:00
|
|
|
|
2020-09-30 10:34:09 +00:00
|
|
|
"github.com/btcsuite/btcutil"
|
2020-09-03 08:36:43 +00:00
|
|
|
"github.com/lightninglabs/lndclient"
|
2020-09-30 10:34:02 +00:00
|
|
|
"github.com/lightninglabs/loop"
|
|
|
|
"github.com/lightninglabs/loop/loopdb"
|
2020-09-03 08:36:43 +00:00
|
|
|
"github.com/lightninglabs/loop/test"
|
2020-09-30 10:34:05 +00:00
|
|
|
"github.com/lightningnetwork/lnd/clock"
|
2020-09-30 10:34:08 +00:00
|
|
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
2020-09-01 07:58:08 +00:00
|
|
|
"github.com/lightningnetwork/lnd/lnwire"
|
2020-09-30 10:34:07 +00:00
|
|
|
"github.com/lightningnetwork/lnd/routing/route"
|
2020-09-01 07:58:08 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
2020-09-30 10:34:02 +00:00
|
|
|
var (
|
2020-09-30 10:34:05 +00:00
|
|
|
testTime = time.Date(2020, 02, 13, 0, 0, 0, 0, time.UTC)
|
|
|
|
|
2020-09-30 10:34:02 +00:00
|
|
|
chanID1 = lnwire.NewShortChanIDFromInt(1)
|
|
|
|
chanID2 = lnwire.NewShortChanIDFromInt(2)
|
|
|
|
|
2020-09-30 10:34:07 +00:00
|
|
|
peer1 = route.Vertex{1}
|
|
|
|
peer2 = route.Vertex{2}
|
|
|
|
|
2020-09-30 10:34:02 +00:00
|
|
|
channel1 = lndclient.ChannelInfo{
|
|
|
|
ChannelID: chanID1.ToUint64(),
|
2020-09-30 10:34:07 +00:00
|
|
|
PubKeyBytes: peer1,
|
|
|
|
LocalBalance: 10000,
|
|
|
|
RemoteBalance: 0,
|
|
|
|
Capacity: 10000,
|
|
|
|
}
|
|
|
|
|
|
|
|
channel2 = lndclient.ChannelInfo{
|
|
|
|
ChannelID: chanID2.ToUint64(),
|
|
|
|
PubKeyBytes: peer2,
|
2020-09-30 10:34:02 +00:00
|
|
|
LocalBalance: 10000,
|
|
|
|
RemoteBalance: 0,
|
|
|
|
Capacity: 10000,
|
|
|
|
}
|
|
|
|
|
|
|
|
// chanRule is a rule that produces chan1Rec.
|
|
|
|
chanRule = NewThresholdRule(50, 0)
|
|
|
|
|
2020-09-30 10:34:09 +00:00
|
|
|
testQuote = &loop.LoopOutQuote{
|
|
|
|
SwapFee: btcutil.Amount(1),
|
|
|
|
PrepayAmount: btcutil.Amount(500),
|
|
|
|
MinerFee: btcutil.Amount(50),
|
|
|
|
}
|
|
|
|
|
2020-09-30 10:34:02 +00:00
|
|
|
prepayFee = ppmToSat(
|
2020-09-30 10:34:09 +00:00
|
|
|
testQuote.PrepayAmount, defaultPrepayRoutingFeePPM,
|
2020-09-30 10:34:02 +00:00
|
|
|
)
|
|
|
|
routingFee = ppmToSat(7500, defaultRoutingFeePPM)
|
|
|
|
|
|
|
|
// chan1Rec is the suggested swap for channel 1 when we use chanRule.
|
|
|
|
chan1Rec = loop.OutRequest{
|
|
|
|
Amount: 7500,
|
|
|
|
OutgoingChanSet: loopdb.ChannelSet{chanID1.ToUint64()},
|
|
|
|
MaxPrepayRoutingFee: prepayFee,
|
|
|
|
MaxSwapRoutingFee: routingFee,
|
|
|
|
MaxMinerFee: defaultMaximumMinerFee,
|
2020-09-30 10:34:09 +00:00
|
|
|
MaxSwapFee: testQuote.SwapFee,
|
|
|
|
MaxPrepayAmount: testQuote.PrepayAmount,
|
2020-09-30 10:34:02 +00:00
|
|
|
SweepConfTarget: loop.DefaultSweepConfTarget,
|
|
|
|
}
|
2020-09-30 10:34:07 +00:00
|
|
|
|
|
|
|
// chan2Rec is the suggested swap for channel 2 when we use chanRule.
|
|
|
|
chan2Rec = loop.OutRequest{
|
|
|
|
Amount: 7500,
|
|
|
|
OutgoingChanSet: loopdb.ChannelSet{chanID2.ToUint64()},
|
|
|
|
MaxPrepayRoutingFee: prepayFee,
|
|
|
|
MaxSwapRoutingFee: routingFee,
|
|
|
|
MaxMinerFee: defaultMaximumMinerFee,
|
2020-09-30 10:34:09 +00:00
|
|
|
MaxPrepayAmount: testQuote.PrepayAmount,
|
|
|
|
MaxSwapFee: testQuote.SwapFee,
|
2020-09-30 10:34:07 +00:00
|
|
|
SweepConfTarget: loop.DefaultSweepConfTarget,
|
|
|
|
}
|
|
|
|
|
|
|
|
// chan1Out is a contract that uses channel 1, used to represent on
|
|
|
|
// disk swap using chan 1.
|
|
|
|
chan1Out = &loopdb.LoopOutContract{
|
|
|
|
OutgoingChanSet: loopdb.ChannelSet(
|
|
|
|
[]uint64{
|
|
|
|
chanID1.ToUint64(),
|
|
|
|
},
|
|
|
|
),
|
|
|
|
}
|
2020-09-30 10:34:02 +00:00
|
|
|
)
|
|
|
|
|
2020-09-01 07:58:08 +00:00
|
|
|
// newTestConfig creates a default test config.
|
2020-09-30 10:34:02 +00:00
|
|
|
func newTestConfig() (*Config, *test.LndMockServices) {
|
|
|
|
lnd := test.NewMockLnd()
|
|
|
|
|
2020-09-30 10:34:08 +00:00
|
|
|
// Set our fee estimate for the default number of confirmations to our
|
|
|
|
// limit so that our fees will be ok by default.
|
|
|
|
lnd.SetFeeEstimate(
|
|
|
|
defaultParameters.SweepConfTarget,
|
|
|
|
defaultParameters.SweepFeeRateLimit,
|
|
|
|
)
|
|
|
|
|
2020-09-01 07:58:08 +00:00
|
|
|
return &Config{
|
|
|
|
LoopOutRestrictions: func(_ context.Context) (*Restrictions,
|
|
|
|
error) {
|
|
|
|
|
|
|
|
return NewRestrictions(1, 10000), nil
|
|
|
|
},
|
2020-09-30 10:34:05 +00:00
|
|
|
Lnd: &lnd.LndServices,
|
|
|
|
Clock: clock.NewTestClock(testTime),
|
2020-09-30 10:34:07 +00:00
|
|
|
ListLoopOut: func() ([]*loopdb.LoopOut, error) {
|
|
|
|
return nil, nil
|
|
|
|
},
|
|
|
|
ListLoopIn: func() ([]*loopdb.LoopIn, error) {
|
|
|
|
return nil, nil
|
|
|
|
},
|
2020-09-30 10:34:09 +00:00
|
|
|
LoopOutQuote: func(_ context.Context,
|
|
|
|
_ *loop.LoopOutQuoteRequest) (*loop.LoopOutQuote,
|
|
|
|
error) {
|
|
|
|
|
|
|
|
return testQuote, nil
|
|
|
|
},
|
2020-09-30 10:34:02 +00:00
|
|
|
}, lnd
|
2020-09-01 07:58:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TestParameters tests getting and setting of parameters for our manager.
|
|
|
|
func TestParameters(t *testing.T) {
|
2020-09-30 10:34:02 +00:00
|
|
|
cfg, _ := newTestConfig()
|
|
|
|
manager := NewManager(cfg)
|
2020-09-01 07:58:08 +00:00
|
|
|
|
|
|
|
chanID := lnwire.NewShortChanIDFromInt(1)
|
|
|
|
|
|
|
|
// Start with the case where we have no rules set.
|
|
|
|
startParams := manager.GetParameters()
|
2020-09-30 10:34:06 +00:00
|
|
|
require.Equal(t, defaultParameters, startParams)
|
2020-09-01 07:58:08 +00:00
|
|
|
|
|
|
|
// Mutate the parameters returned by our get function.
|
|
|
|
startParams.ChannelRules[chanID] = NewThresholdRule(1, 1)
|
|
|
|
|
|
|
|
// Make sure that we have not mutated the liquidity manager's params
|
|
|
|
// by making this change.
|
|
|
|
params := manager.GetParameters()
|
2020-09-30 10:34:06 +00:00
|
|
|
require.Equal(t, defaultParameters, params)
|
2020-09-01 07:58:08 +00:00
|
|
|
|
|
|
|
// Provide a valid set of parameters and validate assert that they are
|
|
|
|
// set.
|
|
|
|
originalRule := NewThresholdRule(10, 10)
|
2020-09-30 10:34:06 +00:00
|
|
|
expected := defaultParameters
|
|
|
|
expected.ChannelRules = map[lnwire.ShortChannelID]*ThresholdRule{
|
|
|
|
chanID: originalRule,
|
2020-09-01 07:58:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
err := manager.SetParameters(expected)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// Check that changing the parameters we just set does not mutate
|
|
|
|
// our liquidity manager's parameters.
|
|
|
|
expected.ChannelRules[chanID] = NewThresholdRule(11, 11)
|
|
|
|
|
|
|
|
params = manager.GetParameters()
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, originalRule, params.ChannelRules[chanID])
|
|
|
|
|
|
|
|
// Set invalid parameters and assert that we fail.
|
|
|
|
expected.ChannelRules = map[lnwire.ShortChannelID]*ThresholdRule{
|
|
|
|
lnwire.NewShortChanIDFromInt(0): NewThresholdRule(1, 2),
|
|
|
|
}
|
|
|
|
err = manager.SetParameters(expected)
|
|
|
|
require.Equal(t, ErrZeroChannelID, err)
|
|
|
|
}
|
2020-09-03 08:36:43 +00:00
|
|
|
|
2020-09-30 10:34:07 +00:00
|
|
|
// TestRestrictedSuggestions tests getting of swap suggestions when we have
|
|
|
|
// other in-flight swaps. We setup our manager with a set of channels and rules
|
|
|
|
// that require a loop out swap, focusing on the filtering our of channels that
|
2020-09-30 10:34:08 +00:00
|
|
|
// are in use for in-flight swaps, or those which have recently failed.
|
2020-09-30 10:34:07 +00:00
|
|
|
func TestRestrictedSuggestions(t *testing.T) {
|
2020-09-30 10:34:08 +00:00
|
|
|
var (
|
|
|
|
failedWithinTimeout = &loopdb.LoopEvent{
|
|
|
|
SwapStateData: loopdb.SwapStateData{
|
|
|
|
State: loopdb.StateFailOffchainPayments,
|
|
|
|
},
|
|
|
|
Time: testTime,
|
|
|
|
}
|
|
|
|
|
|
|
|
failedBeforeBackoff = &loopdb.LoopEvent{
|
|
|
|
SwapStateData: loopdb.SwapStateData{
|
|
|
|
State: loopdb.StateFailOffchainPayments,
|
|
|
|
},
|
|
|
|
Time: testTime.Add(
|
|
|
|
defaultFailureBackoff * -1,
|
|
|
|
),
|
|
|
|
}
|
|
|
|
|
|
|
|
// failedTemporary is a swap that failed outside of our backoff
|
|
|
|
// period, but we still want to back off because the swap is
|
|
|
|
// considered pending.
|
|
|
|
failedTemporary = &loopdb.LoopEvent{
|
|
|
|
SwapStateData: loopdb.SwapStateData{
|
|
|
|
State: loopdb.StateFailTemporary,
|
|
|
|
},
|
|
|
|
Time: testTime.Add(
|
|
|
|
defaultFailureBackoff * -3,
|
|
|
|
),
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2020-09-30 10:34:07 +00:00
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
channels []lndclient.ChannelInfo
|
|
|
|
loopOut []*loopdb.LoopOut
|
|
|
|
loopIn []*loopdb.LoopIn
|
|
|
|
expected []loop.OutRequest
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "no existing swaps",
|
|
|
|
channels: []lndclient.ChannelInfo{
|
|
|
|
channel1,
|
|
|
|
},
|
|
|
|
loopOut: nil,
|
|
|
|
loopIn: nil,
|
|
|
|
expected: []loop.OutRequest{
|
|
|
|
chan1Rec,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "unrestricted loop out",
|
|
|
|
channels: []lndclient.ChannelInfo{
|
|
|
|
channel1, channel2,
|
|
|
|
},
|
|
|
|
loopOut: []*loopdb.LoopOut{
|
|
|
|
{
|
|
|
|
Contract: &loopdb.LoopOutContract{
|
|
|
|
OutgoingChanSet: nil,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expected: nil,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "unrestricted loop in",
|
|
|
|
channels: []lndclient.ChannelInfo{
|
|
|
|
channel1, channel2,
|
|
|
|
},
|
|
|
|
loopIn: []*loopdb.LoopIn{
|
|
|
|
{
|
|
|
|
Contract: &loopdb.LoopInContract{
|
|
|
|
LastHop: nil,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expected: nil,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "restricted loop out",
|
|
|
|
channels: []lndclient.ChannelInfo{
|
|
|
|
channel1, channel2,
|
|
|
|
},
|
|
|
|
loopOut: []*loopdb.LoopOut{
|
|
|
|
{
|
|
|
|
Contract: chan1Out,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expected: []loop.OutRequest{
|
|
|
|
chan2Rec,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "restricted loop in",
|
|
|
|
channels: []lndclient.ChannelInfo{
|
|
|
|
channel1, channel2,
|
|
|
|
},
|
|
|
|
loopIn: []*loopdb.LoopIn{
|
|
|
|
{
|
|
|
|
Contract: &loopdb.LoopInContract{
|
|
|
|
LastHop: &peer2,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expected: []loop.OutRequest{
|
|
|
|
chan1Rec,
|
|
|
|
},
|
|
|
|
},
|
2020-09-30 10:34:08 +00:00
|
|
|
{
|
|
|
|
name: "swap failed recently",
|
|
|
|
channels: []lndclient.ChannelInfo{
|
|
|
|
channel1,
|
|
|
|
},
|
|
|
|
loopOut: []*loopdb.LoopOut{
|
|
|
|
{
|
|
|
|
Contract: chan1Out,
|
|
|
|
Loop: loopdb.Loop{
|
|
|
|
Events: []*loopdb.LoopEvent{
|
|
|
|
failedWithinTimeout,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expected: nil,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "swap failed before cutoff",
|
|
|
|
channels: []lndclient.ChannelInfo{
|
|
|
|
channel1,
|
|
|
|
},
|
|
|
|
loopOut: []*loopdb.LoopOut{
|
|
|
|
{
|
|
|
|
Contract: chan1Out,
|
|
|
|
Loop: loopdb.Loop{
|
|
|
|
Events: []*loopdb.LoopEvent{
|
|
|
|
failedBeforeBackoff,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expected: []loop.OutRequest{
|
|
|
|
chan1Rec,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "temporary failure",
|
|
|
|
channels: []lndclient.ChannelInfo{
|
|
|
|
channel1,
|
|
|
|
},
|
|
|
|
loopOut: []*loopdb.LoopOut{
|
|
|
|
{
|
|
|
|
Contract: chan1Out,
|
|
|
|
Loop: loopdb.Loop{
|
|
|
|
Events: []*loopdb.LoopEvent{
|
|
|
|
failedTemporary,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expected: nil,
|
|
|
|
},
|
2020-09-30 10:34:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, testCase := range tests {
|
|
|
|
testCase := testCase
|
|
|
|
|
|
|
|
t.Run(testCase.name, func(t *testing.T) {
|
|
|
|
// Create a manager config which will return the test
|
|
|
|
// case's set of existing swaps.
|
|
|
|
cfg, lnd := newTestConfig()
|
|
|
|
cfg.ListLoopOut = func() ([]*loopdb.LoopOut, error) {
|
|
|
|
return testCase.loopOut, nil
|
|
|
|
}
|
|
|
|
cfg.ListLoopIn = func() ([]*loopdb.LoopIn, error) {
|
|
|
|
return testCase.loopIn, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
rules := map[lnwire.ShortChannelID]*ThresholdRule{
|
|
|
|
chanID1: chanRule,
|
|
|
|
chanID2: chanRule,
|
|
|
|
}
|
|
|
|
|
|
|
|
testSuggestSwaps(
|
|
|
|
t, cfg, lnd, testCase.channels, rules,
|
|
|
|
testCase.expected,
|
|
|
|
)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-30 10:34:08 +00:00
|
|
|
// TestSweepFeeLimit tests getting of swap suggestions when our estimated sweep
|
|
|
|
// fee is above and below the configured limit.
|
|
|
|
func TestSweepFeeLimit(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
feeRate chainfee.SatPerKWeight
|
|
|
|
swaps []loop.OutRequest
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "fee estimate ok",
|
|
|
|
feeRate: defaultSweepFeeRateLimit,
|
|
|
|
swaps: []loop.OutRequest{
|
|
|
|
chan1Rec,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "fee estimate above limit",
|
|
|
|
feeRate: defaultSweepFeeRateLimit + 1,
|
|
|
|
swaps: nil,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, testCase := range tests {
|
|
|
|
testCase := testCase
|
|
|
|
|
|
|
|
t.Run(testCase.name, func(t *testing.T) {
|
|
|
|
cfg, lnd := newTestConfig()
|
|
|
|
|
|
|
|
// Set our test case's fee rate for our mock lnd.
|
|
|
|
lnd.SetFeeEstimate(
|
|
|
|
loop.DefaultSweepConfTarget, testCase.feeRate,
|
|
|
|
)
|
|
|
|
|
|
|
|
channels := []lndclient.ChannelInfo{
|
|
|
|
channel1,
|
|
|
|
}
|
|
|
|
|
|
|
|
rules := map[lnwire.ShortChannelID]*ThresholdRule{
|
|
|
|
chanID1: chanRule,
|
|
|
|
}
|
|
|
|
|
|
|
|
testSuggestSwaps(
|
|
|
|
t, cfg, lnd, channels, rules, testCase.swaps,
|
|
|
|
)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-30 10:34:02 +00:00
|
|
|
// TestSuggestSwaps tests getting of swap suggestions based on the rules set for
|
|
|
|
// the liquidity manager and the current set of channel balances.
|
2020-09-03 08:36:43 +00:00
|
|
|
func TestSuggestSwaps(t *testing.T) {
|
|
|
|
tests := []struct {
|
2020-09-30 10:34:02 +00:00
|
|
|
name string
|
|
|
|
rules map[lnwire.ShortChannelID]*ThresholdRule
|
|
|
|
swaps []loop.OutRequest
|
2020-09-03 08:36:43 +00:00
|
|
|
}{
|
|
|
|
{
|
2020-09-30 10:34:02 +00:00
|
|
|
name: "no rules",
|
|
|
|
rules: map[lnwire.ShortChannelID]*ThresholdRule{},
|
2020-09-03 08:36:43 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "loop out",
|
2020-09-30 10:34:02 +00:00
|
|
|
rules: map[lnwire.ShortChannelID]*ThresholdRule{
|
|
|
|
chanID1: chanRule,
|
2020-09-03 08:36:43 +00:00
|
|
|
},
|
2020-09-30 10:34:02 +00:00
|
|
|
swaps: []loop.OutRequest{
|
|
|
|
chan1Rec,
|
2020-09-03 08:36:43 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "no rule for channel",
|
2020-09-30 10:34:02 +00:00
|
|
|
rules: map[lnwire.ShortChannelID]*ThresholdRule{
|
|
|
|
chanID2: NewThresholdRule(10, 10),
|
2020-09-03 08:36:43 +00:00
|
|
|
},
|
|
|
|
swaps: nil,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, testCase := range tests {
|
|
|
|
testCase := testCase
|
|
|
|
|
|
|
|
t.Run(testCase.name, func(t *testing.T) {
|
2020-09-30 10:34:02 +00:00
|
|
|
cfg, lnd := newTestConfig()
|
2020-09-03 08:36:43 +00:00
|
|
|
|
2020-09-30 10:34:02 +00:00
|
|
|
channels := []lndclient.ChannelInfo{
|
|
|
|
channel1,
|
|
|
|
}
|
2020-09-03 08:36:43 +00:00
|
|
|
|
2020-09-30 10:34:02 +00:00
|
|
|
testSuggestSwaps(
|
|
|
|
t, cfg, lnd, channels, testCase.rules,
|
|
|
|
testCase.swaps,
|
|
|
|
)
|
2020-09-03 08:36:43 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2020-09-30 10:34:02 +00:00
|
|
|
|
2020-09-30 10:34:09 +00:00
|
|
|
// TestFeeLimits tests limiting of swap suggestions by fees.
|
|
|
|
func TestFeeLimits(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
quote *loop.LoopOutQuote
|
|
|
|
expected []loop.OutRequest
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "fees ok",
|
|
|
|
quote: testQuote,
|
|
|
|
expected: []loop.OutRequest{
|
|
|
|
chan1Rec,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "insufficient prepay",
|
|
|
|
quote: &loop.LoopOutQuote{
|
|
|
|
SwapFee: 1,
|
|
|
|
PrepayAmount: defaultMaximumPrepay + 1,
|
|
|
|
MinerFee: 50,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "insufficient miner fee",
|
|
|
|
quote: &loop.LoopOutQuote{
|
|
|
|
SwapFee: 1,
|
|
|
|
PrepayAmount: 100,
|
|
|
|
MinerFee: defaultMaximumMinerFee + 1,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// Swap fee limited to 0.5% of 7500 = 37,5.
|
|
|
|
name: "insufficient swap fee",
|
|
|
|
quote: &loop.LoopOutQuote{
|
|
|
|
SwapFee: 38,
|
|
|
|
PrepayAmount: 100,
|
|
|
|
MinerFee: 500,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, testCase := range tests {
|
|
|
|
testCase := testCase
|
|
|
|
|
|
|
|
t.Run(testCase.name, func(t *testing.T) {
|
|
|
|
cfg, lnd := newTestConfig()
|
|
|
|
cfg.LoopOutQuote = func(context.Context,
|
|
|
|
*loop.LoopOutQuoteRequest) (*loop.LoopOutQuote,
|
|
|
|
error) {
|
|
|
|
|
|
|
|
return testCase.quote, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
channels := []lndclient.ChannelInfo{
|
|
|
|
channel1,
|
|
|
|
}
|
|
|
|
rules := map[lnwire.ShortChannelID]*ThresholdRule{
|
|
|
|
chanID1: chanRule,
|
|
|
|
}
|
|
|
|
|
|
|
|
testSuggestSwaps(
|
|
|
|
t, cfg, lnd, channels, rules, testCase.expected,
|
|
|
|
)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-30 10:34:02 +00:00
|
|
|
// testSuggestSwaps tests getting swap suggestions.
|
|
|
|
func testSuggestSwaps(t *testing.T, cfg *Config, lnd *test.LndMockServices,
|
|
|
|
channels []lndclient.ChannelInfo,
|
|
|
|
rules map[lnwire.ShortChannelID]*ThresholdRule,
|
|
|
|
expected []loop.OutRequest) {
|
|
|
|
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
// Create a mock lnd with the set of channels set in our test case and
|
|
|
|
// update our test case lnd to use these channels.
|
|
|
|
lnd.Channels = channels
|
|
|
|
|
|
|
|
// Create a new manager, get our current set of parameters and update
|
|
|
|
// them to use the rules set by the test.
|
|
|
|
manager := NewManager(cfg)
|
|
|
|
|
|
|
|
currentParams := manager.GetParameters()
|
|
|
|
currentParams.ChannelRules = rules
|
|
|
|
|
|
|
|
err := manager.SetParameters(currentParams)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
actual, err := manager.SuggestSwaps(context.Background())
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, expected, actual)
|
|
|
|
}
|