Implementación de Contratos Inteligentes en Solidity: Funciones y Modificadores

Clase 13 de 21Curso de Introducción a Celo con Solidity

Resumen

¿Cómo estructurar un contrato inteligente elegante y funcional?

Crear un contrato inteligente efectivo no se trata solo de escribir código que funcione, sino de hacerlo de una manera que sea fácilmente entendible y mantenible. A lo largo de este proceso, se busca implementar funciones cruciales como el registro del creador, la retirada de ganancias por parte del vendedor, y todo ello con estilo. Utilizando Remix como entorno de desarrollo, es posible alcanzar estos objetivos manteniendo el orden y la claridad en el código.

¿Cuál es la función del constructor en un contrato inteligente?

En el lenguaje Solidity, el constructor se encarga de establecer las bases del contrato al recibir parámetros necesarios durante la creación de la instancia. En el ejemplo proporcionado, el constructor recibe:

  • Direcciones del comprador y del vendedor.
  • Monto del pago.
  • Dirección del árbitro para resolver disputas.

El constructor asigna estos valores a las variables pertinentes, iniciando también variables de control como depósito listo y pago listo, ambas establecidas inicialmente como false.

¿Cómo se implementa la función de depósito de pago?

La función depositarPago habilita al comprador a realizar un depósito por el monto acordado. Para garantizar la seguridad y precisión, se considera:

  1. Uso del modificador payable para habilitar pagos en la criptomoneda Zerogold.
  2. Verificación del remitente del mensaje como el comprador.
  3. Comprobación que el monto proporcionado coincida con el monto establecido inicialmente.

Al cumplir con estas verificaciones, se actualiza la variable depósito listo a true.

function depositarPago() public payable {
    require(msg.sender == comprador, "Solo el comprador puede depositar.");
    require(msg.value == montoPago, "El monto del pago es incorrecto.");
    depositoListo = true;
}

¿Cómo se confirma la recepción del comprador?

La función compradorConfirmaOK es crucial para completar el flujo de pago. Una vez el comprador recibe el producto conforme, se habilita al vendedor a retirar el depósito. Aquí se verifica que sea el comprador quien realiza la confirmación, y posteriormente, se establece la variable compradorOK en true.

¿En qué consiste la función de retirada de pagos?

La función retirarPago permite al vendedor recibir los fondos una vez el comprador lo confirma. Antes de la transacción, se asegura que la confirmación del comprador fue realizada. Luego, se transforma la dirección del vendedor a una dirección payable para permitir la transferencia del pago. La variable pago listo se actualiza a true al completarse el proceso.

function retirarPago() public {
    require(compradorOK, "El comprador aun no confirma la recepcion.");
    vendedor.transfer(montoPago);
    pagoListo = true;
}

¿Qué papel desempeña el árbitro en el contrato?

En situaciones de disputa, el árbitro actúa como mediador. La función pagarPorÁrbitro permite que el árbitro intervenga y resuelva el desacuerdo entre las partes, solicitando evidencia antes de decidir. Solo el árbitro tiene permiso para ejecutar esta función, asegurando la neutralidad del proceso.

function pagarPorÁrbitro() public {
    require(msg.sender == arbitro, "Solo el arbitro puede ejecutar.");
    retirarPago();
}

¿Cómo mejorar la legibilidad del código?

Una de las mejores prácticas en programación es usar modificadores para evitar la redundancia. Implementar un modificador como onlyComprador centraliza la verificación del remitente, simplificando el código y facilitando su lectura y mantenimiento.

modifier onlyComprador() {
    require(msg.sender == comprador, "Acceso denegado a no compradores.");
    _;
}

function depositarPago() public payable onlyComprador {
    require(msg.value == montoPago, "El monto del pago es incorrecto.");
    depositoListo = true;
}

¿Cómo se integra el patrón Ownable en el contrato?

El patrón Ownable de OpenZeppelin introduce un propietario del contrato, que en este caso se asigna al árbitro. Esto reduce la cantidad de variables y simplifica la lógica al eliminar referencias redundantes al árbitro, especificando directamente el propietario como la única entidad con permiso para tomar decisiones clave en el contrato.

Con la incorporación de tales prácticas, se logra un contrato inteligente que no solo satisface las necesidades inmediatas sino que está preparado para ser escalado, ajustado y mantenido en el tiempo.