Skip to content

Commit 9a67edb

Browse files
committed
cmd: add --group_key CLI flag to all channel commands
1 parent 9fe4408 commit 9a67edb

File tree

1 file changed

+111
-86
lines changed

1 file changed

+111
-86
lines changed

cmd/litcli/ln.go

Lines changed: 111 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@ import (
77
"encoding/hex"
88
"errors"
99
"fmt"
10-
"strconv"
1110

12-
"github.com/lightninglabs/taproot-assets/asset"
1311
"github.com/lightninglabs/taproot-assets/rfq"
1412
"github.com/lightninglabs/taproot-assets/rfqmath"
1513
"github.com/lightninglabs/taproot-assets/rpcutils"
@@ -35,8 +33,9 @@ const (
3533

3634
var lnCommands = []cli.Command{
3735
{
38-
Name: "ln",
39-
Usage: "Interact with the Lightning Network.",
36+
Name: "ln",
37+
Usage: "Interact with Taproot Assets on the Lightning " +
38+
"Network.",
4039
Category: "Taproot Assets on LN",
4140
Subcommands: []cli.Command{
4241
fundChannelCommand,
@@ -83,8 +82,16 @@ var fundChannelCommand = cli.Command{
8382
"channel.",
8483
},
8584
cli.StringFlag{
86-
Name: "asset_id",
87-
Usage: "The asset ID to commit to the channel.",
85+
Name: "asset_id",
86+
Usage: "The asset ID to commit to the channel; " +
87+
"cannot be used at the same time as " +
88+
"--group_key",
89+
},
90+
cli.StringFlag{
91+
Name: "group_key",
92+
Usage: "The group key to use for selecting assets to " +
93+
"commit to the channel; cannot be used at " +
94+
"the same time as --asset_id",
8895
},
8996
},
9097
Action: fundChannel,
@@ -106,9 +113,9 @@ func fundChannel(c *cli.Context) error {
106113
return fmt.Errorf("error fetching assets: %w", err)
107114
}
108115

109-
assetIDBytes, err := hex.DecodeString(c.String("asset_id"))
116+
assetIDBytes, groupKeyBytes, err := parseAssetIdentifier(c)
110117
if err != nil {
111-
return fmt.Errorf("error hex decoding asset ID: %w", err)
118+
return fmt.Errorf("unable to parse asset identifier: %w", err)
112119
}
113120

114121
requestedAmount := c.Uint64("asset_amount")
@@ -149,6 +156,7 @@ func fundChannel(c *cli.Context) error {
149156
ctx, &tchrpc.FundChannelRequest{
150157
AssetAmount: requestedAmount,
151158
AssetId: assetIDBytes,
159+
GroupKey: groupKeyBytes,
152160
PeerPubkey: nodePubBytes,
153161
FeeRateSatPerVbyte: uint32(c.Uint64("sat_per_vbyte")),
154162
PushSat: c.Int64("push_amt"),
@@ -167,7 +175,15 @@ var (
167175
assetIDFlag = cli.StringFlag{
168176
Name: "asset_id",
169177
Usage: "the asset ID of the asset to use when sending " +
170-
"payments with assets",
178+
"payments with assets; cannot be used at the same " +
179+
"time as --group_key",
180+
}
181+
182+
groupKeyFlag = cli.StringFlag{
183+
Name: "group_key",
184+
Usage: "the group key of the asset to use when sending " +
185+
"payments with assets; cannot be used at the same " +
186+
"time as --asset_id",
171187
}
172188

173189
assetAmountFlag = cli.Uint64Flag{
@@ -281,18 +297,19 @@ var sendPaymentCommand = cli.Command{
281297
Name: "sendpayment",
282298
Category: commands.SendPaymentCommand.Category,
283299
Usage: "Send a payment over Lightning, potentially using a " +
284-
"mulit-asset channel as the first hop",
300+
"multi-asset channel as the first hop.",
285301
Description: commands.SendPaymentCommand.Description + `
286302
To send an multi-asset LN payment to a single hop, the --asset_id=X
287-
argument should be used.
303+
or --group_key=X argument should be used.
288304
289305
Note that this will only work in concert with the --keysend argument.
290306
`,
291-
ArgsUsage: commands.SendPaymentCommand.ArgsUsage + " --asset_id=X " +
292-
"--asset_amount=Y [--rfq_peer_pubkey=Z]",
307+
ArgsUsage: commands.SendPaymentCommand.ArgsUsage + " [--asset_id=X " +
308+
" | --group_key=X] --asset_amount=Y [--rfq_peer_pubkey=Z] " +
309+
"[--allow_overpay]",
293310
Flags: append(
294-
commands.SendPaymentCommand.Flags, assetIDFlag, assetAmountFlag,
295-
rfqPeerPubKeyFlag, allowOverpayFlag,
311+
commands.SendPaymentCommand.Flags, assetIDFlag, groupKeyFlag,
312+
assetAmountFlag, rfqPeerPubKeyFlag, allowOverpayFlag,
296313
),
297314
Action: sendPayment,
298315
}
@@ -321,19 +338,9 @@ func sendPayment(cliCtx *cli.Context) error {
321338
}
322339
defer cleanup()
323340

324-
switch {
325-
case !cliCtx.IsSet(assetIDFlag.Name):
326-
return fmt.Errorf("the --asset_id flag must be set")
327-
case !cliCtx.IsSet("keysend"):
328-
return fmt.Errorf("the --keysend flag must be set")
329-
case !cliCtx.IsSet(assetAmountFlag.Name):
330-
return fmt.Errorf("--asset_amount must be set")
331-
}
332-
333-
assetIDStr := cliCtx.String(assetIDFlag.Name)
334-
assetIDBytes, err := hex.DecodeString(assetIDStr)
341+
assetIDBytes, groupKeyBytes, err := parseAssetIdentifier(cliCtx)
335342
if err != nil {
336-
return fmt.Errorf("unable to decode assetID: %v", err)
343+
return fmt.Errorf("unable to parse asset identifier: %w", err)
337344
}
338345

339346
assetAmountToSend := cliCtx.Uint64(assetAmountFlag.Name)
@@ -363,7 +370,9 @@ func sendPayment(cliCtx *cli.Context) error {
363370
"is instead: %v", len(destNode))
364371
}
365372

366-
rfqPeerKey, err := hex.DecodeString(cliCtx.String(rfqPeerPubKeyFlag.Name))
373+
rfqPeerKey, err := hex.DecodeString(
374+
cliCtx.String(rfqPeerPubKeyFlag.Name),
375+
)
367376
if err != nil {
368377
return fmt.Errorf("unable to decode RFQ peer public key: "+
369378
"%w", err)
@@ -412,6 +421,7 @@ func sendPayment(cliCtx *cli.Context) error {
412421
stream, err := tchrpcClient.SendPayment(
413422
ctx, &tchrpc.SendPaymentRequest{
414423
AssetId: assetIDBytes,
424+
GroupKey: groupKeyBytes,
415425
AssetAmount: assetAmountToSend,
416426
PeerPubkey: rfqPeerKey,
417427
PaymentRequest: req,
@@ -432,22 +442,24 @@ func sendPayment(cliCtx *cli.Context) error {
432442
var payInvoiceCommand = cli.Command{
433443
Name: "payinvoice",
434444
Category: "Payments",
435-
Usage: "Pay an invoice over lightning using an asset.",
445+
Usage: "Pay an invoice over Lightning, potentially using a " +
446+
"multi-asset channel as the first hop.",
436447
Description: `
437448
This command attempts to pay an invoice using an asset channel as the
438-
source of the payment. The asset ID of the channel must be specified
439-
using the --asset_id flag.
449+
source of the payment. The asset of the channel must be specified using
450+
the --asset_id or --group_key flag.
451+
452+
This command is a shortcut for 'sendpayment --pay_req='.
440453
`,
441-
ArgsUsage: "pay_req --asset_id=X",
454+
ArgsUsage: "pay_req [--asset_id=X | --group_key=X] " +
455+
"[--rfq_peer_pubkey=y] [--allow_overpay]",
442456
Flags: append(commands.PaymentFlags(),
443457
cli.Int64Flag{
444458
Name: "amt",
445459
Usage: "(optional) number of satoshis to fulfill the " +
446460
"invoice",
447461
},
448-
assetIDFlag,
449-
rfqPeerPubKeyFlag,
450-
allowOverpayFlag,
462+
assetIDFlag, groupKeyFlag, rfqPeerPubKeyFlag, allowOverpayFlag,
451463
),
452464
Action: payInvoice,
453465
}
@@ -486,15 +498,9 @@ func payInvoice(cli *cli.Context) error {
486498
return err
487499
}
488500

489-
if !cli.IsSet(assetIDFlag.Name) {
490-
return fmt.Errorf("the --asset_id flag must be set")
491-
}
492-
493-
assetIDStr := cli.String(assetIDFlag.Name)
494-
495-
assetIDBytes, err := hex.DecodeString(assetIDStr)
501+
assetIDBytes, groupKeyBytes, err := parseAssetIdentifier(cli)
496502
if err != nil {
497-
return fmt.Errorf("unable to decode assetID: %v", err)
503+
return fmt.Errorf("unable to parse asset identifier: %w", err)
498504
}
499505

500506
rfqPeerKey, err := hex.DecodeString(cli.String(rfqPeerPubKeyFlag.Name))
@@ -521,6 +527,7 @@ func payInvoice(cli *cli.Context) error {
521527
stream, err := tchrpcClient.SendPayment(
522528
ctx, &tchrpc.SendPaymentRequest{
523529
AssetId: assetIDBytes,
530+
GroupKey: groupKeyBytes,
524531
PeerPubkey: rfqPeerKey,
525532
PaymentRequest: req,
526533
AllowOverpay: allowOverpay,
@@ -546,12 +553,19 @@ var addInvoiceCommand = cli.Command{
546553
Add a new invoice, expressing intent for a future payment, received in
547554
Taproot Assets.
548555
`,
549-
ArgsUsage: "asset_id asset_amount",
556+
ArgsUsage: "[--asset_id=X | --group_key=X] --asset_amount=Y " +
557+
"[--rfq_peer_pubkey=Z] ",
550558
Flags: append(
551559
commands.AddInvoiceCommand.Flags,
552560
cli.StringFlag{
553-
Name: "asset_id",
554-
Usage: "the asset ID of the asset to receive",
561+
Name: "asset_id",
562+
Usage: "the asset ID of the asset to receive; cannot " +
563+
"be used at the same time as --group_key",
564+
},
565+
cli.StringFlag{
566+
Name: "group_key",
567+
Usage: "the group key of the asset to receive; " +
568+
"cannot be used at the same time as --asset_id",
555569
},
556570
cli.Uint64Flag{
557571
Name: "asset_amount",
@@ -570,36 +584,15 @@ var addInvoiceCommand = cli.Command{
570584
}
571585

572586
func addInvoice(cli *cli.Context) error {
573-
args := cli.Args()
574587
ctx := getContext()
575588

576-
var assetIDStr string
577-
switch {
578-
case cli.IsSet("asset_id"):
579-
assetIDStr = cli.String("asset_id")
580-
case args.Present():
581-
assetIDStr = args.First()
582-
args = args.Tail()
583-
default:
584-
return fmt.Errorf("asset_id argument missing")
585-
}
586-
587589
var (
588-
assetAmount uint64
590+
assetAmount = cli.Uint64("asset_amount")
589591
preimage []byte
590592
descHash []byte
591593
err error
592594
)
593-
switch {
594-
case cli.IsSet("asset_amount"):
595-
assetAmount = cli.Uint64("asset_amount")
596-
case args.Present():
597-
assetAmount, err = strconv.ParseUint(args.First(), 10, 64)
598-
if err != nil {
599-
return fmt.Errorf("unable to parse asset amount %w",
600-
err)
601-
}
602-
default:
595+
if assetAmount == 0 {
603596
return fmt.Errorf("asset_amount argument missing")
604597
}
605598

@@ -620,14 +613,11 @@ func addInvoice(cli *cli.Context) error {
620613
expirySeconds = cli.Int64("expiry")
621614
}
622615

623-
assetIDBytes, err := hex.DecodeString(assetIDStr)
616+
assetIDBytes, groupKeyBytes, err := parseAssetIdentifier(cli)
624617
if err != nil {
625-
return fmt.Errorf("unable to decode assetID: %v", err)
618+
return fmt.Errorf("unable to parse asset identifier: %w", err)
626619
}
627620

628-
var assetID asset.ID
629-
copy(assetID[:], assetIDBytes)
630-
631621
rfqPeerKey, err := hex.DecodeString(cli.String(rfqPeerPubKeyFlag.Name))
632622
if err != nil {
633623
return fmt.Errorf("unable to decode RFQ peer public key: "+
@@ -643,6 +633,7 @@ func addInvoice(cli *cli.Context) error {
643633
channelsClient := tchrpc.NewTaprootAssetChannelsClient(tapdConn)
644634
resp, err := channelsClient.AddInvoice(ctx, &tchrpc.AddInvoiceRequest{
645635
AssetId: assetIDBytes,
636+
GroupKey: groupKeyBytes,
646637
AssetAmount: assetAmount,
647638
PeerPubkey: rfqPeerKey,
648639
InvoiceRequest: &lnrpc.Invoice{
@@ -668,43 +659,39 @@ var decodeAssetInvoiceCommand = cli.Command{
668659
Name: "decodeassetinvoice",
669660
Category: "Payments",
670661
Usage: "Decodes an LN invoice and displays the invoice's amount in " +
671-
"asset units specified by an asset ID",
662+
"asset units specified by an asset ID or group key.",
672663
Description: `
673664
This command can be used to display the information encoded in an
674665
invoice.
675-
Given a chosen asset_id, the invoice's amount expressed in units of the
676-
asset will be displayed.
666+
Given a chosen asset_id or group_key, the invoice's amount expressed in
667+
units of the asset will be displayed.
677668
678669
Other information such as the decimal display of an asset, and the asset
679670
group information (if applicable) are also shown.
680671
`,
681-
ArgsUsage: "--pay_req=X --asset_id=X",
672+
ArgsUsage: "--pay_req=X [--asset_id=X | --group_key=X]",
682673
Flags: []cli.Flag{
683674
cli.StringFlag{
684675
Name: "pay_req",
685676
Usage: "a zpay32 encoded payment request to fulfill",
686677
},
687-
assetIDFlag,
678+
assetIDFlag, groupKeyFlag,
688679
},
689680
Action: decodeAssetInvoice,
690681
}
691682

692683
func decodeAssetInvoice(cli *cli.Context) error {
693684
ctx := getContext()
694685

695-
switch {
696-
case !cli.IsSet("pay_req"):
686+
if !cli.IsSet("pay_req") {
697687
return fmt.Errorf("pay_req argument missing")
698-
case !cli.IsSet(assetIDFlag.Name):
699-
return fmt.Errorf("the --asset_id flag must be set")
700688
}
701689

702690
payReq := cli.String("pay_req")
703691

704-
assetIDStr := cli.String(assetIDFlag.Name)
705-
assetIDBytes, err := hex.DecodeString(assetIDStr)
692+
assetIDBytes, groupKeyBytes, err := parseAssetIdentifier(cli)
706693
if err != nil {
707-
return fmt.Errorf("unable to decode assetID: %v", err)
694+
return fmt.Errorf("unable to parse asset identifier: %w", err)
708695
}
709696

710697
tapdConn, cleanup, err := connectSuperMacClient(ctx, cli)
@@ -716,6 +703,7 @@ func decodeAssetInvoice(cli *cli.Context) error {
716703
channelsClient := tchrpc.NewTaprootAssetChannelsClient(tapdConn)
717704
resp, err := channelsClient.DecodeAssetPayReq(ctx, &tchrpc.AssetPayReq{
718705
AssetId: assetIDBytes,
706+
GroupKey: groupKeyBytes,
719707
PayReqString: payReq,
720708
})
721709
if err != nil {
@@ -726,3 +714,40 @@ func decodeAssetInvoice(cli *cli.Context) error {
726714

727715
return nil
728716
}
717+
718+
// parseAssetIdentifier parses either the asset ID or group key from the command
719+
// line arguments.
720+
func parseAssetIdentifier(cli *cli.Context) ([]byte, []byte, error) {
721+
if !cli.IsSet(assetIDFlag.Name) && !cli.IsSet(groupKeyFlag.Name) {
722+
return nil, nil, fmt.Errorf("either the --asset_id or " +
723+
"--group_key flag must be set")
724+
}
725+
726+
var (
727+
assetIDBytes []byte
728+
groupKeyBytes []byte
729+
err error
730+
)
731+
if cli.IsSet("asset_id") {
732+
assetIDBytes, err = hex.DecodeString(cli.String("asset_id"))
733+
if err != nil {
734+
return nil, nil, fmt.Errorf("error hex decoding asset "+
735+
"ID: %w", err)
736+
}
737+
}
738+
739+
if cli.IsSet("group_key") {
740+
groupKeyBytes, err = hex.DecodeString(cli.String("group_key"))
741+
if err != nil {
742+
return nil, nil, fmt.Errorf("error hex decoding group "+
743+
"key: %w", err)
744+
}
745+
}
746+
747+
if len(assetIDBytes) == 0 && len(groupKeyBytes) == 0 {
748+
return nil, nil, fmt.Errorf("only one of --asset_id and " +
749+
"--group_key can be set")
750+
}
751+
752+
return assetIDBytes, groupKeyBytes, nil
753+
}

0 commit comments

Comments
 (0)