Integrando Pagos en Ether y Datos Externos con Chainlink en Smart Contracts

Cuando interactuamos con una red compatible con la Máquina Virtual de Ethereum (EVM), cada transacción conlleva parámetros específicos más allá del simple envío de fondos. El campo Value indica la cantidad de ETH que se transfiere mediante dicha operación.

Componentes de una Transacción

Cada solicitud de bloques incluye metadatos esenciales para su validación:

  • Nonce: Contador incremental de transacciones por cuenta.
  • Gas Limit y Price: Definición de los recursos computacionales y su coste.
  • To: Dirección receptora (contrato o wallet).
  • Data: Payload utilizado para invocar funciones de contratos inteligentes.
  • Firma (v, r, s): Componentes criptográficos que autentican el origen.

Es importante recordar que las unidades de valor en Ethereum siguen la escala de wei. Para facilitar las conversiones, existen herramientas estándar como eth-converter.com.

Aceptando Fondos en Contratos Inteligentes

Tanto las carteras como las direcciones de contratos pueden custodiar activos nativos. Para permitir que un contrato reciba ETH, la función correspondiente debe estar marcada explícitamente con el modificador payable.

Para asegurar que una transacción cumpla con ciertos criterios económicos, utilizamos sentencias de valiadción. Por ejemplo, podríamos exigir que el envío sea superior a 1 ETH:

require(msg.value > 1e18, "La cantidad enviada es insuficiente");

Si la condición falla, el estado de la cadena se revierte (rollback), liberando el gas restante pero consumiendo el necesario hasta el punto de fallo. Esto permite validar límites mínimos antes de proceder con lógica interna.

El Problema de la Determinación de Precios

Los blockchains son entornos deterministas; todos los nodos deben llegar al mismo consenso. Sin embargo, carecen de capacidad nativa para acceder a datos externos (como el precio del dólar frente al Ether) o eventos fuera de la red. Introducir variables externas sin control puede romper la consistencia del consenso, fenómeno conocido como el problema de los oráculos.

Para resolver esto, se emplean redes de oráculos descentralizadas. Chainlink actúa como capa intermedia segura, suministrando información veraz desde fuentes externas hacia el contrato inteligente.

Utilizando Feeds de Chainlink

Chainlink ofrece servicios listos para usar, destacando principalmente los Data Feeds (alimentación de datos). Estos agregan precios de múltiples proveedores mediante nodos independientes, caclulando la mediana para evitar manipulaciones individuales, y firman los resultados para garantizar su integridad en la blockchain.

Siguientes funcionalidades clave incluyen:

  1. VRF (Randomness Verifiable): Generación de números aleatorios probables matemáticamente.
  2. Keepers: Automatización de funciones basada en disparadores de eventos.
  3. Any API: Personalización para obtener datos genéricos vía HTTP.

Implementación Práctica: Validación en Dólares

Dado que los contratos no manejan decimales nativamente, la conversión entre ETH y moneda fiduciaria requiere manipulación matemática cuidadosa. A continuación, se presenta una arquitectura refactorizada para gestionar depósitos con umbral mínimo en dólares utilizando el Feed de Precios de Chainlink en la red Sepolia.

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

import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";

contract CryptoFunder {
    // Umbral mínimo expresado en centavos (usando precisión de 18 decimales)
    uint256 public constant MIN_USD_VAL = 50 * 1e18; 
    address private immutable FEED_ADDRESS;
    AggregatorV3Interface internal priceFeed;

    constructor(address _feedAddress) {
        FEED_ADDRESS = _feedAddress;
        priceFeed = AggregatorV3Interface(_feedAddress);
    }

    /**
     * Recibe fondos verificando si el valor en USD supera el mínimo establecido.
     */
    function depositar(uint256 expectedMinUsd) public payable {
        uint256 currentEthInUsd = calcularValorEnDolares(msg.value);
        
        require(
            currentEthInUsd >= expectedMinUsd, 
            "El importe enviado no alcanza el equivalente en USD requerido"
        );
        
        // Lógica adicional post-verificación...
    }

    /**
     * Obtiene el último dato del feed de precios.
     * Retorno: (roundID, respuesta, startedAt, timestamp, answeredInRound)
     */
    function obtenerPrecioActual() public view returns (int256 precioRaw) {
        (/*uint80 roundID*/, int256 answer, /*uint startedAt*/, /*uint timeStamp*/, /*uint80 answeredInRound*/) = 
            priceFeed.latestRoundData();
        return answer;
    }

    /**
     * Calcula cuánto vale una cantidad de ETH en US Dollars dentro del contrato.
     * Nota: Los feeds suelen tener 8 decimales, mientras que ETH usa 18.
     */
    function calcularValorEnDolares(uint256 amountEth) public view returns (uint256) {
        int256 rawPrice = obtenerPrecioActual();
        uint256 priceWithDecimals = uint256(rawPrice) * 1e10; // Ajuste de precisión (8 + 10 = 18)

        // Fórmula: (CantidadETH * PrecioPorEth) / FactorWei
        uint256 valorUsd = (amountEth * priceWithDecimals) / 1e18; 
        
        return valorUsd;
    }

    /**
     * Permite al propietario retirar los fondos acumulados.
     */
    function retirarFondos() public {
        payable(msg.sender).transfer(address(this).balance);
    }
}

Al implementar este código, es crucial gestionar las diferentes escalas de decimales. Mientras que el token Ether tiene 18 cifras decimales (1 ETH = $10^{18}$ wei), los feeds de precios de Chainlink a menudo tienen solo 8 cifras decimales. Para igualar ambas escalas, multiplicamos el precio cruda obtenida por 1e10. Esto asegura que, al realizar operaciones aritméticas y dividir finalmente por 1e18, el resultado refleje correctamente el valor fiduciario deseado sin errores de truncamiento.

Etiquetas: Solidity chainlink smart-contracts Ethereum Web3

Publicado el 10-24 21:28