Move abi-spec to status-go
This commit is contained in:
parent
bcdb14bd48
commit
e49236a83c
|
@ -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), ¶msRaw); 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
|
||||
}
|
|
@ -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))
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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])
|
||||
}
|
|
@ -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 ""
|
||||
}
|
|
@ -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"))
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue