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 }