github.com/aeternity/aepp-sdk-go@v1.0.3-0.20190606142815-1c0ffdc21fd9/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/aeternity"
    24  
    25  	"github.com/spf13/cobra"
    26  )
    27  
    28  var (
    29  	waitForTx       bool
    30  	spendTxPayload  string
    31  	printPrivateKey bool
    32  	accountFileName string
    33  	password        string
    34  	fee             string // leave it as a string because viper cannot parse it directly into a BigInt
    35  	ttl             uint64
    36  	nonce           uint64
    37  	regex           bool
    38  )
    39  
    40  // accountCmd implements the account command
    41  var accountCmd = &cobra.Command{
    42  	Use:   "account PRIVATE_KEY_PATH",
    43  	Short: "Interact with a account",
    44  	Long:  ``,
    45  }
    46  
    47  // addressCmd implements the account address subcommand
    48  var addressCmd = &cobra.Command{
    49  	Use:   "address ACCOUNT_KEYSTORE",
    50  	Short: "Print the aeternity account address",
    51  	Long:  ``,
    52  	Args:  cobra.ExactArgs(1),
    53  	RunE:  addressFunc,
    54  }
    55  
    56  func getPassword() (p string, err error) {
    57  	if len(password) != 0 {
    58  		return password, nil
    59  	}
    60  	p, err = AskPassword("Enter the password to unlock the keystore: ")
    61  	if err != nil {
    62  		return "", err
    63  	}
    64  	return p, nil
    65  }
    66  
    67  func addressFunc(cmd *cobra.Command, args []string) error {
    68  	p, err := getPassword()
    69  	if err != nil {
    70  		return err
    71  	}
    72  
    73  	// load the account
    74  	account, err := aeternity.LoadAccountFromKeyStoreFile(args[0], p)
    75  	if err != nil {
    76  		return err
    77  	}
    78  
    79  	aeternity.Pp("Account address", account.Address)
    80  	if printPrivateKey {
    81  		if AskYes("Are you sure you want to print your private key? This could be insecure.", false) {
    82  			aeternity.Pp("Account private key", account.SigningKeyToHexString())
    83  		}
    84  	}
    85  
    86  	return nil
    87  }
    88  
    89  // createCmd implements the account generate subcommand
    90  var createCmd = &cobra.Command{
    91  	Use:   "create ACCOUNT_KEYSTORE",
    92  	Short: "Create a new account",
    93  	Long:  ``,
    94  	Args:  cobra.ExactArgs(1),
    95  	RunE:  createFunc,
    96  }
    97  
    98  func createFunc(cmd *cobra.Command, args []string) (err error) {
    99  	account, _ := aeternity.NewAccount()
   100  	p, err := getPassword()
   101  	if err != nil {
   102  		return err
   103  	}
   104  	accountFileName = args[0]
   105  
   106  	// check if a name was given
   107  	f, err := aeternity.StoreAccountToKeyStoreFile(account, p, accountFileName)
   108  	if err != nil {
   109  		return err
   110  	}
   111  
   112  	aeternity.Pp(
   113  		"Wallet path", f,
   114  		"Account address", account.Address,
   115  	)
   116  
   117  	return nil
   118  }
   119  
   120  // balanceCmd implements the account balance subcommand
   121  var balanceCmd = &cobra.Command{
   122  	Use:   "balance ACCOUNT_KEYSTORE",
   123  	Short: "Get the balance of an account",
   124  	Long:  ``,
   125  	Args:  cobra.ExactArgs(1),
   126  	RunE:  balanceFunc,
   127  }
   128  
   129  func balanceFunc(cmd *cobra.Command, args []string) (err error) {
   130  	aeCli := NewAeCli()
   131  	p, err := getPassword()
   132  
   133  	// load the account
   134  	account, err := aeternity.LoadAccountFromKeyStoreFile(args[0], p)
   135  	if err != nil {
   136  		return err
   137  	}
   138  
   139  	a, err := aeCli.APIGetAccount(account.Address)
   140  	if err != nil {
   141  		return err
   142  	}
   143  
   144  	aeternity.PrintObject("account", a)
   145  	return nil
   146  }
   147  
   148  // signCmd implements the account sign subcommand
   149  var signCmd = &cobra.Command{
   150  	Use:   "sign ACCOUNT_KEYSTORE UNSIGNED_TRANSACTION",
   151  	Short: "Sign the input (e.g. a transaction)",
   152  	Long:  ``,
   153  	Args:  cobra.ExactArgs(2),
   154  	RunE:  signFunc,
   155  }
   156  
   157  func signFunc(cmd *cobra.Command, args []string) (err error) {
   158  	p, err := getPassword()
   159  
   160  	// load the account
   161  	account, err := aeternity.LoadAccountFromKeyStoreFile(args[0], p)
   162  	if err != nil {
   163  		return err
   164  	}
   165  
   166  	txUnsignedBase64 := args[1]
   167  	txSignedBase64, txHash, signature, err := aeternity.SignEncodeTxStr(account, txUnsignedBase64, aeternity.Config.Node.NetworkID)
   168  	if err != nil {
   169  		return err
   170  	}
   171  
   172  	aeternity.Pp(
   173  		"Signing account address", account.Address,
   174  		"Signature", signature,
   175  		"Unsigned", txUnsignedBase64,
   176  		"Signed", txSignedBase64,
   177  		"Hash", txHash,
   178  	)
   179  	return nil
   180  }
   181  
   182  // saveCmd implements the account save subcommand
   183  var saveCmd = &cobra.Command{
   184  	Use:   "save ACCOUNT_KEYSTORE ACCOUNT_HEX_STRING",
   185  	Short: "Save an account from a hex string to a keystore file",
   186  	Long:  ``,
   187  	Args:  cobra.ExactArgs(2),
   188  	RunE:  saveFunc,
   189  }
   190  
   191  func saveFunc(cmd *cobra.Command, args []string) (err error) {
   192  	accountFileName := args[0]
   193  	account, err := aeternity.AccountFromHexString(args[1])
   194  	if err != nil {
   195  		return err
   196  	}
   197  
   198  	p, err := getPassword()
   199  
   200  	f, err := aeternity.StoreAccountToKeyStoreFile(account, p, accountFileName)
   201  	if err != nil {
   202  		return err
   203  	}
   204  
   205  	aeternity.Pp("Keystore path ", f)
   206  
   207  	return nil
   208  }
   209  
   210  var vanityCmd = &cobra.Command{
   211  	Use:   "vanity",
   212  	Short: "Find an account that starts with or contains the user-specified text",
   213  	Long:  ``,
   214  	Args:  cobra.MinimumNArgs(1),
   215  	Run:   vanityFunc,
   216  }
   217  
   218  func vanityFunc(cmd *cobra.Command, args []string) {
   219  	var searchString string
   220  	if regex {
   221  		searchString = args[0]
   222  	} else {
   223  		searchString = fmt.Sprintf("^%s", args[0])
   224  	}
   225  	r, err := regexp.Compile(searchString)
   226  	if err != nil {
   227  		fmt.Println("Ouch! The search input ", searchString, "is not a valid regexp")
   228  		return
   229  	}
   230  	fmt.Println("The search for your account matching", searchString, "has begun")
   231  
   232  	var wg sync.WaitGroup
   233  	wg.Add(runtime.NumCPU())
   234  	for i := 0; i < runtime.NumCPU(); i++ {
   235  		go func() {
   236  			for {
   237  				a, _ := aeternity.NewAccount()
   238  
   239  				if r.MatchString(a.Address[3:]) {
   240  					fmt.Println("FOUND!")
   241  					fmt.Println("Secret: ", a.SigningKeyToHexString())
   242  					fmt.Println("Address", a.Address)
   243  				}
   244  			}
   245  		}()
   246  	}
   247  	wg.Wait()
   248  
   249  }
   250  
   251  func init() {
   252  	RootCmd.AddCommand(accountCmd)
   253  	accountCmd.AddCommand(addressCmd)
   254  	accountCmd.AddCommand(createCmd)
   255  	accountCmd.AddCommand(saveCmd)
   256  	accountCmd.AddCommand(balanceCmd)
   257  	accountCmd.AddCommand(signCmd)
   258  	accountCmd.AddCommand(vanityCmd)
   259  	accountCmd.PersistentFlags().StringVar(&password, "password", "", "Read account password from stdin [WARN: this method is not secure]")
   260  	// account address flags
   261  	addressCmd.Flags().BoolVar(&printPrivateKey, "private-key", false, "Print the private key as hex string")
   262  	vanityCmd.Flags().BoolVar(&regex, "regex", false, "Search using a regular expression that can match anywhere within the address instead of a string that matches at the beginning")
   263  }