Skip to content

Commit 97c6db4

Browse files
tanut32039Tanut Lertwarachai
and
Tanut Lertwarachai
authored
[Feature] - add prompt (#21)
* add prompt * add prompt * fix lint * remove password mask * refac huh option * add cointype account index to prompt --------- Co-authored-by: Tanut Lertwarachai <[email protected]>
1 parent 9515de5 commit 97c6db4

File tree

4 files changed

+207
-55
lines changed

4 files changed

+207
-55
lines changed

cmd/flags.go

+2-7
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
package cmd
22

33
const (
4-
flagHome = "home"
5-
flagFile = "file"
6-
flagMnemonic = "mnemonic"
7-
flagPrivateKey = "priv_key"
8-
flagCoinType = "coin-type"
9-
flagAccount = "account"
10-
flagAccountIndex = "index"
4+
flagHome = "home"
5+
flagFile = "file"
116
)

cmd/keys.go

+137-36
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,27 @@ package cmd
33
import (
44
"encoding/json"
55
"fmt"
6+
"strconv"
67
"strings"
78

9+
"github.com/charmbracelet/huh"
810
"github.com/spf13/cobra"
911

1012
"github.com/bandprotocol/falcon/relayer"
1113
)
1214

15+
const (
16+
privateKeyLabel = "Private key (provide an existing private key)"
17+
mnemonicLabel = "Mnemonic (recover from an existing mnemonic phrase)"
18+
defaultLabel = "Generate new address (no private key or mnemonic needed)"
19+
)
20+
21+
const (
22+
privateKeyResult = iota
23+
mnemonicResult
24+
defaultResult
25+
)
26+
1327
// keysCmd represents the keys command
1428
func keysCmd(app *relayer.App) *cobra.Command {
1529
cmd := &cobra.Command{
@@ -42,41 +56,133 @@ $ %s k a eth test-key`, appName, appName)),
4256
RunE: func(cmd *cobra.Command, args []string) error {
4357
chainName := args[0]
4458
keyName := args[1]
45-
46-
mnemonic, err := cmd.Flags().GetString(flagMnemonic)
47-
if err != nil {
59+
mnemonic := ""
60+
privateKey := ""
61+
62+
var (
63+
coinType, account, index uint64
64+
coinTypeStr, accountStr, indexStr string
65+
)
66+
67+
// Use huh to create a form for user input
68+
selection := 0
69+
selectionPrompt := huh.NewGroup(huh.NewSelect[int]().
70+
Title("Choose how to add a key").
71+
Options(
72+
huh.NewOption(privateKeyLabel, privateKeyResult),
73+
huh.NewOption(mnemonicLabel, mnemonicResult),
74+
huh.NewOption(defaultLabel, defaultResult),
75+
).
76+
Value(&selection))
77+
78+
form := huh.NewForm(selectionPrompt)
79+
if err := form.WithTheme(huh.ThemeBase()).Run(); err != nil {
4880
return err
4981
}
5082

51-
privateKey, err := cmd.Flags().GetString(flagPrivateKey)
52-
if err != nil {
53-
return err
54-
}
55-
56-
if mnemonic != "" && privateKey != "" {
57-
return fmt.Errorf("only one of mnemonic or private key should be provided, not both")
83+
// Coin type input
84+
coinTypeInput := huh.NewInput().
85+
Title("Enter a coin type").
86+
Description("Coin type number for HD derivation (default: 60; leave empty to use default)").
87+
Value(&coinTypeStr).Validate(
88+
func(s string) error {
89+
if s == "" {
90+
coinType = defaultCoinType
91+
return nil
92+
}
93+
var err error
94+
coinType, err = strconv.ParseUint(s, 10, 32)
95+
if err != nil {
96+
return fmt.Errorf("invalid coin type input (should be uint32)")
97+
}
98+
99+
return nil
100+
},
101+
)
102+
103+
// Account type input
104+
accountInput := huh.NewInput().
105+
Title("Enter an account").
106+
Description("Account number in the HD derivation path (default: 0; leave empty to use default)").
107+
Value(&accountStr).Validate(
108+
func(s string) error {
109+
if s == "" {
110+
account = 0
111+
return nil
112+
}
113+
var err error
114+
account, err = strconv.ParseUint(s, 10, 32)
115+
if err != nil {
116+
return fmt.Errorf("invalid account input (should be uint32)")
117+
}
118+
119+
return nil
120+
},
121+
)
122+
123+
// Index type input
124+
indexInput := huh.NewInput().
125+
Title("Enter an index").
126+
Description("Index number for the specific address within an account in the HD derivation path (default: 0; leave empty to use default)").
127+
Value(&indexStr).Validate(
128+
func(s string) error {
129+
if s == "" {
130+
index = 0
131+
return nil
132+
}
133+
var err error
134+
index, err = strconv.ParseUint(s, 10, 32)
135+
if err != nil {
136+
return fmt.Errorf("invalid index input (should be uint32)")
137+
}
138+
139+
return nil
140+
},
141+
)
142+
143+
// Handle the selected option
144+
switch selection {
145+
case privateKeyResult:
146+
privateKeyPrompt := huh.NewGroup(huh.NewInput().
147+
Title("Enter your private key").
148+
Value(&privateKey))
149+
150+
form := huh.NewForm(privateKeyPrompt)
151+
if err := form.WithTheme(huh.ThemeBase()).Run(); err != nil {
152+
return err
153+
}
154+
155+
case mnemonicResult:
156+
mnemonicPrompt := huh.NewGroup(huh.NewInput().
157+
Title("Enter your mnemonic").
158+
Value(&mnemonic),
159+
coinTypeInput,
160+
accountInput,
161+
indexInput,
162+
)
163+
164+
form := huh.NewForm(mnemonicPrompt)
165+
if err := form.WithTheme(huh.ThemeBase()).Run(); err != nil {
166+
return err
167+
}
168+
case defaultResult:
169+
defaultPrompt := huh.NewGroup(coinTypeInput, accountInput, indexInput)
170+
form := huh.NewForm(defaultPrompt)
171+
if err := form.WithTheme(huh.ThemeBase()).Run(); err != nil {
172+
return err
173+
}
58174
}
59175

60-
coinType, err := cmd.Flags().GetInt32(flagCoinType)
61-
if err != nil {
62-
return err
63-
}
64-
65-
if coinType < 0 {
66-
coinType = defaultCoinType
67-
}
68-
69-
account, err := cmd.Flags().GetUint(flagAccount)
70-
if err != nil {
71-
return err
72-
}
73-
74-
index, err := cmd.Flags().GetUint(flagAccountIndex)
75-
if err != nil {
76-
return err
77-
}
78-
79-
keyOutput, err := app.AddKey(chainName, keyName, mnemonic, privateKey, uint32(coinType), account, index)
176+
// Add the key to the app
177+
keyOutput, err := app.AddKey(
178+
chainName,
179+
keyName,
180+
mnemonic,
181+
privateKey,
182+
uint32(coinType),
183+
uint(account),
184+
uint(index),
185+
)
80186
if err != nil {
81187
return err
82188
}
@@ -90,12 +196,7 @@ $ %s k a eth test-key`, appName, appName)),
90196
return nil
91197
},
92198
}
93-
cmd.Flags().StringP(flagMnemonic, "m", "", "add new key from specified mnemonic")
94-
cmd.Flags().StringP(flagPrivateKey, "p", "", "add new key from specified private key")
95-
cmd.Flags().Int32(flagCoinType, -1, "coin type number for HD derivation")
96-
cmd.Flags().Uint(flagAccount, 0, "account number within the HD derivation path")
97-
cmd.Flags().
98-
Uint(flagAccountIndex, 0, "Index number for the specific address within an account in the HD derivation path")
199+
99200
return cmd
100201
}
101202

go.mod

+22-3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ require (
66
cosmossdk.io/math v1.4.0
77
cosmossdk.io/x/tx v0.13.5
88
github.com/bandprotocol/chain/v3 v3.0.0-20241202095241-21710ba55161
9+
github.com/charmbracelet/huh v0.6.0
910
github.com/cometbft/cometbft v0.38.12
1011
github.com/cosmos/cosmos-sdk v0.50.10
1112
github.com/cosmos/gogoproto v1.7.0
@@ -41,6 +42,8 @@ require (
4142
github.com/Masterminds/semver/v3 v3.3.1 // indirect
4243
github.com/Microsoft/go-winio v0.6.2 // indirect
4344
github.com/StackExchange/wmi v1.2.1 // indirect
45+
github.com/atotto/clipboard v0.1.4 // indirect
46+
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
4447
github.com/bandprotocol/go-owasm v0.3.1 // indirect
4548
github.com/beorn7/perks v1.0.1 // indirect
4649
github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect
@@ -49,9 +52,16 @@ require (
4952
github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect
5053
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect
5154
github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce // indirect
55+
github.com/catppuccin/go v0.2.0 // indirect
5256
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
5357
github.com/cespare/xxhash v1.1.0 // indirect
5458
github.com/cespare/xxhash/v2 v2.3.0 // indirect
59+
github.com/charmbracelet/bubbles v0.20.0 // indirect
60+
github.com/charmbracelet/bubbletea v1.2.4 // indirect
61+
github.com/charmbracelet/lipgloss v1.0.0 // indirect
62+
github.com/charmbracelet/x/ansi v0.4.5 // indirect
63+
github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 // indirect
64+
github.com/charmbracelet/x/term v0.2.1 // indirect
5565
github.com/cockroachdb/errors v1.11.3 // indirect
5666
github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce // indirect
5767
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
@@ -84,6 +94,7 @@ require (
8494
github.com/dustin/go-humanize v1.0.1 // indirect
8595
github.com/dvsekhvalnov/jose2go v1.6.0 // indirect
8696
github.com/emicklei/dot v1.6.1 // indirect
97+
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
8798
github.com/ethereum/c-kzg-4844 v1.0.0 // indirect
8899
github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9 // indirect
89100
github.com/fatih/color v1.16.0 // indirect
@@ -127,12 +138,19 @@ require (
127138
github.com/kr/pretty v0.3.1 // indirect
128139
github.com/kr/text v0.2.0 // indirect
129140
github.com/linxGnu/grocksdb v1.8.14 // indirect
141+
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
130142
github.com/magiconair/properties v1.8.7 // indirect
131143
github.com/mattn/go-colorable v0.1.13 // indirect
132144
github.com/mattn/go-isatty v0.0.20 // indirect
145+
github.com/mattn/go-localereader v0.0.1 // indirect
146+
github.com/mattn/go-runewidth v0.0.16 // indirect
133147
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
148+
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
134149
github.com/mmcloughlin/addchain v0.4.0 // indirect
135150
github.com/mtibben/percent v0.2.1 // indirect
151+
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
152+
github.com/muesli/cancelreader v0.2.2 // indirect
153+
github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a // indirect
136154
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
137155
github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a // indirect
138156
github.com/oklog/run v1.1.0 // indirect
@@ -144,6 +162,7 @@ require (
144162
github.com/prometheus/common v0.55.0 // indirect
145163
github.com/prometheus/procfs v0.15.1 // indirect
146164
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
165+
github.com/rivo/uniseg v0.4.7 // indirect
147166
github.com/rogpeppe/go-internal v1.12.0 // indirect
148167
github.com/rs/cors v1.11.1 // indirect
149168
github.com/rs/zerolog v1.33.0 // indirect
@@ -170,10 +189,10 @@ require (
170189
golang.org/x/crypto v0.26.0 // indirect
171190
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect
172191
golang.org/x/net v0.28.0 // indirect
173-
golang.org/x/sync v0.8.0 // indirect
174-
golang.org/x/sys v0.24.0 // indirect
192+
golang.org/x/sync v0.9.0 // indirect
193+
golang.org/x/sys v0.27.0 // indirect
175194
golang.org/x/term v0.23.0 // indirect
176-
golang.org/x/text v0.17.0 // indirect
195+
golang.org/x/text v0.18.0 // indirect
177196
google.golang.org/genproto v0.0.0-20240701130421-f6361c86f094 // indirect
178197
google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38 // indirect
179198
google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 // indirect

0 commit comments

Comments
 (0)