mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-03-01 17:13:45 +00:00
accounts/abi: support constructor/fallback/receive
This commit is contained in:
parent
bf541d1dfd
commit
fd81bb1b9f
2 changed files with 235 additions and 2 deletions
|
|
@ -68,9 +68,14 @@ func parseHumanReadableABIArray(signatures []string) ([]byte, error) {
|
|||
}
|
||||
isEvent := resultType == "event"
|
||||
isFunction := resultType == "function"
|
||||
isConstructor := resultType == "constructor"
|
||||
isFallback := resultType == "fallback"
|
||||
isReceive := resultType == "receive"
|
||||
|
||||
if name, ok := result["name"]; ok {
|
||||
normalized["name"] = name
|
||||
if !isConstructor && !isFallback && !isReceive {
|
||||
if name, ok := result["name"]; ok {
|
||||
normalized["name"] = name
|
||||
}
|
||||
}
|
||||
if inputs, ok := result["inputs"].([]ArgumentMarshaling); ok {
|
||||
normInputs := make([]map[string]interface{}, len(inputs))
|
||||
|
|
@ -169,6 +174,53 @@ func TestParseHumanReadableABI(t *testing.T) {
|
|||
}
|
||||
]`,
|
||||
},
|
||||
{
|
||||
name: "constructor",
|
||||
input: []string{"constructor(address owner, uint256 initialSupply)"},
|
||||
expected: `[
|
||||
{
|
||||
"type": "constructor",
|
||||
"inputs": [
|
||||
{"name": "owner", "type": "address"},
|
||||
{"name": "initialSupply", "type": "uint256"}
|
||||
],
|
||||
"stateMutability": "nonpayable"
|
||||
}
|
||||
]`,
|
||||
},
|
||||
{
|
||||
name: "constructor payable",
|
||||
input: []string{"constructor(address owner) payable"},
|
||||
expected: `[
|
||||
{
|
||||
"type": "constructor",
|
||||
"inputs": [
|
||||
{"name": "owner", "type": "address"}
|
||||
],
|
||||
"stateMutability": "payable"
|
||||
}
|
||||
]`,
|
||||
},
|
||||
{
|
||||
name: "fallback function",
|
||||
input: []string{"fallback()"},
|
||||
expected: `[
|
||||
{
|
||||
"type": "fallback",
|
||||
"stateMutability": "nonpayable"
|
||||
}
|
||||
]`,
|
||||
},
|
||||
{
|
||||
name: "receive function",
|
||||
input: []string{"receive() payable"},
|
||||
expected: `[
|
||||
{
|
||||
"type": "receive",
|
||||
"stateMutability": "payable"
|
||||
}
|
||||
]`,
|
||||
},
|
||||
{
|
||||
name: "multiple functions",
|
||||
input: []string{
|
||||
|
|
@ -384,6 +436,48 @@ func TestParseHumanReadableABI(t *testing.T) {
|
|||
}
|
||||
]`,
|
||||
},
|
||||
{
|
||||
name: "int and uint without explicit sizes normalize to 256 bits",
|
||||
input: []string{
|
||||
"function testIntUint(int value1, uint value2)",
|
||||
"function testArrays(int[] values1, uint[10] values2)",
|
||||
"function testMixed(int value1, uint value2, int8 value3, uint256 value4)",
|
||||
},
|
||||
expected: `[
|
||||
{
|
||||
"type": "function",
|
||||
"name": "testIntUint",
|
||||
"inputs": [
|
||||
{"name": "value1", "type": "int256"},
|
||||
{"name": "value2", "type": "uint256"}
|
||||
],
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable"
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"name": "testArrays",
|
||||
"inputs": [
|
||||
{"name": "values1", "type": "int256[]"},
|
||||
{"name": "values2", "type": "uint256[10]"}
|
||||
],
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable"
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"name": "testMixed",
|
||||
"inputs": [
|
||||
{"name": "value1", "type": "int256"},
|
||||
{"name": "value2", "type": "uint256"},
|
||||
{"name": "value3", "type": "int8"},
|
||||
{"name": "value4", "type": "uint256"}
|
||||
],
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable"
|
||||
}
|
||||
]`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
|
|
|||
|
|
@ -51,6 +51,18 @@ type ABIMarshaling map[string]interface{}
|
|||
func ParseHumanReadableABI(signature string) (ABIMarshaling, error) {
|
||||
signature = skipWhitespace(signature)
|
||||
|
||||
if strings.HasPrefix(signature, "constructor") {
|
||||
return ParseConstructor(signature)
|
||||
}
|
||||
|
||||
if strings.HasPrefix(signature, "fallback") {
|
||||
return ParseFallback(signature)
|
||||
}
|
||||
|
||||
if strings.HasPrefix(signature, "receive") {
|
||||
return ParseReceive(signature)
|
||||
}
|
||||
|
||||
if strings.HasPrefix(signature, "event ") || (strings.Contains(signature, "(") && strings.Contains(signature, "indexed")) {
|
||||
event, err := ParseEvent(signature)
|
||||
if err != nil {
|
||||
|
|
@ -151,6 +163,23 @@ func parseKeyword(s string, keyword string) (string, bool) {
|
|||
return skipWhitespace(rest), true
|
||||
}
|
||||
|
||||
// normalizeType normalizes bare int/uint to int256/uint256, including arrays
|
||||
func normalizeType(typeName string) string {
|
||||
if typeName == "int" {
|
||||
return "int256"
|
||||
}
|
||||
if typeName == "uint" {
|
||||
return "uint256"
|
||||
}
|
||||
if strings.HasPrefix(typeName, "int[") {
|
||||
return "int256" + typeName[3:]
|
||||
}
|
||||
if strings.HasPrefix(typeName, "uint[") {
|
||||
return "uint256" + typeName[4:]
|
||||
}
|
||||
return typeName
|
||||
}
|
||||
|
||||
func parseElementaryType(unescapedSelector string) (string, string, error) {
|
||||
parsedType, rest, err := parseToken(unescapedSelector, false)
|
||||
if err != nil {
|
||||
|
|
@ -169,6 +198,7 @@ func parseElementaryType(unescapedSelector string) (string, string, error) {
|
|||
parsedType = parsedType + string(rest[0])
|
||||
rest = rest[1:]
|
||||
}
|
||||
parsedType = normalizeType(parsedType)
|
||||
return parsedType, rest, nil
|
||||
}
|
||||
|
||||
|
|
@ -431,6 +461,115 @@ func ParseError(unescapedSelector string) (ErrorMarshaling, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// ParseConstructor parses a constructor signature
|
||||
func ParseConstructor(signature string) (ABIMarshaling, error) {
|
||||
signature = skipWhitespace(signature)
|
||||
|
||||
rest, _ := parseKeyword(signature, "constructor")
|
||||
rest = skipWhitespace(rest)
|
||||
|
||||
if len(rest) == 0 || rest[0] != '(' {
|
||||
return nil, fmt.Errorf("expected '(' after constructor keyword")
|
||||
}
|
||||
rest = rest[1:]
|
||||
|
||||
parenCount := 1
|
||||
paramEnd := 0
|
||||
for i := 0; i < len(rest); i++ {
|
||||
if rest[i] == '(' {
|
||||
parenCount++
|
||||
} else if rest[i] == ')' {
|
||||
parenCount--
|
||||
if parenCount == 0 {
|
||||
paramEnd = i
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if parenCount != 0 {
|
||||
return nil, fmt.Errorf("unbalanced parentheses in constructor signature")
|
||||
}
|
||||
|
||||
paramsStr := rest[:paramEnd]
|
||||
arguments, err := parseParameterList(paramsStr, false)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse constructor parameters: %v", err)
|
||||
}
|
||||
|
||||
rest = skipWhitespace(rest[paramEnd+1:])
|
||||
|
||||
stateMutability := "nonpayable"
|
||||
if newRest, found := parseKeyword(rest, "payable"); found {
|
||||
stateMutability = "payable"
|
||||
rest = newRest
|
||||
}
|
||||
|
||||
result := make(ABIMarshaling)
|
||||
result["type"] = "constructor"
|
||||
result["inputs"] = arguments
|
||||
result["stateMutability"] = stateMutability
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ParseFallback parses a fallback function signature
|
||||
// ParseFallback parses a fallback function signature (no parameters allowed)
|
||||
func ParseFallback(signature string) (ABIMarshaling, error) {
|
||||
signature = skipWhitespace(signature)
|
||||
|
||||
rest, _ := parseKeyword(signature, "fallback")
|
||||
rest = skipWhitespace(rest)
|
||||
|
||||
if len(rest) == 0 || rest[0] != '(' {
|
||||
return nil, fmt.Errorf("expected '(' after fallback keyword")
|
||||
}
|
||||
rest = rest[1:]
|
||||
|
||||
if len(rest) == 0 || rest[0] != ')' {
|
||||
return nil, fmt.Errorf("fallback function cannot have parameters")
|
||||
}
|
||||
rest = skipWhitespace(rest[1:])
|
||||
|
||||
stateMutability := "nonpayable"
|
||||
if newRest, found := parseKeyword(rest, "payable"); found {
|
||||
stateMutability = "payable"
|
||||
rest = newRest
|
||||
}
|
||||
|
||||
result := make(ABIMarshaling)
|
||||
result["type"] = "fallback"
|
||||
result["stateMutability"] = stateMutability
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ParseReceive parses a receive function signature (no parameters, always payable)
|
||||
func ParseReceive(signature string) (ABIMarshaling, error) {
|
||||
signature = skipWhitespace(signature)
|
||||
|
||||
rest, _ := parseKeyword(signature, "receive")
|
||||
rest = skipWhitespace(rest)
|
||||
|
||||
if len(rest) == 0 || rest[0] != '(' {
|
||||
return nil, fmt.Errorf("expected '(' after receive keyword")
|
||||
}
|
||||
rest = rest[1:]
|
||||
|
||||
if len(rest) == 0 || rest[0] != ')' {
|
||||
return nil, fmt.Errorf("receive function cannot have parameters")
|
||||
}
|
||||
rest = skipWhitespace(rest[1:])
|
||||
|
||||
stateMutability := "payable"
|
||||
if newRest, found := parseKeyword(rest, "payable"); found {
|
||||
rest = newRest
|
||||
}
|
||||
|
||||
result := make(ABIMarshaling)
|
||||
result["type"] = "receive"
|
||||
result["stateMutability"] = stateMutability
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func ParseSelector(unescapedSelector string) (SelectorMarshaling, error) {
|
||||
unescapedSelector = skipWhitespace(unescapedSelector)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue