@@ -9,7 +9,10 @@ import (
99 "strings"
1010
1111 "github.com/btcsuite/btcd/chaincfg/chainhash"
12+ "github.com/lightninglabs/loop/labels"
1213 "github.com/lightninglabs/loop/looprpc"
14+ "github.com/lightninglabs/loop/swapserverrpc"
15+ "github.com/lightningnetwork/lnd/routing/route"
1316 "github.com/urfave/cli"
1417)
1518
@@ -24,6 +27,27 @@ var staticAddressCommands = cli.Command{
2427 withdrawalCommand ,
2528 summaryCommand ,
2629 },
30+ Description : `
31+ Requests a loop-in swap based on static address deposits.
32+ ` ,
33+ Flags : []cli.Flag {
34+ cli.StringSliceFlag {
35+ Name : "utxo" ,
36+ Usage : "specify the utxos of deposits as " +
37+ "outpoints(tx:idx) that should be looped in." ,
38+ },
39+ cli.BoolFlag {
40+ Name : "all" ,
41+ Usage : "loop in all static address deposits." ,
42+ },
43+ lastHopFlag ,
44+ labelFlag ,
45+ routeHintsFlag ,
46+ privateFlag ,
47+ forceFlag ,
48+ verboseFlag ,
49+ },
50+ Action : staticAddressLoopIn ,
2751}
2852
2953var newStaticAddressCommand = cli.Command {
@@ -194,10 +218,14 @@ var summaryCommand = cli.Command{
194218 cli.StringFlag {
195219 Name : "filter" ,
196220 Usage : "specify a filter to only display deposits in " +
197- "the specified state. The state can be one " +
198- "of [deposited|withdrawing|withdrawn|" +
199- "publish_expired_deposit|" +
200- "wait_for_expiry_sweep|expired|failed]." ,
221+ "the specified state. Leaving out the filter " +
222+ "returns all deposits.\n The state can be one " +
223+ "of the following: \n " +
224+ "deposited\n withdrawing\n withdrawn\n " +
225+ "loopingin\n loopedin\n " +
226+ "publish_expired_deposit\n " +
227+ "sweep_htlc_timeout\n htlc_timeout_swept\n " +
228+ "wait_for_expiry_sweep\n expired\n failed\n ." ,
201229 },
202230 },
203231 Action : summary ,
@@ -229,9 +257,21 @@ func summary(ctx *cli.Context) error {
229257 case "withdrawn" :
230258 filterState = looprpc .DepositState_WITHDRAWN
231259
260+ case "loopingin" :
261+ filterState = looprpc .DepositState_LOOPING_IN
262+
263+ case "loopedin" :
264+ filterState = looprpc .DepositState_LOOPED_IN
265+
232266 case "publish_expired_deposit" :
233267 filterState = looprpc .DepositState_PUBLISH_EXPIRED
234268
269+ case "sweep_htlc_timeout" :
270+ filterState = looprpc .DepositState_SWEEP_HTLC_TIMEOUT
271+
272+ case "htlc_timeout_swept" :
273+ filterState = looprpc .DepositState_HTLC_TIMEOUT_SWEPT
274+
235275 case "wait_for_expiry_sweep" :
236276 filterState = looprpc .DepositState_WAIT_FOR_EXPIRY_SWEEP
237277
@@ -297,3 +337,143 @@ func NewProtoOutPoint(op string) (*looprpc.OutPoint, error) {
297337 OutputIndex : uint32 (outputIndex ),
298338 }, nil
299339}
340+
341+ func staticAddressLoopIn (ctx * cli.Context ) error {
342+ if ctx .NArg () > 0 {
343+ return cli .ShowCommandHelp (ctx , "static" )
344+ }
345+
346+ client , cleanup , err := getClient (ctx )
347+ if err != nil {
348+ return err
349+ }
350+ defer cleanup ()
351+
352+ var (
353+ ctxb = context .Background ()
354+ isAllSelected = ctx .IsSet ("all" )
355+ isUtxoSelected = ctx .IsSet ("utxo" )
356+ label = ctx .String ("static-loop-in" )
357+ hints []* swapserverrpc.RouteHint
358+ lastHop []byte
359+ )
360+
361+ // Validate our label early so that we can fail before getting a quote.
362+ if err := labels .Validate (label ); err != nil {
363+ return err
364+ }
365+
366+ // Private and route hints are mutually exclusive as setting private
367+ // means we retrieve our own route hints from the connected node.
368+ hints , err = validateRouteHints (ctx )
369+ if err != nil {
370+ return err
371+ }
372+
373+ if ctx .IsSet (lastHopFlag .Name ) {
374+ lastHopVertex , err := route .NewVertexFromStr (
375+ ctx .String (lastHopFlag .Name ),
376+ )
377+ if err != nil {
378+ return err
379+ }
380+
381+ lastHop = lastHopVertex [:]
382+ }
383+
384+ // Get the amount we need to quote for.
385+ summaryResp , err := client .GetStaticAddressSummary (
386+ ctxb , & looprpc.StaticAddressSummaryRequest {
387+ StateFilter : looprpc .DepositState_DEPOSITED ,
388+ },
389+ )
390+ if err != nil {
391+ return err
392+ }
393+
394+ var depositOutpoints []string
395+ switch {
396+ case isAllSelected == isUtxoSelected :
397+ return errors .New ("must select either all or some utxos" )
398+
399+ case isAllSelected :
400+ depositOutpoints = depositsToOutpoints (
401+ summaryResp .FilteredDeposits ,
402+ )
403+
404+ case isUtxoSelected :
405+ depositOutpoints = ctx .StringSlice ("utxo" )
406+
407+ default :
408+ return fmt .Errorf ("unknown quote request" )
409+ }
410+
411+ quoteReq := & looprpc.QuoteRequest {
412+ LoopInRouteHints : hints ,
413+ LoopInLastHop : lastHop ,
414+ Private : ctx .Bool (privateFlag .Name ),
415+ DepositOutpoints : depositOutpoints ,
416+ }
417+ quote , err := client .GetLoopInQuote (ctxb , quoteReq )
418+ if err != nil {
419+ return err
420+ }
421+
422+ limits := getInLimits (quote )
423+
424+ // populate the quote request with the sum of selected deposits and
425+ // prompt the user for acceptance.
426+ quoteReq .Amt = sumDeposits (
427+ depositOutpoints , summaryResp .FilteredDeposits ,
428+ )
429+ if ! (ctx .Bool ("force" ) || ctx .Bool ("f" )) {
430+ err = displayInDetails (quoteReq , quote , ctx .Bool ("verbose" ))
431+ if err != nil {
432+ return err
433+ }
434+ }
435+
436+ req := & looprpc.StaticAddressLoopInRequest {
437+ Outpoints : depositOutpoints ,
438+ MaxSwapFee : int64 (limits .maxSwapFee ),
439+ LastHop : lastHop ,
440+ Label : ctx .String (labelFlag .Name ),
441+ Initiator : defaultInitiator ,
442+ RouteHints : hints ,
443+ Private : ctx .Bool ("private" ),
444+ }
445+
446+ resp , err := client .StaticAddressLoopIn (ctxb , req )
447+ if err != nil {
448+ return err
449+ }
450+
451+ fmt .Printf ("Static loop-in response from the server: %v\n " , resp )
452+
453+ return nil
454+ }
455+
456+ func sumDeposits (outpoints []string , deposits []* looprpc.Deposit ) int64 {
457+ var sum int64
458+ depositMap := make (map [string ]* looprpc.Deposit )
459+ for _ , deposit := range deposits {
460+ depositMap [deposit .Outpoint ] = deposit
461+ }
462+
463+ for _ , outpoint := range outpoints {
464+ if deposit , ok := depositMap [outpoint ]; ok {
465+ sum += deposit .Value
466+ }
467+ }
468+
469+ return sum
470+ }
471+
472+ func depositsToOutpoints (deposits []* looprpc.Deposit ) []string {
473+ outpoints := make ([]string , 0 , len (deposits ))
474+ for _ , deposit := range deposits {
475+ outpoints = append (outpoints , deposit .Outpoint )
476+ }
477+
478+ return outpoints
479+ }
0 commit comments