External Calls
STATICCALL
contract SolidityContract {
// "9a884bde": "get21()" - function signature
function get21() external pure returns (uint256) {
return 21;
}
} In Yul, we have to load the function selector into memory, then point to the region that will be part of our abi call, i.e. bytes 28 to 32 which contain the function signature
function externalViewCallNoArgs(address _a)
external
view
returns (uint256)
{
assembly {
mstore(0x00, 0x9a884bde)
// 000000000000000000000000000000000000000000000000000000009a884bde
// | |
// 28 32
let success := staticcall(gas(), _a, 28, 32, 0x00, 0x20)
if iszero(success) {
revert(0, 0)
}
return(0x00, 0x20)
}
}Opcodes for making external calls:
staticcall,call, anddelegatecallIf we are inside of a view function, we have to use
staticcall, because static calls do not change state. if state is being changed, the call will revertThe compiler will not allow us to use
callwithin a view function, since the function is not supposed to modify stateBreakdown of arguments in
staticcall:gas()- amount of remaining gas the contract has left. can be hardcoded to a smaller amount, can be used if we don’t trust the receiving contract, since it may attempt to consume all the gas in a DoS attack_a- address of the contract we are calling28, 32- intended[tx.data](<http://tx.data>), which is what we have loaded into memory0x00, 0x20- region in memory that we are going to copy the results back into. so when the function returns, it will override the function selector in 0x00, but it does not matter since we don’t need this info any more
Getting return values from a revert call in Yul
when a function reverts, it will still return the revert values to the same location that we assigned to it, in this case 0x00 - 0x20
Calling a function that includes arguments
since the arguments take up more than 64 bytes, we cant put it in scratch space
have to store the function arguments into locations in memory with
mstore
CALL
Difference from
staticcallis the addition of acallvalue()variable, which is used to forward the ETH received as part of the transaction (msg.value)If a function is not payable,
callvalue()can just be set to 0
Unknown return size
in some situations, we don’t know what the size of the return value will be
if the function returns some unknown data size, e.g. a string or an array, we use
returndatasize()to obtain the return data size, and ignore the allocated positions in staticcall
returndatacopywill copy the return value into a location in memory: in this case, copy into slot 0, the data at 0, up to the total size of the return data
DELEGATECALL
Openzeppelin implementation of delegatecall
Last updated