Skip to content

Latest commit

 

History

History
196 lines (145 loc) · 7.46 KB

Cli.md

File metadata and controls

196 lines (145 loc) · 7.46 KB

CLI

A Command Line Interface (CLI) will help us interact with our app once it is running on a machine somewhere. Each Module has its own namespace within the CLI that gives it the ability to create and sign Messages destined to be handled by that module. It also comes with the ability to query the state of that module. When combined with the rest of the app, the CLI will let you do things like generate keys for a new account or check the status of an interaction you already had with the application.

The CLI for our module is broken into two files called tx.go and query.go which are located in ./nfts/client/cli/. One file is for making transactions that contain messages which will ultimately update our state. The other is for making queries which will give us the ability to read information from our state. Both files utilize the Cobra library.

Transactions

The tx.go file contains GetTxCmd which is a standard method within the Cosmos SDK. It is referenced later in the module.go file which describes exactly which attributes a module has. This makes it easier to incorporate different modules for different reasons at the level of the actual application. After all, we are focusing on a module at this point, but later we will create an application that utilizes this module as well as other modules that are already available within the Cosmos SDK.

Inside GetTxCmd we create a new module-specific command and call is nfts. Within this command we add a sub-command for each Message type we've defined:

  • GetMsgMintTweetNFT

Each function takes parameters from the Cobra CLI tool to create a new msg, sign it and submit it to the application to be processed. These functions should go into the tx.go file and look as follows:

package cli

import (
    "bufio"
    "strconv"
    
    "github.com/spf13/cobra"
    "github.com/spf13/viper"
    
    "github.com/cosmos/cosmos-sdk/client/context"
    "github.com/cosmos/cosmos-sdk/client/flags"
    "github.com/cosmos/cosmos-sdk/codec"
    sdk "github.com/cosmos/cosmos-sdk/types"
    authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
    authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
    
    "github.com/FreeFlixMedia/modules/nfts/internal/types"
)

func GetTxCmd(cdc *codec.Codec) *cobra.Command {
    NFTTxCmd := &cobra.Command{
        Use:   types.ModuleName,
        Short: "nfts  transfer transaction subcommands",
    }
    
    NFTTxCmd.AddCommand(flags.PostCommands(
        GetMsgMintTweetNFT(cdc),
    )...)
    
    return NFTTxCmd
}

func GetMsgMintTweetNFT(cdc *codec.Codec) *cobra.Command {
    cmd := &cobra.Command{
        Use:   "mint-nft ",
        Short: "mint tweet nft",
        RunE: func(cmd *cobra.Command, args []string) error {
            inBuf := bufio.NewReader(cmd.InOrStdin())
            txBldr := authtypes.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc))
            cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc)
            
            var fee sdk.Coin
            var share sdk.Dec
            var err error
            
            license, err := strconv.ParseBool(viper.GetString(FlagLicence))
            if err != nil {
                return err
            }
            
            feeStr := viper.GetString(FlagLicenceFee)
            if feeStr != "" {
                fee, err = sdk.ParseCoin(feeStr)
                if err != nil {
                    return err
                }
                
            }
            
            shareStr := viper.GetString(FlagRevenueShare)
            if shareStr != "" {
                share, err = sdk.NewDecFromStr(shareStr)
                if err != nil {
                    return err
                }
                
            }
            
            msg := types.NewMsgMintNFT(cliCtx.GetFromAddress(), viper.GetString(FlagAssetID), license, fee, share, viper.GetString(FlagTwitterHandle))
            if err := msg.ValidateBasic(); err != nil {
                return err
            }
            return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
        },
    }
    
    cmd.Flags().String(FlagAssetID, "", "AssetID")
    cmd.Flags().String(FlagTwitterHandle, "", "Twitter handle")
    cmd.Flags().String(FlagLicenceFee, "0coco", "Twitter handle")
    cmd.Flags().String(FlagRevenueShare, "0", "Revenue share")
    cmd.Flags().String(FlagLicence, "false", "license")
    return cmd
}

Query

The query.go file contains similar Cobra commands that reserve a new namespace for referencing our nfts module. Instead of creating and submitting messages, however, the query.go the file creates queries and returns the results in human-readable form. The queries it handles are the same we defined in our querier.go file earlier:

  • GetCmdQueryTweetNFT
  • GetCmdQueryTweetsByAccount

After defining these commands, your query.go file should look like:

package cli

import (
    "fmt"
    
    "github.com/cosmos/cosmos-sdk/client"
    "github.com/cosmos/cosmos-sdk/client/context"
    "github.com/cosmos/cosmos-sdk/client/flags"
    "github.com/cosmos/cosmos-sdk/codec"
    "github.com/spf13/cobra"
    
    "github.com/FreeFlixMedia/modules/nfts/internal/types"
)

func GetQueryCmd(cdc *codec.Codec) *cobra.Command {
    cmd := &cobra.Command{
        Use:                        types.ModuleName,
        Short:                      "Querying commands for the nft module",
        DisableFlagParsing:         true,
        SuggestionsMinimumDistance: 2,
        RunE:                       client.ValidateCmd,
    }
    
    cmd.AddCommand(
        GetCmdQueryTweetNFT(cdc),
        GetCmdQueryTweetsByAccount(cdc),
    )
    
    return cmd
}

func GetCmdQueryTweetNFT(cdc *codec.Codec) *cobra.Command {
    cmd := &cobra.Command{
        Use:   "nft [id]",
        Short: "Get NFT using nft id ",
        Args:  cobra.ExactArgs(1),
        RunE: func(cmd *cobra.Command, args []string) error {
            cliCtx := context.NewCLIContext().WithCodec(cdc)
            
            res, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s/%s", types.QuerierRoute, types.QueryTweetNFT, args[0]), nil)
            if err != nil {
                return err
            }
            
            var tweetNFT types.BaseTweetNFT
            cdc.MustUnmarshalJSON(res, &tweetNFT)
            return cliCtx.PrintOutput(tweetNFT)
        },
    }
    return flags.GetCommands(cmd)[0]
}

func GetCmdQueryTweetsByAccount(cdc *codec.Codec) *cobra.Command {
    cmd := &cobra.Command{
        Use:   "nfts [address]",
        Short: "Get  NFTs associated to account",
        Args:  cobra.ExactArgs(1),
        RunE: func(cmd *cobra.Command, args []string) error {
            cliCtx := context.NewCLIContext().WithCodec(cdc)
            
            res, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s/%s", types.QuerierRoute, types.QueryTweetNFTsByAddress, args[0]), nil)
            if err != nil {
                return err
            }
            
            var tweetNFTs []types.BaseTweetNFT
            cdc.MustUnmarshalJSON(res, &tweetNFTs)
            return cliCtx.PrintOutput(tweetNFTs)
        },
    }
    return flags.GetCommands(cmd)[0]
    
}

While these are all the major moving pieces of a module (Message, Handler, Keeper, Querier, and Client) there are some organizational tasks that we have yet to complete. The next step will be making sure that our module is completely configured to make it usable within any application.