diff --git a/cmd/signer/abihelper.go b/cmd/signer/abihelper.go
new file mode 100644
index 0000000000..7b8a0f525e
--- /dev/null
+++ b/cmd/signer/abihelper.go
@@ -0,0 +1,107 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of go-ethereum.
+//
+// go-ethereum is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// go-ethereum is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with go-ethereum. If not, see .
+
+package main
+
+import (
+ "fmt"
+ "github.com/ethereum/go-ethereum/accounts/abi"
+ "strings"
+ "bytes"
+ "github.com/ethereum/go-ethereum/common"
+)
+
+type decodedArgument struct {
+ soltype string
+ value interface{}
+}
+type decodedCallData struct {
+ signature string
+ name string
+ inputs []decodedArgument
+}
+
+func (arg decodedArgument) String() string {
+ return fmt.Sprintf("%v: %v", arg.soltype, arg.value)
+}
+func (cd decodedCallData) String() string {
+ args := make([]string, len(cd.inputs))
+ for i, arg := range cd.inputs {
+ args[i] = arg.String()
+ }
+ return fmt.Sprintf("%s(%s)", cd.name, strings.Join(args, ","))
+}
+
+// parseCallData matches the provided call data against the abi definition,
+// and returns a struct containing the actual go-typed values
+func parseCallData(calldata []byte, abidata string) (*decodedCallData, error) {
+
+ if len(calldata) < 4 {
+ return nil, fmt.Errorf("Invalid ABI-data, incomplete method signature of (%d bytes)", len(calldata))
+ }
+
+ abispec, err := abi.JSON(strings.NewReader(abidata))
+ if err != nil {
+ return nil, fmt.Errorf("Failed parsing JSON ABI: %v", err)
+ }
+
+ sigdata, argdata := calldata[:4], calldata[4:]
+ if len(argdata)%32 != 0 {
+ return nil, fmt.Errorf("Not ABI-encoded data; length should be a multiple of 32 (was %d)", len(argdata))
+ }
+
+ method := abispec.MethodById(sigdata)
+ if method == nil {
+ return nil, fmt.Errorf("Supplied ABI spec does not contain method signature in data: 0x%x", sigdata)
+ }
+
+ decoded := decodedCallData{signature: method.Sig(), name: method.Name}
+
+ for n, argument := range method.Inputs {
+ value, err := abi.ToGoType(n*32, argument.Type, argdata)
+
+ if err != nil {
+ return nil, fmt.Errorf("Failed to decode argument %d (signature %v): %v", n, method.Sig(), err)
+ } else {
+ decodedArg := decodedArgument{
+ soltype: argument.Type.String(),
+ value: value,
+ }
+ decoded.inputs = append(decoded.inputs, decodedArg)
+ }
+ }
+
+ // We're finished decoding the data. At this point, we encode the decoded data to see if it matches with the
+ // original data. If we didn't do that, it would e.g. be possible to stuff extra data into the arguments, which
+ // is not detected by merely decoding the data.
+
+ var (
+ gotypedArguments = make([]interface{}, len(decoded.inputs))
+ encoded []byte
+ )
+ for i, arg := range decoded.inputs {
+ gotypedArguments[i] = arg.value
+ }
+ encoded, err = abispec.Pack(method.Name, gotypedArguments...)
+
+ if !bytes.Equal(encoded, calldata){
+ exp := common.Bytes2Hex(encoded)
+ was := common.Bytes2Hex(calldata)
+ return nil, fmt.Errorf("WARNING: Supplied data is stuffed with extra data. %v \nWant %s\nHave %s", decoded,was, exp)
+ }
+
+ return &decoded, nil
+}
diff --git a/cmd/signer/abihelper_test.go b/cmd/signer/abihelper_test.go
new file mode 100644
index 0000000000..daad0f17a7
--- /dev/null
+++ b/cmd/signer/abihelper_test.go
@@ -0,0 +1,79 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of go-ethereum.
+//
+// go-ethereum is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// go-ethereum is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with go-ethereum. If not, see .
+
+package main
+
+import (
+ "github.com/ethereum/go-ethereum/common"
+ "testing"
+)
+
+func TestMartin(t *testing.T) {
+
+ // send(uint256) : a52c101e
+ // compareAndApprove(address,uint256,uint256) : 751e1079
+ // issue(address[],uint256) : 42958b54
+ jsondata := `
+[
+ {"type":"function","name":"send","inputs":[{"name":"a","type":"uint256"}]},
+ {"type":"function","name":"compareAndApprove","inputs":[{"name":"a","type":"address"},{"name":"a","type":"uint256"},{"name":"a","type":"uint256"}]},
+ {"type":"function","name":"issue","inputs":[{"name":"a","type":"address[]"},{"name":"a","type":"uint256"}]},
+ {"type":"function","name":"sam","inputs":[{"name":"a","type":"bytes"},{"name":"a","type":"bool"},{"name":"a","type":"uint256[]"}]}
+]`
+ //Expected failures
+ for _, hexdata := range []string{
+ "a52c101e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000042",
+ "a52c101e000000000000000000000000000000000000000000000000000000000000001200",
+ "a52c101e00000000000000000000000000000000000000000000000000000000000000",
+ "a52c101e",
+ "a52c10",
+ "",
+ "751e10790000000000000000000000000000000000000000000000000000000000000012",
+ "751e1079FFffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "deadbeef00000000000000000000000000000000000000000000000000000000000000",
+ "42958b5400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000042",
+ "a52c101e00ff0000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000042",
+ } {
+ _, err := parseCallData(common.Hex2Bytes(hexdata), jsondata)
+ if err == nil {
+ t.Errorf("Expected decoding to fail: %s", hexdata)
+ }
+ }
+
+ //Expected success
+ for _, hexdata := range []string{
+ // From https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
+ "a5643bf20000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000464617665000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003",
+ "a52c101e0000000000000000000000000000000000000000000000000000000000000012",
+ "a52c101eFFffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "751e1079000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "42958b54" +
+ // start of dynamic type
+ "0000000000000000000000000000000000000000000000000000000000000040" +
+ //uint256
+ "0000000000000000000000000000000000000000000000000000000000000001" +
+ // length of array
+ "0000000000000000000000000000000000000000000000000000000000000002" +
+ // array values
+ "000000000000000000000000000000000000000000000000000000000000dead" +
+ "000000000000000000000000000000000000000000000000000000000000beef",
+ } {
+ _, err := parseCallData(common.Hex2Bytes(hexdata), jsondata)
+ if err != nil {
+ t.Errorf("Unexpected failure on input %s:\n %v (%d bytes) ", hexdata, err, len(common.Hex2Bytes(hexdata)))
+ }
+ }
+}