github.com/status-im/status-go@v1.1.0/services/wallet/thirdparty/fourbytegithub/client.go (about) 1 package fourbytegithub 2 3 import ( 4 "errors" 5 "fmt" 6 "io/ioutil" 7 "net/http" 8 "regexp" 9 "strings" 10 "time" 11 12 "github.com/ethereum/go-ethereum/accounts/abi" 13 "github.com/status-im/status-go/services/wallet/thirdparty" 14 ) 15 16 type Signature struct { 17 ID int `json:"id"` 18 Text string `json:"text_signature"` 19 } 20 21 type ByID []Signature 22 23 func (s ByID) Len() int { return len(s) } 24 func (s ByID) Less(i, j int) bool { return s[i].ID > s[j].ID } 25 func (s ByID) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 26 27 type SignatureList struct { 28 Count int `json:"count"` 29 Results []Signature `json:"results"` 30 } 31 32 type Client struct { 33 Client *http.Client 34 URL string 35 } 36 37 func NewClient() *Client { 38 return &Client{Client: &http.Client{Timeout: time.Minute}, URL: "https://raw.githubusercontent.com"} 39 } 40 41 func (c *Client) DoQuery(url string) (*http.Response, error) { 42 resp, err := c.Client.Get(url) 43 44 if err != nil { 45 return nil, err 46 } 47 return resp, nil 48 } 49 50 func (c *Client) Run(data string) (*thirdparty.DataParsed, error) { 51 if len(data) < 10 || !strings.HasPrefix(data, "0x") { 52 return nil, errors.New("input is badly formatted") 53 } 54 methodSigData := data[2:10] 55 url := fmt.Sprintf("%s/ethereum-lists/4bytes/master/signatures/%s", c.URL, methodSigData) 56 resp, err := c.DoQuery(url) 57 if err != nil { 58 return nil, err 59 } 60 defer resp.Body.Close() 61 62 body, err := ioutil.ReadAll(resp.Body) 63 if err != nil { 64 return nil, err 65 } 66 signature := string(body) 67 rgx := regexp.MustCompile(`\((.*?)\)`) 68 69 id := fmt.Sprintf("0x%s", methodSigData) 70 name := strings.Split(signature, "(")[0] 71 rs := rgx.FindStringSubmatch(signature) 72 inputsMapString := make(map[string]string) 73 74 if len(rs[1]) > 0 { 75 inputs := make([]string, 0) 76 rawInputs := strings.Split(rs[1], ",") 77 for index, typ := range rawInputs { 78 if index == len(rawInputs)-1 && typ == "bytes" { 79 continue 80 } 81 inputs = append(inputs, fmt.Sprintf("{\"name\":\"%d\",\"type\":\"%s\"}", index, typ)) 82 } 83 84 functionABI := fmt.Sprintf("[{\"constant\":true,\"inputs\":[%s],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\", \"name\": \"%s\"}], ", strings.Join(inputs, ","), name) 85 contractABI, err := abi.JSON(strings.NewReader(functionABI)) 86 if err != nil { 87 return nil, err 88 } 89 method := contractABI.Methods[name] 90 inputsMap := make(map[string]interface{}) 91 if err := method.Inputs.UnpackIntoMap(inputsMap, []byte(data[10:])); err != nil { 92 return nil, err 93 } 94 for key, value := range inputsMap { 95 inputsMapString[key] = fmt.Sprintf("%v", value) 96 } 97 } 98 99 return &thirdparty.DataParsed{ 100 Name: name, 101 ID: id, 102 Signature: signature, 103 Inputs: inputsMapString, 104 }, nil 105 }