Skip to content

Commit

Permalink
Merge pull request #1 from kaleido-io/align-tuple
Browse files Browse the repository at this point in the history
Working through PR 29
  • Loading branch information
jimthematrix authored Nov 30, 2022
2 parents 2dd5992 + 4c8221b commit cf018f0
Show file tree
Hide file tree
Showing 9 changed files with 454 additions and 108 deletions.
2 changes: 1 addition & 1 deletion cmd/ffsigner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func TestRunOK(t *testing.T) {
defer close(done)
err := Execute()
if err != nil {
assert.Regexp(t, "context deadline", err)
assert.Error(t, err)
}
}()

Expand Down
3 changes: 2 additions & 1 deletion internal/signermsgs/en_error_messges.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ var (
MsgTupleABINotArrayOrMap = ffe("FF22038", "Input type %T is not array or map for component %s")
MsgTupleInABINoName = ffe("FF22039", "Tuple child %d does not have a name for component %s")
MsgMissingInputKeyABITuple = ffe("FF22040", "Input map missing key '%s' required for tuple component %s")
MsgBadABITypeComponent = ffe("FF22041", "Bad ABI type component: %s")
MsgBadABITypeComponent = ffe("FF22041", "Bad ABI type component: %d")
MsgWrongTypeComponentABIEncode = ffe("FF22042", "Incorrect type expected=%s found=%T for ABI encoding of component %s")
MsgInsufficientDataABIEncode = ffe("FF22043", "Insufficient data elements on input expected=%d found=%d for ABI encoding of component %s")
MsgNumberTooLargeABIEncode = ffe("FF22044", "Numeric value does not fit in bit length %d for ABI encoding of component %s")
Expand All @@ -77,4 +77,5 @@ var (
MsgMissingRegexpCaptureGroup = ffe("FF22057", "Regular expression is missing a capture group (subexpression) for address: /%s/")
MsgAddressMismatch = ffe("FF22059", "Address '%s' loaded from wallet file does not match requested lookup address / filename '%s'")
MsgFailedToStartListener = ffe("FF22060", "Failed to start filesystem listener: %s")
MsgDecodeNotTuple = ffe("FF22061", "Decode can only be called against a root tuple component type=%d")
)
87 changes: 86 additions & 1 deletion pkg/abi/abi.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,32 @@

/*
Tl;dr
sampleABI, _ := ParseABI([]byte(`[
{
"name": "transfer",
"inputs": [
{"name": "recipient", "internalType": "address", "type": "address" },
{"name": "amount", "internalType": "uint256", "type": "uint256"}
],
"outputs": [{"internalType": "bool", "type": "bool"}],
"stateMutability": "nonpayable",
"type": "function"
}
]`))
transferABIFn := sampleABI.Functions()["transfer"]
sampleABICallBytes, _ := transferABIFn.EncodeCallDataJSON([]byte(
`{"recipient":"0x4a0d852ebb58fc88cb260bb270ae240f72edc45b","amount":"100000000000000000"}`,
))
fmt.Printf("ABI Call Bytes: %s\n", hex.EncodeToString(sampleABICallBytes))
values, _ := transferABIFn.DecodeCallData(sampleABICallBytes)
outputJSON, _ := NewSerializer().
SetFormattingMode(FormatAsObjects).
SetByteSerializer(HexByteSerializer0xPrefix).
SerializeJSON(values)
fmt.Printf("Back to JSON: %s\n", outputJSON)
The abi package allows encoding and decoding of ABI encoded bytes, for the inputs/outputs
to EVM functions, and the parsing of EVM logs/events.
Expand Down Expand Up @@ -227,6 +253,11 @@ func (e *Entry) IsFunction() bool {
}
}

func ParseABI(data []byte) (ABI, error) {
var abi ABI
return abi, json.Unmarshal(data, &abi)
}

// Validate processes all the components of all the entries in this ABI, to build a parsing tree
func (a ABI) Validate() (err error) {
return a.ValidateCtx(context.Background())
Expand Down Expand Up @@ -352,10 +383,38 @@ func (pa ParameterArray) DecodeABIDataCtx(ctx context.Context, b []byte, offset
if err != nil {
return nil, err
}
_, cv, err = decodeABIElement(ctx, "", b, offset, offset, component.(*typeComponent))
_, cv, err = walkTupleABIBytes(ctx, b, offset, component.(*typeComponent))
return cv, err
}

// EncodeABIData is a helper to go all the way from JSON data to encoded ABI bytes
func (pa ParameterArray) EncodeABIDataJSON(jsonData []byte) ([]byte, error) {
return pa.EncodeABIDataJSONCtx(context.Background(), jsonData)
}

// EncodeABIData is a helper to go all the way from JSON data to encoded ABI bytes
func (pa ParameterArray) EncodeABIDataJSONCtx(ctx context.Context, jsonData []byte) ([]byte, error) {
cv, err := pa.ParseJSONCtx(ctx, jsonData)
if err != nil {
return nil, err
}
return cv.EncodeABIDataCtx(ctx)
}

// EncodeABIData goes all the way from interface inputs, to encoded ABI bytes
// The TypeComponentTree is created and discarded within the function
func (pa ParameterArray) EncodeABIDataValues(v interface{}) ([]byte, error) {
return pa.EncodeABIDataValuesCtx(context.Background(), v)
}

func (pa ParameterArray) EncodeABIDataValuesCtx(ctx context.Context, v interface{}) ([]byte, error) {
cv, err := pa.ParseExternalDataCtx(ctx, v)
if err != nil {
return nil, err
}
return cv.EncodeABIDataCtx(ctx)
}

// String returns the signature string. If a Validate needs to be initiated, and that
// parse fails, then the error is logged, but is not returned
func (e *Entry) String() string {
Expand Down Expand Up @@ -396,6 +455,32 @@ func (e *Entry) FunctionSelectorBytes() ethtypes.HexBytes0xPrefix {
return id
}

// EncodeCallDataValues is a helper to go straight from an JSON input, to binary encoded call data
func (e *Entry) EncodeCallDataJSON(jsonData []byte) ([]byte, error) {
return e.EncodeCallDataJSONCtx(context.Background(), jsonData)
}

func (e *Entry) EncodeCallDataJSONCtx(ctx context.Context, jsonData []byte) ([]byte, error) {
cv, err := e.Inputs.ParseJSONCtx(ctx, jsonData)
if err != nil {
return nil, err
}
return e.EncodeCallDataCtx(ctx, cv)
}

// EncodeCallDataValues is a helper to go straight from an interface input, such as a map or array, to call data
func (e *Entry) EncodeCallDataValues(values interface{}) ([]byte, error) {
return e.EncodeCallDataValuesCtx(context.Background(), values)
}

func (e *Entry) EncodeCallDataValuesCtx(ctx context.Context, values interface{}) ([]byte, error) {
cv, err := e.Inputs.ParseExternalDataCtx(ctx, values)
if err != nil {
return nil, err
}
return e.EncodeCallDataCtx(ctx, cv)
}

// EncodeCallData serializes the inputs of the entry, prefixed with the function selector
func (e *Entry) EncodeCallData(cv *ComponentValue) ([]byte, error) {
return e.EncodeCallDataCtx(context.Background(), cv)
Expand Down
92 changes: 92 additions & 0 deletions pkg/abi/abi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,20 @@ const sampleABI3 = `[
}
]`

const sampleABI4 = `[
{
"name": "simple",
"type": "function",
"inputs": [
{
"name": "a",
"type": "string"
}
],
"outputs": []
}
]`

func testABI(t *testing.T, abiJSON string) (abi ABI) {
err := json.Unmarshal([]byte(abiJSON), &abi)
assert.NoError(t, err)
Expand Down Expand Up @@ -239,6 +253,36 @@ func TestDocsFunctionCallExample(t *testing.T) {
assert.Equal(t, "0xa9059cbb2ab09eb219583f4a59a5d0623ade346d962bcd4e46b11da047c9049b", sigHash.String())
}

func TestTLdr(t *testing.T) {

sampleABI, _ := ParseABI([]byte(`[
{
"name": "transfer",
"inputs": [
{"name": "recipient", "internalType": "address", "type": "address" },
{"name": "amount", "internalType": "uint256", "type": "uint256"}
],
"outputs": [{"internalType": "bool", "type": "bool"}],
"stateMutability": "nonpayable",
"type": "function"
}
]`))
transferABIFn := sampleABI.Functions()["transfer"]
sampleABICallBytes, _ := transferABIFn.EncodeCallDataJSON([]byte(
`{"recipient":"0x4a0d852ebb58fc88cb260bb270ae240f72edc45b","amount":"100000000000000000"}`,
))
fmt.Printf("ABI Call Bytes: %s\n", hex.EncodeToString(sampleABICallBytes))
values, _ := transferABIFn.DecodeCallData(sampleABICallBytes)
outputJSON, _ := NewSerializer().
SetFormattingMode(FormatAsObjects).
SetByteSerializer(HexByteSerializer0xPrefix).
SerializeJSON(values)
fmt.Printf("Back to JSON: %s\n", outputJSON)

assert.JSONEq(t, `{"recipient":"0x4a0d852ebb58fc88cb260bb270ae240f72edc45b","amount":"100000000000000000"}`, string(outputJSON))

}

func TestABIGetTupleTypeTree(t *testing.T) {

var abi ABI
Expand Down Expand Up @@ -745,3 +789,51 @@ func TestGetConstructor(t *testing.T) {
assert.Equal(t, Constructor, c.Type)
assert.Equal(t, 1, len(c.Inputs))
}

func TestEncodeABIDataJSONHelper(t *testing.T) {

a, _ := ParseABI([]byte(sampleABI4))
_, err := a[0].Inputs.EncodeABIDataJSON([]byte(`[]`))
assert.Regexp(t, "FF22037", err)

b, err := a[0].Inputs.EncodeABIDataJSON([]byte(`["test"]`))
assert.NoError(t, err)
assert.Equal(t, "000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000047465737400000000000000000000000000000000000000000000000000000000", hex.EncodeToString(b))

}

func TestEncodeABIDataValuesHelper(t *testing.T) {

a, _ := ParseABI([]byte(sampleABI4))
_, err := a[0].Inputs.EncodeABIDataValues([]string{})
assert.Regexp(t, "FF22037", err)

b, err := a[0].Inputs.EncodeABIDataValues([]string{"test"})
assert.NoError(t, err)
assert.Equal(t, "000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000047465737400000000000000000000000000000000000000000000000000000000", hex.EncodeToString(b))

}

func TestEncodeCallDataJSONHelper(t *testing.T) {

a, _ := ParseABI([]byte(sampleABI4))
_, err := a[0].EncodeCallDataJSON([]byte(`[]`))
assert.Regexp(t, "FF22037", err)

b, err := a[0].EncodeCallDataJSON([]byte(`["test"]`))
assert.NoError(t, err)
assert.Equal(t, "113bc475000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000047465737400000000000000000000000000000000000000000000000000000000", hex.EncodeToString(b))

}

func TestEncodeCallDataValuesHelper(t *testing.T) {

a, _ := ParseABI([]byte(sampleABI4))
_, err := a[0].EncodeCallDataValues([]string{})
assert.Regexp(t, "FF22037", err)

b, err := a[0].EncodeCallDataValues([]string{"test"})
assert.NoError(t, err)
assert.Equal(t, "113bc475000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000047465737400000000000000000000000000000000000000000000000000000000", hex.EncodeToString(b))

}
Loading

0 comments on commit cf018f0

Please sign in to comment.