diff --git a/README.md b/README.md index d91acc5..30d8fdd 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,9 @@ A simple CLI to transform bech32 addresses -### Usage +## Usage + +### Transform address from one bech32 prefix to another (same coin type) ``` bash $ bech32 transform -h @@ -19,13 +21,30 @@ $ bech32 transform cosmos1ge60jkvf2wygslexprqgshxgmzd6zqludz8wyt osmo $ bech32 t cosmos1ge60jkvf2wygslexprqgshxgmzd6zqludz8wyt osmo ``` -### Example +### Derive a validator address from either a hex address or a base64 pubkey -``` bash -$ bech32 transform cosmos1ge60jkvf2wygslexprqgshxgmzd6zqludz8wyt osmo -osmo1ge60jkvf2wygslexprqgshxgmzd6zqlu9e57je +```bash +$ bech32 valcons -h +validator consensus address transformation + +Usage: + bech32 valcons [flags] + +Aliases: + valcons, v + +Examples: +$ bech32 valcons osmo --pubkey wC+QT4cw8WWOwRZhL/XZ8XusXSH7Q3kvhEnFFPagXis= +$ bech32 v osmo --pubkey wC+QT4cw8WWOwRZhL/XZ8XusXSH7Q3kvhEnFFPagXis= +$ bech32 v osmo --address 023DCF3F6AEA4E0098ABBA2AF23F3D65AC324851 +$ bech32 v osmo --address 023DCF3F6AEA4E0098ABBA2AF23F3D65AC324851 + +Flags: + --address string validator hex address to transform + --pubkey string validator base64 pubkey to transform ``` + ### Build static bins ``` diff --git a/cmd/root.go b/cmd/root.go index bffdc95..00b3960 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -25,6 +25,7 @@ func NewRootCmd(log *zap.Logger) *cobra.Command { rootCmd.AddCommand( transformCmd(a), + valConsCmd(a), versionCmd(a), ) diff --git a/cmd/valcons.go b/cmd/valcons.go new file mode 100644 index 0000000..5da4493 --- /dev/null +++ b/cmd/valcons.go @@ -0,0 +1,74 @@ +package cmd + +import ( + "crypto/sha256" + "encoding/base64" + "encoding/hex" + "fmt" + "strings" + + "github.com/cosmos/cosmos-sdk/types/bech32" + "github.com/spf13/cobra" +) + +const ( + flagAddress = "address" + flagPubkey = "pubkey" +) + +func valConsCmd(a *appState) *cobra.Command { + cmd := &cobra.Command{ + Use: "valcons", + Aliases: []string{"v"}, + Short: "validator consensus address transformation", + Args: cobra.ExactArgs(1), + Example: strings.TrimSpace(fmt.Sprintf(` +$ %s valcons osmo --pubkey wC+QT4cw8WWOwRZhL/XZ8XusXSH7Q3kvhEnFFPagXis= +$ %s v osmo --pubkey wC+QT4cw8WWOwRZhL/XZ8XusXSH7Q3kvhEnFFPagXis= +$ %s v osmo --address 023DCF3F6AEA4E0098ABBA2AF23F3D65AC324851 +$ %s v osmo --address 023DCF3F6AEA4E0098ABBA2AF23F3D65AC324851`, + appName, appName, appName, appName)), + RunE: func(cmd *cobra.Command, args []string) error { + prefix := args[0] + address, _ := cmd.Flags().GetString(flagAddress) + pubkey, _ := cmd.Flags().GetString(flagPubkey) + + if address == "" && pubkey == "" { + return fmt.Errorf("either --address or --pubkey must be specified") + } + + if address != "" && pubkey != "" { + return fmt.Errorf("either --address or --pubkey must be specified, not both") + } + + var err error + var addrBz []byte + + if address != "" { + addrBz, err = hex.DecodeString(address) + if err != nil { + return fmt.Errorf("failed to decode address: %s - %w", address, err) + } + } else { + pubkeyBz, err := base64.StdEncoding.DecodeString(pubkey) + if err != nil { + return fmt.Errorf("failed to decode pubkey: %s - %w", pubkey, err) + } + hash := sha256.Sum256(pubkeyBz) + addrBz = hash[:20] + } + + valcons, err := bech32.ConvertAndEncode(prefix+"valcons", addrBz) + if err != nil { + return fmt.Errorf("failed to encode with prefix: %s - %w", prefix, err) + } + fmt.Println(valcons) + + return nil + }, + } + + cmd.Flags().String(flagAddress, "", "validator hex address to transform") + cmd.Flags().String(flagPubkey, "", "validator base64 pubkey to transform") + return cmd +}