diff --git a/accounts/abi/argument.go b/accounts/abi/argument.go index 90fd9d05fc4f7..fdc6ff164806b 100644 --- a/accounts/abi/argument.go +++ b/accounts/abi/argument.go @@ -272,14 +272,13 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) { return ret, nil } -// capitalise makes the first character of a string upper case, also removing any -// prefixing underscores from the variable names. -func capitalise(input string) string { - for len(input) > 0 && input[0] == '_' { - input = input[1:] - } - if len(input) == 0 { - return "" +// ToCamelCase converts an under-score string to a camel-case string +func ToCamelCase(input string) string { + parts := strings.Split(input, "_") + for i, s := range parts { + if len(s) > 0 { + parts[i] = strings.ToUpper(s[:1]) + s[1:] + } } - return strings.ToUpper(input[:1]) + input[1:] + return strings.Join(parts, "") } diff --git a/accounts/abi/bind/bind.go b/accounts/abi/bind/bind.go index 4dca4b4ea361a..21e16060c9261 100644 --- a/accounts/abi/bind/bind.go +++ b/accounts/abi/bind/bind.go @@ -387,48 +387,15 @@ var methodNormalizer = map[Lang]func(string) string{ // capitalise makes a camel-case string which starts with an upper case character. func capitalise(input string) string { - for len(input) > 0 && input[0] == '_' { - input = input[1:] - } - if len(input) == 0 { - return "" - } - return toCamelCase(strings.ToUpper(input[:1]) + input[1:]) + return abi.ToCamelCase(input) } // decapitalise makes a camel-case string which starts with a lower case character. func decapitalise(input string) string { - for len(input) > 0 && input[0] == '_' { - input = input[1:] - } - if len(input) == 0 { - return "" - } - return toCamelCase(strings.ToLower(input[:1]) + input[1:]) -} - -// toCamelCase converts an under-score string to a camel-case string -func toCamelCase(input string) string { - toupper := false + // NOTE: This is the current behavior, it doesn't match the comment + // above and needs to be investigated. + return abi.ToCamelCase(input) - result := "" - for k, v := range input { - switch { - case k == 0: - result = strings.ToUpper(string(input[0])) - - case toupper: - result += strings.ToUpper(string(v)) - toupper = false - - case v == '_': - toupper = true - - default: - result += string(v) - } - } - return result } // structured checks whether a list of ABI data types has enough information to diff --git a/accounts/abi/reflect.go b/accounts/abi/reflect.go index 6ec79a12fa3eb..f541cf3bfe8f3 100644 --- a/accounts/abi/reflect.go +++ b/accounts/abi/reflect.go @@ -186,7 +186,7 @@ func mapAbiToStructFields(args Arguments, value reflect.Value) (map[string]strin for _, arg := range args { abiFieldName := arg.Name - structFieldName := capitalise(abiFieldName) + structFieldName := ToCamelCase(abiFieldName) if structFieldName == "" { return nil, fmt.Errorf("abi: purely underscored output cannot unpack to struct") diff --git a/accounts/abi/unpack_test.go b/accounts/abi/unpack_test.go index 22aa1a8579d13..3873414c9f8c6 100644 --- a/accounts/abi/unpack_test.go +++ b/accounts/abi/unpack_test.go @@ -310,6 +310,53 @@ var unpackTests = []unpackTest{ Int2 *big.Int }{big.NewInt(1), big.NewInt(2)}, }, + { + def: `[{"name":"int_one","type":"int256"}]`, + enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + want: struct { + IntOne *big.Int + }{big.NewInt(1)}, + }, + { + def: `[{"name":"int__one","type":"int256"}]`, + enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + want: struct { + IntOne *big.Int + }{big.NewInt(1)}, + }, + { + def: `[{"name":"int_one_","type":"int256"}]`, + enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + want: struct { + IntOne *big.Int + }{big.NewInt(1)}, + }, + { + def: `[{"name":"int_one","type":"int256"}, {"name":"intone","type":"int256"}]`, + enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + want: struct { + IntOne *big.Int + Intone *big.Int + }{big.NewInt(1), big.NewInt(2)}, + }, + { + def: `[{"name":"___","type":"int256"}]`, + enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + want: struct { + IntOne *big.Int + Intone *big.Int + }{}, + err: "abi: purely underscored output cannot unpack to struct", + }, + { + def: `[{"name":"int_one","type":"int256"},{"name":"IntOne","type":"int256"}]`, + enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + want: struct { + Int1 *big.Int + Int2 *big.Int + }{}, + err: "abi: multiple outputs mapping to the same struct field 'IntOne'", + }, { def: `[{"name":"int","type":"int256"},{"name":"Int","type":"int256"}]`, enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",