@@ -8,9 +8,11 @@ import (
88 "strconv"
99 "strings"
1010
11+ "github.com/btcsuite/btcd/btcec/v2"
1112 "github.com/btcsuite/btcd/wire"
1213 taprootassets "github.com/lightninglabs/taproot-assets"
1314 "github.com/lightninglabs/taproot-assets/address"
15+ "github.com/lightninglabs/taproot-assets/asset"
1416 "github.com/lightninglabs/taproot-assets/tapcfg"
1517 "github.com/lightninglabs/taproot-assets/taprpc"
1618 wrpc "github.com/lightninglabs/taproot-assets/taprpc/assetwalletrpc"
@@ -1092,6 +1094,10 @@ var burnAssetsCommand = cli.Command{
10921094 Name : assetIDName ,
10931095 Usage : "the asset ID to burn units from" ,
10941096 },
1097+ cli.StringFlag {
1098+ Name : assetGroupKeyName ,
1099+ Usage : "the group key to burn units from" ,
1100+ },
10951101 cli.Uint64Flag {
10961102 Name : assetAmountName ,
10971103 Usage : "the amount of units to burn/destroy" ,
@@ -1106,15 +1112,66 @@ var burnAssetsCommand = cli.Command{
11061112 Action : burnAssets ,
11071113}
11081114
1115+ // buildAssetSpecifier validates and constructs an asset.Specifier from
1116+ // CLI context
1117+ func buildAssetSpecifier (ctx * cli.Context ) (* asset.Specifier , error ) {
1118+ assetIDHex := ctx .String (assetIDName )
1119+ groupKeyHex := ctx .String (assetGroupKeyName )
1120+
1121+ // At least one of asset ID or group key must be provided.
1122+ if assetIDHex == "" && groupKeyHex == "" {
1123+ return nil , fmt .Errorf ("either asset ID or " +
1124+ "group key must be specified" )
1125+ }
1126+
1127+ var (
1128+ assetID * asset.ID
1129+ groupKey * btcec.PublicKey
1130+ err error
1131+ )
1132+
1133+ // Parse asset ID if provided.
1134+ if assetIDHex != "" {
1135+ assetIDBytes , err := hex .DecodeString (assetIDHex )
1136+ if err != nil {
1137+ return nil , fmt .Errorf ("invalid asset ID: %w" , err )
1138+ }
1139+
1140+ var id asset.ID
1141+ copy (id [:], assetIDBytes )
1142+ assetID = & id
1143+ }
1144+
1145+ // Parse group key if provided.
1146+ if groupKeyHex != "" {
1147+ groupKeyBytes , err := hex .DecodeString (groupKeyHex )
1148+ if err != nil {
1149+ return nil , fmt .Errorf ("invalid group key: %w" , err )
1150+ }
1151+
1152+ groupKey , err = btcec .ParsePubKey (groupKeyBytes )
1153+ if err != nil {
1154+ return nil , fmt .Errorf ("invalid group key: %w" , err )
1155+ }
1156+ }
1157+
1158+ // Construct the asset specifier.
1159+ assetSpecifier , err := asset .NewSpecifier (assetID , groupKey , nil , true )
1160+ if err != nil {
1161+ return nil , fmt .Errorf ("invalid asset specifier: %w" , err )
1162+ }
1163+
1164+ return & assetSpecifier , nil
1165+ }
1166+
11091167func burnAssets (ctx * cli.Context ) error {
11101168 if ctx .NArg () != 0 || ctx .NumFlags () == 0 {
11111169 return cli .ShowSubcommandHelp (ctx )
11121170 }
11131171
1114- assetIDHex := ctx .String (assetIDName )
1115- assetIDBytes , err := hex .DecodeString (assetIDHex )
1172+ assetSpecifier , err := buildAssetSpecifier (ctx )
11161173 if err != nil {
1117- return fmt .Errorf ("invalid asset ID" )
1174+ return fmt .Errorf ("invalid asset specifier: %w" , err )
11181175 }
11191176
11201177 burnAmount := ctx .Uint64 (assetAmountName )
@@ -1126,42 +1183,82 @@ func burnAssets(ctx *cli.Context) error {
11261183 client , cleanUp := getClient (ctx )
11271184 defer cleanUp ()
11281185
1186+ assetIDBytes , groupKeyBytes := assetSpecifier .AsBytes ()
1187+
11291188 if ! ctx .Bool (burnOverrideConfirmationName ) {
1130- balance , err := client .ListBalances (
1131- ctxc , & taprpc.ListBalancesRequest {
1132- GroupBy : & taprpc.ListBalancesRequest_AssetId {
1133- AssetId : true ,
1189+ var currBalance uint64
1190+
1191+ // When both asset ID and group key are provided,
1192+ // prioritize asset ID for balance checking since
1193+ // it's more specific.
1194+ switch {
1195+ case len (assetIDBytes ) > 0 :
1196+ // nolint: lll
1197+ balance , err := client .ListBalances (ctxc ,
1198+ & taprpc.ListBalancesRequest {
1199+ GroupBy : & taprpc.ListBalancesRequest_AssetId {
1200+ AssetId : true ,
1201+ },
1202+ AssetFilter : assetIDBytes ,
11341203 },
1135- AssetFilter : assetIDBytes ,
1136- },
1137- )
1138- if err != nil {
1139- return fmt .Errorf ("unable to list current asset " +
1140- "balances: %w" , err )
1141- }
1204+ )
1205+ if err != nil {
1206+ return fmt .Errorf ("unable to list current " +
1207+ "asset balances: %w" , err )
1208+ }
1209+
1210+ idHex := hex .EncodeToString (assetIDBytes )
1211+ assetBalance , ok := balance .AssetBalances [idHex ]
1212+ if ! ok {
1213+ return fmt .Errorf ("couldn't fetch balance for " +
1214+ "asset ID %x" , assetIDBytes )
1215+ }
1216+
1217+ currBalance = assetBalance .Balance
1218+
1219+ case len (groupKeyBytes ) > 0 :
1220+ // nolint: lll
1221+ balance , err := client .ListBalances (ctxc ,
1222+ & taprpc.ListBalancesRequest {
1223+ GroupBy : & taprpc.ListBalancesRequest_GroupKey {
1224+ GroupKey : true ,
1225+ },
1226+ AssetFilter : groupKeyBytes ,
1227+ },
1228+ )
1229+ if err != nil {
1230+ return fmt .Errorf ("unable to list current " +
1231+ "asset balances: %w" , err )
1232+ }
11421233
1143- assetBalance , ok := balance .AssetBalances [assetIDHex ]
1144- if ! ok {
1145- return fmt .Errorf ("couldn't fetch balance for asset %x" ,
1146- assetIDBytes )
1234+ gkHex := hex .EncodeToString (groupKeyBytes )
1235+ groupBalance , ok := balance .AssetGroupBalances [gkHex ]
1236+ if ! ok {
1237+ return fmt .Errorf ("couldn't fetch balance for " +
1238+ "group key %x" , groupKeyBytes )
1239+ }
1240+
1241+ currBalance = groupBalance .Balance
11471242 }
11481243
11491244 msg := fmt .Sprintf ("Please confirm destructive action.\n " +
1150- "Asset ID: %x \n Current available balance: %d\n " +
1245+ "%s \n Current available balance: %d\n " +
11511246 "Amount to burn: %d\n Are you sure you want to " +
11521247 "irreversibly burn (destroy, remove from circulation) " +
11531248 "the specified amount of assets?\n Please answer 'yes' " +
1154- "or 'no' and press enter: " , assetIDBytes ,
1155- assetBalance .Balance , burnAmount )
1249+ "or 'no' and press enter: " ,
1250+ assetSpecifier .String (), currBalance , burnAmount ,
1251+ )
11561252
11571253 if ! promptForConfirmation (msg ) {
11581254 return nil
11591255 }
11601256 }
11611257
11621258 resp , err := client .BurnAsset (ctxc , & taprpc.BurnAssetRequest {
1163- Asset : & taprpc.BurnAssetRequest_AssetId {
1164- AssetId : assetIDBytes ,
1259+ AssetSpecifier : & taprpc.AssetSpecifier {
1260+ Id : assetIDBytes ,
1261+ GroupKey : groupKeyBytes ,
11651262 },
11661263 AmountToBurn : burnAmount ,
11671264 ConfirmationText : taprootassets .AssetBurnConfirmationText ,
0 commit comments