Al darle la responsabilidad de ejecutar ciertas tareas en un contrato inteligente a un reducido grupo de usuarios, podemos caer en problemas de centralización del mismo. Una buena práctica para remediar esto, es colocando un retraso en la ejecución de la acción.
Demoras en la ejecución de una tarea
OpenZeppelin implementa un contrato inteligente llamado TimelockController que permite establecer una demora antes de la ejecución de una tarea.
Supongamos que en un contrato inteligente que emite tokens, sus administradores deciden aumentar la emisión de los mismos. Esto podría llevar a que el precio de los tokens baje considerablemente. Sería oportuno darles 48 o 72 horas a sus usuarios para que decidan retirar sus fondos o continuar participando del proyecto.
Implementación de TimelockController
TimelockController, a su vez, hereda del contrato AccessControl para que el mismo sea administrado por diferentes roles de usuarios.
bytes32 public constant TIMELOCK_ADMIN_ROLE =keccak256("TIMELOCK_ADMIN_ROLE");bytes32 public constant PROPOSER_ROLE =keccak256("PROPOSER_ROLE");bytes32 public constant EXECUTOR_ROLE =keccak256("EXECUTOR_ROLE");bytes32 public constant CANCELLER_ROLE =keccak256("CANCELLER_ROLE");
Es contrato tiene roles variados, desde sus administradores, los usuarios que proponen los cambios, los que ejecutan las tareas y los que cancelan las mismas. Pudiendo ser, una misma cuenta, responsable de todas las operaciones.
Por otro lado, para el despliegue de este contrato se requiere definir tanto el tiempo de espera como los responsables de proponer y ejecutar las tareas.
Además de disponer de una serie de eventos para notificar a los usuarios de una nueva propuesta o de la pronta ejecución de una tarea que puede provocar cambios en el contrato.
Es importante que los usuarios del contrato sepan de cuánto tiempo disponen para tomar una decisión. Tal vez no sea aconsejable otorgar escasos minutos. La comunicación con los mismos enviando notificaciones o en redes sociales es de vital importancia para mantener su confianza.
Es un contrato que puede causar problemas o malos entendidos con la comunidad que participa del proyecto, es crucial la notificación a los usuarios de cualquier cambio trascendental en el contrato.
Conclusión
Este tipo de contratos pueden caer fácilmente en problemas de centralización. Su utilización está limitada a casos de uso con buenos motivos para ser implementada una funcionalidad como tal.
Es importante conocer conceptualmente todo lo que pude desarrollarse en un contrato inteligente para proponerlo y/o implementarlo llegada la necesidad en un proyecto.
Estuve probando como implementar las capacidades que tiene el TimelockController. Logré entenderlo usando Remix y luego intenté implementarlo incluyendo pruebas en hardhat. Esto último aún sigo tratando de correr el execute. Pero igual les dejo el contrato de ejemplo y las pruebas unitarias:
al deployar el contrato se debe pasar arrays vacios para los proposers y los executers
importante asignar al menos un proposer y un executor
algunos de los parametros son de tipo 32bytes, por lo que implica una conversion
el argumento data es un calldata (callback), que se refiere al metodo a invocar lo que implica aplicarle un abiEncoding
el delay es obligatorio y debe ser mayor o igual al minDelay
el operationId se puede sacar invocando el hashOperation, aunque tambien se puede obtener de la respuesta
la operation no se ejecuta sola al cumplirse el tiempo, sino que pasa a un estado Ready y entonces es que está disponible para que el Executor lo ejecute.
Cuando lean la documentacion del TimelockController, lleguen hasta final donde explican los principales atributos y el ciclo de vida
muy buen resumen, gracias por compartir!
gracias!!
El contrato de TimelockController parece haber sido ampliado. Ahora incluye un nuevo rol llamado CANCELLER_ROLE y hereda interfaces del estandar ERC721 y ERC1155 para recibir este tipo de tokens.