---
# System prepended metadata

title: GuiaSolidity

---

# Guía Completa de Solidity: Desde Básico hasta Transferencias de Ether

## 📚 Introducción

Bienvenido a esta guía completa de Solidity. Imagina que Solidity es como un lenguaje especial que utilizamos para escribir "contratos inteligentes" en la blockchain de Ethereum. Estos contratos son como pequeños programas que pueden manejar dinero digital (Ether) de forma automática y segura.

---

## 🏷️ 1. Tipos de Datos en Solidity

### ¿Qué son los tipos de datos?

Los tipos de datos son como "etiquetas" que le dicen a la computadora qué tipo de información estamos guardando. Es como organizar tu casa: tienes cajones para ropa, otros para documentos, y otros para herramientas.

### Tipos de Datos Básicos

#### 1.1 Números Enteros (uint, int)

```solidity
pragma solidity ^0.8.0;

contract EjemploTipos {
    // uint = números positivos solamente (0, 1, 2, 3...)
    uint256 public edad = 25;           // Puede almacenar números muy grandes
    uint8 public diasSemana = 7;        // Números pequeños (0-255)
    
    // int = números positivos y negativos (-3, -2, -1, 0, 1, 2, 3...)
    int256 public temperatura = -10;     // Puede ser negativo
    
    // Explicación: Es como tener diferentes tamaños de cajas
    // uint8 = caja pequeña (0-255)
    // uint256 = caja gigante (números enormes)
}
```

**Explicación simple:** Imagina que tienes diferentes tipos de contenedores para números. Algunos solo pueden guardar números positivos (uint), otros pueden guardar números negativos también (int).

#### 1.2 Texto (string)

```solidity
contract EjemploTexto {
    string public nombre = "Juan Pérez";
    string public mensaje = "Hola, mundo!";
    
    // Los strings son como notas escritas que puedes leer
    // Siempre van entre comillas
}
```

#### 1.3 Verdadero o Falso (bool)

```solidity
contract EjemploBooleano {
    bool public estaActivo = true;      // Verdadero
    bool public estaCompleto = false;   // Falso
    
    // Es como un interruptor de luz: encendido (true) o apagado (false)
}
```

#### 1.4 Direcciones (address)

```solidity
contract EjemploDireccion {
    address public propietario = 0x742d35Cc6634C0532925a3b8D6a3ca2F62fb5b7;
    
    // Una dirección es como la dirección de tu casa, pero para wallets
    // Cada persona tiene una dirección única en Ethereum
}
```

### Ejemplo Completo de Tipos de Datos

```solidity
pragma solidity ^0.8.0;

contract TiposDatos {
    // Números
    uint256 public precio = 100;        // Precio en wei (unidad más pequeña de Ether)
    int256 public balance = -50;        // Balance que puede ser negativo
    
    // Texto
    string public nombreProducto = "Café Premium";
    
    // Booleano
    bool public disponible = true;
    
    // Dirección
    address public vendedor = 0x742d35Cc6634C0532925a3b8D6a3ca2F62fb5b7;
    
    // Función para mostrar información
    function obtenerInfo() public view returns (string memory, uint256, bool) {
        return (nombreProducto, precio, disponible);
    }
}
```

---

## 🌍 2. Variables Globales

### ¿Qué son las variables globales?

Las variables globales son como información que está disponible en todo momento dentro de tu contrato. Es como tener un reloj en la pared que todos pueden ver desde cualquier parte de la casa.

### Variables Globales Más Importantes

```solidity
pragma solidity ^0.8.0;

contract VariablesGlobales {
    address public propietario;
    uint256 public tiempoCreacion;
    
    constructor() {
        propietario = msg.sender;      // Quien despliega el contrato
        tiempoCreacion = block.timestamp; // Momento actual
    }
    
    function informacionBloque() public view returns (
        address,    // Minero actual
        uint256,    // Número de bloque
        uint256,    // Timestamp
        uint256     // Difficulty
    ) {
        return (
            block.coinbase,     // Dirección del minero
            block.number,       // Número del bloque actual
            block.timestamp,    // Tiempo actual en segundos
            block.difficulty    // Dificultad de minado
        );
    }
    
    function informacionTransaccion() public payable returns (
        address,    // Quien envía la transacción
        uint256,    // Cuánto Ether envía
        uint256     // Gas usado
    ) {
        return (
            msg.sender,    // Tu dirección
            msg.value,     // Ether que enviaste
            gasleft()      // Gas restante
        );
    }
}
```

### Explicación Detallada de Variables Globales

#### msg.sender
```solidity
// msg.sender es como ver el nombre en el sobre de una carta
// Te dice quién está enviando la transacción
address public ultimoUsuario = msg.sender;
```

#### msg.value
```solidity
// msg.value te dice cuánto Ether envió la persona
// Es como contar el dinero en un sobre
uint256 public ultimoPago = msg.value;
```

#### block.timestamp
```solidity
// block.timestamp es como mirar el reloj
// Te dice la hora exacta en segundos
uint256 public momentoActual = block.timestamp;
```

---

## 🔧 3. Funciones en Solidity

### ¿Qué son las funciones?

Las funciones son como "recetas" o "instrucciones" que le dices a tu contrato que haga. Es como tener un robot que puede hacer diferentes tareas cuando se lo pides.

### Tipos de Funciones

#### 3.1 Funciones Básicas

```solidity
pragma solidity ^0.8.0;

contract EjemploFunciones {
    uint256 public numero = 0;
    string public mensaje = "Hola";
    
    // Función que NO cambia nada (view)
    // Es como "mirar" algo sin tocarlo
    function verNumero() public view returns (uint256) {
        return numero;
    }
    
    // Función que CAMBIA algo
    // Es como "modificar" algo
    function cambiarNumero(uint256 _nuevoNumero) public {
        numero = _nuevoNumero;
    }
    
    // Función que no lee ni cambia nada (pure)
    // Es como hacer una cuenta matemática
    function sumar(uint256 a, uint256 b) public pure returns (uint256) {
        return a + b;
    }
}
```

#### 3.2 Funciones con Modificadores de Acceso

```solidity
contract FuncionesAcceso {
    address public propietario;
    uint256 private dineroSecreto = 1000;
    
    constructor() {
        propietario = msg.sender;
    }
    
    // Solo el propietario puede usar esta función
    modifier soloPropiestario() {
        require(msg.sender == propietario, "No eres el propietario");
        _;
    }
    
    // Función pública - todos pueden usarla
    function funcionPublica() public view returns (string memory) {
        return "Cualquiera puede ver esto";
    }
    
    // Función privada - solo este contrato puede usarla
    function funcionPrivada() private view returns (uint256) {
        return dineroSecreto;
    }
    
    // Función con restricción
    function cambiarDineroSecreto(uint256 _nuevaCantidad) public soloPropiestario {
        dineroSecreto = _nuevaCantidad;
    }
}
```


---

## 💰 4. Transferencias de Ether

### ¿Qué es una transferencia de Ether?

Una transferencia de Ether es como enviar dinero digital de una persona a otra. Es como enviar dinero por transferencia bancaria, pero usando la blockchain.

### Métodos de Transferencia

#### 4.1 Transfer (Método Básico)

```solidity
pragma solidity ^0.8.0;

contract TransferBasico {
    address public propietario;
    
    constructor() {
        propietario = msg.sender;
    }
    
    // Función para enviar Ether usando transfer
    function enviarEtherTransfer(address payable _destinatario, uint256 _cantidad) public {
        require(msg.sender == propietario, "Solo el propietario puede enviar");
        require(address(this).balance >= _cantidad, "No hay suficiente Ether");
        
        // transfer automáticamente revierte si falla
        _destinatario.transfer(_cantidad);
    }
    
    // Función para ver el balance del contrato
    function verBalance() public view returns (uint256) {
        return address(this).balance;
    }
}
```

#### 4.2 Send (Método con Verificación Manual)

```solidity
contract TransferSend {
    address public propietario;
    
    constructor() {
        propietario = msg.sender;
    }
    
    function enviarEtherSend(address payable _destinatario, uint256 _cantidad) public returns (bool) {
        require(msg.sender == propietario, "Solo el propietario puede enviar");
        require(address(this).balance >= _cantidad, "No hay suficiente Ether");
        
        // send retorna true/false, necesitas verificar manualmente
        bool exito = _destinatario.send(_cantidad);
        require(exito, "Transferencia fallida");
        
        return exito;
    }
}
```

#### 4.3 Call (Método Moderno y Recomendado)

```solidity
contract TransferCall {
    address public propietario;
    
    constructor() {
        propietario = msg.sender;
    }
    
    function enviarEtherCall(address payable _destinatario, uint256 _cantidad) public {
        require(msg.sender == propietario, "Solo el propietario puede enviar");
        require(address(this).balance >= _cantidad, "No hay suficiente Ether");
        
        // call es el método más seguro y moderno
        (bool exito, ) = _destinatario.call{value: _cantidad}("");
        require(exito, "Transferencia fallida");
    }
}
```

### Ejemplo Práctico: Sistema de Pagos

```solidity
pragma solidity ^0.8.0;

contract SistemaPagos {
    address public propietario;
    uint256 public totalRecaudado;
    
    // Mapeo para rastrear pagos
    mapping(address => uint256) public pagosRealizados;
    
    // Eventos para registrar actividad
    event PagoRecibido(address from, uint256 amount);
    event PagoEnviado(address to, uint256 amount);
    
    constructor() {
        propietario = msg.sender;
        totalRecaudado = 0;
    }
    
    // Función para recibir pagos
    function realizarPago() public payable {
        require(msg.value > 0, "Debe enviar algo de Ether");
        
        pagosRealizados[msg.sender] += msg.value;
        totalRecaudado += msg.value;
        
        emit PagoRecibido(msg.sender, msg.value);
    }
    
    // Función para enviar dinero (solo propietario)
    function enviarPago(address payable _destinatario, uint256 _cantidad) public {
        require(msg.sender == propietario, "Solo el propietario puede enviar");
        require(address(this).balance >= _cantidad, "Balance insuficiente");
        require(_cantidad > 0, "La cantidad debe ser mayor a 0");
        
        (bool exito, ) = _destinatario.call{value: _cantidad}("");
        require(exito, "Transferencia fallida");
        
        emit PagoEnviado(_destinatario, _cantidad);
    }
    
    // Función para retirar todo (solo propietario)
    function retirarTodo() public {
        require(msg.sender == propietario, "Solo el propietario puede retirar");
        uint256 balance = address(this).balance;
        require(balance > 0, "No hay nada que retirar");
        
        (bool exito, ) = payable(propietario).call{value: balance}("");
        require(exito, "Retiro fallido");
    }
}
```

---

## 📨 5. Cómo Reciben Ether los Contratos

### ¿Cómo puede un contrato recibir Ether?

Un contrato puede recibir Ether de varias formas, como una caja que puede recibir dinero de diferentes maneras.

### 5.1 Función Payable

```solidity
pragma solidity ^0.8.0;

contract ReceptorEther {
    address public propietario;
    uint256 public totalRecibido;
    
    // Mapeo para rastrear quién envió cuánto
    mapping(address => uint256) public contribuciones;
    
    constructor() {
        propietario = msg.sender;
    }
    
    // Función que puede recibir Ether (payable)
    function depositar() public payable {
        require(msg.value > 0, "Debe enviar Ether");
        
        contribuciones[msg.sender] += msg.value;
        totalRecibido += msg.value;
    }
    
    // Función para depositar con mensaje
    function depositarConMensaje(string memory _mensaje) public payable {
        require(msg.value > 0, "Debe enviar Ether");
        
        contribuciones[msg.sender] += msg.value;
        totalRecibido += msg.value;
        
        // Aquí podrías guardar el mensaje si quisieras
        // Por simplicidad, solo lo recibimos
    }
}
```

### 5.2 Función Receive

```solidity
contract ReceptorAutomatico {
    address public propietario;
    uint256 public etherRecibido;
    
    constructor() {
        propietario = msg.sender;
    }
    
    // receive() se ejecuta cuando alguien envía Ether directamente al contrato
    // Es como tener un buzón automático
    receive() external payable {
        etherRecibido += msg.value;
    }
    
    // fallback() se ejecuta cuando no hay función que coincida
    fallback() external payable {
        etherRecibido += msg.value;
    }
    
    function verBalance() public view returns (uint256) {
        return address(this).balance;
    }
}
```

### 5.3 Ejemplo Completo: Caja de Ahorros

```solidity
pragma solidity ^0.8.0;

contract CajaAhorros {
    address public propietario;
    uint256 public metaAhorro;
    uint256 public totalAhorrado;
    bool public metaAlcanzada;
    
    // Mapeo de ahorradores
    mapping(address => uint256) public ahorros;
    address[] public ahorradores;
    
    // Eventos
    event AhorroRealizado(address ahorrador, uint256 cantidad);
    event MetaAlcanzada(uint256 totalFinal);
    event RetiroRealizado(address ahorrador, uint256 cantidad);
    
    constructor(uint256 _metaAhorro) {
        propietario = msg.sender;
        metaAhorro = _metaAhorro;
        totalAhorrado = 0;
        metaAlcanzada = false;
    }
    
    // Función para ahorrar
    function ahorrar() public payable {
        require(msg.value > 0, "Debe enviar algo de Ether");
        require(!metaAlcanzada, "Meta ya alcanzada");
        
        // Si es la primera vez que ahorra, agregarlo a la lista
        if (ahorros[msg.sender] == 0) {
            ahorradores.push(msg.sender);
        }
        
        ahorros[msg.sender] += msg.value;
        totalAhorrado += msg.value;
        
        emit AhorroRealizado(msg.sender, msg.value);
        
        // Verificar si se alcanzó la meta
        if (totalAhorrado >= metaAhorro) {
            metaAlcanzada = true;
            emit MetaAlcanzada(totalAhorrado);
        }
    }
    
    // Función para retirar ahorros (solo si la meta fue alcanzada)
    function retirarAhorros() public {
        require(metaAlcanzada, "Meta no alcanzada aun");
        require(ahorros[msg.sender] > 0, "No tienes ahorros");
        
        uint256 cantidad = ahorros[msg.sender];
        ahorros[msg.sender] = 0;
        
        (bool exito, ) = payable(msg.sender).call{value: cantidad}("");
        require(exito, "Retiro fallido");
        
        emit RetiroRealizado(msg.sender, cantidad);
    }
    
    // Función automática para recibir Ether
    receive() external payable {
        // Redirigir a la función ahorrar
        this.ahorrar{value: msg.value}();
    }
    
    // Función para ver información
    function verInformacion() public view returns (
        uint256 meta,
        uint256 totalActual,
        bool alcanzada,
        uint256 misAhorros
    ) {
        return (
            metaAhorro,
            totalAhorrado,
            metaAlcanzada,
            ahorros[msg.sender]
        );
    }
    
    // Función para ver todos los ahorradores
    function verAhorradores() public view returns (address[] memory) {
        return ahorradores;
    }
}
```

---

## 🎯 6. Ejemplo Práctico Completo: Tienda Online

Aquí tienes un ejemplo que combina todo lo que hemos aprendido:

```solidity
pragma solidity ^0.8.0;

contract TiendaOnline {
    // Variables de estado
    address public propietario;
    uint256 public totalVentas;
    uint256 public numeroProductos;
    
    // Estructura para productos
    struct Producto {
        uint256 id;
        string nombre;
        uint256 precio;
        uint256 stock;
        bool activo;
    }
    
    // Mapeos
    mapping(uint256 => Producto) public productos;
    mapping(address => uint256) public comprasCliente;
    
    // Arrays
    uint256[] public productosDisponibles;
    
    // Eventos
    event ProductoAgregado(uint256 id, string nombre, uint256 precio);
    event CompraRealizada(address cliente, uint256 productoId, uint256 cantidad);
    event StockActualizado(uint256 productoId, uint256 nuevoStock);
    
    constructor() {
        propietario = msg.sender;
        totalVentas = 0;
        numeroProductos = 0;
    }
    
    // Modificador para solo propietario
    modifier soloPropiestario() {
        require(msg.sender == propietario, "Solo el propietario puede hacer esto");
        _;
    }
    
    // Función para agregar productos
    function agregarProducto(
        string memory _nombre,
        uint256 _precio,
        uint256 _stock
    ) public soloPropiestario {
        numeroProductos++;
        
        productos[numeroProductos] = Producto({
            id: numeroProductos,
            nombre: _nombre,
            precio: _precio,
            stock: _stock,
            activo: true
        });
        
        productosDisponibles.push(numeroProductos);
        
        emit ProductoAgregado(numeroProductos, _nombre, _precio);
    }
    
    // Función para comprar productos
    function comprarProducto(uint256 _productoId, uint256 _cantidad) public payable {
        Producto storage producto = productos[_productoId];
        
        require(producto.activo, "Producto no disponible");
        require(producto.stock >= _cantidad, "Stock insuficiente");
        require(msg.value >= producto.precio * _cantidad, "Pago insuficiente");
        
        // Actualizar stock
        producto.stock -= _cantidad;
        
        // Registrar compra
        comprasCliente[msg.sender] += _cantidad;
        totalVentas += producto.precio * _cantidad;
        
        // Devolver cambio si es necesario
        uint256 cambio = msg.value - (producto.precio * _cantidad);
        if (cambio > 0) {
            (bool exito, ) = payable(msg.sender).call{value: cambio}("");
            require(exito, "Error al devolver cambio");
        }
        
        emit CompraRealizada(msg.sender, _productoId, _cantidad);
        emit StockActualizado(_productoId, producto.stock);
    }
    
    // Función para ver producto
    function verProducto(uint256 _productoId) public view returns (
        uint256 id,
        string memory nombre,
        uint256 precio,
        uint256 stock,
        bool activo
    ) {
        Producto memory producto = productos[_productoId];
        return (
            producto.id,
            producto.nombre,
            producto.precio,
            producto.stock,
            producto.activo
        );
    }
    
    // Función para retirar ganancias (solo propietario)
    function retirarGanancias() public soloPropiestario {
        uint256 balance = address(this).balance;
        require(balance > 0, "No hay ganancias para retirar");
        
        (bool exito, ) = payable(propietario).call{value: balance}("");
        require(exito, "Error al retirar ganancias");
    }
    
    // Función para ver balance del contrato
    function verBalance() public view returns (uint256) {
        return address(this).balance;
    }
    
    // Función para ver productos disponibles
    function verProductosDisponibles() public view returns (uint256[] memory) {
        return productosDisponibles;
    }
    
    // Función automática para recibir Ether
    receive() external payable {
        // Simplemente acepta el Ether
        // Podrías agregar lógica adicional aquí
    }
}
```

---

## 📝 Resumen y Mejores Prácticas

### Conceptos Clave Aprendidos:

1. **Tipos de Datos**: Como organizar diferentes tipos de información
2. **Variables Globales**: Información siempre disponible en el contrato
3. **Funciones**: Instrucciones que puede ejecutar el contrato
4. **Transferencias**: Cómo enviar Ether de forma segura
5. **Recepción de Ether**: Cómo los contratos pueden recibir dinero

### Mejores Prácticas:

1. **Siempre usar `require()`** para verificar condiciones
2. **Usar `call()` en lugar de `transfer()`** para transferencias
3. **Emitir eventos** para registrar actividades importantes
4. **Usar modificadores** para controlar acceso
5. **Manejar errores** apropiadamente
6. **Documentar tu código** con comentarios claros

### Próximos Pasos:

1. Practica con estos ejemplos
2. Modifica los contratos para agregar nuevas funcionalidades
3. Aprende sobre seguridad en contratos inteligentes
4. Explora bibliotecas como OpenZeppelin
5. Practica con testnets antes de usar dinero real

¡Felicidades! Has completado una introducción completa a Solidity. Con estos conceptos básicos puedes empezar a crear tus propios contratos inteligentes.