Skip to content

Commit

Permalink
Merge pull request #116 from keep-network/bytes20-32
Browse files Browse the repository at this point in the history
Support bytes20 and bytes32 in Ethereum contract bindings
  • Loading branch information
lukasz-zimnoch authored May 1, 2023
2 parents 2632871 + b412b7a commit 5cc3757
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 0 deletions.
39 changes: 39 additions & 0 deletions pkg/utils/decode/bytes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package decode

import (
"fmt"

"github.com/ethereum/go-ethereum/common/hexutil"
)

// ParseBytes20 parses `string` into `[20]byte` type. The input string must have
// 20 bytes hex-encoded.
func ParseBytes20(str string) ([20]byte, error) {
bytesArray := [20]byte{}
slice, err := hexutil.Decode(str)
if err != nil {
return bytesArray, err
}
if len(slice) != 20 {
return bytesArray, fmt.Errorf("expected 20 bytes array; has: [%v]", len(slice))
}

copy(bytesArray[:], slice)
return bytesArray, nil
}

// ParseBytes32 parses `string` into `[32]byte` type. The input string must have
// 32 bytes hex-encoded.
func ParseBytes32(str string) ([32]byte, error) {
bytesArray := [32]byte{}
slice, err := hexutil.Decode(str)
if err != nil {
return bytesArray, err
}
if len(slice) != 32 {
return bytesArray, fmt.Errorf("expected 32 bytes array; has: [%v]", len(slice))
}

copy(bytesArray[:], slice)
return bytesArray, nil
}
126 changes: 126 additions & 0 deletions pkg/utils/decode/bytes_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package decode

import (
"fmt"
"testing"
)

func TestParseBytes20(t *testing.T) {
hexEncoded := "0x3805eed0bb0792eff8815addedb36add2c7257e5"
bytes, err := ParseBytes20(hexEncoded)
if err != nil {
t.Fatal(err)
}

roundtrip := fmt.Sprintf("0x%x", bytes)

if roundtrip != hexEncoded {
t.Errorf(
"unexpected parsed bytes\nexpected: %v\nactual: %v\n",
hexEncoded,
roundtrip,
)
}
}

func TestParseBytes20_Fail(t *testing.T) {

var tests = map[string]struct {
input string
expectedError string
}{
"too short": {
input: "0xFFFF",
expectedError: "expected 20 bytes array; has: [2]",
},
"empty": {
input: "",
expectedError: "empty hex string",
},
"just 0x prefix": {
input: "0x",
expectedError: "expected 20 bytes array; has: [0]",
},
"no prefix": {
input: "FF",
expectedError: "hex string without 0x prefix",
},
"invalid hex": {
input: "0xLMA0",
expectedError: "invalid hex string",
},
}

for testName, test := range tests {
t.Run(testName, func(t *testing.T) {
_, actualError := ParseBytes20(test.input)
if actualError.Error() != test.expectedError {
t.Errorf(
"unexpected error\nexpected: %v\nactual: %v\n",
test.expectedError,
actualError,
)
}
})
}
}

func TestParseBytes32(t *testing.T) {
hexEncoded := "0xad63a8286ea7fa22d75e167216171417a96c4753946fd45e3a8dff4e4f29a830"
bytes, err := ParseBytes32(hexEncoded)
if err != nil {
t.Fatal(err)
}

roundtrip := fmt.Sprintf("0x%x", bytes)

if roundtrip != hexEncoded {
t.Errorf(
"unexpected parsed bytes\nexpected: %v\nactual: %v\n",
hexEncoded,
roundtrip,
)
}
}

func TestParseBytes32_Fail(t *testing.T) {

var tests = map[string]struct {
input string
expectedError string
}{
"too short": {
input: "0xFFFF",
expectedError: "expected 32 bytes array; has: [2]",
},
"empty": {
input: "",
expectedError: "empty hex string",
},
"just 0x prefix": {
input: "0x",
expectedError: "expected 32 bytes array; has: [0]",
},
"no prefix": {
input: "FF",
expectedError: "hex string without 0x prefix",
},
"invalid hex": {
input: "0xLMA0",
expectedError: "invalid hex string",
},
}

for testName, test := range tests {
t.Run(testName, func(t *testing.T) {
_, actualError := ParseBytes32(test.input)
if actualError.Error() != test.expectedError {
t.Errorf(
"unexpected error\nexpected: %v\nactual: %v\n",
test.expectedError,
actualError,
)
}
})
}
}
4 changes: 4 additions & 0 deletions tools/generators/ethereum/contract_parsing.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,10 @@ func buildMethodInfo(
switch goType {
case "[]byte":
cmdParsingFn = "hexutil.Decode(%s)"
case "[20]byte":
cmdParsingFn = "decode.ParseBytes20(%s)"
case "[32]byte":
cmdParsingFn = "decode.ParseBytes32(%s)"
case "common.Address":
cmdParsingFn = "chainutil.AddressFromHex(%s)"
case "*big.Int":
Expand Down

0 comments on commit 5cc3757

Please sign in to comment.