From d6428f73353e2cf82e502e8f56662490032b0dc1 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 18 Jun 2024 11:01:32 +0200 Subject: [PATCH] feat(client): Add flag & reading mnemonic from file (backport #20690) (#20712) Co-authored-by: Hieu Vu <72878483+hieuvubk@users.noreply.github.com> Co-authored-by: marbar3778 --- CHANGELOG.md | 4 ++++ client/keys/add.go | 52 ++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 292aa1524e13..b061e87d52a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,10 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## [Unreleased] +## Features + +* (client) [#20690](https://github.com/cosmos/cosmos-sdk/pull/20690) Import mnemonic from file + ## Improvements * (x/authz,x/feegrant) [#20590](https://github.com/cosmos/cosmos-sdk/pull/20590) Provide updated keeper in depinject for authz and feegrant modules. diff --git a/client/keys/add.go b/client/keys/add.go index b98c5c9b7cc5..ec00cf50fa24 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -7,6 +7,8 @@ import ( "encoding/json" "errors" "fmt" + "io" + "os" "sort" "github.com/cosmos/go-bip39" @@ -35,6 +37,8 @@ const ( flagNoSort = "nosort" flagHDPath = "hd-path" flagPubKeyBase64 = "pubkey-base64" + flagIndiscreet = "indiscreet" + flagMnemonicSrc = "source" // DefaultKeyPass contains the default key password for genesis transactions DefaultKeyPass = "12345678" @@ -57,6 +61,11 @@ local keystore. Use the --pubkey flag to add arbitrary public keys to the keystore for constructing multisig transactions. +Use the --source flag to import mnemonic from a file in recover or interactive mode. +Example: + + keys add testing --recover --source ./mnemonic.txt + You can create and store a multisig key by passing the list of key names stored in a keyring and the minimum number of signatures required through --multisig-threshold. The keys are sorted by address, unless the flag --nosort is set. @@ -83,6 +92,8 @@ Example: f.Uint32(flagAccount, 0, "Account number for HD derivation (less than equal 2147483647)") f.Uint32(flagIndex, 0, "Address index number for HD derivation (less than equal 2147483647)") f.String(flags.FlagKeyType, string(hd.Secp256k1Type), "Key signing algorithm to generate keys for") + f.Bool(flagIndiscreet, false, "Print seed phrase directly on current terminal (only valid when --no-backup is false)") + f.String(flagMnemonicSrc, "", "Import mnemonic from a file (only usable when recover or interactive is passed)") // support old flags name for backwards compatibility f.SetNormalizeFunc(func(f *pflag.FlagSet, name string) pflag.NormalizedName { @@ -270,19 +281,34 @@ func runAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *buf var mnemonic, bip39Passphrase string recoverFlag, _ := cmd.Flags().GetBool(flagRecover) + mnemonicSrc, _ := cmd.Flags().GetString(flagMnemonicSrc) if recoverFlag { - mnemonic, err = input.GetString("Enter your bip39 mnemonic", inBuf) - if err != nil { - return err + if mnemonicSrc != "" { + mnemonic, err = readMnemonicFromFile(mnemonicSrc) + if err != nil { + return err + } + } else { + mnemonic, err = input.GetString("Enter your bip39 mnemonic", inBuf) + if err != nil { + return err + } } if !bip39.IsMnemonicValid(mnemonic) { return errors.New("invalid mnemonic") } } else if interactive { - mnemonic, err = input.GetString("Enter your bip39 mnemonic, or hit enter to generate one.", inBuf) - if err != nil { - return err + if mnemonicSrc != "" { + mnemonic, err = readMnemonicFromFile(mnemonicSrc) + if err != nil { + return err + } + } else { + mnemonic, err = input.GetString("Enter your bip39 mnemonic, or hit enter to generate one.", inBuf) + if err != nil { + return err + } } if !bip39.IsMnemonicValid(mnemonic) && mnemonic != "" { @@ -377,3 +403,17 @@ func printCreate(cmd *cobra.Command, k *keyring.Record, showMnemonic bool, mnemo return nil } + +func readMnemonicFromFile(filePath string) (string, error) { + file, err := os.Open(filePath) + if err != nil { + return "", err + } + defer file.Close() + + bz, err := io.ReadAll(file) + if err != nil { + return "", err + } + return string(bz), nil +}