From 6f145da3281da9f4db0d2ab3ca760ca5d56e6b58 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Federico=20Kunze=20K=C3=BCllmer?=
 <31522760+fedekunze@users.noreply.github.com>
Date: Fri, 20 Aug 2021 05:01:57 -0400
Subject: [PATCH] client: add EIP55 address to `debug` command (#464)

* cmd: debug command

* c++

* docs
---
 CHANGELOG.md            |   1 +
 client/debug/debug.go   | 128 ++++++++++++++++++++++++++++++++++++++++
 cmd/ethermintd/root.go  |   2 +-
 docs/basics/accounts.md |  27 ++++-----
 4 files changed, 142 insertions(+), 16 deletions(-)
 create mode 100644 client/debug/debug.go

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 522d15cc..1db2f9e7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -71,6 +71,7 @@ the Tracer type used to collect execution traces from the EVM transaction execut
 
 ### Improvements
 
+* (client) [tharsis#450](https://github.com/tharsis/ethermint/issues/450) Add EIP55 hex address support on `debug addr` command.
 * (server) [tharsis#343](https://github.com/tharsis/ethermint/pull/343) Define a wrap tendermint logger `Handler` go-ethereum's `root` logger.
 * (rpc) [tharsis#457](https://github.com/tharsis/ethermint/pull/457) Configure RPC gas cap through app config.
 * (evm) [tharsis#434](https://github.com/tharsis/ethermint/pull/434) Support different `Tracer` types for the EVM.
diff --git a/client/debug/debug.go b/client/debug/debug.go
new file mode 100644
index 00000000..9e89633b
--- /dev/null
+++ b/client/debug/debug.go
@@ -0,0 +1,128 @@
+package debug
+
+import (
+	"encoding/hex"
+	"fmt"
+	"strconv"
+	"strings"
+
+	"github.com/spf13/cobra"
+	"github.com/tendermint/tendermint/libs/bytes"
+
+	"github.com/ethereum/go-ethereum/common"
+
+	"github.com/cosmos/cosmos-sdk/client"
+	cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
+	sdk "github.com/cosmos/cosmos-sdk/types"
+	"github.com/cosmos/cosmos-sdk/version"
+)
+
+// Cmd creates a main CLI command
+func Cmd() *cobra.Command {
+	cmd := &cobra.Command{
+		Use:   "debug",
+		Short: "Tool for helping with debugging your application",
+		RunE:  client.ValidateCmd,
+	}
+
+	cmd.AddCommand(PubkeyCmd())
+	cmd.AddCommand(AddrCmd())
+	cmd.AddCommand(RawBytesCmd())
+
+	return cmd
+}
+
+// getPubKeyFromString decodes SDK PubKey using JSON marshaler.
+func getPubKeyFromString(ctx client.Context, pkstr string) (cryptotypes.PubKey, error) {
+	var pk cryptotypes.PubKey
+	err := ctx.Codec.UnmarshalInterfaceJSON([]byte(pkstr), &pk)
+	return pk, err
+}
+
+func PubkeyCmd() *cobra.Command {
+	return &cobra.Command{
+		Use:   "pubkey [pubkey]",
+		Short: "Decode a pubkey from proto JSON",
+		Long:  "Decode a pubkey from proto JSON and display it's address",
+		Example: fmt.Sprintf(
+			`"$ %s debug pubkey '{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"AurroA7jvfPd1AadmmOvWM2rJSwipXfRf8yD6pLbA2DJ"}'`,
+			version.AppName,
+		),
+		Args: cobra.ExactArgs(1),
+		RunE: func(cmd *cobra.Command, args []string) error {
+			clientCtx := client.GetClientContextFromCmd(cmd)
+			pk, err := getPubKeyFromString(clientCtx, args[0])
+			if err != nil {
+				return err
+			}
+
+			addr := pk.Address()
+			cmd.Printf("Address (EIP-55): %s\n", common.BytesToAddress(addr))
+			cmd.Printf("Bech32 Acc: %s\n", sdk.AccAddress(addr))
+			cmd.Println("PubKey Hex:", hex.EncodeToString(pk.Bytes()))
+			return nil
+		},
+	}
+}
+
+func AddrCmd() *cobra.Command {
+	return &cobra.Command{
+		Use:   "addr [address]",
+		Short: "Convert an address between hex and bech32",
+		Long:  "Convert an address between hex encoding and bech32.",
+		Example: fmt.Sprintf(
+			`$ %s debug addr eth10jmp6sgh4cc6zt3e8gw05wavvejgr5pw2unfju
+$ %s debug addr 0xA588C66983a81e800Db4dF74564F09f91c026351`, version.AppName, version.AppName),
+		Args: cobra.ExactArgs(1),
+		RunE: func(cmd *cobra.Command, args []string) error {
+
+			addrString := args[0]
+			cfg := sdk.GetConfig()
+
+			var addr []byte
+			switch {
+			case common.IsHexAddress(addrString):
+				addr = common.HexToAddress(addrString).Bytes()
+			case strings.HasPrefix(addrString, cfg.GetBech32ValidatorAddrPrefix()):
+				addr, _ = sdk.ValAddressFromBech32(addrString)
+			case strings.HasPrefix(addrString, cfg.GetBech32AccountAddrPrefix()):
+				addr, _ = sdk.AccAddressFromBech32(addrString)
+			default:
+				return fmt.Errorf("expected a valid hex or bech32 address (acc prefix %s), got '%s'", cfg.GetBech32AccountAddrPrefix(), addrString)
+			}
+
+			cmd.Println("Address bytes:", addr)
+			cmd.Printf("Address (hex): %s\n", bytes.HexBytes(addr))
+			cmd.Printf("Address (EIP-55): %s\n", common.BytesToAddress(addr))
+			cmd.Printf("Bech32 Acc: %s\n", sdk.AccAddress(addr))
+			cmd.Printf("Bech32 Val: %s\n", sdk.ValAddress(addr))
+			return nil
+		},
+	}
+}
+
+func RawBytesCmd() *cobra.Command {
+	return &cobra.Command{
+		Use:     "raw-bytes [raw-bytes]",
+		Short:   "Convert raw bytes output (eg. [10 21 13 255]) to hex",
+		Example: fmt.Sprintf(`$ %s debug raw-bytes [72 101 108 108 111 44 32 112 108 97 121 103 114 111 117 110 100]`, version.AppName),
+		Args:    cobra.ExactArgs(1),
+		RunE: func(_ *cobra.Command, args []string) error {
+			stringBytes := args[0]
+			stringBytes = strings.Trim(stringBytes, "[")
+			stringBytes = strings.Trim(stringBytes, "]")
+			spl := strings.Split(stringBytes, " ")
+
+			byteArray := []byte{}
+			for _, s := range spl {
+				b, err := strconv.ParseInt(s, 10, 8)
+				if err != nil {
+					return err
+				}
+				byteArray = append(byteArray, byte(b))
+			}
+			fmt.Printf("%X\n", byteArray)
+			return nil
+		},
+	}
+}
diff --git a/cmd/ethermintd/root.go b/cmd/ethermintd/root.go
index 4d87e9de..8ea1dd4e 100644
--- a/cmd/ethermintd/root.go
+++ b/cmd/ethermintd/root.go
@@ -16,7 +16,6 @@ import (
 	"github.com/cosmos/cosmos-sdk/baseapp"
 	"github.com/cosmos/cosmos-sdk/client"
 	"github.com/cosmos/cosmos-sdk/client/config"
-	"github.com/cosmos/cosmos-sdk/client/debug"
 	"github.com/cosmos/cosmos-sdk/client/flags"
 	"github.com/cosmos/cosmos-sdk/client/rpc"
 	sdkserver "github.com/cosmos/cosmos-sdk/server"
@@ -33,6 +32,7 @@ import (
 
 	"github.com/tharsis/ethermint/app"
 	ethermintclient "github.com/tharsis/ethermint/client"
+	"github.com/tharsis/ethermint/client/debug"
 	"github.com/tharsis/ethermint/crypto/hd"
 	"github.com/tharsis/ethermint/encoding"
 	"github.com/tharsis/ethermint/server"
diff --git a/docs/basics/accounts.md b/docs/basics/accounts.md
index 9699ba16..85ca5d19 100644
--- a/docs/basics/accounts.md
+++ b/docs/basics/accounts.md
@@ -56,24 +56,21 @@ Cosmos `sdk.AccAddress`.
 The `ethermintd debug addr <address>` can be used to convert an address between hex and bech32 formats. For example:
 
 ```bash
-ethermintd debug addr eth12uqc42yj77hk64cdr3vsnpkfs6k0pllln7rudt
-    Address: [87 1 138 168 146 247 175 109 87 13 28 89 9 134 201 134 172 240 255 255]
-    Address (hex): 57018AA892F7AF6D570D1C590986C986ACF0FFFF
-    Bech32 Acc: eth12uqc42yj77hk64cdr3vsnpkfs6k0pllln7rudt
-    Bech32 Val: ethvaloper12uqc42yj77hk64cdr3vsnpkfs6k0pllldvagr4
+ethermintd debug addr eth10jmp6sgh4cc6zt3e8gw05wavvejgr5pw2unfju
+  Address bytes:  [124 182 29 65 23 174 49 161 46 57 58 28 250 59 172 102 100 129 208 46]
+  Address (hex): 7CB61D4117AE31A12E393A1CFA3BAC666481D02E
+  Address (EIP-55): 0x7cB61D4117AE31a12E393a1Cfa3BaC666481D02E
+  Bech32 Acc: eth10jmp6sgh4cc6zt3e8gw05wavvejgr5pw2unfju
+  Bech32 Val: ethvaloper10jmp6sgh4cc6zt3e8gw05wavvejgr5pw5wdauz
 
-ethermintd debug addr 57018AA892F7af6D570D1c590986c986aCf0fFff
-    Address: [87 1 138 168 146 247 175 109 87 13 28 89 9 134 201 134 172 240 255 255]
-    Address (hex): 57018AA892F7AF6D570D1C590986C986ACF0FFFF
-    Bech32 Acc: eth12uqc42yj77hk64cdr3vsnpkfs6k0pllln7rudt
-    Bech32 Val: ethvaloper12uqc42yj77hk64cdr3vsnpkfs6k0pllldvagr4
+ethermintd debug addr 0x7cB61D4117AE31a12E393a1Cfa3BaC666481D02E
+  Address bytes:  [124 182 29 65 23 174 49 161 46 57 58 28 250 59 172 102 100 129 208 46]
+  Address (hex): 7CB61D4117AE31A12E393A1CFA3BAC666481D02E
+  Address (EIP-55): 0x7cB61D4117AE31a12E393a1Cfa3BaC666481D02E
+  Bech32 Acc: eth10jmp6sgh4cc6zt3e8gw05wavvejgr5pw2unfju
+  Bech32 Val: ethvaloper10jmp6sgh4cc6zt3e8gw05wavvejgr5pw5wdauz
 ```
 
-::: tip
-Add the `0x` prefix to the returned hex address above to represent the Ethereum hex address format. For example:
-`Address (hex): 57018AA892F7AF6D570D1C590986C986ACF0FFFF` implies that `0x57018AA892F7AF6D570D1C590986C986ACF0FFFF` is the Ethereum hex address.
-:::
-
 ### Key output
 
 ::: tip