Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ABI Decoding Issue with go-ethereum: "Improperly Formatted Output" for Complex Tuple Array #30929

Open
m-quigley opened this issue Dec 18, 2024 · 3 comments
Assignees

Comments

@m-quigley
Copy link

m-quigley commented Dec 18, 2024

I'm encountering an issue with decoding ABI data using go-ethereum's abi.Unpack or UnpackIntoInterface method. Here are the details:

Go Code Attempt:

type Route struct {
  From    common.Address
  To      common.Address
  Stable  bool
  Factory common.Address
}

type SwapExactTokensForTokensInput struct {
  AmountIn     *big.Int
  AmountOutMin *big.Int
  Routes       []Route
  To           common.Address
  Deadline     *big.Int
}

	abiJSON := `[
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "amountIn",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "amountOutMin",
        "type": "uint256"
      },
      {
        "components": [
          {
            "internalType": "address",
            "name": "from",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "to",
            "type": "address"
          },
          {
            "internalType": "bool",
            "name": "stable",
            "type": "bool"
          },
          {
            "internalType": "address",
            "name": "factory",
            "type": "address"
          }
        ],
        "internalType": "struct IRouter.Route[]",
        "name": "routes",
        "type": "tuple[]"
      },
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "deadline",
        "type": "uint256"
      }
    ],
    "name": "swapExactTokensForTokens",
    "outputs": [
      {
        "internalType": "uint256[]",
        "name": "amounts",
        "type": "uint256[]"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  }]`

	parsedABI, err := abi.JSON(strings.NewReader(abiJSON))
	if err != nil {
		log.Fatalf("Error parsing ABI: %v", err)
	}

	input := "0xcac88ea9000000000000000000000000000000000000000000000001c9f78d2893e4000000000000000000000000000000000000000000000001b4c0595a86aa1c10000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000001a6228e2f05ee0c0e822be08249c815b37467f4000000000000000000000000000000000000000000000000000000000676035ba00000000000000000000000000000000000000000000000000000000000000010000000000000000000000004200000000000000000000000000000000000006000000000000000000000000800822d361335b4d5f352dac293ca4128b5b605f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000420dd381b31aef6683db6b902084cb0ffece40da"

	var inputStruct SwapExactTokensForTokensInput
	if err := parsedABI.UnpackIntoInterface(&inputStruct, "swapExactTokensForTokens", common.FromHex(input)); err != nil {
		log.Fatalf("Error unpacking input: %v", err)
	}

Error Received:

Error unpacking input: abi: improperly formatted output: "\xcaȎ\xa9\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xc9\xf7\x8d(\x93\xe4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xb4\xc0YZ\x86\xaa\x1c\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1ab(\xe2\xf0^\xe0\xc0\xe8\"\xbe\b$\x9c\x81[7F\x7f@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00g`5\xba\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\b\"\xd3a3[M_5-\xac)<\xa4\x12\x8b[`_\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B\rӁ\xb3\x1a\xeff\x83\xdbk\x90 \x84\xcb\x0f\xfe\xce@\xda" - Bytes: [202 200 142 169 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 201 247 141 40 147 228 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 180 192 89 90 134 170 28 16 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 0 0 160 0 0 0 0 0 0 0 0 0 0 0 0 26 98 40 226 240 94 224 192 232 34 190 8 36 156 129 91 55 70 127 64 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 103 96 53 186 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 1 0 0 0 0 0 0 0 0 0 0 0 0 66 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 128 8 34 211 97 51 91 77 95 53 45 172 41 60 164 18 139 91 96 95 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 0 0 0 0 0 0 0 0 0 0 0 0 0 66 13 211 129 179 26 239 102 131 219 107 144 32 132 203 15 254 206 64 218]

Steps Taken:

  • Verified that the ABI matches the function signature in the smart contract.
  • Checked that the hex input is correctly formatted and converted to bytes.
  • Tested decoding in JavaScript with ethers.js, which works without issues.
  • Tested decoding in https://lab.miguelmota.com/ethereum-input-data-decoder/example/, which works without issues.
  • Ensured struct definitions match ABI specifications.

Question:

Can anyone identify why this decoding fails in Go, or is there a known issue with decoding such complex tuple arrays with go-ethereum? Any suggestions or fixes would be greatly appreciated.
I've used this same approach for decoding calldata hundreds of times, first time facing this issue

Additional Info:

go-ethereum version: 1.22
Go version: v1.14.12

any help would be hugely appreciated

@m-quigley
Copy link
Author

m-quigley commented Dec 18, 2024

the ABI is a subset of this CAs abi, if that helps at all
https://basescan.org/address/0xcf77a3ba9a5ca399b7c97c74d54e5b1beb874e43

@m-quigley
Copy link
Author

also, slicing off the method selector

if err := parsedABI.UnpackIntoInterface(&inputStruct, "swapExactTokensForTokens", common.FromHex(input)[4:]); err != nil {

results in

2024/12/18 12:02:51 Error unpacking input: abi: cannot marshal in to go slice: offset 33000000000000000032 would go over slice boundary (len=320)

@m-quigley
Copy link
Author

m-quigley commented Dec 18, 2024

Found #26242 which is the same issue, never fully resolved. I have the same result, if I use method.Inputs.Unpack it works

@jwasinger jwasinger self-assigned this Dec 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants