diff --git a/accounts/abi/abi.go b/accounts/abi/abi.go
index abcb403db27bc61ae6aab2a0d9dc3b1f4fd5009d..254b1f7fb4fdcbf790f2216c87e4165ad44c1ef3 100644
--- a/accounts/abi/abi.go
+++ b/accounts/abi/abi.go
@@ -136,11 +136,11 @@ func (abi *ABI) UnmarshalJSON(data []byte) error {
 
 // MethodById looks up a method by the 4-byte id
 // returns nil if none found
-func (abi *ABI) MethodById(sigdata []byte) *Method {
+func (abi *ABI) MethodById(sigdata []byte) (*Method, error) {
 	for _, method := range abi.Methods {
 		if bytes.Equal(method.Id(), sigdata[:4]) {
-			return &method
+			return &method, nil
 		}
 	}
-	return nil
+	return nil, fmt.Errorf("no method with id: %#x", sigdata[:4])
 }
diff --git a/accounts/abi/abi_test.go b/accounts/abi/abi_test.go
index 2d43b631c2adf37ca9961700b2566c415f2303e0..35e0094ddda171b88006e555093cb16eec943c5e 100644
--- a/accounts/abi/abi_test.go
+++ b/accounts/abi/abi_test.go
@@ -689,7 +689,11 @@ func TestABI_MethodById(t *testing.T) {
 	}
 	for name, m := range abi.Methods {
 		a := fmt.Sprintf("%v", m)
-		b := fmt.Sprintf("%v", abi.MethodById(m.Id()))
+		m2, err := abi.MethodById(m.Id())
+		if err != nil {
+			t.Fatalf("Failed to look up ABI method: %v", err)
+		}
+		b := fmt.Sprintf("%v", m2)
 		if a != b {
 			t.Errorf("Method %v (id %v) not 'findable' by id in ABI", name, common.ToHex(m.Id()))
 		}
diff --git a/accounts/abi/argument.go b/accounts/abi/argument.go
index 04ca6150ad39fc797ec3f482fea35380a7ec142a..f171f4cc6375de400c217c2264f8f2cdc5f27383 100644
--- a/accounts/abi/argument.go
+++ b/accounts/abi/argument.go
@@ -67,6 +67,17 @@ func (arguments Arguments) LengthNonIndexed() int {
 	return out
 }
 
+// NonIndexed returns the arguments with indexed arguments filtered out
+func (arguments Arguments) NonIndexed() Arguments {
+	var ret []Argument
+	for _, arg := range arguments {
+		if !arg.Indexed {
+			ret = append(ret, arg)
+		}
+	}
+	return ret
+}
+
 // isTuple returns true for non-atomic constructs, like (uint,uint) or uint[]
 func (arguments Arguments) isTuple() bool {
 	return len(arguments) > 1
@@ -74,21 +85,25 @@ func (arguments Arguments) isTuple() bool {
 
 // Unpack performs the operation hexdata -> Go format
 func (arguments Arguments) Unpack(v interface{}, data []byte) error {
-	if arguments.isTuple() {
-		return arguments.unpackTuple(v, data)
-	}
-	return arguments.unpackAtomic(v, data)
-}
 
-func (arguments Arguments) unpackTuple(v interface{}, output []byte) error {
 	// make sure the passed value is arguments pointer
-	valueOf := reflect.ValueOf(v)
-	if reflect.Ptr != valueOf.Kind() {
+	if reflect.Ptr != reflect.ValueOf(v).Kind() {
 		return fmt.Errorf("abi: Unpack(non-pointer %T)", v)
 	}
+	marshalledValues, err := arguments.UnpackValues(data)
+	if err != nil {
+		return err
+	}
+	if arguments.isTuple() {
+		return arguments.unpackTuple(v, marshalledValues)
+	}
+	return arguments.unpackAtomic(v, marshalledValues)
+}
+
+func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interface{}) error {
 
 	var (
-		value = valueOf.Elem()
+		value = reflect.ValueOf(v).Elem()
 		typ   = value.Type()
 		kind  = value.Kind()
 	)
@@ -110,30 +125,9 @@ func (arguments Arguments) unpackTuple(v interface{}, output []byte) error {
 			exists[field] = true
 		}
 	}
-	// `i` counts the nonindexed arguments.
-	// `j` counts the number of complex types.
-	// both `i` and `j` are used to to correctly compute `data` offset.
+	for i, arg := range arguments.NonIndexed() {
 
-	i, j := -1, 0
-	for _, arg := range arguments {
-
-		if arg.Indexed {
-			// can't read, continue
-			continue
-		}
-		i++
-		marshalledValue, err := toGoType((i+j)*32, arg.Type, output)
-		if err != nil {
-			return err
-		}
-
-		if arg.Type.T == ArrayTy {
-			// combined index ('i' + 'j') need to be adjusted only by size of array, thus
-			// we need to decrement 'j' because 'i' was incremented
-			j += arg.Type.Size - 1
-		}
-
-		reflectValue := reflect.ValueOf(marshalledValue)
+		reflectValue := reflect.ValueOf(marshalledValues[i])
 
 		switch kind {
 		case reflect.Struct:
@@ -166,34 +160,52 @@ func (arguments Arguments) unpackTuple(v interface{}, output []byte) error {
 }
 
 // unpackAtomic unpacks ( hexdata -> go ) a single value
-func (arguments Arguments) unpackAtomic(v interface{}, output []byte) error {
-	// make sure the passed value is arguments pointer
-	valueOf := reflect.ValueOf(v)
-	if reflect.Ptr != valueOf.Kind() {
-		return fmt.Errorf("abi: Unpack(non-pointer %T)", v)
-	}
-	arg := arguments[0]
-	if arg.Indexed {
-		return fmt.Errorf("abi: attempting to unpack indexed variable into element.")
+func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues []interface{}) error {
+	if len(marshalledValues) != 1 {
+		return fmt.Errorf("abi: wrong length, expected single value, got %d", len(marshalledValues))
 	}
+	elem := reflect.ValueOf(v).Elem()
+	reflectValue := reflect.ValueOf(marshalledValues[0])
+	return set(elem, reflectValue, arguments.NonIndexed()[0])
+}
 
-	value := valueOf.Elem()
+// UnpackValues can be used to unpack ABI-encoded hexdata according to the ABI-specification,
+// without supplying a struct to unpack into. Instead, this method returns a list containing the
+// values. An atomic argument will be a list with one element.
+func (arguments Arguments) UnpackValues(data []byte) ([]interface{}, error) {
+	retval := make([]interface{}, 0, arguments.LengthNonIndexed())
+	virtualArgs := 0
+	for index, arg := range arguments.NonIndexed() {
+		marshalledValue, err := toGoType((index+virtualArgs)*32, arg.Type, data)
+		if arg.Type.T == ArrayTy {
+			// If we have a static array, like [3]uint256, these are coded as
+			// just like uint256,uint256,uint256.
+			// This means that we need to add two 'virtual' arguments when
+			// we count the index from now on
 
-	marshalledValue, err := toGoType(0, arg.Type, output)
-	if err != nil {
-		return err
+			virtualArgs += arg.Type.Size - 1
+		}
+		if err != nil {
+			return nil, err
+		}
+		retval = append(retval, marshalledValue)
 	}
-	return set(value, reflect.ValueOf(marshalledValue), arg)
+	return retval, nil
 }
 
-// Unpack performs the operation Go format -> Hexdata
+// PackValues performs the operation Go format -> Hexdata
+// It is the semantic opposite of UnpackValues
+func (arguments Arguments) PackValues(args []interface{}) ([]byte, error) {
+	return arguments.Pack(args...)
+}
+
+// Pack performs the operation Go format -> Hexdata
 func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) {
 	// Make sure arguments match up and pack them
 	abiArgs := arguments
 	if len(args) != len(abiArgs) {
 		return nil, fmt.Errorf("argument count mismatch: %d for %d", len(args), len(abiArgs))
 	}
-
 	// variable input is the output appended at the end of packed
 	// output. This is used for strings and bytes types input.
 	var variableInput []byte
@@ -207,7 +219,6 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) {
 			inputOffset += 32
 		}
 	}
-
 	var ret []byte
 	for i, a := range args {
 		input := abiArgs[i]
@@ -216,7 +227,6 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) {
 		if err != nil {
 			return nil, err
 		}
-
 		// check for a slice type (string, bytes, slice)
 		if input.Type.requiresLengthPrefix() {
 			// calculate the offset
diff --git a/accounts/abi/unpack.go b/accounts/abi/unpack.go
index 33424566185985a87f27748fc33acd821a576073..761c80edfda5e543d60406f9630c849876d4529e 100644
--- a/accounts/abi/unpack.go
+++ b/accounts/abi/unpack.go
@@ -95,6 +95,9 @@ func readFixedBytes(t Type, word []byte) (interface{}, error) {
 
 // iteratively unpack elements
 func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) {
+	if size < 0 {
+		return nil, fmt.Errorf("cannot marshal input to array, size is negative (%d)", size)
+	}
 	if start+32*size > len(output) {
 		return nil, fmt.Errorf("abi: cannot marshal in to go array: offset %d would go over slice boundary (len=%d)", len(output), start+32*size)
 	}
@@ -181,16 +184,32 @@ func toGoType(index int, t Type, output []byte) (interface{}, error) {
 
 // interprets a 32 byte slice as an offset and then determines which indice to look to decode the type.
 func lengthPrefixPointsTo(index int, output []byte) (start int, length int, err error) {
-	offset := int(binary.BigEndian.Uint64(output[index+24 : index+32]))
-	if offset+32 > len(output) {
-		return 0, 0, fmt.Errorf("abi: cannot marshal in to go slice: offset %d would go over slice boundary (len=%d)", len(output), offset+32)
+	bigOffsetEnd := big.NewInt(0).SetBytes(output[index : index+32])
+	bigOffsetEnd.Add(bigOffsetEnd, common.Big32)
+	outputLength := big.NewInt(int64(len(output)))
+
+	if bigOffsetEnd.Cmp(outputLength) > 0 {
+		return 0, 0, fmt.Errorf("abi: cannot marshal in to go slice: offset %v would go over slice boundary (len=%v)", bigOffsetEnd, outputLength)
 	}
-	length = int(binary.BigEndian.Uint64(output[offset+24 : offset+32]))
-	if offset+32+length > len(output) {
-		return 0, 0, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), offset+32+length)
+
+	if bigOffsetEnd.BitLen() > 63 {
+		return 0, 0, fmt.Errorf("abi offset larger than int64: %v", bigOffsetEnd)
 	}
-	start = offset + 32
 
-	//fmt.Printf("LENGTH PREFIX INFO: \nsize: %v\noffset: %v\nstart: %v\n", length, offset, start)
+	offsetEnd := int(bigOffsetEnd.Uint64())
+	lengthBig := big.NewInt(0).SetBytes(output[offsetEnd-32 : offsetEnd])
+
+	totalSize := big.NewInt(0)
+	totalSize.Add(totalSize, bigOffsetEnd)
+	totalSize.Add(totalSize, lengthBig)
+	if totalSize.BitLen() > 63 {
+		return 0, 0, fmt.Errorf("abi length larger than int64: %v", totalSize)
+	}
+
+	if totalSize.Cmp(outputLength) > 0 {
+		return 0, 0, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %v require %v", outputLength, totalSize)
+	}
+	start = int(bigOffsetEnd.Uint64())
+	length = int(lengthBig.Uint64())
 	return
 }
diff --git a/accounts/abi/unpack_test.go b/accounts/abi/unpack_test.go
index a65426a30b2e3d9420bc8f36ba1873dfcfb7824d..742211244b441e00ed32a12192928f710b7f21f3 100644
--- a/accounts/abi/unpack_test.go
+++ b/accounts/abi/unpack_test.go
@@ -130,7 +130,7 @@ var unpackTests = []unpackTest{
 	{
 		def:  `[{"type": "bytes32"}]`,
 		enc:  "0100000000000000000000000000000000000000000000000000000000000000",
-		want: common.HexToHash("0100000000000000000000000000000000000000000000000000000000000000"),
+		want: [32]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
 	},
 	{
 		def:  `[{"type": "function"}]`,
@@ -683,3 +683,73 @@ func TestUnmarshal(t *testing.T) {
 		t.Fatal("expected error:", err)
 	}
 }
+
+func TestOOMMaliciousInput(t *testing.T) {
+	oomTests := []unpackTest{
+		{
+			def: `[{"type": "uint8[]"}]`,
+			enc: "0000000000000000000000000000000000000000000000000000000000000020" + // offset
+				"0000000000000000000000000000000000000000000000000000000000000003" + // num elems
+				"0000000000000000000000000000000000000000000000000000000000000001" + // elem 1
+				"0000000000000000000000000000000000000000000000000000000000000002", // elem 2
+		},
+		{ // Length larger than 64 bits
+			def: `[{"type": "uint8[]"}]`,
+			enc: "0000000000000000000000000000000000000000000000000000000000000020" + // offset
+				"00ffffffffffffffffffffffffffffffffffffffffffffff0000000000000002" + // num elems
+				"0000000000000000000000000000000000000000000000000000000000000001" + // elem 1
+				"0000000000000000000000000000000000000000000000000000000000000002", // elem 2
+		},
+		{ // Offset very large (over 64 bits)
+			def: `[{"type": "uint8[]"}]`,
+			enc: "00ffffffffffffffffffffffffffffffffffffffffffffff0000000000000020" + // offset
+				"0000000000000000000000000000000000000000000000000000000000000002" + // num elems
+				"0000000000000000000000000000000000000000000000000000000000000001" + // elem 1
+				"0000000000000000000000000000000000000000000000000000000000000002", // elem 2
+		},
+		{ // Offset very large (below 64 bits)
+			def: `[{"type": "uint8[]"}]`,
+			enc: "0000000000000000000000000000000000000000000000007ffffffffff00020" + // offset
+				"0000000000000000000000000000000000000000000000000000000000000002" + // num elems
+				"0000000000000000000000000000000000000000000000000000000000000001" + // elem 1
+				"0000000000000000000000000000000000000000000000000000000000000002", // elem 2
+		},
+		{ // Offset negative (as 64 bit)
+			def: `[{"type": "uint8[]"}]`,
+			enc: "000000000000000000000000000000000000000000000000f000000000000020" + // offset
+				"0000000000000000000000000000000000000000000000000000000000000002" + // num elems
+				"0000000000000000000000000000000000000000000000000000000000000001" + // elem 1
+				"0000000000000000000000000000000000000000000000000000000000000002", // elem 2
+		},
+
+		{ // Negative length
+			def: `[{"type": "uint8[]"}]`,
+			enc: "0000000000000000000000000000000000000000000000000000000000000020" + // offset
+				"000000000000000000000000000000000000000000000000f000000000000002" + // num elems
+				"0000000000000000000000000000000000000000000000000000000000000001" + // elem 1
+				"0000000000000000000000000000000000000000000000000000000000000002", // elem 2
+		},
+		{ // Very large length
+			def: `[{"type": "uint8[]"}]`,
+			enc: "0000000000000000000000000000000000000000000000000000000000000020" + // offset
+				"0000000000000000000000000000000000000000000000007fffffffff000002" + // num elems
+				"0000000000000000000000000000000000000000000000000000000000000001" + // elem 1
+				"0000000000000000000000000000000000000000000000000000000000000002", // elem 2
+		},
+	}
+	for i, test := range oomTests {
+		def := fmt.Sprintf(`[{ "name" : "method", "outputs": %s}]`, test.def)
+		abi, err := JSON(strings.NewReader(def))
+		if err != nil {
+			t.Fatalf("invalid ABI definition %s: %v", def, err)
+		}
+		encb, err := hex.DecodeString(test.enc)
+		if err != nil {
+			t.Fatalf("invalid hex: %s" + test.enc)
+		}
+		_, err = abi.Methods["method"].Outputs.UnpackValues(encb)
+		if err == nil {
+			t.Fatalf("Expected error on malicious input, test %d", i)
+		}
+	}
+}