github.com/aeternity/aepp-sdk-go/v6@v6.0.0/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/v6/account"
    24  	"github.com/aeternity/aepp-sdk-go/v6/config"
    25  	"github.com/aeternity/aepp-sdk-go/v6/naet"
    26  	"github.com/aeternity/aepp-sdk-go/v6/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  	txSignedBase64, txHash, signature, err := transactions.SignHashTx(account, tx, config.Node.NetworkID)
   178  	if err != nil {
   179  		return err
   180  	}
   181  
   182  	Pp(
   183  		"Signing account address", account.Address,
   184  		"Signature", signature,
   185  		"Unsigned", txUnsignedBase64,
   186  		"Signed", txSignedBase64,
   187  		"Hash", txHash,
   188  	)
   189  	return nil
   190  }
   191  
   192  // saveCmd implements the account save subcommand
   193  var saveCmd = &cobra.Command{
   194  	Use:   "save ACCOUNT_KEYSTORE ACCOUNT_HEX_STRING",
   195  	Short: "Save an account from a hex string to a keystore file",
   196  	Long:  ``,
   197  	Args:  cobra.ExactArgs(2),
   198  	RunE:  saveFunc,
   199  }
   200  
   201  func saveFunc(cmd *cobra.Command, args []string) (err error) {
   202  	accountFileName := args[0]
   203  	acc, err := account.FromHexString(args[1])
   204  	if err != nil {
   205  		return err
   206  	}
   207  
   208  	p, err := getPassword()
   209  
   210  	f, err := account.StoreToKeyStoreFile(acc, p, accountFileName)
   211  	if err != nil {
   212  		return err
   213  	}
   214  
   215  	Pp("Keystore path ", f)
   216  
   217  	return nil
   218  }
   219  
   220  var vanityCmd = &cobra.Command{
   221  	Use:   "vanity",
   222  	Short: "Find an account that starts with or contains the user-specified text",
   223  	Long:  ``,
   224  	Args:  cobra.MinimumNArgs(1),
   225  	Run:   vanityFunc,
   226  }
   227  
   228  func vanityFunc(cmd *cobra.Command, args []string) {
   229  	var searchString string
   230  	if regex {
   231  		searchString = args[0]
   232  	} else {
   233  		searchString = fmt.Sprintf("^%s", args[0])
   234  	}
   235  	r, err := regexp.Compile(searchString)
   236  	if err != nil {
   237  		fmt.Println("Ouch! The search input ", searchString, "is not a valid regexp")
   238  		return
   239  	}
   240  	fmt.Println("The search for your account matching", searchString, "has begun")
   241  
   242  	var wg sync.WaitGroup
   243  	wg.Add(runtime.NumCPU())
   244  	for i := 0; i < runtime.NumCPU(); i++ {
   245  		go func() {
   246  			for {
   247  				a, _ := account.New()
   248  
   249  				if r.MatchString(a.Address[3:]) {
   250  					fmt.Println("FOUND!")
   251  					fmt.Println("Secret: ", a.SigningKeyToHexString())
   252  					fmt.Println("Address", a.Address)
   253  				}
   254  			}
   255  		}()
   256  	}
   257  	wg.Wait()
   258  
   259  }
   260  
   261  func init() {
   262  	RootCmd.AddCommand(accountCmd)
   263  	accountCmd.AddCommand(addressCmd)
   264  	accountCmd.AddCommand(createCmd)
   265  	accountCmd.AddCommand(saveCmd)
   266  	accountCmd.AddCommand(balanceCmd)
   267  	accountCmd.AddCommand(signCmd)
   268  	accountCmd.AddCommand(vanityCmd)
   269  	accountCmd.PersistentFlags().StringVar(&password, "password", "", "Read account password from stdin [WARN: this method is not secure]")
   270  	// account address flags
   271  	addressCmd.Flags().BoolVar(&printPrivateKey, "private-key", false, "Print the private key as hex string")
   272  	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")
   273  }