Move abi-spec to status-go

This commit is contained in:
frank 2022-08-24 20:42:41 +08:00 committed by Andrea Maria Piana
parent bcdb14bd48
commit e49236a83c
8 changed files with 655 additions and 1 deletions

View File

@ -1 +1 @@
0.109.1
0.109.2

161
abi-spec/core.go Normal file
View File

@ -0,0 +1,161 @@
package abispec
import (
"encoding/hex"
"encoding/json"
"fmt"
"math/big"
"reflect"
"regexp"
"strings"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
)
var methodPattern = regexp.MustCompile(`(^[a-zA-Z].*)\((.*)\)`)
var maxSafeInteger = big.NewInt(int64(9007199254740991))
const transferInputs = `[{"type":"address"},{"type":"uint256"}]`
const transferFunctionName = "transfer"
var transferInDef = fmt.Sprintf(`[{ "name" : "%s", "type": "function", "inputs": %s}]`, transferFunctionName, transferInputs)
var transferAbi, _ = abi.JSON(strings.NewReader(transferInDef))
func EncodeTransfer(to string, value string) (string, error) {
amount, success := big.NewInt(0).SetString(value, 0)
if !success {
return "", fmt.Errorf("failed to convert %s to big.Int", value)
}
address := common.HexToAddress(to)
result, err := transferAbi.Pack(transferFunctionName, address, amount)
if err != nil {
return "", fmt.Errorf("pack failed: %v", err)
}
return "0x" + hex.EncodeToString(result), nil
}
func Encode(method string, paramsJSON string) (string, error) {
matches := methodPattern.FindStringSubmatch(method)
if len(matches) != 3 {
return "", fmt.Errorf("unrecognized method: %s", method)
}
methodName := matches[1]
paramTypesString := strings.TrimSpace(matches[2])
// value of inputs looks like: `[{ "type": "uint32" },{ "type": "bool" }]`
inputs := "["
var params []interface{}
if len(paramTypesString) > 0 {
var paramsRaw []json.RawMessage
if err := json.Unmarshal([]byte(paramsJSON), &paramsRaw); err != nil {
return "", fmt.Errorf("unable to unmarshal params: %v", err)
}
types := strings.Split(paramTypesString, ",")
if len(paramsRaw) != len(types) {
return "", fmt.Errorf("num of param type should equal to num of param value, actual value: %d, %d", len(types), len(paramsRaw))
}
for i, typeName := range types {
if i != 0 {
inputs += ","
}
inputs += fmt.Sprintf(`{"type":"%s"}`, typeName)
param, err := toGoTypeValue(typeName, paramsRaw[i])
if err != nil {
return "", err
}
params = append(params, param.Interface())
}
}
inputs += "]"
inDef := fmt.Sprintf(`[{ "name" : "%s", "type": "function", "inputs": %s}]`, methodName, inputs)
inAbi, err := abi.JSON(strings.NewReader(inDef))
if err != nil {
return "", fmt.Errorf("invalid ABI definition %s, %v", inDef, err)
}
var result []byte
result, err = inAbi.Pack(methodName, params...)
if err != nil {
return "", fmt.Errorf("Pack failed: %v", err)
}
return "0x" + hex.EncodeToString(result), nil
}
// override result to make it looks like what status-mobile need
func overrideResult(out []interface{}) []interface{} {
for i, v := range out {
outType := reflect.TypeOf(v)
switch outType.String() {
case "[]uint8":
out[i] = "0x" + common.Bytes2Hex(v.([]uint8))
case bigIntType:
vv := v.(*big.Int)
if vv.Cmp(maxSafeInteger) == 1 {
out[i] = vv.String()
}
}
if outType.Kind() == reflect.Array && outType.Elem().Kind() == reflect.Array && outType.Elem().Elem().Kind() == reflect.Uint8 { //case e.g. [2][3]uint8
val := reflect.ValueOf(v)
rowNum := val.Len()
colNum := val.Index(0).Len()
var ss = make([]string, rowNum)
for i := 0; i < rowNum; i++ {
bytes := make([]uint8, colNum)
for j := 0; j < colNum; j++ {
bytes[j] = uint8(val.Index(i).Index(j).Uint())
}
ss[i] = common.Bytes2Hex(bytes)
}
out[i] = ss
} else if outType.String() != "common.Address" && outType.Kind() == reflect.Array && outType.Elem().Kind() == reflect.Uint8 {
val := reflect.ValueOf(v)
len := val.Len()
bytes := make([]uint8, len)
for i := 0; i < len; i++ {
bytes[i] = uint8(val.Index(i).Uint())
}
out[i] = common.Bytes2Hex(bytes)
}
}
return out
}
// bytesString e.g. 0x000000000000000000000000000000000000000000000000000000005bc741cd00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000013b86dbf1a83c9e6a492914a0ee39e8a5b7eb60700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002e516d533152484e4a57414b356e426f6f57454d34654d644268707a35666e325764557473457357754a4b79356147000000000000000000000000000000000000
// types e.g. []string{"uint256","bytes","address","uint256","uint256"}
func Decode(bytesString string, types []string) ([]interface{}, error) {
outputs := "["
for i, typeName := range types {
if i != 0 {
outputs += ","
}
outputs += fmt.Sprintf(`{"type":"%s"}`, typeName)
}
outputs += "]"
def := fmt.Sprintf(`[{ "name" : "method", "type": "function", "outputs": %s}]`, outputs)
abi, err := abi.JSON(strings.NewReader(def))
if err != nil {
return nil, fmt.Errorf("invalid ABI definition %s: %v", def, err)
}
if strings.HasPrefix(bytesString, "0x") {
bytesString = bytesString[2:]
}
bytes, err := hex.DecodeString(bytesString)
if err != nil {
return nil, fmt.Errorf("invalid hex %s: %v", bytesString, err)
}
out, err := abi.Unpack("method", bytes)
if err != nil {
return nil, fmt.Errorf("unpack failed: %v", err)
}
return overrideResult(out), nil
}

133
abi-spec/core_test.go Normal file
View File

@ -0,0 +1,133 @@
package abispec
import (
"encoding/json"
"testing"
"github.com/stretchr/testify/require"
)
func TestMethodPattern(t *testing.T) {
results := methodPattern.FindStringSubmatch("sam(bytes,bool,uint256[])")
require.Equal(t, "sam(bytes,bool,uint256[])", results[0])
require.Equal(t, "sam", results[1])
require.Equal(t, "bytes,bool,uint256[]", results[2])
results = methodPattern.FindStringSubmatch("s(bytes,bool,uint256[])")
require.Equal(t, "s(bytes,bool,uint256[])", results[0])
require.Equal(t, "s", results[1])
require.Equal(t, "bytes,bool,uint256[]", results[2])
results = methodPattern.FindStringSubmatch("s1(bytes,bool,uint256[])")
require.Equal(t, "s1(bytes,bool,uint256[])", results[0])
require.Equal(t, "s1", results[1])
require.Equal(t, "bytes,bool,uint256[]", results[2])
results = methodPattern.FindStringSubmatch("1s(bytes,bool,uint256[])")
require.Len(t, results, 0)
}
func TestEncodeTransfer(t *testing.T) {
result, err := EncodeTransfer("0x6f5f90fb1dD8E406F233442935F689bA7D5701b2", "10000")
require.NoError(t, err)
require.Equal(t, "0xa9059cbb0000000000000000000000006f5f90fb1dd8e406f233442935f689ba7d5701b20000000000000000000000000000000000000000000000000000000000002710", result)
result, err = EncodeTransfer("0x6f5f90fb1dD8E406F233442935F689bA7D5701b2", "0x2710")
require.NoError(t, err)
require.Equal(t, "0xa9059cbb0000000000000000000000006f5f90fb1dd8e406f233442935f689ba7d5701b20000000000000000000000000000000000000000000000000000000000002710", result)
}
func TestEncode(t *testing.T) {
result, err := Encode("baz(uint32,bool)", "[69,true]")
require.NoError(t, err)
require.Equal(t, "0xcdcd77c000000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000001", result)
result, err = Encode("baz(uint256,bool)", "[69,true]")
require.NoError(t, err)
require.Equal(t, "0x72ed38b600000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000001", result)
result, err = Encode("bar(bytes3[2])", `[["abc","def"]]`)
require.NoError(t, err)
require.Equal(t, "0xfce353f661626300000000000000000000000000000000000000000000000000000000006465660000000000000000000000000000000000000000000000000000000000", result)
result, err = Encode("sam(bytes)", `["dave"]`)
require.NoError(t, err)
require.Equal(t, "0x05e73fb9000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000046461766500000000000000000000000000000000000000000000000000000000", result)
result, err = Encode("sam(bytes,bool,uint256[])", `["dave",true,[1,2,3]]`)
require.NoError(t, err)
require.Equal(t, "0xa5643bf20000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000464617665000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003", result)
result, err = Encode("f(bytes10)", `["1234567890"]`)
require.NoError(t, err)
require.Equal(t, "0x6350865e3132333435363738393000000000000000000000000000000000000000000000", result)
result, err = Encode("f(uint256,uint32[],bytes10,bytes)", `[291,[1110,1929],"1234567890","Hello, world!"]`)
require.NoError(t, err)
require.Equal(t, "0x8be6524600000000000000000000000000000000000000000000000000000000000001230000000000000000000000000000000000000000000000000000000000000080313233343536373839300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000004560000000000000000000000000000000000000000000000000000000000000789000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20776f726c642100000000000000000000000000000000000000", result)
result, err = Encode("getExpectedRate(address,address,uint256)", `["0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee","0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",1000]`)
require.NoError(t, err)
require.Equal(t, "0x809a9e55000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee00000000000000000000000000000000000000000000000000000000000003e8", result)
result, err = Encode("f(uint256)", `["115792089237316195423570985008687907853269984665640564039457584007913129639935"]`)
require.NoError(t, err)
require.Equal(t, "0xb3de648bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", result)
//TODO following case would fail cause go-ethereum does not support type uint
//result, err = Encode("g(uint[][],string[])", `[[[1,2],[3]],["one","two","three"]]`)
//require.NoError(t, err)
//require.Equal(t, "0xad6a3446000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000036f6e650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000374776f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000057468726565000000000000000000000000000000000000000000000000000000", result)
}
func TestDecode(t *testing.T) {
out, err := Decode("0x000000000000000000000000000000000000000000000000000000005bc741cd00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000013b86dbf1a83c9e6a492914a0ee39e8a5b7eb60700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002e516d533152484e4a57414b356e426f6f57454d34654d644268707a35666e325764557473457357754a4b79356147000000000000000000000000000000000000",
[]string{"uint256", "bytes", "address", "uint256", "uint256"})
require.NoError(t, err)
bytes, err := json.Marshal(out)
require.NoError(t, err)
require.JSONEq(t, `[1539785165,"0x516d533152484e4a57414b356e426f6f57454d34654d644268707a35666e325764557473457357754a4b79356147","0x13b86dbf1a83c9e6a492914a0ee39e8a5b7eb607",0,0]`, string(bytes))
out, err = Decode("0x0000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000d7621dc58210001",
[]string{"uint256", "uint256"})
require.NoError(t, err)
bytes, err = json.Marshal(out)
require.NoError(t, err)
require.JSONEq(t, `["1000000000000000000","970000000000000001"]`, string(bytes))
out, err = Decode("0x000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee00000000000000000000000000000000000000000000000000000000000003e8",
[]string{"address", "address", "uint256"})
require.NoError(t, err)
bytes, err = json.Marshal(out)
require.NoError(t, err)
require.JSONEq(t, `["0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee","0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",1000]`, string(bytes))
out, err = Decode("0x00000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000001",
[]string{"uint32", "bool"})
require.NoError(t, err)
bytes, err = json.Marshal(out)
require.NoError(t, err)
require.JSONEq(t, `[69,true]`, string(bytes))
out, err = Decode("0x61626300000000000000000000000000000000000000000000000000000000006465660000000000000000000000000000000000000000000000000000000000",
[]string{"bytes3[2]"})
require.NoError(t, err)
bytes, err = json.Marshal(out[0])
require.NoError(t, err)
require.JSONEq(t, `["616263","646566"]`, string(bytes))
out, err = Decode("0x0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000464617665000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003",
[]string{"string", "bool", "uint256[]"})
require.NoError(t, err)
bytes, err = json.Marshal(out)
require.NoError(t, err)
require.JSONEq(t, `["dave",true,[1,2,3]]`, string(bytes))
out, err = Decode("0x00000000000000000000000000000000000000000000000000000000000001230000000000000000000000000000000000000000000000000000000000000080313233343536373839300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000004560000000000000000000000000000000000000000000000000000000000000789000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20776f726c642100000000000000000000000000000000000000",
[]string{"uint256", "uint32[]", "bytes10", "bytes"})
require.NoError(t, err)
bytes, err = json.Marshal(out)
require.NoError(t, err)
require.JSONEq(t, `[291,[1110,1929],"31323334353637383930","0x48656c6c6f2c20776f726c6421"]`, string(bytes))
}

190
abi-spec/types.go Normal file
View File

@ -0,0 +1,190 @@
package abispec
import (
"encoding/json"
"fmt"
"math/big"
"reflect"
"regexp"
"strconv"
"strings"
"github.com/ethereum/go-ethereum/common"
)
const bigIntType = "*big.Int"
var zero = big.NewInt(0)
var arrayTypePattern = regexp.MustCompile(`(\[([\d]*)\])`)
var bytesType = reflect.TypeOf([]byte{})
var typeMap = map[string]reflect.Type{
"uint8": reflect.TypeOf(uint8(0)),
"int8": reflect.TypeOf(int8(0)),
"uint16": reflect.TypeOf(uint16(0)),
"int16": reflect.TypeOf(int16(0)),
"uint32": reflect.TypeOf(uint32(0)),
"int32": reflect.TypeOf(int32(0)),
"uint64": reflect.TypeOf(uint64(0)),
"int64": reflect.TypeOf(int64(0)),
"bytes": bytesType,
"bytes1": reflect.TypeOf([1]byte{}),
"bytes2": reflect.TypeOf([2]byte{}),
"bytes3": reflect.TypeOf([3]byte{}),
"bytes4": reflect.TypeOf([4]byte{}),
"bytes5": reflect.TypeOf([5]byte{}),
"bytes6": reflect.TypeOf([6]byte{}),
"bytes7": reflect.TypeOf([7]byte{}),
"bytes8": reflect.TypeOf([8]byte{}),
"bytes9": reflect.TypeOf([9]byte{}),
"bytes10": reflect.TypeOf([10]byte{}),
"bytes11": reflect.TypeOf([11]byte{}),
"bytes12": reflect.TypeOf([12]byte{}),
"bytes13": reflect.TypeOf([13]byte{}),
"bytes14": reflect.TypeOf([14]byte{}),
"bytes15": reflect.TypeOf([15]byte{}),
"bytes16": reflect.TypeOf([16]byte{}),
"bytes17": reflect.TypeOf([17]byte{}),
"bytes18": reflect.TypeOf([18]byte{}),
"bytes19": reflect.TypeOf([19]byte{}),
"bytes20": reflect.TypeOf([20]byte{}),
"bytes21": reflect.TypeOf([21]byte{}),
"bytes22": reflect.TypeOf([22]byte{}),
"bytes23": reflect.TypeOf([23]byte{}),
"bytes24": reflect.TypeOf([24]byte{}),
"bytes25": reflect.TypeOf([25]byte{}),
"bytes26": reflect.TypeOf([26]byte{}),
"bytes27": reflect.TypeOf([27]byte{}),
"bytes28": reflect.TypeOf([28]byte{}),
"bytes29": reflect.TypeOf([29]byte{}),
"bytes30": reflect.TypeOf([30]byte{}),
"bytes31": reflect.TypeOf([31]byte{}),
"bytes32": reflect.TypeOf([32]byte{}),
"address": reflect.TypeOf(common.Address{}),
"bool": reflect.TypeOf(false),
"string": reflect.TypeOf(""),
}
func toGoType(solidityType string) (reflect.Type, error) {
if t, ok := typeMap[solidityType]; ok {
return t, nil
}
if arrayTypePattern.MatchString(solidityType) { // type of array
index := arrayTypePattern.FindStringIndex(solidityType)[0]
arrayType, err := toGoType(solidityType[0:index])
if err != nil {
return nil, err
}
matches := arrayTypePattern.FindAllStringSubmatch(solidityType, -1)
for i := 0; i <= len(matches)-1; i++ {
sizeStr := matches[i][2]
if sizeStr == "" {
arrayType = reflect.SliceOf(arrayType)
} else {
length, err := strconv.Atoi(sizeStr)
if err != nil {
return nil, err
}
arrayType = reflect.ArrayOf(length, arrayType)
}
}
return arrayType, nil
}
// uint and int are aliases for uint256 and int256, respectively.
// source: https://docs.soliditylang.org/en/v0.8.11/types.html
//TODO should we support type: uint ?? currently, go-ethereum doesn't support type uint
if strings.HasPrefix(solidityType, "uint") || strings.HasPrefix(solidityType, "int") {
return reflect.TypeOf(zero), nil
}
return nil, fmt.Errorf("unsupported type: %s", solidityType)
}
func toGoTypeValue(solidityType string, raw json.RawMessage) (*reflect.Value, error) {
goType, err := toGoType(solidityType)
if err != nil {
return nil, err
}
value := reflect.New(goType)
if goType == bytesType { // to support case like: Encode("sam(bytes)", `["dave"]`)
var s string
err = json.Unmarshal(raw, &s)
if err != nil {
return nil, err
}
bytes := []byte(s)
value.Elem().SetBytes(bytes)
return &value, nil
}
err = json.Unmarshal(raw, value.Interface())
if err != nil {
if goType.String() == bigIntType {
var s string
err = json.Unmarshal(raw, &s)
if err != nil {
return nil, err
}
v, success := big.NewInt(0).SetString(s, 0)
if !success {
return nil, fmt.Errorf("convert to go type value failed, value: %s", s)
}
value = reflect.ValueOf(v)
} else if goType.Kind() == reflect.Array { // to support case like: Encode("f(bytes10)", `["1234567890"]`)
elemKind := goType.Elem().Kind()
if elemKind == reflect.Uint8 {
var s string
err = json.Unmarshal(raw, &s)
if err != nil {
return nil, err
}
bytes := []byte(s)
for i, b := range bytes {
value.Elem().Index(i).Set(reflect.ValueOf(b))
}
return &value, nil
}
if elemKind == reflect.Array { // to support case like: Encode("bar(bytes3[2])", `[["abc","def"]]`)
var ss []string
err = json.Unmarshal(raw, &ss)
if err != nil {
return nil, err
}
var bytes [][]byte
for _, s := range ss {
bytes = append(bytes, []byte(s))
}
// convert []byte to []int
// note: Array and slice values encode as JSON arrays, except that []byte encodes as a base64-encoded string, and a nil slice encodes as the null JSON object.
var ints = make([][]int, len(bytes))
for i, r := range bytes {
ints[i] = make([]int, len(r))
for j, b := range r {
ints[i][j] = int(b)
}
}
jsonString, err := json.Marshal(ints)
if err != nil {
return nil, err
}
if err = json.Unmarshal(jsonString, value.Interface()); err != nil {
return nil, err
}
}
}
}
return &value, err
}

64
abi-spec/types_test.go Normal file
View File

@ -0,0 +1,64 @@
package abispec
import (
"encoding/json"
"testing"
"github.com/stretchr/testify/require"
)
func TestToGoTypeValue(t *testing.T) {
var raw json.RawMessage
err := json.Unmarshal([]byte(`"dave"`), &raw)
require.NoError(t, err)
val, err := toGoTypeValue("bytes", raw)
require.NoError(t, err)
require.Equal(t, []byte("dave"), val.Elem().Bytes())
err = json.Unmarshal([]byte(`true`), &raw)
require.NoError(t, err)
val, err = toGoTypeValue("bool", raw)
require.NoError(t, err)
require.True(t, val.Elem().Bool())
}
func TestToGoType(t *testing.T) {
var raws []json.RawMessage
err := json.Unmarshal([]byte("[8]"), &raws)
require.NoError(t, err)
value, err := toGoTypeValue("uint8", raws[0])
require.NoError(t, err)
require.Equal(t, uint8(8), *value.Interface().(*uint8))
goType, err := toGoType("uint256[][3][]")
require.NoError(t, err)
require.Equal(t, "[][3][]*big.Int", goType.String())
goType, err = toGoType("uint256[][][3]")
require.NoError(t, err)
require.Equal(t, "[3][][]*big.Int", goType.String())
goType, err = toGoType("uint256[3][][]")
require.NoError(t, err)
require.Equal(t, "[][][3]*big.Int", goType.String())
goType, err = toGoType("bytes3[2]")
require.NoError(t, err)
require.Equal(t, "[2][3]uint8", goType.String())
}
func TestArrayTypePattern(t *testing.T) {
require.True(t, arrayTypePattern.MatchString(`uint8[]`))
require.False(t, arrayTypePattern.MatchString(`uint8`))
s := "uint8[][2][1][]"
matches := arrayTypePattern.FindAllStringSubmatch(s, -1)
require.Equal(t, 3, len(matches[0]))
require.Equal(t, "", matches[0][2])
require.Equal(t, "2", matches[1][2])
index := arrayTypePattern.FindStringIndex(s)[0]
require.Equal(t, 5, index)
require.Equal(t, "uint8", s[0:index])
}

22
abi-spec/utils.go Normal file
View File

@ -0,0 +1,22 @@
package abispec
import (
"fmt"
"math/big"
)
func HexToNumber(hex string) string {
num, success := big.NewInt(0).SetString(hex, 16)
if success {
return num.String()
}
return ""
}
func NumberToHex(numString string) string {
num, success := big.NewInt(0).SetString(numString, 0)
if success {
return fmt.Sprintf("%x", num)
}
return ""
}

35
abi-spec/utils_test.go Normal file
View File

@ -0,0 +1,35 @@
package abispec
import (
"encoding/json"
"testing"
"github.com/stretchr/testify/require"
)
func TestHexToNumber(t *testing.T) {
//hex number is less than 53 bits, it returns a number
num := HexToNumber("9")
bytes, err := json.Marshal(num)
require.NoError(t, err)
require.JSONEq(t, `"9"`, string(bytes))
num = HexToNumber("99999999")
bytes, err = json.Marshal(num)
require.NoError(t, err)
require.JSONEq(t, `"2576980377"`, string(bytes))
num = HexToNumber("1fffffffffffff")
bytes, err = json.Marshal(num)
require.NoError(t, err)
require.JSONEq(t, `"9007199254740991"`, string(bytes))
num = HexToNumber("9999999999999999")
bytes, err = json.Marshal(num)
require.NoError(t, err)
require.JSONEq(t, `"11068046444225730969"`, string(bytes))
}
func TestNumberToHex(t *testing.T) {
require.Equal(t, "20000000000002", NumberToHex("9007199254740994"))
}

View File

@ -16,6 +16,7 @@ import (
"github.com/status-im/zxcvbn-go"
"github.com/status-im/zxcvbn-go/scoring"
abi_spec "github.com/status-im/status-go/abi-spec"
"github.com/status-im/status-go/api"
"github.com/status-im/status-go/api/multiformat"
"github.com/status-im/status-go/eth-node/types"
@ -937,3 +938,51 @@ func InputConnectionStringForBootstrapping(cs, configJSON string) string {
err := server.StartUpPairingClient(statusBackend.GetMultiaccountDB(), cs, configJSON)
return makeJSONResponse(err)
}
func EncodeTransfer(to string, value string) string {
result, err := abi_spec.EncodeTransfer(to, value)
if err != nil {
log.Error("failed to encode transfer", "to", to, "value", value, "error", err)
return ""
}
return result
}
func EncodeFunctionCall(method string, paramsJSON string) string {
result, err := abi_spec.Encode(method, paramsJSON)
if err != nil {
log.Error("failed to encode function call", "method", method, "paramsJSON", paramsJSON, "error", err)
}
return result
}
func DecodeParameters(decodeParamJSON string) string {
decodeParam := struct {
BytesString string `json:"bytesString"`
Types []string `json:"types"`
}{}
err := json.Unmarshal([]byte(decodeParamJSON), &decodeParam)
if err != nil {
log.Error("failed to unmarshal json when decoding parameters", "decodeParamJSON", decodeParamJSON, "error", err)
return ""
}
result, err := abi_spec.Decode(decodeParam.BytesString, decodeParam.Types)
if err != nil {
log.Error("failed to decode parameters", "decodeParamJSON", decodeParamJSON, "error", err)
return ""
}
bytes, err := json.Marshal(result)
if err != nil {
log.Error("failed to marshal result", "result", result, "decodeParamJSON", decodeParamJSON, "error", err)
return ""
}
return string(bytes)
}
func HexToNumber(hex string) string {
return abi_spec.HexToNumber(hex)
}
func NumberToHex(numString string) string {
return abi_spec.NumberToHex(numString)
}