@@ -386,6 +386,10 @@ type Manager struct {
386386 // current liquidity balance.
387387 cfg * Config
388388
389+ // builder is the swap builder responsible for creating swaps of our
390+ // chosen type for us.
391+ builder swapBuilder
392+
389393 // params is the set of parameters we are currently using. These may be
390394 // updated at runtime.
391395 params Parameters
@@ -424,8 +428,9 @@ func (m *Manager) Run(ctx context.Context) error {
424428// NewManager creates a liquidity manager which has no rules set.
425429func NewManager (cfg * Config ) * Manager {
426430 return & Manager {
427- cfg : cfg ,
428- params : defaultParameters ,
431+ cfg : cfg ,
432+ params : defaultParameters ,
433+ builder : newLoopOutBuilder (cfg ),
429434 }
430435}
431436
@@ -616,14 +621,7 @@ func (m *Manager) SuggestSwaps(ctx context.Context, autoloop bool) (
616621 // estimate is to sweep within our target number of confirmations. If
617622 // This fee exceeds the fee limit we have set, we will not suggest any
618623 // swaps at present.
619- estimate , err := m .cfg .Lnd .WalletKit .EstimateFee (
620- ctx , m .params .SweepConfTarget ,
621- )
622- if err != nil {
623- return nil , err
624- }
625-
626- if err := m .params .FeeLimit .mayLoopOut (estimate ); err != nil {
624+ if err := m .builder .maySwap (ctx , m .params ); err != nil {
627625 var reasonErr * reasonError
628626 if errors .As (err , & reasonErr ) {
629627 return m .singleReasonSuggestion (reasonErr .reason ), nil
@@ -635,7 +633,7 @@ func (m *Manager) SuggestSwaps(ctx context.Context, autoloop bool) (
635633
636634 // Get the current server side restrictions, combined with the client
637635 // set restrictions, if any.
638- restrictions , err := m .getSwapRestrictions (ctx , swap . TypeOut )
636+ restrictions , err := m .getSwapRestrictions (ctx , m . builder . swapType () )
639637 if err != nil {
640638 return nil , err
641639 }
@@ -846,65 +844,24 @@ func (m *Manager) suggestSwap(ctx context.Context, traffic *swapTraffic,
846844 balance * balances , rule * ThresholdRule , restrictions * Restrictions ,
847845 autoloop bool ) (swapSuggestion , error ) {
848846
849- // Check whether we can perform a swap.
850- err := traffic .maySwap (balance .pubkey , balance .channels )
847+ // First, check whether this peer/channel combination is already in use
848+ // for our swap.
849+ err := m .builder .inUse (traffic , balance .pubkey , balance .channels )
851850 if err != nil {
852851 return nil , err
853852 }
854853
855- // We can have nil suggestions in the case where no action is
856- // required, so we skip over them .
854+ // Next, get the amount that we need to swap for this entity, skipping
855+ // over it if no change in liquidity is required .
857856 amount := rule .swapAmount (balance , restrictions )
858857 if amount == 0 {
859858 return nil , newReasonError (ReasonLiquidityOk )
860859 }
861860
862- swap , err := m .loopOutSwap (ctx , amount , balance , autoloop )
863- if err != nil {
864- return nil , err
865- }
866-
867- return & loopOutSwapSuggestion {
868- OutRequest : * swap ,
869- }, nil
870- }
871-
872- // loopOutSwap creates a loop out swap with the amount provided for the balance
873- // described by the balance set provided. A reason that indicates whether we
874- // can swap is returned. If this value is not ReasonNone, there is no possible
875- // swap and the loop out request returned will be nil.
876- func (m * Manager ) loopOutSwap (ctx context.Context , amount btcutil.Amount ,
877- balance * balances , autoloop bool ) (* loop.OutRequest , error ) {
878-
879- quote , err := m .cfg .LoopOutQuote (
880- ctx , & loop.LoopOutQuoteRequest {
881- Amount : amount ,
882- SweepConfTarget : m .params .SweepConfTarget ,
883- SwapPublicationDeadline : m .cfg .Clock .Now (),
884- },
885- )
886- if err != nil {
887- return nil , err
888- }
889-
890- log .Debugf ("quote for suggestion: %v, swap fee: %v, " +
891- "miner fee: %v, prepay: %v" , amount , quote .SwapFee ,
892- quote .MinerFee , quote .PrepayAmount )
893-
894- // Check that the estimated fees for the suggested swap are
895- // below the fee limits configured by the manager.
896- if err := m .params .FeeLimit .loopOutLimits (amount , quote ); err != nil {
897- return nil , err
898- }
899-
900- outRequest , err := m .makeLoopOutRequest (
901- ctx , amount , balance , quote , autoloop ,
861+ return m .builder .buildSwap (
862+ ctx , balance .pubkey , balance .channels , amount , autoloop ,
863+ m .params ,
902864 )
903- if err != nil {
904- return nil , err
905- }
906-
907- return & outRequest , nil
908865}
909866
910867// getSwapRestrictions queries the server for its latest swap size restrictions,
@@ -942,58 +899,6 @@ func (m *Manager) getSwapRestrictions(ctx context.Context, swapType swap.Type) (
942899 return restrictions , nil
943900}
944901
945- // makeLoopOutRequest creates a loop out request from a suggestion. Since we
946- // do not get any information about our off-chain routing fees when we request
947- // a quote, we just set our prepay and route maximum fees directly from the
948- // amounts we expect to route. The estimation we use elsewhere is the repo is
949- // route-independent, which is a very poor estimation so we don't bother with
950- // checking against this inaccurate constant. We use the exact prepay amount
951- // and swap fee given to us by the server, but use our maximum miner fee anyway
952- // to give us some leeway when performing the swap. We take an auto-out which
953- // determines whether we set a label identifying this swap as automatically
954- // dispatched, and decides whether we set a sweep address (we don't bother for
955- // non-auto requests, because the client api will set it anyway).
956- func (m * Manager ) makeLoopOutRequest (ctx context.Context ,
957- amount btcutil.Amount , balance * balances , quote * loop.LoopOutQuote ,
958- autoloop bool ) (loop.OutRequest , error ) {
959-
960- prepayMaxFee , routeMaxFee , minerFee := m .params .FeeLimit .loopOutFees (
961- amount , quote ,
962- )
963-
964- var chanSet loopdb.ChannelSet
965- for _ , channel := range balance .channels {
966- chanSet = append (chanSet , channel .ToUint64 ())
967- }
968-
969- // Create a request with our calculated routing fees. We can use the
970- // swap fee, prepay amount and miner fee from the quote because we have
971- // already validated them.
972- request := loop.OutRequest {
973- Amount : amount ,
974- OutgoingChanSet : chanSet ,
975- MaxPrepayRoutingFee : prepayMaxFee ,
976- MaxSwapRoutingFee : routeMaxFee ,
977- MaxMinerFee : minerFee ,
978- MaxSwapFee : quote .SwapFee ,
979- MaxPrepayAmount : quote .PrepayAmount ,
980- SweepConfTarget : m .params .SweepConfTarget ,
981- Initiator : autoloopSwapInitiator ,
982- }
983-
984- if autoloop {
985- request .Label = labels .AutoloopLabel (swap .TypeOut )
986-
987- addr , err := m .cfg .Lnd .WalletKit .NextAddr (ctx )
988- if err != nil {
989- return loop.OutRequest {}, err
990- }
991- request .DestAddr = addr
992- }
993-
994- return request , nil
995- }
996-
997902// worstCaseOutFees calculates the largest possible fees for a loop out swap,
998903// comparing the fees for a successful swap to the cost when the client pays
999904// the prepay because they failed to sweep the on chain htlc. This is unlikely,
@@ -1177,38 +1082,6 @@ func newSwapTraffic() *swapTraffic {
11771082 }
11781083}
11791084
1180- // maySwap returns a boolean that indicates whether we may perform a swap for a
1181- // peer and its set of channels.
1182- func (s * swapTraffic ) maySwap (peer route.Vertex ,
1183- channels []lnwire.ShortChannelID ) error {
1184-
1185- for _ , chanID := range channels {
1186- lastFail , recentFail := s .failedLoopOut [chanID ]
1187- if recentFail {
1188- log .Debugf ("Channel: %v not eligible for suggestions, was " +
1189- "part of a failed swap at: %v" , chanID , lastFail )
1190-
1191- return newReasonError (ReasonFailureBackoff )
1192- }
1193-
1194- if s .ongoingLoopOut [chanID ] {
1195- log .Debugf ("Channel: %v not eligible for suggestions, " +
1196- "ongoing loop out utilizing channel" , chanID )
1197-
1198- return newReasonError (ReasonLoopOut )
1199- }
1200- }
1201-
1202- if s .ongoingLoopIn [peer ] {
1203- log .Debugf ("Peer: %x not eligible for suggestions ongoing " +
1204- "loop in utilizing peer" , peer )
1205-
1206- return newReasonError (ReasonLoopIn )
1207- }
1208-
1209- return nil
1210- }
1211-
12121085// satPerKwToSatPerVByte converts sat per kWeight to sat per vByte.
12131086func satPerKwToSatPerVByte (satPerKw chainfee.SatPerKWeight ) int64 {
12141087 return int64 (satPerKw .FeePerKVByte () / 1000 )
0 commit comments