GridPlus / gridplus-sdk

SDK for communicating with the GridPlus Lattice1 hardware wallet
MIT License
50 stars 24 forks source link

Edge case in `getParamStrNames` - invalid tuple type deconstruction #484

Closed alex-miller-0 closed 1 year ago

alex-miller-0 commented 1 year ago

We are not properly constructing types to ethers.js' ABI decoder. Consider the example:

Function:

upgradeInstallation((address,uint16,uint16,uint40,bool,uint256,uint256),uint256,bytes,uint40)

Calldata: (less function selector)

0x00000000000000000000000038a1e0bf2745740c303fe4140397d157818a6e3c000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004d0200000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000003a95000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000175800000000000000000000000000000000000000000000000000000000000000041254e600d62d2023c81f092c2f95951cc1e540c572230eb00d57e2ee613e44fb34ca84461f23fc8be1eea17a4c3c95c6c08fe1ba2c9cb55de326919947c9b947b1b00000000000000000000000000000000000000000000000000000000000000

This will produce the following def:

[
  "upgradeInstallation",
  [
    "#1",
    7,
    0,
    [],
    [
      [
        "#1-1",
        1,
        0,
        []
      ],
      [
        "#1-2",
        3,
        2,
        []
      ],
      [
        "#1-3",
        3,
        2,
        []
      ],
      [
        "#1-4",
        3,
        5,
        []
      ],
      [
        "#1-5",
        2,
        0,
        []
      ],
      [
        "#1-6",
        3,
        32,
        []
      ],
      [
        "#1-7",
        3,
        32,
        []
      ]
    ]
  ],
  [
    "#2",
    3,
    32,
    []
  ],
  [
    "#3",
    5,
    0,
    []
  ],
  [
    "#4",
    3,
    5,
    []
  ]
]

Which is correct. However, when calling getParamStrNames I get the following types:

[ 'tuple', 'uint256', 'bytes', 'uint40' ]

This is incorrect and results in an invalid ABI decoding from ethers' module:

> x = coder.decode([ 'tuple', 'uint256', 'bytes', 'uint40' ], calldata)
[
  [],
  BigNumber {
    _hex: '0x38a1e0bf2745740c303fe4140397d157818a6e3c',
    _isBigNumber: true
  },
  [Getter],
  38
]
> x[2]
Uncaught:
null: overflow [ See: https://links.ethers.org/v5-errors-NUMERIC_FAULT-overflow ] (fault="overflow", operation="toNumber", value="101655816912589427149257469225545537015158869111648147050794596951950635302912", code=NUMERIC_FAULT, version=bignumber/5.6.2)
    at Logger.makeError (/Users/alexmiller/Projects/new-gridplus/tools/gridplus-sdk/node_modules/@ethersproject/logger/lib/index.js:233:21)
    at Logger.throwError (/Users/alexmiller/Projects/new-gridplus/tools/gridplus-sdk/node_modules/@ethersproject/logger/lib/index.js:242:20)
    at throwFault (/Users/alexmiller/Projects/new-gridplus/tools/gridplus-sdk/node_modules/@ethersproject/bignumber/lib/bignumber.js:303:19)
    at BigNumber.toNumber (/Users/alexmiller/Projects/new-gridplus/tools/gridplus-sdk/node_modules/@ethersproject/bignumber/lib/bignumber.js:151:13)
    at DynamicBytesCoder.decode (/Users/alexmiller/Projects/new-gridplus/tools/gridplus-sdk/node_modules/@ethersproject/abi/lib/coders/bytes.js:36:52)
    at BytesCoder.decode (/Users/alexmiller/Projects/new-gridplus/tools/gridplus-sdk/node_modules/@ethersproject/abi/lib/coders/bytes.js:47:86)
    at /Users/alexmiller/Projects/new-gridplus/tools/gridplus-sdk/node_modules/@ethersproject/abi/lib/coders/array.js:94:31
    at Array.forEach (<anonymous>)
    at unpack (/Users/alexmiller/Projects/new-gridplus/tools/gridplus-sdk/node_modules/@ethersproject/abi/lib/coders/array.js:88:12)
    at TupleCoder.decode (/Users/alexmiller/Projects/new-gridplus/tools/gridplus-sdk/node_modules/@ethersproject/abi/lib/coders/tuple.js:74:60) {
  reason: 'overflow',
  code: 'NUMERIC_FAULT',
  fault: 'overflow',
  operation: 'toNumber',
  value: '101655816912589427149257469225545537015158869111648147050794596951950635302912',
  baseType: 'bytes',
  type: 'bytes'
}

Here's the correct decoding:

coder.decode([
  'tuple(address, uint16, uint16, uint40, bool, uint256, uint256)',
  'uint256',
  'bytes',
  'uint40'
], calldata)
> coder.decode(types, calldata)
[
  [
    '0x38A1E0Bf2745740C303FE4140397D157818A6e3C',
    14,
    38,
    0,
    false,
    BigNumber { _hex: '0x4d02', _isBigNumber: true },
    BigNumber { _hex: '0x41', _isBigNumber: true }
  ],
  BigNumber { _hex: '0x3a95', _isBigNumber: true },
  '0x254e600d62d2023c81f092c2f95951cc1e540c572230eb00d57e2ee613e44fb34ca84461f23fc8be1eea17a4c3c95c6c08fe1ba2c9cb55de326919947c9b947b1b',
  95616
]

So there is something about this tuple that is not getting properly parsed... 🤔