feat: add fourbyte github integration
This commit is contained in:
parent
61527f8c78
commit
dffcb708ea
|
@ -115,7 +115,7 @@ func (api *API) GetTransfersForIdentities(ctx context.Context, identities []tran
|
||||||
func (api *API) FetchDecodedTxData(ctx context.Context, data string) (*thirdparty.DataParsed, error) {
|
func (api *API) FetchDecodedTxData(ctx context.Context, data string) (*thirdparty.DataParsed, error) {
|
||||||
log.Debug("[Wallet: FetchDecodedTxData]")
|
log.Debug("[Wallet: FetchDecodedTxData]")
|
||||||
|
|
||||||
return api.s.decoder.Run(data)
|
return api.s.decoder.Decode(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated: GetCachedBalances is deprecated. Use GetTokensBalances instead
|
// Deprecated: GetCachedBalances is deprecated. Use GetTokensBalances instead
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
package wallet
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/status-im/status-go/services/wallet/thirdparty"
|
||||||
|
"github.com/status-im/status-go/services/wallet/thirdparty/fourbyte"
|
||||||
|
"github.com/status-im/status-go/services/wallet/thirdparty/fourbytegithub"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Decoder struct {
|
||||||
|
Main *fourbytegithub.Client
|
||||||
|
Fallback *fourbyte.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDecoder() *Decoder {
|
||||||
|
return &Decoder{
|
||||||
|
Main: fourbytegithub.NewClient(),
|
||||||
|
Fallback: fourbyte.NewClient(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) Decode(data string) (*thirdparty.DataParsed, error) {
|
||||||
|
parsed, err := d.Main.Run(data)
|
||||||
|
if err == nil {
|
||||||
|
return parsed, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return d.Fallback.Run(data)
|
||||||
|
}
|
|
@ -27,7 +27,6 @@ import (
|
||||||
"github.com/status-im/status-go/services/wallet/thirdparty/alchemy"
|
"github.com/status-im/status-go/services/wallet/thirdparty/alchemy"
|
||||||
"github.com/status-im/status-go/services/wallet/thirdparty/coingecko"
|
"github.com/status-im/status-go/services/wallet/thirdparty/coingecko"
|
||||||
"github.com/status-im/status-go/services/wallet/thirdparty/cryptocompare"
|
"github.com/status-im/status-go/services/wallet/thirdparty/cryptocompare"
|
||||||
"github.com/status-im/status-go/services/wallet/thirdparty/fourbyte"
|
|
||||||
"github.com/status-im/status-go/services/wallet/thirdparty/infura"
|
"github.com/status-im/status-go/services/wallet/thirdparty/infura"
|
||||||
"github.com/status-im/status-go/services/wallet/token"
|
"github.com/status-im/status-go/services/wallet/token"
|
||||||
"github.com/status-im/status-go/services/wallet/transfer"
|
"github.com/status-im/status-go/services/wallet/transfer"
|
||||||
|
@ -127,7 +126,7 @@ func NewService(
|
||||||
history: history,
|
history: history,
|
||||||
currency: currency,
|
currency: currency,
|
||||||
activity: activity,
|
activity: activity,
|
||||||
decoder: fourbyte.NewClient(),
|
decoder: NewDecoder(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,7 +154,7 @@ type Service struct {
|
||||||
history *history.Service
|
history *history.Service
|
||||||
currency *currency.Service
|
currency *currency.Service
|
||||||
activity *activity.Service
|
activity *activity.Service
|
||||||
decoder thirdparty.DecoderProvider
|
decoder *Decoder
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start signals transmitter.
|
// Start signals transmitter.
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
package fourbytegithub
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||||
|
"github.com/status-im/status-go/services/wallet/thirdparty"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Signature struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Text string `json:"text_signature"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ByID []Signature
|
||||||
|
|
||||||
|
func (s ByID) Len() int { return len(s) }
|
||||||
|
func (s ByID) Less(i, j int) bool { return s[i].ID > s[j].ID }
|
||||||
|
func (s ByID) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||||
|
|
||||||
|
type SignatureList struct {
|
||||||
|
Count int `json:"count"`
|
||||||
|
Results []Signature `json:"results"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
Client *http.Client
|
||||||
|
URL string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClient() *Client {
|
||||||
|
return &Client{Client: &http.Client{Timeout: time.Minute}, URL: "https://raw.githubusercontent.com"}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) DoQuery(url string) (*http.Response, error) {
|
||||||
|
resp, err := c.Client.Get(url)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) Run(data string) (*thirdparty.DataParsed, error) {
|
||||||
|
if len(data) < 10 || !strings.HasPrefix(data, "0x") {
|
||||||
|
return nil, errors.New("input is badly formatted")
|
||||||
|
}
|
||||||
|
methodSigData := data[2:10]
|
||||||
|
url := fmt.Sprintf("%s/ethereum-lists/4bytes/master/signatures/%s", c.URL, methodSigData)
|
||||||
|
resp, err := c.DoQuery(url)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
signature := string(body)
|
||||||
|
rgx := regexp.MustCompile(`\((.*?)\)`)
|
||||||
|
|
||||||
|
id := fmt.Sprintf("0x%s", methodSigData)
|
||||||
|
name := strings.Split(signature, "(")[0]
|
||||||
|
rs := rgx.FindStringSubmatch(signature)
|
||||||
|
|
||||||
|
inputs := make([]string, 0)
|
||||||
|
rawInputs := strings.Split(rs[1], ",")
|
||||||
|
for index, typ := range rawInputs {
|
||||||
|
if index == len(rawInputs)-1 && typ == "bytes" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
inputs = append(inputs, fmt.Sprintf("{\"name\":\"%d\",\"type\":\"%s\"}", index, typ))
|
||||||
|
}
|
||||||
|
|
||||||
|
functionABI := fmt.Sprintf("[{\"constant\":true,\"inputs\":[%s],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\", \"name\": \"%s\"}], ", strings.Join(inputs, ","), name)
|
||||||
|
contractABI, err := abi.JSON(strings.NewReader(functionABI))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
method := contractABI.Methods[name]
|
||||||
|
inputsMap := make(map[string]interface{})
|
||||||
|
if err := method.Inputs.UnpackIntoMap(inputsMap, []byte(data[10:])); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
inputsMapString := make(map[string]string)
|
||||||
|
for key, value := range inputsMap {
|
||||||
|
inputsMapString[key] = fmt.Sprintf("%v", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &thirdparty.DataParsed{
|
||||||
|
Name: name,
|
||||||
|
ID: id,
|
||||||
|
Signature: signature,
|
||||||
|
Inputs: inputsMapString,
|
||||||
|
}, nil
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package fourbytegithub
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRun(t *testing.T) {
|
||||||
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(200)
|
||||||
|
_, err := w.Write([]byte("transfer(address,uint256)"))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
defer srv.Close()
|
||||||
|
|
||||||
|
fb := NewClient()
|
||||||
|
fb.Client = srv.Client()
|
||||||
|
fb.URL = srv.URL
|
||||||
|
|
||||||
|
res, err := fb.Run("0xa9059cbb000000000000000000000000e0e40d81121d41a7d85d8d2462b475074f9df5ec0000000000000000000000000000000000000000000000000000000077359400")
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, res.Signature, "transfer(address,uint256)")
|
||||||
|
require.Equal(t, res.ID, "0xa9059cbb")
|
||||||
|
require.Equal(t, res.Name, "transfer")
|
||||||
|
require.Equal(t, res.Inputs, map[string]string{
|
||||||
|
"0": "0x3030303030303030303030306530653430643831",
|
||||||
|
"1": "22252012820881184517742036120632151212095838186768864961872069019727748752739",
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in New Issue