@@ -162,6 +162,21 @@ var (
162162
163163 // ErrZeroInFlight is returned is a zero in flight swaps value is set.
164164 ErrZeroInFlight = errors .New ("max in flight swaps must be >=0" )
165+
166+ // ErrMinimumExceedsMaximumAmt is returned when the minimum configured
167+ // swap amount is more than the maximum.
168+ ErrMinimumExceedsMaximumAmt = errors .New ("minimum swap amount " +
169+ "exceeds maximum" )
170+
171+ // ErrMaxExceedsServer is returned if the maximum swap amount set is
172+ // more than the server offers.
173+ ErrMaxExceedsServer = errors .New ("maximum swap amount is more than " +
174+ "server maximum" )
175+
176+ // ErrMinLessThanServer is returned if the minimum swap amount set is
177+ // less than the server minimum.
178+ ErrMinLessThanServer = errors .New ("minimum swap amount is less than " +
179+ "server minimum" )
165180)
166181
167182// Config contains the external functionality required to run the
@@ -264,6 +279,10 @@ type Parameters struct {
264279 // sweep during a fee spike.
265280 MaximumMinerFee btcutil.Amount
266281
282+ // ClientRestrictions are the restrictions placed on swap size by the
283+ // client.
284+ ClientRestrictions Restrictions
285+
267286 // ChannelRules maps a short channel ID to a rule that describes how we
268287 // would like liquidity to be managed.
269288 ChannelRules map [lnwire.ShortChannelID ]* ThresholdRule
@@ -283,17 +302,19 @@ func (p Parameters) String() string {
283302 "fee rate limit: %v, sweep conf target: %v, maximum prepay: " +
284303 "%v, maximum miner fee: %v, maximum swap fee ppm: %v, maximum " +
285304 "routing fee ppm: %v, maximum prepay routing fee ppm: %v, " +
286- "auto budget: %v, budget start: %v, max auto in flight: %v" ,
305+ "auto budget: %v, budget start: %v, max auto in flight: %v, " +
306+ "minimum swap size=%v, maximum swap size=%v" ,
287307 strings .Join (channelRules , "," ), p .FailureBackOff ,
288308 p .SweepFeeRateLimit , p .SweepConfTarget , p .MaximumPrepay ,
289309 p .MaximumMinerFee , p .MaximumSwapFeePPM ,
290310 p .MaximumRoutingFeePPM , p .MaximumPrepayRoutingFeePPM ,
291- p .AutoFeeBudget , p .AutoFeeStartDate , p .MaxAutoInFlight )
311+ p .AutoFeeBudget , p .AutoFeeStartDate , p .MaxAutoInFlight ,
312+ p .ClientRestrictions .Minimum , p .ClientRestrictions .Maximum )
292313}
293314
294315// validate checks whether a set of parameters is valid. It takes the minimum
295316// confirmations we allow for sweep confirmation target as a parameter.
296- func (p Parameters ) validate (minConfs int32 ) error {
317+ func (p Parameters ) validate (minConfs int32 , server * Restrictions ) error {
297318 for channel , rule := range p .ChannelRules {
298319 if channel .ToUint64 () == 0 {
299320 return ErrZeroChannelID
@@ -347,6 +368,47 @@ func (p Parameters) validate(minConfs int32) error {
347368 return ErrZeroInFlight
348369 }
349370
371+ err := validateRestrictions (server , & p .ClientRestrictions )
372+ if err != nil {
373+ return err
374+ }
375+
376+ return nil
377+ }
378+
379+ // validateRestrictions checks that client restrictions fall within the server's
380+ // restrictions.
381+ func validateRestrictions (server , client * Restrictions ) error {
382+ zeroMin := client .Minimum == 0
383+ zeroMax := client .Maximum == 0
384+
385+ if zeroMin && zeroMax {
386+ return nil
387+ }
388+
389+ // If we have a non-zero maximum, we need to ensure it is greater than
390+ // our minimum (which is fine if min is zero), and does not exceed the
391+ // server's maximum.
392+ if ! zeroMax {
393+ if client .Minimum > client .Maximum {
394+ return ErrMinimumExceedsMaximumAmt
395+ }
396+
397+ if client .Maximum > server .Maximum {
398+ return ErrMaxExceedsServer
399+ }
400+ }
401+
402+ if zeroMin {
403+ return nil
404+ }
405+
406+ // If the client set a minimum, ensure it is at least equal to the
407+ // server's limit.
408+ if client .Minimum < server .Minimum {
409+ return ErrMinLessThanServer
410+ }
411+
350412 return nil
351413}
352414
@@ -403,8 +465,14 @@ func (m *Manager) GetParameters() Parameters {
403465
404466// SetParameters updates our current set of parameters if the new parameters
405467// provided are valid.
406- func (m * Manager ) SetParameters (params Parameters ) error {
407- if err := params .validate (m .cfg .MinimumConfirmations ); err != nil {
468+ func (m * Manager ) SetParameters (ctx context.Context , params Parameters ) error {
469+ restrictions , err := m .cfg .LoopOutRestrictions (ctx )
470+ if err != nil {
471+ return err
472+ }
473+
474+ err = params .validate (m .cfg .MinimumConfirmations , restrictions )
475+ if err != nil {
408476 return err
409477 }
410478
@@ -517,8 +585,9 @@ func (m *Manager) SuggestSwaps(ctx context.Context, autoOut bool) (
517585 return nil , nil
518586 }
519587
520- // Get the current server side restrictions.
521- outRestrictions , err := m .cfg .LoopOutRestrictions (ctx )
588+ // Get the current server side restrictions, combined with the client
589+ // set restrictions, if any.
590+ outRestrictions , err := m .getLoopOutRestrictions (ctx )
522591 if err != nil {
523592 return nil , err
524593 }
@@ -674,6 +743,41 @@ func (m *Manager) SuggestSwaps(ctx context.Context, autoOut bool) (
674743 return inBudget , nil
675744}
676745
746+ // getLoopOutRestrictions queries the server for its latest swap size
747+ // restrictions, validates client restrictions (if present) against these
748+ // values and merges the client's custom requirements with the server's limits
749+ // to produce a single set of limitations for our swap.
750+ func (m * Manager ) getLoopOutRestrictions (ctx context.Context ) (* Restrictions ,
751+ error ) {
752+
753+ restrictions , err := m .cfg .LoopOutRestrictions (ctx )
754+ if err != nil {
755+ return nil , err
756+ }
757+
758+ // It is possible that the server has updated its restrictions since
759+ // we validated our client restrictions, so we validate again to ensure
760+ // that our restrictions are within the server's bounds.
761+ err = validateRestrictions (restrictions , & m .params .ClientRestrictions )
762+ if err != nil {
763+ return nil , err
764+ }
765+
766+ // If our minimum is more than the server's minimum, we set it.
767+ if m .params .ClientRestrictions .Minimum > restrictions .Minimum {
768+ restrictions .Minimum = m .params .ClientRestrictions .Minimum
769+ }
770+
771+ // If our maximum set and is less than the server's maximum, we set it.
772+ if m .params .ClientRestrictions .Maximum != 0 &&
773+ m .params .ClientRestrictions .Maximum < restrictions .Maximum {
774+
775+ restrictions .Maximum = m .params .ClientRestrictions .Maximum
776+ }
777+
778+ return restrictions , nil
779+ }
780+
677781// makeLoopOutRequest creates a loop out request from a suggestion. Since we
678782// do not get any information about our off-chain routing fees when we request
679783// a quote, we just set our prepay and route maximum fees directly from the
0 commit comments