MultisigWallet.sol
Este contrato Multisig Wallet (MultisigWallet.sol) permite a múltiples propietarios aprobar y ejecutar transacciones. La seguridad se incrementa al requerir un número mínimo de confirmaciones antes de ejecutar una transacción, evitando que un solo punto de falla comprometa los fondos del contrato.
Licencia SPDX y versión de Solidity
Comenzamos con el identificador de licencia SPDX y la declaración de la versión de Solidity. Estos son requerimientos indispensables en todo contrato Solidity.
Declaración del contrato y variables de estado
Definimos el contrato MultisigWallet y las variables de estado principales: owners almacena las direcciones de los propietarios del contrato, y requiredConfirmations indica cuántas confirmaciones se necesitan para ejecutar una transacción.
Estructura de transacciones
Definimos la estructura Transaction, que representa una transacción propuesta. Incluye la dirección de destino (to), el valor en ETH (value), los datos de la llamada (data), si la transacción ha sido ejecutada (executed), y el número de confirmaciones recibidas (numConfirmations). También creamos el array transactions para almacenar todas las transacciones propuestas.
Constructor con validación
Añadimos un constructor que recibe la lista de propietarios y el número requerido de confirmaciones. Incluimos validaciones críticas: que no esté vacío, que el número de confirmaciones sea válido, que no haya propietarios duplicados y que ninguna dirección sea cero.
Mapping de propietarios
Añadimos el mapping isOwner que nos permite verificar rápidamente si una dirección es propietaria del contrato. Esto es esencial para las validaciones de acceso en las funciones del contrato.
Modificador de acceso
Creamos el modificador onlyOwner para restringir el acceso a ciertas funciones solo a los propietarios del contrato. Este modificador utiliza el mapping isOwner para verificar que el llamante sea un propietario válido.
Eventos
Definimos los eventos del contrato. Los eventos son fundamentales en Solidity porque permiten que aplicaciones externas escuchen y reaccionen a las acciones del contrato. Emitimos eventos cuando se envía, confirma, revoca o ejecuta una transacción, lo que proporciona trazabilidad completa de todas las operaciones.
Envío de transacciones
Añadimos la función submitTransaction, que permite a un propietario proponer una nueva transacción. La transacción se añade al array transactions con estado inicial executed = false y numConfirmations = 0. Emitimos el evento correspondiente.
Confirmación de transacciones con protección contra duplicados
Añadimos la función confirmTransaction, que permite a los propietarios confirmar una transacción. Incluimos dos validaciones importantes: que la transacción no haya sido ejecutada, y que el propietario no haya confirmado previamente (prevención de confirmaciones duplicadas). También creamos el mapping confirmations para rastrear qué propietarios han confirmado cada transacción.
Ejecución de transacciones
Añadimos la función executeTransaction, que permite ejecutar una transacción una vez que ha recibido el número necesario de confirmaciones. Esta función marca la transacción como ejecutada antes de realizar la llamada externa, siguiendo el patrón Checks-Effects-Interactions para prevenir ataques de reentrada. Utilizamos call para enviar ETH y ejecutar datos de contrato.
Revocación de confirmaciones
Añadimos la función revokeConfirmation, que permite a un propietario revocar su confirmación antes de que la transacción sea ejecutada. Esto aumenta la flexibilidad del sistema y permite correcciones en caso de errores.
Función receive para recibir ETH
Añadimos la función receive() para permitir que el contrato reciba ETH directamente. Sin esta función, las transferencias de ETH al contrato fallarían. Esto es esencial para que los propietarios puedan depositar fondos en la billetera multisig.
// SPDX-License-Identifier: MITpragma solidity ^0.8.29;
MultisigWallet.sol
Hemos completado el contrato MultisigWallet.sol. Este contrato permite la gestión segura de fondos a través de múltiples firmas, proporcionando un mayor control y seguridad en la ejecución de transacciones. Las mejoras principales incluyen: validaciones en el constructor (direcciones no nulas, propietarios únicos, número de confirmaciones válido), un modificador onlyOwner para control de acceso, prevención de confirmaciones duplicadas, eventos para trazabilidad, el patrón Checks-Effects-Interactions en la ejecución de transacciones (marcar como ejecutada antes de la llamada externa), y la función receive() para aceptar depósitos de ETH.