github.com/benorgera/go-ethereum@v1.10.18-0.20220401011646-b3f57b1a73ba/accounts/abi/selector_parser.go (about) 1 package abi 2 3 import ( 4 "fmt" 5 ) 6 7 type SelectorMarshaling struct { 8 Name string `json:"name"` 9 Type string `json:"type"` 10 Inputs []ArgumentMarshaling `json:"inputs"` 11 } 12 13 func isDigit(c byte) bool { 14 return c >= '0' && c <= '9' 15 } 16 17 func isAlpha(c byte) bool { 18 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') 19 } 20 21 func isIdentifierSymbol(c byte) bool { 22 return c == '$' || c == '_' 23 } 24 25 func parseToken(unescapedSelector string, isIdent bool) (string, string, error) { 26 if len(unescapedSelector) == 0 { 27 return "", "", fmt.Errorf("empty token") 28 } 29 firstChar := unescapedSelector[0] 30 position := 1 31 if !(isAlpha(firstChar) || (isIdent && isIdentifierSymbol(firstChar))) { 32 return "", "", fmt.Errorf("invalid token start: %c", firstChar) 33 } 34 for position < len(unescapedSelector) { 35 char := unescapedSelector[position] 36 if !(isAlpha(char) || isDigit(char) || (isIdent && isIdentifierSymbol(char))) { 37 break 38 } 39 position++ 40 } 41 return unescapedSelector[:position], unescapedSelector[position:], nil 42 } 43 44 func parseIdentifier(unescapedSelector string) (string, string, error) { 45 return parseToken(unescapedSelector, true) 46 } 47 48 func parseElementaryType(unescapedSelector string) (string, string, error) { 49 parsedType, rest, err := parseToken(unescapedSelector, false) 50 if err != nil { 51 return "", "", fmt.Errorf("failed to parse elementary type: %v", err) 52 } 53 // handle arrays 54 for len(rest) > 0 && rest[0] == '[' { 55 parsedType = parsedType + string(rest[0]) 56 rest = rest[1:] 57 for len(rest) > 0 && isDigit(rest[0]) { 58 parsedType = parsedType + string(rest[0]) 59 rest = rest[1:] 60 } 61 if len(rest) == 0 || rest[0] != ']' { 62 return "", "", fmt.Errorf("failed to parse array: expected ']', got %c", unescapedSelector[0]) 63 } 64 parsedType = parsedType + string(rest[0]) 65 rest = rest[1:] 66 } 67 return parsedType, rest, nil 68 } 69 70 func parseCompositeType(unescapedSelector string) ([]interface{}, string, error) { 71 if len(unescapedSelector) == 0 || unescapedSelector[0] != '(' { 72 return nil, "", fmt.Errorf("expected '(', got %c", unescapedSelector[0]) 73 } 74 parsedType, rest, err := parseType(unescapedSelector[1:]) 75 if err != nil { 76 return nil, "", fmt.Errorf("failed to parse type: %v", err) 77 } 78 result := []interface{}{parsedType} 79 for len(rest) > 0 && rest[0] != ')' { 80 parsedType, rest, err = parseType(rest[1:]) 81 if err != nil { 82 return nil, "", fmt.Errorf("failed to parse type: %v", err) 83 } 84 result = append(result, parsedType) 85 } 86 if len(rest) == 0 || rest[0] != ')' { 87 return nil, "", fmt.Errorf("expected ')', got '%s'", rest) 88 } 89 return result, rest[1:], nil 90 } 91 92 func parseType(unescapedSelector string) (interface{}, string, error) { 93 if len(unescapedSelector) == 0 { 94 return nil, "", fmt.Errorf("empty type") 95 } 96 if unescapedSelector[0] == '(' { 97 return parseCompositeType(unescapedSelector) 98 } else { 99 return parseElementaryType(unescapedSelector) 100 } 101 } 102 103 func assembleArgs(args []interface{}) ([]ArgumentMarshaling, error) { 104 arguments := make([]ArgumentMarshaling, 0) 105 for i, arg := range args { 106 // generate dummy name to avoid unmarshal issues 107 name := fmt.Sprintf("name%d", i) 108 if s, ok := arg.(string); ok { 109 arguments = append(arguments, ArgumentMarshaling{name, s, s, nil, false}) 110 } else if components, ok := arg.([]interface{}); ok { 111 subArgs, err := assembleArgs(components) 112 if err != nil { 113 return nil, fmt.Errorf("failed to assemble components: %v", err) 114 } 115 arguments = append(arguments, ArgumentMarshaling{name, "tuple", "tuple", subArgs, false}) 116 } else { 117 return nil, fmt.Errorf("failed to assemble args: unexpected type %T", arg) 118 } 119 } 120 return arguments, nil 121 } 122 123 // ParseSelector converts a method selector into a struct that can be JSON encoded 124 // and consumed by other functions in this package. 125 // Note, although uppercase letters are not part of the ABI spec, this function 126 // still accepts it as the general format is valid. 127 func ParseSelector(unescapedSelector string) (SelectorMarshaling, error) { 128 name, rest, err := parseIdentifier(unescapedSelector) 129 if err != nil { 130 return SelectorMarshaling{}, fmt.Errorf("failed to parse selector '%s': %v", unescapedSelector, err) 131 } 132 args := []interface{}{} 133 if len(rest) >= 2 && rest[0] == '(' && rest[1] == ')' { 134 rest = rest[2:] 135 } else { 136 args, rest, err = parseCompositeType(rest) 137 if err != nil { 138 return SelectorMarshaling{}, fmt.Errorf("failed to parse selector '%s': %v", unescapedSelector, err) 139 } 140 } 141 if len(rest) > 0 { 142 return SelectorMarshaling{}, fmt.Errorf("failed to parse selector '%s': unexpected string '%s'", unescapedSelector, rest) 143 } 144 145 // Reassemble the fake ABI and constuct the JSON 146 fakeArgs, err := assembleArgs(args) 147 if err != nil { 148 return SelectorMarshaling{}, fmt.Errorf("failed to parse selector: %v", err) 149 } 150 151 return SelectorMarshaling{name, "function", fakeArgs}, nil 152 }