github.com/theQRL/go-zond@v0.1.1/accounts/abi/selector_parser.go (about) 1 // Copyright 2022 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package abi 18 19 import ( 20 "errors" 21 "fmt" 22 ) 23 24 type SelectorMarshaling struct { 25 Name string `json:"name"` 26 Type string `json:"type"` 27 Inputs []ArgumentMarshaling `json:"inputs"` 28 } 29 30 func isDigit(c byte) bool { 31 return c >= '0' && c <= '9' 32 } 33 34 func isAlpha(c byte) bool { 35 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') 36 } 37 38 func isIdentifierSymbol(c byte) bool { 39 return c == '$' || c == '_' 40 } 41 42 func parseToken(unescapedSelector string, isIdent bool) (string, string, error) { 43 if len(unescapedSelector) == 0 { 44 return "", "", errors.New("empty token") 45 } 46 firstChar := unescapedSelector[0] 47 position := 1 48 if !(isAlpha(firstChar) || (isIdent && isIdentifierSymbol(firstChar))) { 49 return "", "", fmt.Errorf("invalid token start: %c", firstChar) 50 } 51 for position < len(unescapedSelector) { 52 char := unescapedSelector[position] 53 if !(isAlpha(char) || isDigit(char) || (isIdent && isIdentifierSymbol(char))) { 54 break 55 } 56 position++ 57 } 58 return unescapedSelector[:position], unescapedSelector[position:], nil 59 } 60 61 func parseIdentifier(unescapedSelector string) (string, string, error) { 62 return parseToken(unescapedSelector, true) 63 } 64 65 func parseElementaryType(unescapedSelector string) (string, string, error) { 66 parsedType, rest, err := parseToken(unescapedSelector, false) 67 if err != nil { 68 return "", "", fmt.Errorf("failed to parse elementary type: %v", err) 69 } 70 // handle arrays 71 for len(rest) > 0 && rest[0] == '[' { 72 parsedType = parsedType + string(rest[0]) 73 rest = rest[1:] 74 for len(rest) > 0 && isDigit(rest[0]) { 75 parsedType = parsedType + string(rest[0]) 76 rest = rest[1:] 77 } 78 if len(rest) == 0 || rest[0] != ']' { 79 return "", "", fmt.Errorf("failed to parse array: expected ']', got %c", unescapedSelector[0]) 80 } 81 parsedType = parsedType + string(rest[0]) 82 rest = rest[1:] 83 } 84 return parsedType, rest, nil 85 } 86 87 func parseCompositeType(unescapedSelector string) ([]interface{}, string, error) { 88 if len(unescapedSelector) == 0 || unescapedSelector[0] != '(' { 89 return nil, "", fmt.Errorf("expected '(', got %c", unescapedSelector[0]) 90 } 91 parsedType, rest, err := parseType(unescapedSelector[1:]) 92 if err != nil { 93 return nil, "", fmt.Errorf("failed to parse type: %v", err) 94 } 95 result := []interface{}{parsedType} 96 for len(rest) > 0 && rest[0] != ')' { 97 parsedType, rest, err = parseType(rest[1:]) 98 if err != nil { 99 return nil, "", fmt.Errorf("failed to parse type: %v", err) 100 } 101 result = append(result, parsedType) 102 } 103 if len(rest) == 0 || rest[0] != ')' { 104 return nil, "", fmt.Errorf("expected ')', got '%s'", rest) 105 } 106 if len(rest) >= 3 && rest[1] == '[' && rest[2] == ']' { 107 return append(result, "[]"), rest[3:], nil 108 } 109 return result, rest[1:], nil 110 } 111 112 func parseType(unescapedSelector string) (interface{}, string, error) { 113 if len(unescapedSelector) == 0 { 114 return nil, "", errors.New("empty type") 115 } 116 if unescapedSelector[0] == '(' { 117 return parseCompositeType(unescapedSelector) 118 } else { 119 return parseElementaryType(unescapedSelector) 120 } 121 } 122 123 func assembleArgs(args []interface{}) ([]ArgumentMarshaling, error) { 124 arguments := make([]ArgumentMarshaling, 0) 125 for i, arg := range args { 126 // generate dummy name to avoid unmarshal issues 127 name := fmt.Sprintf("name%d", i) 128 if s, ok := arg.(string); ok { 129 arguments = append(arguments, ArgumentMarshaling{name, s, s, nil, false}) 130 } else if components, ok := arg.([]interface{}); ok { 131 subArgs, err := assembleArgs(components) 132 if err != nil { 133 return nil, fmt.Errorf("failed to assemble components: %v", err) 134 } 135 tupleType := "tuple" 136 if len(subArgs) != 0 && subArgs[len(subArgs)-1].Type == "[]" { 137 subArgs = subArgs[:len(subArgs)-1] 138 tupleType = "tuple[]" 139 } 140 arguments = append(arguments, ArgumentMarshaling{name, tupleType, tupleType, subArgs, false}) 141 } else { 142 return nil, fmt.Errorf("failed to assemble args: unexpected type %T", arg) 143 } 144 } 145 return arguments, nil 146 } 147 148 // ParseSelector converts a method selector into a struct that can be JSON encoded 149 // and consumed by other functions in this package. 150 // Note, although uppercase letters are not part of the ABI spec, this function 151 // still accepts it as the general format is valid. 152 func ParseSelector(unescapedSelector string) (SelectorMarshaling, error) { 153 name, rest, err := parseIdentifier(unescapedSelector) 154 if err != nil { 155 return SelectorMarshaling{}, fmt.Errorf("failed to parse selector '%s': %v", unescapedSelector, err) 156 } 157 args := []interface{}{} 158 if len(rest) >= 2 && rest[0] == '(' && rest[1] == ')' { 159 rest = rest[2:] 160 } else { 161 args, rest, err = parseCompositeType(rest) 162 if err != nil { 163 return SelectorMarshaling{}, fmt.Errorf("failed to parse selector '%s': %v", unescapedSelector, err) 164 } 165 } 166 if len(rest) > 0 { 167 return SelectorMarshaling{}, fmt.Errorf("failed to parse selector '%s': unexpected string '%s'", unescapedSelector, rest) 168 } 169 170 // Reassemble the fake ABI and construct the JSON 171 fakeArgs, err := assembleArgs(args) 172 if err != nil { 173 return SelectorMarshaling{}, fmt.Errorf("failed to parse selector: %v", err) 174 } 175 176 return SelectorMarshaling{name, "function", fakeArgs}, nil 177 }