github.com/lino-network/lino@v0.6.11/x/account/client/cli/tx.go (about)

     1  package cli
     2  
     3  import (
     4  	"encoding/hex"
     5  	"fmt"
     6  	"strconv"
     7  	"strings"
     8  
     9  	"github.com/cosmos/cosmos-sdk/codec"
    10  	sdk "github.com/cosmos/cosmos-sdk/types"
    11  	"github.com/spf13/cobra"
    12  	"github.com/spf13/viper"
    13  	"github.com/tendermint/tendermint/crypto/secp256k1"
    14  
    15  	"github.com/lino-network/lino/client"
    16  	linotypes "github.com/lino-network/lino/types"
    17  	"github.com/lino-network/lino/x/account/types"
    18  )
    19  
    20  const (
    21  	FlagTo          = "to"
    22  	FlagName        = "name"
    23  	FlagAmount      = "amount"
    24  	FlagRegFee      = "reg-fee"
    25  	FlagMemo        = "memo"
    26  	FlagAddr        = "addr"
    27  	FlagAddrSeq     = "addr-seq"
    28  	FlagAddrPrivKey = "addr-priv-key"
    29  	FlagNewTxKey    = "new-tx-priv"
    30  	FlagNewSignKey  = "new-sign-pub"
    31  )
    32  
    33  func GetTxCmd(cdc *codec.Codec) *cobra.Command {
    34  	cmd := &cobra.Command{
    35  		Use:                        types.ModuleName,
    36  		Short:                      "Account tx subcommands, type is either 'addr' or 'user'.",
    37  		DisableFlagParsing:         true,
    38  		SuggestionsMinimumDistance: 2,
    39  		RunE:                       client.ValidateCmd,
    40  	}
    41  
    42  	cmd.AddCommand(client.PostCommands(
    43  		getCmdRegister(cdc),
    44  		getCmdTransferV2(cdc),
    45  		getCmdBind(cdc),
    46  		getCmdRecover(cdc),
    47  	)...)
    48  
    49  	return cmd
    50  }
    51  
    52  // getCmdRegister - register a new user with random generated private keys.
    53  func getCmdRegister(cdc *codec.Codec) *cobra.Command {
    54  	cmd := &cobra.Command{
    55  		Use:   "register <type:referrer> --reg-fee <amount> --name <name>",
    56  		Short: "register <type:referrer> --reg-fee <amount> --name <name>",
    57  		Args:  cobra.ExactArgs(1),
    58  		RunE: func(cmd *cobra.Command, args []string) error {
    59  			ctx := client.NewCoreContextFromViper().WithTxEncoder(linotypes.TxEncoder(cdc))
    60  			referrer, err := parseAccOrAddr(args[0])
    61  			if err != nil {
    62  				return err
    63  			}
    64  			amount := viper.GetString(FlagRegFee)
    65  			username := linotypes.AccountKey(viper.GetString(FlagName))
    66  
    67  			txPriv := secp256k1.GenPrivKey()
    68  			signPriv := secp256k1.GenPrivKey()
    69  
    70  			fmt.Println(
    71  				"tx private hex-encoded:",
    72  				strings.ToUpper(hex.EncodeToString(txPriv.Bytes())))
    73  			fmt.Println(
    74  				"signing private key hex-encoded:",
    75  				strings.ToUpper(hex.EncodeToString(signPriv.Bytes())))
    76  			msg := types.RegisterV2Msg{
    77  				Referrer:             referrer,
    78  				NewUser:              username,
    79  				RegisterFee:          amount,
    80  				NewTransactionPubKey: txPriv.PubKey(),
    81  				NewSigningPubKey:     signPriv.PubKey(),
    82  			}
    83  			return ctx.DoTxPrintResponse(msg, client.OptionalSigner{
    84  				PrivKey: txPriv,
    85  				Seq:     0,
    86  			})
    87  		},
    88  	}
    89  	cmd.Flags().String(FlagRegFee, "", "amount of register fee")
    90  	cmd.Flags().String(FlagName, "", "name of new user")
    91  	_ = cmd.MarkFlagRequired(FlagRegFee)
    92  	_ = cmd.MarkFlagRequired(FlagName)
    93  	return cmd
    94  }
    95  
    96  // getCmdBind - bind username to an address.
    97  func getCmdBind(cdc *codec.Codec) *cobra.Command {
    98  	cmd := &cobra.Command{
    99  		Use:   "bind <type:referrer>",
   100  		Short: "bind <type:referrer> --addr <addr> --addr-priv-key <key> --addr-seq <seq> --name <name> --reg-fee <amount>",
   101  		Long:  "bind <type:referrer> --addr <addr> --addr-priv-key <key> --addr-seq <seq> --name <name> --reg-fee <amount> will bind <addr> with <name> as username. The signing key will be the same as transaction key.",
   102  		Args:  cobra.ExactArgs(1),
   103  		RunE: func(cmd *cobra.Command, args []string) error {
   104  			ctx := client.NewCoreContextFromViper().WithTxEncoder(linotypes.TxEncoder(cdc))
   105  			referrer, err := parseAccOrAddr(args[0])
   106  			if err != nil {
   107  				return err
   108  			}
   109  			amount := viper.GetString(FlagRegFee)
   110  			username := linotypes.AccountKey(viper.GetString(FlagName))
   111  			addr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddr))
   112  			if err != nil {
   113  				return err
   114  			}
   115  			addrPriv, err := client.ParsePrivKey(viper.GetString(FlagAddrPrivKey))
   116  			if err != nil {
   117  				return err
   118  			}
   119  			addrSeq, err := strconv.ParseInt(viper.GetString(FlagAddrSeq), 10, 64)
   120  			if err != nil {
   121  				return err
   122  			}
   123  
   124  			if addr.String() != sdk.AccAddress(addrPriv.PubKey().Address()).String() {
   125  				return fmt.Errorf("address and priv-key mismatch, priv-key's addr: %s",
   126  					sdk.AccAddress(addrPriv.PubKey().Address()))
   127  			}
   128  
   129  			msg := types.RegisterV2Msg{
   130  				Referrer:             referrer,
   131  				NewUser:              username,
   132  				RegisterFee:          amount,
   133  				NewTransactionPubKey: addrPriv.PubKey(),
   134  				NewSigningPubKey:     addrPriv.PubKey(),
   135  			}
   136  			return ctx.DoTxPrintResponse(msg, client.OptionalSigner{
   137  				PrivKey: addrPriv,
   138  				Seq:     uint64(addrSeq),
   139  			})
   140  		},
   141  	}
   142  
   143  	cmd.Flags().String(FlagAddr, "", "address to be binded with the name")
   144  	cmd.Flags().String(FlagAddrPrivKey, "", "private hex of the address")
   145  	cmd.Flags().String(FlagAddrSeq, "", "sequence # of the address")
   146  	cmd.Flags().String(FlagRegFee, "", "amount of register fee")
   147  	cmd.Flags().String(FlagName, "", "name of new user")
   148  	_ = cmd.MarkFlagRequired(FlagAddr)
   149  	_ = cmd.MarkFlagRequired(FlagAddrPrivKey)
   150  	_ = cmd.MarkFlagRequired(FlagAddrSeq)
   151  	_ = cmd.MarkFlagRequired(FlagRegFee)
   152  	_ = cmd.MarkFlagRequired(FlagName)
   153  	return cmd
   154  }
   155  
   156  // GetCmdTransferV2 -
   157  func getCmdTransferV2(cdc *codec.Codec) *cobra.Command {
   158  	cmd := &cobra.Command{
   159  		Use:   "transfer",
   160  		Short: "transfer <type:from> --to <type:to> --amount <amount> --memo memo, See help for type",
   161  		Long:  "type is either 'addr' or 'user', e.g. transfer addr:lino158de3... --to user:yxia --amount 10 --memo 'demo'",
   162  		Args:  cobra.ExactArgs(1),
   163  		RunE: func(cmd *cobra.Command, args []string) error {
   164  			ctx := client.NewCoreContextFromViper().WithTxEncoder(linotypes.TxEncoder(cdc))
   165  			from, err := parseAccOrAddr(args[0])
   166  			if err != nil {
   167  				return err
   168  			}
   169  			to, err := parseAccOrAddr(viper.GetString(FlagTo))
   170  			if err != nil {
   171  				return err
   172  			}
   173  			amount := viper.GetString(FlagAmount)
   174  			memo := viper.GetString(FlagMemo)
   175  			msg := types.TransferV2Msg{
   176  				Sender:   from,
   177  				Receiver: to,
   178  				Amount:   amount,
   179  				Memo:     memo,
   180  			}
   181  			return ctx.DoTxPrintResponse(msg)
   182  		},
   183  	}
   184  	cmd.Flags().String(FlagTo, "", "receiver username")
   185  	cmd.Flags().String(FlagAmount, "", "amount to transfer")
   186  	cmd.Flags().String(FlagMemo, "", "memo msg")
   187  	_ = cmd.MarkFlagRequired(FlagTo)
   188  	_ = cmd.MarkFlagRequired(FlagAmount)
   189  	return cmd
   190  }
   191  
   192  // getCmdRecover -
   193  func getCmdRecover(cdc *codec.Codec) *cobra.Command {
   194  	cmd := &cobra.Command{
   195  		Use:   "recover",
   196  		Short: "recover <username> --new-tx-priv <new-priv-key> --new-sign-pub <pubkey-hex>",
   197  		Long:  "recover <username> --new-tx-priv <new-priv-key> --new-sign-pub <pubkey-hex>",
   198  		Args:  cobra.ExactArgs(1),
   199  		RunE: func(cmd *cobra.Command, args []string) error {
   200  			ctx := client.NewCoreContextFromViper().WithTxEncoder(linotypes.TxEncoder(cdc))
   201  			user := args[0]
   202  			if !linotypes.AccountKey(user).IsValid() {
   203  				return fmt.Errorf("invalid username: %s", user)
   204  			}
   205  
   206  			txPrivKey, err := client.ParsePrivKey(viper.GetString(FlagNewTxKey))
   207  			if err != nil {
   208  				return fmt.Errorf("invalid new tx key: %s", err)
   209  			}
   210  
   211  			signPubKey, err := client.ParsePubKey(viper.GetString(FlagNewSignKey))
   212  			if err != nil {
   213  				return fmt.Errorf("invalid new sign key: %s", err)
   214  			}
   215  
   216  			msg := types.NewRecoverMsg(user, txPrivKey.PubKey(), signPubKey)
   217  			return ctx.DoTxPrintResponse(msg, client.OptionalSigner{
   218  				PrivKey: txPrivKey,
   219  				Seq:     0,
   220  			})
   221  		},
   222  	}
   223  	cmd.Flags().String(FlagNewTxKey, "", "new transaction private key")
   224  	cmd.Flags().String(FlagNewSignKey, "", "new signing key")
   225  	_ = cmd.MarkFlagRequired(FlagNewTxKey)
   226  	_ = cmd.MarkFlagRequired(FlagNewSignKey)
   227  	return cmd
   228  }
   229  
   230  func parseAccOrAddr(s string) (rst linotypes.AccOrAddr, err error) {
   231  	comps := strings.Split(s, ":")
   232  	if len(comps) != 2 || !(comps[0] == "addr" || comps[0] == "user") {
   233  		return rst, fmt.Errorf("invalid param: %s", s)
   234  	}
   235  	if comps[0] == "addr" {
   236  		addr, err := sdk.AccAddressFromBech32(comps[1])
   237  		if err != nil {
   238  			return rst, err
   239  		}
   240  		return linotypes.NewAccOrAddrFromAddr(addr), nil
   241  	} else {
   242  		return linotypes.NewAccOrAddrFromAcc(linotypes.AccountKey(comps[1])), nil
   243  	}
   244  }