Reputation: 4811
If I am given an input like this
0x18cbafe5000000000000000000000000000000000000000000000001885c663d0035bce200000000000000000000000000000000000000000000000000f5666f7fdaa62600000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000c0be713b48822271b362e9fac00479f5134172e80000000000000000000000000000000000000000000000000000000060e93fa900000000000000000000000000000000000000000000000000000000000000020000000000000000000000009813037ee2218799597d83d4a5b6f3b6778218d9000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
If I have a function signature like this "swapExactTokensForETH(uint256,uint256,address[],address,uint256)"
is it possible to decode without the ABI?
I know the types from the signature
"types": [
"uint256",
"uint256",
"address[]",
"address",
"uint256"
],
But when decoded it looks like this:
"inputs": [
"1885c663d0035bce2",
"f5666f7fdaa626",
[
"9813037ee2218799597d83d4a5b6f3b6778218d9",
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
],
"c0be713b48822271b362e9fac00479f5134172e8",
"60e93fa9"
]
Where index 0 is the uint256, index 1 is the next uint256, index 2 is address[], index 3 is address and index 4 is the uint256
So what logic is there to know that the array in index 2 is pulled from the two addresses at the end of the input from the transaction.
I am trying not to need the ABI to decode the input like this if that is possible
I know I can split up the input from the transaction like this:
[ '000000000000000000000000000000000000000000000001885c663d0035bce2', '00000000000000000000000000000000000000000000000000f5666f7fdaa626', '00000000000000000000000000000000000000000000000000000000000000a0', '000000000000000000000000c0be713b48822271b362e9fac00479f5134172e8', '0000000000000000000000000000000000000000000000000000000060e93fa9', '0000000000000000000000000000000000000000000000000000000000000002', '0000000000000000000000009813037ee2218799597d83d4a5b6f3b6778218d9', '000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2' ]
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?
Is this where the abi comes in useful like decoding using web3? Or is this possible to decode without the abi?
Upvotes: 5
Views: 8763
Reputation: 43521
is it possible to decode without the ABI?
Only if you have at least the function signature or definition.
If you didn't know what input types there are, you wouldn't be able to tell whether this input
00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003666f6f0000000000000000000000000000000000000000000000000000000000
is a string foo
or three consecutive unsigned integers (decimal values):
32
3
46332796673528066027243215619882264990369332300865266851730502456685210107904
An easy way (without the actual ABI JSON) if you know the input datatypes, is to use the web3 decodeParameters function.
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
}
The values are already encoded to their respective datatypes - so for example integers are decimal (and not hex as in your question). They are returned as strings simply because JS can sometimes run into rounding errors when working with large integers.
Mind that the first 4 bytes (8 hex characters; in your case 18cbafe5
) is the function selector - not the parameter value. So you don't pass it to the decodeParameters()
function.
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?
That's how the ABI works. If you have a dynamic type, its actual slot contains the offset pointing to the actual location of the values (including the prepended length). In your case that's 160 (hexa0
) bytes.
All dynamic values are ordered at the end of the payload, prepended by a length of the section.
In your case, the 2
states that there are 2 values in this array, and the rest are the actual values of the array.
You can find more info about the ordering in the docs: https://docs.soliditylang.org/en/v0.8.7/abi-spec.html#formal-specification-of-the-encoding
Upvotes: 6