Skip to content

Commit a151ffd

Browse files
committed
all loopin changes
1 parent 2c94110 commit a151ffd

32 files changed

+4838
-580
lines changed

cmd/loop/staticaddr.go

Lines changed: 167 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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

2976
var 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+
}

interface.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,44 @@ type LoopInRequest struct {
234234
RouteHints [][]zpay32.HopHint
235235
}
236236

237+
// StaticAddressLoopInRequest contains the required parameters for the swap.
238+
type StaticAddressLoopInRequest struct {
239+
DepositOutpoints []string
240+
241+
// MaxSwapFee is the maximum we are willing to pay the server for the
242+
// swap. This value is not disclosed in the swap initiation call, but if
243+
// the server asks for a higher fee, we abort the swap. Typically this
244+
// value is taken from the response of the LoopInQuote call. It
245+
// includes the pre-pay amount.
246+
MaxSwapFee btcutil.Amount
247+
248+
// LastHop optionally specifies the last hop to use for the loop in
249+
// payment.
250+
LastHop *route.Vertex
251+
252+
// Label contains an optional label for the swap.
253+
Label string
254+
255+
// Initiator is an optional string that identifies what software
256+
// initiated the swap (loop CLI, autolooper, LiT UI and so on) and is
257+
// appended to the user agent string.
258+
Initiator string
259+
260+
// Private indicates whether the destination node should be considered
261+
// private. In which case, loop will generate hophints to assist with
262+
// probing and payment.
263+
Private bool
264+
265+
// RouteHints are optional route hints to reach the destination through
266+
// private channels.
267+
RouteHints [][]zpay32.HopHint
268+
}
269+
270+
// StaticAddressLoopInResponse contains the parameters for the static address
271+
// loop-in.
272+
type StaticAddressLoopInResponse struct {
273+
}
274+
237275
// LoopInTerms are the server terms on which it executes loop in swaps.
238276
type LoopInTerms struct {
239277
// MinSwapAmount is the minimum amount that the server requires for a

loopd/daemon.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"crypto/tls"
66
"errors"
77
"fmt"
8+
"github.com/lightninglabs/loop/staticaddr/loopin"
89
"net"
910
"net/http"
1011
"strings"
@@ -513,6 +514,7 @@ func (d *Daemon) initialize(withMacaroonService bool) error {
513514
staticAddressManager *address.Manager
514515
depositManager *deposit.Manager
515516
withdrawalManager *withdraw.Manager
517+
staticLoopInManager *loopin.Manager
516518
)
517519
// Create the reservation and instantout managers.
518520
if d.cfg.EnableExperimental {
@@ -589,6 +591,30 @@ func (d *Daemon) initialize(withMacaroonService bool) error {
589591
Signer: d.lnd.Signer,
590592
}
591593
withdrawalManager = withdraw.NewManager(withdrawalCfg)
594+
595+
// Static address loop-in manager setup.
596+
staticAddressLoopInStore := loopin.NewSqlStore(
597+
loopdb.NewTypedStore[loopin.Querier](baseDb),
598+
clock.NewDefaultClock(), depositStore,
599+
d.lnd.ChainParams,
600+
)
601+
602+
loopinCfg := &loopin.Config{
603+
StaticAddressServerClient: staticAddressClient,
604+
SwapClient: swapClient,
605+
LndClient: d.lnd.Client,
606+
InvoicesClient: d.lnd.Invoices,
607+
NodePubkey: d.lnd.NodePubkey,
608+
AddressManager: staticAddressManager,
609+
DepositManager: depositManager,
610+
WithdrawalManager: withdrawalManager,
611+
Store: staticAddressLoopInStore,
612+
WalletKit: d.lnd.WalletKit,
613+
ChainNotifier: d.lnd.ChainNotifier,
614+
ChainParams: d.lnd.ChainParams,
615+
Signer: d.lnd.Signer,
616+
}
617+
staticLoopInManager = loopin.NewManager(loopinCfg)
592618
}
593619

594620
// Now finally fully initialize the swap client RPC server instance.
@@ -607,6 +633,7 @@ func (d *Daemon) initialize(withMacaroonService bool) error {
607633
staticAddressManager: staticAddressManager,
608634
depositManager: depositManager,
609635
withdrawalManager: withdrawalManager,
636+
staticLoopInManager: staticLoopInManager,
610637
}
611638

612639
// Retrieve all currently existing swaps from the database.
@@ -764,6 +791,33 @@ func (d *Daemon) initialize(withMacaroonService bool) error {
764791
withdrawalManager.WaitInitComplete()
765792
}
766793

794+
// Start the static address loop-in manager.
795+
if staticLoopInManager != nil {
796+
d.wg.Add(1)
797+
go func() {
798+
defer d.wg.Done()
799+
800+
// Lnd's GetInfo call supplies us with the current block
801+
// height.
802+
info, err := d.lnd.Client.GetInfo(d.mainCtx)
803+
if err != nil {
804+
d.internalErrChan <- err
805+
return
806+
}
807+
808+
log.Info("Starting static address loop-in manager...")
809+
err = staticLoopInManager.Run(
810+
d.mainCtx, info.BlockHeight,
811+
)
812+
if err != nil && !errors.Is(context.Canceled, err) {
813+
d.internalErrChan <- err
814+
}
815+
log.Info("Starting static address loop-in manager " +
816+
"stopped")
817+
}()
818+
staticLoopInManager.WaitInitComplete()
819+
}
820+
767821
// Last, start our internal error handler. This will return exactly one
768822
// error or nil on the main error channel to inform the caller that
769823
// something went wrong or that shutdown is complete. We don't add to

loopd/perms/perms.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,13 @@ var RequiredPermissions = map[string][]bakery.Op{
101101
Entity: "loop",
102102
Action: "in",
103103
}},
104+
"/looprpc.SwapClient/StaticAddressLoopIn": {{
105+
Entity: "swap",
106+
Action: "read",
107+
}, {
108+
Entity: "loop",
109+
Action: "in",
110+
}},
104111
"/looprpc.SwapClient/GetLsatTokens": {{
105112
Entity: "auth",
106113
Action: "read",

0 commit comments

Comments
 (0)