I have a function with a parameter of bytes calldata that needs to be decoded to a struct, but the call reverts in assembly. I believe the issue has something to do with the nested array. I have used a similiar technique with only a 1-dimensional array and it seems to work OK.
struct InputParams {
address[] exchangeAddresses;
address[][] exchangePoolOrPaths;
address[] tokenAddresses;
uint256 tokenStartAmount;
uint256[] tokenAmountsExpected;
}
function execute(uint blockNumber, bytes calldata data, bool admin) external
{
InputParams memory params = abi.decode(data, (InputParams)); // this reverts in assembly
}
Inspecting the raw input to transacting with this function does not provide much info. I parsed out below the separate parameters and they seem to be encoded OK:
0xb83775a0 // function signature
0000000000000000000000000000000000000000000000000000000000000000 // parameter "blockNumber" == 0
0000000000000000000000000000000000000000000000000000000000000060 // parameter bytes calldata "data" offset value
0000000000000000000000000000000000000000000000000000000000000001 // parameter "admin" == 1
00000000000000000000000000000000000000000000000000000000000002c0 // struct InputParams length
00000000000000000000000000000000000000000000000000000000000000a0 // offset of exchangeAddresses[]
0000000000000000000000000000000000000000000000000000000000000100 // offset of exchangePoolOrPaths[][]
00000000000000000000000000000000000000000000000000000000000001e0 // offset of tokenAddresses[]
0000000000000000000000000000000000000000000000004563918244f40000 // value of tokenStartAmount
0000000000000000000000000000000000000000000000000000000000000260 // offset of tokenAmountsExpected[]
0000000000000000000000000000000000000000000000000000000000000002 // number of items in exchangeAddresses[]
0000000000000000000000001cb3aca0179bc96cd9612d6c27285b0458a2500f // value of exchangeAddresses[0]
00000000000000000000000080d73310b92da08b230adf441a6352e8f9631a77 // value of exchangeAddresses[1]
0000000000000000000000000000000000000000000000000000000000000002 // number of items in exchangePoolOrPaths[*][]
0000000000000000000000000000000000000000000000000000000000000040 // offset of array at exchangePoolOrPaths[0]
0000000000000000000000000000000000000000000000000000000000000080 // offset of array at exchangePoolOrPaths[1]
0000000000000000000000000000000000000000000000000000000000000001 // number of items in array at exchangePoolOrPaths[0]
000000000000000000000000b5ffd0a221fc94de9255382e70ce1aec76b68c89 // value of exchangePoolOrPaths[0][0]
0000000000000000000000000000000000000000000000000000000000000001 // number of items in array at exchangePoolOrPaths[1]
0000000000000000000000003b3d4eefdc603b232907a7f3d0ed1eea5c62b5f7 // value of exchangePoolOrPaths[1][0]
0000000000000000000000000000000000000000000000000000000000000003 // number of items in tokenAddresses[]
000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 // value of tokenAddresses[0]
0000000000000000000000000ae055097c6d159879521c384f1d2123d1f195e6 // value of tokenAddresses[1]
000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 // value of tokenAddresses[2]
0000000000000000000000000000000000000000000000000000000000000002 // number of items in tokenAmountsExpected[]
0000000000000000000000000000000000000000000000039fe550f187a54000 // value of tokenAmountsExpected[0]
0000000000000000000000000000000000000000000000004563918244f40000 // value of tokenAmountsExpected[1]
Does anyone have any idea what the problem could be here?
Edit:
I think I simplified the problem case. I think there's an issue with decode and dynamic arrays inside structs.
What works:
struct InputParams
{
address[2] exchangeAddresses;
}
function execute(uint blockNumber, bytes calldata data, bool admin) external
{
InputParams memory params = abi.decode(data, (InputParams));
}
with calldata:
0xb83775a0
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000060
0000000000000000000000000000000000000000000000000000000000000001
0000000000000000000000000000000000000000000000000000000000000040
000000000000000000000000b5ffd0a221fc94de9255382e70ce1aec76b68c89
0000000000000000000000003b3d4eefdc603b232907a7f3d0ed1eea5c62b5f7
What does not work (reverts during decode):
struct InputParams
{
address[] exchangeAddresses;
}
function execute(uint blockNumber, bytes calldata data, bool admin) external
{
InputParams memory params = abi.decode(data, (InputParams));
}
with calldata:
0xb83775a0
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000060
0000000000000000000000000000000000000000000000000000000000000001
0000000000000000000000000000000000000000000000000000000000000080
0000000000000000000000000000000000000000000000000000000000000020
0000000000000000000000000000000000000000000000000000000000000002
000000000000000000000000b5ffd0a221fc94de9255382e70ce1aec76b68c89
0000000000000000000000003b3d4eefdc603b232907a7f3d0ed1eea5c62b5f7
Does anyone have any ideas or if I am actually just passing incorrect calldata…
Best Answer
Issue resolved here: https://github.com/ethereum/solidity/issues/9747#issuecomment-687833241
The input calldata was incorrect