En este tutorial vamos a ver qué son los evento en Solidity y cómo puedes usarlos para interactuar con otros sistemas o aplicaciones.
Contenidos
Qué es un evento
Los eventos te permiten enviar datos desde un Smart Contract a otros sistemas, como por ejemplo una interfaz web o una aplicación que ejecutes en tu teléfono.
Un ejemplo de esto podría ser el caso de un exchange descentralizado en donde se intercambian tokens en el ámbito del Smart Contract. Desde el propio contrato podrás emitir eventos para informar a la aplicación web3 o a la aplicación que muestra información acerca de las transacciones que se ejecutan en el exchange.
Es importante que sepas que la función de los eventos se limita a la interacción con sistemas externos a la blockchain, por lo que no podrás leer un evento en tu Smart Contract emitido desde tu Smart Contract o desde otro Smart Contract. Una vez emitas el evento, será imposible acceder a un evento ya emitido. Para este propósito es más apropiado el uso de una variable almacenada como storage
.
Sin embargo, el coste de GAS de emitir un evento es inferior al del uso de una variable definida como storage
. Si no necesitas acceder a un variable desde el Smart Contract en el futuro, entonces sí deberías usar un evento.
Cómo declarar un evento
Los contratos se declaran a nivel de contrato. Es decir, que tendrán que estar al mismo nivel que la declaración de una función. Se declaran usando la sentencia event
, tras la cual debes introducir el identificador del evento, que suele estar en camel case por convención. Tras el identificador del evento debes agregar entre paréntesis la declaración los campos que contendrá en el evento, separándolos por una coma. Tal y como puedes comprobar, los eventos también son datos estructurados.
Vamos a declarar un evento que sea capaz de enviar información acerca de las transacciones que se ejecuten. Para ello, en el siguiente ejemplo creamos un contrato al que llamaremos MiContrato
. En su interior definiremos el evento EventoTransferencia
:
pragma solidity ^0.8.13;
contract MiContrato
{
event EventoTransferencia (
uint fecha,
address remitente,
address destinatario,
uint cantidad
);
}
Tal y como ves, hemos declarado el campo fecha de tipo uint
, que aceptará el timestamp del momento en el que se ha ejecutado la transacción en el campo fecha
. También aceptará un emisor de tipo address
en el campo remitente
, un receptor en al campo destinatario
y la cantidad a enviar en el campo cantidad
.
Cómo emitir un evento
Para iniciar un evento necesitamos emitirlo mediante la sentencia emit
seguida del nombre de los argumentos que acepta el evento en el mismo orden en el que se han definido.
Continuando con nuestro ejemplo, vamos a crear una función, a la que llamaremos transferir
, que sea capaz de emitir el evento EventoTransferencia
. Esta función aceptará como argumentos la dirección del destinatario
y la cantidad
a enviar en la transferencia:
function transferir(address destinatario, uint cantidad) external
{
emit EventoTransferencia(block.timestamp, msg.sender, destinatario, cantidad);
}
Para consumir este evento necesitaremos usar una librería web3 en nuestra aplicación. En dicha aplicación recibiremos el evento, pudiéndolo consumir e iniciar las operaciones pertinentes.
Por si te encuentras con código antiguo de Solidity, decir que antes la versión de 0.5 no Solidity era necesario usar la sentencia emit
a la hora de emitir un evento, sino que bastaba con usar el nombre del evento directamente.
Cómo indexar un evento
Por ahora hemos definido el evento y hemos visto cómo emitirlo, aunque todavía tenemos que ver cómo indexarlo. Los índices permiten que las aplicaciones externas que consumen el evento obtengan información acerca de los mismos. Podría haber miles de eventos emitidos desde un único Smart Contract, pero quizás solamente nos interese que los usuarios reciban los eventos que hagan referencia a las operaciones relacionadas con ellos.
Por ejemplo, en nuestro Smart Contract se podrían realizar cientos de miles de transferencias. Sin embargo, no sería óptimo que obtuvieses información actualizada acerca de todos ellos, sino únicamente de aquellos que afectan a la dirección de tu wallet. Para poder filtrar los eventos necesitaremos usar sentencia indexed
a la hora de definir el evento.
Actualizando nuestro ejemplo, vamos a modificar la declaración del contrato agregando un índice a la dirección del remitente:
pragma solidity ^0.8.13;
contract MiContrato
{
event EventoTransferencia (
uint fecha,
address indexed remitente,
address destinatario,
uint cantidad
);
}
Seguramente estés pensando que no estaría mal que todos los campos pudiesen ser índices. Sin embargo, has de saber que el mantenimiento de los índices suponen mucha carga de trabajo para la blockchain, por lo que no se permiten más de tres índices por evento.
Este sería el código completo de nuestro Smart Contract:
pragma solidity ^0.8.13;
contract MiContrato
{
event EventoTransferencia (
uint indexed fecha,
address indexed remitente,
address indexed destinatario,
uint cantidad
);
function transferir(address destinatario, uint cantidad) external
{
emit EventoTransferencia(block.timestamp, msg.sender, destinatario, cantidad);
}
}
Esto ha sido todo.