使用 Go 进行 Solidity ABI 编解码

Jun 29 2019 blockchain

类型对应关系

类型 Solidity Go
字符串 string string
布尔 bool bool
地址 address common.Address
无符号整数 uintN uintN 或 *big.Int
有符号整数 intN intN 或 *big.Int
固定长度字节数组 bytesN [N]byte
动态长度字节数组 bytes []byte
固定长度数组 T[k] array
动态长度数组 T[] slice
枚举 enum uintN
映射 mapping -
结构体 struct -

备注:

使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package main

import (
"encoding/json"
"fmt"
"math/big"
"os"
"strings"

"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
)

/*
pragma solidity ^0.6.0;

interface ABI {
function List(address owner) external view returns (address[] memory receiver, uint256[] memory values);
function Value(address owner) external view returns (uint256 values);
}
*/

const RawABI = `[
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
}
],
"name": "List",
"outputs": [
{
"internalType": "address[]",
"name": "receiver",
"type": "address[]"
},
{
"internalType": "uint256[]",
"name": "values",
"type": "uint256[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
}
],
"name": "Value",
"outputs": [
{
"internalType": "uint256",
"name": "values",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
}
]`

func main() {
parsed, err := abi.JSON(strings.NewReader(RawABI))
if err != nil {
panic(err)
}

{
address := common.HexToAddress("0x80819B3F30e9D77DE6BE3Df9d6EfaA88261DfF9c")

// Value 参数编码
valueInput, err := parsed.Pack("Value", address)
if err != nil {
panic(err)
}

// Value 参数解码
var addrwant common.Address
if err := parsed.Methods["Value"].Inputs.Unpack(&addrwant, valueInput[4:]); err != nil {
panic(err)
}
fmt.Println("should equals", addrwant == address)

// Value 返回值解码
var balance *big.Int
var returns = common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000005f5e100")
if err := parsed.Unpack(&balance, "Value", returns); err != nil {
panic(err)
}
fmt.Println("Value 返回值", balance)
}

// List 返回值编码
{
// 注意:字段名称需要与 ABI 编码的定义的一致
// 比如,这里 ABI 编码返回值第一个为 receiver 那么转化为 Go 就是首字母大写的 Receiver
var res struct {
Receiver []common.Address // 返回值名称
Values []*big.Int // 返回值名称
}

// {"Receiver":["0x80819b3f30e9d77de6be3df9d6efaa88261dff9c"],"Values":[10]}
raw := common.Hex2Bytes("00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000080819b3f30e9d77de6be3df9d6efaa88261dff9c0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000a")
if err := parsed.Unpack(&res, "List", raw); err != nil {
panic(err)
}
_ = json.NewEncoder(os.Stdout).Encode(&res)
}
}