github.com/Finschia/finschia-sdk@v0.49.1/x/collection/client/cli/tx.go (about)

     1  package cli
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/spf13/cobra"
     8  
     9  	"github.com/Finschia/finschia-sdk/client"
    10  	"github.com/Finschia/finschia-sdk/client/flags"
    11  	"github.com/Finschia/finschia-sdk/client/tx"
    12  	sdk "github.com/Finschia/finschia-sdk/types"
    13  	sdkerrors "github.com/Finschia/finschia-sdk/types/errors"
    14  	"github.com/Finschia/finschia-sdk/version"
    15  	"github.com/Finschia/finschia-sdk/x/collection"
    16  )
    17  
    18  const (
    19  	// common flags for the entities
    20  	FlagName = "name"
    21  	FlagMeta = "meta"
    22  
    23  	// flag for contracts
    24  	FlagBaseImgURI = "base-img-uri"
    25  
    26  	// flag for fungible token classes
    27  	FlagDecimals = "decimals"
    28  	FlagMintable = "mintable"
    29  	FlagTo       = "to"
    30  	FlagSupply   = "supply"
    31  
    32  	DefaultDecimals = 8
    33  	DefaultSupply   = "0"
    34  )
    35  
    36  // NewTxCmd returns the transaction commands for this module
    37  func NewTxCmd() *cobra.Command {
    38  	txCmd := &cobra.Command{
    39  		Use:                        collection.ModuleName,
    40  		Short:                      fmt.Sprintf("%s transactions subcommands", collection.ModuleName),
    41  		DisableFlagParsing:         true,
    42  		SuggestionsMinimumDistance: 2,
    43  		RunE:                       client.ValidateCmd,
    44  	}
    45  
    46  	txCmd.AddCommand(
    47  		NewTxCmdSendFT(),
    48  		NewTxCmdOperatorSendFT(),
    49  		NewTxCmdSendNFT(),
    50  		NewTxCmdOperatorSendNFT(),
    51  		NewTxCmdCreateContract(),
    52  		NewTxCmdIssueFT(),
    53  		NewTxCmdIssueNFT(),
    54  		NewTxCmdMintFT(),
    55  		NewTxCmdMintNFT(),
    56  		NewTxCmdAttach(),
    57  		NewTxCmdDetach(),
    58  		NewTxCmdOperatorAttach(),
    59  		NewTxCmdOperatorDetach(),
    60  		NewTxCmdGrantPermission(),
    61  		NewTxCmdRevokePermission(),
    62  		NewTxCmdAuthorizeOperator(),
    63  		NewTxCmdRevokeOperator(),
    64  		NewTxCmdModify(),
    65  	)
    66  
    67  	return txCmd
    68  }
    69  
    70  func NewTxCmdSendFT() *cobra.Command {
    71  	cmd := &cobra.Command{
    72  		Use:   "send-ft [contract-id] [from] [to] [amount]",
    73  		Args:  cobra.ExactArgs(4),
    74  		Short: "send fungible tokens",
    75  		Long: strings.TrimSpace(fmt.Sprintf(`
    76  			$ %s tx %s send-ft [contract-id] [from] [to] [amount]`, version.AppName, collection.ModuleName),
    77  		),
    78  		RunE: func(cmd *cobra.Command, args []string) error {
    79  			from := args[1]
    80  			if err := cmd.Flags().Set(flags.FlagFrom, from); err != nil {
    81  				return err
    82  			}
    83  
    84  			clientCtx, err := client.GetClientTxContext(cmd)
    85  			if err != nil {
    86  				return err
    87  			}
    88  
    89  			amountStr := args[3]
    90  			amount, err := collection.ParseCoins(amountStr)
    91  			if err != nil {
    92  				return err
    93  			}
    94  
    95  			msg := &collection.MsgSendFT{
    96  				ContractId: args[0],
    97  				From:       from,
    98  				To:         args[2],
    99  				Amount:     amount,
   100  			}
   101  			if err := msg.ValidateBasic(); err != nil {
   102  				return err
   103  			}
   104  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
   105  		},
   106  	}
   107  
   108  	flags.AddTxFlagsToCmd(cmd)
   109  	return cmd
   110  }
   111  
   112  func NewTxCmdOperatorSendFT() *cobra.Command {
   113  	cmd := &cobra.Command{
   114  		Use:   "operator-send-ft [contract-id] [operator] [from] [to] [amount]",
   115  		Args:  cobra.ExactArgs(5),
   116  		Short: "send tokens by operator",
   117  		Long: strings.TrimSpace(fmt.Sprintf(`
   118  			$ %s tx %s operator-send-ft [contract-id] [operator] [from] [to] [amount]`, version.AppName, collection.ModuleName),
   119  		),
   120  		RunE: func(cmd *cobra.Command, args []string) error {
   121  			operator := args[1]
   122  			if err := cmd.Flags().Set(flags.FlagFrom, operator); err != nil {
   123  				return err
   124  			}
   125  
   126  			clientCtx, err := client.GetClientTxContext(cmd)
   127  			if err != nil {
   128  				return err
   129  			}
   130  
   131  			amountStr := args[4]
   132  			amount, err := collection.ParseCoins(amountStr)
   133  			if err != nil {
   134  				return err
   135  			}
   136  
   137  			msg := collection.MsgOperatorSendFT{
   138  				ContractId: args[0],
   139  				Operator:   operator,
   140  				From:       args[2],
   141  				To:         args[3],
   142  				Amount:     amount,
   143  			}
   144  			if err := msg.ValidateBasic(); err != nil {
   145  				return err
   146  			}
   147  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
   148  		},
   149  	}
   150  
   151  	flags.AddTxFlagsToCmd(cmd)
   152  	return cmd
   153  }
   154  
   155  func NewTxCmdSendNFT() *cobra.Command {
   156  	cmd := &cobra.Command{
   157  		Use:   "send-nft [contract-id] [from] [to] [token-id]",
   158  		Args:  cobra.ExactArgs(4),
   159  		Short: "send non-fungible tokens",
   160  		Long: strings.TrimSpace(fmt.Sprintf(`
   161  			$ %s tx %s send-nft [contract-id] [from] [to] [token-id]`, version.AppName, collection.ModuleName),
   162  		),
   163  		RunE: func(cmd *cobra.Command, args []string) error {
   164  			from := args[1]
   165  			if err := cmd.Flags().Set(flags.FlagFrom, from); err != nil {
   166  				return err
   167  			}
   168  
   169  			clientCtx, err := client.GetClientTxContext(cmd)
   170  			if err != nil {
   171  				return err
   172  			}
   173  
   174  			msg := &collection.MsgSendNFT{
   175  				ContractId: args[0],
   176  				From:       from,
   177  				To:         args[2],
   178  				TokenIds:   []string{args[3]},
   179  			}
   180  			if err := msg.ValidateBasic(); err != nil {
   181  				return err
   182  			}
   183  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
   184  		},
   185  	}
   186  
   187  	flags.AddTxFlagsToCmd(cmd)
   188  	return cmd
   189  }
   190  
   191  func NewTxCmdOperatorSendNFT() *cobra.Command {
   192  	cmd := &cobra.Command{
   193  		Use:   "operator-send-nft [contract-id] [operator] [from] [to] [amount]",
   194  		Args:  cobra.ExactArgs(5),
   195  		Short: "send tokens by operator",
   196  		Long: strings.TrimSpace(fmt.Sprintf(`
   197  			$ %s tx %s operator-send-nft [contract-id] [operator] [from] [to] [amount]`, version.AppName, collection.ModuleName),
   198  		),
   199  		RunE: func(cmd *cobra.Command, args []string) error {
   200  			operator := args[1]
   201  			if err := cmd.Flags().Set(flags.FlagFrom, operator); err != nil {
   202  				return err
   203  			}
   204  
   205  			clientCtx, err := client.GetClientTxContext(cmd)
   206  			if err != nil {
   207  				return err
   208  			}
   209  
   210  			msg := collection.MsgOperatorSendNFT{
   211  				ContractId: args[0],
   212  				Operator:   operator,
   213  				From:       args[2],
   214  				To:         args[3],
   215  				TokenIds:   []string{args[4]},
   216  			}
   217  			if err := msg.ValidateBasic(); err != nil {
   218  				return err
   219  			}
   220  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
   221  		},
   222  	}
   223  
   224  	flags.AddTxFlagsToCmd(cmd)
   225  	return cmd
   226  }
   227  
   228  func NewTxCmdCreateContract() *cobra.Command {
   229  	cmd := &cobra.Command{
   230  		Use:   "create-contract [creator]",
   231  		Args:  cobra.ExactArgs(1),
   232  		Short: "create a contract",
   233  		Long: strings.TrimSpace(fmt.Sprintf(`
   234  			$ %s tx %s create-contract [creator]`, version.AppName, collection.ModuleName),
   235  		),
   236  		RunE: func(cmd *cobra.Command, args []string) error {
   237  			creator := args[0]
   238  			if err := cmd.Flags().Set(flags.FlagFrom, creator); err != nil {
   239  				return err
   240  			}
   241  
   242  			clientCtx, err := client.GetClientTxContext(cmd)
   243  			if err != nil {
   244  				return err
   245  			}
   246  
   247  			name, err := cmd.Flags().GetString(FlagName)
   248  			if err != nil {
   249  				return err
   250  			}
   251  
   252  			baseImgURI, err := cmd.Flags().GetString(FlagBaseImgURI)
   253  			if err != nil {
   254  				return err
   255  			}
   256  
   257  			meta, err := cmd.Flags().GetString(FlagMeta)
   258  			if err != nil {
   259  				return err
   260  			}
   261  
   262  			msg := collection.MsgCreateContract{
   263  				Owner: creator,
   264  				Name:  name,
   265  				Uri:   baseImgURI,
   266  				Meta:  meta,
   267  			}
   268  			if err := msg.ValidateBasic(); err != nil {
   269  				return err
   270  			}
   271  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
   272  		},
   273  	}
   274  
   275  	flags.AddTxFlagsToCmd(cmd)
   276  	cmd.Flags().String(FlagName, "", "set name")
   277  	cmd.Flags().String(FlagBaseImgURI, "", "set base-img-uri")
   278  	cmd.Flags().String(FlagMeta, "", "set meta")
   279  
   280  	return cmd
   281  }
   282  
   283  func NewTxCmdIssueFT() *cobra.Command {
   284  	cmd := &cobra.Command{
   285  		Use:   "issue-ft [contract-id] [operator]",
   286  		Args:  cobra.ExactArgs(2),
   287  		Short: "create a fungible token class",
   288  		Long: strings.TrimSpace(fmt.Sprintf(`
   289  			$ %s tx %s issue-ft [contract-id] [operator]`, version.AppName, collection.ModuleName),
   290  		),
   291  		RunE: func(cmd *cobra.Command, args []string) error {
   292  			operator := args[1]
   293  			if err := cmd.Flags().Set(flags.FlagFrom, operator); err != nil {
   294  				return err
   295  			}
   296  
   297  			clientCtx, err := client.GetClientTxContext(cmd)
   298  			if err != nil {
   299  				return err
   300  			}
   301  
   302  			name, err := cmd.Flags().GetString(FlagName)
   303  			if err != nil {
   304  				return err
   305  			}
   306  
   307  			meta, err := cmd.Flags().GetString(FlagMeta)
   308  			if err != nil {
   309  				return err
   310  			}
   311  
   312  			decimals, err := cmd.Flags().GetInt32(FlagDecimals)
   313  			if err != nil {
   314  				return err
   315  			}
   316  
   317  			mintable, err := cmd.Flags().GetBool(FlagMintable)
   318  			if err != nil {
   319  				return err
   320  			}
   321  
   322  			supplyStr, err := cmd.Flags().GetString(FlagSupply)
   323  			if err != nil {
   324  				return err
   325  			}
   326  			supply, ok := sdk.NewIntFromString(supplyStr)
   327  			if !ok {
   328  				return sdkerrors.ErrInvalidType.Wrapf("failed to set supply: %s", supplyStr)
   329  			}
   330  
   331  			to, err := cmd.Flags().GetString(FlagTo)
   332  			if err != nil {
   333  				return err
   334  			}
   335  
   336  			msg := collection.MsgIssueFT{
   337  				ContractId: args[0],
   338  				Owner:      operator,
   339  				Name:       name,
   340  				Meta:       meta,
   341  				Decimals:   decimals,
   342  				Mintable:   mintable,
   343  				To:         to,
   344  				Amount:     supply,
   345  			}
   346  			if err := msg.ValidateBasic(); err != nil {
   347  				return err
   348  			}
   349  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
   350  		},
   351  	}
   352  
   353  	flags.AddTxFlagsToCmd(cmd)
   354  	cmd.Flags().String(FlagName, "", "set name")
   355  	_ = cmd.MarkFlagRequired(FlagName)
   356  	cmd.Flags().String(FlagMeta, "", "set meta")
   357  	cmd.Flags().String(FlagTo, "", "address to send the initial supply")
   358  	_ = cmd.MarkFlagRequired(FlagTo)
   359  	cmd.Flags().Bool(FlagMintable, false, "set mintable")
   360  	cmd.Flags().String(FlagSupply, DefaultSupply, "initial supply")
   361  	cmd.Flags().Int32(FlagDecimals, DefaultDecimals, "set decimals")
   362  
   363  	return cmd
   364  }
   365  
   366  func NewTxCmdIssueNFT() *cobra.Command {
   367  	cmd := &cobra.Command{
   368  		Use:   "issue-nft [contract-id] [operator]",
   369  		Args:  cobra.ExactArgs(2),
   370  		Short: "create a non-fungible token class",
   371  		Long: strings.TrimSpace(fmt.Sprintf(`
   372  			$ %s tx %s issue-nft [contract-id] [operator]`, version.AppName, collection.ModuleName),
   373  		),
   374  		RunE: func(cmd *cobra.Command, args []string) error {
   375  			operator := args[1]
   376  			if err := cmd.Flags().Set(flags.FlagFrom, operator); err != nil {
   377  				return err
   378  			}
   379  
   380  			clientCtx, err := client.GetClientTxContext(cmd)
   381  			if err != nil {
   382  				return err
   383  			}
   384  
   385  			name, err := cmd.Flags().GetString(FlagName)
   386  			if err != nil {
   387  				return err
   388  			}
   389  
   390  			meta, err := cmd.Flags().GetString(FlagMeta)
   391  			if err != nil {
   392  				return err
   393  			}
   394  
   395  			msg := collection.MsgIssueNFT{
   396  				ContractId: args[0],
   397  				Owner:      operator,
   398  				Name:       name,
   399  				Meta:       meta,
   400  			}
   401  			if err := msg.ValidateBasic(); err != nil {
   402  				return err
   403  			}
   404  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
   405  		},
   406  	}
   407  
   408  	flags.AddTxFlagsToCmd(cmd)
   409  	cmd.Flags().String(FlagName, "", "set name")
   410  	cmd.Flags().String(FlagMeta, "", "set meta")
   411  
   412  	return cmd
   413  }
   414  
   415  func NewTxCmdMintFT() *cobra.Command {
   416  	cmd := &cobra.Command{
   417  		Use:   "mint-ft [contract-id] [operator] [to] [class-id] [amount]",
   418  		Args:  cobra.ExactArgs(5),
   419  		Short: "mint fungible tokens",
   420  		Long: strings.TrimSpace(fmt.Sprintf(`
   421  			$ %s tx %s mint-ft [contract-id] [operator] [to] [class-id] [amount]`, version.AppName, collection.ModuleName),
   422  		),
   423  		RunE: func(cmd *cobra.Command, args []string) error {
   424  			operator := args[1]
   425  			if err := cmd.Flags().Set(flags.FlagFrom, operator); err != nil {
   426  				return err
   427  			}
   428  
   429  			clientCtx, err := client.GetClientTxContext(cmd)
   430  			if err != nil {
   431  				return err
   432  			}
   433  
   434  			amountStr := args[4]
   435  			amount, ok := sdk.NewIntFromString(amountStr)
   436  			if !ok {
   437  				return sdkerrors.ErrInvalidType.Wrapf("failed to set amount: %s", amountStr)
   438  			}
   439  
   440  			coins := collection.NewCoins(collection.NewFTCoin(args[3], amount))
   441  			msg := collection.MsgMintFT{
   442  				ContractId: args[0],
   443  				From:       args[1],
   444  				To:         args[2],
   445  				Amount:     coins,
   446  			}
   447  			if err := msg.ValidateBasic(); err != nil {
   448  				return err
   449  			}
   450  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
   451  		},
   452  	}
   453  
   454  	flags.AddTxFlagsToCmd(cmd)
   455  	return cmd
   456  }
   457  
   458  func NewTxCmdMintNFT() *cobra.Command {
   459  	cmd := &cobra.Command{
   460  		Use:   "mint-nft [contract-id] [operator] [to] [class-id]",
   461  		Args:  cobra.ExactArgs(4),
   462  		Short: "mint non-fungible tokens",
   463  		Long: strings.TrimSpace(fmt.Sprintf(`
   464  			$ %s tx %s mint-nft [contract-id] [operator] [to] [class-id]`, version.AppName, collection.ModuleName),
   465  		),
   466  		RunE: func(cmd *cobra.Command, args []string) error {
   467  			operator := args[1]
   468  			if err := cmd.Flags().Set(flags.FlagFrom, operator); err != nil {
   469  				return err
   470  			}
   471  
   472  			clientCtx, err := client.GetClientTxContext(cmd)
   473  			if err != nil {
   474  				return err
   475  			}
   476  
   477  			name, err := cmd.Flags().GetString(FlagName)
   478  			if err != nil {
   479  				return err
   480  			}
   481  
   482  			meta, err := cmd.Flags().GetString(FlagMeta)
   483  			if err != nil {
   484  				return err
   485  			}
   486  
   487  			params := []collection.MintNFTParam{{
   488  				TokenType: args[3],
   489  				Name:      name,
   490  				Meta:      meta,
   491  			}}
   492  
   493  			msg := collection.MsgMintNFT{
   494  				ContractId: args[0],
   495  				From:       args[1],
   496  				To:         args[2],
   497  				Params:     params,
   498  			}
   499  			if err := msg.ValidateBasic(); err != nil {
   500  				return err
   501  			}
   502  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
   503  		},
   504  	}
   505  
   506  	flags.AddTxFlagsToCmd(cmd)
   507  	cmd.Flags().String(FlagName, "", "set name")
   508  	cmd.Flags().String(FlagMeta, "", "set meta")
   509  	_ = cmd.MarkFlagRequired(FlagName)
   510  
   511  	return cmd
   512  }
   513  
   514  func NewTxCmdBurnFT() *cobra.Command {
   515  	cmd := &cobra.Command{
   516  		Use:   "burn-ft [contract-id] [from] [amount]",
   517  		Args:  cobra.ExactArgs(3),
   518  		Short: "burn tokens",
   519  		Long: strings.TrimSpace(fmt.Sprintf(`
   520  			$ %s tx %s burn-ft [contract-id] [from] [amount]`, version.AppName, collection.ModuleName),
   521  		),
   522  		RunE: func(cmd *cobra.Command, args []string) error {
   523  			from := args[1]
   524  			if err := cmd.Flags().Set(flags.FlagFrom, from); err != nil {
   525  				return err
   526  			}
   527  
   528  			clientCtx, err := client.GetClientTxContext(cmd)
   529  			if err != nil {
   530  				return err
   531  			}
   532  
   533  			amountStr := args[2]
   534  			amount, err := collection.ParseCoins(amountStr)
   535  			if err != nil {
   536  				return err
   537  			}
   538  
   539  			msg := collection.MsgBurnFT{
   540  				ContractId: args[0],
   541  				From:       from,
   542  				Amount:     amount,
   543  			}
   544  			if err := msg.ValidateBasic(); err != nil {
   545  				return err
   546  			}
   547  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
   548  		},
   549  	}
   550  
   551  	flags.AddTxFlagsToCmd(cmd)
   552  	return cmd
   553  }
   554  
   555  func NewTxCmdOperatorBurnFT() *cobra.Command {
   556  	cmd := &cobra.Command{
   557  		Use:   "operator-burn-ft [contract-id] [operator] [from] [amount]",
   558  		Args:  cobra.ExactArgs(4),
   559  		Short: "burn tokens by a given operator",
   560  		Long: strings.TrimSpace(fmt.Sprintf(`
   561  			$ %s tx %s operator-burn-ft [contract-id] [operator] [from] [amount]`, version.AppName, collection.ModuleName),
   562  		),
   563  		RunE: func(cmd *cobra.Command, args []string) error {
   564  			operator := args[1]
   565  			if err := cmd.Flags().Set(flags.FlagFrom, operator); err != nil {
   566  				return err
   567  			}
   568  
   569  			clientCtx, err := client.GetClientTxContext(cmd)
   570  			if err != nil {
   571  				return err
   572  			}
   573  
   574  			amountStr := args[3]
   575  			amount, err := collection.ParseCoins(amountStr)
   576  			if err != nil {
   577  				return err
   578  			}
   579  
   580  			msg := collection.MsgOperatorBurnFT{
   581  				ContractId: args[0],
   582  				Operator:   operator,
   583  				From:       args[2],
   584  				Amount:     amount,
   585  			}
   586  			if err := msg.ValidateBasic(); err != nil {
   587  				return err
   588  			}
   589  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
   590  		},
   591  	}
   592  
   593  	flags.AddTxFlagsToCmd(cmd)
   594  	return cmd
   595  }
   596  
   597  func NewTxCmdBurnNFT() *cobra.Command {
   598  	cmd := &cobra.Command{
   599  		Use:   "burn-nft [contract-id] [from] [token-id]",
   600  		Args:  cobra.ExactArgs(3),
   601  		Short: "burn tokens",
   602  		Long: strings.TrimSpace(fmt.Sprintf(`
   603  			$ %s tx %s burn-nft [contract-id] [from] [token-id]`, version.AppName, collection.ModuleName),
   604  		),
   605  		RunE: func(cmd *cobra.Command, args []string) error {
   606  			from := args[1]
   607  			if err := cmd.Flags().Set(flags.FlagFrom, from); err != nil {
   608  				return err
   609  			}
   610  
   611  			clientCtx, err := client.GetClientTxContext(cmd)
   612  			if err != nil {
   613  				return err
   614  			}
   615  
   616  			msg := collection.MsgBurnNFT{
   617  				ContractId: args[0],
   618  				From:       from,
   619  				TokenIds:   []string{args[2]},
   620  			}
   621  			if err := msg.ValidateBasic(); err != nil {
   622  				return err
   623  			}
   624  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
   625  		},
   626  	}
   627  
   628  	flags.AddTxFlagsToCmd(cmd)
   629  	return cmd
   630  }
   631  
   632  func NewTxCmdOperatorBurnNFT() *cobra.Command {
   633  	cmd := &cobra.Command{
   634  		Use:   "operator-burn-nft [contract-id] [operator] [from] [token-id]",
   635  		Args:  cobra.ExactArgs(4),
   636  		Short: "burn tokens by a given operator",
   637  		Long: strings.TrimSpace(fmt.Sprintf(`
   638  			$ %s tx %s operator-burn-nft [contract-id] [operator] [from] [token-id]`, version.AppName, collection.ModuleName),
   639  		),
   640  		RunE: func(cmd *cobra.Command, args []string) error {
   641  			operator := args[1]
   642  			if err := cmd.Flags().Set(flags.FlagFrom, operator); err != nil {
   643  				return err
   644  			}
   645  
   646  			clientCtx, err := client.GetClientTxContext(cmd)
   647  			if err != nil {
   648  				return err
   649  			}
   650  
   651  			msg := collection.MsgOperatorBurnNFT{
   652  				ContractId: args[0],
   653  				Operator:   operator,
   654  				From:       args[2],
   655  				TokenIds:   []string{args[3]},
   656  			}
   657  			if err := msg.ValidateBasic(); err != nil {
   658  				return err
   659  			}
   660  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
   661  		},
   662  	}
   663  
   664  	flags.AddTxFlagsToCmd(cmd)
   665  	return cmd
   666  }
   667  
   668  func NewTxCmdModify() *cobra.Command {
   669  	cmd := &cobra.Command{
   670  		Use:   "modify [contract-id] [operator] [token-type] [token-index] [key] [value]",
   671  		Args:  cobra.ExactArgs(6),
   672  		Short: "modify",
   673  		Long: strings.TrimSpace(fmt.Sprintf(`
   674  			$ %s tx %s modify [contract-id] [operator] [token-type] [token-index] [key] [value]`, version.AppName, collection.ModuleName),
   675  		),
   676  		RunE: func(cmd *cobra.Command, args []string) error {
   677  			operator := args[1]
   678  			if err := cmd.Flags().Set(flags.FlagFrom, operator); err != nil {
   679  				return err
   680  			}
   681  
   682  			clientCtx, err := client.GetClientTxContext(cmd)
   683  			if err != nil {
   684  				return err
   685  			}
   686  
   687  			changes := []collection.Attribute{{
   688  				Key:   args[4],
   689  				Value: args[5],
   690  			}}
   691  			msg := collection.MsgModify{
   692  				ContractId: args[0],
   693  				Owner:      args[1],
   694  				TokenType:  args[2],
   695  				TokenIndex: args[3],
   696  				Changes:    changes,
   697  			}
   698  			if err := msg.ValidateBasic(); err != nil {
   699  				return err
   700  			}
   701  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
   702  		},
   703  	}
   704  
   705  	flags.AddTxFlagsToCmd(cmd)
   706  	return cmd
   707  }
   708  
   709  func NewTxCmdAttach() *cobra.Command {
   710  	cmd := &cobra.Command{
   711  		Use:   "attach [contract-id] [holder] [subject] [target]",
   712  		Args:  cobra.ExactArgs(4),
   713  		Short: "attach a token to another",
   714  		Long: strings.TrimSpace(fmt.Sprintf(`
   715  			$ %s tx %s attach [contract-id] [holder] [subject] [target]`, version.AppName, collection.ModuleName),
   716  		),
   717  		RunE: func(cmd *cobra.Command, args []string) error {
   718  			holder := args[1]
   719  			if err := cmd.Flags().Set(flags.FlagFrom, holder); err != nil {
   720  				return err
   721  			}
   722  
   723  			clientCtx, err := client.GetClientTxContext(cmd)
   724  			if err != nil {
   725  				return err
   726  			}
   727  
   728  			msg := collection.MsgAttach{
   729  				ContractId: args[0],
   730  				From:       holder,
   731  				TokenId:    args[2],
   732  				ToTokenId:  args[3],
   733  			}
   734  			if err := msg.ValidateBasic(); err != nil {
   735  				return err
   736  			}
   737  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
   738  		},
   739  	}
   740  
   741  	flags.AddTxFlagsToCmd(cmd)
   742  	return cmd
   743  }
   744  
   745  func NewTxCmdDetach() *cobra.Command {
   746  	cmd := &cobra.Command{
   747  		Use:   "detach [contract-id] [holder] [subject]",
   748  		Args:  cobra.ExactArgs(3),
   749  		Short: "detach a token from its parent",
   750  		Long: strings.TrimSpace(fmt.Sprintf(`
   751  			$ %s tx %s detach [contract-id] [holder] [subject]`, version.AppName, collection.ModuleName),
   752  		),
   753  		RunE: func(cmd *cobra.Command, args []string) error {
   754  			holder := args[1]
   755  			if err := cmd.Flags().Set(flags.FlagFrom, holder); err != nil {
   756  				return err
   757  			}
   758  
   759  			clientCtx, err := client.GetClientTxContext(cmd)
   760  			if err != nil {
   761  				return err
   762  			}
   763  
   764  			msg := collection.MsgDetach{
   765  				ContractId: args[0],
   766  				From:       holder,
   767  				TokenId:    args[2],
   768  			}
   769  			if err := msg.ValidateBasic(); err != nil {
   770  				return err
   771  			}
   772  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
   773  		},
   774  	}
   775  
   776  	flags.AddTxFlagsToCmd(cmd)
   777  	return cmd
   778  }
   779  
   780  func NewTxCmdOperatorAttach() *cobra.Command {
   781  	cmd := &cobra.Command{
   782  		Use:   "operator-attach [contract-id] [operator] [holder] [subject] [target]",
   783  		Args:  cobra.ExactArgs(5),
   784  		Short: "attach a token to another by the operator",
   785  		Long: strings.TrimSpace(fmt.Sprintf(`
   786  			$ %s tx %s operator-attach [contract-id] [operator] [holder] [subject] [target]`, version.AppName, collection.ModuleName),
   787  		),
   788  		RunE: func(cmd *cobra.Command, args []string) error {
   789  			operator := args[1]
   790  			if err := cmd.Flags().Set(flags.FlagFrom, operator); err != nil {
   791  				return err
   792  			}
   793  
   794  			clientCtx, err := client.GetClientTxContext(cmd)
   795  			if err != nil {
   796  				return err
   797  			}
   798  
   799  			msg := collection.MsgOperatorAttach{
   800  				ContractId: args[0],
   801  				Operator:   operator,
   802  				From:       args[2],
   803  				TokenId:    args[3],
   804  				ToTokenId:  args[4],
   805  			}
   806  			if err := msg.ValidateBasic(); err != nil {
   807  				return err
   808  			}
   809  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
   810  		},
   811  	}
   812  
   813  	flags.AddTxFlagsToCmd(cmd)
   814  	return cmd
   815  }
   816  
   817  func NewTxCmdOperatorDetach() *cobra.Command {
   818  	cmd := &cobra.Command{
   819  		Use:   "operator-detach [contract-id] [operator] [holder] [subject]",
   820  		Args:  cobra.ExactArgs(4),
   821  		Short: "detach a token from its parent by the operator",
   822  		Long: strings.TrimSpace(fmt.Sprintf(`
   823  			$ %s tx %s operator-detach [contract-id] [operator] [holder] [subject]`, version.AppName, collection.ModuleName),
   824  		),
   825  		RunE: func(cmd *cobra.Command, args []string) error {
   826  			operator := args[1]
   827  			if err := cmd.Flags().Set(flags.FlagFrom, operator); err != nil {
   828  				return err
   829  			}
   830  
   831  			clientCtx, err := client.GetClientTxContext(cmd)
   832  			if err != nil {
   833  				return err
   834  			}
   835  
   836  			msg := collection.MsgOperatorDetach{
   837  				ContractId: args[0],
   838  				Operator:   operator,
   839  				From:       args[2],
   840  				TokenId:    args[3],
   841  			}
   842  			if err := msg.ValidateBasic(); err != nil {
   843  				return err
   844  			}
   845  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
   846  		},
   847  	}
   848  
   849  	flags.AddTxFlagsToCmd(cmd)
   850  	return cmd
   851  }
   852  
   853  func NewTxCmdGrantPermission() *cobra.Command {
   854  	cmd := &cobra.Command{
   855  		Use:   "grant-permission [contract-id] [granter] [grantee] [permission]",
   856  		Args:  cobra.ExactArgs(4),
   857  		Short: "grant a permission for mint, burn, modify and issue",
   858  		Long: strings.TrimSpace(fmt.Sprintf(`
   859  			$ %s tx %s grant-permission [contract-id] [granter] [grantee] [permission]`, version.AppName, collection.ModuleName),
   860  		),
   861  		RunE: func(cmd *cobra.Command, args []string) error {
   862  			granter := args[1]
   863  			if err := cmd.Flags().Set(flags.FlagFrom, granter); err != nil {
   864  				return err
   865  			}
   866  
   867  			clientCtx, err := client.GetClientTxContext(cmd)
   868  			if err != nil {
   869  				return err
   870  			}
   871  
   872  			msg := collection.MsgGrantPermission{
   873  				ContractId: args[0],
   874  				From:       granter,
   875  				To:         args[2],
   876  				Permission: args[3],
   877  			}
   878  			if err := msg.ValidateBasic(); err != nil {
   879  				return err
   880  			}
   881  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
   882  		},
   883  	}
   884  
   885  	flags.AddTxFlagsToCmd(cmd)
   886  	return cmd
   887  }
   888  
   889  func NewTxCmdRevokePermission() *cobra.Command {
   890  	cmd := &cobra.Command{
   891  		Use:   "revoke-permission [contract-id] [grantee] [permission]",
   892  		Args:  cobra.ExactArgs(3),
   893  		Short: "revoke a permission by a given grantee",
   894  		Long: strings.TrimSpace(fmt.Sprintf(`
   895  			$ %s tx %s revoke-permission [contract-id] [grantee] [permission]`, version.AppName, collection.ModuleName),
   896  		),
   897  		RunE: func(cmd *cobra.Command, args []string) error {
   898  			grantee := args[1]
   899  			if err := cmd.Flags().Set(flags.FlagFrom, grantee); err != nil {
   900  				return err
   901  			}
   902  
   903  			clientCtx, err := client.GetClientTxContext(cmd)
   904  			if err != nil {
   905  				return err
   906  			}
   907  
   908  			msg := collection.MsgRevokePermission{
   909  				ContractId: args[0],
   910  				From:       grantee,
   911  				Permission: args[2],
   912  			}
   913  			if err := msg.ValidateBasic(); err != nil {
   914  				return err
   915  			}
   916  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
   917  		},
   918  	}
   919  
   920  	flags.AddTxFlagsToCmd(cmd)
   921  	return cmd
   922  }
   923  
   924  func NewTxCmdAuthorizeOperator() *cobra.Command {
   925  	cmd := &cobra.Command{
   926  		Use:   "authorize-operator [contract-id] [holder] [operator]",
   927  		Args:  cobra.ExactArgs(3),
   928  		Short: "authorize operator to manipulate tokens of holder",
   929  		Long: strings.TrimSpace(fmt.Sprintf(`
   930  			$ %s tx %s authorize-operator [contract-id] [holder] [operator]`, version.AppName, collection.ModuleName),
   931  		),
   932  		RunE: func(cmd *cobra.Command, args []string) error {
   933  			holder := args[1]
   934  			if err := cmd.Flags().Set(flags.FlagFrom, holder); err != nil {
   935  				return err
   936  			}
   937  
   938  			clientCtx, err := client.GetClientTxContext(cmd)
   939  			if err != nil {
   940  				return err
   941  			}
   942  
   943  			msg := collection.MsgAuthorizeOperator{
   944  				ContractId: args[0],
   945  				Holder:     holder,
   946  				Operator:   args[2],
   947  			}
   948  			if err := msg.ValidateBasic(); err != nil {
   949  				return err
   950  			}
   951  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
   952  		},
   953  	}
   954  
   955  	flags.AddTxFlagsToCmd(cmd)
   956  	return cmd
   957  }
   958  
   959  func NewTxCmdRevokeOperator() *cobra.Command {
   960  	cmd := &cobra.Command{
   961  		Use:   "revoke-operator [contract-id] [holder] [operator]",
   962  		Args:  cobra.ExactArgs(3),
   963  		Short: "revoke operator",
   964  		Long: strings.TrimSpace(fmt.Sprintf(`
   965  			$ %s tx %s revoke-operator [contract-id] [holder] [operator]`, version.AppName, collection.ModuleName),
   966  		),
   967  		RunE: func(cmd *cobra.Command, args []string) error {
   968  			holder := args[1]
   969  			if err := cmd.Flags().Set(flags.FlagFrom, holder); err != nil {
   970  				return err
   971  			}
   972  
   973  			clientCtx, err := client.GetClientTxContext(cmd)
   974  			if err != nil {
   975  				return err
   976  			}
   977  
   978  			msg := collection.MsgRevokeOperator{
   979  				ContractId: args[0],
   980  				Holder:     holder,
   981  				Operator:   args[2],
   982  			}
   983  			if err := msg.ValidateBasic(); err != nil {
   984  				return err
   985  			}
   986  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
   987  		},
   988  	}
   989  
   990  	flags.AddTxFlagsToCmd(cmd)
   991  	return cmd
   992  }