I'm trying to execute contract's function use abi encode and call
function, but I'm getting an error. Don't know how to resolve this issue.
pragma solidity >=0.8.0;
contract AbiTest {
event A(uint);
event Out(bytes);
function test() public {
bytes4 func = bytes4(keccak256("callMe(uint[])"));
uint[] memory arr = new uint[](3);
arr[0] = 3;
arr[1] = 4;
(bool res, bytes memory data) = address(this).call(abi.encode(func, arr));
emit Out(data);
require(res);
}
function callMe(uint[] memory array) public {
emit A(array[0]);
emit A(array[1]);
}
}
This solution works well, if arguments sizes are known at compile time, but with dynamic sizes this doesn't work.
How can I resolve it?
Need to use abi.encodePacked
see Solidity doc instead of abi.encode
because second one don't compress items and therefore uses 32 bytes for the function name.
pragma solidity >=0.8.0;
contract Abi2Test {
function getByte() public returns (bytes memory) {
bytes4 func = bytes4(keccak256("callMe(uint256[])"));
return abi.encode(func);
}
function getByte2() public returns (bytes memory) {
bytes4 func = bytes4(keccak256("callMe(uint256[])"));
return abi.encodePacked(func);
}
}
getByte
output: 0x6600981c00000000000000000000000000000000000000000000000000000000
getByte2
output: 0x6600981c
Therefore, when you use encode
with function signature additionally will be allocated 28 bytes and EVM can't correctly parse passed value.
So, to correctly call function with abi.encode
and abi.encodePacked
you need to pack arguments with encode at the first, and at the second group function's signature with encoded bytes.
pragma solidity >=0.8.0;
contract Abi2Test {
event A(uint256);
event Out(bytes);
event Out1(bytes);
function test() public {
bytes4 func = bytes4(keccak256("callMe(uint256[])"));
uint256[] memory arr = new uint256[](3);
arr[0] = 3;
arr[1] = 4;
(bool res, bytes memory data) = address(this).call(abi.encodePacked(func, abi.encode(arr)));
emit Out(data);
require(res);
}
function callMe(uint256[] memory array) public {
emit A(array.length);
emit Out1(msg.data);
}
}