解码没有abi的交易输入?

decoding input of a transaction without abi?

如果我得到这样的输入

0x18cbafe5000000000000000000000000000000000000000000000001885c663d0035bce200000000000000000000000000000000000000000000000000f5666f7fdaa62600000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000c0be713b48822271b362e9fac00479f5134172e80000000000000000000000000000000000000000000000000000000060e93fa900000000000000000000000000000000000000000000000000000000000000020000000000000000000000009813037ee2218799597d83d4a5b6f3b6778218d9000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2

如果我有这样的函数签名"swapExactTokensForETH(uint256,uint256,address[],address,uint256)" 没有 ABI 可以解码吗?

我从签名中知道类型

"types": [
    "uint256",
    "uint256",
    "address[]",
    "address",
    "uint256"
],

但是解码后看起来像这样:

"inputs": [
    "1885c663d0035bce2",
    "f5666f7fdaa626",
    [
        "9813037ee2218799597d83d4a5b6f3b6778218d9",
        "c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
    ],
    "c0be713b48822271b362e9fac00479f5134172e8",
    "60e93fa9"
 ]

其中索引0是uint256,索引1是下一个uint256,索引2是地址[],索引3是地址,索引4是uint256

那么有什么逻辑可以知道索引2中的数组是从事务输入末尾的两个地址中拉取的。

如果可能的话,我尽量不需要 ABI 像这样解码输入

我知道我可以像这样拆分交易的输入:

[ '000000000000000000000000000000000000000000000001885c663d0035bce2', '00000000000000000000000000000000000000000000000000f5666f7fdaa626', '00000000000000000000000000000000000000000000000000000000000000a0', '000000000000000000000000c0be713b48822271b362e9fac00479f5134172e8', '0000000000000000000000000000000000000000000000000000000060e93fa9', '0000000000000000000000000000000000000000000000000000000000000002', '0000000000000000000000009813037ee2218799597d83d4a5b6f3b6778218d9', '000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2' ]

该数组中的最后两个是上面输入数组中索引 2 显示的地址。但是按照函数签名的顺序是第三,我怎么知道是从最后面的输入中拉出来的呢?

这就是 abi 发挥作用的地方,就像使用 web3 解码一样吗?或者这是否可以在没有 abi 的情况下解码?

is it possible to decode without the ABI?

仅当您至少拥有函数签名或定义时。

如果你不知道有哪些输入类型,你将无法判断这个输入是否正确

00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003666f6f0000000000000000000000000000000000000000000000000000000000

是一个字符串foo

或三个连续的无符号整数(十进制值):

  • 32
  • 3
  • 46332796673528066027243215619882264990369332300865266851730502456685210107904

如果您知道输入数据类型,一个简单的方法(没有实际的 ABI JSON)是使用 web3 decodeParameters 函数。

const data = web3.eth.abi.decodeParameters(
    ["uint256", "uint256", "address[]", "address", "uint256"],
    "000000000000000000000000000000000000000000000001885c663d0035bce200000000000000000000000000000000000000000000000000f5666f7fdaa62600000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000c0be713b48822271b362e9fac00479f5134172e80000000000000000000000000000000000000000000000000000000060e93fa900000000000000000000000000000000000000000000000000000000000000020000000000000000000000009813037ee2218799597d83d4a5b6f3b6778218d9000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
);

returns

Result {
  '0': '28272584972907691234',
  '1': '69073998366549542',
  '2': [
    '0x9813037ee2218799597d83D4a5B6F3b6778218d9',
    '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'
  ],
  '3': '0xc0Be713B48822271b362e9Fac00479f5134172e8',
  '4': '1625898921',
  __length__: 5
}

这些值已经编码为它们各自的数据类型 - 例如整数是十进制的(而不是你问题中的十六进制)。它们作为字符串返回只是因为 JS 在处理大整数时有时 运行 会出现舍入错误。

请注意前 4 个字节(8 个十六进制字符;在您的情况下 18cbafe5)是函数选择器 - 而不是参数值。所以你不要将它传递给 decodeParameters() 函数。


Where the last two in that array from this are the addresses that show up for index 2 in the inputs array above. But in the order of the function signature is third, how do I know that it is pulled from the input from the end?

这就是 ABI 的工作原理。如果你有一个动态类型,它的实际插槽包含指向值实际位置的偏移量(包括前置长度)。在你的情况下是 160 (hexa0) 字节。

所有动态值都排在有效负载的末尾,前面加上部分的长度。

在您的例子中,2 表示此数组中有 2 个值,其余为数组的实际值。

您可以在文档中找到有关排序的更多信息:https://docs.soliditylang.org/en/v0.8.7/abi-spec.html#formal-specification-of-the-encoding