如果我得到这样的输入
0 x18cbafe5000000000000000000000000000000000000000000000001885c663d0035bce200000000000000000000000000000000000000000000000000f5666f7fdaa62600000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000c0be713b48822271b362e9fac00479f5134172e80000000000000000000000000000000000000000000000000000000060e93fa900000000000000000000000000000000000000000000000000000000000000020000000000000000000000009813037ee2218799597d83d4a5b6f3b6778218d9000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
如果我有一个像这样的函数签名"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来解码这样的输入
我知道我可以像这样分割事务的输入:
("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0be713b48822271b362e9fac00479f5134172288","000000000000000000000000000000000000000000000000000000000000000000000000000000000060e93fa9","0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002","000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009813037ee2218799597d83d4a5b6f3b6778218d9","000000000000000000000000 c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")
这个数组的最后两个是上面输入数组中索引2的地址。但是在函数签名的顺序是第三,我怎么知道它是从输入端拉出来的?
这是abi在有用的地方像解码使用web3吗?或者没有abi也可以解码吗?
是否可以在没有ABI的情况下进行解码?
只有当你至少有函数签名或定义。
如果你不知道有哪些输入类型,你将无法判断这个输入
00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003666f6f0000000000000000000000000000000000000000000000000000000000
是一个字符串foo
或三个连续的无符号整数(十进制值):
32
3
46332796673528066027243215619882264990369332300865266851730502456685210107904
如果您知道输入数据类型,一个简单的方法(不需要实际的ABI JSON)是使用web3 decodeParameters函数。
const data = web3.eth.abi.decodeParameters(
["uint256", "uint256", "address[]", "address", "uint256"],
"000000000000000000000000000000000000000000000001885c663d0035bce200000000000000000000000000000000000000000000000000f5666f7fdaa62600000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000c0be713b48822271b362e9fac00479f5134172e80000000000000000000000000000000000000000000000000000000060e93fa900000000000000000000000000000000000000000000000000000000000000020000000000000000000000009813037ee2218799597d83d4a5b6f3b6778218d9000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
);
返回Result {
'0': '28272584972907691234',
'1': '69073998366549542',
'2': [
'0x9813037ee2218799597d83D4a5B6F3b6778218d9',
'0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'
],
'3': '0xc0Be713B48822271b362e9Fac00479f5134172e8',
'4': '1625898921',
__length__: 5
}
这些值已经被编码为它们各自的数据类型——例如整数是十进制的(而不是你问题中的十六进制)。它们作为字符串返回,只是因为JS在处理大整数时有时会遇到舍入错误。
注意前4个字节(8个十六进制字符;在您的情况下,18cbafe5
)是函数选择器-而不是参数值。所以你不把它传递给decodeParameters()
函数。
其中数组的最后两个是上面输入数组中索引2的地址。但是在函数签名的顺序是第三,我怎么知道它是从输入端拉出来的?
这就是ABI的工作原理。如果使用动态类型,则其实际槽位包含指向值的实际位置的偏移量(包括前置长度)。在您的情况下,是160(十六进制a0
)字节。
所有的动态值都在有效载荷的末尾排序,前面加上section的长度。
在您的例子中,2
声明在这个数组中有2个值,其余的是数组的实际值。
您可以在文档中找到有关排序的更多信息:https://docs.soliditylang.org/en/v0.8.7/abi-spec.html#formal-specification-of-the-encoding