diff --git a/cmd/loop/liquidity.go b/cmd/loop/liquidity.go index 57b48ec..f3b823a 100644 --- a/cmd/loop/liquidity.go +++ b/cmd/loop/liquidity.go @@ -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") } diff --git a/docs/autoloop.md b/docs/autoloop.md index 2a25232..63fc5bf 100644 --- a/docs/autoloop.md +++ b/docs/autoloop.md @@ -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. diff --git a/liquidity/liquidity.go b/liquidity/liquidity.go index f70a08a..6586a00 100644 --- a/liquidity/liquidity.go +++ b/liquidity/liquidity.go @@ -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. diff --git a/liquidity/liquidity_test.go b/liquidity/liquidity_test.go index 0872394..557cf22 100644 --- a/liquidity/liquidity_test.go +++ b/liquidity/liquidity_test.go @@ -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() diff --git a/liquidity/reasons.go b/liquidity/reasons.go new file mode 100644 index 0000000..d685f61 --- /dev/null +++ b/liquidity/reasons.go @@ -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 +) diff --git a/loopd/swapclient_server.go b/loopd/swapclient_server.go index abacd7a..a4b9764 100644 --- a/loopd/swapclient_server.go +++ b/loopd/swapclient_server.go @@ -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 diff --git a/looprpc/client.pb.go b/looprpc/client.pb.go index 1a034d8..7e72f33 100644 --- a/looprpc/client.pb.go +++ b/looprpc/client.pb.go @@ -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. diff --git a/looprpc/client.proto b/looprpc/client.proto index 6a78c7f..482de67 100644 --- a/looprpc/client.proto +++ b/looprpc/client.proto @@ -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; } diff --git a/looprpc/client.swagger.json b/looprpc/client.swagger.json index 3a90098..ca9550c 100644 --- a/looprpc/client.swagger.json +++ b/looprpc/client.swagger.json @@ -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." } } }, diff --git a/release_notes.md b/release_notes.md index c5ee3dd..ced6a24 100644 --- a/release_notes.md +++ b/release_notes.md @@ -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