@@ -118,6 +118,11 @@ func (s *Client) FetchLoopOutSwaps() ([]*loopdb.LoopOut, error) {
118
118
return s .Store .FetchLoopOutSwaps ()
119
119
}
120
120
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
+
121
126
// Run is a blocking call that executes all swaps. Any pending swaps are
122
127
// restored from persistent storage and resumed. Subsequent updates will be
123
128
// sent through the passed in statusChan. The function can be terminated by
@@ -144,7 +149,12 @@ func (s *Client) Run(ctx context.Context,
144
149
145
150
// Query store before starting event loop to prevent new swaps from
146
151
// 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 ()
148
158
if err != nil {
149
159
return err
150
160
}
@@ -154,7 +164,7 @@ func (s *Client) Run(ctx context.Context,
154
164
go func () {
155
165
defer s .wg .Done ()
156
166
157
- s .resumeSwaps (mainCtx , pendingSwaps )
167
+ s .resumeSwaps (mainCtx , pendingLoopOutSwaps , pendingLoopInSwaps )
158
168
159
169
// Signal that new requests can be accepted. Otherwise the new
160
170
// swap could already have been added to the store and read in
@@ -194,19 +204,33 @@ func (s *Client) Run(ctx context.Context,
194
204
195
205
// resumeSwaps restarts all pending swaps from the provided list.
196
206
func (s * Client ) resumeSwaps (ctx context.Context ,
197
- swaps []* loopdb.LoopOut ) {
207
+ loopOutSwaps []* loopdb.LoopOut , loopInSwaps [] * loopdb. LoopIn ) {
198
208
199
- for _ , pend := range swaps {
209
+ swapCfg := & swapConfig {
210
+ lnd : s .lndServices ,
211
+ store : s .Store ,
212
+ }
213
+
214
+ for _ , pend := range loopOutSwaps {
200
215
if pend .State ().Type () != loopdb .StateTypePending {
201
216
continue
202
217
}
203
- swapCfg := & swapConfig {
204
- lnd : s .lndServices ,
205
- store : s .Store ,
206
- }
207
218
swap , err := resumeLoopOutSwap (ctx , swapCfg , pend )
208
219
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 )
210
234
continue
211
235
}
212
236
@@ -224,15 +248,15 @@ func (s *Client) resumeSwaps(ctx context.Context,
224
248
//
225
249
// The return value is a hash that uniquely identifies the new swap.
226
250
func (s * Client ) LoopOut (globalCtx context.Context ,
227
- request * OutRequest ) (* lntypes.Hash , error ) {
251
+ request * OutRequest ) (* lntypes.Hash , btcutil. Address , error ) {
228
252
229
253
logger .Infof ("LoopOut %v to %v (channel: %v)" ,
230
254
request .Amount , request .DestAddr ,
231
255
request .LoopOutChannel ,
232
256
)
233
257
234
258
if err := s .waitForInitialized (globalCtx ); err != nil {
235
- return nil , err
259
+ return nil , nil , err
236
260
}
237
261
238
262
// Create a new swap object for this swap.
@@ -246,15 +270,15 @@ func (s *Client) LoopOut(globalCtx context.Context,
246
270
globalCtx , swapCfg , initiationHeight , request ,
247
271
)
248
272
if err != nil {
249
- return nil , err
273
+ return nil , nil , err
250
274
}
251
275
252
276
// Post swap to the main loop.
253
277
s .executor .initiateSwap (globalCtx , swap )
254
278
255
279
// Return hash so that the caller can identify this swap in the updates
256
280
// stream.
257
- return & swap .hash , nil
281
+ return & swap .hash , swap . htlc . Address , nil
258
282
}
259
283
260
284
// LoopOutQuote takes a LoopOut amount and returns a break down of estimated
@@ -283,7 +307,7 @@ func (s *Client) LoopOutQuote(ctx context.Context,
283
307
)
284
308
285
309
minerFee , err := s .sweeper .GetSweepFee (
286
- ctx , swap .QuoteHtlc .MaxSuccessWitnessSize ,
310
+ ctx , swap .QuoteHtlc .AddSuccessToEstimator ,
287
311
request .SweepConfTarget ,
288
312
)
289
313
if err != nil {
@@ -320,3 +344,85 @@ func (s *Client) waitForInitialized(ctx context.Context) error {
320
344
321
345
return nil
322
346
}
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