diff --git a/ioctl/newcmd/hdwallet/hdwalletcreate.go b/ioctl/newcmd/hdwallet/hdwalletcreate.go new file mode 100644 index 0000000000..3c700bd753 --- /dev/null +++ b/ioctl/newcmd/hdwallet/hdwalletcreate.go @@ -0,0 +1,77 @@ +// Copyright (c) 2022 IoTeX Foundation +// This is an alpha (internal) release and is not suitable for production. This source code is provided 'as is' and no +// warranties are given as to title or non-infringement, merchantability or fitness for purpose and, to the extent +// permitted by law, all liability for your use of the code is disclaimed. This source code is governed by Apache +// License 2.0 that can be found in the LICENSE file. + +package hdwallet + +import ( + "github.com/pkg/errors" + "github.com/spf13/cobra" + "github.com/tyler-smith/go-bip39" + + "github.com/iotexproject/iotex-core/ioctl" + "github.com/iotexproject/iotex-core/ioctl/config" +) + +// Multi-language support +var ( + _createByMnemonicCmdShorts = map[config.Language]string{ + config.English: "create hdwallet using mnemonic", + config.Chinese: "通过助记词创建新钱包", + } + _createByMnemonicCmdUses = map[config.Language]string{ + config.English: "create", + config.Chinese: "create 创建", + } +) + +// NewHdwalletCreateCmd represents the hdwallet create command +func NewHdwalletCreateCmd(client ioctl.Client) *cobra.Command { + use, _ := client.SelectTranslation(_createByMnemonicCmdUses) + short, _ := client.SelectTranslation(_createByMnemonicCmdShorts) + + return &cobra.Command{ + Use: use, + Short: short, + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + cmd.SilenceUsage = true + if client.IsHdWalletConfigFileExist() { + cmd.Println("Please run 'ioctl hdwallet delete' before import") + return nil + } + cmd.Println("Set password") + password, err := client.ReadSecret() + if err != nil { + return errors.Wrap(err, "failed to get password") + } + cmd.Println("Enter password again") + passwordAgain, err := client.ReadSecret() + if err != nil { + return errors.Wrap(err, "failed to get password") + } + if password != passwordAgain { + return ErrPasswdNotMatch + } + + entropy, err := bip39.NewEntropy(128) + if err != nil { + return err + } + mnemonic, err := bip39.NewMnemonic(entropy) + if err != nil { + return err + } + + if err = client.WriteHdWalletConfigFile(mnemonic, password); err != nil { + return err + } + + cmd.Printf("Mnemonic phrase: %s\n"+ + "It is used to recover your wallet in case you forgot the password. Write them down and store it in a safe place.\n", mnemonic) + return nil + }, + } +} diff --git a/ioctl/newcmd/hdwallet/hdwalletcreate_test.go b/ioctl/newcmd/hdwallet/hdwalletcreate_test.go new file mode 100644 index 0000000000..0647ed2719 --- /dev/null +++ b/ioctl/newcmd/hdwallet/hdwalletcreate_test.go @@ -0,0 +1,58 @@ +// Copyright (c) 2022 IoTeX Foundation +// This is an alpha (internal) release and is not suitable for production. This source code is provided 'as is' and no +// warranties are given as to title or non-infringement, merchantability or fitness for purpose and, to the extent +// permitted by law, all liability for your use of the code is disclaimed. This source code is governed by Apache +// License 2.0 that can be found in the LICENSE file. + +package hdwallet + +import ( + "testing" + + "github.com/golang/mock/gomock" + "github.com/pkg/errors" + "github.com/stretchr/testify/require" + + "github.com/iotexproject/iotex-core/ioctl/config" + "github.com/iotexproject/iotex-core/ioctl/util" + "github.com/iotexproject/iotex-core/test/mock/mock_ioctlclient" +) + +func TestNewHdwalletCreateCmd(t *testing.T) { + require := require.New(t) + ctrl := gomock.NewController(t) + client := mock_ioctlclient.NewMockClient(ctrl) + password := "123" + + client.EXPECT().SelectTranslation(gomock.Any()).Return("mockTranslationString", config.English).Times(9) + client.EXPECT().IsHdWalletConfigFileExist().Return(false).Times(3) + + t.Run("create hdwallet", func(t *testing.T) { + client.EXPECT().ReadSecret().Return(password, nil).Times(2) + client.EXPECT().WriteHdWalletConfigFile(gomock.Any(), gomock.Any()).Return(nil) + + cmd := NewHdwalletCreateCmd(client) + result, err := util.ExecuteCmd(cmd) + require.NoError(err) + require.Contains(result, "It is used to recover your wallet in case you forgot the password. Write them down and store it in a safe place.") + }) + + t.Run("failed to get password", func(t *testing.T) { + expectedErr := errors.New("failed to get password") + client.EXPECT().ReadSecret().Return("", expectedErr) + + cmd := NewHdwalletCreateCmd(client) + _, err := util.ExecuteCmd(cmd) + require.Contains(err.Error(), expectedErr.Error()) + }) + + t.Run("password not match", func(t *testing.T) { + expectedErr := errors.New("password doesn't match") + client.EXPECT().ReadSecret().Return(password, nil) + client.EXPECT().ReadSecret().Return("test", nil) + + cmd := NewHdwalletCreateCmd(client) + _, err := util.ExecuteCmd(cmd) + require.Equal(err.Error(), expectedErr.Error()) + }) +}