Hello!
could I copy the function body of supportsERC165InterfaceUnchecked and adapt it in order to call another external function returning a single boolean type argument? I.e. I want to modify staticall
to use a different function selector, and I'm expecting a true or false boolean result in the decoded data.
Thank you in advance,
Cosimo
You would have to modify:
bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId);
With both your function selector & the correct parameters instead of the interfaceId.
The function does expect a boolean as the return value from the function you call, not 100% sure how it handles a revert, but just test that to make sure 
1 Like
Thanks again, just making sure there was nothing else to change besides the new function selector and parameters, I'm also expecting boolean to be returned
I'll test for reverts.
All the best
I've tested it, here is my implementation
function _staticcallUnchecked(bytes memory encodedParams, address account)
private
view
returns (bool)
{
/**
* perform static call
* `staticcall(g, a, in, insize, out, outsize)` identical to `call(g, a, 0, in, insize, out, outsize)` but do not allow state modifications.
* call contract at address a with input mem[in…(in+insize)) providing g gas and v wei and output area mem[out…(out+outsize)) returning 0 on error (eg. out of gas) and 1 on success
* - https://docs.soliditylang.org/en/latest/yul.html#yul-call-return-area
*/
bool success;
uint256 returnSize;
uint256 returnValue;
assembly {
success := staticcall(
30000, // gas
account, // address
add(encodedParams, 0x20), // encoded encodedParams input and offset indicating at which bytes index the string starts. Here 0x20 (in hex) = 32 (in decimals). add(encodedParams, 32) it moves the pointer to the raw encodedParams skipping the size field.
mload(encodedParams), // input size. mload(encodedParams) read 32 bytes pointed by encodedParams (it returns the length of encodedParams)
0x00, // output
0x20 // output size
)
// Setting output and output size to 0 is due to historical reason. In early EVM versions you had to know the output size in advance, it was a limiting factor for some kind of operations (proxy contracts) so in the Bizantium fork new opcodes were introduced ReturnDataSize and ReturnDataCopy. This allow the caller to determine the output size after the call (ReturnDataSize) and allowing copying to memory (ReturnDataCopy).
returnSize := returndatasize() // how much memory do we need to allocate for the response
returnValue := mload(0x00)
}
return success && returnSize >= 0x20 && returnValue > 0;
}
It is called like in this example:
_staticcallUnchecked(
abi.encodeWithSelector(0xf6a3d24e, _collection), // function selector: 0xf6a3d24e or bytes4(keccak256("exists(address)"));
_collectionsWhitelist[i]
)
It only returns true if both the call succeed AND if the returned boolean is true, it doesn't revert otherwise if the call fails.
In my case I did not need to require that the call succeeded as the resulting bool is wrapped in an if check.