github.com/aeternity/aepp-sdk-go/v7@v7.0.1/cmd/account.go (about) 1 // Copyright © 2018 NAME HERE <EMAIL ADDRESS> 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package cmd 16 17 import ( 18 "fmt" 19 "regexp" 20 "runtime" 21 "sync" 22 23 "github.com/aeternity/aepp-sdk-go/v7/account" 24 "github.com/aeternity/aepp-sdk-go/v7/config" 25 "github.com/aeternity/aepp-sdk-go/v7/naet" 26 "github.com/aeternity/aepp-sdk-go/v7/transactions" 27 28 "github.com/spf13/cobra" 29 ) 30 31 var ( 32 waitForTx bool 33 spendTxPayload string 34 printPrivateKey bool 35 accountFileName string 36 password string 37 fee string // leave it as a string because viper cannot parse it directly into a BigInt 38 ttl uint64 39 nonce uint64 40 regex bool 41 ) 42 43 // accountCmd implements the account command 44 var accountCmd = &cobra.Command{ 45 Use: "account PRIVATE_KEY_PATH", 46 Short: "Interact with a account", 47 Long: ``, 48 } 49 50 // addressCmd implements the account address subcommand 51 var addressCmd = &cobra.Command{ 52 Use: "address ACCOUNT_KEYSTORE", 53 Short: "Print the aeternity account address", 54 Long: ``, 55 Args: cobra.ExactArgs(1), 56 RunE: addressFunc, 57 } 58 59 func getPassword() (p string, err error) { 60 if len(password) != 0 { 61 return password, nil 62 } 63 p, err = AskPassword("Enter the password to unlock the keystore: ") 64 if err != nil { 65 return "", err 66 } 67 return p, nil 68 } 69 70 func addressFunc(cmd *cobra.Command, args []string) error { 71 p, err := getPassword() 72 if err != nil { 73 return err 74 } 75 76 // load the account 77 account, err := account.LoadFromKeyStoreFile(args[0], p) 78 if err != nil { 79 return err 80 } 81 82 Pp("Account address", account.Address) 83 if printPrivateKey { 84 if AskYes("Are you sure you want to print your private key? This could be insecure.", false) { 85 Pp("Account private key", account.SigningKeyToHexString()) 86 } 87 } 88 89 return nil 90 } 91 92 // createCmd implements the account generate subcommand 93 var createCmd = &cobra.Command{ 94 Use: "create ACCOUNT_KEYSTORE", 95 Short: "Create a new account", 96 Long: ``, 97 Args: cobra.ExactArgs(1), 98 RunE: createFunc, 99 } 100 101 func createFunc(cmd *cobra.Command, args []string) (err error) { 102 acc, _ := account.New() 103 p, err := getPassword() 104 if err != nil { 105 return err 106 } 107 accountFileName = args[0] 108 109 // check if a name was given 110 f, err := account.StoreToKeyStoreFile(acc, p, accountFileName) 111 if err != nil { 112 return err 113 } 114 115 Pp( 116 "Wallet path", f, 117 "Account address", acc.Address, 118 ) 119 120 return nil 121 } 122 123 // balanceCmd implements the account balance subcommand 124 var balanceCmd = &cobra.Command{ 125 Use: "balance ACCOUNT_KEYSTORE", 126 Short: "Get the balance of an account", 127 Long: ``, 128 Args: cobra.ExactArgs(1), 129 RunE: func(cmd *cobra.Command, args []string) error { 130 node := newAeNode() 131 return balanceFunc(node, args) 132 }, 133 } 134 135 func balanceFunc(conn naet.GetAccounter, args []string) (err error) { 136 p, err := getPassword() 137 138 // load the account 139 account, err := account.LoadFromKeyStoreFile(args[0], p) 140 if err != nil { 141 return err 142 } 143 144 a, err := conn.GetAccount(account.Address) 145 if err != nil { 146 return err 147 } 148 149 PrintObject("account", a) 150 return nil 151 } 152 153 // signCmd implements the account sign subcommand 154 var signCmd = &cobra.Command{ 155 Use: "sign ACCOUNT_KEYSTORE UNSIGNED_TRANSACTION", 156 Short: "Sign the input (e.g. a transaction)", 157 Long: ``, 158 Args: cobra.ExactArgs(2), 159 RunE: signFunc, 160 } 161 162 func signFunc(cmd *cobra.Command, args []string) (err error) { 163 p, err := getPassword() 164 165 // load the account 166 account, err := account.LoadFromKeyStoreFile(args[0], p) 167 if err != nil { 168 return err 169 } 170 171 txUnsignedBase64 := args[1] 172 tx, err := transactions.DeserializeTxStr(txUnsignedBase64) 173 if err != nil { 174 return err 175 } 176 177 txSigned, txHash, signature, err := transactions.SignHashTx(account, tx, config.Node.NetworkID) 178 if err != nil { 179 return err 180 } 181 txSignedB64, err := transactions.SerializeTx(txSigned) 182 if err != nil { 183 return err 184 } 185 186 Pp( 187 "Signing account address", account.Address, 188 "Signature", signature, 189 "Unsigned", txUnsignedBase64, 190 "Signed", txSignedB64, 191 "Hash", txHash, 192 ) 193 return nil 194 } 195 196 // saveCmd implements the account save subcommand 197 var saveCmd = &cobra.Command{ 198 Use: "save ACCOUNT_KEYSTORE ACCOUNT_HEX_STRING", 199 Short: "Save an account from a hex string to a keystore file", 200 Long: ``, 201 Args: cobra.ExactArgs(2), 202 RunE: saveFunc, 203 } 204 205 func saveFunc(cmd *cobra.Command, args []string) (err error) { 206 accountFileName := args[0] 207 acc, err := account.FromHexString(args[1]) 208 if err != nil { 209 return err 210 } 211 212 p, err := getPassword() 213 214 f, err := account.StoreToKeyStoreFile(acc, p, accountFileName) 215 if err != nil { 216 return err 217 } 218 219 Pp("Keystore path ", f) 220 221 return nil 222 } 223 224 var vanityCmd = &cobra.Command{ 225 Use: "vanity", 226 Short: "Find an account that starts with or contains the user-specified text", 227 Long: ``, 228 Args: cobra.MinimumNArgs(1), 229 Run: vanityFunc, 230 } 231 232 func vanityFunc(cmd *cobra.Command, args []string) { 233 var searchString string 234 if regex { 235 searchString = args[0] 236 } else { 237 searchString = fmt.Sprintf("^%s", args[0]) 238 } 239 r, err := regexp.Compile(searchString) 240 if err != nil { 241 fmt.Println("Ouch! The search input ", searchString, "is not a valid regexp") 242 return 243 } 244 fmt.Println("The search for your account matching", searchString, "has begun") 245 246 foundAccounts := make(chan *account.Account, 5) 247 var wg sync.WaitGroup 248 wg.Add(runtime.NumCPU()) 249 for i := 0; i < runtime.NumCPU(); i++ { 250 go func() { 251 for { 252 a, _ := account.New() 253 if r.MatchString(a.Address[3:]) { 254 foundAccounts <- a 255 } 256 } 257 }() 258 } 259 for a := range foundAccounts { 260 fmt.Printf("Found account! %s \n", a.Address) 261 filename := fmt.Sprintf("account.%s.json", a.Address) 262 yes := AskYes(fmt.Sprintf("Save it to %s?", filename), false) 263 if yes { 264 pw, err := AskPassword("To encrypt the keystore, please provide a password") 265 if err != nil { 266 fmt.Println(err) 267 } 268 269 path, err := account.StoreToKeyStoreFile(a, pw, filename) 270 if err != nil { 271 fmt.Println(err) 272 } 273 fmt.Println("Account saved in", path) 274 275 continueSearch := AskYes("Would you like to continue searching?", false) 276 if !continueSearch { 277 return 278 } 279 } 280 } 281 wg.Wait() 282 } 283 284 func init() { 285 RootCmd.AddCommand(accountCmd) 286 accountCmd.AddCommand(addressCmd) 287 accountCmd.AddCommand(createCmd) 288 accountCmd.AddCommand(saveCmd) 289 accountCmd.AddCommand(balanceCmd) 290 accountCmd.AddCommand(signCmd) 291 accountCmd.AddCommand(vanityCmd) 292 accountCmd.PersistentFlags().StringVar(&password, "password", "", "Read account password from stdin [WARN: this method is not secure]") 293 // account address flags 294 addressCmd.Flags().BoolVar(&printPrivateKey, "private-key", false, "Print the private key as hex string") 295 vanityCmd.Flags().BoolVar(®ex, "regex", false, "Search using a regular expression that can match anywhere within the address instead of a string that matches at the beginning") 296 }