Using .staticcall(...) is allowed in view functions, but adding a gas restriction .staticcall.gas(n)(...) makes it disallowed in a view function.
The following doesn't compile unless you remove .gas(30000).
pragma solidity ^0.5.0;
contract Test {
function test(address target) external view returns (bool status) {
(status, ) = target.staticcall.gas(30000)("");
}
}
Error:
TypeError: Function declared as view, but this expression (potentially)
modifies the state and thus requires non-payable (the default) or payable.
(status, ) = target.staticcall.gas(30000)("");
Since .gas() only restricts the amount sent I agree that it should work in view functions.
The following code can be used as a template for an assembly-based workaround to this issue (assuming an uint256 return value):
bytes memory rawTx = abi.encodeWithSelector(selector, <data>);
(bool success, uint256 result) = staticCallWithMaxGas(address(to), maxGas, rawTx);
function staticCallWithMaxGas(address to, uint256 maxGas, bytes memory data) private view returns (bool, uint256) {
bool success;
uint256 result;
assembly {
let dataPtr := add(data, 0x20)
let dataSize := mload(data)
// The 32-byte result is placed memory position 0 (scratch space)
success := staticcall(maxGas, to, dataPtr, dataSize, 0, 32)
result := mload(0)
}
return (success, result);
}