Staticcall es como una llamada regular de Ethereum, excepto que revierte si ocurre un cambio de estado. No se puede utilizar para transferir Ether. Tanto el opcode de la EVM, la función de ensamblador de Yul, como la función integrada de Solidity se llaman staticcall.
EIP 214
Staticcall fue introducido en el EIP 214 y añadido a Ethereum en 2017 como parte del Byzantium hard fork. Para las funciones en las que solo se desea un valor de retorno y no se quieren cambios de estado, añade una capa de seguridad. Staticcall revertirá si el contrato llamado provoca un cambio de estado, lo que incluye: registrar un evento, enviar Ether, crear un contrato, destruir un contrato o modificar una variable de almacenamiento. Leer una variable de almacenamiento está permitido. Una llamada que no transfiere Ether está permitida siempre que no resulte en un cambio de estado.
Funciones view
Solidity compila las funciones view que llaman a contratos externos para utilizar staticcall internamente.
Aquí hay un ejemplo mínimo:
contract ERC20User {
IERC20 public token;
// rest of the code
function myBalance() public view returns (uint256 balance) {
balance = token.balanceOf(address(this));
}
function myBalanceLowLevelEquivalent() public view returns (uint256 balance) {
(bool ok, bytes memory result) = token.staticcall(abi.encodeWithSignature("balanceOf(address)", address(this)));
require(ok);
balance = abi.decode(result, (uint256));
}
}
Si balanceOf cambia el estado, el código revertirá.
Meta Argumentos
La cantidad de gas enviada se puede especificar de la siguiente manera. La cantidad de gas reenviada está sujeta a la regla 63/64 descrita en el EIP 150.
staticcall{gas: gasAmount}(abiEncodedArguments);
Vectores de Ataque
Aunque staticcall es en cierto sentido “más seguro” que una llamada regular, eso no significa que se pueda descuidar la seguridad al usarlo.
Denegación de Servicio
Staticcall sigue estando sujeto a ataques de denegación de servicio mediante gas griefing. Considere la situación en la que el token ERC20 anterior pone un bucle infinito dentro de la función balanceOf. Al contrato que hace la llamada todavía le quedará gas, pero solo 1/64 de la cantidad original, según el EIP 150.
Reentrancia de solo lectura
Otro vector de ataque para el staticcall es obtener valores de retorno incorrectos. En el ataque de reentrancia de solo lectura, los valores del token se manipulan temporalmente con un flashloan, de modo que cualquier contrato inteligente que esté consultando los valores (a través de staticcall) podría ser hackeado mediante manipulación de oráculo.
Staticcall en ensamblador de Yul
En el ensamblador de Yul, los argumentos para staticcall son los siguientes:
let ok := staticcall(gas, addressToCall, in, insize, out, outsize)
Los argumentos out y outsize son la región de la memoria donde se copiará el valor de retorno. Sin embargo, ambos valores suelen establecerse en cero y, en su lugar, se utilizan “returndatacopy” y “returndatasize” para manejar de forma flexible los tamaños de retorno variables.
Estos opcodes se introdujeron en el EIP 211, eliminando la necesidad de predecir la longitud del valor de retorno proveniente del otro contrato inteligente.
Vea este ejemplo:
returndatacopy(0, 0, returndatasize())
Las variables in e insize apuntan a la región de la memoria donde se encuentra la parte de los datos (generalmente abi-encoded) de la llamada al contrato externo.
La variable ok devuelve true si el staticcall tiene éxito y false si revierte. Los reverts no se propagan hacia arriba.
Uso con contratos inteligentes precompilados
Staticcall es la forma adecuada de interactuar con los contratos precompilados de Ethereum (direcciones 0x01 a 0x09), ya que ninguno de ellos cambia el estado.
El siguiente ejemplo calculará el SHA256 de un uint. Tenga en cuenta que este precompilado hashea los datos directamente, y no debe ser abi-encoded.
function getSha256(uint256 x) public view returns (bytes32 hashOut) {
(bool ok, bytes memory result) = address(0x02).staticcall(abi.encode(x));
require(ok);
hashOut = abi.decode(result, (bytes32));
}
Más información
Consulte nuestro bootcamp para desarrolladores de Solidity experto para aprender conceptos más avanzados de desarrollo en Ethereum. También tenemos un curso gratuito de Solidity.
Publicado originalmente el 10 de abril de 2023