@@ -118,6 +118,11 @@ func (s *Client) FetchLoopOutSwaps() ([]*loopdb.LoopOut, error) {
118118 return s .Store .FetchLoopOutSwaps ()
119119}
120120
121+ // FetchLoopInSwaps returns a list of all swaps currently in the database.
122+ func (s * Client ) FetchLoopInSwaps () ([]* loopdb.LoopIn , error ) {
123+ return s .Store .FetchLoopInSwaps ()
124+ }
125+
121126// Run is a blocking call that executes all swaps. Any pending swaps are
122127// restored from persistent storage and resumed. Subsequent updates will be
123128// sent through the passed in statusChan. The function can be terminated by
@@ -144,7 +149,12 @@ func (s *Client) Run(ctx context.Context,
144149
145150 // Query store before starting event loop to prevent new swaps from
146151 // being treated as swaps that need to be resumed.
147- pendingSwaps , err := s .Store .FetchLoopOutSwaps ()
152+ pendingLoopOutSwaps , err := s .Store .FetchLoopOutSwaps ()
153+ if err != nil {
154+ return err
155+ }
156+
157+ pendingLoopInSwaps , err := s .Store .FetchLoopInSwaps ()
148158 if err != nil {
149159 return err
150160 }
@@ -154,7 +164,7 @@ func (s *Client) Run(ctx context.Context,
154164 go func () {
155165 defer s .wg .Done ()
156166
157- s .resumeSwaps (mainCtx , pendingSwaps )
167+ s .resumeSwaps (mainCtx , pendingLoopOutSwaps , pendingLoopInSwaps )
158168
159169 // Signal that new requests can be accepted. Otherwise the new
160170 // swap could already have been added to the store and read in
@@ -194,19 +204,33 @@ func (s *Client) Run(ctx context.Context,
194204
195205// resumeSwaps restarts all pending swaps from the provided list.
196206func (s * Client ) resumeSwaps (ctx context.Context ,
197- swaps []* loopdb.LoopOut ) {
207+ loopOutSwaps []* loopdb.LoopOut , loopInSwaps [] * loopdb. LoopIn ) {
198208
199- for _ , pend := range swaps {
209+ swapCfg := & swapConfig {
210+ lnd : s .lndServices ,
211+ store : s .Store ,
212+ }
213+
214+ for _ , pend := range loopOutSwaps {
200215 if pend .State ().Type () != loopdb .StateTypePending {
201216 continue
202217 }
203- swapCfg := & swapConfig {
204- lnd : s .lndServices ,
205- store : s .Store ,
206- }
207218 swap , err := resumeLoopOutSwap (ctx , swapCfg , pend )
208219 if err != nil {
209- logger .Errorf ("resuming swap: %v" , err )
220+ logger .Errorf ("resuming loop out swap: %v" , err )
221+ continue
222+ }
223+
224+ s .executor .initiateSwap (ctx , swap )
225+ }
226+
227+ for _ , pend := range loopInSwaps {
228+ if pend .State ().Type () != loopdb .StateTypePending {
229+ continue
230+ }
231+ swap , err := resumeLoopInSwap (ctx , swapCfg , pend )
232+ if err != nil {
233+ logger .Errorf ("resuming loop in swap: %v" , err )
210234 continue
211235 }
212236
@@ -224,15 +248,15 @@ func (s *Client) resumeSwaps(ctx context.Context,
224248//
225249// The return value is a hash that uniquely identifies the new swap.
226250func (s * Client ) LoopOut (globalCtx context.Context ,
227- request * OutRequest ) (* lntypes.Hash , error ) {
251+ request * OutRequest ) (* lntypes.Hash , btcutil. Address , error ) {
228252
229253 logger .Infof ("LoopOut %v to %v (channel: %v)" ,
230254 request .Amount , request .DestAddr ,
231255 request .LoopOutChannel ,
232256 )
233257
234258 if err := s .waitForInitialized (globalCtx ); err != nil {
235- return nil , err
259+ return nil , nil , err
236260 }
237261
238262 // Create a new swap object for this swap.
@@ -246,15 +270,15 @@ func (s *Client) LoopOut(globalCtx context.Context,
246270 globalCtx , swapCfg , initiationHeight , request ,
247271 )
248272 if err != nil {
249- return nil , err
273+ return nil , nil , err
250274 }
251275
252276 // Post swap to the main loop.
253277 s .executor .initiateSwap (globalCtx , swap )
254278
255279 // Return hash so that the caller can identify this swap in the updates
256280 // stream.
257- return & swap .hash , nil
281+ return & swap .hash , swap . htlc . Address , nil
258282}
259283
260284// LoopOutQuote takes a LoopOut amount and returns a break down of estimated
@@ -283,7 +307,7 @@ func (s *Client) LoopOutQuote(ctx context.Context,
283307 )
284308
285309 minerFee , err := s .sweeper .GetSweepFee (
286- ctx , swap .QuoteHtlc .MaxSuccessWitnessSize ,
310+ ctx , swap .QuoteHtlc .AddSuccessToEstimator ,
287311 request .SweepConfTarget ,
288312 )
289313 if err != nil {
@@ -320,3 +344,85 @@ func (s *Client) waitForInitialized(ctx context.Context) error {
320344
321345 return nil
322346}
347+
348+ // LoopIn initiates a loop in swap.
349+ func (s * Client ) LoopIn (globalCtx context.Context ,
350+ request * LoopInRequest ) (* lntypes.Hash , btcutil.Address , error ) {
351+
352+ logger .Infof ("Loop in %v (channel: %v)" ,
353+ request .Amount ,
354+ request .LoopInChannel ,
355+ )
356+
357+ if err := s .waitForInitialized (globalCtx ); err != nil {
358+ return nil , nil , err
359+ }
360+
361+ // Create a new swap object for this swap.
362+ initiationHeight := s .executor .height ()
363+ swapCfg := swapConfig {
364+ lnd : s .lndServices ,
365+ store : s .Store ,
366+ server : s .Server ,
367+ }
368+ swap , err := newLoopInSwap (
369+ globalCtx , & swapCfg , initiationHeight , request ,
370+ )
371+ if err != nil {
372+ return nil , nil , err
373+ }
374+
375+ // Post swap to the main loop.
376+ s .executor .initiateSwap (globalCtx , swap )
377+
378+ // Return hash so that the caller can identify this swap in the updates
379+ // stream.
380+ return & swap .hash , swap .htlc .Address , nil
381+ }
382+
383+ // LoopInQuote takes an amount and returns a break down of estimated
384+ // costs for the client. Both the swap server and the on-chain fee estimator are
385+ // queried to get to build the quote response.
386+ func (s * Client ) LoopInQuote (ctx context.Context ,
387+ request * LoopInQuoteRequest ) (* LoopInQuote , error ) {
388+
389+ // Retrieve current server terms to calculate swap fee.
390+ terms , err := s .Server .GetLoopInTerms (ctx )
391+ if err != nil {
392+ return nil , err
393+ }
394+
395+ // Check amount limits.
396+ if request .Amount < terms .MinSwapAmount {
397+ return nil , ErrSwapAmountTooLow
398+ }
399+
400+ if request .Amount > terms .MaxSwapAmount {
401+ return nil , ErrSwapAmountTooHigh
402+ }
403+
404+ // Calculate swap fee.
405+ swapFee := terms .SwapFeeBase +
406+ request .Amount * btcutil .Amount (terms .SwapFeeRate )/
407+ btcutil .Amount (swap .FeeRateTotalParts )
408+
409+ // Get estimate for miner fee.
410+ minerFee , err := s .lndServices .Client .EstimateFeeToP2WSH (
411+ ctx , request .Amount , request .HtlcConfTarget ,
412+ )
413+ if err != nil {
414+ return nil , err
415+ }
416+
417+ return & LoopInQuote {
418+ SwapFee : swapFee ,
419+ MinerFee : minerFee ,
420+ }, nil
421+ }
422+
423+ // LoopInTerms returns the terms on which the server executes swaps.
424+ func (s * Client ) LoopInTerms (ctx context.Context ) (
425+ * LoopInTerms , error ) {
426+
427+ return s .Server .GetLoopInTerms (ctx )
428+ }
0 commit comments