Skip to content

Instantly share code, notes, and snippets.

@whilei
Last active October 1, 2019 16:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save whilei/74dd184785c716139428815e2727a299 to your computer and use it in GitHub Desktop.
Save whilei/74dd184785c716139428815e2727a299 to your computer and use it in GitHub Desktop.
// Code generated by go-openrpc. DO NOT EDIT.
/*
Copyright © 2019 NAME HERE <EMAIL ADDRESS>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd
import (
"errors"
"fmt"
"github.com/spf13/cobra"
"log"
"strconv"
"strings"
"bytes"
"io/ioutil"
"net/http"
"os"
"encoding/json"
rpct "github.com/gregdhill/go-openrpc/rpc"
homedir "github.com/mitchellh/go-homedir"
"github.com/spf13/viper"
)
var cfgFile string
var rpcAddr string
// Ethereum JSON-RPC CLI
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "FIXME",
Short: "A brief description of your application",
Long: `A longer description that spans multiple lines and likely contains
examples and usage of using your application. For example:
Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
// Uncomment the following line if your bare application
// has an action associated with it:
// Run: func(cmd *cobra.Command, args []string) { },
}
var errJSONRPC = errors.New("json rpc did return error")
func makeJSONRPCRequest(name string, params []byte) ([]byte, error) {
reqBody := rpct.RPCRequest{
JSONRPC: "2.0",
Method: name,
Params: params,
ID: os.Getpid(), // TODO
}
reqBod, err := json.Marshal(reqBody)
if err != nil {
return nil, err
}
req, err := http.NewRequest("POST", rpcAddr, bytes.NewBuffer(reqBod))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
if resp.StatusCode != 200 {
err = errors.New("request errored")
return body, err
}
errResponse := rpct.RPCErrorResponse{}
err = json.Unmarshal(body, &errResponse)
if err != nil {
return body, err
}
if errResponse.Error != nil {
// Did get error response from server.
return body, errJSONRPC
}
return body, nil
}
func handleJSONRPCResponse(body []byte, err error) {
fmt.Println(string(body))
if err == nil {
os.Exit(0)
}
if err == errJSONRPC {
os.Exit(1)
}
os.Exit(2)
}
// marshalParams returns a JSONified map or array
// If any of the values contain an "=", then a map will
// be used.
// When using a map, if not ALL values contain an =,
// then an error will be thrown.
func marshalParams(params []string) ([]byte, error) {
paramsMapT := make(map[string]interface{})
paramsArrayT := []interface{}{}
if len(params) == 0 {
return json.Marshal(paramsArrayT)
}
useArray := true
for _, a := range params {
if strings.Contains(a, "=") {
useArray = false
}
}
for _, a := range params {
if !useArray && !strings.Contains(a, "=") {
return nil, errors.New("invalid params - when using '=' syntax for an object parameter, all values must be of the format key=value")
}
var key, val string
if !useArray {
kv := strings.Split(a, "=")
key, val = kv[0], kv[1]
} else {
val = a
}
if vint, err := strconv.Atoi(val); err == nil {
paramsMapT[key] = vint
paramsArrayT = append(paramsArrayT, vint)
} else if vbool, err := strconv.ParseBool(val); err == nil {
paramsMapT[key] = vbool
paramsArrayT = append(paramsArrayT, vbool)
} else {
paramsMapT[key] = val
paramsArrayT = append(paramsArrayT, val)
}
}
/*
if verbose {
log.Println("request", )
}
*/
if useArray {
return json.Marshal(paramsArrayT)
}
return json.Marshal(paramsMapT)
}
var web3ClientVersionCmd = &cobra.Command{
Use: "web3_clientVersion",
Short: "current client version",
Long: `
Params: <NONE>
Returns:
"type": "string",
"title": "clientVersion"
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("web3_clientVersion", params)
handleJSONRPCResponse(body, err)
},
}
var web3Sha3Cmd = &cobra.Command{
Use: "web3_sha3",
Short: "Hashes data",
Long: `
Params:
- (0):<data>
"type": "string",
"title": "data",
"pattern": "^0x[a-fA-F\\d]+$"
Returns:
"description": "Hex representation of a Keccak 256 hash",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("web3_sha3", params)
handleJSONRPCResponse(body, err)
},
}
var netListeningCmd = &cobra.Command{
Use: "net_listening",
Short: "returns listening status",
Long: `
Params: <NONE>
Returns:
"type": "boolean",
"title": "isNetListening"
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("net_listening", params)
handleJSONRPCResponse(body, err)
},
}
var netPeerCountCmd = &cobra.Command{
Use: "net_peerCount",
Short: "number of peers",
Long: `
Params: <NONE>
Returns:
"description": "Hex representation of number of connected peers",
"type": "string",
"title": "numConnectedPeers"
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("net_peerCount", params)
handleJSONRPCResponse(body, err)
},
}
var netVersionCmd = &cobra.Command{
Use: "net_version",
Short: "chain ID associated with network",
Long: `
Params: <NONE>
Returns:
"type": "string",
"title": "chainID",
"pattern": "^0x[a-fA-F\\d]+$"
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("net_version", params)
handleJSONRPCResponse(body, err)
},
}
var ethBlockNumberCmd = &cobra.Command{
Use: "eth_blockNumber",
Short: "Returns the number of most recent block.",
Long: `
Params: <NONE>
Returns:
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F\\d]+$"
,
"type": "string",
"enum": [
"earliest",
"latest",
"pending"
]
]
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_blockNumber", params)
handleJSONRPCResponse(body, err)
},
}
var ethCallCmd = &cobra.Command{
Use: "eth_call",
Short: "Executes a new message call (locally) immediately without creating a transaction on the block chain.",
Long: `
Params:
- (0): [Required] <transaction>
"type": "object",
"required": [
"gas",
"gasPrice",
"nonce"
],
"properties":
"blockHash":
"description": "Hash of the block where this transaction was in. null when its pending",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"type": "null"
]
,
"blockNumber":
"description": "Block number where this transaction was in. null when its pending",
"type": "string",
"pattern": "^0x[a-fA-F\\d]+$"
,
"data":
"description": "The data field sent with the transaction",
"type": "string"
,
"from":
"description": "Address of the sender",
"type": "string",
"pattern": "^0x[a-fA-F\\d]40$"
,
"gas":
"description": "The gas limit provided by the sender in Wei",
"type": "string"
,
"gasPrice":
"description": "The gas price willing to be paid by the sender in Wei",
"type": "string"
,
"hash":
"type": "string",
"$ref": "#/components/schemas/Keccak"
,
"nonce":
"description": "The total number of prior transactions made by the sender",
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"r":
"description": "ECDSA signature r",
"type": "string"
,
"s":
"description": "ECDSA signature s",
"type": "string"
,
"to":
"description": "address of the receiver. null when its a contract creation transaction",
"type": "string",
"pattern": "^0x[a-fA-F\\d]40$"
,
"transactionIndex":
"description": "Integer of the transaction's index position in the block. null when its pending",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"type": "null"
]
,
"v":
"description": "ECDSA recovery id",
"type": "string"
,
"value":
"description": "Value of Ether being transferred in Wei",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
- (1): [Required] <blockNumber>
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F\\d]+$"
,
"type": "string",
"enum": [
"earliest",
"latest",
"pending"
]
]
Returns:
"description": "Hex representation of a variable length byte array",
"type": "string",
"pattern": "^0x([a-fA-F0-9]?)+$"
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_call", params)
handleJSONRPCResponse(body, err)
},
}
var ethChainIdCmd = &cobra.Command{
Use: "eth_chainId",
Short: "Returns the currently configured chain id",
Long: `
Params: <NONE>
Returns:
"type": "string",
"title": "chainId",
"pattern": "^0x[a-fA-F\\d]+$"
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_chainId", params)
handleJSONRPCResponse(body, err)
},
}
var ethCoinbaseCmd = &cobra.Command{
Use: "eth_coinbase",
Short: "Returns the client coinbase address.",
Long: `
Params: <NONE>
Returns:
"type": "string",
"pattern": "^0x[a-fA-F\\d]40$"
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_coinbase", params)
handleJSONRPCResponse(body, err)
},
}
var ethEstimateGasCmd = &cobra.Command{
Use: "eth_estimateGas",
Short: "Generates and returns an estimate of how much gas is necessary to allow the transaction to complete. The transaction will not be added to the blockchain. Note that the estimate may be significantly more than the amount of gas actually used by the transaction, for a variety of reasons including EVM mechanics and node performance.",
Long: `
Params:
- (0): [Required] <transaction>
"type": "object",
"required": [
"gas",
"gasPrice",
"nonce"
],
"properties":
"blockHash":
"description": "Hash of the block where this transaction was in. null when its pending",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"type": "null"
]
,
"blockNumber":
"description": "Block number where this transaction was in. null when its pending",
"type": "string",
"pattern": "^0x[a-fA-F\\d]+$"
,
"data":
"description": "The data field sent with the transaction",
"type": "string"
,
"from":
"description": "Address of the sender",
"type": "string",
"pattern": "^0x[a-fA-F\\d]40$"
,
"gas":
"description": "The gas limit provided by the sender in Wei",
"type": "string"
,
"gasPrice":
"description": "The gas price willing to be paid by the sender in Wei",
"type": "string"
,
"hash":
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"nonce":
"description": "The total number of prior transactions made by the sender",
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"r":
"description": "ECDSA signature r",
"type": "string"
,
"s":
"description": "ECDSA signature s",
"type": "string"
,
"to":
"description": "address of the receiver. null when its a contract creation transaction",
"type": "string",
"pattern": "^0x[a-fA-F\\d]40$"
,
"transactionIndex":
"description": "Integer of the transaction's index position in the block. null when its pending",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"type": "null"
]
,
"v":
"description": "ECDSA recovery id",
"type": "string"
,
"value":
"description": "Value of Ether being transferred in Wei",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
Returns:
"description": "Hex representation of the integer",
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_estimateGas", params)
handleJSONRPCResponse(body, err)
},
}
var ethGasPriceCmd = &cobra.Command{
Use: "eth_gasPrice",
Short: "Returns the current price per gas in wei",
Long: `
Params: <NONE>
Returns:
"description": "Hex representation of the integer",
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_gasPrice", params)
handleJSONRPCResponse(body, err)
},
}
var ethGetBalanceCmd = &cobra.Command{
Use: "eth_getBalance",
Short: "Returns Ether balance of a given or account or contract",
Long: `
Params:
- (0): [Required] <address>
"type": "string",
"pattern": "^0x[a-fA-F\\d]40$"
- (1):<blockNumber>
"description": "The hex representation of the block's height",
"type": "string",
"pattern": "^0x[a-fA-F\\d]+$"
Returns:
"title": "getBalanceResult",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"type": "null"
]
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_getBalance", params)
handleJSONRPCResponse(body, err)
},
}
var ethGetBlockByHashCmd = &cobra.Command{
Use: "eth_getBlockByHash",
Short: "Gets a block for a given hash",
Long: `
Params:
- (0): [Required] <blockHash>
"description": "The hex representation of the Keccak 256 of the RLP encoded block",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
- (1): [Required] <includeTransactions>
"type": "boolean",
"title": "isTransactionsIncluded"
Returns:
"title": "getBlockByHashResult",
"oneOf": [
"type": "object",
"properties":
"difficulty":
"description": "Integer of the difficulty for this block",
"type": "string"
,
"extraData":
"description": "The 'extra data' field of this block",
"type": "string"
,
"gasLimit":
"description": "The maximum gas allowed in this block",
"type": "string"
,
"gasUsed":
"description": "The total used gas by all transactions in this block",
"type": "string"
,
"hash":
"description": "The block hash or null when its the pending block",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"type": "null"
]
,
"logsBloom":
"description": "The bloom filter for the logs of the block or null when its the pending block",
"type": "string",
"pattern": "^0x[a-fA-F\\d]+$"
,
"miner":
"description": "The address of the beneficiary to whom the mining rewards were given or null when its the pending block",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F\\d]40$"
,
"type": "null"
]
,
"nonce":
"description": "Randomly selected number to satisfy the proof-of-work or null when its the pending block",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"type": "null"
]
,
"number":
"description": "The block number or null when its the pending block",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"type": "null"
]
,
"parentHash":
"description": "Hash of the parent block",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"receiptsRoot":
"description": "The root of the receipts trie of the block",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"sha3Uncles":
"description": "Keccak hash of the uncles data in the block",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"size":
"description": "Integer the size of this block in bytes",
"type": "string"
,
"stateRoot":
"description": "The root of the final state trie of the block",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"timestamp":
"description": "The unix timestamp for when the block was collated",
"type": "string"
,
"totalDifficulty":
"description": "Integer of the total difficulty of the chain until this block",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"type": "null"
]
,
"transactions":
"description": "Array of transaction objects, or 32 Bytes transaction hashes depending on the last given parameter",
"type": "array",
"items":
"oneOf": [
"$ref": "#/components/schemas/Transaction"
,
"$ref": "#/components/schemas/TransactionHash"
]
,
"transactionsRoot":
"description": "The root of the transactions trie of the block.",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"uncles":
"description": "Array of uncle hashes",
"type": "array",
"items":
"description": "Block hash of the RLP encoding of an uncle block",
"$ref": "#/components/schemas/Keccak"
,
"type": "null"
]
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_getBlockByHash", params)
handleJSONRPCResponse(body, err)
},
}
var ethGetBlockByNumberCmd = &cobra.Command{
Use: "eth_getBlockByNumber",
Short: "Gets a block for a given number salad",
Long: `
Params:
- (0): [Required] <blockNumber>
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F\\d]+$"
,
"type": "string",
"enum": [
"earliest",
"latest",
"pending"
]
]
- (1): [Required] <includeTransactions>
"type": "boolean",
"title": "isTransactionsIncluded"
Returns:
"title": "getBlockByNumberResult",
"oneOf": [
"type": "object",
"properties":
"difficulty":
"description": "Integer of the difficulty for this block",
"type": "string"
,
"extraData":
"description": "The 'extra data' field of this block",
"type": "string"
,
"gasLimit":
"description": "The maximum gas allowed in this block",
"type": "string"
,
"gasUsed":
"description": "The total used gas by all transactions in this block",
"type": "string"
,
"hash":
"description": "The block hash or null when its the pending block",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"type": "null"
]
,
"logsBloom":
"description": "The bloom filter for the logs of the block or null when its the pending block",
"type": "string",
"pattern": "^0x[a-fA-F\\d]+$"
,
"miner":
"description": "The address of the beneficiary to whom the mining rewards were given or null when its the pending block",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F\\d]40$"
,
"type": "null"
]
,
"nonce":
"description": "Randomly selected number to satisfy the proof-of-work or null when its the pending block",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"type": "null"
]
,
"number":
"description": "The block number or null when its the pending block",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"type": "null"
]
,
"parentHash":
"description": "Hash of the parent block",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"receiptsRoot":
"description": "The root of the receipts trie of the block",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"sha3Uncles":
"description": "Keccak hash of the uncles data in the block",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"size":
"description": "Integer the size of this block in bytes",
"type": "string"
,
"stateRoot":
"description": "The root of the final state trie of the block",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"timestamp":
"description": "The unix timestamp for when the block was collated",
"type": "string"
,
"totalDifficulty":
"description": "Integer of the total difficulty of the chain until this block",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"type": "null"
]
,
"transactions":
"description": "Array of transaction objects, or 32 Bytes transaction hashes depending on the last given parameter",
"type": "array",
"items":
"oneOf": [
"$ref": "#/components/schemas/Transaction"
,
"$ref": "#/components/schemas/TransactionHash"
]
,
"transactionsRoot":
"description": "The root of the transactions trie of the block.",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"uncles":
"description": "Array of uncle hashes",
"type": "array",
"items":
"description": "Block hash of the RLP encoding of an uncle block",
"$ref": "#/components/schemas/Keccak"
,
"type": "null"
]
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_getBlockByNumber", params)
handleJSONRPCResponse(body, err)
},
}
var ethGetBlockTransactionCountByHashCmd = &cobra.Command{
Use: "eth_getBlockTransactionCountByHash",
Short: "Returns the number of transactions in a block from a block matching the given block hash.",
Long: `
Params:
- (0): [Required] <blockHash>
"description": "The hex representation of the Keccak 256 of the RLP encoded block",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
Returns:
"title": "blockTransactionCountByHash",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"type": "null"
]
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_getBlockTransactionCountByHash", params)
handleJSONRPCResponse(body, err)
},
}
var ethGetBlockTransactionCountByNumberCmd = &cobra.Command{
Use: "eth_getBlockTransactionCountByNumber",
Short: "Returns the number of transactions in a block from a block matching the given block number.",
Long: `
Params:
- (0): [Required] <blockNumber>
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F\\d]+$"
,
"type": "string",
"enum": [
"earliest",
"latest",
"pending"
]
]
Returns:
"title": "blockTransactionCountByHash",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"type": "null"
]
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_getBlockTransactionCountByNumber", params)
handleJSONRPCResponse(body, err)
},
}
var ethGetCodeCmd = &cobra.Command{
Use: "eth_getCode",
Short: "Returns code at a given contract address",
Long: `
Params:
- (0): [Required] <address>
"type": "string",
"pattern": "^0x[a-fA-F\\d]40$"
- (1):<blockNumber>
"description": "The hex representation of the block's height",
"type": "string",
"pattern": "^0x[a-fA-F\\d]+$"
Returns:
"description": "Hex representation of a variable length byte array",
"type": "string",
"pattern": "^0x([a-fA-F0-9]?)+$"
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_getCode", params)
handleJSONRPCResponse(body, err)
},
}
var ethGetFilterChangesCmd = &cobra.Command{
Use: "eth_getFilterChanges",
Short: "Polling method for a filter, which returns an array of logs which occurred since last poll.",
Long: `
Params:
- (0): [Required] <filterId>
"description": "An identifier used to reference the filter.",
"type": "string"
Returns:
"type": "array",
"title": "logResult",
"items":
"$ref": "#/components/schemas/Log"
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_getFilterChanges", params)
handleJSONRPCResponse(body, err)
},
}
var ethGetFilterLogsCmd = &cobra.Command{
Use: "eth_getFilterLogs",
Short: "Returns an array of all logs matching filter with given id.",
Long: `
Params:
- (0): [Required] <filterId>
"description": "An identifier used to reference the filter.",
"type": "string"
Returns:
"type": "array",
"items":
"$ref": "#/components/schemas/Log"
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_getFilterLogs", params)
handleJSONRPCResponse(body, err)
},
}
var ethGetRawTransactionByHashCmd = &cobra.Command{
Use: "eth_getRawTransactionByHash",
Short: "Returns raw transaction data of a transaction with the given hash.",
Long: `
Params:
- (0): [Required] <transactionHash>
"description": "Keccak 256 Hash of the RLP encoding of a transaction",
"type": "string",
"$ref": "#/components/schemas/Keccak"
Returns:
"description": "Hex representation of a variable length byte array",
"type": "string",
"pattern": "^0x([a-fA-F0-9]?)+$"
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_getRawTransactionByHash", params)
handleJSONRPCResponse(body, err)
},
}
var ethGetRawTransactionByBlockHashAndIndexCmd = &cobra.Command{
Use: "eth_getRawTransactionByBlockHashAndIndex",
Short: "Returns raw transaction data of a transaction with the given hash.",
Long: `
Params:
- (0): [Required] <blockHash>
"description": "The hex representation of the Keccak 256 of the RLP encoded block",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
- (1): [Required] <index>
"description": "Hex representation of the integer",
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
Returns:
"description": "Hex representation of a variable length byte array",
"type": "string",
"pattern": "^0x([a-fA-F0-9]?)+$"
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_getRawTransactionByBlockHashAndIndex", params)
handleJSONRPCResponse(body, err)
},
}
var ethGetRawTransactionByBlockNumberAndIndexCmd = &cobra.Command{
Use: "eth_getRawTransactionByBlockNumberAndIndex",
Short: "Returns raw transaction data of a transaction with the given hash.",
Long: `
Params:
- (0): [Required] <blockNumber>
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F\\d]+$"
,
"type": "string",
"enum": [
"earliest",
"latest",
"pending"
]
]
- (1): [Required] <index>
"description": "Hex representation of the integer",
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
Returns:
"description": "Hex representation of a variable length byte array",
"type": "string",
"pattern": "^0x([a-fA-F0-9]?)+$"
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_getRawTransactionByBlockNumberAndIndex", params)
handleJSONRPCResponse(body, err)
},
}
var ethGetLogsCmd = &cobra.Command{
Use: "eth_getLogs",
Short: "Returns an array of all logs matching a given filter object.",
Long: `
Params:
- (0): [Required] <filter>
"description": "A filter used to monitor the blockchain for log/events",
"type": "object",
"properties":
"address":
"oneOf": [
"description": "Address of the contract from which to monitor events",
"type": "string",
"pattern": "^0x[a-fA-F\\d]40$"
,
"description": "List of contract addresses from which to monitor events",
"type": "array",
"items":
"$ref": "#/components/schemas/Address"
]
,
"fromBlock":
"description": "Block from which to begin filtering events",
"type": "string",
"pattern": "^0x[a-fA-F\\d]+$"
,
"toBlock":
"description": "Block from which to end filtering events",
"type": "string",
"pattern": "^0x[a-fA-F\\d]+$"
,
"topics":
"description": "Array of 32 Bytes DATA topics. Topics are order-dependent. Each topic can also be an array of DATA with 'or' options",
"type": "array",
"items":
"description": "Indexable 32 bytes piece of data (made from the event's function signature in solidity)",
"$ref": "#/components/schemas/DataWord"
Returns:
"type": "array",
"items":
"$ref": "#/components/schemas/Log"
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_getLogs", params)
handleJSONRPCResponse(body, err)
},
}
var ethGetStorageAtCmd = &cobra.Command{
Use: "eth_getStorageAt",
Short: "Gets a storage value from a contract address, a position, and an optional blockNumber",
Long: `
Params:
- (0): [Required] <address>
"type": "string",
"pattern": "^0x[a-fA-F\\d]40$"
- (1): [Required] <key>
"description": "Hex representation of the storage slot where the variable exists",
"type": "string",
"pattern": "^0x([a-fA-F0-9]?)+$"
- (2): [Required] <blockNumber>
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F\\d]+$"
,
"type": "string",
"enum": [
"earliest",
"latest",
"pending"
]
]
Returns:
"description": "Hex representation of a 256 bit unit of data",
"type": "string",
"pattern": "^0x([a-fA-F\\d]64)?$"
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_getStorageAt", params)
handleJSONRPCResponse(body, err)
},
}
var ethGetTransactionByBlockHashAndIndexCmd = &cobra.Command{
Use: "eth_getTransactionByBlockHashAndIndex",
Short: "Returns the information about a transaction requested by the block hash and index of which it was mined.",
Long: `
Params:
- (0): [Required] <blockHash>
"description": "The hex representation of the Keccak 256 of the RLP encoded block",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
- (1): [Required] <index>
"description": "Hex representation of the integer",
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
Returns:
"oneOf": [
"type": "object",
"required": [
"gas",
"gasPrice",
"nonce"
],
"properties":
"blockHash":
"description": "Hash of the block where this transaction was in. null when its pending",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"type": "null"
]
,
"blockNumber":
"description": "Block number where this transaction was in. null when its pending",
"type": "string",
"pattern": "^0x[a-fA-F\\d]+$"
,
"data":
"description": "The data field sent with the transaction",
"type": "string"
,
"from":
"description": "Address of the sender",
"type": "string",
"pattern": "^0x[a-fA-F\\d]40$"
,
"gas":
"description": "The gas limit provided by the sender in Wei",
"type": "string"
,
"gasPrice":
"description": "The gas price willing to be paid by the sender in Wei",
"type": "string"
,
"hash":
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"nonce":
"description": "The total number of prior transactions made by the sender",
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"r":
"description": "ECDSA signature r",
"type": "string"
,
"s":
"description": "ECDSA signature s",
"type": "string"
,
"to":
"description": "address of the receiver. null when its a contract creation transaction",
"type": "string",
"pattern": "^0x[a-fA-F\\d]40$"
,
"transactionIndex":
"description": "Integer of the transaction's index position in the block. null when its pending",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"type": "null"
]
,
"v":
"description": "ECDSA recovery id",
"type": "string"
,
"value":
"description": "Value of Ether being transferred in Wei",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"type": "null"
]
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_getTransactionByBlockHashAndIndex", params)
handleJSONRPCResponse(body, err)
},
}
var ethGetTransactionByBlockNumberAndIndexCmd = &cobra.Command{
Use: "eth_getTransactionByBlockNumberAndIndex",
Short: "Returns the information about a transaction requested by the block hash and index of which it was mined.",
Long: `
Params:
- (0): [Required] <blockNumber>
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F\\d]+$"
,
"type": "string",
"enum": [
"earliest",
"latest",
"pending"
]
]
- (1): [Required] <index>
"description": "Hex representation of the integer",
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
Returns:
"oneOf": [
"type": "object",
"required": [
"gas",
"gasPrice",
"nonce"
],
"properties":
"blockHash":
"description": "Hash of the block where this transaction was in. null when its pending",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"type": "null"
]
,
"blockNumber":
"description": "Block number where this transaction was in. null when its pending",
"type": "string",
"pattern": "^0x[a-fA-F\\d]+$"
,
"data":
"description": "The data field sent with the transaction",
"type": "string"
,
"from":
"description": "Address of the sender",
"type": "string",
"pattern": "^0x[a-fA-F\\d]40$"
,
"gas":
"description": "The gas limit provided by the sender in Wei",
"type": "string"
,
"gasPrice":
"description": "The gas price willing to be paid by the sender in Wei",
"type": "string"
,
"hash":
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"nonce":
"description": "The total number of prior transactions made by the sender",
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"r":
"description": "ECDSA signature r",
"type": "string"
,
"s":
"description": "ECDSA signature s",
"type": "string"
,
"to":
"description": "address of the receiver. null when its a contract creation transaction",
"type": "string",
"pattern": "^0x[a-fA-F\\d]40$"
,
"transactionIndex":
"description": "Integer of the transaction's index position in the block. null when its pending",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"type": "null"
]
,
"v":
"description": "ECDSA recovery id",
"type": "string"
,
"value":
"description": "Value of Ether being transferred in Wei",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"type": "null"
]
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_getTransactionByBlockNumberAndIndex", params)
handleJSONRPCResponse(body, err)
},
}
var ethGetTransactionByHashCmd = &cobra.Command{
Use: "eth_getTransactionByHash",
Short: "Returns the information about a transaction requested by transaction hash.",
Long: `
Params:
- (0): [Required] <transactionHash>
"description": "Keccak 256 Hash of the RLP encoding of a transaction",
"type": "string",
"$ref": "#/components/schemas/Keccak"
Returns:
"oneOf": [
"type": "object",
"required": [
"gas",
"gasPrice",
"nonce"
],
"properties":
"blockHash":
"description": "Hash of the block where this transaction was in. null when its pending",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"type": "null"
]
,
"blockNumber":
"description": "Block number where this transaction was in. null when its pending",
"type": "string",
"pattern": "^0x[a-fA-F\\d]+$"
,
"data":
"description": "The data field sent with the transaction",
"type": "string"
,
"from":
"description": "Address of the sender",
"type": "string",
"pattern": "^0x[a-fA-F\\d]40$"
,
"gas":
"description": "The gas limit provided by the sender in Wei",
"type": "string"
,
"gasPrice":
"description": "The gas price willing to be paid by the sender in Wei",
"type": "string"
,
"hash":
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"nonce":
"description": "The total number of prior transactions made by the sender",
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"r":
"description": "ECDSA signature r",
"type": "string"
,
"s":
"description": "ECDSA signature s",
"type": "string"
,
"to":
"description": "address of the receiver. null when its a contract creation transaction",
"type": "string",
"pattern": "^0x[a-fA-F\\d]40$"
,
"transactionIndex":
"description": "Integer of the transaction's index position in the block. null when its pending",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"type": "null"
]
,
"v":
"description": "ECDSA recovery id",
"type": "string"
,
"value":
"description": "Value of Ether being transferred in Wei",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"type": "null"
]
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_getTransactionByHash", params)
handleJSONRPCResponse(body, err)
},
}
var ethGetTransactionCountCmd = &cobra.Command{
Use: "eth_getTransactionCount",
Short: "Returns the number of transactions sent from an address",
Long: `
Params:
- (0): [Required] <address>
"type": "string",
"pattern": "^0x[a-fA-F\\d]40$"
- (1): [Required] <blockNumber>
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F\\d]+$"
,
"type": "string",
"enum": [
"earliest",
"latest",
"pending"
]
]
Returns:
"title": "nonceOrNull",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"type": "null"
]
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_getTransactionCount", params)
handleJSONRPCResponse(body, err)
},
}
var ethGetTransactionReceiptCmd = &cobra.Command{
Use: "eth_getTransactionReceipt",
Short: "Returns the receipt information of a transaction by its hash.",
Long: `
Params:
- (0): [Required] <transactionHash>
"description": "Keccak 256 Hash of the RLP encoding of a transaction",
"type": "string",
"$ref": "#/components/schemas/Keccak"
Returns:
"title": "receipt",
"oneOf": [
"type": "object",
"required": [
"blockHash",
"blockNumber",
"contractAddress",
"cumulativeGasUsed",
"from",
"gasUsed",
"logs",
"logsBloom",
"to",
"transactionHash",
"transactionIndex"
],
"properties":
"blockHash":
"description": "BlockHash of the block in which the transaction was mined",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"blockNumber":
"description": "BlockNumber of the block in which the transaction was mined",
"type": "string",
"pattern": "^0x[a-fA-F\\d]+$"
,
"contractAddress":
"description": "The contract address created, if the transaction was a contract creation, otherwise null",
"type": "string",
"pattern": "^0x[a-fA-F\\d]40$"
,
"cumulativeGasUsed":
"description": "The gas units used by the transaction",
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"from":
"description": "The sender of the transaction",
"type": "string",
"pattern": "^0x[a-fA-F\\d]40$"
,
"gasUsed":
"description": "The total gas used by the transaction",
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"logs":
"description": "An array of all the logs triggered during the transaction",
"type": "array",
"items":
"$ref": "#/components/schemas/Log"
,
"logsBloom":
"type": "string"
,
"postTransactionState":
"description": "The intermediate stateRoot directly after transaction execution.",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"status":
"description": "Whether or not the transaction threw an error.",
"type": "string"
,
"to":
"description": "Destination address of the transaction",
"type": "string",
"pattern": "^0x[a-fA-F\\d]40$"
,
"transactionHash":
"description": "Keccak 256 of the transaction",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"transactionIndex":
"description": "An array of all the logs triggered during the transaction",
"type": "string"
,
"type": "null"
]
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_getTransactionReceipt", params)
handleJSONRPCResponse(body, err)
},
}
var ethGetUncleByBlockHashAndIndexCmd = &cobra.Command{
Use: "eth_getUncleByBlockHashAndIndex",
Short: "Returns information about a uncle of a block by hash and uncle index position.",
Long: `
Params:
- (0): [Required] <blockHash>
"description": "The hex representation of the Keccak 256 of the RLP encoded block",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
- (1): [Required] <index>
"description": "Hex representation of the integer",
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
Returns:
"title": "uncleOrNull",
"oneOf": [
"type": "object",
"properties":
"difficulty":
"description": "Integer of the difficulty for this block",
"type": "string"
,
"extraData":
"description": "The 'extra data' field of this block",
"type": "string"
,
"gasLimit":
"description": "The maximum gas allowed in this block",
"type": "string"
,
"gasUsed":
"description": "The total used gas by all transactions in this block",
"type": "string"
,
"hash":
"description": "The block hash or null when its the pending block",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"type": "null"
]
,
"logsBloom":
"description": "The bloom filter for the logs of the block or null when its the pending block",
"type": "string",
"pattern": "^0x[a-fA-F\\d]+$"
,
"miner":
"description": "The address of the beneficiary to whom the mining rewards were given or null when its the pending block",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F\\d]40$"
,
"type": "null"
]
,
"nonce":
"description": "Randomly selected number to satisfy the proof-of-work or null when its the pending block",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"type": "null"
]
,
"number":
"description": "The block number or null when its the pending block",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"type": "null"
]
,
"parentHash":
"description": "Hash of the parent block",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"receiptsRoot":
"description": "The root of the receipts trie of the block",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"sha3Uncles":
"description": "Keccak hash of the uncles data in the block",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"size":
"description": "Integer the size of this block in bytes",
"type": "string"
,
"stateRoot":
"description": "The root of the final state trie of the block",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"timestamp":
"description": "The unix timestamp for when the block was collated",
"type": "string"
,
"totalDifficulty":
"description": "Integer of the total difficulty of the chain until this block",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"type": "null"
]
,
"transactionsRoot":
"description": "The root of the transactions trie of the block.",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"uncles":
"description": "Array of uncle hashes",
"type": "array",
"items":
"description": "Block hash of the RLP encoding of an uncle block",
"$ref": "#/components/schemas/Keccak"
,
"type": "null"
]
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_getUncleByBlockHashAndIndex", params)
handleJSONRPCResponse(body, err)
},
}
var ethGetUncleByBlockNumberAndIndexCmd = &cobra.Command{
Use: "eth_getUncleByBlockNumberAndIndex",
Short: "Returns information about a uncle of a block by hash and uncle index position.",
Long: `
Params:
- (0): [Required] <uncleBlockNumber>
"description": "The hex representation of the block's height",
"type": "string",
"pattern": "^0x[a-fA-F\\d]+$"
- (1): [Required] <index>
"description": "Hex representation of the integer",
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
Returns:
"oneOf": [
"type": "object",
"properties":
"difficulty":
"description": "Integer of the difficulty for this block",
"type": "string"
,
"extraData":
"description": "The 'extra data' field of this block",
"type": "string"
,
"gasLimit":
"description": "The maximum gas allowed in this block",
"type": "string"
,
"gasUsed":
"description": "The total used gas by all transactions in this block",
"type": "string"
,
"hash":
"description": "The block hash or null when its the pending block",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"type": "null"
]
,
"logsBloom":
"description": "The bloom filter for the logs of the block or null when its the pending block",
"type": "string",
"pattern": "^0x[a-fA-F\\d]+$"
,
"miner":
"description": "The address of the beneficiary to whom the mining rewards were given or null when its the pending block",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F\\d]40$"
,
"type": "null"
]
,
"nonce":
"description": "Randomly selected number to satisfy the proof-of-work or null when its the pending block",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"type": "null"
]
,
"number":
"description": "The block number or null when its the pending block",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"type": "null"
]
,
"parentHash":
"description": "Hash of the parent block",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"receiptsRoot":
"description": "The root of the receipts trie of the block",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"sha3Uncles":
"description": "Keccak hash of the uncles data in the block",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"size":
"description": "Integer the size of this block in bytes",
"type": "string"
,
"stateRoot":
"description": "The root of the final state trie of the block",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"timestamp":
"description": "The unix timestamp for when the block was collated",
"type": "string"
,
"totalDifficulty":
"description": "Integer of the total difficulty of the chain until this block",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"type": "null"
]
,
"transactionsRoot":
"description": "The root of the transactions trie of the block.",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"uncles":
"description": "Array of uncle hashes",
"type": "array",
"items":
"description": "Block hash of the RLP encoding of an uncle block",
"$ref": "#/components/schemas/Keccak"
,
"type": "null"
]
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_getUncleByBlockNumberAndIndex", params)
handleJSONRPCResponse(body, err)
},
}
var ethGetUncleCountByBlockHashCmd = &cobra.Command{
Use: "eth_getUncleCountByBlockHash",
Short: "Returns the number of uncles in a block from a block matching the given block hash.",
Long: `
Params:
- (0): [Required] <blockHash>
"description": "The hex representation of the Keccak 256 of the RLP encoded block",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
Returns:
"title": "uncleCountOrNull",
"oneOf": [
"description": "The Number of total uncles in the given block",
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"type": "null"
]
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_getUncleCountByBlockHash", params)
handleJSONRPCResponse(body, err)
},
}
var ethGetUncleCountByBlockNumberCmd = &cobra.Command{
Use: "eth_getUncleCountByBlockNumber",
Short: "Returns the number of uncles in a block from a block matching the given block number.",
Long: `
Params:
- (0): [Required] <blockNumber>
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F\\d]+$"
,
"type": "string",
"enum": [
"earliest",
"latest",
"pending"
]
]
Returns:
"title": "uncleCountOrNull",
"oneOf": [
"description": "The Number of total uncles in the given block",
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"type": "null"
]
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_getUncleCountByBlockNumber", params)
handleJSONRPCResponse(body, err)
},
}
var ethGetProofCmd = &cobra.Command{
Use: "eth_getProof",
Short: "Returns the account- and storage-values of the specified account including the Merkle-proof.",
Long: `
Params:
- (0): [Required] <address>
"type": "string",
"pattern": "^0x[a-fA-F\\d]40$"
- (1): [Required] <storageKeys>
"description": "The storage keys of all the storage slots being requested",
"title": "storageKeys",
"items":
"description": "A storage key is indexed from the solidity compiler by the order it is declared. For mappings it uses the keccak of the mapping key with its position (and recursively for X-dimensional mappings)",
"$ref": "#/components/schemas/Integer"
- (2): [Required] <blockNumber>
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F\\d]+$"
,
"type": "string",
"enum": [
"earliest",
"latest",
"pending"
]
]
Returns:
"title": "proofAccountOrNull",
"oneOf": [
"description": "The merkle proofs of the specified account connecting them to the blockhash of the block specified",
"type": "object",
"title": "proofAccount",
"properties":
"accountProof":
"$ref": "#/components/schemas/ProofNodes"
,
"address":
"description": "The address of the account or contract of the request",
"type": "string",
"pattern": "^0x[a-fA-F\\d]40$"
,
"balance":
"description": "The Ether balance of the account or contract of the request",
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"codeHash":
"description": "The code hash of the contract of the request (keccak(NULL) if external account)",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"nonce":
"description": "The transaction count of the account or contract of the request",
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"storageHash":
"description": "The storage hash of the contract of the request (keccak(rlp(NULL)) if external account)",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"storageProof":
"type": "array",
"items":
"description": "Object proving a relationship of a storage value to an account's storageHash.",
"type": "object",
"properties":
"key":
"description": "The key used to get the storage slot in its account tree",
"$ref": "#/components/schemas/Integer"
,
"proof":
"$ref": "#/components/schemas/ProofNodes"
,
"value":
"description": "The value of the storage slot in its account tree",
"$ref": "#/components/schemas/Integer"
,
"type": "null"
]
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_getProof", params)
handleJSONRPCResponse(body, err)
},
}
var ethGetWorkCmd = &cobra.Command{
Use: "eth_getWork",
Short: "Returns the hash of the current block, the seedHash, and the boundary condition to be met ('target').",
Long: `
Params: <NONE>
Returns:
"type": "array",
"items": [
"$ref": "#/components/schemas/DataWord"
,
"$ref": "#/components/schemas/DataWord"
,
"$ref": "#/components/schemas/DataWord"
]
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_getWork", params)
handleJSONRPCResponse(body, err)
},
}
var ethHashrateCmd = &cobra.Command{
Use: "eth_hashrate",
Short: "Returns the number of hashes per second that the node is mining with.",
Long: `
Params: <NONE>
Returns:
"description": "Hex representation of the integer",
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_hashrate", params)
handleJSONRPCResponse(body, err)
},
}
var ethMiningCmd = &cobra.Command{
Use: "eth_mining",
Short: "Returns true if client is actively mining new blocks.",
Long: `
Params: <NONE>
Returns:
"description": "Whether of not the client is mining",
"type": "boolean"
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_mining", params)
handleJSONRPCResponse(body, err)
},
}
var ethNewBlockFilterCmd = &cobra.Command{
Use: "eth_newBlockFilter",
Short: "Creates a filter in the node, to notify when a new block arrives. To check if the state has changed, call eth_getFilterChanges.",
Long: `
Params: <NONE>
Returns:
"description": "Hex representation of the integer",
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_newBlockFilter", params)
handleJSONRPCResponse(body, err)
},
}
var ethNewFilterCmd = &cobra.Command{
Use: "eth_newFilter",
Short: "Creates a filter object, based on filter options, to notify when the state changes (logs). To check if the state has changed, call eth_getFilterChanges.",
Long: `
Params:
- (0): [Required] <filter>
"description": "A filter used to monitor the blockchain for log/events",
"type": "object",
"properties":
"address":
"oneOf": [
"description": "Address of the contract from which to monitor events",
"type": "string",
"pattern": "^0x[a-fA-F\\d]40$"
,
"description": "List of contract addresses from which to monitor events",
"type": "array",
"items":
"$ref": "#/components/schemas/Address"
]
,
"fromBlock":
"description": "Block from which to begin filtering events",
"type": "string",
"pattern": "^0x[a-fA-F\\d]+$"
,
"toBlock":
"description": "Block from which to end filtering events",
"type": "string",
"pattern": "^0x[a-fA-F\\d]+$"
,
"topics":
"description": "Array of 32 Bytes DATA topics. Topics are order-dependent. Each topic can also be an array of DATA with 'or' options",
"type": "array",
"items":
"description": "Indexable 32 bytes piece of data (made from the event's function signature in solidity)",
"$ref": "#/components/schemas/DataWord"
Returns:
"description": "Hex representation of the integer",
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_newFilter", params)
handleJSONRPCResponse(body, err)
},
}
var ethNewPendingTransactionFilterCmd = &cobra.Command{
Use: "eth_newPendingTransactionFilter",
Short: "Creates a filter in the node, to notify when new pending transactions arrive. To check if the state has changed, call eth_getFilterChanges.",
Long: `
Params: <NONE>
Returns:
"description": "Hex representation of the integer",
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_newPendingTransactionFilter", params)
handleJSONRPCResponse(body, err)
},
}
var ethPendingTransactionsCmd = &cobra.Command{
Use: "eth_pendingTransactions",
Short: "Returns the pending transactions list",
Long: `
Params: <NONE>
Returns:
"type": "array",
"items":
"$ref": "#/components/schemas/Transaction"
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_pendingTransactions", params)
handleJSONRPCResponse(body, err)
},
}
var ethProtocolVersionCmd = &cobra.Command{
Use: "eth_protocolVersion",
Short: "Returns the current ethereum protocol version.",
Long: `
Params: <NONE>
Returns:
"description": "Hex representation of the integer",
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_protocolVersion", params)
handleJSONRPCResponse(body, err)
},
}
var ethSignCmd = &cobra.Command{
Use: "eth_sign",
Short: "The sign method calculates an Ethereum specific signature.",
Long: `
Params:
- (0):<>
"type": "string",
"pattern": "^0x[a-fA-F\\d]40$"
- (1):<>
"description": "Hex representation of a variable length byte array",
"type": "string",
"pattern": "^0x([a-fA-F0-9]?)+$"
Returns:
"description": "Hex representation of a variable length byte array",
"type": "string",
"pattern": "^0x([a-fA-F0-9]?)+$"
`,
Deprecated: "DEPRECATED: Use at your own risk.",
PreRun: func(cmd *cobra.Command, args []string) {
log.Println("WARNING: This method (eth_sign) is deprecated. Use at your own risk.")
},
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_sign", params)
handleJSONRPCResponse(body, err)
},
}
var ethAccountsCmd = &cobra.Command{
Use: "eth_accounts",
Short: "Returns a list of addresses owned by client.",
Long: `
Params: <NONE>
Returns:
"type": "array",
"items":
"$ref": "#/components/schemas/Address"
`,
Deprecated: "DEPRECATED: Use at your own risk.",
PreRun: func(cmd *cobra.Command, args []string) {
log.Println("WARNING: This method (eth_accounts) is deprecated. Use at your own risk.")
},
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_accounts", params)
handleJSONRPCResponse(body, err)
},
}
var ethSendTransactionCmd = &cobra.Command{
Use: "eth_sendTransaction",
Short: "Creates new message call transaction or a contract creation, if the data field contains code.",
Long: `
Params:
- (0): [Required] <transaction>
"type": "object",
"required": [
"gas",
"gasPrice",
"nonce"
],
"properties":
"blockHash":
"description": "Hash of the block where this transaction was in. null when its pending",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"type": "null"
]
,
"blockNumber":
"description": "Block number where this transaction was in. null when its pending",
"type": "string",
"pattern": "^0x[a-fA-F\\d]+$"
,
"data":
"description": "The data field sent with the transaction",
"type": "string"
,
"from":
"description": "Address of the sender",
"type": "string",
"pattern": "^0x[a-fA-F\\d]40$"
,
"gas":
"description": "The gas limit provided by the sender in Wei",
"type": "string"
,
"gasPrice":
"description": "The gas price willing to be paid by the sender in Wei",
"type": "string"
,
"hash":
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
,
"nonce":
"description": "The total number of prior transactions made by the sender",
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"r":
"description": "ECDSA signature r",
"type": "string"
,
"s":
"description": "ECDSA signature s",
"type": "string"
,
"to":
"description": "address of the receiver. null when its a contract creation transaction",
"type": "string",
"pattern": "^0x[a-fA-F\\d]40$"
,
"transactionIndex":
"description": "Integer of the transaction's index position in the block. null when its pending",
"oneOf": [
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"type": "null"
]
,
"v":
"description": "ECDSA recovery id",
"type": "string"
,
"value":
"description": "Value of Ether being transferred in Wei",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
Returns:
"description": "Hex representation of a Keccak 256 hash",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
`,
Deprecated: "DEPRECATED: Use at your own risk.",
PreRun: func(cmd *cobra.Command, args []string) {
log.Println("WARNING: This method (eth_sendTransaction) is deprecated. Use at your own risk.")
},
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_sendTransaction", params)
handleJSONRPCResponse(body, err)
},
}
var ethSendRawTransactionCmd = &cobra.Command{
Use: "eth_sendRawTransaction",
Short: "Creates new message call transaction or a contract creation for signed transactions.",
Long: `
Params:
- (0): [Required] <signedTransactionData>
"description": "Hex representation of a variable length byte array",
"type": "string",
"pattern": "^0x([a-fA-F0-9]?)+$"
Returns:
"description": "Hex representation of a Keccak 256 hash",
"type": "string",
"pattern": "^0x[a-fA-F\\d]64$"
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_sendRawTransaction", params)
handleJSONRPCResponse(body, err)
},
}
var ethSubmitHashrateCmd = &cobra.Command{
Use: "eth_submitHashrate",
Short: "Returns an array of all logs matching a given filter object.",
Long: `
Params:
- (0): [Required] <hashRate>
"description": "Hex representation of a 256 bit unit of data",
"type": "string",
"pattern": "^0x([a-fA-F\\d]64)?$"
- (1): [Required] <id>
"description": "Hex representation of a 256 bit unit of data",
"type": "string",
"pattern": "^0x([a-fA-F\\d]64)?$"
Returns:
"description": "whether of not submitting went through successfully",
"type": "boolean"
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_submitHashrate", params)
handleJSONRPCResponse(body, err)
},
}
var ethSubmitWorkCmd = &cobra.Command{
Use: "eth_submitWork",
Short: "Used for submitting a proof-of-work solution.",
Long: `
Params:
- (0): [Required] <nonce>
"description": "A number only to be used once",
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
- (1): [Required] <powHash>
"description": "Current block header PoW hash.",
"$ref": "#/components/schemas/DataWord"
- (2): [Required] <mixHash>
"description": "The mix digest.",
"$ref": "#/components/schemas/DataWord"
Returns:
"description": "Whether or not the provided solution is valid",
"type": "boolean"
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_submitWork", params)
handleJSONRPCResponse(body, err)
},
}
var ethSyncingCmd = &cobra.Command{
Use: "eth_syncing",
Short: "Returns an object with data about the sync status or false.",
Long: `
Params: <NONE>
Returns:
"oneOf": [
"description": "An object with sync status data",
"type": "object",
"title": "syncStatus",
"properties":
"currentBlock":
"description": "The current block, same as eth_blockNumber",
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"highestBlock":
"description": "The estimated highest block",
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"knownStates":
"description": "The known states",
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"pulledStates":
"description": "The pulled states",
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"startingBlock":
"description": "Block at which the import started (will only be reset, after the sync reached his head)",
"type": "string",
"pattern": "^0x[a-fA-F0-9]+$"
,
"description": "The value 'false' indicating that syncing is complete",
"type": "boolean"
]
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_syncing", params)
handleJSONRPCResponse(body, err)
},
}
var ethUninstallFilterCmd = &cobra.Command{
Use: "eth_uninstallFilter",
Short: "Uninstalls a filter with given id. Should always be called when watch is no longer needed. Additionally Filters timeout when they aren't requested with eth_getFilterChanges for a period of time.",
Long: `
Params:
- (0): [Required] <filterId>
"description": "An identifier used to reference the filter.",
"type": "string"
Returns:
"description": "Whether of not the filter was successfully uninstalled",
"type": "boolean"
`,
Run: func(cmd *cobra.Command, args []string) {
// len params: 0
params, err := marshalParams(args)
if err != nil {
log.Fatalln(err)
}
body, err := makeJSONRPCRequest("eth_uninstallFilter", params)
handleJSONRPCResponse(body, err)
},
}
// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
func init() {
cobra.OnInitialize(initConfig)
// Here you will define your flags and configuration settings.
// Cobra supports persistent flags, which, if defined here,
// will be global for your application.
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.FIXME.yaml)")
rootCmd.PersistentFlags().StringVar(&rpcAddr, "addr", "http://localhost:8545", "Address for JSON-RPC HTTP calls")
// Cobra also supports local flags, which will only run
// when this action is called directly.
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
rootCmd.AddCommand(web3ClientVersionCmd)
rootCmd.AddCommand(web3Sha3Cmd)
rootCmd.AddCommand(netListeningCmd)
rootCmd.AddCommand(netPeerCountCmd)
rootCmd.AddCommand(netVersionCmd)
rootCmd.AddCommand(ethBlockNumberCmd)
rootCmd.AddCommand(ethCallCmd)
rootCmd.AddCommand(ethChainIdCmd)
rootCmd.AddCommand(ethCoinbaseCmd)
rootCmd.AddCommand(ethEstimateGasCmd)
rootCmd.AddCommand(ethGasPriceCmd)
rootCmd.AddCommand(ethGetBalanceCmd)
rootCmd.AddCommand(ethGetBlockByHashCmd)
rootCmd.AddCommand(ethGetBlockByNumberCmd)
rootCmd.AddCommand(ethGetBlockTransactionCountByHashCmd)
rootCmd.AddCommand(ethGetBlockTransactionCountByNumberCmd)
rootCmd.AddCommand(ethGetCodeCmd)
rootCmd.AddCommand(ethGetFilterChangesCmd)
rootCmd.AddCommand(ethGetFilterLogsCmd)
rootCmd.AddCommand(ethGetRawTransactionByHashCmd)
rootCmd.AddCommand(ethGetRawTransactionByBlockHashAndIndexCmd)
rootCmd.AddCommand(ethGetRawTransactionByBlockNumberAndIndexCmd)
rootCmd.AddCommand(ethGetLogsCmd)
rootCmd.AddCommand(ethGetStorageAtCmd)
rootCmd.AddCommand(ethGetTransactionByBlockHashAndIndexCmd)
rootCmd.AddCommand(ethGetTransactionByBlockNumberAndIndexCmd)
rootCmd.AddCommand(ethGetTransactionByHashCmd)
rootCmd.AddCommand(ethGetTransactionCountCmd)
rootCmd.AddCommand(ethGetTransactionReceiptCmd)
rootCmd.AddCommand(ethGetUncleByBlockHashAndIndexCmd)
rootCmd.AddCommand(ethGetUncleByBlockNumberAndIndexCmd)
rootCmd.AddCommand(ethGetUncleCountByBlockHashCmd)
rootCmd.AddCommand(ethGetUncleCountByBlockNumberCmd)
rootCmd.AddCommand(ethGetProofCmd)
rootCmd.AddCommand(ethGetWorkCmd)
rootCmd.AddCommand(ethHashrateCmd)
rootCmd.AddCommand(ethMiningCmd)
rootCmd.AddCommand(ethNewBlockFilterCmd)
rootCmd.AddCommand(ethNewFilterCmd)
rootCmd.AddCommand(ethNewPendingTransactionFilterCmd)
rootCmd.AddCommand(ethPendingTransactionsCmd)
rootCmd.AddCommand(ethProtocolVersionCmd)
rootCmd.AddCommand(ethSignCmd)
rootCmd.AddCommand(ethAccountsCmd)
rootCmd.AddCommand(ethSendTransactionCmd)
rootCmd.AddCommand(ethSendRawTransactionCmd)
rootCmd.AddCommand(ethSubmitHashrateCmd)
rootCmd.AddCommand(ethSubmitWorkCmd)
rootCmd.AddCommand(ethSyncingCmd)
rootCmd.AddCommand(ethUninstallFilterCmd)
}
// initConfig reads in config file and ENV variables if set.
func initConfig() {
if cfgFile != "" {
// Use config file from the flag.
viper.SetConfigFile(cfgFile)
} else {
// Find home directory.
home, err := homedir.Dir()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// Search config in home directory with name ".FIXME" (without extension).
viper.AddConfigPath(home)
viper.SetConfigName(".FIXME")
}
viper.AutomaticEnv() // read in environment variables that match
// If a config file is found, read it in.
if err := viper.ReadInConfig(); err == nil {
fmt.Println("Using config file:", viper.ConfigFileUsed())
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment