// Copyright 2020 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

package abi

import (
	"math/big"

	"github.com/simcord-llc/bitbon-system-blockchain/common"
)

type packUnpackTest struct {
	def      string
	unpacked interface{}
	packed   string
}

var packUnpackTests = []packUnpackTest{
	// Booleans
	{
		def:      `[{ "type": "bool" }]`,
		packed:   "0000000000000000000000000000000000000000000000000000000000000001",
		unpacked: true,
	},
	{
		def:      `[{ "type": "bool" }]`,
		packed:   "0000000000000000000000000000000000000000000000000000000000000000",
		unpacked: false,
	},
	// Integers
	{
		def:      `[{ "type": "uint8" }]`,
		unpacked: uint8(2),
		packed:   "0000000000000000000000000000000000000000000000000000000000000002",
	},
	{
		def:      `[{ "type": "uint8[]" }]`,
		unpacked: []uint8{1, 2},
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
	},
	{
		def:      `[{ "type": "uint16" }]`,
		unpacked: uint16(2),
		packed:   "0000000000000000000000000000000000000000000000000000000000000002",
	},
	{
		def:      `[{ "type": "uint16[]" }]`,
		unpacked: []uint16{1, 2},
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
	},
	{
		def:      `[{"type": "uint17"}]`,
		packed:   "0000000000000000000000000000000000000000000000000000000000000001",
		unpacked: big.NewInt(1),
	},
	{
		def:      `[{"type": "uint32"}]`,
		packed:   "0000000000000000000000000000000000000000000000000000000000000001",
		unpacked: uint32(1),
	},
	{
		def:      `[{"type": "uint32[]"}]`,
		unpacked: []uint32{1, 2},
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
	},
	{
		def:      `[{"type": "uint64"}]`,
		unpacked: uint64(2),
		packed:   "0000000000000000000000000000000000000000000000000000000000000002",
	},
	{
		def:      `[{"type": "uint64[]"}]`,
		unpacked: []uint64{1, 2},
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
	},
	{
		def:      `[{"type": "uint256"}]`,
		unpacked: big.NewInt(2),
		packed:   "0000000000000000000000000000000000000000000000000000000000000002",
	},
	{
		def:      `[{"type": "uint256[]"}]`,
		unpacked: []*big.Int{big.NewInt(1), big.NewInt(2)},
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
	},
	{
		def:      `[{"type": "int8"}]`,
		unpacked: int8(2),
		packed:   "0000000000000000000000000000000000000000000000000000000000000002",
	},
	{
		def:      `[{"type": "int8[]"}]`,
		unpacked: []int8{1, 2},
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
	},
	{
		def:      `[{"type": "int16"}]`,
		unpacked: int16(2),
		packed:   "0000000000000000000000000000000000000000000000000000000000000002",
	},
	{
		def:      `[{"type": "int16[]"}]`,
		unpacked: []int16{1, 2},
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
	},
	{
		def:      `[{"type": "int17"}]`,
		packed:   "0000000000000000000000000000000000000000000000000000000000000001",
		unpacked: big.NewInt(1),
	},
	{
		def:      `[{"type": "int32"}]`,
		unpacked: int32(2),
		packed:   "0000000000000000000000000000000000000000000000000000000000000002",
	},
	{
		def:      `[{"type": "int32"}]`,
		packed:   "0000000000000000000000000000000000000000000000000000000000000001",
		unpacked: int32(1),
	},
	{
		def:      `[{"type": "int32[]"}]`,
		unpacked: []int32{1, 2},
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
	},
	{
		def:      `[{"type": "int64"}]`,
		unpacked: int64(2),
		packed:   "0000000000000000000000000000000000000000000000000000000000000002",
	},
	{
		def:      `[{"type": "int64[]"}]`,
		unpacked: []int64{1, 2},
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
	},
	{
		def:      `[{"type": "int256"}]`,
		unpacked: big.NewInt(2),
		packed:   "0000000000000000000000000000000000000000000000000000000000000002",
	},
	{
		def:      `[{"type": "int256"}]`,
		packed:   "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
		unpacked: big.NewInt(-1),
	},
	{
		def:      `[{"type": "int256[]"}]`,
		unpacked: []*big.Int{big.NewInt(1), big.NewInt(2)},
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
	},
	// Address
	{
		def:      `[{"type": "address"}]`,
		packed:   "0000000000000000000000000100000000000000000000000000000000000000",
		unpacked: common.Address{1},
	},
	{
		def:      `[{"type": "address[]"}]`,
		unpacked: []common.Address{{1}, {2}},
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000100000000000000000000000000000000000000" +
			"0000000000000000000000000200000000000000000000000000000000000000",
	},
	// Bytes
	{
		def:      `[{"type": "bytes1"}]`,
		unpacked: [1]byte{1},
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "bytes2"}]`,
		unpacked: [2]byte{1},
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "bytes3"}]`,
		unpacked: [3]byte{1},
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "bytes4"}]`,
		unpacked: [4]byte{1},
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "bytes5"}]`,
		unpacked: [5]byte{1},
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "bytes6"}]`,
		unpacked: [6]byte{1},
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "bytes7"}]`,
		unpacked: [7]byte{1},
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "bytes8"}]`,
		unpacked: [8]byte{1},
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "bytes9"}]`,
		unpacked: [9]byte{1},
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "bytes10"}]`,
		unpacked: [10]byte{1},
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "bytes11"}]`,
		unpacked: [11]byte{1},
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "bytes12"}]`,
		unpacked: [12]byte{1},
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "bytes13"}]`,
		unpacked: [13]byte{1},
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "bytes14"}]`,
		unpacked: [14]byte{1},
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "bytes15"}]`,
		unpacked: [15]byte{1},
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "bytes16"}]`,
		unpacked: [16]byte{1},
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "bytes17"}]`,
		unpacked: [17]byte{1},
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "bytes18"}]`,
		unpacked: [18]byte{1},
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "bytes19"}]`,
		unpacked: [19]byte{1},
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "bytes20"}]`,
		unpacked: [20]byte{1},
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "bytes21"}]`,
		unpacked: [21]byte{1},
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "bytes22"}]`,
		unpacked: [22]byte{1},
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "bytes23"}]`,
		unpacked: [23]byte{1},
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "bytes24"}]`,
		unpacked: [24]byte{1},
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "bytes25"}]`,
		unpacked: [25]byte{1},
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "bytes26"}]`,
		unpacked: [26]byte{1},
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "bytes27"}]`,
		unpacked: [27]byte{1},
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "bytes28"}]`,
		unpacked: [28]byte{1},
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "bytes29"}]`,
		unpacked: [29]byte{1},
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "bytes30"}]`,
		unpacked: [30]byte{1},
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "bytes31"}]`,
		unpacked: [31]byte{1},
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "bytes32"}]`,
		unpacked: [32]byte{1},
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "bytes32"}]`,
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
		unpacked: [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": "bytes"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000020" +
			"0100000000000000000000000000000000000000000000000000000000000000",
		unpacked: common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
	},
	{
		def:      `[{"type": "bytes32"}]`,
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
		unpacked: [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},
	},
	// Functions
	{
		def:      `[{"type": "function"}]`,
		packed:   "0100000000000000000000000000000000000000000000000000000000000000",
		unpacked: [24]byte{1},
	},
	// Slice and Array
	{
		def: `[{"type": "uint8[]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
		unpacked: []uint8{1, 2},
	},
	{
		def: `[{"type": "uint8[]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000000",
		unpacked: []uint8{},
	},
	{
		def: `[{"type": "uint256[]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000000",
		unpacked: []*big.Int{},
	},
	{
		def: `[{"type": "uint8[2]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
		unpacked: [2]uint8{1, 2},
	},
	{
		def: `[{"type": "int8[2]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
		unpacked: [2]int8{1, 2},
	},
	{
		def: `[{"type": "int16[]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
		unpacked: []int16{1, 2},
	},
	{
		def: `[{"type": "int16[2]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
		unpacked: [2]int16{1, 2},
	},
	{
		def: `[{"type": "int32[]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
		unpacked: []int32{1, 2},
	},
	{
		def: `[{"type": "int32[2]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
		unpacked: [2]int32{1, 2},
	},
	{
		def: `[{"type": "int64[]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
		unpacked: []int64{1, 2},
	},
	{
		def: `[{"type": "int64[2]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
		unpacked: [2]int64{1, 2},
	},
	{
		def: `[{"type": "int256[]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
		unpacked: []*big.Int{big.NewInt(1), big.NewInt(2)},
	},
	{
		def: `[{"type": "int256[3]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000003",
		unpacked: [3]*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3)},
	},
	// multi dimensional, if these pass, all types that don't require length prefix should pass
	{
		def: `[{"type": "uint8[][]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000000",
		unpacked: [][]uint8{},
	},
	{
		def: `[{"type": "uint8[][]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000040" +
			"00000000000000000000000000000000000000000000000000000000000000a0" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
		unpacked: [][]uint8{{1, 2}, {1, 2}},
	},
	{
		def: `[{"type": "uint8[][]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000040" +
			"00000000000000000000000000000000000000000000000000000000000000a0" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000003" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000003",
		unpacked: [][]uint8{{1, 2}, {1, 2, 3}},
	},
	{
		def: `[{"type": "uint8[2][2]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
		unpacked: [2][2]uint8{{1, 2}, {1, 2}},
	},
	{
		def: `[{"type": "uint8[][2]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000040" +
			"0000000000000000000000000000000000000000000000000000000000000060" +
			"0000000000000000000000000000000000000000000000000000000000000000" +
			"0000000000000000000000000000000000000000000000000000000000000000",
		unpacked: [2][]uint8{{}, {}},
	},
	{
		def: `[{"type": "uint8[][2]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000040" +
			"0000000000000000000000000000000000000000000000000000000000000080" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000001",
		unpacked: [2][]uint8{{1}, {1}},
	},
	{
		def: `[{"type": "uint8[2][]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000000",
		unpacked: [][2]uint8{},
	},
	{
		def: `[{"type": "uint8[2][]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
		unpacked: [][2]uint8{{1, 2}},
	},
	{
		def: `[{"type": "uint8[2][]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
		unpacked: [][2]uint8{{1, 2}, {1, 2}},
	},
	{
		def: `[{"type": "uint16[]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
		unpacked: []uint16{1, 2},
	},
	{
		def: `[{"type": "uint16[2]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
		unpacked: [2]uint16{1, 2},
	},
	{
		def: `[{"type": "uint32[]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
		unpacked: []uint32{1, 2},
	},
	{
		def:      `[{"type": "uint32[2][3][4]"}]`,
		unpacked: [4][3][2]uint32{{{1, 2}, {3, 4}, {5, 6}}, {{7, 8}, {9, 10}, {11, 12}}, {{13, 14}, {15, 16}, {17, 18}}, {{19, 20}, {21, 22}, {23, 24}}},
		packed: "0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000003" +
			"0000000000000000000000000000000000000000000000000000000000000004" +
			"0000000000000000000000000000000000000000000000000000000000000005" +
			"0000000000000000000000000000000000000000000000000000000000000006" +
			"0000000000000000000000000000000000000000000000000000000000000007" +
			"0000000000000000000000000000000000000000000000000000000000000008" +
			"0000000000000000000000000000000000000000000000000000000000000009" +
			"000000000000000000000000000000000000000000000000000000000000000a" +
			"000000000000000000000000000000000000000000000000000000000000000b" +
			"000000000000000000000000000000000000000000000000000000000000000c" +
			"000000000000000000000000000000000000000000000000000000000000000d" +
			"000000000000000000000000000000000000000000000000000000000000000e" +
			"000000000000000000000000000000000000000000000000000000000000000f" +
			"0000000000000000000000000000000000000000000000000000000000000010" +
			"0000000000000000000000000000000000000000000000000000000000000011" +
			"0000000000000000000000000000000000000000000000000000000000000012" +
			"0000000000000000000000000000000000000000000000000000000000000013" +
			"0000000000000000000000000000000000000000000000000000000000000014" +
			"0000000000000000000000000000000000000000000000000000000000000015" +
			"0000000000000000000000000000000000000000000000000000000000000016" +
			"0000000000000000000000000000000000000000000000000000000000000017" +
			"0000000000000000000000000000000000000000000000000000000000000018",
	},

	{
		def:      `[{"type": "bytes32[]"}]`,
		unpacked: []common.Hash{{1}, {2}},
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0100000000000000000000000000000000000000000000000000000000000000" +
			"0200000000000000000000000000000000000000000000000000000000000000",
	},
	{
		def: `[{"type": "uint32[2]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
		unpacked: [2]uint32{1, 2},
	},
	{
		def: `[{"type": "uint64[]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
		unpacked: []uint64{1, 2},
	},
	{
		def: `[{"type": "uint64[2]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
		unpacked: [2]uint64{1, 2},
	},
	{
		def: `[{"type": "uint256[]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
		unpacked: []*big.Int{big.NewInt(1), big.NewInt(2)},
	},
	{
		def: `[{"type": "uint256[3]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000003",
		unpacked: [3]*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3)},
	},
	{
		def: `[{"type": "string[4]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000080" +
			"00000000000000000000000000000000000000000000000000000000000000c0" +
			"0000000000000000000000000000000000000000000000000000000000000100" +
			"0000000000000000000000000000000000000000000000000000000000000140" +
			"0000000000000000000000000000000000000000000000000000000000000005" +
			"48656c6c6f000000000000000000000000000000000000000000000000000000" +
			"0000000000000000000000000000000000000000000000000000000000000005" +
			"576f726c64000000000000000000000000000000000000000000000000000000" +
			"000000000000000000000000000000000000000000000000000000000000000b" +
			"476f2d657468657265756d000000000000000000000000000000000000000000" +
			"0000000000000000000000000000000000000000000000000000000000000008" +
			"457468657265756d000000000000000000000000000000000000000000000000",
		unpacked: [4]string{"Hello", "World", "Go-ethereum", "Ethereum"},
	},
	{
		def: `[{"type": "string[]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000040" +
			"0000000000000000000000000000000000000000000000000000000000000080" +
			"0000000000000000000000000000000000000000000000000000000000000008" +
			"457468657265756d000000000000000000000000000000000000000000000000" +
			"000000000000000000000000000000000000000000000000000000000000000b" +
			"676f2d657468657265756d000000000000000000000000000000000000000000",
		unpacked: []string{"Ethereum", "go-ethereum"},
	},
	{
		def: `[{"type": "bytes[]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000040" +
			"0000000000000000000000000000000000000000000000000000000000000080" +
			"0000000000000000000000000000000000000000000000000000000000000003" +
			"f0f0f00000000000000000000000000000000000000000000000000000000000" +
			"0000000000000000000000000000000000000000000000000000000000000003" +
			"f0f0f00000000000000000000000000000000000000000000000000000000000",
		unpacked: [][]byte{{0xf0, 0xf0, 0xf0}, {0xf0, 0xf0, 0xf0}},
	},
	{
		def: `[{"type": "uint256[2][][]"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000040" +
			"00000000000000000000000000000000000000000000000000000000000000e0" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"00000000000000000000000000000000000000000000000000000000000000c8" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"00000000000000000000000000000000000000000000000000000000000003e8" +
			"0000000000000000000000000000000000000000000000000000000000000002" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"00000000000000000000000000000000000000000000000000000000000000c8" +
			"0000000000000000000000000000000000000000000000000000000000000001" +
			"00000000000000000000000000000000000000000000000000000000000003e8",
		unpacked: [][][2]*big.Int{{{big.NewInt(1), big.NewInt(200)}, {big.NewInt(1), big.NewInt(1000)}}, {{big.NewInt(1), big.NewInt(200)}, {big.NewInt(1), big.NewInt(1000)}}},
	},
	// struct outputs
	{
		def: `[{"name":"int1","type":"int256"},{"name":"int2","type":"int256"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
		unpacked: struct {
			Int1 *big.Int
			Int2 *big.Int
		}{big.NewInt(1), big.NewInt(2)},
	},
	{
		def:    `[{"name":"int_one","type":"int256"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000001",
		unpacked: struct {
			IntOne *big.Int
		}{big.NewInt(1)},
	},
	{
		def:    `[{"name":"int__one","type":"int256"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000001",
		unpacked: struct {
			IntOne *big.Int
		}{big.NewInt(1)},
	},
	{
		def:    `[{"name":"int_one_","type":"int256"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000001",
		unpacked: struct {
			IntOne *big.Int
		}{big.NewInt(1)},
	},
	{
		def: `[{"name":"int_one","type":"int256"}, {"name":"intone","type":"int256"}]`,
		packed: "0000000000000000000000000000000000000000000000000000000000000001" +
			"0000000000000000000000000000000000000000000000000000000000000002",
		unpacked: struct {
			IntOne *big.Int
			Intone *big.Int
		}{big.NewInt(1), big.NewInt(2)},
	},
	{
		def:      `[{"type": "string"}]`,
		unpacked: "foobar",
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000006" +
			"666f6f6261720000000000000000000000000000000000000000000000000000",
	},
	{
		def:      `[{"type": "string[]"}]`,
		unpacked: []string{"hello", "foobar"},
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2
			"0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i = 0
			"0000000000000000000000000000000000000000000000000000000000000080" + // offset 128 to i = 1
			"0000000000000000000000000000000000000000000000000000000000000005" + // len(str[0]) = 5
			"68656c6c6f000000000000000000000000000000000000000000000000000000" + // str[0]
			"0000000000000000000000000000000000000000000000000000000000000006" + // len(str[1]) = 6
			"666f6f6261720000000000000000000000000000000000000000000000000000", // str[1]
	},
	{
		def:      `[{"type": "string[2]"}]`,
		unpacked: [2]string{"hello", "foobar"},
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000040" + // offset to i = 0
			"0000000000000000000000000000000000000000000000000000000000000080" + // offset to i = 1
			"0000000000000000000000000000000000000000000000000000000000000005" + // len(str[0]) = 5
			"68656c6c6f000000000000000000000000000000000000000000000000000000" + // str[0]
			"0000000000000000000000000000000000000000000000000000000000000006" + // len(str[1]) = 6
			"666f6f6261720000000000000000000000000000000000000000000000000000", // str[1]
	},
	{
		def:      `[{"type": "bytes32[][]"}]`,
		unpacked: [][][32]byte{{{1}, {2}}, {{3}, {4}, {5}}},
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2
			"0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i = 0
			"00000000000000000000000000000000000000000000000000000000000000a0" + // offset 160 to i = 1
			"0000000000000000000000000000000000000000000000000000000000000002" + // len(array[0]) = 2
			"0100000000000000000000000000000000000000000000000000000000000000" + // array[0][0]
			"0200000000000000000000000000000000000000000000000000000000000000" + // array[0][1]
			"0000000000000000000000000000000000000000000000000000000000000003" + // len(array[1]) = 3
			"0300000000000000000000000000000000000000000000000000000000000000" + // array[1][0]
			"0400000000000000000000000000000000000000000000000000000000000000" + // array[1][1]
			"0500000000000000000000000000000000000000000000000000000000000000", // array[1][2]
	},
	{
		def:      `[{"type": "bytes32[][2]"}]`,
		unpacked: [2][][32]byte{{{1}, {2}}, {{3}, {4}, {5}}},
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i = 0
			"00000000000000000000000000000000000000000000000000000000000000a0" + // offset 160 to i = 1
			"0000000000000000000000000000000000000000000000000000000000000002" + // len(array[0]) = 2
			"0100000000000000000000000000000000000000000000000000000000000000" + // array[0][0]
			"0200000000000000000000000000000000000000000000000000000000000000" + // array[0][1]
			"0000000000000000000000000000000000000000000000000000000000000003" + // len(array[1]) = 3
			"0300000000000000000000000000000000000000000000000000000000000000" + // array[1][0]
			"0400000000000000000000000000000000000000000000000000000000000000" + // array[1][1]
			"0500000000000000000000000000000000000000000000000000000000000000", // array[1][2]
	},
	{
		def:      `[{"type": "bytes32[3][2]"}]`,
		unpacked: [2][3][32]byte{{{1}, {2}, {3}}, {{3}, {4}, {5}}},
		packed: "0100000000000000000000000000000000000000000000000000000000000000" + // array[0][0]
			"0200000000000000000000000000000000000000000000000000000000000000" + // array[0][1]
			"0300000000000000000000000000000000000000000000000000000000000000" + // array[0][2]
			"0300000000000000000000000000000000000000000000000000000000000000" + // array[1][0]
			"0400000000000000000000000000000000000000000000000000000000000000" + // array[1][1]
			"0500000000000000000000000000000000000000000000000000000000000000", // array[1][2]
	},
	{
		// static tuple
		def: `[{"name":"a","type":"int64"}, 
		{"name":"b","type":"int256"}, 
		{"name":"c","type":"int256"}, 
		{"name":"d","type":"bool"},
		{"name":"e","type":"bytes32[3][2]"}]`,
		unpacked: struct {
			A int64
			B *big.Int
			C *big.Int
			D bool
			E [2][3][32]byte
		}{1, big.NewInt(1), big.NewInt(-1), true, [2][3][32]byte{{{1}, {2}, {3}}, {{3}, {4}, {5}}}},
		packed: "0000000000000000000000000000000000000000000000000000000000000001" + // struct[a]
			"0000000000000000000000000000000000000000000000000000000000000001" + // struct[b]
			"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + // struct[c]
			"0000000000000000000000000000000000000000000000000000000000000001" + // struct[d]
			"0100000000000000000000000000000000000000000000000000000000000000" + // struct[e] array[0][0]
			"0200000000000000000000000000000000000000000000000000000000000000" + // struct[e] array[0][1]
			"0300000000000000000000000000000000000000000000000000000000000000" + // struct[e] array[0][2]
			"0300000000000000000000000000000000000000000000000000000000000000" + // struct[e] array[1][0]
			"0400000000000000000000000000000000000000000000000000000000000000" + // struct[e] array[1][1]
			"0500000000000000000000000000000000000000000000000000000000000000", // struct[e] array[1][2]
	},
	{
		def: `[{"name":"a","type":"string"}, 
		{"name":"b","type":"int64"}, 
		{"name":"c","type":"bytes"}, 
		{"name":"d","type":"string[]"},
		{"name":"e","type":"int256[]"},
		{"name":"f","type":"address[]"}]`,
		unpacked: struct {
			FieldA string `abi:"a"` // Test whether abi tag works
			FieldB int64  `abi:"b"`
			C      []byte
			D      []string
			E      []*big.Int
			F      []common.Address
		}{"foobar", 1, []byte{1}, []string{"foo", "bar"}, []*big.Int{big.NewInt(1), big.NewInt(-1)}, []common.Address{{1}, {2}}},
		packed: "00000000000000000000000000000000000000000000000000000000000000c0" + // struct[a] offset
			"0000000000000000000000000000000000000000000000000000000000000001" + // struct[b]
			"0000000000000000000000000000000000000000000000000000000000000100" + // struct[c] offset
			"0000000000000000000000000000000000000000000000000000000000000140" + // struct[d] offset
			"0000000000000000000000000000000000000000000000000000000000000220" + // struct[e] offset
			"0000000000000000000000000000000000000000000000000000000000000280" + // struct[f] offset
			"0000000000000000000000000000000000000000000000000000000000000006" + // struct[a] length
			"666f6f6261720000000000000000000000000000000000000000000000000000" + // struct[a] "foobar"
			"0000000000000000000000000000000000000000000000000000000000000001" + // struct[c] length
			"0100000000000000000000000000000000000000000000000000000000000000" + // []byte{1}
			"0000000000000000000000000000000000000000000000000000000000000002" + // struct[d] length
			"0000000000000000000000000000000000000000000000000000000000000040" + // foo offset
			"0000000000000000000000000000000000000000000000000000000000000080" + // bar offset
			"0000000000000000000000000000000000000000000000000000000000000003" + // foo length
			"666f6f0000000000000000000000000000000000000000000000000000000000" + // foo
			"0000000000000000000000000000000000000000000000000000000000000003" + // bar offset
			"6261720000000000000000000000000000000000000000000000000000000000" + // bar
			"0000000000000000000000000000000000000000000000000000000000000002" + // struct[e] length
			"0000000000000000000000000000000000000000000000000000000000000001" + // 1
			"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + // -1
			"0000000000000000000000000000000000000000000000000000000000000002" + // struct[f] length
			"0000000000000000000000000100000000000000000000000000000000000000" + // common.Address{1}
			"0000000000000000000000000200000000000000000000000000000000000000", // common.Address{2}
	},
	{
		def: `[{"components": [{"name": "a","type": "uint256"},	
							{"name": "b","type": "uint256[]"}],	
							"name": "a","type": "tuple"},
							{"name": "b","type": "uint256[]"}]`,
		unpacked: struct {
			A struct {
				FieldA *big.Int `abi:"a"`
				B      []*big.Int
			}
			B []*big.Int
		}{
			A: struct {
				FieldA *big.Int `abi:"a"` // Test whether abi tag works for nested tuple
				B      []*big.Int
			}{big.NewInt(1), []*big.Int{big.NewInt(1), big.NewInt(2)}},
			B: []*big.Int{big.NewInt(1), big.NewInt(2)}},
		packed: "0000000000000000000000000000000000000000000000000000000000000040" + // a offset
			"00000000000000000000000000000000000000000000000000000000000000e0" + // b offset
			"0000000000000000000000000000000000000000000000000000000000000001" + // a.a value
			"0000000000000000000000000000000000000000000000000000000000000040" + // a.b offset
			"0000000000000000000000000000000000000000000000000000000000000002" + // a.b length
			"0000000000000000000000000000000000000000000000000000000000000001" + // a.b[0] value
			"0000000000000000000000000000000000000000000000000000000000000002" + // a.b[1] value
			"0000000000000000000000000000000000000000000000000000000000000002" + // b length
			"0000000000000000000000000000000000000000000000000000000000000001" + // b[0] value
			"0000000000000000000000000000000000000000000000000000000000000002", // b[1] value
	},

	{
		def: `[{"components": [{"name": "a","type": "int256"},	
							{"name": "b","type": "int256[]"}],	
							"name": "a","type": "tuple[]"}]`,
		unpacked: []struct {
			A *big.Int
			B []*big.Int
		}{
			{big.NewInt(-1), []*big.Int{big.NewInt(1), big.NewInt(3)}},
			{big.NewInt(1), []*big.Int{big.NewInt(2), big.NewInt(-1)}},
		},
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000002" + // tuple length
			"0000000000000000000000000000000000000000000000000000000000000040" + // tuple[0] offset
			"00000000000000000000000000000000000000000000000000000000000000e0" + // tuple[1] offset
			"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + // tuple[0].A
			"0000000000000000000000000000000000000000000000000000000000000040" + // tuple[0].B offset
			"0000000000000000000000000000000000000000000000000000000000000002" + // tuple[0].B length
			"0000000000000000000000000000000000000000000000000000000000000001" + // tuple[0].B[0] value
			"0000000000000000000000000000000000000000000000000000000000000003" + // tuple[0].B[1] value
			"0000000000000000000000000000000000000000000000000000000000000001" + // tuple[1].A
			"0000000000000000000000000000000000000000000000000000000000000040" + // tuple[1].B offset
			"0000000000000000000000000000000000000000000000000000000000000002" + // tuple[1].B length
			"0000000000000000000000000000000000000000000000000000000000000002" + // tuple[1].B[0] value
			"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // tuple[1].B[1] value
	},
	{
		def: `[{"components": [{"name": "a","type": "int256"},	
							{"name": "b","type": "int256"}],	
							"name": "a","type": "tuple[2]"}]`,
		unpacked: [2]struct {
			A *big.Int
			B *big.Int
		}{
			{big.NewInt(-1), big.NewInt(1)},
			{big.NewInt(1), big.NewInt(-1)},
		},
		packed: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + // tuple[0].a
			"0000000000000000000000000000000000000000000000000000000000000001" + // tuple[0].b
			"0000000000000000000000000000000000000000000000000000000000000001" + // tuple[1].a
			"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // tuple[1].b
	},
	{
		def: `[{"components": [{"name": "a","type": "int256[]"}],
							"name": "a","type": "tuple[2]"}]`,
		unpacked: [2]struct {
			A []*big.Int
		}{
			{[]*big.Int{big.NewInt(-1), big.NewInt(1)}},
			{[]*big.Int{big.NewInt(1), big.NewInt(-1)}},
		},
		packed: "0000000000000000000000000000000000000000000000000000000000000020" +
			"0000000000000000000000000000000000000000000000000000000000000040" + // tuple[0] offset
			"00000000000000000000000000000000000000000000000000000000000000c0" + // tuple[1] offset
			"0000000000000000000000000000000000000000000000000000000000000020" + // tuple[0].A offset
			"0000000000000000000000000000000000000000000000000000000000000002" + // tuple[0].A length
			"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + // tuple[0].A[0]
			"0000000000000000000000000000000000000000000000000000000000000001" + // tuple[0].A[1]
			"0000000000000000000000000000000000000000000000000000000000000020" + // tuple[1].A offset
			"0000000000000000000000000000000000000000000000000000000000000002" + // tuple[1].A length
			"0000000000000000000000000000000000000000000000000000000000000001" + // tuple[1].A[0]
			"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // tuple[1].A[1]
	},
}
