Skip to content

Commit 9261c38

Browse files
committed
Support names in selector parser
1 parent a89e988 commit 9261c38

File tree

2 files changed

+146
-10
lines changed

2 files changed

+146
-10
lines changed

accounts/abi/selector_parser.go

Lines changed: 136 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@ func isDigit(c byte) bool {
1717
}
1818

1919
func isAlpha(c byte) bool {
20-
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == ' ')
20+
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
21+
}
22+
23+
func isSpace(c byte) bool {
24+
return c == ' '
2125
}
2226

2327
func isIdentifierSymbol(c byte) bool {
@@ -35,7 +39,7 @@ func parseToken(unescapedSelector string, isIdent bool) (string, string, error)
3539
}
3640
for position < len(unescapedSelector) {
3741
char := unescapedSelector[position]
38-
if !(isAlpha(char) || isDigit(char) || (isIdent && isIdentifierSymbol(char))) {
42+
if !(isAlpha(char) || isDigit(char) || (isIdent && isIdentifierSymbol(char)) || (!isIdent && isSpace(char))) {
3943
break
4044
}
4145
position++
@@ -48,6 +52,32 @@ func parseIdentifier(unescapedSelector string) (string, string, error) {
4852
}
4953

5054
func parseElementaryType(unescapedSelector string) (parsedType string, rest string, err error) {
55+
parsedType, rest, err = parseToken(unescapedSelector, false)
56+
if err != nil {
57+
return "", "", fmt.Errorf("failed to parse elementary type: %v", err)
58+
}
59+
parts := strings.Split(parsedType, " ")
60+
if len(parts) > 1 {
61+
parsedType = parsedType[len(parts[0])+1:]
62+
}
63+
// handle arrays
64+
for len(rest) > 0 && rest[0] == '[' {
65+
parsedType = parsedType + string(rest[0])
66+
rest = rest[1:]
67+
for len(rest) > 0 && isDigit(rest[0]) {
68+
parsedType = parsedType + string(rest[0])
69+
rest = rest[1:]
70+
}
71+
if len(rest) == 0 || rest[0] != ']' {
72+
return "", "", fmt.Errorf("failed to parse array: expected ']', got %c", unescapedSelector[0])
73+
}
74+
parsedType = parsedType + string(rest[0])
75+
rest = rest[1:]
76+
}
77+
return parsedType, rest, nil
78+
}
79+
80+
func parseElementaryTypeWithName(unescapedSelector string) (parsedType string, rest string, err error) {
5181
parsedType, rest, err = parseToken(unescapedSelector, false)
5282
if err != nil {
5383
return "", "", fmt.Errorf("failed to parse elementary type: %v", err)
@@ -95,7 +125,77 @@ func parseCompositeType(unescapedSelector string) (result []interface{}, rest st
95125
return result, rest[1:], nil
96126
}
97127

128+
func parseCompositeTypeWithName(unescapedSelector string) (result []interface{}, rest string, err error) {
129+
var name string
130+
parts := strings.Split(unescapedSelector, " ")
131+
if len(parts) < 2 {
132+
return nil, "", fmt.Errorf("expected name in the beginning, got %s", unescapedSelector)
133+
} else {
134+
name = parts[0]
135+
unescapedSelector = unescapedSelector[len(parts[0])+1:]
136+
}
137+
if len(unescapedSelector) == 0 || unescapedSelector[0] != '(' {
138+
return nil, "", fmt.Errorf("expected '(...', got %s", unescapedSelector)
139+
}
140+
result = []interface{}{name}
141+
var parsedType interface{}
142+
var counter int64
143+
parsedType, rest, err = parseTypeWithName(unescapedSelector[1:], counter)
144+
if err != nil {
145+
return nil, "", fmt.Errorf("failed to parse type: %v", err)
146+
}
147+
result = append(result, parsedType)
148+
for len(rest) > 0 && rest[0] != ')' {
149+
counter += 1
150+
parsedType, rest, err = parseTypeWithName(rest[1:], counter)
151+
if err != nil {
152+
return nil, "", fmt.Errorf("failed to parse type: %v", err)
153+
}
154+
result = append(result, parsedType)
155+
}
156+
if len(rest) == 0 || rest[0] != ')' {
157+
return nil, "", fmt.Errorf("expected ')', got '%s'", rest)
158+
}
159+
if len(rest) >= 3 && rest[1] == '[' && rest[2] == ']' {
160+
return append(result, "[]"), rest[3:], nil
161+
}
162+
return result, rest[1:], nil
163+
}
164+
165+
func parseFunctionsArgs(unescapedSelector string) (result []interface{}, rest string, err error) {
166+
if len(unescapedSelector) == 0 || unescapedSelector[0] != '(' {
167+
return nil, "", fmt.Errorf("expected '(...', got %s", unescapedSelector)
168+
}
169+
var parsedType interface{}
170+
var counter int64
171+
parsedType, rest, err = parseTypeWithName(unescapedSelector[1:], counter)
172+
if err != nil {
173+
return nil, "", fmt.Errorf("failed to parse type: %v", err)
174+
}
175+
result = []interface{}{parsedType}
176+
177+
for len(rest) > 0 && rest[0] != ')' {
178+
counter += 1
179+
parsedType, rest, err = parseTypeWithName(rest[1:], counter)
180+
if err != nil {
181+
return nil, "", fmt.Errorf("failed to parse type: %v", err)
182+
}
183+
result = append(result, parsedType)
184+
}
185+
if len(rest) == 0 || rest[0] != ')' {
186+
return nil, "", fmt.Errorf("expected ')', got '%s'", rest)
187+
}
188+
if len(rest) >= 3 && rest[1] == '[' && rest[2] == ']' {
189+
return append(result, "[]"), rest[3:], nil
190+
}
191+
return result, rest[1:], nil
192+
}
193+
98194
func parseType(unescapedSelector string) (interface{}, string, error) {
195+
parts := strings.Split(unescapedSelector, " ")
196+
if len(parts) > 1 {
197+
unescapedSelector = unescapedSelector[len(parts[0])+1:]
198+
}
99199
if len(unescapedSelector) == 0 {
100200
return nil, "", errors.New("empty type")
101201
}
@@ -106,22 +206,48 @@ func parseType(unescapedSelector string) (interface{}, string, error) {
106206
}
107207
}
108208

209+
func parseTypeWithName(unescapedSelector string, counter int64) (interface{}, string, error) {
210+
name, rest, _ := parseIdentifier(unescapedSelector)
211+
if len(rest) > 0 && rest[0] == ' ' {
212+
unescapedSelector = unescapedSelector[len(name)+1:]
213+
} else {
214+
name = fmt.Sprintf("name%d", counter)
215+
}
216+
if len(unescapedSelector) == 0 {
217+
return nil, "", errors.New("empty type")
218+
}
219+
if unescapedSelector[0] == '(' {
220+
return parseCompositeTypeWithName(fmt.Sprintf("%v %v", name, unescapedSelector))
221+
} else {
222+
return parseElementaryTypeWithName(fmt.Sprintf("%v %v", name, unescapedSelector))
223+
}
224+
}
225+
109226
func assembleArgs(args []interface{}) (arguments []ArgumentMarshaling, err error) {
110227
arguments = make([]ArgumentMarshaling, 0)
111-
for i, arg := range args {
112-
// generate dummy name to avoid unmarshal issues
113-
name := fmt.Sprintf("name%d", i)
228+
for _, arg := range args {
229+
var name string
114230
if s, ok := arg.(string); ok {
231+
if s == "[]" {
232+
arguments = append(arguments, ArgumentMarshaling{Name: name, Type: s, InternalType: s})
233+
continue
234+
}
115235
parts := strings.Split(s, " ")
116-
if len(parts) > 2 {
117-
return nil, fmt.Errorf("more than 2 spaces in type declaration in selector %s", s)
118-
} else if len(parts) == 2 {
236+
if len(parts) < 2 {
237+
return nil, fmt.Errorf("no name in arg %s", s)
238+
} else {
119239
name = parts[0]
120-
s = parts[1]
240+
s = s[len(name)+1:]
121241
}
122242
arguments = append(arguments, ArgumentMarshaling{Name: name, Type: s, InternalType: s})
123243
} else if components, ok := arg.([]interface{}); ok {
124244
var subArgs []ArgumentMarshaling
245+
if len(components) < 2 {
246+
return nil, fmt.Errorf("no name in components %s", components)
247+
} else {
248+
name = components[0].(string)
249+
components = components[1:]
250+
}
125251
subArgs, err = assembleArgs(components)
126252
if err != nil {
127253
return nil, fmt.Errorf("failed to assemble components: %v", err)
@@ -153,7 +279,7 @@ func ParseSelector(unescapedSelector string) (m SelectorMarshaling, err error) {
153279
if len(rest) >= 2 && rest[0] == '(' && rest[1] == ')' {
154280
rest = rest[2:]
155281
} else {
156-
args, rest, err = parseCompositeType(rest)
282+
args, rest, err = parseFunctionsArgs(rest)
157283
if err != nil {
158284
return SelectorMarshaling{}, fmt.Errorf("failed to parse selector '%s': %v", unescapedSelector, err)
159285
}

accounts/abi/selector_parser_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"fmt"
2121
"log"
2222
"reflect"
23+
"strings"
2324
"testing"
2425
)
2526

@@ -29,6 +30,11 @@ func TestParseSelector(t *testing.T) {
2930
for i, typeOrComponents := range types {
3031
name := fmt.Sprintf("name%d", i)
3132
if typeName, ok := typeOrComponents.(string); ok {
33+
names := strings.Split(typeName, " ")
34+
if len(names) > 1 {
35+
name = names[0]
36+
typeName = typeName[len(name)+1:]
37+
}
3238
result = append(result, ArgumentMarshaling{name, typeName, typeName, nil, false})
3339
} else if components, ok := typeOrComponents.([]ArgumentMarshaling); ok {
3440
result = append(result, ArgumentMarshaling{name, "tuple", "tuple", components, false})
@@ -59,6 +65,10 @@ func TestParseSelector(t *testing.T) {
5965
mkType([][]ArgumentMarshaling{mkType("uint256", "uint256")}, "bytes32[]")},
6066
{"singleArrayNestWithArrayAndArray((uint256[],address[2],uint8[4][][5])[],bytes32[])", "singleArrayNestWithArrayAndArray",
6167
mkType([][]ArgumentMarshaling{mkType("uint256[]", "address[2]", "uint8[4][][5]")}, "bytes32[]")},
68+
{"transfer(to address,amount uint256)", "transfer",
69+
mkType("to address", "amount uint256")},
70+
{"execute(((a address,c uint256,b uint8),(d uint8,e bytes)),(address,uint256),(uint8,(uint256,address),(uint256,address),address,address,bytes),(uint256,bytes),(uint256,bytes))", "execute",
71+
mkType(mkType(mkType("a address", "c uint256", "b uint8"), mkType("d uint8", "e bytes")), mkType("address", "uint256"), mkType("uint8", mkType("uint256", "address"), mkType("uint256", "address"), "address", "address", "bytes"), mkType("uint256", "bytes"), mkType("uint256", "bytes"))},
6272
}
6373
for i, tt := range tests {
6474
selector, err := ParseSelector(tt.input)

0 commit comments

Comments
 (0)