@@ -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,50 @@ var staticAddressCommands = cli.Command{
2427 withdrawalCommand ,
2528 summaryCommand ,
2629 },
30+ Description : `
31+ TODO .
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+ cli.StringFlag {
44+ Name : "last_hop" ,
45+ Usage : "the pubkey of the last hop to use for this " +
46+ "swap" ,
47+ },
48+ cli.StringFlag {
49+ Name : "label" ,
50+ Usage : fmt .Sprintf ("an optional label for this swap," +
51+ "limited to %v characters. The label may not " +
52+ "start with our reserved prefix: %v." ,
53+ labels .MaxLength , labels .Reserved ),
54+ },
55+ cli.StringSliceFlag {
56+ Name : "route_hints" ,
57+ Usage : "route hints that can each be individually " +
58+ "used to assist in reaching the invoice's " +
59+ "destination" ,
60+ },
61+ cli.BoolFlag {
62+ Name : "private" ,
63+ Usage : "generates and passes route hints. Should be " +
64+ "used if the connected node is only " +
65+ "reachable via private channels" ,
66+ },
67+ cli.BoolFlag {
68+ Name : "force, f" ,
69+ Usage : "Assumes yes during confirmation. Using this " +
70+ "option will result in an immediate swap" ,
71+ },
72+ },
73+ Action : staticAddressLoopIn ,
2774}
2875
2976var newStaticAddressCommand = cli.Command {
@@ -196,7 +243,7 @@ var summaryCommand = cli.Command{
196243 Usage : "specify a filter to only display deposits in " +
197244 "the specified state. The state can be one " +
198245 "of [deposited|withdrawing|withdrawn|" +
199- "publish_expired_deposit|" +
246+ "loopingin|loopedin| publish_expired_deposit|" +
200247 "wait_for_expiry_sweep|expired|failed]." ,
201248 },
202249 },
@@ -229,6 +276,12 @@ func summary(ctx *cli.Context) error {
229276 case "withdrawn" :
230277 filterState = looprpc .DepositState_WITHDRAWN
231278
279+ case "loopingin" :
280+ filterState = looprpc .DepositState_LOOPING_IN
281+
282+ case "loopedin" :
283+ filterState = looprpc .DepositState_LOOPED_IN
284+
232285 case "publish_expired_deposit" :
233286 filterState = looprpc .DepositState_PUBLISH_EXPIRED
234287
@@ -297,3 +350,116 @@ func NewProtoOutPoint(op string) (*looprpc.OutPoint, error) {
297350 OutputIndex : uint32 (outputIndex ),
298351 }, nil
299352}
353+
354+ func staticAddressLoopIn (ctx * cli.Context ) error {
355+ if ctx .NArg () > 0 {
356+ return cli .ShowCommandHelp (ctx , "static" )
357+ }
358+
359+ client , cleanup , err := getClient (ctx )
360+ if err != nil {
361+ return err
362+ }
363+ defer cleanup ()
364+
365+ var (
366+ ctxb = context .Background ()
367+ isAllSelected = ctx .IsSet ("all" )
368+ isUtxoSelected = ctx .IsSet ("utxo" )
369+ label = ctx .String ("static-loop-in" )
370+ hints []* swapserverrpc.RouteHint
371+ lastHop []byte
372+ )
373+
374+ // Validate our label early so that we can fail before getting a quote.
375+ if err := labels .Validate (label ); err != nil {
376+ return err
377+ }
378+
379+ // Private and route hints are mutually exclusive as setting private
380+ // means we retrieve our own route hints from the connected node.
381+ hints , err = validateRouteHints (ctx )
382+ if err != nil {
383+ return err
384+ }
385+
386+ if ctx .IsSet (lastHopFlag .Name ) {
387+ lastHopVertex , err := route .NewVertexFromStr (
388+ ctx .String (lastHopFlag .Name ),
389+ )
390+ if err != nil {
391+ return err
392+ }
393+
394+ lastHop = lastHopVertex [:]
395+ }
396+
397+ // Get the amount we need to quote for.
398+ summaryResp , err := client .GetStaticAddressSummary (
399+ ctxb , & looprpc.StaticAddressSummaryRequest {
400+ StateFilter : looprpc .DepositState_DEPOSITED ,
401+ },
402+ )
403+ if err != nil {
404+ return err
405+ }
406+
407+ var depositOutpoints []string
408+ switch {
409+ case isAllSelected == isUtxoSelected :
410+ return errors .New ("must select either all or some utxos" )
411+
412+ case isAllSelected :
413+ depositOutpoints = depositsToOutpoints (
414+ summaryResp .FilteredDeposits ,
415+ )
416+
417+ case isUtxoSelected :
418+ depositOutpoints = ctx .StringSlice ("utxo" )
419+
420+ default :
421+ return fmt .Errorf ("unknown quote request" )
422+ }
423+
424+ quote , err := client .GetLoopInQuote (
425+ ctxb , & looprpc.QuoteRequest {
426+ LoopInRouteHints : hints ,
427+ LoopInLastHop : lastHop ,
428+ Private : ctx .Bool (privateFlag .Name ),
429+ DepositOutpoints : depositOutpoints ,
430+ },
431+ )
432+ if err != nil {
433+ return err
434+ }
435+
436+ limits := getInLimits (quote )
437+
438+ req := & looprpc.StaticAddressLoopInRequest {
439+ Outpoints : depositOutpoints ,
440+ MaxSwapFee : int64 (limits .maxSwapFee ),
441+ LastHop : lastHop ,
442+ Label : ctx .String (labelFlag .Name ),
443+ Initiator : defaultInitiator ,
444+ RouteHints : hints ,
445+ Private : ctx .Bool ("private" ),
446+ }
447+
448+ resp , err := client .StaticAddressLoopIn (ctxb , req )
449+ if err != nil {
450+ return err
451+ }
452+
453+ fmt .Printf ("Static loop-in response from the server: %v\n " , resp )
454+
455+ return nil
456+ }
457+
458+ func depositsToOutpoints (deposits []* looprpc.Deposit ) []string {
459+ outpoints := make ([]string , 0 , len (deposits ))
460+ for _ , deposit := range deposits {
461+ outpoints = append (outpoints , deposit .Outpoint )
462+ }
463+
464+ return outpoints
465+ }
0 commit comments