
Fallback function: Capturando llamadas perdidas
En Solidity, la función fallback es una función especial que permite a los contratos manejar situaciones en las que se reciben llamadas inesperadas o Ether sin datos asociados. Esta función actúa como una especie de “captura todo” para interacciones no previstas con el contrato.
Definición y Propósito
La función fallback es una función sin nombre que se declara de la siguiente manera:
fallback() external payable {
// Lógica de la función
}
Esta función se ejecuta en dos escenarios principales:
-
Llamadas a funciones inexistentes: Cuando una llamada al contrato no coincide con ninguna de las funciones definidas.
-
Recepción de Ether sin datos: Si el contrato recibe Ether sin datos y no tiene definida una función
receive
, se invoca la función fallback.
Diferencia entre receive
y fallback
Desde Solidity 0.6.0, se introdujo la función receive
para manejar específicamente la recepción de Ether sin datos:
receive() external payable {
// Lógica para recibir Ether
}
La diferencia clave es que la función receive
se ejecuta únicamente cuando se envía Ether sin datos al contrato. Por otro lado, la función fallback se ejecuta cuando no hay coincidencia con ninguna función existente o cuando se envía Ether con datos que no coinciden con ninguna función.
Los proxies y la función fallback
La aplicación más utilizada de la función fallback es en los contratos proxy.
Estos contratos sirven como intermediarios entre los usuarios y la lógica de negocio de otro contrato (el contrato de implementación).
Para lograr esto, los proxies utilizan la función fallback para redirigir llamadas desconocidas a la dirección de la implementación mediante la instrucción
delegatecall
.
Esto permite que la lógica de negocio pueda actualizarse sin cambiar la dirección del contrato con el que interactúan los usuarios.
Consideraciones Importantes
-
Gas Limitado: En la mayoría de los casos, las llamadas que activan la función fallback reciben un límite de gas bajo (generalmente 2300 unidades de gas), como cuando son activadas por
transfer
osend
. Sin embargo, cuando se ejecuta mediantecall
odelegatecall
, el gas disponible no está restringido, lo que permite realizar operaciones complejas, como en los contratos proxy. -
Seguridad: Es recomendable implementar medidas de seguridad dentro de la función fallback para prevenir comportamientos inesperados o ataques, como los de reentrada. Por ejemplo, si no se desea que el contrato reciba Ether directamente, se puede hacer que la función fallback revierta la transacción:
fallback() external {
revert("El contrato no acepta Ether directamente");
}
Ejemplo Práctico
A continuación, un ejemplo de un contrato que utiliza tanto la función receive
como la función fallback:
contract EjemploFallback {
event LogFallback(address sender, uint amount, bytes data);
event LogReceive(address sender, uint amount);
// Función que se ejecuta al recibir Ether sin datos
receive() external payable {
emit LogReceive(msg.sender, msg.value);
}
// Función que se ejecuta al recibir llamadas
// que no coinciden con ninguna función
fallback() external payable {
emit LogFallback(msg.sender, msg.value, msg.data);
}
}
En este contrato, la función receive
se ejecuta cuando se envía Ether sin datos, mientras que la función fallback se activa para llamadas que no coinciden
con ninguna función definida o cuando se envía Ether con datos no reconocidos. Ambas funciones emiten eventos que registran la información de la transacción.