go-ethereum icon indicating copy to clipboard operation
go-ethereum copied to clipboard

ABI unpacking failure on non 32 byte multiple input - but can get around via method itself

Open fxfactorial opened this issue 1 year ago • 1 comments


const router = (```
[
    {
        "inputs": [
            {
                "internalType": "bytes",
                "name": "commands",
                "type": "bytes"
            },
            {
                "internalType": "bytes[]",
                "name": "inputs",
                "type": "bytes[]"
            },
            {
                "internalType": "uint256",
                "name": "deadline",
                "type": "uint256"
            }
        ],
        "name": "execute",
        "outputs": [],
        "stateMutability": "payable",
        "type": "function"
    }
]
```)


var (
 contractABI  = abi.JSON(strings.NewReader(router))
	payload2 = common.Hex2Bytes("3593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000657c7e2f00000000000000000000000000000000000000000000000000000000000000030a080c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000001600000000000000000000000007d8146cf21e8d7cbe46054e01588207b51198729000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000065a405f700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fc91a3afd70395cd496c647d5a6cc9d4b2b7fad00000000000000000000000000000000000000000000000000000000657c7fff00000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000041736de91d05e0d3501511a9540d908c0d0ca7cce20f7b8e56f1211b3218de48f76a268f6903ae1e647e1d7f2325a45eff2bee9e187abed0897e225caf3cf500011b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000d3c21bcecceda10000000000000000000000000000000000000000000000000000000058569948b55b00a00000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000007d8146cf21e8d7cbe46054e01588207b51198729000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000058569948b55b00a")
)

		decoded, err := contractABI.Unpack("execute", payload2)

will fail on if len(data)%32 != 0 { in getArguments becuse 1060 % 32 == 4, not 0. But you can get around it by grabbing the method directly contract.Methods["execute"] and unpacking that way

fxfactorial avatar Dec 15 '23 16:12 fxfactorial

If you used the correct encoding tool, your input should be modulo 32 == 0, which shouldn't be an issue with ABI decoding.

YancyParker avatar Mar 01 '24 05:03 YancyParker

The signature 3593564c is the method execute(bytes,bytes[],uint256). Therefore, when you invoke contractABI.Unpack("execute", 0x3593564c0000..), you are telling it basically "call execute with arguments execute, 1, 2.."

You cannot pass the 4-byte method signature to the method itself. If you invoke contractABI.Unpack("execute", payload2[4:]) it should be fine

package xyz

import (
	"strings"
	"testing"

	"github.com/ethereum/go-ethereum/accounts/abi"
	"github.com/ethereum/go-ethereum/common"
)

var router = `
[
    {
        "inputs": [
            {
                "internalType": "bytes",
                "name": "commands",
                "type": "bytes"
            },
            {
                "internalType": "bytes[]",
                "name": "inputs",
                "type": "bytes[]"
            },
            {
                "internalType": "uint256",
                "name": "deadline",
                "type": "uint256"
            }
        ],
        "name": "execute",
        "outputs": [],
        "stateMutability": "payable",
        "type": "function"
    }
]
`

func TestFoo(t *testing.T) {
	contractABI, err := abi.JSON(strings.NewReader(router))
	if err != nil {
		t.Fatal(err)
	}
	payload2 := common.Hex2Bytes("3593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000657c7e2f00000000000000000000000000000000000000000000000000000000000000030a080c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000001600000000000000000000000007d8146cf21e8d7cbe46054e01588207b51198729000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000065a405f700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fc91a3afd70395cd496c647d5a6cc9d4b2b7fad00000000000000000000000000000000000000000000000000000000657c7fff00000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000041736de91d05e0d3501511a9540d908c0d0ca7cce20f7b8e56f1211b3218de48f76a268f6903ae1e647e1d7f2325a45eff2bee9e187abed0897e225caf3cf500011b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000d3c21bcecceda10000000000000000000000000000000000000000000000000000000058569948b55b00a00000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000007d8146cf21e8d7cbe46054e01588207b51198729000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000058569948b55b00a")
	_, err = contractABI.Unpack("execute", payload2[4:])
	if err != nil {
		t.Fatalf("error: %v\n", err)
	}
}

This works, but removing [4:] makes it fail with error: abi: improperly formatted output: "5\x93VL\x0...

holiman avatar Aug 09 '24 07:08 holiman