-
Notifications
You must be signed in to change notification settings - Fork 4
/
contract_interface.go
131 lines (114 loc) · 2.72 KB
/
contract_interface.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
package ast
import (
"github.com/dipdup-net/go-lib/tools/ast/interfaces"
"github.com/dipdup-net/go-lib/tools/consts"
)
// contract tags
const (
ContractTagFA1 = "fa1"
ContractTagFA1_2 = "fa1-2"
ContractTagFA2 = "fa2"
ContractTagViewNat = "view_nat"
ContractTagViewAddress = "view_address"
ContractTagViewBalanceOf = "view_balance_of"
)
type contractInterface struct {
Entrypoints map[string]Node
IsRoot bool
}
var interfaceTrees = map[string]contractInterface{}
// FindContractInterfaces -
func FindContractInterfaces(tree *TypedAst) []string {
if initInterfaceTrees() != nil {
return nil
}
tags := make([]string, 0)
for tag := range interfaceTrees {
if FindContractInterface(tree, tag) {
tags = append(tags, tag)
}
}
return tags
}
func findViewContractInterfaces(tree *TypedAst) []string {
if initInterfaceTrees() != nil {
return nil
}
tags := make([]string, 0)
for _, tag := range []string{ContractTagViewNat, ContractTagViewAddress, ContractTagViewBalanceOf} {
if FindContractInterface(tree, tag) {
tags = append(tags, tag)
}
}
return tags
}
// FindContractInterface -
func FindContractInterface(tree *TypedAst, name string) bool {
if initInterfaceTrees() != nil {
return false
}
if contract, ok := interfaceTrees[name]; ok {
return findEntrypoints(tree, contract, nil)
}
return false
}
func findEntrypoints(tree *TypedAst, ci contractInterface, exists map[string]struct{}) bool {
if ci.IsRoot {
if len(tree.Nodes) != 1 || len(ci.Entrypoints) != 1 {
return false
}
return tree.Nodes[0].EqualType(ci.Entrypoints[consts.DefaultEntrypoint])
}
if exists == nil {
exists = make(map[string]struct{})
}
for i := range tree.Nodes {
if tree.Nodes[i].IsPrim(consts.OR) {
or := tree.Nodes[i].(*Or)
orTree := &TypedAst{
Nodes: []Node{or.LeftType, or.RightType},
}
if findEntrypoints(orTree, ci, exists) {
return true
}
continue
}
for name, subTree := range ci.Entrypoints {
if _, ok := exists[name]; !ok && tree.Nodes[i].EqualType(subTree) {
exists[name] = struct{}{}
}
}
if len(exists) == len(ci.Entrypoints) {
return true
}
}
return false
}
func initInterfaceTrees() error {
if len(interfaceTrees) > 0 {
return nil
}
all, err := interfaces.GetAll()
if err != nil {
return err
}
for name, data := range all {
ci := contractInterface{
Entrypoints: make(map[string]Node),
IsRoot: data.IsRoot,
}
for key, str := range data.Entrypoints {
var tree UntypedAST
if err := json.Unmarshal(str, &tree); err != nil {
return err
}
t, err := tree.ToTypedAST()
if err != nil {
return err
}
ci.Entrypoints[key] = t.Nodes[0]
}
interfaceTrees[name] = ci
}
return nil
}