@@ -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+ 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+ 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 {
@@ -194,10 +241,14 @@ var summaryCommand = cli.Command{
194241 cli.StringFlag {
195242 Name : "filter" ,
196243 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]." ,
244+ "the specified state. Leaving out the filter " +
245+ "returns all deposits.\n The state can be one " +
246+ "of the following: \n " +
247+ "deposited\n withdrawing\n withdrawn\n " +
248+ "loopingin\n loopedin\n " +
249+ "publish_expired_deposit\n " +
250+ "sweep_htlc_timeout\n htlc_timeout_swept\n " +
251+ "wait_for_expiry_sweep\n expired\n failed\n ." ,
201252 },
202253 },
203254 Action : summary ,
@@ -229,9 +280,21 @@ func summary(ctx *cli.Context) error {
229280 case "withdrawn" :
230281 filterState = looprpc .DepositState_WITHDRAWN
231282
283+ case "loopingin" :
284+ filterState = looprpc .DepositState_LOOPING_IN
285+
286+ case "loopedin" :
287+ filterState = looprpc .DepositState_LOOPED_IN
288+
232289 case "publish_expired_deposit" :
233290 filterState = looprpc .DepositState_PUBLISH_EXPIRED
234291
292+ case "sweep_htlc_timeout" :
293+ filterState = looprpc .DepositState_SWEEP_HTLC_TIMEOUT
294+
295+ case "htlc_timeout_swept" :
296+ filterState = looprpc .DepositState_HTLC_TIMEOUT_SWEPT
297+
235298 case "wait_for_expiry_sweep" :
236299 filterState = looprpc .DepositState_WAIT_FOR_EXPIRY_SWEEP
237300
@@ -297,3 +360,116 @@ func NewProtoOutPoint(op string) (*looprpc.OutPoint, error) {
297360 OutputIndex : uint32 (outputIndex ),
298361 }, nil
299362}
363+
364+ func staticAddressLoopIn (ctx * cli.Context ) error {
365+ if ctx .NArg () > 0 {
366+ return cli .ShowCommandHelp (ctx , "static" )
367+ }
368+
369+ client , cleanup , err := getClient (ctx )
370+ if err != nil {
371+ return err
372+ }
373+ defer cleanup ()
374+
375+ var (
376+ ctxb = context .Background ()
377+ isAllSelected = ctx .IsSet ("all" )
378+ isUtxoSelected = ctx .IsSet ("utxo" )
379+ label = ctx .String ("static-loop-in" )
380+ hints []* swapserverrpc.RouteHint
381+ lastHop []byte
382+ )
383+
384+ // Validate our label early so that we can fail before getting a quote.
385+ if err := labels .Validate (label ); err != nil {
386+ return err
387+ }
388+
389+ // Private and route hints are mutually exclusive as setting private
390+ // means we retrieve our own route hints from the connected node.
391+ hints , err = validateRouteHints (ctx )
392+ if err != nil {
393+ return err
394+ }
395+
396+ if ctx .IsSet (lastHopFlag .Name ) {
397+ lastHopVertex , err := route .NewVertexFromStr (
398+ ctx .String (lastHopFlag .Name ),
399+ )
400+ if err != nil {
401+ return err
402+ }
403+
404+ lastHop = lastHopVertex [:]
405+ }
406+
407+ // Get the amount we need to quote for.
408+ summaryResp , err := client .GetStaticAddressSummary (
409+ ctxb , & looprpc.StaticAddressSummaryRequest {
410+ StateFilter : looprpc .DepositState_DEPOSITED ,
411+ },
412+ )
413+ if err != nil {
414+ return err
415+ }
416+
417+ var depositOutpoints []string
418+ switch {
419+ case isAllSelected == isUtxoSelected :
420+ return errors .New ("must select either all or some utxos" )
421+
422+ case isAllSelected :
423+ depositOutpoints = depositsToOutpoints (
424+ summaryResp .FilteredDeposits ,
425+ )
426+
427+ case isUtxoSelected :
428+ depositOutpoints = ctx .StringSlice ("utxo" )
429+
430+ default :
431+ return fmt .Errorf ("unknown quote request" )
432+ }
433+
434+ quote , err := client .GetLoopInQuote (
435+ ctxb , & looprpc.QuoteRequest {
436+ LoopInRouteHints : hints ,
437+ LoopInLastHop : lastHop ,
438+ Private : ctx .Bool (privateFlag .Name ),
439+ DepositOutpoints : depositOutpoints ,
440+ },
441+ )
442+ if err != nil {
443+ return err
444+ }
445+
446+ limits := getInLimits (quote )
447+
448+ req := & looprpc.StaticAddressLoopInRequest {
449+ Outpoints : depositOutpoints ,
450+ MaxSwapFee : int64 (limits .maxSwapFee ),
451+ LastHop : lastHop ,
452+ Label : ctx .String (labelFlag .Name ),
453+ Initiator : defaultInitiator ,
454+ RouteHints : hints ,
455+ Private : ctx .Bool ("private" ),
456+ }
457+
458+ resp , err := client .StaticAddressLoopIn (ctxb , req )
459+ if err != nil {
460+ return err
461+ }
462+
463+ fmt .Printf ("Static loop-in response from the server: %v\n " , resp )
464+
465+ return nil
466+ }
467+
468+ func depositsToOutpoints (deposits []* looprpc.Deposit ) []string {
469+ outpoints := make ([]string , 0 , len (deposits ))
470+ for _ , deposit := range deposits {
471+ outpoints = append (outpoints , deposit .Outpoint )
472+ }
473+
474+ return outpoints
475+ }
0 commit comments