diff --git a/go.mod b/go.mod index 3e81ae0..36bcd18 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.17 require ( github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 + github.com/chia-network/go-chia-libs v0.6.0 github.com/itchyny/gojq v0.12.9 github.com/spf13/cobra v1.6.1 ) @@ -15,6 +16,7 @@ require ( github.com/itchyny/timefmt-go v0.1.4 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.16 // indirect + github.com/samber/mo v1.11.0 // indirect github.com/spf13/pflag v1.0.5 // indirect golang.org/x/sys v0.1.0 // indirect ) diff --git a/go.sum b/go.sum index 251c341..0c3d7da 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,11 @@ github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 h1:ZBbLwSJqkHBuFDA6DUhhse0IGJ7T5bemHyNILUjvOq4= github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2/go.mod h1:VSw57q4QFiWDbRnjdX8Cb3Ow0SFncRw+bA/ofY6Q83w= +github.com/chia-network/go-chia-libs v0.6.0 h1:HF9OHb2oLRvsVkM5umH11m085UrMp5Pg/xMO43EHmBE= +github.com/chia-network/go-chia-libs v0.6.0/go.mod h1:uqlNmpIlkRd4vtE+cXoUIAEdbDgCKK0Gp9XzrPgpkEM= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f h1:7LYC+Yfkj3CTRcShK0KOL/w6iTiKyqqBA9a41Wnggw8= github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f/go.mod h1:pFlLw2CfqZiIBOx6BuCeRLCrfxBJipTY0nIOF/VbGcI= github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= @@ -19,20 +21,21 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/samber/mo v1.11.0 h1:ZOiSkrGGpNhVv/1dxP02risztdMTIwE8KSW9OG4k5bY= +github.com/samber/mo v1.11.0/go.mod h1:BfkrCPuYzVG3ZljnZB783WIJIGk1mcZr9c9CPf8tAxs= github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/cmd/coinset/address.go b/internal/cmd/coinset/address.go new file mode 100644 index 0000000..b9162b6 --- /dev/null +++ b/internal/cmd/coinset/address.go @@ -0,0 +1,19 @@ +package cmd + +import "github.com/spf13/cobra" + +var addressCmd = &cobra.Command{ + Use: "address", + Short: "Encode/decode address to/from puzzle hash", + Long: `Encode/decode address to/from puzzle hash.`, +} + +func init() { + addressCmd.SetHelpFunc(func(command *cobra.Command, strings []string) { + command.Flags().MarkHidden("api") + command.Flags().MarkHidden("mainnet") + command.Flags().MarkHidden("testnet") + addressCmd.Parent().HelpFunc()(command, strings) + }) + rootCmd.AddCommand(addressCmd) +} diff --git a/internal/cmd/coinset/address_decode.go b/internal/cmd/coinset/address_decode.go new file mode 100644 index 0000000..d83daf6 --- /dev/null +++ b/internal/cmd/coinset/address_decode.go @@ -0,0 +1,72 @@ +package cmd + +import ( + "encoding/hex" + "encoding/json" + "fmt" + + "github.com/chia-network/go-chia-libs/pkg/bech32m" + "github.com/chia-network/go-chia-libs/pkg/types" + "github.com/spf13/cobra" +) + +var crUseTestnetPrefix bool + +func init() { + addressDecodeCmd.Flags().BoolVarP(&crUseTestnetPrefix, "use-prefix-txch", "t", false, "use testnet prefix 'txch'") + addressDecodeCmd.SetHelpFunc(func(command *cobra.Command, strings []string) { + command.Parent().HelpFunc()(command, strings) + }) + + addressCmd.AddCommand(addressDecodeCmd) +} + +var addressDecodeCmd = &cobra.Command{ + Use: "decode ", + Args: func(cmd *cobra.Command, args []string) error { + if err := cobra.ExactArgs(1)(cmd, args); err != nil { + return err + } + if isHex(args[0]) == true { + return nil + } + return fmt.Errorf("invalid hex value specified: %s", args[0]) + }, + Short: "Decode address from puzzle hash", + Long: `Decode address from puzzle hash`, + Run: func(cmd *cobra.Command, args []string) { + prefix := "xch" + if crUseTestnetPrefix { + prefix = "txch" + } + jsonData := map[string]interface{}{} + jsonData["puzzle_hash"] = formatHex(args[0]) + + hexBytes, err := hex.DecodeString(cleanHex(args[0])) + if err != nil { + fmt.Println(err) + return + } + + hexBytes32, err := types.BytesToBytes32(hexBytes) + if err != nil { + fmt.Println(err) + return + } + + address, err := bech32m.EncodePuzzleHash(hexBytes32, prefix) + if err != nil { + fmt.Println(err) + return + } + jsonData["address"] = address + + byteResult, _ := json.Marshal(jsonData) + if raw { + fmt.Println(string(byteResult)) + return + } + + processJsonData(jsonData) + }, +} diff --git a/internal/cmd/coinset/address_encode.go b/internal/cmd/coinset/address_encode.go new file mode 100644 index 0000000..f29adab --- /dev/null +++ b/internal/cmd/coinset/address_encode.go @@ -0,0 +1,50 @@ +package cmd + +import ( + "encoding/json" + "fmt" + + "github.com/chia-network/go-chia-libs/pkg/bech32m" + "github.com/spf13/cobra" +) + +func init() { + addressEncodeCmd.SetHelpFunc(func(command *cobra.Command, strings []string) { + command.Parent().HelpFunc()(command, strings) + }) + + addressCmd.AddCommand(addressEncodeCmd) +} + +var addressEncodeCmd = &cobra.Command{ + Use: "encode
", + Args: func(cmd *cobra.Command, args []string) error { + if err := cobra.ExactArgs(1)(cmd, args); err != nil { + return err + } + if isAddress(args[0]) == true { + return nil + } + return fmt.Errorf("invalid address value specified: %s", args[0]) + }, + Short: "Encode address to puzzle hash", + Long: `Encode address to puzzle hash`, + Run: func(cmd *cobra.Command, args []string) { + jsonData := map[string]interface{}{} + jsonData["address"] = args[0] + _, puzzleHashBytes, err := bech32m.DecodePuzzleHash(args[0]) + if err != nil { + fmt.Println(err) + return + } + jsonData["puzzle_hash"] = puzzleHashBytes.String() + + byteResult, _ := json.Marshal(jsonData) + if raw { + fmt.Println(string(byteResult)) + return + } + + processJsonData(jsonData) + }, +} diff --git a/internal/cmd/coinset/util.go b/internal/cmd/coinset/util.go index bb65a09..d7fa6ff 100644 --- a/internal/cmd/coinset/util.go +++ b/internal/cmd/coinset/util.go @@ -12,6 +12,11 @@ import ( "github.com/itchyny/gojq" ) +func isAddress(str string) bool { + r, err := regexp.MatchString("^(xch|txch){1}[0-9A-Za-z]{59}$", str) + return err == nil && r == true +} + func isHex(str string) bool { r, err := regexp.MatchString("^(0x)?[0-9A-Fa-f]+$", str) return err == nil && r == true @@ -25,6 +30,13 @@ func formatHex(str string) string { return "0x" + str } +func cleanHex(str string) string { + if str[:2] == "0x" { + return str[2:] + } + return str +} + func apiRoot() string { if api != "" { return api @@ -54,21 +66,16 @@ func makeRequest(rpc string, jsonData map[string]interface{}) { return } - var result map[string]interface{} byteResult, _ := io.ReadAll(resp.Body) + processJsonBytes(byteResult) +} - if raw { - fmt.Println(string(byteResult)) - return - } - - json.Unmarshal(byteResult, &result) - +func processJsonData(jsonData map[string]interface{}) { query, err := gojq.Parse(jq) if err != nil { fmt.Println(err) } - iter := query.Run(result) // or query.RunWithContext + iter := query.Run(jsonData) // or query.RunWithContext for { v, ok := iter.Next() if !ok { @@ -86,6 +93,12 @@ func makeRequest(rpc string, jsonData map[string]interface{}) { } } +func processJsonBytes(jsonBytes []byte) { + var jsonData map[string]interface{} + json.Unmarshal(jsonBytes, &jsonData) + processJsonData(jsonData) +} + func handleRequest(req *http.Request, err error) { }