-
Notifications
You must be signed in to change notification settings - Fork 0
/
abi.go
137 lines (120 loc) · 3.39 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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Copyright (c) 2018 The VeChainThor developers
// Copyright (c) 2019 The PlayMaker developers
// Distributed under the GNU Lesser General Public License v3.0 software license, see the accompanying
// file LICENSE or <https://www.gnu.org/licenses/lgpl-3.0.html>
package abi
import (
"encoding/json"
"errors"
ethabi "github.com/ethereum/go-ethereum/accounts/abi"
"github.com/playmakerchain/powerplay/powerplay"
)
// ABI holds information about methods and events of contract.
type ABI struct {
constructor *Method
methods []*Method
events []*Event
nameToMethod map[string]*Method
nameToEvent map[string]*Event
idToMethod map[MethodID]*Method
idToEvent map[powerplay.Bytes32]*Event
}
// New create an ABI instance.
func New(data []byte) (*ABI, error) {
var fields []struct {
Type string
Name string
Constant bool
Anonymous bool
Inputs []ethabi.Argument
Outputs []ethabi.Argument
}
if err := json.Unmarshal(data, &fields); err != nil {
return nil, err
}
abi := &ABI{
nameToMethod: make(map[string]*Method),
nameToEvent: make(map[string]*Event),
idToMethod: make(map[MethodID]*Method),
idToEvent: make(map[powerplay.Bytes32]*Event),
}
for _, field := range fields {
switch field.Type {
case "constructor":
abi.constructor = &Method{
MethodID{},
ðabi.Method{Inputs: field.Inputs},
}
// empty defaults to function according to the abi spec
case "function", "":
ethMethod := ethabi.Method{
Name: field.Name,
Const: field.Constant,
Inputs: field.Inputs,
Outputs: field.Outputs,
}
var id MethodID
copy(id[:], ethMethod.Id())
method := &Method{id, ðMethod}
abi.methods = append(abi.methods, method)
abi.idToMethod[id] = method
abi.nameToMethod[ethMethod.Name] = method
case "event":
ethEvent := ethabi.Event{
Name: field.Name,
Anonymous: field.Anonymous,
Inputs: field.Inputs,
}
event := newEvent(ðEvent)
abi.events = append(abi.events, event)
abi.idToEvent[event.ID()] = event
abi.nameToEvent[ethEvent.Name] = event
}
}
return abi, nil
}
// Constructor returns the constructor method if any.
func (a *ABI) Constructor() *Method {
return a.constructor
}
// Methods returns all methods excluding constructor.
func (a *ABI) Methods() []*Method {
return a.methods
}
// Events returns all events
func (a *ABI) Events() []*Event {
return a.events
}
// MethodByInput find the method for given input.
// If the input shorter than MethodID, or method not found, an error returned.
func (a *ABI) MethodByInput(input []byte) (*Method, error) {
id, err := ExtractMethodID(input)
if err != nil {
return nil, err
}
m, found := a.idToMethod[id]
if !found {
return nil, errors.New("method not found")
}
return m, nil
}
// MethodByName find method for the given method name.
func (a *ABI) MethodByName(name string) (*Method, bool) {
m, found := a.nameToMethod[name]
return m, found
}
// MethodByID returns method for given method id.
func (a *ABI) MethodByID(id MethodID) (*Method, bool) {
m, found := a.idToMethod[id]
return m, found
}
// EventByName find event for the given event name.
func (a *ABI) EventByName(name string) (*Event, bool) {
e, found := a.nameToEvent[name]
return e, found
}
// EventByID returns the event for the given event id.
func (a *ABI) EventByID(id powerplay.Bytes32) (*Event, bool) {
e, found := a.idToEvent[id]
return e, found
}