Inicio / Blockchain / Blockchain: De Cero a Desarrollador / Solidity: Fundamentos

Solidity: Fundamentos

Tipos, funciones, visibilidad, modifiers, eventos y errores.

Intermedio Funciones
🔒 Solo lectura
📖

Estás en modo lectura

Puedes leer toda la lección, pero para marcar progreso, hacer ejercicios y ganar XP necesitas una cuenta Pro.

Desbloquear por $9/mes

Solidity: Fundamentos

Solidity es el lenguaje de programación principal para escribir smart contracts en Ethereum y blockchains compatibles con la EVM. Es un lenguaje de alto nivel, tipado estáticamente, influenciado por JavaScript, Python y C++.

Primer Smart Contract

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract HolaMundo {
    string public saludo = "Hola, Blockchain!";

    function setSaludo(string memory _nuevoSaludo) public {
        saludo = _nuevoSaludo;
    }

    function getSaludo() public view returns (string memory) {
        return saludo;
    }
}

Desglose

SPDX-License-Identifier → Licencia del código (obligatorio)
pragma solidity ^0.8.20  → Versión del compilador
contract                 → Similar a class en otros lenguajes
public                   → Visibilidad (accesible externamente)
string memory            → Tipo + ubicación de datos
view                     → No modifica el estado
returns                  → Tipo de retorno

Tipos de Datos

Tipos por valor

contract TiposDeDatos {
    // Enteros
    uint256 public enteroPositivo = 42;      // 0 a 2²⁵⁶-1
    int256 public enteroConSigno = -42;       // -2²⁵⁵ a 2²⁵⁵-1
    uint8 public enteroPequeno = 255;         // 0 a 255

    // Booleanos
    bool public activo = true;

    // Direcciones
    address public owner = 0x742d35Cc6634C0532925a3b844Bc9e7595f2bD09;
    address payable public receptor; // puede recibir ETH

    // Bytes
    bytes32 public hash;            // Tamaño fijo
    bytes public dataDinamica;      // Tamaño variable

    // Enums
    enum Estado { Activo, Pausado, Cancelado }
    Estado public estado = Estado.Activo;
}

Tipos por referencia

contract TiposReferencia {
    // Arrays
    uint[] public numeros;           // Dinámico
    uint[5] public fijos;            // Fijo (5 elementos)

    // Mapping (diccionario)
    mapping(address => uint) public balances;
    mapping(address => mapping(address => uint)) public allowances;

    // Strings
    string public nombre = "Mi Contrato";

    // Structs
    struct Usuario {
        string nombre;
        uint edad;
        address wallet;
        bool activo;
    }

    Usuario[] public usuarios;
    mapping(address => Usuario) public usuarioPorAddress;
}

Variables Especiales

Solidity proporciona variables globales con información del contexto:

contract VariablesGlobales {
    function info() public view returns (
        address sender,
        uint valor,
        uint bloque,
        uint timestamp,
        uint gasRestante
    ) {
        sender      = msg.sender;        // Quien llama la función
        valor       = msg.value;         // ETH enviado (en Wei)
        bloque      = block.number;      // Número de bloque actual
        timestamp   = block.timestamp;   // Timestamp del bloque
        gasRestante = gasleft();         // Gas disponible
    }
}

Funciones

Visibilidad

contract Visibilidad {
    // public: accesible desde cualquier lugar
    function publica() public pure returns (string memory) {
        return "Cualquiera puede llamarme";
    }

    // external: solo desde fuera del contrato
    function externa() external pure returns (string memory) {
        return "Solo desde fuera";
    }

    // internal: solo este contrato y herederos
    function interna() internal pure returns (string memory) {
        return "Solo interna";
    }

    // private: solo este contrato
    function privada() private pure returns (string memory) {
        return "Solo este contrato";
    }
}

Modificadores de estado

contract ModificadoresEstado {
    uint public contador;

    // view: lee el estado pero no lo modifica
    function getContador() public view returns (uint) {
        return contador;
    }

    // pure: no lee ni modifica el estado
    function sumar(uint a, uint b) public pure returns (uint) {
        return a + b;
    }

    // payable: puede recibir ETH
    function depositar() public payable {
        // msg.value contiene el ETH enviado
    }

    // (sin modificador): puede leer y modificar el estado
    function incrementar() public {
        contador += 1;
    }
}

Constructor

contract MiContrato {
    address public owner;
    string public nombre;

    // Se ejecuta una sola vez al desplegar el contrato
    constructor(string memory _nombre) {
        owner = msg.sender;
        nombre = _nombre;
    }
}

Modificadores (Modifiers)

Los modifiers permiten reutilizar lógica de validación:

contract Modificadores {
    address public owner;

    constructor() {
        owner = msg.sender;
    }

    modifier soloOwner() {
        require(msg.sender == owner, "No eres el owner");
        _; // Placeholder para el cuerpo de la función
    }

    modifier costoMinimo(uint _cantidad) {
        require(msg.value >= _cantidad, "ETH insuficiente");
        _;
    }

    // Usar modificadores
    function retirar() public soloOwner {
        payable(owner).transfer(address(this).balance);
    }

    function comprar() public payable costoMinimo(0.01 ether) {
        // Solo se ejecuta si msg.value >= 0.01 ETH
    }
}

Eventos

Los eventos permiten registrar información en los logs de la blockchain (mucho más barato que el storage):

contract Eventos {
    event Transferencia(
        address indexed desde,
        address indexed hacia,
        uint cantidad
    );

    event NuevoUsuario(address indexed usuario, string nombre);

    mapping(address => uint) public balances;

    function transferir(address _a, uint _cantidad) public {
        balances[msg.sender] -= _cantidad;
        balances[_a] += _cantidad;

        emit Transferencia(msg.sender, _a, _cantidad);
    }
}

Los eventos indexed se pueden filtrar eficientemente desde aplicaciones frontend.

Manejo de Errores

contract Errores {
    // require: validación de inputs y condiciones
    function retirar(uint cantidad) public {
        require(cantidad > 0, "Cantidad debe ser mayor a 0");
        require(balances[msg.sender] >= cantidad, "Saldo insuficiente");
        // ...
    }

    // revert: similar a require, útil con lógica compleja
    function procesar(uint tipo) public {
        if (tipo == 0) {
            revert("Tipo invalido");
        }
    }

    // assert: verificar invariantes (nunca debería fallar)
    function dividir(uint a, uint b) public pure returns (uint) {
        assert(b != 0);
        return a / b;
    }

    // Custom errors (más eficientes en gas)
    error SaldoInsuficiente(uint disponible, uint requerido);

    mapping(address => uint) public balances;

    function retirarV2(uint cantidad) public {
        if (balances[msg.sender] < cantidad) {
            revert SaldoInsuficiente(balances[msg.sender], cantidad);
        }
    }
}

Resumen

Solidity es un lenguaje tipado y compilado diseñado para la EVM. Los tipos fundamentales incluyen uint, address, bool, mapping y struct. Las funciones tienen visibilidad (public, external, internal, private) y modificadores de estado (view, pure, payable). Los modifiers permiten reutilizar validaciones, los eventos registran logs eficientes, y el manejo de errores con require, revert y custom errors protege los contratos.

🔒

Ejercicio práctico disponible

Primer smart contract en Solidity

Desbloquear ejercicios
// Primer smart contract en Solidity
// Desbloquea Pro para acceder a este ejercicio
// y ganar +50 XP al completarlo

function ejemplo() {
    // Tu código aquí...
}

¿Te gustó esta lección?

Con Pro puedes marcar progreso, hacer ejercicios, tomar quizzes, ganar XP y obtener tu constancia.

Ver planes desde $9/mes