github.com/iotexproject/iotex-core@v1.14.1-rc1/ioctl/newcmd/hdwallet/hdwalletderive.go (about)

     1  // Copyright (c) 2022 IoTeX Foundation
     2  // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
     3  // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
     4  // This source code is governed by Apache License 2.0 that can be found in the LICENSE file.
     5  
     6  package hdwallet
     7  
     8  import (
     9  	"fmt"
    10  
    11  	ecrypt "github.com/ethereum/go-ethereum/crypto"
    12  	"github.com/iotexproject/go-pkgs/crypto"
    13  	hdwallet "github.com/miguelmota/go-ethereum-hdwallet"
    14  	"github.com/pkg/errors"
    15  	"github.com/spf13/cobra"
    16  
    17  	"github.com/iotexproject/iotex-core/ioctl"
    18  	"github.com/iotexproject/iotex-core/ioctl/config"
    19  	"github.com/iotexproject/iotex-core/ioctl/util"
    20  )
    21  
    22  // Multi-language support
    23  var (
    24  	_hdwalletDeriveCmdShorts = map[config.Language]string{
    25  		config.English: "derive key from HDWallet",
    26  		config.Chinese: "查询HDWallet钱包的派生key地址",
    27  	}
    28  )
    29  
    30  // NewHdwalletDeriveCmd represents the hdwallet derive command
    31  func NewHdwalletDeriveCmd(client ioctl.Client) *cobra.Command {
    32  	short, _ := client.SelectTranslation(_hdwalletDeriveCmdShorts)
    33  
    34  	return &cobra.Command{
    35  		Use:   "derive id1/id2/id3",
    36  		Short: short,
    37  		Args:  cobra.ExactArgs(1),
    38  		RunE: func(cmd *cobra.Command, args []string) error {
    39  			cmd.SilenceUsage = true
    40  			signer := "hdw::" + args[0]
    41  			account, change, index, err := util.ParseHdwPath(signer)
    42  			if err != nil {
    43  				return errors.Wrap(err, "invalid hdwallet key format")
    44  			}
    45  
    46  			cmd.Println("Enter password:")
    47  			password, err := client.ReadSecret()
    48  			if err != nil {
    49  				return errors.Wrap(err, "failed to get password")
    50  			}
    51  
    52  			addr, _, err := DeriveKey(client, account, change, index, password)
    53  			if err != nil {
    54  				return err
    55  			}
    56  			cmd.Printf("address: %s\n", addr)
    57  			return nil
    58  		},
    59  	}
    60  }
    61  
    62  // DeriveKey derives the key according to path
    63  func DeriveKey(client ioctl.Client, account, change, index uint32, password string) (string, crypto.PrivateKey, error) {
    64  	mnemonic, err := client.HdwalletMnemonic(password)
    65  	if err != nil {
    66  		return "", nil, err
    67  	}
    68  	wallet, err := hdwallet.NewFromMnemonic(mnemonic)
    69  	if err != nil {
    70  		return "", nil, err
    71  	}
    72  
    73  	derivationPath := fmt.Sprintf("%s/%d'/%d/%d", DefaultRootDerivationPath, account, change, index)
    74  	path := hdwallet.MustParseDerivationPath(derivationPath)
    75  	walletAccount, err := wallet.Derive(path, false)
    76  	if err != nil {
    77  		return "", nil, errors.Wrap(err, "failed to get account by derive path")
    78  	}
    79  
    80  	private, err := wallet.PrivateKey(walletAccount)
    81  	if err != nil {
    82  		return "", nil, errors.Wrap(err, "failed to get private key")
    83  	}
    84  	prvKey, err := crypto.BytesToPrivateKey(ecrypt.FromECDSA(private))
    85  	if err != nil {
    86  		return "", nil, errors.Wrap(err, "failed to Bytes private key")
    87  	}
    88  
    89  	addr := prvKey.PublicKey().Address()
    90  	if addr == nil {
    91  		return "", nil, errors.Wrap(err, "failed to convert public key into address")
    92  	}
    93  	return addr.String(), prvKey, nil
    94  }