Commit 29a29ac1 authored by Mark Tyneway's avatar Mark Tyneway

op-chain-ops: cleanup

parent fdd2761f
...@@ -170,6 +170,8 @@ type BatchTransaction struct { ...@@ -170,6 +170,8 @@ type BatchTransaction struct {
// An error is defined by: // An error is defined by:
// - incorrectly encoded calldata // - incorrectly encoded calldata
// - mismatch in number of arguments // - mismatch in number of arguments
// It does not currently work on structs, will return no error if a "tuple"
// is used as an argument. Need to find a generic way to work with structs.
func (bt *BatchTransaction) Check() error { func (bt *BatchTransaction) Check() error {
if len(bt.Method.Inputs) != len(bt.InputValues) { if len(bt.Method.Inputs) != len(bt.InputValues) {
return fmt.Errorf("expected %d inputs but got %d", len(bt.Method.Inputs), len(bt.InputValues)) return fmt.Errorf("expected %d inputs but got %d", len(bt.Method.Inputs), len(bt.InputValues))
...@@ -184,6 +186,32 @@ func (bt *BatchTransaction) Check() error { ...@@ -184,6 +186,32 @@ func (bt *BatchTransaction) Check() error {
if !bytes.Equal(bt.Data[0:4], selector) { if !bytes.Equal(bt.Data[0:4], selector) {
return fmt.Errorf("data does not match signature") return fmt.Errorf("data does not match signature")
} }
// Check the calldata
values := make([]any, len(bt.Method.Inputs))
for i, input := range bt.Method.Inputs {
value, ok := bt.InputValues[input.Name]
if !ok {
return fmt.Errorf("missing input %s", input.Name)
}
// Need to figure out better way to handle tuples in a generic way
if input.Type == "tuple" {
return nil
}
arg, err := unstringifyArg(value, input.Type)
if err != nil {
return err
}
values[i] = arg
}
calldata, err := bt.Arguments().PackValues(values)
if err != nil {
return err
}
if !bytes.Equal(bt.Data[4:], calldata) {
return fmt.Errorf("calldata does not match inputs, expected %s, got %s", hexutil.Encode(bt.Data[4:]), hexutil.Encode(calldata))
}
} }
return nil return nil
} }
...@@ -197,6 +225,22 @@ func (bt *BatchTransaction) Signature() string { ...@@ -197,6 +225,22 @@ func (bt *BatchTransaction) Signature() string {
return fmt.Sprintf("%s(%s)", bt.Method.Name, strings.Join(types, ",")) return fmt.Sprintf("%s(%s)", bt.Method.Name, strings.Join(types, ","))
} }
func (bt *BatchTransaction) Arguments() abi.Arguments {
arguments := make(abi.Arguments, len(bt.Method.Inputs))
for i, input := range bt.Method.Inputs {
serialized, err := json.Marshal(input)
if err != nil {
panic(err)
}
var arg abi.Argument
if err := json.Unmarshal(serialized, &arg); err != nil {
panic(err)
}
arguments[i] = arg
}
return arguments
}
// UnmarshalJSON will unmarshal a BatchTransaction from JSON. // UnmarshalJSON will unmarshal a BatchTransaction from JSON.
func (b *BatchTransaction) UnmarshalJSON(data []byte) error { func (b *BatchTransaction) UnmarshalJSON(data []byte) error {
var bt batchTransactionMarshaling var bt batchTransactionMarshaling
......
...@@ -71,7 +71,7 @@ func TestBatchAddCallFinalizeWithdrawalTransaction(t *testing.T) { ...@@ -71,7 +71,7 @@ func TestBatchAddCallFinalizeWithdrawalTransaction(t *testing.T) {
} }
// TestBatchAddCallDespostTransaction ensures that simple calls can be serialized correctly. // TestBatchAddCallDespostTransaction ensures that simple calls can be serialized correctly.
func TestBatchAddCallDespostTransaction(t *testing.T) { func TestBatchAddCallDespositTransaction(t *testing.T) {
file, err := os.ReadFile("testdata/portal-abi.json") file, err := os.ReadFile("testdata/portal-abi.json")
require.NoError(t, err) require.NoError(t, err)
portalABI, err := abi.JSON(bytes.NewReader(file)) portalABI, err := abi.JSON(bytes.NewReader(file))
......
...@@ -88,18 +88,50 @@ func stringifyArg(argument any) (string, error) { ...@@ -88,18 +88,50 @@ func stringifyArg(argument any) (string, error) {
} }
} }
// countArgs will recursively count the number of arguments in an abi.Argument. // unstringifyArg converts a string to a Go type.
func countArgs(total *int, input abi.Argument) error { func unstringifyArg(arg string, typ string) (any, error) {
for i, elem := range input.Type.TupleElems { switch typ {
e := *elem case "address":
*total++ return common.HexToAddress(arg), nil
arg := abi.Argument{ case "bool":
Name: input.Type.TupleRawNames[i], return strconv.ParseBool(arg)
Type: e, case "uint8":
} val, err := strconv.ParseUint(arg, 10, 8)
return countArgs(total, arg) return uint8(val), err
case "uint16":
val, err := strconv.ParseUint(arg, 10, 16)
return uint16(val), err
case "uint32":
val, err := strconv.ParseUint(arg, 10, 32)
return uint32(val), err
case "uint64":
val, err := strconv.ParseUint(arg, 10, 64)
return val, err
case "int8":
val, err := strconv.ParseInt(arg, 10, 8)
return val, err
case "int16":
val, err := strconv.ParseInt(arg, 10, 16)
return val, err
case "int32":
val, err := strconv.ParseInt(arg, 10, 32)
return val, err
case "int64":
val, err := strconv.ParseInt(arg, 10, 64)
return val, err
case "uint256", "int256":
val, ok := new(big.Int).SetString(arg, 10)
if !ok {
return nil, fmt.Errorf("failed to parse %s as big.Int", arg)
}
return val, nil
case "string":
return arg, nil
case "bytes":
return hexutil.Decode(arg)
default:
return nil, fmt.Errorf("unknown type: %s", typ)
} }
return nil
} }
// createContractInput converts an abi.Argument to one or more ContractInputs. // createContractInput converts an abi.Argument to one or more ContractInputs.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment