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/taprpc"
@@ -83,8 +81,16 @@ var fundChannelCommand = cli.Command{
8381 "channel." ,
8482 },
8583 cli.StringFlag {
86- Name : "asset_id" ,
87- Usage : "The asset ID to commit to the channel." ,
84+ Name : "asset_id" ,
85+ Usage : "The asset ID to commit to the channel; " +
86+ "cannot be used at the same time as " +
87+ "--group_key" ,
88+ },
89+ cli.StringFlag {
90+ Name : "group_key" ,
91+ Usage : "The group key to use for selecting assets to " +
92+ "commit to the channel; cannot be used at " +
93+ "the same time as --asset_id" ,
8894 },
8995 },
9096 Action : fundChannel ,
@@ -106,9 +112,9 @@ func fundChannel(c *cli.Context) error {
106112 return fmt .Errorf ("error fetching assets: %w" , err )
107113 }
108114
109- assetIDBytes , err := hex . DecodeString ( c . String ( "asset_id" ) )
115+ assetIDBytes , groupKeyBytes , err := parseAssetIdentifier ( c )
110116 if err != nil {
111- return fmt .Errorf ("error hex decoding asset ID : %w" , err )
117+ return fmt .Errorf ("unable to parse asset identifier : %w" , err )
112118 }
113119
114120 requestedAmount := c .Uint64 ("asset_amount" )
@@ -149,6 +155,7 @@ func fundChannel(c *cli.Context) error {
149155 ctx , & tchrpc.FundChannelRequest {
150156 AssetAmount : requestedAmount ,
151157 AssetId : assetIDBytes ,
158+ GroupKey : groupKeyBytes ,
152159 PeerPubkey : nodePubBytes ,
153160 FeeRateSatPerVbyte : uint32 (c .Uint64 ("sat_per_vbyte" )),
154161 PushSat : c .Int64 ("push_amt" ),
@@ -167,7 +174,15 @@ var (
167174 assetIDFlag = cli.StringFlag {
168175 Name : "asset_id" ,
169176 Usage : "the asset ID of the asset to use when sending " +
170- "payments with assets" ,
177+ "payments with assets; cannot be used at the same " +
178+ "time as --group_key" ,
179+ }
180+
181+ groupKeyFlag = cli.StringFlag {
182+ Name : "group_key" ,
183+ Usage : "the group key of the asset to use when sending " +
184+ "payments with assets; cannot be used at the same " +
185+ "time as --asset_id" ,
171186 }
172187
173188 assetAmountFlag = cli.Uint64Flag {
@@ -288,11 +303,12 @@ var sendPaymentCommand = cli.Command{
288303
289304 Note that this will only work in concert with the --keysend argument.
290305 ` ,
291- ArgsUsage : commands .SendPaymentCommand .ArgsUsage + " --asset_id=X " +
292- "--asset_amount=Y [--rfq_peer_pubkey=Z]" ,
306+ ArgsUsage : commands .SendPaymentCommand .ArgsUsage + " [--asset_id=X " +
307+ " | --group_key=X] --asset_amount=Y [--rfq_peer_pubkey=Z] " +
308+ "[--allow_overpay]" ,
293309 Flags : append (
294- commands .SendPaymentCommand .Flags , assetIDFlag , assetAmountFlag ,
295- rfqPeerPubKeyFlag , allowOverpayFlag ,
310+ commands .SendPaymentCommand .Flags , assetIDFlag , groupKeyFlag ,
311+ assetAmountFlag , rfqPeerPubKeyFlag , allowOverpayFlag ,
296312 ),
297313 Action : sendPayment ,
298314}
@@ -322,18 +338,15 @@ func sendPayment(cliCtx *cli.Context) error {
322338 defer cleanup ()
323339
324340 switch {
325- case ! cliCtx .IsSet (assetIDFlag .Name ):
326- return fmt .Errorf ("the --asset_id flag must be set" )
327341 case ! cliCtx .IsSet ("keysend" ):
328342 return fmt .Errorf ("the --keysend flag must be set" )
329343 case ! cliCtx .IsSet (assetAmountFlag .Name ):
330344 return fmt .Errorf ("--asset_amount must be set" )
331345 }
332346
333- assetIDStr := cliCtx .String (assetIDFlag .Name )
334- assetIDBytes , err := hex .DecodeString (assetIDStr )
347+ assetIDBytes , groupKeyBytes , err := parseAssetIdentifier (cliCtx )
335348 if err != nil {
336- return fmt .Errorf ("unable to decode assetID : %v " , err )
349+ return fmt .Errorf ("unable to parse asset identifier : %w " , err )
337350 }
338351
339352 assetAmountToSend := cliCtx .Uint64 (assetAmountFlag .Name )
@@ -363,7 +376,9 @@ func sendPayment(cliCtx *cli.Context) error {
363376 "is instead: %v" , len (destNode ))
364377 }
365378
366- rfqPeerKey , err := hex .DecodeString (cliCtx .String (rfqPeerPubKeyFlag .Name ))
379+ rfqPeerKey , err := hex .DecodeString (
380+ cliCtx .String (rfqPeerPubKeyFlag .Name ),
381+ )
367382 if err != nil {
368383 return fmt .Errorf ("unable to decode RFQ peer public key: " +
369384 "%w" , err )
@@ -412,6 +427,7 @@ func sendPayment(cliCtx *cli.Context) error {
412427 stream , err := tchrpcClient .SendPayment (
413428 ctx , & tchrpc.SendPaymentRequest {
414429 AssetId : assetIDBytes ,
430+ GroupKey : groupKeyBytes ,
415431 AssetAmount : assetAmountToSend ,
416432 PeerPubkey : rfqPeerKey ,
417433 PaymentRequest : req ,
@@ -438,16 +454,15 @@ var payInvoiceCommand = cli.Command{
438454 source of the payment. The asset ID of the channel must be specified
439455 using the --asset_id flag.
440456 ` ,
441- ArgsUsage : "pay_req --asset_id=X" ,
457+ ArgsUsage : "pay_req [--asset_id=X | --group_key=X] " +
458+ "[--rfq_peer_pubkey=y] [--allow_overpay]" ,
442459 Flags : append (commands .PaymentFlags (),
443460 cli.Int64Flag {
444461 Name : "amt" ,
445462 Usage : "(optional) number of satoshis to fulfill the " +
446463 "invoice" ,
447464 },
448- assetIDFlag ,
449- rfqPeerPubKeyFlag ,
450- allowOverpayFlag ,
465+ assetIDFlag , groupKeyFlag , rfqPeerPubKeyFlag , allowOverpayFlag ,
451466 ),
452467 Action : payInvoice ,
453468}
@@ -486,15 +501,9 @@ func payInvoice(cli *cli.Context) error {
486501 return err
487502 }
488503
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 )
504+ assetIDBytes , groupKeyBytes , err := parseAssetIdentifier (cli )
496505 if err != nil {
497- return fmt .Errorf ("unable to decode assetID : %v " , err )
506+ return fmt .Errorf ("unable to parse asset identifier : %w " , err )
498507 }
499508
500509 rfqPeerKey , err := hex .DecodeString (cli .String (rfqPeerPubKeyFlag .Name ))
@@ -521,6 +530,7 @@ func payInvoice(cli *cli.Context) error {
521530 stream , err := tchrpcClient .SendPayment (
522531 ctx , & tchrpc.SendPaymentRequest {
523532 AssetId : assetIDBytes ,
533+ GroupKey : groupKeyBytes ,
524534 PeerPubkey : rfqPeerKey ,
525535 PaymentRequest : req ,
526536 AllowOverpay : allowOverpay ,
@@ -545,13 +555,22 @@ var addInvoiceCommand = cli.Command{
545555 Description : `
546556 Add a new invoice, expressing intent for a future payment, received in
547557 Taproot Assets.
558+
559+ This command is a shortcut for 'sendpayment --pay_req='.
548560 ` ,
549- ArgsUsage : "asset_id asset_amount" ,
561+ ArgsUsage : "[--asset_id=X | --group_key=X] --asset_amount=Y " +
562+ "[--rfq_peer_pubkey=Z] " ,
550563 Flags : append (
551564 commands .AddInvoiceCommand .Flags ,
552565 cli.StringFlag {
553- Name : "asset_id" ,
554- Usage : "the asset ID of the asset to receive" ,
566+ Name : "asset_id" ,
567+ Usage : "the asset ID of the asset to receive; cannot " +
568+ "be used at the same time as --group_key" ,
569+ },
570+ cli.StringFlag {
571+ Name : "group_key" ,
572+ Usage : "the group key of the asset to receive; " +
573+ "cannot be used at the same time as --asset_id" ,
555574 },
556575 cli.Uint64Flag {
557576 Name : "asset_amount" ,
@@ -570,36 +589,15 @@ var addInvoiceCommand = cli.Command{
570589}
571590
572591func addInvoice (cli * cli.Context ) error {
573- args := cli .Args ()
574592 ctx := getContext ()
575593
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-
587594 var (
588- assetAmount uint64
595+ assetAmount = cli . Uint64 ( "asset_amount" )
589596 preimage []byte
590597 descHash []byte
591598 err error
592599 )
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 :
600+ if assetAmount == 0 {
603601 return fmt .Errorf ("asset_amount argument missing" )
604602 }
605603
@@ -620,14 +618,11 @@ func addInvoice(cli *cli.Context) error {
620618 expirySeconds = cli .Int64 ("expiry" )
621619 }
622620
623- assetIDBytes , err := hex . DecodeString ( assetIDStr )
621+ assetIDBytes , groupKeyBytes , err := parseAssetIdentifier ( cli )
624622 if err != nil {
625- return fmt .Errorf ("unable to decode assetID : %v " , err )
623+ return fmt .Errorf ("unable to parse asset identifier : %w " , err )
626624 }
627625
628- var assetID asset.ID
629- copy (assetID [:], assetIDBytes )
630-
631626 rfqPeerKey , err := hex .DecodeString (cli .String (rfqPeerPubKeyFlag .Name ))
632627 if err != nil {
633628 return fmt .Errorf ("unable to decode RFQ peer public key: " +
@@ -643,6 +638,7 @@ func addInvoice(cli *cli.Context) error {
643638 channelsClient := tchrpc .NewTaprootAssetChannelsClient (tapdConn )
644639 resp , err := channelsClient .AddInvoice (ctx , & tchrpc.AddInvoiceRequest {
645640 AssetId : assetIDBytes ,
641+ GroupKey : groupKeyBytes ,
646642 AssetAmount : assetAmount ,
647643 PeerPubkey : rfqPeerKey ,
648644 InvoiceRequest : & lnrpc.Invoice {
@@ -678,33 +674,29 @@ var decodeAssetInvoiceCommand = cli.Command{
678674 Other information such as the decimal display of an asset, and the asset
679675 group information (if applicable) are also shown.
680676 ` ,
681- ArgsUsage : "--pay_req=X --asset_id=X" ,
677+ ArgsUsage : "--pay_req=X [ --asset_id=X | --group_key=X] " ,
682678 Flags : []cli.Flag {
683679 cli.StringFlag {
684680 Name : "pay_req" ,
685681 Usage : "a zpay32 encoded payment request to fulfill" ,
686682 },
687- assetIDFlag ,
683+ assetIDFlag , groupKeyFlag ,
688684 },
689685 Action : decodeAssetInvoice ,
690686}
691687
692688func decodeAssetInvoice (cli * cli.Context ) error {
693689 ctx := getContext ()
694690
695- switch {
696- case ! cli .IsSet ("pay_req" ):
691+ if ! cli .IsSet ("pay_req" ) {
697692 return fmt .Errorf ("pay_req argument missing" )
698- case ! cli .IsSet (assetIDFlag .Name ):
699- return fmt .Errorf ("the --asset_id flag must be set" )
700693 }
701694
702695 payReq := cli .String ("pay_req" )
703696
704- assetIDStr := cli .String (assetIDFlag .Name )
705- assetIDBytes , err := hex .DecodeString (assetIDStr )
697+ assetIDBytes , groupKeyBytes , err := parseAssetIdentifier (cli )
706698 if err != nil {
707- return fmt .Errorf ("unable to decode assetID : %v " , err )
699+ return fmt .Errorf ("unable to parse asset identifier : %w " , err )
708700 }
709701
710702 tapdConn , cleanup , err := connectSuperMacClient (ctx , cli )
@@ -716,6 +708,7 @@ func decodeAssetInvoice(cli *cli.Context) error {
716708 channelsClient := tchrpc .NewTaprootAssetChannelsClient (tapdConn )
717709 resp , err := channelsClient .DecodeAssetPayReq (ctx , & tchrpc.AssetPayReq {
718710 AssetId : assetIDBytes ,
711+ GroupKey : groupKeyBytes ,
719712 PayReqString : payReq ,
720713 })
721714 if err != nil {
@@ -726,3 +719,40 @@ func decodeAssetInvoice(cli *cli.Context) error {
726719
727720 return nil
728721}
722+
723+ // parseAssetIdentifier parses either the asset ID or group key from the command
724+ // line arguments.
725+ func parseAssetIdentifier (cli * cli.Context ) ([]byte , []byte , error ) {
726+ if ! cli .IsSet (assetIDFlag .Name ) && ! cli .IsSet (groupKeyFlag .Name ) {
727+ return nil , nil , fmt .Errorf ("either the --asset_id or " +
728+ "--group_key flag must be set" )
729+ }
730+
731+ var (
732+ assetIDBytes []byte
733+ groupKeyBytes []byte
734+ err error
735+ )
736+ if cli .IsSet ("asset_id" ) {
737+ assetIDBytes , err = hex .DecodeString (cli .String ("asset_id" ))
738+ if err != nil {
739+ return nil , nil , fmt .Errorf ("error hex decoding asset " +
740+ "ID: %w" , err )
741+ }
742+ }
743+
744+ if cli .IsSet ("group_key" ) {
745+ groupKeyBytes , err = hex .DecodeString (cli .String ("group_key" ))
746+ if err != nil {
747+ return nil , nil , fmt .Errorf ("error hex decoding group " +
748+ "key: %w" , err )
749+ }
750+ }
751+
752+ if len (assetIDBytes ) == 0 && len (groupKeyBytes ) == 0 {
753+ return nil , nil , fmt .Errorf ("only one of --asset_id and " +
754+ "--group_key can be set" )
755+ }
756+
757+ return assetIDBytes , groupKeyBytes , nil
758+ }
0 commit comments