Skip to content

Commit

Permalink
feat: web3 and cosmos basic rest calls
Browse files Browse the repository at this point in the history
  • Loading branch information
hanchon committed Jul 26, 2024
1 parent b419fae commit a36a734
Show file tree
Hide file tree
Showing 31 changed files with 13,376 additions and 19 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v20.12.0
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.phony: build docs

dev-docs:
@source /opt/homebrew/opt/nvm/nvm.sh && nvm use && npm run docs:dev

3 changes: 3 additions & 0 deletions docs/pages/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Vivi [Hanchon's crypto toolkit]

Here is a list of tools to avoid rewritting the same code one million times.
53 changes: 53 additions & 0 deletions docs/pages/lib/requester/client.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Client

## Builder

To interact with web3 and cosmos endpoints we need a client:

```go
client := requester.NewClient()
```

:::info
The client defaults to Evmos Mainnet
:::

The client exposes a set of setters to change the default endpoints:

- `WithUnsecureWeb3Endpoint(endpoint string)`
- `WithUnsecureCosmosRestEndpoint(endpoint string)`
- `WithSecureWeb3Endpoint(endpoint string, auth string)`
- `WithSecureCosmosRestEndpoint(endpoint string, auth string)`

:::info
The auth string should be the string that goes after the `Authorization` string in the HTTP request, i.e., `Bearer 1337`
:::

## General Requests

### Get

There are two functions exposed, they are mostly used internally:

- `c.SendGetRequestEasyJSON(endpoint, url, res, auth)`: It uses a `easyjson.Unmarshaller` to quickly decode the response
- `c.SendGetRequest(endpoint, url, auth)`: It returns the response as a byte array if the status code is 200

### Post

There is a function exposed, it is mostly used internally:

- `c.SendPostRequestEasyJSON(endpoint, url, res, auth)`: It uses a `easyjson.Unmarshaller` to quickly decode the response

:::info
To unmarshall responses in a quick way with `easyjson`, it requires running the program against the file that has the struct and it'll create the `_easyjson.go` next to it with the required functions.

```sh
easyjson --all lib/types/cosmos/block_cosmos.go
```

:::

## Blockchain Requests

- [Web3 Requests](/lib/requester/web3)
- [Cosmos Requests](/lib/requester/cosmos)
19 changes: 19 additions & 0 deletions docs/pages/lib/requester/cosmos.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Cosmos Requester

List of supported rest calls to the Cosmos Rest endpoint

## GetBlockByNumber

Sending the height returns the block data.

```go
c.GetBlockCosmos(height)
```

## GetTransaction

Sending the transaction hash returns the transaction data

```go
c.GetCosmosTx(hash string)
```
27 changes: 27 additions & 0 deletions docs/pages/lib/requester/web3.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Web3 Requester

List of supported rest calls to the Web3 endpoint

## GetBlockByNumber

Sending the height and if you need the transactions or not will return the block data.

```go
c.GetBlockByNumber(height, withTransactions)
```

## GetTransactionTrace

Defaults the tracer to `callTracer`

```go
c.GetTransactionTrace(hash)
```

## GetTransactionReceipt

Get the receipt for a given transaction hash

```go
c.GetTransactionReceipt(hash)
```
6 changes: 5 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ module github.com/hanchon/vivi

go 1.22.2

require github.com/valyala/fasthttp v1.55.0
require (
github.com/mailru/easyjson v0.7.7
github.com/valyala/fasthttp v1.55.0
)

require (
github.com/andybalholm/brotli v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
)
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.55.0 h1:Zkefzgt6a7+bVKHnu/YaYSOPfNYNisSVBo/unVCf8k8=
Expand Down
36 changes: 18 additions & 18 deletions lib/requester/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@ import (
)

type Client struct {
Client *fasthttp.Client
Web3Endpoint string
RestEndpoint string
Web3Auth string
RestAuth string
Client *fasthttp.Client
Web3Endpoint string
CosmosRestEndpoint string
Web3Auth string
CosmosRestAuth string
}

const (
defaultWeb3Endpoint = "https://proxy.evmos.org/web3"
defaultRestEndpoint = "https://proxy.evmos.org/cosmos"
defaultWeb3Auth = ""
defaultRestAuth = ""
defaultWeb3Endpoint = "https://proxy.evmos.org/web3"
defaultCosmosRestEndpoint = "https://proxy.evmos.org/cosmos"
defaultWeb3Auth = ""
defaultCosmosRestAuth = ""

defaultRequestTimeout = time.Minute
defaultReadTimeout = time.Minute
Expand All @@ -40,11 +40,11 @@ func NewClient() Client {
}).Dial,
}
return Client{
Client: client,
Web3Endpoint: defaultWeb3Endpoint,
RestEndpoint: defaultRestEndpoint,
Web3Auth: defaultWeb3Auth,
RestAuth: defaultRestAuth,
Client: client,
Web3Endpoint: defaultWeb3Endpoint,
CosmosRestEndpoint: defaultCosmosRestEndpoint,
Web3Auth: defaultWeb3Auth,
CosmosRestAuth: defaultCosmosRestAuth,
}
}

Expand All @@ -55,8 +55,8 @@ func (c *Client) WithUnsecureWeb3Endpoint(endpoint string) *Client {
}

func (c *Client) WithUnsecureRestEndpoint(endpoint string) *Client {
c.RestEndpoint = endpoint
c.RestAuth = ""
c.CosmosRestEndpoint = endpoint
c.CosmosRestAuth = ""
return c
}

Expand All @@ -67,7 +67,7 @@ func (c *Client) WithSecureWeb3Endpoint(endpoint string, auth string) *Client {
}

func (c *Client) WithSecureRestEndpoint(endpoint string, auth string) *Client {
c.RestEndpoint = endpoint
c.RestAuth = auth
c.CosmosRestEndpoint = endpoint
c.CosmosRestAuth = auth
return c
}
27 changes: 27 additions & 0 deletions lib/requester/cosmos.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package requester

import (
cosmostypes "github.com/hanchon/vivi/lib/types/cosmos"
)

func (c *Client) GetBlockCosmos(height string) (*cosmostypes.CosmosBlockResult, error) {
// TODO: add pagination support
var result cosmostypes.CosmosBlockResult
return &result, c.SendGetRequestEasyJSON(
c.CosmosRestEndpoint,
"/cosmos/tx/v1beta1/txs/block/"+height+"?pagination.count_total=true",
&result,
c.CosmosRestAuth,
)
}

func (c *Client) GetCosmosTx(hash string) (*cosmostypes.TxRestResponseForEvents, error) {
// TODO: add the 0x prefix if not included in the hash string
var result cosmostypes.TxRestResponseForEvents
return &result, c.SendGetRequestEasyJSON(
c.CosmosRestEndpoint,
"/cosmos/tx/v1beta1/txs/"+hash,
&result,
c.CosmosRestAuth,
)
}
56 changes: 56 additions & 0 deletions lib/requester/get.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package requester

import (
"errors"
"net/http"
"strconv"

"github.com/mailru/easyjson"
"github.com/valyala/fasthttp"
)

func (c *Client) SendGetRequestEasyJSON(endpoint string, url string, res easyjson.Unmarshaler, auth string) error {
req := fasthttp.AcquireRequest()
req.SetRequestURI(endpoint + url)
req.Header.SetMethod(fasthttp.MethodGet)
if auth != "" {
req.Header.Add("Authorization", auth)
}
resp := fasthttp.AcquireResponse()
err := c.Client.Do(req, resp)
fasthttp.ReleaseRequest(req)
defer fasthttp.ReleaseResponse(resp)
if err != nil {
return err
}

if resp.StatusCode() != http.StatusOK {
return errors.New("incorrect status code: " + strconv.Itoa(resp.StatusCode()))
}

return easyjson.Unmarshal(resp.Body(), res)
}

func (c *Client) SendGetRequest(endpoint string, url string, auth string) ([]byte, error) {
req := fasthttp.AcquireRequest()
req.SetRequestURI(endpoint + url)
req.Header.SetMethod(fasthttp.MethodGet)
if auth != "" {
req.Header.Add("Authorization", auth)
}
resp := fasthttp.AcquireResponse()
err := c.Client.Do(req, resp)
fasthttp.ReleaseRequest(req)
defer fasthttp.ReleaseResponse(resp)
if err != nil {
return []byte{}, err
}

if resp.StatusCode() != http.StatusOK {
return []byte{}, errors.New("incorrect status code: " + strconv.Itoa(resp.StatusCode()))
}

ret := make([]byte, len(resp.Body()))
copy(ret, resp.Body())
return ret, nil
}
37 changes: 37 additions & 0 deletions lib/requester/post.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package requester

import (
"fmt"
"net/http"
"strconv"

"github.com/mailru/easyjson"
"github.com/valyala/fasthttp"
)

func (c *Client) SendPostRequestEasyJSON(endpoint string, body []byte, res easyjson.Unmarshaler, auth string) 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 err
}

statusCode := resp.StatusCode()
if statusCode != http.StatusOK {
return fmt.Errorf("status code is not ok: " + strconv.Itoa(statusCode))
}

respBody := resp.Body()
return easyjson.Unmarshal(respBody, res)
}
37 changes: 37 additions & 0 deletions lib/requester/web3.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package requester

import (
"fmt"

web3types "github.com/hanchon/vivi/lib/types/web3"
)

func (c *Client) GetBlockByNumber(height string, withTransactions bool) (*web3types.BlockByNumberWithTransactions, error) {
var receipt web3types.BlockByNumberWithTransactions
return &receipt, c.SendPostRequestEasyJSON(
c.Web3Endpoint,
[]byte(fmt.Sprintf(`{"method":"eth_getBlockByNumber","params":["%s",%t],"id":1,"jsonrpc":"2.0"}`, height, withTransactions)),
&receipt,
c.Web3Auth,
)
}

func (c *Client) GetTransactionTrace(hash string) (*web3types.TraceTransactionResult, error) {
var trace web3types.TraceTransactionResult
return &trace, c.SendPostRequestEasyJSON(
c.Web3Endpoint,
[]byte(`{"method":"debug_traceTransaction","params":["`+hash+`", {"tracer": "callTracer"}],"id":1,"jsonrpc":"2.0"}`),
&trace,
c.Web3Auth,
)
}

func (c *Client) GetTransactionReceipt(hash string) (*web3types.TxReceipt, error) {
var receipt web3types.TxReceipt
return &receipt, c.SendPostRequestEasyJSON(
c.Web3Endpoint,
[]byte(`{"method":"eth_getTransactionReceipt","params":["`+hash+`"],"id":1,"jsonrpc":"2.0"}`),
&receipt,
c.Web3Auth,
)
}
Loading

0 comments on commit a36a734

Please sign in to comment.