Contenido del curso
Desarrolla el contrato inteligente de un juego
- 4

Diseño de contrato Tic Tac Toe en Solidity
17:36 min - 5

Programación de un contrato inteligente para tic-tac-toe en Solidity
18:57 min - 6

Guardando movimientos y detectando ganador en Solidity
19:48 min - 7

Implementación de NFTs en Contratos de Tic-Tac-Toe con Solidity
18:58 min - 8

Emitir tokens ERC-20 al ganar partidas
07:24 min
Ampliado las capacidades del contrato
Revisando la seguridad del contrato
Continúa desarrollando contratos inteligentes
Estructura de un smart contract en Solidity
Resumen
Aprender a estructurar un smart contract en Solidity es la diferencia entre escribir código que compila y construir contratos legibles, mantenibles y seguros. Si ya escribiste tus primeras líneas en Remix, este recorrido te muestra cómo pasar de un requisito funcional a un contrato bien organizado, usando como ejemplo un contador de visitas con permisos para el implementador.
Qué componentes debe tener un smart contract bien estructurado
Un contrato en Solidity se sostiene sobre piezas que cumplen funciones específicas y conviene escribirlas siempre en el mismo orden.
- Licencia: declara si tu código es open source y bajo qué términos puede compartirse, reutilizarse o atribuirse.
- Imports: referencias a contratos o librerías externas que tu código necesita.
- Nombre del contrato: debe ser descriptivo para entender de un vistazo qué hace.
- Variables o atributos: representan el estado del contrato, la información que se almacena y que los usuarios podrán leer o modificar.
- Constructor: función que se ejecuta una sola vez al desplegar el contrato y suele inicializar valores.
- Funciones: agregan lógica y comportamiento, ya sea para modificar valores o realizar cálculos.
- Modifiers: funciones especiales que añaden validaciones o reglas a otras funciones mediante una palabra clave.
¿Qué es un modifier en Solidity? Es una función reutilizable que añade validaciones a otras funciones. Se conecta con un underscore que indica dónde se ejecuta el código original, antes o después de la validación.
Cómo declarar la licencia y la versión del compilador
La primera línea de tu contrato es un comentario con la licencia [0:55]. Aunque es opcional, si la omites el compilador lanzará un warning, y conviene evitar advertencias al escribir contratos. Puedes elegir entre licencias como GPL o MIT, o trabajar sin licencia si tu código no será compartido.
Después viene la directiva pragma, que define la versión de Solidity. Puedes apuntar a una versión específica o a un rango. Lo recomendable es un rango acotado, idealmente de no más de dos versiones, porque rangos amplios generan problemas de incompatibilidad. Tampoco es buena idea apuntar siempre a la última versión publicada.
solidity // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.0 <0.9.0;
Cómo definir el nombre, las variables y el constructor
El nombre del contrato se declara con la palabra reservada contract, similar a una clase en lenguajes orientados a objetos [3:30]. Si tu código es para práctica, puedes nombrarlo en español; si lo publicarás en un repositorio, mejor en inglés.
Para el contador de visitas necesitas una variable de tipo unsigned integer llamada visitas, ya que las visitas nunca son negativas. Pero hay un detalle: el contador puede no empezar en cero. Quizá ya hubo cinco visitas previas que deben quedar registradas. Ahí entra el constructor.
solidity contract ContadorDeVisitas { uint public visitas; address implementador;
constructor(uint _valorInicial) { visitas = _valorInicial; implementador = msg.sender; }
}
El constructor recibe el valor inicial como parámetro y guarda también la dirección de quien despliega el contrato usando msg.sender, que representa la cuenta que ejecuta la transacción en ese momento.
¿Qué hace msg.sender en un constructor? Captura la dirección de la cuenta que está desplegando el contrato y permite guardarla para validaciones futuras, como restringir funciones al implementador.
Cómo escribir funciones con visibilidad correcta
Las funciones aportan la lógica. En este caso, una función llamada incrementarVisitas cumple un único propósito y su nombre lo deja claro sin leer el código. Debes definir su visibilidad: si solo se usará dentro del contrato, será interna; si se llamará desde fuera, debe ser public.
Como el dueño del contrato necesita invocarla externamente, la declaras pública y, en este caso, no retorna valor.
Cómo agregar validaciones con modifiers
El requisito indica que solo el implementador puede incrementar el contador. Para eso creas un modifier llamado implementador que valida que msg.sender coincida con la dirección guardada al desplegar.
solidity modifier soloImplementador() { require(msg.sender == implementador, "La cuenta no implemento el contrato"); _; }
function incrementarVisitas() public soloImplementador { visitas++; }
El underscore al final indica que primero corre la validación y luego el código de la función. Incluir un mensaje de error en require es una buena práctica porque comunica con claridad qué falló.
Cómo compilar, desplegar y ajustar el contrato en Remix
En Remix, la pestaña con el ícono de Solidity te permite compilar [10:30]. Una palomita verde indica compilación exitosa. Para desplegar, usa la pestaña con el ícono y la flecha, eligiendo la Remix VM como red de pruebas, ideal para iterar rápido sobre código recién escrito.
Al ejecutar el despliegue debes pasar el valor inicial. Una vez desplegado notarás algo: el contador incrementa, pero no tienes forma de leer su valor actual porque la variable es internal por defecto.
Tienes dos opciones para resolverlo:
- Hacer la variable
public, lo que genera automáticamente una función de acceso. - Crear una función específica si quieres añadir lógica al acceso.
Marcar una variable como pública no significa permitir su modificación abierta, solo expone su lectura. Tras redeployar verás un botón que muestra el número de visitas y podrás confirmar que incrementa correctamente, por ejemplo de 12 a 13.
Por qué seguir una estructura facilita el mantenimiento
Esta estructura no es obligatoria, el compilador no te la exige, pero ordenar tu código por secciones, variables, constructor, modifiers y funciones, te permite ubicar cambios al instante. Si surge un nuevo requisito sobre una validación, sabes que vas a los modifiers; si es sobre el estado, vas a las variables.
Puedes llevarlo aún más lejos agrupando funciones por visibilidad: todas las públicas juntas, luego las privadas, luego las internas. En proyectos reales los requisitos cambian sobre la marcha, y un contrato bien estructurado convierte esos cambios en ediciones puntuales en lugar de reescrituras.
¿Cómo organizas tú tus contratos cuando arrancas un proyecto nuevo? Cuéntame en los comentarios qué estructura te ha funcionado mejor.