From 8435050adeb2ae5262af3d6d3b101d5bbdd5ff39 Mon Sep 17 00:00:00 2001 From: Guillermo Paoletti Date: Mon, 19 Aug 2024 00:38:13 +0200 Subject: [PATCH] feat: eth_call command to query view functions (#29) * feat: contracts eth_call to view functions * fixes * docs * fix: build issues * chore: remove unused code * update erc20 abi --- abis/erc20.abi | 222 ++++++++++++++++++ cmd/playground/query/erc20/balance.go | 8 +- cmd/playground/query/erc20/erc20.go | 25 -- cmd/playground/query/erc20/supply.go | 7 +- cmd/playground/tx/solidity/callContract.go | 76 ++++++ cmd/playground/tx/solidity/compileContract.go | 55 ++++- cmd/playground/tx/solidity/deployContract.go | 23 +- .../playground/tx/solidity/compile.mdx | 4 +- .../playground/tx/solidity/contractView.mdx | 21 ++ .../playground/tx/solidity/deploy.mdx | 11 +- docs/pages/lib/requester/web3.mdx | 6 + docs/pages/lib/smartcontract/ABI.mdx | 23 ++ lib/requester/post.go | 27 +++ lib/requester/web3.go | 26 ++ lib/smartcontract/smartcontract.go | 38 +++ playground/cosmosdaemon/cli_helpers.go | 31 +++ vocs.config.ts | 8 + 17 files changed, 548 insertions(+), 63 deletions(-) create mode 100644 abis/erc20.abi create mode 100644 cmd/playground/tx/solidity/callContract.go create mode 100644 docs/pages/hanchond/playground/tx/solidity/contractView.mdx create mode 100644 docs/pages/lib/smartcontract/ABI.mdx create mode 100644 lib/smartcontract/smartcontract.go diff --git a/abis/erc20.abi b/abis/erc20.abi new file mode 100644 index 0000000..06b572d --- /dev/null +++ b/abis/erc20.abi @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/cmd/playground/query/erc20/balance.go b/cmd/playground/query/erc20/balance.go index 43e11bb..ea0d9c6 100644 --- a/cmd/playground/query/erc20/balance.go +++ b/cmd/playground/query/erc20/balance.go @@ -9,6 +9,7 @@ import ( "github.com/hanchon/hanchond/lib/converter" "github.com/hanchon/hanchond/lib/requester" "github.com/hanchon/hanchond/lib/smartcontract/erc20" + "github.com/hanchon/hanchond/playground/cosmosdaemon" "github.com/hanchon/hanchond/playground/sql" "github.com/spf13/cobra" ) @@ -30,7 +31,12 @@ var balanceCmd = &cobra.Command{ os.Exit(1) } - endpoint := getEndpoint(queries, cmd) + endpoint, err := cosmosdaemon.GetWeb3Endpoint(queries, cmd) + if err != nil { + fmt.Printf("error generting web3 endpoint: %s\n", err.Error()) + os.Exit(1) + } + client := requester.NewClient().WithUnsecureWeb3Endpoint(endpoint) heightInt := erc20.Latest if height != "latest" { diff --git a/cmd/playground/query/erc20/erc20.go b/cmd/playground/query/erc20/erc20.go index a3d353b..fafb814 100644 --- a/cmd/playground/query/erc20/erc20.go +++ b/cmd/playground/query/erc20/erc20.go @@ -1,11 +1,8 @@ package erc20 import ( - "fmt" "os" - "github.com/hanchon/hanchond/playground/database" - "github.com/hanchon/hanchond/playground/evmos" "github.com/hanchon/hanchond/playground/filesmanager" "github.com/spf13/cobra" ) @@ -25,25 +22,3 @@ func init() { ERC20Cmd.PersistentFlags().String("url", "", "Set the url path if using external provider") ERC20Cmd.PersistentFlags().Bool("mainnet", false, "Set as true if the query for Evmos mainnet. This flag takes overwrite all the other provider related flags.") } - -func getEndpoint(queries *database.Queries, cmd *cobra.Command) string { - endpoint := "" - mainnet, _ := cmd.Flags().GetBool("mainnet") - if mainnet { - return "https://proxy.evmos.org/web3" - } - - url, _ := cmd.Flags().GetString("url") - if url != "" { - endpoint = url - } else { - nodeID, err := cmd.Flags().GetString("node") - if err != nil { - fmt.Println("node not set") - os.Exit(1) - } - e := evmos.NewEvmosFromDB(queries, nodeID) - endpoint = fmt.Sprintf("http://localhost:%d", e.Ports.P8545) - } - return endpoint -} diff --git a/cmd/playground/query/erc20/supply.go b/cmd/playground/query/erc20/supply.go index 15ee339..9742f34 100644 --- a/cmd/playground/query/erc20/supply.go +++ b/cmd/playground/query/erc20/supply.go @@ -8,6 +8,7 @@ import ( "github.com/hanchon/hanchond/lib/requester" "github.com/hanchon/hanchond/lib/smartcontract/erc20" + "github.com/hanchon/hanchond/playground/cosmosdaemon" "github.com/hanchon/hanchond/playground/sql" "github.com/spf13/cobra" ) @@ -21,7 +22,11 @@ var supplyCmd = &cobra.Command{ queries := sql.InitDBFromCmd(cmd) contract := strings.TrimSpace(args[0]) - endpoint := getEndpoint(queries, cmd) + endpoint, err := cosmosdaemon.GetWeb3Endpoint(queries, cmd) + if err != nil { + fmt.Printf("error generting web3 endpoint: %s\n", err.Error()) + os.Exit(1) + } client := requester.NewClient().WithUnsecureWeb3Endpoint(endpoint) height, _ := cmd.Flags().GetString("height") diff --git a/cmd/playground/tx/solidity/callContract.go b/cmd/playground/tx/solidity/callContract.go new file mode 100644 index 0000000..9c44b90 --- /dev/null +++ b/cmd/playground/tx/solidity/callContract.go @@ -0,0 +1,76 @@ +package solidity + +import ( + "fmt" + "os" + "strings" + + "github.com/hanchon/hanchond/lib/requester" + "github.com/hanchon/hanchond/lib/smartcontract" + "github.com/hanchon/hanchond/playground/cosmosdaemon" + "github.com/hanchon/hanchond/playground/filesmanager" + "github.com/hanchon/hanchond/playground/sql" + "github.com/spf13/cobra" +) + +var params []string + +// callContractViewCmd represents the callContractView command +var callContractViewCmd = &cobra.Command{ + Use: "call-contract-view [contract] [abi_path] [method]", + Args: cobra.ExactArgs(3), + Short: "Call a contract view with eth_call", + Run: func(cmd *cobra.Command, args []string) { + queries := sql.InitDBFromCmd(cmd) + + height, err := cmd.Flags().GetString("height") + if err != nil { + fmt.Println("could not read height value:", err.Error()) + os.Exit(1) + } + + contract := strings.TrimSpace(args[0]) + abiPath := strings.TrimSpace(args[1]) + method := strings.TrimSpace(args[2]) + + abiBytes, err := filesmanager.ReadFile(abiPath) + if err != nil { + fmt.Printf("error reading the abi file:%s\n", err.Error()) + os.Exit(1) + } + + endpoint, err := cosmosdaemon.GetWeb3Endpoint(queries, cmd) + if err != nil { + fmt.Printf("error generting web3 endpoint: %s\n", err.Error()) + os.Exit(1) + } + + callArgs, err := smartcontract.StringsToABIArguments(params) + if err != nil { + fmt.Printf("error converting arguments: %s\n", err.Error()) + os.Exit(1) + } + + client := requester.NewClient().WithUnsecureWeb3Endpoint(endpoint) + + callData, err := smartcontract.ABIPack(abiBytes, method, callArgs...) + if err != nil { + fmt.Println(err.Error()) + os.Exit(1) + } + + resp, err := client.EthCall(contract, callData, height) + if err != nil { + fmt.Println("error on eth call", err.Error()) + os.Exit(1) + } + fmt.Println(string(resp)) + os.Exit(0) + }, +} + +func init() { + SolidityCmd.AddCommand(callContractViewCmd) + callContractViewCmd.Flags().String("height", "latest", "Query at the given height.") + callContractViewCmd.Flags().StringSliceVarP(¶ms, "params", "p", []string{}, "A list of params. If the param is an address, prefix with `a:0x123...`") +} diff --git a/cmd/playground/tx/solidity/compileContract.go b/cmd/playground/tx/solidity/compileContract.go index e6cd3eb..4a8eca1 100644 --- a/cmd/playground/tx/solidity/compileContract.go +++ b/cmd/playground/tx/solidity/compileContract.go @@ -4,7 +4,7 @@ import ( "fmt" "os" "os/exec" - "strings" + "path/filepath" "github.com/hanchon/hanchond/playground/filesmanager" "github.com/hanchon/hanchond/playground/sql" @@ -37,23 +37,43 @@ var compileContractCmd = &cobra.Command{ } pathToSolidityCode := args[0] - paths := strings.Split(pathToSolidityCode, "/") - fileName := strings.Split(paths[len(paths)-1], ".sol")[0] solcPath := filesmanager.GetSolcPath(solcVersion) - compileCmd := exec.Command(solcPath, "--optimize", "--combined-json", "abi,bin", pathToSolidityCode, "-o", outputFolder) + if err := filesmanager.CleanUpTempFolder(); err != nil { + fmt.Printf("could not clean up temp folder:%s\n", err.Error()) + os.Exit(1) + } + + folderName := "compiler" + if err := filesmanager.CreateTempFolder(folderName); err != nil { + fmt.Printf("could not create up temp folder:%s\n", err.Error()) + os.Exit(1) + } + + compileCmd := exec.Command(solcPath, "--optimize", "--abi", "--bin", pathToSolidityCode, "-o", filesmanager.GetBranchFolder(folderName)) out, err := compileCmd.CombinedOutput() if err != nil { fmt.Printf("error compiling the contract:%s. %s\n", err.Error(), string(out)) os.Exit(1) } - if err := os.Rename(outputFolder+"combined.json", outputFolder+fileName+".json"); err != nil { - fmt.Printf("error copying the built file: %s\n", err.Error()) + if err := moveFiles(filesmanager.GetBranchFolder(folderName), outputFolder, "abi"); err != nil { + fmt.Printf("error copying the built files: %s\n", err.Error()) + os.Exit(1) + } + + if err := moveFiles(filesmanager.GetBranchFolder(folderName), outputFolder, "bin"); err != nil { + fmt.Printf("error copying the built files: %s\n", err.Error()) os.Exit(1) } - fmt.Printf("Contract compiled at %s%s.json\n", outputFolder, fileName) + + if err := filesmanager.CleanUpTempFolder(); err != nil { + fmt.Printf("could not clean up temp folder:%s\n", err.Error()) + os.Exit(1) + } + + fmt.Printf("Contract compiled at %s\n", outputFolder) }, } @@ -62,3 +82,24 @@ func init() { compileContractCmd.Flags().StringP("output-folder", "o", "./", "Output folder where the compile code will be saved") compileContractCmd.Flags().StringP("solc-version", "v", "0.8.0", "Solc version used to compile the code") } + +func moveFiles(in, out, extension string) error { + files, err := filepath.Glob(in + "/*." + extension) + if err != nil { + return err + } + if len(files) == 0 { + return err + } + + for _, v := range files { + if err := filesmanager.CopyFile( + v, + out, + ); err != nil { + return err + } + } + + return nil +} diff --git a/cmd/playground/tx/solidity/deployContract.go b/cmd/playground/tx/solidity/deployContract.go index e2ced8b..6f56f37 100644 --- a/cmd/playground/tx/solidity/deployContract.go +++ b/cmd/playground/tx/solidity/deployContract.go @@ -1,8 +1,6 @@ package solidity import ( - "encoding/hex" - "encoding/json" "fmt" "os" @@ -14,11 +12,11 @@ import ( // deployContractCmd represents the deploy command var deployContractCmd = &cobra.Command{ - Use: "deploy-contract [path_to_bytecode]", + Use: "deploy-contract [path_to_bin_file]", Args: cobra.ExactArgs(1), Aliases: []string{"d"}, Short: "Deploy a solidity contract", - Long: "The bytecode file must have the following format: {\"bytecode\":\"60806...\",...}", + Long: "The bytecode file must contain just the hex data", Run: func(cmd *cobra.Command, args []string) { queries := sql.InitDBFromCmd(cmd) nodeID, err := cmd.Flags().GetString("node") @@ -44,22 +42,7 @@ var deployContractCmd = &cobra.Command{ os.Exit(1) } - type Bytecode struct { - Bytecode string `json:"bytecode"` - } - var b Bytecode - if err := json.Unmarshal(bytecode, &b); err != nil { - fmt.Printf("error unmarshing the json file: %s\n", err.Error()) - os.Exit(1) - } - - bytes, err := hex.DecodeString(b.Bytecode) - if err != nil { - fmt.Printf("error decoding the bytecode: %s\n", err.Error()) - os.Exit(1) - } - - txHash, err := builder.DeployContract(0, bytes, uint64(gasLimit)) + txHash, err := builder.DeployContract(0, bytecode, uint64(gasLimit)) if err != nil { fmt.Printf("error sending the transaction: %s\n", err.Error()) os.Exit(1) diff --git a/docs/pages/hanchond/playground/tx/solidity/compile.mdx b/docs/pages/hanchond/playground/tx/solidity/compile.mdx index dff1710..821110e 100644 --- a/docs/pages/hanchond/playground/tx/solidity/compile.mdx +++ b/docs/pages/hanchond/playground/tx/solidity/compile.mdx @@ -10,13 +10,13 @@ The `solc` version must be [built](/hanchond/playground/buildSolc) before runnin There are two available flags: - version: it is used to set the solc version -- output-folder: it is used to set the folder where the compile contract will be stored +- output-folder: it is used to set the folder where the compiled contract will be stored ::: ```bash hanchond playground tx solidity compile ./temp/address.sol -v 0.6.12 -o /tmp -Contract compiled at /tmp/address.json +Contract compiled at /tmp ``` :::warning diff --git a/docs/pages/hanchond/playground/tx/solidity/contractView.mdx b/docs/pages/hanchond/playground/tx/solidity/contractView.mdx new file mode 100644 index 0000000..35abae9 --- /dev/null +++ b/docs/pages/hanchond/playground/tx/solidity/contractView.mdx @@ -0,0 +1,21 @@ +# Contract View + +The `call-contract-view` command can be used to send an `eth_call` request to a deployed smart contract. + +The arguments are: + +- Contract Address +- ABI path +- Method name +- Params list + +```bash +hanchond playground tx solidity call-contract-view 0x80b5a32E4F032B2a058b4F29EC95EEfEEB87aDcd ./abis/erc20.abi balanceOf --params=a:0x354bF866A4B006C9AF9d9e06d9364217A8616E12 +{"jsonrpc":"2.0","id":1,"result":"0x00000000000000000000000000000000000000000000000000000000000007d0"} +``` + +The supported params list can be found [here](/lib/smartcontract/ABI) + +:::info +The params MUST be prefixed with the type followed by `:` +::: diff --git a/docs/pages/hanchond/playground/tx/solidity/deploy.mdx b/docs/pages/hanchond/playground/tx/solidity/deploy.mdx index 4b9dc9c..dcd6839 100644 --- a/docs/pages/hanchond/playground/tx/solidity/deploy.mdx +++ b/docs/pages/hanchond/playground/tx/solidity/deploy.mdx @@ -6,18 +6,15 @@ The command `compile-contract` can be used to compile a `.sol` file. ## File Format -The compiled file must have the following format: +The compiled`.bin` file must have the following format: -```json -{ - "bytecode":"hex_string", - ... -} +```sh +60.... ``` ## Deploy the Contract ```bash -hanchond playground tx solidity deploy-contract /tmp/account.json +hanchond playground tx solidity deploy-contract /tmp/CheckAddress.bin {"contract_address":"0xc2f633d1e91e1a2edeb55274753b44b204a4df91", "tx_hash":"0xa0a473953fb8ff88cbd7f63c956992d2621a7fbc47a6ba59427ef8482a0baf9f"} ``` diff --git a/docs/pages/lib/requester/web3.mdx b/docs/pages/lib/requester/web3.mdx index 9d85e0b..10ba7e4 100644 --- a/docs/pages/lib/requester/web3.mdx +++ b/docs/pages/lib/requester/web3.mdx @@ -78,3 +78,9 @@ Broadcast the transaction object ```go txHash, err := c.BroadcastTX(tx) ``` + +## Eth_call + +```go +resp, err := client.EthCall(contract, callData, height) +``` diff --git a/docs/pages/lib/smartcontract/ABI.mdx b/docs/pages/lib/smartcontract/ABI.mdx new file mode 100644 index 0000000..f5297c1 --- /dev/null +++ b/docs/pages/lib/smartcontract/ABI.mdx @@ -0,0 +1,23 @@ +# ABI Helpers + +## ABI Pack + +To simplify the pack of arguments, the `ABIPack` function was created: + +```go +callData, err := smartcontract.ABIPack(abiBytes, method, callArgs...) +``` + +This is meant to be used after reading the `abi` file from disk. + +## Strings To ABIArguments + +The `StringsToABIArguments` function can be used to convert the strings used in the `cli` to the correct type used by solidity. + +```go +callArgs, err := smartcontract.StringsToABIArguments(params) +``` + +Supported types: + +- Address: `a:0x123...` diff --git a/lib/requester/post.go b/lib/requester/post.go index 0764055..a740226 100644 --- a/lib/requester/post.go +++ b/lib/requester/post.go @@ -35,3 +35,30 @@ func (c *Client) SendPostRequestEasyJSON(endpoint string, body []byte, res easyj respBody := resp.Body() return easyjson.Unmarshal(respBody, res) } + +func (c *Client) SendPostRequest(endpoint string, body []byte, auth string) ([]byte, error) { + req := fasthttp.AcquireRequest() + req.SetRequestURI(endpoint) + req.Header.SetMethod(fasthttp.MethodPost) + req.Header.SetContentTypeBytes([]byte("application/json")) + if auth != "" { + req.Header.Add("Authorization", auth) + } + req.SetBodyRaw(body) + + resp := fasthttp.AcquireResponse() + err := c.Client.DoTimeout(req, resp, c.Client.ReadTimeout) + fasthttp.ReleaseRequest(req) + defer fasthttp.ReleaseResponse(resp) + if err != nil { + return []byte{}, err + } + + if resp.StatusCode() != http.StatusOK { + return []byte{}, fmt.Errorf("incorrect status code: %d", resp.StatusCode()) + } + + ret := make([]byte, len(resp.Body())) + copy(ret, resp.Body()) + return ret, nil +} diff --git a/lib/requester/web3.go b/lib/requester/web3.go index 6222bc3..445bd7d 100644 --- a/lib/requester/web3.go +++ b/lib/requester/web3.go @@ -127,3 +127,29 @@ func (c *Client) BroadcastTx(tx *coretypes.Transaction) (string, error) { return "", fmt.Errorf("%s", resp.Error.Message) } + +// Eth_call +func (c *Client) EthCall(address string, data string, height string) ([]byte, error) { + heightString, err := heigthToQueryParam(height) + if err != nil { + return nil, err + } + return c.SendPostRequest( + c.Web3Endpoint, + []byte(`{"method":"eth_call","params":[{"to":"`+address+`","data":"`+data+`"},"`+heightString+`"],"id":1,"jsonrpc":"2.0"}`), + c.Web3Auth, + ) +} + +func heigthToQueryParam(height string) (string, error) { + heightString := "latest" + if height != "latest" { + temp, err := strconv.ParseInt(height, 10, 64) + if err != nil { + return "", fmt.Errorf("invalid height: %s", err.Error()) + } + + heightString = fmt.Sprintf("0x%x", temp) + } + return heightString, nil +} diff --git a/lib/smartcontract/smartcontract.go b/lib/smartcontract/smartcontract.go new file mode 100644 index 0000000..381c430 --- /dev/null +++ b/lib/smartcontract/smartcontract.go @@ -0,0 +1,38 @@ +package smartcontract + +import ( + "encoding/hex" + "fmt" + "strings" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" +) + +func ABIPack(abiBytes []byte, method string, args ...interface{}) (string, error) { + parsedABI, err := abi.JSON(strings.NewReader(string(abiBytes))) + if err != nil { + return "", fmt.Errorf("failed to parse the ABI: %s", err.Error()) + } + + callData, err := parsedABI.Pack(method, args...) + if err != nil { + return "", fmt.Errorf("failed to pack the ABI: %s", err.Error()) + } + + return "0x" + hex.EncodeToString(callData), nil +} + +func StringsToABIArguments(args []string) ([]interface{}, error) { + callArgs := []interface{}{} + for _, v := range args { + value := strings.Split(v, ":") + switch value[0] { + case "a": + callArgs = append(callArgs, common.HexToAddress(value[1])) + default: + return callArgs, fmt.Errorf("invalid param type") + } + } + return callArgs, nil +} diff --git a/playground/cosmosdaemon/cli_helpers.go b/playground/cosmosdaemon/cli_helpers.go index 697fec7..5f83906 100644 --- a/playground/cosmosdaemon/cli_helpers.go +++ b/playground/cosmosdaemon/cli_helpers.go @@ -1,11 +1,14 @@ package cosmosdaemon import ( + "context" "fmt" "path/filepath" + "strconv" "github.com/hanchon/hanchond/playground/database" "github.com/hanchon/hanchond/playground/filesmanager" + "github.com/spf13/cobra" ) func InitMultiNodeChain(nodes []*Daemon, queries *database.Queries) (int64, error) { @@ -146,3 +149,31 @@ func UpdatePeers(nodes []*Daemon, queries *database.Queries) error { } return nil } + +func GetWeb3Endpoint(queries *database.Queries, cmd *cobra.Command) (string, error) { + endpoint := "" + mainnet, _ := cmd.Flags().GetBool("mainnet") + if mainnet { + return "https://proxy.evmos.org/web3", nil + } + + url, _ := cmd.Flags().GetString("url") + if url != "" { + endpoint = url + } else { + nodeID, err := cmd.Flags().GetString("node") + if err != nil { + return "", fmt.Errorf("node not set") + } + validatorID, err := strconv.ParseInt(nodeID, 10, 64) + if err != nil { + return "", err + } + ports, err := queries.GetNodePorts(context.Background(), validatorID) + if err != nil { + return "", err + } + endpoint = fmt.Sprintf("http://localhost:%d", ports.P8545) + } + return endpoint, nil +} diff --git a/vocs.config.ts b/vocs.config.ts index a906e73..1fb2521 100644 --- a/vocs.config.ts +++ b/vocs.config.ts @@ -164,6 +164,10 @@ export default defineConfig({ text: "Deploy a Contract", link: "/hanchond/playground/tx/solidity/deploy", }, + { + text: "Call Contract View", + link: "/hanchond/playground/tx/solidity/contractView", + }, ], }, ], @@ -307,6 +311,10 @@ export default defineConfig({ link: "/lib/smartcontract", collapsed: false, items: [ + { + text: "ABI", + link: "/lib/smartcontract/ABI", + }, { text: "ERC20", link: "/lib/smartcontract/erc20",