Merge pull request #332 from carlaKC/autoloop-1-disqualified

autoloop: add reasons to explain no action
pull/335/head
Carla Kirk-Cohen 3 years ago committed by GitHub
commit fe42664e16
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -2,12 +2,15 @@ package main
import (
"context"
"errors"
"fmt"
"strconv"
"github.com/lightninglabs/loop/liquidity"
"github.com/lightninglabs/loop/looprpc"
"github.com/urfave/cli"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
var getLiquidityParamsCommand = cli.Command{
@ -411,11 +414,22 @@ func suggestSwap(ctx *cli.Context) error {
resp, err := client.SuggestSwaps(
context.Background(), &looprpc.SuggestSwapsRequest{},
)
if err != nil {
if err == nil {
printRespJSON(resp)
return nil
}
// If we got an error because no rules are set, we want to display a
// friendly message.
rpcErr, ok := status.FromError(err)
if !ok {
return err
}
printJSON(resp)
if rpcErr.Code() != codes.FailedPrecondition {
return err
}
return nil
return errors.New("no rules set for autolooper, please set rules " +
"using the setrule command")
}

@ -224,8 +224,51 @@ in manually dispatched swaps - for loop out, this would mean the channel is
specified in the outgoing channel swap, and for loop in the channel's peer is
specified as the last hop for an ongoing swap. This check is put in place to
prevent the autolooper from interfering with swaps you have created yourself.
If there is an ongoing swap that does not have a restriction placed on it (no
outgoing channel set, or last hop), then the autolooper will take no action
until it has resolved, because it does not know how that swap will affect
liquidity balances.
## Disqualified Swaps
There are various restrictions placed on the client's autoloop functionality.
If a channel is not eligible for a swap at present, or it does not need one
based on the current set of liquidity rules, it will be listed in the
`Disqualified` section of the output of the `SuggestSwaps` API. One of the
following reasons will be displayed:
* Budget not started: if the start date for your budget is in the future,
no swaps will be executed until the start date is reached. See [budget](#budget) to
update.
* Budget elapsed: if the autolooper has elapsed the budget assigned to it for
fees, this reason will be returned. See [budget](#budget) to update.
* Sweep fees: this reason will be displayed if the estimated chain fee rate for
sweeping a loop out swap is higher than the current limit. See [sweep fees](#fee-market-awareness)
to update.
* In flight: there is a limit to the number of automatically dispatched swaps
that the client allows. If this limit has been reached, no further swaps
will be automatically dispatched until the in-flight swaps complete. See
[in flight limit](#in-flight-limit) to update.
* Budget insufficient: if there is not enough remaining budget for a swap,
including the amount currently reserved for in flight swaps, an insufficient
reason will be displayed. This differs from budget elapsed because there is
still budget remaining, just not enough to execute a specific swap.
* Swap fee: there is a limit placed on the fee that the client will pay to the
server for automatically dispatched swaps. The swap fee reason will be shown
if the fees advertised by the server are too high. See [swap fee](#swap-fee)
to update.
* Miner fee: if the estimated on-chain fees for a swap are too high, autoloop
will display a miner fee reason. See [miner fee](#miner-fee) to update.
* Prepay: if the no-show fee that the server will pay in the unlikely event
that the client fails to complete a swap is too high, a prepay reason will
be returned. See [no show fees](#no-show-fee) to update.
* Backoff: if an automatically dispatched swap has recently failed for a channel,
autoloop will backoff for a period before retrying. See [failure backoff](#failure-backoff)
to update.
* Loop out: if there is currently a loop out swap in-flight on a channel, it
will not be used for automated swaps. This issue will resolve itself once the
in-flight swap completes.
* Loop in: if there is currently a loop in swap in-flight for a peer, it will
not be used for automated swaps. This will resolve itself once the swap is
completed.
* Liquidity ok: if a channel's current liquidity balance is within the bound set
by the rule that it applies to, then a liquidity ok reason will be displayed
to indicate that no action is required for that channel.
Further details for all of these reasons can be found in loopd's debug level
logs.

@ -178,6 +178,9 @@ var (
// less than the server minimum.
ErrMinLessThanServer = errors.New("minimum swap amount is less than " +
"server minimum")
// ErrNoRules is returned when no rules are set for swap suggestions.
ErrNoRules = errors.New("no rules set for autoloop")
)
// Config contains the external functionality required to run the
@ -439,7 +442,14 @@ func (m *Manager) Run(ctx context.Context) error {
for {
select {
case <-m.cfg.AutoloopTicker.Ticks():
if err := m.autoloop(ctx); err != nil {
err := m.autoloop(ctx)
switch err {
case ErrNoRules:
log.Debugf("No rules configured for autoloop")
case nil:
default:
log.Errorf("autoloop failed: %v", err)
}
@ -506,12 +516,12 @@ func cloneParameters(params Parameters) Parameters {
// autoloop gets a set of suggested swaps and dispatches them automatically if
// we have automated looping enabled.
func (m *Manager) autoloop(ctx context.Context) error {
swaps, err := m.SuggestSwaps(ctx, true)
suggestion, err := m.SuggestSwaps(ctx, true)
if err != nil {
return err
}
for _, swap := range swaps {
for _, swap := range suggestion.OutSwaps {
// If we don't actually have dispatch of swaps enabled, log
// suggestions.
if !m.params.Autoloop {
@ -547,6 +557,36 @@ func (m *Manager) ForceAutoLoop(ctx context.Context) error {
}
}
// Suggestions provides a set of suggested swaps, and the set of channels that
// were excluded from consideration.
type Suggestions struct {
// OutSwaps is the set of loop out swaps that we suggest executing.
OutSwaps []loop.OutRequest
// DisqualifiedChans maps the set of channels that we do not recommend
// swaps on to the reason that we did not recommend a swap.
DisqualifiedChans map[lnwire.ShortChannelID]Reason
}
func newSuggestions() *Suggestions {
return &Suggestions{
DisqualifiedChans: make(map[lnwire.ShortChannelID]Reason),
}
}
// singleReasonSuggestion is a helper function which returns a set of
// suggestions where all of our rules are disqualified due to a reason that
// applies to all of them (such as being out of budget).
func (m *Manager) singleReasonSuggestion(reason Reason) *Suggestions {
resp := newSuggestions()
for id := range m.params.ChannelRules {
resp.DisqualifiedChans[id] = reason
}
return resp
}
// SuggestSwaps returns a set of swap suggestions based on our current liquidity
// balance for the set of rules configured for the manager, failing if there are
// no rules set. It takes an autoloop boolean that indicates whether the
@ -554,7 +594,7 @@ func (m *Manager) ForceAutoLoop(ctx context.Context) error {
// to determine the information we add to our swap suggestion and whether we
// return any suggestions.
func (m *Manager) SuggestSwaps(ctx context.Context, autoloop bool) (
[]loop.OutRequest, error) {
*Suggestions, error) {
m.paramsLock.Lock()
defer m.paramsLock.Unlock()
@ -562,7 +602,7 @@ func (m *Manager) SuggestSwaps(ctx context.Context, autoloop bool) (
// If we have no rules set, exit early to avoid unnecessary calls to
// lnd and the server.
if len(m.params.ChannelRules) == 0 {
return nil, nil
return nil, ErrNoRules
}
// If our start date is in the future, we interpret this as meaning that
@ -572,7 +612,7 @@ func (m *Manager) SuggestSwaps(ctx context.Context, autoloop bool) (
log.Debugf("autoloop fee budget start time: %v is in "+
"the future", m.params.AutoFeeStartDate)
return nil, nil
return m.singleReasonSuggestion(ReasonBudgetNotStarted), nil
}
// Before we get any swap suggestions, we check what the current fee
@ -593,7 +633,7 @@ func (m *Manager) SuggestSwaps(ctx context.Context, autoloop bool) (
satPerKwToSatPerVByte(estimate),
satPerKwToSatPerVByte(m.params.SweepFeeRateLimit))
return nil, nil
return m.singleReasonSuggestion(ReasonSweepFees), nil
}
// Get the current server side restrictions, combined with the client
@ -630,7 +670,7 @@ func (m *Manager) SuggestSwaps(ctx context.Context, autoloop bool) (
m.params.AutoFeeBudget, summary.spentFees,
summary.pendingFees)
return nil, nil
return m.singleReasonSuggestion(ReasonBudgetElapsed), nil
}
// If we have already reached our total allowed number of in flight
@ -639,29 +679,45 @@ func (m *Manager) SuggestSwaps(ctx context.Context, autoloop bool) (
if allowedSwaps <= 0 {
log.Debugf("%v autoloops allowed, %v in flight",
m.params.MaxAutoInFlight, summary.inFlightCount)
return nil, nil
return m.singleReasonSuggestion(ReasonInFlight), nil
}
eligible, err := m.getEligibleChannels(ctx, loopOut, loopIn)
channels, err := m.cfg.Lnd.Client.ListChannels(ctx)
if err != nil {
return nil, err
}
var suggestions []loop.OutRequest
for _, channel := range eligible {
channelID := lnwire.NewShortChanIDFromInt(channel.ChannelID)
rule, ok := m.params.ChannelRules[channelID]
// Get a summary of the channels and peers that are not eligible due
// to ongoing swaps.
traffic := m.currentSwapTraffic(loopOut, loopIn)
var (
suggestions []loop.OutRequest
disqualified = make(map[lnwire.ShortChannelID]Reason)
)
for _, channel := range channels {
balance := newBalances(channel)
rule, ok := m.params.ChannelRules[balance.channelID]
if !ok {
continue
}
balance := newBalances(channel)
suggestion := rule.suggestSwap(balance, restrictions)
// Check whether we can perform a swap, adding the channel to
// our set of disqualified swaps if it is not eligible.
reason := traffic.maySwap(channel.PubKeyBytes, balance.channelID)
if reason != ReasonNone {
disqualified[balance.channelID] = reason
continue
}
// We can have nil suggestions in the case where no action is
// required, so we skip over them.
suggestion := rule.suggestSwap(balance, restrictions)
if suggestion == nil {
disqualified[balance.channelID] = ReasonLiquidityOk
continue
}
@ -683,11 +739,9 @@ func (m *Manager) SuggestSwaps(ctx context.Context, autoloop bool) (
// Check that the estimated fees for the suggested swap are
// below the fee limits configured by the manager.
err = m.checkFeeLimits(quote, suggestion.Amount)
if err != nil {
log.Infof("suggestion: %v expected fees too high: %v",
suggestion, err)
feeReason := m.checkFeeLimits(quote, suggestion.Amount)
if feeReason != ReasonNone {
disqualified[balance.channelID] = feeReason
continue
}
@ -700,10 +754,16 @@ func (m *Manager) SuggestSwaps(ctx context.Context, autoloop bool) (
suggestions = append(suggestions, outRequest)
}
// If we have no suggestions after we have applied all of our limits,
// just return.
// Finally, run through all possible swaps, excluding swaps that are
// not feasible due to fee or budget restrictions.
resp := &Suggestions{
DisqualifiedChans: disqualified,
}
// If we have no swaps to execute after we have applied all of our
// limits, just return our set of disqualified swaps.
if len(suggestions) == 0 {
return nil, nil
return resp, nil
}
// Sort suggestions by amount in descending order.
@ -713,12 +773,38 @@ func (m *Manager) SuggestSwaps(ctx context.Context, autoloop bool) (
// Run through our suggested swaps in descending order of amount and
// return all of the swaps which will fit within our remaining budget.
var (
available = m.params.AutoFeeBudget - summary.totalFees()
inBudget []loop.OutRequest
)
available := m.params.AutoFeeBudget - summary.totalFees()
// setReason is a helper that adds a swap's channels to our disqualified
// list with the reason provided.
setReason := func(reason Reason, swap loop.OutRequest) {
for _, id := range swap.OutgoingChanSet {
chanID := lnwire.NewShortChanIDFromInt(id)
resp.DisqualifiedChans[chanID] = reason
}
}
for _, swap := range suggestions {
swap := swap
// If we do not have enough funds available, or we hit our
// in flight limit, we record this value for the rest of the
// swaps.
var reason Reason
switch {
case available == 0:
reason = ReasonBudgetInsufficient
case len(resp.OutSwaps) == allowedSwaps:
reason = ReasonInFlight
}
if reason != ReasonNone {
setReason(reason, swap)
continue
}
fees := worstCaseOutFees(
swap.MaxPrepayRoutingFee, swap.MaxSwapRoutingFee,
swap.MaxSwapFee, swap.MaxMinerFee, swap.MaxPrepayAmount,
@ -729,17 +815,13 @@ func (m *Manager) SuggestSwaps(ctx context.Context, autoloop bool) (
// fall within the budget and decrement our available amount.
if fees <= available {
available -= fees
inBudget = append(inBudget, swap)
}
// If we're out of budget, or we have hit the max number of
// swaps that we want to dispatch at one time, exit early.
if available == 0 || allowedSwaps == len(inBudget) {
break
resp.OutSwaps = append(resp.OutSwaps, swap)
} else {
setReason(ReasonBudgetInsufficient, swap)
}
}
return inBudget, nil
return resp, nil
}
// getSwapRestrictions queries the server for its latest swap size restrictions,
@ -918,19 +1000,13 @@ func (m *Manager) checkExistingAutoLoops(ctx context.Context,
return &summary, nil
}
// getEligibleChannels takes lists of our existing loop out and in swaps, and
// gets a list of channels that are not currently being utilized for a swap.
// If an unrestricted swap is ongoing, we return an empty set of channels
// because we don't know which channels balances it will affect.
func (m *Manager) getEligibleChannels(ctx context.Context,
loopOut []*loopdb.LoopOut, loopIn []*loopdb.LoopIn) (
[]lndclient.ChannelInfo, error) {
// currentSwapTraffic examines our existing swaps and returns a summary of the
// current activity which can be used to determine whether we should perform
// any swaps.
func (m *Manager) currentSwapTraffic(loopOut []*loopdb.LoopOut,
loopIn []*loopdb.LoopIn) *swapTraffic {
var (
existingOut = make(map[lnwire.ShortChannelID]bool)
existingIn = make(map[route.Vertex]bool)
failedOut = make(map[lnwire.ShortChannelID]time.Time)
)
traffic := newSwapTraffic()
// Failure cutoff is the most recent failure timestamp we will still
// consider a channel eligible. Any channels involved in swaps that have
@ -963,7 +1039,7 @@ func (m *Manager) getEligibleChannels(ctx context.Context,
id,
)
failedOut[chanID] = failedAt
traffic.failedLoopOut[chanID] = failedAt
}
}
}
@ -978,16 +1054,9 @@ func (m *Manager) getEligibleChannels(ctx context.Context,
continue
}
if len(chanSet) == 0 {
log.Debugf("Ongoing unrestricted loop out: "+
"%v, no suggestions at present", out.Hash)
return nil, nil
}
for _, id := range chanSet {
chanID := lnwire.NewShortChanIDFromInt(id)
existingOut[chanID] = true
traffic.ongoingLoopOut[chanID] = true
}
}
@ -997,83 +1066,91 @@ func (m *Manager) getEligibleChannels(ctx context.Context,
continue
}
// Skip over swaps that may come through any peer.
if in.Contract.LastHop == nil {
log.Debugf("Ongoing unrestricted loop in: "+
"%v, no suggestions at present", in.Hash)
return nil, nil
continue
}
existingIn[*in.Contract.LastHop] = true
traffic.ongoingLoopIn[*in.Contract.LastHop] = true
}
channels, err := m.cfg.Lnd.Client.ListChannels(ctx)
if err != nil {
return nil, err
}
return traffic
}
// Run through our set of channels and skip over any channels that
// are currently being utilized by a restricted swap (where restricted
// means that a loop out limited channels, or a loop in limited last
// hop).
var eligible []lndclient.ChannelInfo
for _, channel := range channels {
shortID := lnwire.NewShortChanIDFromInt(channel.ChannelID)
// swapTraffic contains a summary of our current and previously failed swaps.
type swapTraffic struct {
ongoingLoopOut map[lnwire.ShortChannelID]bool
ongoingLoopIn map[route.Vertex]bool
failedLoopOut map[lnwire.ShortChannelID]time.Time
}
lastFail, recentFail := failedOut[shortID]
if recentFail {
log.Debugf("Channel: %v not eligible for "+
"suggestions, was part of a failed swap at: %v",
channel.ChannelID, lastFail)
func newSwapTraffic() *swapTraffic {
return &swapTraffic{
ongoingLoopOut: make(map[lnwire.ShortChannelID]bool),
ongoingLoopIn: make(map[route.Vertex]bool),
failedLoopOut: make(map[lnwire.ShortChannelID]time.Time),
}
}
continue
}
// maySwap returns a boolean that indicates whether we may perform a swap for a
// peer and its set of channels.
func (s *swapTraffic) maySwap(peer route.Vertex,
chanID lnwire.ShortChannelID) Reason {
if existingOut[shortID] {
log.Debugf("Channel: %v not eligible for "+
"suggestions, ongoing loop out utilizing "+
"channel", channel.ChannelID)
lastFail, recentFail := s.failedLoopOut[chanID]
if recentFail {
log.Debugf("Channel: %v not eligible for suggestions, was "+
"part of a failed swap at: %v", chanID, lastFail)
continue
}
return ReasonFailureBackoff
}
if existingIn[channel.PubKeyBytes] {
log.Debugf("Channel: %v not eligible for "+
"suggestions, ongoing loop in utilizing "+
"peer", channel.ChannelID)
if s.ongoingLoopOut[chanID] {
log.Debugf("Channel: %v not eligible for suggestions, "+
"ongoing loop out utilizing channel", chanID)
continue
}
return ReasonLoopOut
}
if s.ongoingLoopIn[peer] {
log.Debugf("Peer: %x not eligible for suggestions ongoing "+
"loop in utilizing peer", peer)
eligible = append(eligible, channel)
return ReasonLoopIn
}
return eligible, nil
return ReasonNone
}
// checkFeeLimits takes a set of fees for a swap and checks whether they exceed
// our swap limits.
func (m *Manager) checkFeeLimits(quote *loop.LoopOutQuote,
swapAmt btcutil.Amount) error {
swapAmt btcutil.Amount) Reason {
maxFee := ppmToSat(swapAmt, m.params.MaximumSwapFeePPM)
if quote.SwapFee > maxFee {
return fmt.Errorf("quoted swap fee: %v > maximum swap fee: %v",
log.Debugf("quoted swap fee: %v > maximum swap fee: %v",
quote.SwapFee, maxFee)
return ReasonSwapFee
}
if quote.MinerFee > m.params.MaximumMinerFee {
return fmt.Errorf("quoted miner fee: %v > maximum miner "+
log.Debugf("quoted miner fee: %v > maximum miner "+
"fee: %v", quote.MinerFee, m.params.MaximumMinerFee)
return ReasonMinerFee
}
if quote.PrepayAmount > m.params.MaximumPrepay {
return fmt.Errorf("quoted prepay: %v > maximum prepay: %v",
log.Debugf("quoted prepay: %v > maximum prepay: %v",
quote.PrepayAmount, m.params.MaximumPrepay)
return ReasonPrepay
}
return nil
return ReasonNone
}
// satPerKwToSatPerVByte converts sat per kWeight to sat per vByte.

@ -107,6 +107,10 @@ var (
}
testRestrictions = NewRestrictions(1, 10000)
// noneDisqualified can be used in tests where we don't have any
// disqualified channels so that we can use require.Equal.
noneDisqualified = make(map[lnwire.ShortChannelID]Reason)
)
// newTestConfig creates a default test config.
@ -283,7 +287,7 @@ func TestRestrictedSuggestions(t *testing.T) {
channels []lndclient.ChannelInfo
loopOut []*loopdb.LoopOut
loopIn []*loopdb.LoopIn
expected []loop.OutRequest
expected *Suggestions
}{
{
name: "no existing swaps",
@ -292,14 +296,17 @@ func TestRestrictedSuggestions(t *testing.T) {
},
loopOut: nil,
loopIn: nil,
expected: []loop.OutRequest{
chan1Rec,
expected: &Suggestions{
OutSwaps: []loop.OutRequest{
chan1Rec,
},
DisqualifiedChans: noneDisqualified,
},
},
{
name: "unrestricted loop out",
channels: []lndclient.ChannelInfo{
channel1, channel2,
channel1,
},
loopOut: []*loopdb.LoopOut{
{
@ -308,12 +315,17 @@ func TestRestrictedSuggestions(t *testing.T) {
},
},
},
expected: nil,
expected: &Suggestions{
OutSwaps: []loop.OutRequest{
chan1Rec,
},
DisqualifiedChans: noneDisqualified,
},
},
{
name: "unrestricted loop in",
channels: []lndclient.ChannelInfo{
channel1, channel2,
channel1,
},
loopIn: []*loopdb.LoopIn{
{
@ -322,7 +334,12 @@ func TestRestrictedSuggestions(t *testing.T) {
},
},
},
expected: nil,
expected: &Suggestions{
OutSwaps: []loop.OutRequest{
chan1Rec,
},
DisqualifiedChans: noneDisqualified,
},
},
{
name: "restricted loop out",
@ -334,8 +351,13 @@ func TestRestrictedSuggestions(t *testing.T) {
Contract: chan1Out,
},
},
expected: []loop.OutRequest{
chan2Rec,
expected: &Suggestions{
OutSwaps: []loop.OutRequest{
chan2Rec,
},
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
chanID1: ReasonLoopOut,
},
},
},
{
@ -350,8 +372,13 @@ func TestRestrictedSuggestions(t *testing.T) {
},
},
},
expected: []loop.OutRequest{
chan1Rec,
expected: &Suggestions{
OutSwaps: []loop.OutRequest{
chan1Rec,
},
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
chanID2: ReasonLoopIn,
},
},
},
{
@ -369,7 +396,11 @@ func TestRestrictedSuggestions(t *testing.T) {
},
},
},
expected: nil,
expected: &Suggestions{
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
chanID1: ReasonFailureBackoff,
},
},
},
{
name: "swap failed before cutoff",
@ -386,8 +417,11 @@ func TestRestrictedSuggestions(t *testing.T) {
},
},
},
expected: []loop.OutRequest{
chan1Rec,
expected: &Suggestions{
OutSwaps: []loop.OutRequest{
chan1Rec,
},
DisqualifiedChans: noneDisqualified,
},
},
{
@ -405,7 +439,11 @@ func TestRestrictedSuggestions(t *testing.T) {
},
},
},
expected: nil,
expected: &Suggestions{
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
chanID1: ReasonLoopOut,
},
},
},
}
@ -443,21 +481,28 @@ func TestRestrictedSuggestions(t *testing.T) {
// fee is above and below the configured limit.
func TestSweepFeeLimit(t *testing.T) {
tests := []struct {
name string
feeRate chainfee.SatPerKWeight
swaps []loop.OutRequest
name string
feeRate chainfee.SatPerKWeight
suggestions *Suggestions
}{
{
name: "fee estimate ok",
feeRate: defaultSweepFeeRateLimit,
swaps: []loop.OutRequest{
chan1Rec,
suggestions: &Suggestions{
OutSwaps: []loop.OutRequest{
chan1Rec,
},
DisqualifiedChans: noneDisqualified,
},
},
{
name: "fee estimate above limit",
feeRate: defaultSweepFeeRateLimit + 1,
swaps: nil,
suggestions: &Suggestions{
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
chanID1: ReasonSweepFees,
},
},
},
}
@ -483,7 +528,7 @@ func TestSweepFeeLimit(t *testing.T) {
testSuggestSwaps(
t, newSuggestSwapsSetup(cfg, lnd, params),
testCase.swaps, nil,
testCase.suggestions, nil,
)
})
}
@ -493,21 +538,26 @@ func TestSweepFeeLimit(t *testing.T) {
// the liquidity manager and the current set of channel balances.
func TestSuggestSwaps(t *testing.T) {
tests := []struct {
name string
rules map[lnwire.ShortChannelID]*ThresholdRule
swaps []loop.OutRequest
name string
rules map[lnwire.ShortChannelID]*ThresholdRule
suggestions *Suggestions
err error
}{
{
name: "no rules",
rules: map[lnwire.ShortChannelID]*ThresholdRule{},
err: ErrNoRules,
},
{
name: "loop out",
rules: map[lnwire.ShortChannelID]*ThresholdRule{
chanID1: chanRule,
},
swaps: []loop.OutRequest{
chan1Rec,
suggestions: &Suggestions{
OutSwaps: []loop.OutRequest{
chan1Rec,
},
DisqualifiedChans: noneDisqualified,
},
},
{
@ -515,7 +565,9 @@ func TestSuggestSwaps(t *testing.T) {
rules: map[lnwire.ShortChannelID]*ThresholdRule{
chanID2: NewThresholdRule(10, 10),
},
swaps: nil,
suggestions: &Suggestions{
DisqualifiedChans: noneDisqualified,
},
},
}
@ -534,7 +586,7 @@ func TestSuggestSwaps(t *testing.T) {
testSuggestSwaps(
t, newSuggestSwapsSetup(cfg, lnd, params),
testCase.swaps, nil,
testCase.suggestions, testCase.err,
)
})
}
@ -543,15 +595,18 @@ func TestSuggestSwaps(t *testing.T) {
// TestFeeLimits tests limiting of swap suggestions by fees.
func TestFeeLimits(t *testing.T) {
tests := []struct {
name string
quote *loop.LoopOutQuote
expected []loop.OutRequest
name string
quote *loop.LoopOutQuote
suggestions *Suggestions
}{
{
name: "fees ok",
quote: testQuote,
expected: []loop.OutRequest{
chan1Rec,
suggestions: &Suggestions{
OutSwaps: []loop.OutRequest{
chan1Rec,
},
DisqualifiedChans: noneDisqualified,
},
},
{
@ -561,6 +616,11 @@ func TestFeeLimits(t *testing.T) {
PrepayAmount: defaultMaximumPrepay + 1,
MinerFee: 50,
},
suggestions: &Suggestions{
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
chanID1: ReasonPrepay,
},
},
},
{
name: "insufficient miner fee",
@ -569,6 +629,11 @@ func TestFeeLimits(t *testing.T) {
PrepayAmount: 100,
MinerFee: defaultMaximumMinerFee + 1,
},
suggestions: &Suggestions{
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
chanID1: ReasonMinerFee,
},
},
},
{
// Swap fee limited to 0.5% of 7500 = 37,5.
@ -578,6 +643,11 @@ func TestFeeLimits(t *testing.T) {
PrepayAmount: 100,
MinerFee: 500,
},
suggestions: &Suggestions{
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
chanID1: ReasonSwapFee,
},
},
},
}
@ -604,7 +674,7 @@ func TestFeeLimits(t *testing.T) {
testSuggestSwaps(
t, newSuggestSwapsSetup(cfg, lnd, params),
testCase.expected, nil,
testCase.suggestions, nil,
)
})
}
@ -635,8 +705,8 @@ func TestFeeBudget(t *testing.T) {
// last update time to their total cost.
existingSwaps map[time.Time]btcutil.Amount
// expectedSwaps is the set of swaps we expect to be suggested.
expectedSwaps []loop.OutRequest
// suggestions is the set of swaps we expect to be suggested.
suggestions *Suggestions
}{
{
// Two swaps will cost (78+5000)*2, set exactly 10156
@ -644,8 +714,11 @@ func TestFeeBudget(t *testing.T) {
name: "budget for 2 swaps, no existing",
budget: 10156,
maxMinerFee: 5000,
expectedSwaps: []loop.OutRequest{
chan1Rec, chan2Rec,
suggestions: &Suggestions{
OutSwaps: []loop.OutRequest{
chan1Rec, chan2Rec,
},
DisqualifiedChans: noneDisqualified,
},
},
{
@ -654,8 +727,13 @@ func TestFeeBudget(t *testing.T) {
name: "budget for 1 swaps, no existing",
budget: 10155,
maxMinerFee: 5000,
expectedSwaps: []loop.OutRequest{
chan1Rec,
suggestions: &Suggestions{
OutSwaps: []loop.OutRequest{
chan1Rec,
},
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
chanID2: ReasonBudgetInsufficient,
},
},
},
{
@ -667,8 +745,11 @@ func TestFeeBudget(t *testing.T) {
existingSwaps: map[time.Time]btcutil.Amount{
testBudgetStart.Add(time.Hour * -1): 200,
},
expectedSwaps: []loop.OutRequest{
chan1Rec, chan2Rec,
suggestions: &Suggestions{
OutSwaps: []loop.OutRequest{
chan1Rec, chan2Rec,
},
DisqualifiedChans: noneDisqualified,
},
},
{
@ -680,8 +761,13 @@ func TestFeeBudget(t *testing.T) {
existingSwaps: map[time.Time]btcutil.Amount{
testBudgetStart.Add(time.Hour): 500,
},
expectedSwaps: []loop.OutRequest{
chan1Rec,
suggestions: &Suggestions{
OutSwaps: []loop.OutRequest{
chan1Rec,
},
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
chanID2: ReasonBudgetInsufficient,
},
},
},
{
@ -691,7 +777,12 @@ func TestFeeBudget(t *testing.T) {
existingSwaps: map[time.Time]btcutil.Amount{
testBudgetStart.Add(time.Hour): 500,
},
expectedSwaps: nil,
suggestions: &Suggestions{
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
chanID1: ReasonBudgetElapsed,
chanID2: ReasonBudgetElapsed,
},
},
},
}
@ -754,14 +845,14 @@ func TestFeeBudget(t *testing.T) {
// Set our custom max miner fee on each expected swap,
// rather than having to create multiple vars for
// different rates.
for i := range testCase.expectedSwaps {
testCase.expectedSwaps[i].MaxMinerFee =
for i := range testCase.suggestions.OutSwaps {
testCase.suggestions.OutSwaps[i].MaxMinerFee =
testCase.maxMinerFee
}
testSuggestSwaps(
t, newSuggestSwapsSetup(cfg, lnd, params),
testCase.expectedSwaps, nil,
testCase.suggestions, nil,
)
})
}
@ -774,20 +865,26 @@ func TestInFlightLimit(t *testing.T) {
name string
maxInFlight int
existingSwaps []*loopdb.LoopOut
expectedSwaps []loop.OutRequest
suggestions *Suggestions
}{
{
name: "none in flight, extra space",
maxInFlight: 3,
expectedSwaps: []loop.OutRequest{
chan1Rec, chan2Rec,
suggestions: &Suggestions{
OutSwaps: []loop.OutRequest{
chan1Rec, chan2Rec,
},
DisqualifiedChans: noneDisqualified,
},
},
{
name: "none in flight, exact match",
maxInFlight: 2,
expectedSwaps: []loop.OutRequest{
chan1Rec, chan2Rec,
suggestions: &Suggestions{
OutSwaps: []loop.OutRequest{
chan1Rec, chan2Rec,
},
DisqualifiedChans: noneDisqualified,
},
},
{
@ -798,8 +895,13 @@ func TestInFlightLimit(t *testing.T) {
Contract: autoOutContract,
},
},
expectedSwaps: []loop.OutRequest{
chan1Rec,
suggestions: &Suggestions{
OutSwaps: []loop.OutRequest{
chan1Rec,
},
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
chanID2: ReasonInFlight,
},
},
},
{
@ -810,7 +912,12 @@ func TestInFlightLimit(t *testing.T) {
Contract: autoOutContract,
},
},
expectedSwaps: nil,
suggestions: &Suggestions{
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
chanID1: ReasonInFlight,
chanID2: ReasonInFlight,
},
},
},
{
name: "max swaps exceeded",
@ -823,7 +930,12 @@ func TestInFlightLimit(t *testing.T) {
Contract: autoOutContract,
},
},
expectedSwaps: nil,
suggestions: &Suggestions{
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
chanID1: ReasonInFlight,
chanID2: ReasonInFlight,
},
},
},
}
@ -854,7 +966,7 @@ func TestInFlightLimit(t *testing.T) {
testSuggestSwaps(
t, newSuggestSwapsSetup(cfg, lnd, params),
testCase.expectedSwaps, nil,
testCase.suggestions, nil,
)
})
}
@ -869,13 +981,18 @@ func TestSizeRestrictions(t *testing.T) {
}
outSwap = loop.OutRequest{
Amount: 7000,
OutgoingChanSet: loopdb.ChannelSet{chanID1.ToUint64()},
MaxPrepayRoutingFee: prepayFee,
MaxMinerFee: defaultMaximumMinerFee,
MaxSwapFee: testQuote.SwapFee,
MaxPrepayAmount: testQuote.PrepayAmount,
SweepConfTarget: loop.DefaultSweepConfTarget,
Initiator: autoloopSwapInitiator,
MaxSwapRoutingFee: ppmToSat(
7000,
defaultRoutingFeePPM,
),
MaxMinerFee: defaultMaximumMinerFee,
MaxSwapFee: testQuote.SwapFee,
MaxPrepayAmount: testQuote.PrepayAmount,
SweepConfTarget: loop.DefaultSweepConfTarget,
Initiator: autoloopSwapInitiator,
}
)
@ -890,8 +1007,8 @@ func TestSizeRestrictions(t *testing.T) {
// endpoint.
serverRestrictions []Restrictions
// expectedAmount is the amount that we expect for our swap.
expectedAmount btcutil.Amount
// suggestions is the set of suggestions we expect.
suggestions *Suggestions
// expectedError is the error we expect.
expectedError error
@ -904,7 +1021,12 @@ func TestSizeRestrictions(t *testing.T) {
serverRestrictions: []Restrictions{
serverRestrictions, serverRestrictions,
},
expectedAmount: 7500,
suggestions: &Suggestions{
OutSwaps: []loop.OutRequest{
chan1Rec,
},
DisqualifiedChans: noneDisqualified,
},
},
{
name: "minimum more than server, no swap",
@ -914,7 +1036,11 @@ func TestSizeRestrictions(t *testing.T) {
serverRestrictions: []Restrictions{
serverRestrictions, serverRestrictions,
},
expectedAmount: 0,
suggestions: &Suggestions{
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
chanID1: ReasonLiquidityOk,
},
},
},
{
name: "maximum less than server, swap happens",
@ -924,7 +1050,12 @@ func TestSizeRestrictions(t *testing.T) {
serverRestrictions: []Restrictions{
serverRestrictions, serverRestrictions,
},
expectedAmount: 7000,
suggestions: &Suggestions{
OutSwaps: []loop.OutRequest{
outSwap,
},
DisqualifiedChans: noneDisqualified,
},
},
{
// Originally, our client params are ok. But then the
@ -942,8 +1073,8 @@ func TestSizeRestrictions(t *testing.T) {
Maximum: 6000,
},
},
expectedAmount: 0,
expectedError: ErrMaxExceedsServer,
suggestions: nil,
expectedError: ErrMaxExceedsServer,
},
}
@ -975,25 +1106,9 @@ func TestSizeRestrictions(t *testing.T) {
return &restrictions, nil
}
// If we expect a swap (non-zero amount), we add a
// swap to our set of expected swaps, and update amount
// and fee accordingly.
var expectedSwaps []loop.OutRequest
if testCase.expectedAmount != 0 {
outSwap.Amount = testCase.expectedAmount
outSwap.MaxSwapRoutingFee = ppmToSat(
testCase.expectedAmount,
defaultRoutingFeePPM,
)
expectedSwaps = append(expectedSwaps, outSwap)
}
testSuggestSwaps(
t, newSuggestSwapsSetup(cfg, lnd, params),
expectedSwaps, testCase.expectedError,
testCase.suggestions, testCase.expectedError,
)
require.Equal(
@ -1028,7 +1143,7 @@ func newSuggestSwapsSetup(cfg *Config, lnd *test.LndMockServices,
// use the default parameters and setup two channels (channel1 + channel2) with
// chanRule set for each.
func testSuggestSwaps(t *testing.T, setup *testSuggestSwapsSetup,
expected []loop.OutRequest, expectedErr error) {
expected *Suggestions, expectedErr error) {
t.Parallel()

@ -0,0 +1,62 @@
package liquidity
// Reason is an enum which represents the various reasons we have for not
// executing a swap.
type Reason uint8
const (
// ReasonNone is the zero value reason, added so that this enum can
// align with the numeric values used in our protobufs and avoid
// ambiguity around default zero values.
ReasonNone Reason = iota
// ReasonBudgetNotStarted indicates that we do not recommend any swaps
// because the start time for our budget has not arrived yet.
ReasonBudgetNotStarted
// ReasonSweepFees indicates that the estimated fees to sweep swaps
// are too high right now.
ReasonSweepFees
// ReasonBudgetElapsed indicates that the autoloop budget for the
// period has been elapsed.
ReasonBudgetElapsed
// ReasonInFlight indicates that the limit on in-flight automatically
// dispatched swaps has already been reached.
ReasonInFlight
// ReasonSwapFee indicates that the server fee for a specific swap is
// too high.
ReasonSwapFee
// ReasonMinerFee indicates that the miner fee for a specific swap is
// to high.
ReasonMinerFee
// ReasonPrepay indicates that the prepay fee for a specific swap is
// too high.
ReasonPrepay
// ReasonFailureBackoff indicates that a swap has recently failed for
// this target, and the backoff period has not yet passed.
ReasonFailureBackoff
// ReasonLoopOut indicates that a loop out swap is currently utilizing
// the channel, so it is not eligible.
ReasonLoopOut
// ReasonLoopIn indicates that a loop in swap is currently in flight
// for the peer, so it is not eligible.
ReasonLoopIn
// ReasonLiquidityOk indicates that a target meets the liquidity
// balance expressed in its rule, so no swap is needed.
ReasonLiquidityOk
// ReasonBudgetInsufficient indicates that we cannot perform a swap
// because we do not have enough pending budget available. This differs
// from budget elapsed, because we still have some budget available,
// but we have allocated it to other swaps.
ReasonBudgetInsufficient
)

@ -21,6 +21,8 @@ import (
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/queue"
"github.com/lightningnetwork/lnd/routing/route"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
const (
@ -702,14 +704,23 @@ func rpcToRule(rule *looprpc.LiquidityRule) (*liquidity.ThresholdRule, error) {
func (s *swapClientServer) SuggestSwaps(ctx context.Context,
_ *looprpc.SuggestSwapsRequest) (*looprpc.SuggestSwapsResponse, error) {
swaps, err := s.liquidityMgr.SuggestSwaps(ctx, false)
if err != nil {
suggestions, err := s.liquidityMgr.SuggestSwaps(ctx, false)
switch err {
case liquidity.ErrNoRules:
return nil, status.Error(codes.FailedPrecondition, err.Error())
case nil:
default:
return nil, err
}
var loopOut []*looprpc.LoopOutRequest
var (
loopOut []*looprpc.LoopOutRequest
disqualified []*looprpc.Disqualified
)
for _, swap := range swaps {
for _, swap := range suggestions.OutSwaps {
loopOut = append(loopOut, &looprpc.LoopOutRequest{
Amt: int64(swap.Amount),
OutgoingChanSet: swap.OutgoingChanSet,
@ -722,11 +733,71 @@ func (s *swapClientServer) SuggestSwaps(ctx context.Context,
})
}
for id, reason := range suggestions.DisqualifiedChans {
autoloopReason, err := rpcAutoloopReason(reason)
if err != nil {
return nil, err
}
exclChan := &looprpc.Disqualified{
Reason: autoloopReason,
ChannelId: id.ToUint64(),
}
disqualified = append(disqualified, exclChan)
}
return &looprpc.SuggestSwapsResponse{
LoopOut: loopOut,
LoopOut: loopOut,
Disqualified: disqualified,
}, nil
}
func rpcAutoloopReason(reason liquidity.Reason) (looprpc.AutoReason, error) {
switch reason {
case liquidity.ReasonNone:
return looprpc.AutoReason_AUTO_REASON_UNKNOWN, nil
case liquidity.ReasonBudgetNotStarted:
return looprpc.AutoReason_AUTO_REASON_BUDGET_NOT_STARTED, nil
case liquidity.ReasonSweepFees:
return looprpc.AutoReason_AUTO_REASON_SWEEP_FEES, nil
case liquidity.ReasonBudgetElapsed:
return looprpc.AutoReason_AUTO_REASON_BUDGET_ELAPSED, nil
case liquidity.ReasonInFlight:
return looprpc.AutoReason_AUTO_REASON_IN_FLIGHT, nil
case liquidity.ReasonSwapFee:
return looprpc.AutoReason_AUTO_REASON_SWAP_FEE, nil
case liquidity.ReasonMinerFee:
return looprpc.AutoReason_AUTO_REASON_MINER_FEE, nil
case liquidity.ReasonPrepay:
return looprpc.AutoReason_AUTO_REASON_PREPAY, nil
case liquidity.ReasonFailureBackoff:
return looprpc.AutoReason_AUTO_REASON_FAILURE_BACKOFF, nil
case liquidity.ReasonLoopOut:
return looprpc.AutoReason_AUTO_REASON_LOOP_OUT, nil
case liquidity.ReasonLoopIn:
return looprpc.AutoReason_AUTO_REASON_LOOP_IN, nil
case liquidity.ReasonLiquidityOk:
return looprpc.AutoReason_AUTO_REASON_LIQUIDITY_OK, nil
case liquidity.ReasonBudgetInsufficient:
return looprpc.AutoReason_AUTO_REASON_BUDGET_INSUFFICIENT, nil
default:
return 0, fmt.Errorf("unknown autoloop reason: %v", reason)
}
}
// processStatusUpdates reads updates on the status channel and processes them.
//
// NOTE: This must run inside a goroutine as it blocks until the main context

@ -200,6 +200,99 @@ func (LiquidityRuleType) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_014de31d7ac8c57c, []int{3}
}
type AutoReason int32
const (
AutoReason_AUTO_REASON_UNKNOWN AutoReason = 0
//
//Budget not started indicates that we do not recommend any swaps because
//the start time for our budget has not arrived yet.
AutoReason_AUTO_REASON_BUDGET_NOT_STARTED AutoReason = 1
//
//Sweep fees indicates that the estimated fees to sweep swaps are too high
//right now.
AutoReason_AUTO_REASON_SWEEP_FEES AutoReason = 2
//
//Budget elapsed indicates that the autoloop budget for the period has been
//elapsed.
AutoReason_AUTO_REASON_BUDGET_ELAPSED AutoReason = 3
//
//In flight indicates that the limit on in-flight automatically dispatched
//swaps has already been reached.
AutoReason_AUTO_REASON_IN_FLIGHT AutoReason = 4
//
//Swap fee indicates that the server fee for a specific swap is too high.
AutoReason_AUTO_REASON_SWAP_FEE AutoReason = 5
//
//Miner fee indicates that the miner fee for a specific swap is to high.
AutoReason_AUTO_REASON_MINER_FEE AutoReason = 6
//
//Prepay indicates that the prepay fee for a specific swap is too high.
AutoReason_AUTO_REASON_PREPAY AutoReason = 7
//
//Failure backoff indicates that a swap has recently failed for this target,
//and the backoff period has not yet passed.
AutoReason_AUTO_REASON_FAILURE_BACKOFF AutoReason = 8
//
//Loop out indicates that a loop out swap is currently utilizing the channel,
//so it is not eligible.
AutoReason_AUTO_REASON_LOOP_OUT AutoReason = 9
//
//Loop In indicates that a loop in swap is currently in flight for the peer,
//so it is not eligible.
AutoReason_AUTO_REASON_LOOP_IN AutoReason = 10
//
//Liquidity ok indicates that a target meets the liquidity balance expressed
//in its rule, so no swap is needed.
AutoReason_AUTO_REASON_LIQUIDITY_OK AutoReason = 11
//
//Budget insufficient indicates that we cannot perform a swap because we do
//not have enough pending budget available. This differs from budget elapsed,
//because we still have some budget available, but we have allocated it to
//other swaps.
AutoReason_AUTO_REASON_BUDGET_INSUFFICIENT AutoReason = 12
)
var AutoReason_name = map[int32]string{
0: "AUTO_REASON_UNKNOWN",
1: "AUTO_REASON_BUDGET_NOT_STARTED",
2: "AUTO_REASON_SWEEP_FEES",
3: "AUTO_REASON_BUDGET_ELAPSED",
4: "AUTO_REASON_IN_FLIGHT",
5: "AUTO_REASON_SWAP_FEE",
6: "AUTO_REASON_MINER_FEE",
7: "AUTO_REASON_PREPAY",
8: "AUTO_REASON_FAILURE_BACKOFF",
9: "AUTO_REASON_LOOP_OUT",
10: "AUTO_REASON_LOOP_IN",
11: "AUTO_REASON_LIQUIDITY_OK",
12: "AUTO_REASON_BUDGET_INSUFFICIENT",
}
var AutoReason_value = map[string]int32{
"AUTO_REASON_UNKNOWN": 0,
"AUTO_REASON_BUDGET_NOT_STARTED": 1,
"AUTO_REASON_SWEEP_FEES": 2,
"AUTO_REASON_BUDGET_ELAPSED": 3,
"AUTO_REASON_IN_FLIGHT": 4,
"AUTO_REASON_SWAP_FEE": 5,
"AUTO_REASON_MINER_FEE": 6,
"AUTO_REASON_PREPAY": 7,
"AUTO_REASON_FAILURE_BACKOFF": 8,
"AUTO_REASON_LOOP_OUT": 9,
"AUTO_REASON_LOOP_IN": 10,
"AUTO_REASON_LIQUIDITY_OK": 11,
"AUTO_REASON_BUDGET_INSUFFICIENT": 12,
}
func (x AutoReason) String() string {
return proto.EnumName(AutoReason_name, int32(x))
}
func (AutoReason) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_014de31d7ac8c57c, []int{4}
}
type LoopOutRequest struct {
//
//Requested swap amount in sat. This does not include the swap and miner fee.
@ -1954,20 +2047,75 @@ func (m *SuggestSwapsRequest) XXX_DiscardUnknown() {
var xxx_messageInfo_SuggestSwapsRequest proto.InternalMessageInfo
type Disqualified struct {
//
//The short channel ID of the channel that was excluded from our suggestions.
ChannelId uint64 `protobuf:"varint,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"`
//
//The reason that we excluded the channel from the our suggestions.
Reason AutoReason `protobuf:"varint,2,opt,name=reason,proto3,enum=looprpc.AutoReason" json:"reason,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Disqualified) Reset() { *m = Disqualified{} }
func (m *Disqualified) String() string { return proto.CompactTextString(m) }
func (*Disqualified) ProtoMessage() {}
func (*Disqualified) Descriptor() ([]byte, []int) {
return fileDescriptor_014de31d7ac8c57c, []int{23}
}
func (m *Disqualified) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Disqualified.Unmarshal(m, b)
}
func (m *Disqualified) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Disqualified.Marshal(b, m, deterministic)
}
func (m *Disqualified) XXX_Merge(src proto.Message) {
xxx_messageInfo_Disqualified.Merge(m, src)
}
func (m *Disqualified) XXX_Size() int {
return xxx_messageInfo_Disqualified.Size(m)
}
func (m *Disqualified) XXX_DiscardUnknown() {
xxx_messageInfo_Disqualified.DiscardUnknown(m)
}
var xxx_messageInfo_Disqualified proto.InternalMessageInfo
func (m *Disqualified) GetChannelId() uint64 {
if m != nil {
return m.ChannelId
}
return 0
}
func (m *Disqualified) GetReason() AutoReason {
if m != nil {
return m.Reason
}
return AutoReason_AUTO_REASON_UNKNOWN
}
type SuggestSwapsResponse struct {
//
//The set of recommended loop outs.
LoopOut []*LoopOutRequest `protobuf:"bytes,1,rep,name=loop_out,json=loopOut,proto3" json:"loop_out,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
LoopOut []*LoopOutRequest `protobuf:"bytes,1,rep,name=loop_out,json=loopOut,proto3" json:"loop_out,omitempty"`
//
//Disqualified contains the set of channels that swaps are not recommended
//for.
Disqualified []*Disqualified `protobuf:"bytes,2,rep,name=disqualified,proto3" json:"disqualified,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *SuggestSwapsResponse) Reset() { *m = SuggestSwapsResponse{} }
func (m *SuggestSwapsResponse) String() string { return proto.CompactTextString(m) }
func (*SuggestSwapsResponse) ProtoMessage() {}
func (*SuggestSwapsResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_014de31d7ac8c57c, []int{23}
return fileDescriptor_014de31d7ac8c57c, []int{24}
}
func (m *SuggestSwapsResponse) XXX_Unmarshal(b []byte) error {
@ -1995,11 +2143,19 @@ func (m *SuggestSwapsResponse) GetLoopOut() []*LoopOutRequest {
return nil
}
func (m *SuggestSwapsResponse) GetDisqualified() []*Disqualified {
if m != nil {
return m.Disqualified
}
return nil
}
func init() {
proto.RegisterEnum("looprpc.SwapType", SwapType_name, SwapType_value)
proto.RegisterEnum("looprpc.SwapState", SwapState_name, SwapState_value)
proto.RegisterEnum("looprpc.FailureReason", FailureReason_name, FailureReason_value)
proto.RegisterEnum("looprpc.LiquidityRuleType", LiquidityRuleType_name, LiquidityRuleType_value)
proto.RegisterEnum("looprpc.AutoReason", AutoReason_name, AutoReason_value)
proto.RegisterType((*LoopOutRequest)(nil), "looprpc.LoopOutRequest")
proto.RegisterType((*LoopInRequest)(nil), "looprpc.LoopInRequest")
proto.RegisterType((*SwapResponse)(nil), "looprpc.SwapResponse")
@ -2023,163 +2179,177 @@ func init() {
proto.RegisterType((*SetLiquidityParamsRequest)(nil), "looprpc.SetLiquidityParamsRequest")
proto.RegisterType((*SetLiquidityParamsResponse)(nil), "looprpc.SetLiquidityParamsResponse")
proto.RegisterType((*SuggestSwapsRequest)(nil), "looprpc.SuggestSwapsRequest")
proto.RegisterType((*Disqualified)(nil), "looprpc.Disqualified")
proto.RegisterType((*SuggestSwapsResponse)(nil), "looprpc.SuggestSwapsResponse")
}
func init() { proto.RegisterFile("client.proto", fileDescriptor_014de31d7ac8c57c) }
var fileDescriptor_014de31d7ac8c57c = []byte{
// 2389 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0xcd, 0x6f, 0xe3, 0xc6,
0x15, 0x5f, 0x7d, 0x59, 0xd2, 0x13, 0x45, 0xd1, 0xe3, 0x5d, 0x5b, 0x56, 0x1c, 0xc4, 0xcb, 0x64,
0x1b, 0xc7, 0x49, 0xac, 0xc6, 0x39, 0x25, 0x48, 0x0a, 0x68, 0x65, 0x39, 0x96, 0x6b, 0x4b, 0x2a,
0x25, 0x6f, 0x90, 0xa2, 0x00, 0x31, 0x96, 0xc6, 0x16, 0x11, 0xf1, 0x23, 0xe4, 0x68, 0xd7, 0x46,
0xd0, 0x16, 0x28, 0xd0, 0x73, 0x0f, 0xfd, 0x0f, 0x7a, 0xef, 0xad, 0xb7, 0xf6, 0xde, 0x4b, 0x4f,
0xed, 0xb1, 0xd7, 0x5e, 0x7a, 0xe8, 0xff, 0x50, 0xcc, 0x1b, 0x92, 0x22, 0x65, 0xc9, 0x41, 0x0f,
0xbd, 0x89, 0xef, 0xfd, 0xe6, 0xcd, 0x9b, 0xf7, 0xfd, 0x04, 0xca, 0x78, 0x66, 0x31, 0x87, 0x1f,
0x79, 0xbe, 0xcb, 0x5d, 0x52, 0x9c, 0xb9, 0xae, 0xe7, 0x7b, 0xe3, 0xc6, 0xde, 0xad, 0xeb, 0xde,
0xce, 0x58, 0x93, 0x7a, 0x56, 0x93, 0x3a, 0x8e, 0xcb, 0x29, 0xb7, 0x5c, 0x27, 0x90, 0x30, 0xfd,
0x8f, 0x79, 0x50, 0x2f, 0x5c, 0xd7, 0xeb, 0xcf, 0xb9, 0xc1, 0xbe, 0x9b, 0xb3, 0x80, 0x13, 0x0d,
0x72, 0xd4, 0xe6, 0xf5, 0xcc, 0x7e, 0xe6, 0x20, 0x67, 0x88, 0x9f, 0x84, 0x40, 0x7e, 0xc2, 0x02,
0x5e, 0xcf, 0xee, 0x67, 0x0e, 0xca, 0x06, 0xfe, 0x26, 0x4d, 0x78, 0x6a, 0xd3, 0x3b, 0x33, 0x78,
0x43, 0x3d, 0xd3, 0x77, 0xe7, 0xdc, 0x72, 0x6e, 0xcd, 0x1b, 0xc6, 0xea, 0x39, 0x3c, 0xb6, 0x69,
0xd3, 0xbb, 0xe1, 0x1b, 0xea, 0x19, 0x92, 0x73, 0xca, 0x18, 0xf9, 0x14, 0xb6, 0xc5, 0x01, 0xcf,
0x67, 0x1e, 0xbd, 0x4f, 0x1d, 0xc9, 0xe3, 0x91, 0x2d, 0x9b, 0xde, 0x0d, 0x90, 0x99, 0x38, 0xb4,
0x0f, 0x4a, 0x7c, 0x8b, 0x80, 0x16, 0x10, 0x0a, 0xa1, 0x74, 0x81, 0x78, 0x0f, 0xd4, 0x84, 0x58,
0xa1, 0xf8, 0x06, 0x62, 0x94, 0x58, 0x5c, 0xcb, 0xe6, 0x44, 0x87, 0xaa, 0x40, 0xd9, 0x96, 0xc3,
0x7c, 0x14, 0x54, 0x44, 0x50, 0xc5, 0xa6, 0x77, 0x97, 0x82, 0x26, 0x24, 0x7d, 0x04, 0x9a, 0xb0,
0x99, 0xe9, 0xce, 0xb9, 0x39, 0x9e, 0x52, 0xc7, 0x61, 0xb3, 0x7a, 0x69, 0x3f, 0x73, 0x90, 0x7f,
0x99, 0xad, 0x67, 0x0c, 0x75, 0x26, 0xad, 0xd4, 0x96, 0x1c, 0x72, 0x08, 0x9b, 0xee, 0x9c, 0xdf,
0xba, 0xe2, 0x11, 0x02, 0x6d, 0x06, 0x8c, 0xd7, 0x2b, 0xfb, 0xb9, 0x83, 0xbc, 0x51, 0x8b, 0x18,
0x02, 0x3b, 0x64, 0x5c, 0x60, 0x83, 0x37, 0x8c, 0x79, 0xe6, 0xd8, 0x75, 0x6e, 0x4c, 0x4e, 0xfd,
0x5b, 0xc6, 0xeb, 0xe5, 0xfd, 0xcc, 0x41, 0xc1, 0xa8, 0x21, 0xa3, 0xed, 0x3a, 0x37, 0x23, 0x24,
0x93, 0x8f, 0x81, 0x4c, 0xf9, 0x6c, 0x8c, 0x50, 0xcb, 0xb7, 0xa5, 0xb3, 0xea, 0x55, 0x04, 0x6f,
0x0a, 0x4e, 0x3b, 0xc9, 0x20, 0x9f, 0xc3, 0x2e, 0x1a, 0xc7, 0x9b, 0x5f, 0xcf, 0xac, 0x31, 0x12,
0xcd, 0x09, 0xa3, 0x93, 0x99, 0xe5, 0xb0, 0x3a, 0x08, 0xed, 0x8d, 0x1d, 0x01, 0x18, 0x2c, 0xf8,
0x27, 0x21, 0x9b, 0x3c, 0x85, 0xc2, 0x8c, 0x5e, 0xb3, 0x59, 0x5d, 0x41, 0xbf, 0xca, 0x0f, 0xb2,
0x07, 0x65, 0xcb, 0xb1, 0xb8, 0x45, 0xb9, 0xeb, 0xd7, 0x55, 0xe4, 0x2c, 0x08, 0xfa, 0x6f, 0xb3,
0x50, 0x15, 0xf1, 0xd2, 0x75, 0xd6, 0x87, 0xcb, 0xb2, 0xd3, 0xb2, 0x0f, 0x9c, 0xf6, 0xc0, 0x1d,
0xb9, 0x87, 0xee, 0xd8, 0x85, 0xd2, 0x8c, 0x06, 0xdc, 0x9c, 0xba, 0x1e, 0x46, 0x88, 0x62, 0x14,
0xc5, 0xf7, 0x99, 0xeb, 0x91, 0x77, 0xa1, 0xca, 0xee, 0x38, 0xf3, 0x1d, 0x3a, 0x33, 0x85, 0x49,
0x30, 0x2c, 0x4a, 0x86, 0x12, 0x11, 0xcf, 0xf8, 0x6c, 0x4c, 0x0e, 0x40, 0x8b, 0x0d, 0x19, 0xd9,
0x7c, 0x03, 0xcd, 0xa8, 0x46, 0x66, 0x0c, 0x4d, 0x1e, 0xdb, 0xa1, 0xb8, 0xd6, 0x0e, 0xa5, 0x65,
0x3b, 0xfc, 0x3b, 0x03, 0x0a, 0x06, 0x38, 0x0b, 0x3c, 0xd7, 0x09, 0x18, 0x21, 0x90, 0xb5, 0x26,
0x68, 0x85, 0x32, 0xc6, 0x4b, 0xd6, 0x9a, 0x88, 0x27, 0x58, 0x13, 0xf3, 0xfa, 0x9e, 0xb3, 0x00,
0x5f, 0xa8, 0x18, 0x45, 0x6b, 0xf2, 0x52, 0x7c, 0x92, 0x17, 0xa0, 0xa0, 0x76, 0x74, 0x32, 0xf1,
0x59, 0x10, 0xc8, 0xd4, 0xc2, 0x83, 0x15, 0x41, 0x6f, 0x49, 0x32, 0x39, 0x82, 0xad, 0x24, 0xcc,
0x74, 0xbc, 0xe3, 0x37, 0xc1, 0x14, 0xed, 0x51, 0x96, 0xe1, 0x10, 0x22, 0x7b, 0xc8, 0x20, 0x1f,
0x85, 0xd1, 0x13, 0xe1, 0x25, 0xbc, 0x80, 0x70, 0x2d, 0x01, 0x1f, 0x20, 0xfa, 0x05, 0xa8, 0x01,
0xf3, 0x5f, 0x33, 0xdf, 0xb4, 0x59, 0x10, 0xd0, 0x5b, 0x86, 0x06, 0x2a, 0x1b, 0x55, 0x49, 0xbd,
0x94, 0x44, 0x5d, 0x03, 0xf5, 0xd2, 0x75, 0x2c, 0xee, 0xfa, 0xa1, 0xcf, 0xf5, 0x3f, 0xe5, 0x01,
0xc4, 0xeb, 0x87, 0x9c, 0xf2, 0x79, 0xb0, 0xb2, 0x62, 0x08, 0x6b, 0x64, 0xd7, 0x5a, 0xa3, 0xb2,
0x6c, 0x8d, 0x3c, 0xbf, 0xf7, 0x64, 0x18, 0xa8, 0xc7, 0x9b, 0x47, 0x61, 0xed, 0x3a, 0x12, 0x77,
0x8c, 0xee, 0x3d, 0x66, 0x20, 0x9b, 0x1c, 0x40, 0x21, 0xe0, 0x94, 0xcb, 0x8a, 0xa1, 0x1e, 0x93,
0x14, 0x4e, 0xe8, 0xc2, 0x0c, 0x09, 0x20, 0x5f, 0x82, 0x7a, 0x43, 0xad, 0xd9, 0xdc, 0x67, 0xa6,
0xcf, 0x68, 0xe0, 0x3a, 0x18, 0xc9, 0xea, 0xf1, 0x76, 0x7c, 0xe4, 0x54, 0xb2, 0x0d, 0xe4, 0x1a,
0xd5, 0x9b, 0xe4, 0x27, 0x79, 0x1f, 0x6a, 0xa1, 0xab, 0x45, 0x3e, 0x71, 0xcb, 0x8e, 0x2a, 0x8f,
0xba, 0x20, 0x8f, 0x2c, 0x5b, 0x68, 0xa4, 0x61, 0x90, 0xce, 0xbd, 0x09, 0xe5, 0x4c, 0x22, 0x65,
0xfd, 0x51, 0x05, 0xfd, 0x0a, 0xc9, 0x88, 0x5c, 0x76, 0x78, 0x71, 0xb5, 0xc3, 0x57, 0x3b, 0x50,
0x59, 0xe3, 0xc0, 0x35, 0xe1, 0x51, 0x5d, 0x17, 0x1e, 0xef, 0x40, 0x65, 0xec, 0x06, 0xdc, 0x94,
0xfe, 0xc5, 0xa8, 0xce, 0x19, 0x20, 0x48, 0x43, 0xa4, 0x90, 0xe7, 0xa0, 0x20, 0xc0, 0x75, 0xc6,
0x53, 0x6a, 0x39, 0x58, 0xa4, 0x72, 0x06, 0x1e, 0xea, 0x4b, 0x92, 0x48, 0x3e, 0x09, 0xb9, 0xb9,
0x91, 0x18, 0x90, 0xf5, 0x16, 0x31, 0x21, 0x6d, 0x91, 0x52, 0xb5, 0x44, 0x4a, 0xe9, 0x04, 0xb4,
0x0b, 0x2b, 0xe0, 0xc2, 0x5b, 0x41, 0x14, 0x4a, 0x3f, 0x81, 0xcd, 0x04, 0x2d, 0x4c, 0xa6, 0x0f,
0xa0, 0x20, 0xaa, 0x47, 0x50, 0xcf, 0xec, 0xe7, 0x0e, 0x2a, 0xc7, 0x5b, 0x0f, 0x1c, 0x3d, 0x0f,
0x0c, 0x89, 0xd0, 0x9f, 0x43, 0x4d, 0x10, 0xbb, 0xce, 0x8d, 0x1b, 0x55, 0x24, 0x35, 0x4e, 0x45,
0x45, 0x04, 0x9e, 0xae, 0x82, 0x32, 0x62, 0xbe, 0x1d, 0x5f, 0xf9, 0x6b, 0xa8, 0x75, 0x9d, 0x90,
0x12, 0x5e, 0xf8, 0x23, 0xa8, 0xd9, 0x96, 0x23, 0x4b, 0x16, 0xb5, 0xdd, 0xb9, 0xc3, 0x43, 0x87,
0x57, 0x6d, 0xcb, 0x11, 0xf2, 0x5b, 0x48, 0x44, 0x5c, 0x54, 0xda, 0x42, 0xdc, 0x46, 0x88, 0x93,
0xd5, 0x4d, 0xe2, 0xce, 0xf3, 0xa5, 0x8c, 0x96, 0x3d, 0xcf, 0x97, 0xb2, 0x5a, 0xee, 0x3c, 0x5f,
0xca, 0x69, 0xf9, 0xf3, 0x7c, 0x29, 0xaf, 0x15, 0xce, 0xf3, 0xa5, 0xa2, 0x56, 0xd2, 0xff, 0x96,
0x01, 0xad, 0x3f, 0xe7, 0xff, 0x57, 0x15, 0xb0, 0x31, 0x5a, 0x8e, 0x39, 0x9e, 0xf1, 0xd7, 0xe6,
0x84, 0xcd, 0x38, 0x45, 0x77, 0x17, 0x0c, 0xc5, 0xb6, 0x9c, 0xf6, 0x8c, 0xbf, 0x3e, 0x11, 0xb4,
0xa8, 0x7d, 0x26, 0x50, 0xe5, 0x10, 0x45, 0xef, 0x62, 0xd4, 0x0f, 0x3c, 0xe7, 0x0f, 0x19, 0x50,
0x7e, 0x36, 0x77, 0x39, 0x5b, 0xdf, 0x12, 0x30, 0xf0, 0x16, 0x75, 0x38, 0x8b, 0x77, 0xc0, 0x78,
0x51, 0x83, 0x1f, 0x94, 0xf4, 0xdc, 0x8a, 0x92, 0xfe, 0x68, 0xb3, 0xcb, 0x3f, 0xda, 0xec, 0xf4,
0xdf, 0x65, 0x84, 0xd7, 0x43, 0x35, 0x43, 0x93, 0xef, 0x83, 0x12, 0x35, 0x29, 0x33, 0xa0, 0x91,
0xc2, 0x10, 0xc8, 0x2e, 0x35, 0xa4, 0x38, 0xe5, 0x60, 0x82, 0xe1, 0x8d, 0xc1, 0x34, 0x46, 0x86,
0x53, 0x8e, 0xe0, 0x0d, 0x24, 0x2b, 0x3c, 0xf0, 0x36, 0x40, 0xc2, 0x96, 0x05, 0x7c, 0x67, 0x79,
0x9c, 0x30, 0xa4, 0x34, 0x61, 0x5e, 0x2b, 0xe8, 0x7f, 0x97, 0x51, 0xf0, 0xbf, 0xaa, 0xf4, 0x1e,
0xa8, 0x8b, 0x61, 0x07, 0x31, 0xb2, 0xbf, 0x2a, 0x5e, 0x34, 0xed, 0x08, 0xd4, 0x87, 0x61, 0x1d,
0x91, 0x73, 0x47, 0x5a, 0xed, 0x9a, 0xe0, 0x0c, 0x05, 0x23, 0x14, 0x89, 0xf3, 0x89, 0xb0, 0x2b,
0xbd, 0xb7, 0x99, 0xc3, 0x4d, 0x1c, 0xf6, 0x64, 0xcf, 0xad, 0xa1, 0x3d, 0x25, 0xfd, 0x44, 0xf8,
0xf6, 0xf1, 0x07, 0xea, 0x35, 0xa8, 0x8e, 0xdc, 0x6f, 0x99, 0x13, 0x27, 0xdb, 0x17, 0xa0, 0x46,
0x84, 0xf0, 0x89, 0x87, 0xb0, 0xc1, 0x91, 0x12, 0x66, 0xf7, 0xa2, 0x8c, 0x5f, 0x04, 0x94, 0x23,
0xd8, 0x08, 0x11, 0xfa, 0x9f, 0xb3, 0x50, 0x8e, 0xa9, 0x22, 0x48, 0xae, 0x69, 0xc0, 0x4c, 0x9b,
0x8e, 0xa9, 0xef, 0xba, 0x4e, 0x98, 0xe3, 0x8a, 0x20, 0x5e, 0x86, 0x34, 0x51, 0xc2, 0xa2, 0x77,
0x4c, 0x69, 0x30, 0x45, 0xeb, 0x28, 0x46, 0x25, 0xa4, 0x9d, 0xd1, 0x60, 0x4a, 0x3e, 0x00, 0x2d,
0x82, 0x78, 0x3e, 0xb3, 0x6c, 0xd1, 0xf9, 0x64, 0x7f, 0xae, 0x85, 0xf4, 0x41, 0x48, 0x16, 0x05,
0x5e, 0x26, 0x99, 0xe9, 0x51, 0x6b, 0x62, 0xda, 0xc2, 0x8a, 0x72, 0x5e, 0x55, 0x25, 0x7d, 0x40,
0xad, 0xc9, 0x65, 0x40, 0x39, 0xf9, 0x04, 0x9e, 0x25, 0x86, 0xda, 0x04, 0x5c, 0x66, 0x31, 0xf1,
0xe3, 0xa9, 0x36, 0x3e, 0xf2, 0x1c, 0x14, 0xd1, 0x31, 0xcc, 0xb1, 0xcf, 0x28, 0x67, 0x93, 0x30,
0x8f, 0x2b, 0x82, 0xd6, 0x96, 0x24, 0x52, 0x87, 0x22, 0xbb, 0xf3, 0x2c, 0x9f, 0x4d, 0xb0, 0x63,
0x94, 0x8c, 0xe8, 0x53, 0x1c, 0x0e, 0xb8, 0xeb, 0xd3, 0x5b, 0x66, 0x3a, 0xd4, 0x66, 0xe1, 0x88,
0x52, 0x09, 0x69, 0x3d, 0x6a, 0x33, 0xfd, 0x2d, 0xd8, 0xfd, 0x8a, 0xf1, 0x0b, 0xeb, 0xbb, 0xb9,
0x35, 0xb1, 0xf8, 0xfd, 0x80, 0xfa, 0x74, 0x51, 0x05, 0xff, 0x5a, 0x80, 0xad, 0x34, 0x8b, 0x71,
0xe6, 0x8b, 0x0e, 0x54, 0xf0, 0xe7, 0x33, 0x16, 0x79, 0x67, 0xd1, 0x31, 0x63, 0xb0, 0x31, 0x9f,
0x31, 0x43, 0x82, 0xc8, 0x97, 0xb0, 0xb7, 0x08, 0x31, 0x5f, 0xf4, 0xc0, 0x80, 0x72, 0xd3, 0x63,
0xbe, 0xf9, 0x5a, 0x74, 0x7a, 0xb4, 0x3e, 0x66, 0xa5, 0x8c, 0x36, 0x83, 0x72, 0x11, 0x71, 0x03,
0xe6, 0xbf, 0x12, 0x6c, 0xf2, 0x3e, 0x68, 0xc9, 0x51, 0xd1, 0xf4, 0x3c, 0x1b, 0x3d, 0x91, 0x8f,
0xab, 0x99, 0xb0, 0x97, 0x67, 0x93, 0x8f, 0x41, 0xec, 0x07, 0x66, 0xca, 0xc2, 0x9e, 0x1d, 0x26,
0xbd, 0x90, 0xb1, 0x58, 0x1a, 0x04, 0xfc, 0x73, 0x68, 0xac, 0x5e, 0x36, 0xf0, 0x54, 0x01, 0x4f,
0x6d, 0xaf, 0x58, 0x38, 0xc4, 0xd9, 0xf4, 0x46, 0x21, 0x3c, 0xb8, 0x81, 0xf8, 0xc5, 0x46, 0x21,
0x72, 0xe6, 0x03, 0xd8, 0x4c, 0x8d, 0xb0, 0x08, 0x2c, 0x22, 0x50, 0x4d, 0x8c, 0xb1, 0x71, 0x7a,
0x2d, 0x8f, 0xff, 0xa5, 0xd5, 0xe3, 0xff, 0x11, 0x6c, 0x45, 0x83, 0xcb, 0x35, 0x1d, 0x7f, 0xeb,
0xde, 0xdc, 0x98, 0x01, 0x1b, 0x63, 0x51, 0xce, 0x1b, 0x9b, 0x21, 0xeb, 0xa5, 0xe4, 0x0c, 0xd9,
0x98, 0x34, 0xa0, 0x44, 0xe7, 0xdc, 0x15, 0x3e, 0xc2, 0x46, 0x5c, 0x32, 0xe2, 0x6f, 0x21, 0x2b,
0xfa, 0x6d, 0x5e, 0xcf, 0x27, 0xb7, 0x4c, 0x96, 0x8b, 0x8a, 0x94, 0x15, 0xb1, 0x5e, 0x22, 0x47,
0xe8, 0xf9, 0x19, 0xec, 0x3e, 0xc0, 0x73, 0xea, 0x73, 0xd4, 0x40, 0x91, 0x36, 0x5b, 0x3a, 0x25,
0xd8, 0x42, 0x8d, 0x0f, 0x81, 0x08, 0x8e, 0x29, 0x4c, 0x62, 0x39, 0xe6, 0xcd, 0xcc, 0xba, 0x9d,
0x72, 0x9c, 0x43, 0xf2, 0x46, 0x4d, 0x70, 0x2e, 0xe9, 0x5d, 0xd7, 0x39, 0x45, 0xf2, 0xaa, 0x4e,
0xa7, 0x86, 0x3e, 0xff, 0xa1, 0x4e, 0x57, 0x4b, 0xc5, 0x86, 0xc4, 0xe9, 0x7f, 0xc9, 0x40, 0x35,
0x15, 0x9c, 0x58, 0xa4, 0xe4, 0x9e, 0x66, 0x86, 0x93, 0x40, 0xde, 0x28, 0x87, 0x94, 0xee, 0x84,
0x1c, 0x85, 0xe3, 0x66, 0x16, 0x67, 0xc2, 0xc6, 0xea, 0x08, 0x4f, 0xcc, 0x9d, 0x1f, 0x03, 0xb1,
0x9c, 0xb1, 0x6b, 0x8b, 0x18, 0xe2, 0x53, 0x9f, 0x05, 0x53, 0x77, 0x36, 0xc1, 0x38, 0xad, 0x1a,
0x9b, 0x11, 0x67, 0x14, 0x31, 0x04, 0x3c, 0x5e, 0x0d, 0x17, 0xf0, 0xbc, 0x84, 0x47, 0x9c, 0x18,
0xae, 0x7f, 0x03, 0xbb, 0xc3, 0x75, 0x59, 0x4a, 0xbe, 0x00, 0xf0, 0xe2, 0xdc, 0xc4, 0x97, 0x54,
0x8e, 0xf7, 0x1e, 0x2a, 0xbc, 0xc8, 0x5f, 0x23, 0x81, 0xd7, 0xf7, 0xa0, 0xb1, 0x4a, 0xb4, 0x2c,
0xc4, 0xfa, 0x33, 0xd8, 0x1a, 0xce, 0x6f, 0x6f, 0xd9, 0xd2, 0x44, 0x76, 0x0e, 0x4f, 0xd3, 0xe4,
0xb0, 0x6e, 0x1f, 0x43, 0x29, 0xda, 0x8f, 0xc3, 0xda, 0xb0, 0xb3, 0x50, 0x24, 0xf5, 0x17, 0x82,
0x51, 0x0c, 0x97, 0xe5, 0xc3, 0x17, 0x50, 0x8a, 0x66, 0x78, 0xa2, 0x40, 0xe9, 0xa2, 0xdf, 0x1f,
0x98, 0xfd, 0xab, 0x91, 0xf6, 0x84, 0x54, 0xa0, 0x88, 0x5f, 0xdd, 0x9e, 0x96, 0x39, 0x0c, 0xa0,
0x1c, 0x8f, 0xf0, 0xa4, 0x0a, 0xe5, 0x6e, 0xaf, 0x3b, 0xea, 0xb6, 0x46, 0x9d, 0x13, 0xed, 0x09,
0x79, 0x06, 0x9b, 0x03, 0xa3, 0xd3, 0xbd, 0x6c, 0x7d, 0xd5, 0x31, 0x8d, 0xce, 0xab, 0x4e, 0xeb,
0xa2, 0x73, 0xa2, 0x65, 0x08, 0x01, 0xf5, 0x6c, 0x74, 0xd1, 0x36, 0x07, 0x57, 0x2f, 0x2f, 0xba,
0xc3, 0xb3, 0xce, 0x89, 0x96, 0x15, 0x32, 0x87, 0x57, 0xed, 0x76, 0x67, 0x38, 0xd4, 0x72, 0x04,
0x60, 0xe3, 0xb4, 0xd5, 0x15, 0xe0, 0x3c, 0xd9, 0x82, 0x5a, 0xb7, 0xf7, 0xaa, 0xdf, 0x6d, 0x77,
0xcc, 0x61, 0x67, 0x34, 0x12, 0xc4, 0xc2, 0xe1, 0x7f, 0x32, 0x50, 0x4d, 0x6d, 0x01, 0x64, 0x07,
0xb6, 0xc4, 0x91, 0x2b, 0x43, 0xdc, 0xd4, 0x1a, 0xf6, 0x7b, 0x66, 0xaf, 0xdf, 0xeb, 0x68, 0x4f,
0xc8, 0x5b, 0xb0, 0xb3, 0xc4, 0xe8, 0x9f, 0x9e, 0xb6, 0xcf, 0x5a, 0x42, 0x79, 0xd2, 0x80, 0xed,
0x25, 0xe6, 0xa8, 0x7b, 0xd9, 0x11, 0xaf, 0xcc, 0x92, 0x7d, 0xd8, 0x5b, 0xe2, 0x0d, 0xbf, 0xee,
0x74, 0x06, 0x31, 0x22, 0x47, 0x5e, 0xc0, 0xf3, 0x25, 0x44, 0xb7, 0x37, 0xbc, 0x3a, 0x3d, 0xed,
0xb6, 0xbb, 0x9d, 0xde, 0xc8, 0x7c, 0xd5, 0xba, 0xb8, 0xea, 0x68, 0x79, 0xb2, 0x07, 0xf5, 0xe5,
0x4b, 0x3a, 0x97, 0x83, 0xbe, 0xd1, 0x32, 0xbe, 0xd1, 0x0a, 0xe4, 0x5d, 0x78, 0xe7, 0x81, 0x90,
0x76, 0xdf, 0x30, 0x3a, 0xed, 0x91, 0xd9, 0xba, 0xec, 0x5f, 0xf5, 0x46, 0xda, 0xc6, 0x61, 0x53,
0x4c, 0xda, 0x4b, 0x01, 0x2e, 0x4c, 0x76, 0xd5, 0xfb, 0x69, 0xaf, 0xff, 0x75, 0x4f, 0x7b, 0x22,
0x2c, 0x3f, 0x3a, 0x33, 0x3a, 0xc3, 0xb3, 0xfe, 0xc5, 0x89, 0x96, 0x39, 0xfe, 0x67, 0x59, 0x6e,
0x79, 0x6d, 0xfc, 0x5f, 0x89, 0x18, 0x50, 0x0c, 0xdd, 0x4c, 0xd6, 0x39, 0xbe, 0xf1, 0x2c, 0x35,
0xa9, 0xc7, 0x91, 0xb6, 0xf3, 0x9b, 0x7f, 0xfc, 0xeb, 0xf7, 0xd9, 0x4d, 0x5d, 0x69, 0xbe, 0xfe,
0xa4, 0x29, 0x10, 0x4d, 0x77, 0xce, 0x3f, 0xcf, 0x1c, 0x92, 0x3e, 0x6c, 0xc8, 0x7f, 0x13, 0xc8,
0x76, 0x4a, 0x64, 0xfc, 0xf7, 0xc2, 0x3a, 0x89, 0xdb, 0x28, 0x51, 0xd3, 0x2b, 0xb1, 0x44, 0xcb,
0x11, 0x02, 0x3f, 0x83, 0x62, 0xb8, 0xab, 0x26, 0x94, 0x4c, 0x6f, 0xaf, 0x8d, 0x55, 0xeb, 0xc4,
0x8f, 0x33, 0xe4, 0xe7, 0x50, 0x8e, 0x37, 0x11, 0xb2, 0x9b, 0xc8, 0xb1, 0x74, 0x7e, 0x34, 0x1a,
0xab, 0x58, 0x69, 0xb5, 0x88, 0x1a, 0xab, 0x85, 0x5b, 0x0a, 0xb9, 0x92, 0x79, 0x20, 0xb6, 0x14,
0x52, 0x4f, 0x5d, 0x9f, 0x58, 0x5c, 0x56, 0x2a, 0xa6, 0x37, 0x50, 0xe4, 0x53, 0x42, 0x52, 0x22,
0x9b, 0xdf, 0x5b, 0x93, 0x5f, 0x92, 0x5f, 0x80, 0x12, 0x3a, 0x00, 0x77, 0x09, 0xb2, 0x30, 0x56,
0x72, 0xe1, 0x69, 0x2c, 0x1e, 0xb3, 0xbc, 0x75, 0xac, 0x90, 0xee, 0xce, 0x79, 0x93, 0xa3, 0xb4,
0xeb, 0x58, 0x3a, 0xce, 0xa8, 0x09, 0xe9, 0xc9, 0x69, 0x3f, 0x2d, 0x3d, 0x35, 0xcd, 0xea, 0xfb,
0x28, 0xbd, 0x41, 0xea, 0x29, 0xe9, 0xdf, 0x09, 0x4c, 0xf3, 0x7b, 0x6a, 0x73, 0xf1, 0x02, 0x55,
0x8c, 0x28, 0xe8, 0xf2, 0x47, 0xdf, 0xb0, 0xb0, 0xda, 0xd2, 0xee, 0xa6, 0xef, 0xe2, 0x25, 0x5b,
0x64, 0x33, 0x11, 0x0a, 0xf1, 0x0b, 0x16, 0xd2, 0x1f, 0x7d, 0x43, 0x52, 0x7a, 0xfa, 0x09, 0xef,
0xa0, 0xf4, 0x5d, 0xb2, 0x93, 0x94, 0x9e, 0x7c, 0xc1, 0x37, 0x50, 0x15, 0x77, 0x44, 0x43, 0x6a,
0x90, 0x88, 0xe4, 0xd4, 0x24, 0xdc, 0xd8, 0x79, 0x40, 0x4f, 0x67, 0x07, 0xa9, 0xe1, 0x15, 0x01,
0xe5, 0x4d, 0x39, 0xfd, 0x12, 0x0e, 0xe4, 0xe1, 0xfc, 0x46, 0xf4, 0x58, 0xce, 0xda, 0xe1, 0xae,
0xf1, 0x68, 0x8b, 0xd0, 0xf7, 0xf0, 0xc2, 0x6d, 0xf2, 0x14, 0x2f, 0x8c, 0x00, 0x4d, 0x4f, 0xca,
0xff, 0x15, 0x90, 0xe1, 0x63, 0xb7, 0xae, 0x6d, 0x56, 0x8d, 0x77, 0x1f, 0xc5, 0xa4, 0x0d, 0xaa,
0xaf, 0xbc, 0x5c, 0xa4, 0x30, 0x03, 0x25, 0xd9, 0x7f, 0xc8, 0xe2, 0x2d, 0x2b, 0xba, 0x55, 0xe3,
0xed, 0x35, 0xdc, 0xf0, 0xb6, 0x3a, 0xde, 0x46, 0x88, 0x26, 0x6e, 0x13, 0x83, 0x48, 0x33, 0x90,
0xb0, 0xeb, 0x0d, 0xfc, 0x03, 0xfc, 0xd3, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0xe8, 0x03, 0x91,
0x2d, 0x37, 0x17, 0x00, 0x00,
// 2605 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x59, 0x4b, 0x73, 0x1b, 0xc7,
0xf1, 0x17, 0x5e, 0x04, 0xd0, 0x58, 0x00, 0xcb, 0xa1, 0x44, 0x82, 0x30, 0x6d, 0x51, 0x6b, 0xeb,
0x6f, 0x9a, 0xb6, 0xc5, 0xbf, 0xe9, 0x93, 0x5d, 0x76, 0xaa, 0x40, 0x70, 0x29, 0x42, 0x26, 0x01,
0x78, 0x01, 0xc8, 0x25, 0x57, 0xaa, 0xb6, 0x86, 0xc0, 0x90, 0xdc, 0x32, 0xf6, 0xa1, 0xdd, 0x81,
0x44, 0x95, 0x2b, 0x49, 0x55, 0x2a, 0x3e, 0xe7, 0x90, 0x6f, 0x90, 0x7b, 0x6e, 0xb9, 0x25, 0xf7,
0x5c, 0x72, 0x4a, 0x8e, 0xb9, 0xe6, 0x92, 0x43, 0xbe, 0x43, 0x6a, 0x7a, 0x76, 0x17, 0xbb, 0x20,
0x40, 0x55, 0x0e, 0xb9, 0x11, 0xdd, 0xbf, 0xe9, 0x9e, 0x7e, 0x4e, 0xf7, 0x12, 0x94, 0xf1, 0xd4,
0x62, 0x0e, 0x7f, 0xe2, 0xf9, 0x2e, 0x77, 0x49, 0x71, 0xea, 0xba, 0x9e, 0xef, 0x8d, 0x9b, 0x3b,
0x57, 0xae, 0x7b, 0x35, 0x65, 0x07, 0xd4, 0xb3, 0x0e, 0xa8, 0xe3, 0xb8, 0x9c, 0x72, 0xcb, 0x75,
0x02, 0x09, 0xd3, 0xfe, 0x90, 0x87, 0xda, 0x99, 0xeb, 0x7a, 0xbd, 0x19, 0x37, 0xd8, 0xcb, 0x19,
0x0b, 0x38, 0x51, 0x21, 0x47, 0x6d, 0xde, 0xc8, 0xec, 0x66, 0xf6, 0x72, 0x86, 0xf8, 0x93, 0x10,
0xc8, 0x4f, 0x58, 0xc0, 0x1b, 0xd9, 0xdd, 0xcc, 0x5e, 0xd9, 0xc0, 0xbf, 0xc9, 0x01, 0xdc, 0xb7,
0xe9, 0x8d, 0x19, 0xbc, 0xa6, 0x9e, 0xe9, 0xbb, 0x33, 0x6e, 0x39, 0x57, 0xe6, 0x25, 0x63, 0x8d,
0x1c, 0x1e, 0x5b, 0xb7, 0xe9, 0xcd, 0xe0, 0x35, 0xf5, 0x0c, 0xc9, 0x39, 0x61, 0x8c, 0x7c, 0x0e,
0x9b, 0xe2, 0x80, 0xe7, 0x33, 0x8f, 0xbe, 0x49, 0x1d, 0xc9, 0xe3, 0x91, 0x0d, 0x9b, 0xde, 0xf4,
0x91, 0x99, 0x38, 0xb4, 0x0b, 0x4a, 0xac, 0x45, 0x40, 0x0b, 0x08, 0x85, 0x50, 0xba, 0x40, 0x7c,
0x00, 0xb5, 0x84, 0x58, 0x71, 0xf1, 0x35, 0xc4, 0x28, 0xb1, 0xb8, 0x96, 0xcd, 0x89, 0x06, 0x55,
0x81, 0xb2, 0x2d, 0x87, 0xf9, 0x28, 0xa8, 0x88, 0xa0, 0x8a, 0x4d, 0x6f, 0xce, 0x05, 0x4d, 0x48,
0xfa, 0x04, 0x54, 0xe1, 0x33, 0xd3, 0x9d, 0x71, 0x73, 0x7c, 0x4d, 0x1d, 0x87, 0x4d, 0x1b, 0xa5,
0xdd, 0xcc, 0x5e, 0xfe, 0x28, 0xdb, 0xc8, 0x18, 0xb5, 0xa9, 0xf4, 0x52, 0x5b, 0x72, 0xc8, 0x3e,
0xac, 0xbb, 0x33, 0x7e, 0xe5, 0x0a, 0x23, 0x04, 0xda, 0x0c, 0x18, 0x6f, 0x54, 0x76, 0x73, 0x7b,
0x79, 0xa3, 0x1e, 0x31, 0x04, 0x76, 0xc0, 0xb8, 0xc0, 0x06, 0xaf, 0x19, 0xf3, 0xcc, 0xb1, 0xeb,
0x5c, 0x9a, 0x9c, 0xfa, 0x57, 0x8c, 0x37, 0xca, 0xbb, 0x99, 0xbd, 0x82, 0x51, 0x47, 0x46, 0xdb,
0x75, 0x2e, 0x87, 0x48, 0x26, 0x9f, 0x02, 0xb9, 0xe6, 0xd3, 0x31, 0x42, 0x2d, 0xdf, 0x96, 0xc1,
0x6a, 0x54, 0x11, 0xbc, 0x2e, 0x38, 0xed, 0x24, 0x83, 0x7c, 0x09, 0xdb, 0xe8, 0x1c, 0x6f, 0x76,
0x31, 0xb5, 0xc6, 0x48, 0x34, 0x27, 0x8c, 0x4e, 0xa6, 0x96, 0xc3, 0x1a, 0x20, 0x6e, 0x6f, 0x6c,
0x09, 0x40, 0x7f, 0xce, 0x3f, 0x0e, 0xd9, 0xe4, 0x3e, 0x14, 0xa6, 0xf4, 0x82, 0x4d, 0x1b, 0x0a,
0xc6, 0x55, 0xfe, 0x20, 0x3b, 0x50, 0xb6, 0x1c, 0x8b, 0x5b, 0x94, 0xbb, 0x7e, 0xa3, 0x86, 0x9c,
0x39, 0x41, 0xfb, 0x29, 0x0b, 0x55, 0x91, 0x2f, 0x1d, 0x67, 0x75, 0xba, 0x2c, 0x06, 0x2d, 0x7b,
0x2b, 0x68, 0xb7, 0xc2, 0x91, 0xbb, 0x1d, 0x8e, 0x6d, 0x28, 0x4d, 0x69, 0xc0, 0xcd, 0x6b, 0xd7,
0xc3, 0x0c, 0x51, 0x8c, 0xa2, 0xf8, 0x7d, 0xea, 0x7a, 0xe4, 0x7d, 0xa8, 0xb2, 0x1b, 0xce, 0x7c,
0x87, 0x4e, 0x4d, 0xe1, 0x12, 0x4c, 0x8b, 0x92, 0xa1, 0x44, 0xc4, 0x53, 0x3e, 0x1d, 0x93, 0x3d,
0x50, 0x63, 0x47, 0x46, 0x3e, 0x5f, 0x43, 0x37, 0xd6, 0x22, 0x37, 0x86, 0x2e, 0x8f, 0xfd, 0x50,
0x5c, 0xe9, 0x87, 0xd2, 0xa2, 0x1f, 0xfe, 0x95, 0x01, 0x05, 0x13, 0x9c, 0x05, 0x9e, 0xeb, 0x04,
0x8c, 0x10, 0xc8, 0x5a, 0x13, 0xf4, 0x42, 0x19, 0xf3, 0x25, 0x6b, 0x4d, 0x84, 0x09, 0xd6, 0xc4,
0xbc, 0x78, 0xc3, 0x59, 0x80, 0x16, 0x2a, 0x46, 0xd1, 0x9a, 0x1c, 0x89, 0x9f, 0xe4, 0x31, 0x28,
0x78, 0x3b, 0x3a, 0x99, 0xf8, 0x2c, 0x08, 0x64, 0x69, 0xe1, 0xc1, 0x8a, 0xa0, 0xb7, 0x24, 0x99,
0x3c, 0x81, 0x8d, 0x24, 0xcc, 0x74, 0xbc, 0xc3, 0xd7, 0xc1, 0x35, 0xfa, 0xa3, 0x2c, 0xd3, 0x21,
0x44, 0x76, 0x91, 0x41, 0x3e, 0x09, 0xb3, 0x27, 0xc2, 0x4b, 0x78, 0x01, 0xe1, 0x6a, 0x02, 0xde,
0x47, 0xf4, 0x63, 0xa8, 0x05, 0xcc, 0x7f, 0xc5, 0x7c, 0xd3, 0x66, 0x41, 0x40, 0xaf, 0x18, 0x3a,
0xa8, 0x6c, 0x54, 0x25, 0xf5, 0x5c, 0x12, 0x35, 0x15, 0x6a, 0xe7, 0xae, 0x63, 0x71, 0xd7, 0x0f,
0x63, 0xae, 0xfd, 0x31, 0x0f, 0x20, 0xac, 0x1f, 0x70, 0xca, 0x67, 0xc1, 0xd2, 0x8e, 0x21, 0xbc,
0x91, 0x5d, 0xe9, 0x8d, 0xca, 0xa2, 0x37, 0xf2, 0xfc, 0x8d, 0x27, 0xd3, 0xa0, 0x76, 0xb8, 0xfe,
0x24, 0xec, 0x5d, 0x4f, 0x84, 0x8e, 0xe1, 0x1b, 0x8f, 0x19, 0xc8, 0x26, 0x7b, 0x50, 0x08, 0x38,
0xe5, 0xb2, 0x63, 0xd4, 0x0e, 0x49, 0x0a, 0x27, 0xee, 0xc2, 0x0c, 0x09, 0x20, 0x5f, 0x43, 0xed,
0x92, 0x5a, 0xd3, 0x99, 0xcf, 0x4c, 0x9f, 0xd1, 0xc0, 0x75, 0x30, 0x93, 0x6b, 0x87, 0x9b, 0xf1,
0x91, 0x13, 0xc9, 0x36, 0x90, 0x6b, 0x54, 0x2f, 0x93, 0x3f, 0xc9, 0x87, 0x50, 0x0f, 0x43, 0x2d,
0xea, 0x89, 0x5b, 0x76, 0xd4, 0x79, 0x6a, 0x73, 0xf2, 0xd0, 0xb2, 0xc5, 0x8d, 0x54, 0x4c, 0xd2,
0x99, 0x37, 0xa1, 0x9c, 0x49, 0xa4, 0xec, 0x3f, 0x35, 0x41, 0x1f, 0x21, 0x19, 0x91, 0x8b, 0x01,
0x2f, 0x2e, 0x0f, 0xf8, 0xf2, 0x00, 0x2a, 0x2b, 0x02, 0xb8, 0x22, 0x3d, 0xaa, 0xab, 0xd2, 0xe3,
0x21, 0x54, 0xc6, 0x6e, 0xc0, 0x4d, 0x19, 0x5f, 0xcc, 0xea, 0x9c, 0x01, 0x82, 0x34, 0x40, 0x0a,
0x79, 0x04, 0x0a, 0x02, 0x5c, 0x67, 0x7c, 0x4d, 0x2d, 0x07, 0x9b, 0x54, 0xce, 0xc0, 0x43, 0x3d,
0x49, 0x12, 0xc5, 0x27, 0x21, 0x97, 0x97, 0x12, 0x03, 0xb2, 0xdf, 0x22, 0x26, 0xa4, 0xcd, 0x4b,
0xaa, 0x9e, 0x28, 0x29, 0x8d, 0x80, 0x7a, 0x66, 0x05, 0x5c, 0x44, 0x2b, 0x88, 0x52, 0xe9, 0x67,
0xb0, 0x9e, 0xa0, 0x85, 0xc5, 0xf4, 0x11, 0x14, 0x44, 0xf7, 0x08, 0x1a, 0x99, 0xdd, 0xdc, 0x5e,
0xe5, 0x70, 0xe3, 0x56, 0xa0, 0x67, 0x81, 0x21, 0x11, 0xda, 0x23, 0xa8, 0x0b, 0x62, 0xc7, 0xb9,
0x74, 0xa3, 0x8e, 0x54, 0x8b, 0x4b, 0x51, 0x11, 0x89, 0xa7, 0xd5, 0x40, 0x19, 0x32, 0xdf, 0x8e,
0x55, 0xfe, 0x0a, 0xea, 0x1d, 0x27, 0xa4, 0x84, 0x0a, 0xff, 0x0f, 0xea, 0xb6, 0xe5, 0xc8, 0x96,
0x45, 0x6d, 0x77, 0xe6, 0xf0, 0x30, 0xe0, 0x55, 0xdb, 0x72, 0x84, 0xfc, 0x16, 0x12, 0x11, 0x17,
0xb5, 0xb6, 0x10, 0xb7, 0x16, 0xe2, 0x64, 0x77, 0x93, 0xb8, 0x67, 0xf9, 0x52, 0x46, 0xcd, 0x3e,
0xcb, 0x97, 0xb2, 0x6a, 0xee, 0x59, 0xbe, 0x94, 0x53, 0xf3, 0xcf, 0xf2, 0xa5, 0xbc, 0x5a, 0x78,
0x96, 0x2f, 0x15, 0xd5, 0x92, 0xf6, 0xd7, 0x0c, 0xa8, 0xbd, 0x19, 0xff, 0x9f, 0x5e, 0x01, 0x1f,
0x46, 0xcb, 0x31, 0xc7, 0x53, 0xfe, 0xca, 0x9c, 0xb0, 0x29, 0xa7, 0x18, 0xee, 0x82, 0xa1, 0xd8,
0x96, 0xd3, 0x9e, 0xf2, 0x57, 0xc7, 0x82, 0x16, 0x3d, 0x9f, 0x09, 0x54, 0x39, 0x44, 0xd1, 0x9b,
0x18, 0xf5, 0x16, 0x73, 0x7e, 0x9f, 0x01, 0xe5, 0xdb, 0x99, 0xcb, 0xd9, 0xea, 0x27, 0x01, 0x13,
0x6f, 0xde, 0x87, 0xb3, 0xa8, 0x03, 0xc6, 0xf3, 0x1e, 0x7c, 0xab, 0xa5, 0xe7, 0x96, 0xb4, 0xf4,
0x3b, 0x1f, 0xbb, 0xfc, 0x9d, 0x8f, 0x9d, 0xf6, 0xdb, 0x8c, 0x88, 0x7a, 0x78, 0xcd, 0xd0, 0xe5,
0xbb, 0xa0, 0x44, 0x8f, 0x94, 0x19, 0xd0, 0xe8, 0xc2, 0x10, 0xc8, 0x57, 0x6a, 0x40, 0x71, 0xca,
0xc1, 0x02, 0x43, 0x8d, 0xc1, 0x75, 0x8c, 0x0c, 0xa7, 0x1c, 0xc1, 0xeb, 0x4b, 0x56, 0x78, 0xe0,
0x5d, 0x80, 0x84, 0x2f, 0x0b, 0x68, 0x67, 0x79, 0x9c, 0x70, 0xa4, 0x74, 0x61, 0x5e, 0x2d, 0x68,
0x7f, 0x93, 0x59, 0xf0, 0xdf, 0x5e, 0xe9, 0x03, 0xa8, 0xcd, 0x87, 0x1d, 0xc4, 0xc8, 0xf7, 0x55,
0xf1, 0xa2, 0x69, 0x47, 0xa0, 0x3e, 0x0e, 0xfb, 0x88, 0x9c, 0x3b, 0xd2, 0xd7, 0xae, 0x0b, 0xce,
0x40, 0x30, 0x42, 0x91, 0x38, 0x9f, 0x08, 0xbf, 0xd2, 0x37, 0x36, 0x73, 0xb8, 0x89, 0xc3, 0x9e,
0x7c, 0x73, 0xeb, 0xe8, 0x4f, 0x49, 0x3f, 0x16, 0xb1, 0xbd, 0xdb, 0x40, 0xad, 0x0e, 0xd5, 0xa1,
0xfb, 0x03, 0x73, 0xe2, 0x62, 0xfb, 0x0a, 0x6a, 0x11, 0x21, 0x34, 0x71, 0x1f, 0xd6, 0x38, 0x52,
0xc2, 0xea, 0x9e, 0xb7, 0xf1, 0xb3, 0x80, 0x72, 0x04, 0x1b, 0x21, 0x42, 0xfb, 0x53, 0x16, 0xca,
0x31, 0x55, 0x24, 0xc9, 0x05, 0x0d, 0x98, 0x69, 0xd3, 0x31, 0xf5, 0x5d, 0xd7, 0x09, 0x6b, 0x5c,
0x11, 0xc4, 0xf3, 0x90, 0x26, 0x5a, 0x58, 0x64, 0xc7, 0x35, 0x0d, 0xae, 0xd1, 0x3b, 0x8a, 0x51,
0x09, 0x69, 0xa7, 0x34, 0xb8, 0x26, 0x1f, 0x81, 0x1a, 0x41, 0x3c, 0x9f, 0x59, 0xb6, 0x78, 0xf9,
0xe4, 0xfb, 0x5c, 0x0f, 0xe9, 0xfd, 0x90, 0x2c, 0x1a, 0xbc, 0x2c, 0x32, 0xd3, 0xa3, 0xd6, 0xc4,
0xb4, 0x85, 0x17, 0xe5, 0xbc, 0x5a, 0x93, 0xf4, 0x3e, 0xb5, 0x26, 0xe7, 0x01, 0xe5, 0xe4, 0x33,
0x78, 0x90, 0x18, 0x6a, 0x13, 0x70, 0x59, 0xc5, 0xc4, 0x8f, 0xa7, 0xda, 0xf8, 0xc8, 0x23, 0x50,
0xc4, 0x8b, 0x61, 0x8e, 0x7d, 0x46, 0x39, 0x9b, 0x84, 0x75, 0x5c, 0x11, 0xb4, 0xb6, 0x24, 0x91,
0x06, 0x14, 0xd9, 0x8d, 0x67, 0xf9, 0x6c, 0x82, 0x2f, 0x46, 0xc9, 0x88, 0x7e, 0x8a, 0xc3, 0x01,
0x77, 0x7d, 0x7a, 0xc5, 0x4c, 0x87, 0xda, 0x2c, 0x1c, 0x51, 0x2a, 0x21, 0xad, 0x4b, 0x6d, 0xa6,
0xbd, 0x03, 0xdb, 0x4f, 0x19, 0x3f, 0xb3, 0x5e, 0xce, 0xac, 0x89, 0xc5, 0xdf, 0xf4, 0xa9, 0x4f,
0xe7, 0x5d, 0xf0, 0x2f, 0x05, 0xd8, 0x48, 0xb3, 0x18, 0x67, 0xbe, 0x78, 0x81, 0x0a, 0xfe, 0x6c,
0xca, 0xa2, 0xe8, 0xcc, 0x5f, 0xcc, 0x18, 0x6c, 0xcc, 0xa6, 0xcc, 0x90, 0x20, 0xf2, 0x35, 0xec,
0xcc, 0x53, 0xcc, 0x17, 0x6f, 0x60, 0x40, 0xb9, 0xe9, 0x31, 0xdf, 0x7c, 0x25, 0x5e, 0x7a, 0xf4,
0x3e, 0x56, 0xa5, 0xcc, 0x36, 0x83, 0x72, 0x91, 0x71, 0x7d, 0xe6, 0x3f, 0x17, 0x6c, 0xf2, 0x21,
0xa8, 0xc9, 0x51, 0xd1, 0xf4, 0x3c, 0x1b, 0x23, 0x91, 0x8f, 0xbb, 0x99, 0xf0, 0x97, 0x67, 0x93,
0x4f, 0x41, 0xec, 0x07, 0x66, 0xca, 0xc3, 0x9e, 0x1d, 0x16, 0xbd, 0x90, 0x31, 0x5f, 0x1a, 0x04,
0xfc, 0x4b, 0x68, 0x2e, 0x5f, 0x36, 0xf0, 0x54, 0x01, 0x4f, 0x6d, 0x2e, 0x59, 0x38, 0xc4, 0xd9,
0xf4, 0x46, 0x21, 0x22, 0xb8, 0x86, 0xf8, 0xf9, 0x46, 0x21, 0x6a, 0xe6, 0x23, 0x58, 0x4f, 0x8d,
0xb0, 0x08, 0x2c, 0x22, 0xb0, 0x96, 0x18, 0x63, 0xe3, 0xf2, 0x5a, 0x1c, 0xff, 0x4b, 0xcb, 0xc7,
0xff, 0x27, 0xb0, 0x11, 0x0d, 0x2e, 0x17, 0x74, 0xfc, 0x83, 0x7b, 0x79, 0x69, 0x06, 0x6c, 0x8c,
0x4d, 0x39, 0x6f, 0xac, 0x87, 0xac, 0x23, 0xc9, 0x19, 0xb0, 0x31, 0x69, 0x42, 0x89, 0xce, 0xb8,
0x2b, 0x62, 0x84, 0x0f, 0x71, 0xc9, 0x88, 0x7f, 0x0b, 0x59, 0xd1, 0xdf, 0xe6, 0xc5, 0x6c, 0x72,
0xc5, 0x64, 0xbb, 0xa8, 0x48, 0x59, 0x11, 0xeb, 0x08, 0x39, 0xe2, 0x9e, 0x5f, 0xc0, 0xf6, 0x2d,
0x3c, 0xa7, 0x3e, 0xc7, 0x1b, 0x28, 0xd2, 0x67, 0x0b, 0xa7, 0x04, 0x5b, 0x5c, 0xe3, 0x63, 0x20,
0x82, 0x63, 0x0a, 0x97, 0x58, 0x8e, 0x79, 0x39, 0xb5, 0xae, 0xae, 0x39, 0xce, 0x21, 0x79, 0xa3,
0x2e, 0x38, 0xe7, 0xf4, 0xa6, 0xe3, 0x9c, 0x20, 0x79, 0xd9, 0x4b, 0x57, 0x0b, 0x63, 0xfe, 0xb6,
0x97, 0xae, 0x9e, 0xca, 0x0d, 0x89, 0xd3, 0xfe, 0x9c, 0x81, 0x6a, 0x2a, 0x39, 0xb1, 0x49, 0xc9,
0x3d, 0xcd, 0x0c, 0x27, 0x81, 0xbc, 0x51, 0x0e, 0x29, 0x9d, 0x09, 0x79, 0x12, 0x8e, 0x9b, 0x59,
0x9c, 0x09, 0x9b, 0xcb, 0x33, 0x3c, 0x31, 0x77, 0x7e, 0x0a, 0xc4, 0x72, 0xc6, 0xae, 0x2d, 0x72,
0x88, 0x5f, 0xfb, 0x2c, 0xb8, 0x76, 0xa7, 0x13, 0xcc, 0xd3, 0xaa, 0xb1, 0x1e, 0x71, 0x86, 0x11,
0x43, 0xc0, 0xe3, 0xd5, 0x70, 0x0e, 0xcf, 0x4b, 0x78, 0xc4, 0x89, 0xe1, 0xda, 0x0b, 0xd8, 0x1e,
0xac, 0xaa, 0x52, 0xf2, 0x15, 0x80, 0x17, 0xd7, 0x26, 0x5a, 0x52, 0x39, 0xdc, 0xb9, 0x7d, 0xe1,
0x79, 0xfd, 0x1a, 0x09, 0xbc, 0xb6, 0x03, 0xcd, 0x65, 0xa2, 0x65, 0x23, 0xd6, 0x1e, 0xc0, 0xc6,
0x60, 0x76, 0x75, 0xc5, 0x16, 0x26, 0xb2, 0xef, 0x41, 0x39, 0xb6, 0x82, 0x97, 0x33, 0x3a, 0xb5,
0x2e, 0x2d, 0x36, 0x79, 0x9b, 0x33, 0x3f, 0x86, 0xb5, 0x70, 0xc4, 0x96, 0xee, 0x9c, 0x0f, 0x6b,
0xad, 0x19, 0x77, 0xc3, 0xf9, 0x3a, 0x84, 0x68, 0x3f, 0x65, 0xe0, 0x7e, 0x5a, 0x67, 0xf8, 0x28,
0x1c, 0x42, 0x29, 0x5a, 0xbe, 0xc3, 0xc6, 0xb3, 0x35, 0xb7, 0x32, 0xf5, 0x7d, 0xc2, 0x28, 0x86,
0x9b, 0x38, 0xf9, 0x02, 0x94, 0x49, 0xe2, 0xa2, 0x8d, 0x2c, 0x9e, 0x7b, 0x10, 0x9f, 0x4b, 0x5a,
0x61, 0xa4, 0xa0, 0xfb, 0x8f, 0xa1, 0x14, 0xed, 0x16, 0x44, 0x81, 0xd2, 0x59, 0xaf, 0xd7, 0x37,
0x7b, 0xa3, 0xa1, 0x7a, 0x8f, 0x54, 0xa0, 0x88, 0xbf, 0x3a, 0x5d, 0x35, 0xb3, 0x1f, 0x40, 0x39,
0x5e, 0x2d, 0x48, 0x15, 0xca, 0x9d, 0x6e, 0x67, 0xd8, 0x69, 0x0d, 0xf5, 0x63, 0xf5, 0x1e, 0x79,
0x00, 0xeb, 0x7d, 0x43, 0xef, 0x9c, 0xb7, 0x9e, 0xea, 0xa6, 0xa1, 0x3f, 0xd7, 0x5b, 0x67, 0xfa,
0xb1, 0x9a, 0x21, 0x04, 0x6a, 0xa7, 0xc3, 0xb3, 0xb6, 0xd9, 0x1f, 0x1d, 0x9d, 0x75, 0x06, 0xa7,
0xfa, 0xb1, 0x9a, 0x15, 0x32, 0x07, 0xa3, 0x76, 0x5b, 0x1f, 0x0c, 0xd4, 0x1c, 0x01, 0x58, 0x3b,
0x69, 0x75, 0x04, 0x38, 0x4f, 0x36, 0xa0, 0xde, 0xe9, 0x3e, 0xef, 0x75, 0xda, 0xba, 0x39, 0xd0,
0x87, 0x43, 0x41, 0x2c, 0xec, 0xff, 0x3b, 0x03, 0xd5, 0xd4, 0x76, 0x42, 0xb6, 0x60, 0x43, 0x1c,
0x19, 0x19, 0x42, 0x53, 0x6b, 0xd0, 0xeb, 0x9a, 0xdd, 0x5e, 0x57, 0x57, 0xef, 0x91, 0x77, 0x60,
0x6b, 0x81, 0xd1, 0x3b, 0x39, 0x69, 0x9f, 0xb6, 0xc4, 0xe5, 0x49, 0x13, 0x36, 0x17, 0x98, 0xc3,
0xce, 0xb9, 0x2e, 0xac, 0xcc, 0x92, 0x5d, 0xd8, 0x59, 0xe0, 0x0d, 0xbe, 0xd3, 0xf5, 0x7e, 0x8c,
0xc8, 0x91, 0xc7, 0xf0, 0x68, 0x01, 0xd1, 0xe9, 0x0e, 0x46, 0x27, 0x27, 0x9d, 0x76, 0x47, 0xef,
0x0e, 0xcd, 0xe7, 0xad, 0xb3, 0x91, 0xae, 0xe6, 0xc9, 0x0e, 0x34, 0x16, 0x95, 0xe8, 0xe7, 0xfd,
0x9e, 0xd1, 0x32, 0x5e, 0xa8, 0x05, 0xf2, 0x3e, 0x3c, 0xbc, 0x25, 0xa4, 0xdd, 0x33, 0x0c, 0xbd,
0x3d, 0x34, 0x5b, 0xe7, 0xbd, 0x51, 0x77, 0xa8, 0xae, 0xed, 0x1f, 0x88, 0x0d, 0x60, 0xa1, 0xf0,
0x84, 0xcb, 0x46, 0xdd, 0x6f, 0xba, 0xbd, 0xef, 0xba, 0xea, 0x3d, 0xe1, 0xf9, 0xe1, 0xa9, 0xa1,
0x0f, 0x4e, 0x7b, 0x67, 0xc7, 0x6a, 0x66, 0xff, 0x37, 0x39, 0x80, 0x79, 0x6e, 0x09, 0xef, 0xb4,
0x46, 0xc3, 0x5e, 0xa4, 0x61, 0x7e, 0x4c, 0x83, 0xf7, 0x92, 0x8c, 0xa3, 0xd1, 0xf1, 0x53, 0x7d,
0x68, 0x76, 0x7b, 0x43, 0x73, 0x30, 0x6c, 0x19, 0x43, 0x0c, 0x57, 0x13, 0x36, 0x93, 0x18, 0xe9,
0x85, 0x13, 0x5d, 0x1f, 0xa8, 0x59, 0xf2, 0x1e, 0x34, 0x97, 0x9c, 0xd7, 0xcf, 0x5a, 0xfd, 0x81,
0x7e, 0xac, 0xe6, 0xc8, 0x36, 0x3c, 0x48, 0xf2, 0x3b, 0x5d, 0xf3, 0xe4, 0xac, 0xf3, 0xf4, 0x74,
0xa8, 0xe6, 0x49, 0x03, 0xee, 0xa7, 0xc5, 0xb6, 0x50, 0xaa, 0x5a, 0x58, 0x3c, 0x74, 0xde, 0xe9,
0xea, 0x06, 0xb2, 0xd6, 0xc8, 0x26, 0x90, 0x24, 0xab, 0x6f, 0xe8, 0xfd, 0xd6, 0x0b, 0xb5, 0x48,
0x1e, 0xc2, 0x3b, 0x49, 0x7a, 0xe4, 0xd1, 0xa3, 0x56, 0xfb, 0x9b, 0xde, 0xc9, 0x89, 0x5a, 0x5a,
0xd4, 0x16, 0x67, 0x73, 0x79, 0xd1, 0x37, 0x51, 0x66, 0x83, 0x88, 0x5b, 0x8a, 0xd1, 0xf9, 0x76,
0xd4, 0x39, 0xee, 0x0c, 0x5f, 0x98, 0xbd, 0x6f, 0xd4, 0x8a, 0x88, 0xdb, 0x12, 0xcb, 0x93, 0x09,
0xa0, 0x2a, 0x87, 0xff, 0x28, 0xcb, 0x8f, 0x00, 0x6d, 0xfc, 0xec, 0x48, 0x0c, 0x28, 0x86, 0x85,
0x4a, 0x56, 0x95, 0x6e, 0xf3, 0x41, 0x6a, 0x91, 0x8b, 0x1b, 0xd1, 0xd6, 0xaf, 0xff, 0xfe, 0xcf,
0xdf, 0x65, 0xd7, 0x35, 0xe5, 0xe0, 0xd5, 0x67, 0x07, 0x02, 0x71, 0xe0, 0xce, 0xf8, 0x97, 0x99,
0x7d, 0xd2, 0x83, 0x35, 0xf9, 0xb1, 0x89, 0x6c, 0xa6, 0x44, 0xc6, 0x5f, 0x9f, 0x56, 0x49, 0xdc,
0x44, 0x89, 0xaa, 0x56, 0x89, 0x25, 0x5a, 0x8e, 0x10, 0xf8, 0x05, 0x14, 0xc3, 0x4f, 0x19, 0x89,
0x4b, 0xa6, 0x3f, 0x6e, 0x34, 0x97, 0x6d, 0x9b, 0xff, 0x9f, 0x21, 0xdf, 0x43, 0x39, 0x5e, 0x54,
0xc9, 0x76, 0xa2, 0x05, 0xa7, 0xdb, 0x67, 0xb3, 0xb9, 0x8c, 0x95, 0xbe, 0x16, 0xa9, 0xc5, 0xd7,
0xc2, 0x25, 0x96, 0x8c, 0x64, 0x3b, 0x12, 0x4b, 0x2c, 0x69, 0xa4, 0xd4, 0x27, 0xf6, 0xda, 0xa5,
0x17, 0xd3, 0x9a, 0x28, 0xf2, 0x3e, 0x21, 0x29, 0x91, 0x07, 0x3f, 0x5a, 0x93, 0x5f, 0x90, 0x9f,
0x83, 0x12, 0x06, 0x00, 0x57, 0x4d, 0x32, 0x77, 0x56, 0x72, 0x1f, 0x6e, 0xce, 0x8d, 0x59, 0x5c,
0x4a, 0x97, 0x48, 0x77, 0x67, 0xfc, 0x80, 0xa3, 0xb4, 0x8b, 0x58, 0x3a, 0xae, 0x30, 0x09, 0xe9,
0xc9, 0x65, 0x30, 0x2d, 0x3d, 0xb5, 0xec, 0x68, 0xbb, 0x28, 0xbd, 0x49, 0x1a, 0x29, 0xe9, 0x2f,
0x05, 0xe6, 0xe0, 0x47, 0x6a, 0x73, 0x61, 0x41, 0x4d, 0x4c, 0xb0, 0x18, 0xf2, 0x3b, 0x6d, 0x98,
0x7b, 0x6d, 0x61, 0xb5, 0xd7, 0xb6, 0x51, 0xc9, 0x06, 0x59, 0x4f, 0xa4, 0x42, 0x6c, 0xc1, 0x5c,
0xfa, 0x9d, 0x36, 0x24, 0xa5, 0xa7, 0x4d, 0x78, 0x88, 0xd2, 0xb7, 0xc9, 0x56, 0x52, 0x7a, 0xd2,
0x82, 0x17, 0x50, 0x15, 0x3a, 0xa2, 0x1d, 0x26, 0x48, 0x64, 0x72, 0x6a, 0x51, 0x6a, 0x6e, 0xdd,
0xa2, 0xa7, 0xab, 0x83, 0xd4, 0x51, 0x45, 0x40, 0xf9, 0x81, 0x5c, 0x8e, 0x08, 0x07, 0x72, 0x7b,
0xbc, 0x27, 0x5a, 0x2c, 0x67, 0xe5, 0xec, 0xdf, 0xbc, 0x73, 0x82, 0xd0, 0x76, 0x50, 0xe1, 0x26,
0xb9, 0x8f, 0x0a, 0x23, 0xc0, 0x81, 0x27, 0xe5, 0xff, 0x12, 0xc8, 0xe0, 0x2e, 0xad, 0x2b, 0x67,
0x99, 0xe6, 0xfb, 0x77, 0x62, 0xd2, 0x0e, 0xd5, 0x96, 0x2a, 0x17, 0x25, 0xcc, 0x40, 0x49, 0x4e,
0x10, 0x64, 0x6e, 0xcb, 0x92, 0x61, 0xa6, 0xf9, 0xee, 0x0a, 0x6e, 0xa8, 0xad, 0x81, 0xda, 0x08,
0x51, 0x85, 0x36, 0x31, 0xa7, 0x1e, 0x04, 0x12, 0x76, 0xb1, 0x86, 0xff, 0x1f, 0xf9, 0xfc, 0x3f,
0x01, 0x00, 0x00, 0xff, 0xff, 0xb9, 0xba, 0x11, 0xb0, 0x56, 0x19, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.

@ -872,9 +872,102 @@ message SetLiquidityParamsResponse {
message SuggestSwapsRequest {
}
enum AutoReason {
AUTO_REASON_UNKNOWN = 0;
/*
Budget not started indicates that we do not recommend any swaps because
the start time for our budget has not arrived yet.
*/
AUTO_REASON_BUDGET_NOT_STARTED = 1;
/*
Sweep fees indicates that the estimated fees to sweep swaps are too high
right now.
*/
AUTO_REASON_SWEEP_FEES = 2;
/*
Budget elapsed indicates that the autoloop budget for the period has been
elapsed.
*/
AUTO_REASON_BUDGET_ELAPSED = 3;
/*
In flight indicates that the limit on in-flight automatically dispatched
swaps has already been reached.
*/
AUTO_REASON_IN_FLIGHT = 4;
/*
Swap fee indicates that the server fee for a specific swap is too high.
*/
AUTO_REASON_SWAP_FEE = 5;
/*
Miner fee indicates that the miner fee for a specific swap is to high.
*/
AUTO_REASON_MINER_FEE = 6;
/*
Prepay indicates that the prepay fee for a specific swap is too high.
*/
AUTO_REASON_PREPAY = 7;
/*
Failure backoff indicates that a swap has recently failed for this target,
and the backoff period has not yet passed.
*/
AUTO_REASON_FAILURE_BACKOFF = 8;
/*
Loop out indicates that a loop out swap is currently utilizing the channel,
so it is not eligible.
*/
AUTO_REASON_LOOP_OUT = 9;
/*
Loop In indicates that a loop in swap is currently in flight for the peer,
so it is not eligible.
*/
AUTO_REASON_LOOP_IN = 10;
/*
Liquidity ok indicates that a target meets the liquidity balance expressed
in its rule, so no swap is needed.
*/
AUTO_REASON_LIQUIDITY_OK = 11;
/*
Budget insufficient indicates that we cannot perform a swap because we do
not have enough pending budget available. This differs from budget elapsed,
because we still have some budget available, but we have allocated it to
other swaps.
*/
AUTO_REASON_BUDGET_INSUFFICIENT = 12;
}
message Disqualified {
/*
The short channel ID of the channel that was excluded from our suggestions.
*/
uint64 channel_id = 1;
/*
The reason that we excluded the channel from the our suggestions.
*/
AutoReason reason = 2;
}
message SuggestSwapsResponse {
/*
The set of recommended loop outs.
*/
repeated LoopOutRequest loop_out = 1;
/*
Disqualified contains the set of channels that swaps are not recommended
for.
*/
repeated Disqualified disqualified = 2;
}

@ -395,6 +395,40 @@
}
},
"definitions": {
"looprpcAutoReason": {
"type": "string",
"enum": [
"AUTO_REASON_UNKNOWN",
"AUTO_REASON_BUDGET_NOT_STARTED",
"AUTO_REASON_SWEEP_FEES",
"AUTO_REASON_BUDGET_ELAPSED",
"AUTO_REASON_IN_FLIGHT",
"AUTO_REASON_SWAP_FEE",
"AUTO_REASON_MINER_FEE",
"AUTO_REASON_PREPAY",
"AUTO_REASON_FAILURE_BACKOFF",
"AUTO_REASON_LOOP_OUT",
"AUTO_REASON_LOOP_IN",
"AUTO_REASON_LIQUIDITY_OK",
"AUTO_REASON_BUDGET_INSUFFICIENT"
],
"default": "AUTO_REASON_UNKNOWN",
"description": " - AUTO_REASON_BUDGET_NOT_STARTED: Budget not started indicates that we do not recommend any swaps because \nthe start time for our budget has not arrived yet.\n - AUTO_REASON_SWEEP_FEES: Sweep fees indicates that the estimated fees to sweep swaps are too high \nright now.\n - AUTO_REASON_BUDGET_ELAPSED: Budget elapsed indicates that the autoloop budget for the period has been \nelapsed.\n - AUTO_REASON_IN_FLIGHT: In flight indicates that the limit on in-flight automatically dispatched \nswaps has already been reached.\n - AUTO_REASON_SWAP_FEE: Swap fee indicates that the server fee for a specific swap is too high.\n - AUTO_REASON_MINER_FEE: Miner fee indicates that the miner fee for a specific swap is to high.\n - AUTO_REASON_PREPAY: Prepay indicates that the prepay fee for a specific swap is too high.\n - AUTO_REASON_FAILURE_BACKOFF: Failure backoff indicates that a swap has recently failed for this target,\nand the backoff period has not yet passed.\n - AUTO_REASON_LOOP_OUT: Loop out indicates that a loop out swap is currently utilizing the channel,\nso it is not eligible.\n - AUTO_REASON_LOOP_IN: Loop In indicates that a loop in swap is currently in flight for the peer, \nso it is not eligible.\n - AUTO_REASON_LIQUIDITY_OK: Liquidity ok indicates that a target meets the liquidity balance expressed \nin its rule, so no swap is needed.\n - AUTO_REASON_BUDGET_INSUFFICIENT: Budget insufficient indicates that we cannot perform a swap because we do \nnot have enough pending budget available. This differs from budget elapsed, \nbecause we still have some budget available, but we have allocated it to \nother swaps."
},
"looprpcDisqualified": {
"type": "object",
"properties": {
"channel_id": {
"type": "string",
"format": "uint64",
"description": "The short channel ID of the channel that was excluded from our suggestions."
},
"reason": {
"$ref": "#/definitions/looprpcAutoReason",
"description": "The reason that we excluded the channel from the our suggestions."
}
}
},
"looprpcFailureReason": {
"type": "string",
"enum": [
@ -808,6 +842,13 @@
"$ref": "#/definitions/looprpcLoopOutRequest"
},
"description": "The set of recommended loop outs."
},
"disqualified": {
"type": "array",
"items": {
"$ref": "#/definitions/looprpcDisqualified"
},
"description": "Disqualified contains the set of channels that swaps are not recommended\nfor."
}
}
},

@ -24,6 +24,14 @@ This file tracks release notes for the loop client.
baked one with the exact permissions needed for Loop. If the now deprecated
flag/option `--lnd.macaroondir` is used, it will fall back to use only the
`admin.macaroon` from that directory.
* The rules used for autoloop have been relaxed to allow autoloop to dispatch
swaps even if there are manually initiated swaps that are not limited to a
single channel in progress. This change was made to allow autoloop to coexist
with manual swaps.
* The `SuggestSwaps` endpoint has been updated to include reasons that indicate
why the Autolooper is not currently dispatching swaps for the set of rules
that the client is configured with. See the [autoloop documentation](docs/autoloop.md) for a
detailed explanations of these reasons.
#### Breaking Changes
* The `AutoOut`, `AutoOutBudgetSat` and `AutoOutBudgetStartSec` fields in the
@ -31,5 +39,8 @@ This file tracks release notes for the loop client.
been renamed to `Autoloop`, `AutoloopBudgetSat` and `AutoloopBudgetStartSec`.
* The `autoout` flag for enabling automatic dispatch of loop out swaps has been
renamed to `autoloop` so that it can cover loop out and loop in.
* The `SuggestSwaps` rpc call will now fail with a `FailedPrecondition` grpc
error code if no rules are configured for the autolooper. Previously the rpc
would return an empty response.
#### Bug Fixes

Loading…
Cancel
Save