/
abi.go
111 lines (95 loc) · 3.32 KB
/
abi.go
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
package eth
import (
"fmt"
"strings"
"github.com/vordev/VOR/core/logger"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/gobuffalo/packr"
"github.com/pkg/errors"
"github.com/tidwall/gjson"
)
type ContractCodec interface {
ABI() *abi.ABI
GetMethodID(method string) ([]byte, error)
EncodeMessageCall(method string, args ...interface{}) ([]byte, error)
UnpackLog(out interface{}, event string, log types.Log) error
}
// Contract holds the solidity contract's parsed ABI
type contractCodec struct {
abi abi.ABI
}
func getContractCodec(name string, box packr.Box) (ContractCodec, error) {
jsonFile, err := box.Find(name + ".json")
if err != nil {
return nil, errors.Wrap(err, "unable to read contract JSON")
}
abiBytes := gjson.GetBytes(jsonFile, "compilerOutput.abi")
abiParsed, err := abi.JSON(strings.NewReader(abiBytes.Raw))
if err != nil {
return nil, err
}
return &contractCodec{abiParsed}, nil
}
// GetContract loads the contract JSON file from ../../evm-contracts/abi/v0.4
// and parses the ABI JSON contents into an abi.ABI object
//
// NB: These contracts can be built by running
// yarn setup:contracts
// in the base project directory.
func GetContractCodec(name string) (ContractCodec, error) {
box := packr.NewBox("../../../evm-contracts/abi/v0.4")
return getContractCodec(name, box)
}
// GetV6Contract loads the contract JSON file from ../../evm-contracts/abi/v0.6
// and parses the ABI JSON contents into an abi.ABI object
//
// NB: These contracts can be built by running
// yarn setup:contracts
// in the base project directory.
func GetV6ContractCodec(name string) (ContractCodec, error) {
box := packr.NewBox("../../../evm-contracts/abi/v0.6")
return getContractCodec(name, box)
}
func (cc *contractCodec) ABI() *abi.ABI {
return &cc.abi
}
// EncodeMessageCall encodes method name and arguments into a byte array
// to conform with the contract's ABI
func (cc *contractCodec) EncodeMessageCall(method string, args ...interface{}) ([]byte, error) {
return cc.abi.Pack(method, args...)
}
// GetMethodID returns the first 4 bytes of the keccak256 hash of the method
// signature. The passed method is simply the method name, not the parameters,
// as defined by go-ethereum ABI Methods
//
// e.g.
// There are two functions have same name:
// * foo(int,int)
// * foo(uint,uint)
// The method name of the first one will be resolved as foo while the second one
// will be resolved as foo0.
func (cc *contractCodec) GetMethodID(method string) ([]byte, error) {
mabi, found := cc.abi.Methods[method]
if !found {
return []byte{}, errors.New("unable to find contract method " + method)
}
return mabi.ID, nil
}
// MustGetV6ContractEventID finds the event for the given contract by searching
// embedded contract assets from evm/, or panics if not found.
func MustGetV6ContractEventID(name, eventName string) common.Hash {
cc, err := GetV6ContractCodec(name)
if err != nil {
logger.Panic(fmt.Errorf("unable to find contract %s", name))
}
event, found := cc.ABI().Events[eventName]
if !found {
logger.Panic(fmt.Errorf("unable to find event %s for contract %s", eventName, name))
}
return event.ID
}
func (cc *contractCodec) UnpackLog(out interface{}, event string, log types.Log) error {
return gethUnpackLog(cc, out, event, log)
}