tutoriales.com

Tokens No Fungibles Dinámicos (dNFTs) en Ethereum: Creación y Gestión con Solidity y Chainlink VRF

Este tutorial te guiará en la creación de Tokens No Fungibles Dinámicos (dNFTs) en la blockchain de Ethereum utilizando Solidity y la función Verifiable Random Function (VRF) de Chainlink. Descubre cómo los NFTs pueden evolucionar y adaptar sus metadatos e incluso su apariencia basándose en factores externos o eventos programáticos. Aprenderás a diseñar contratos inteligentes que permitan a tus NFTs interactuar con el mundo exterior y cambiar de estado de forma verificable.

Intermedio20 min de lectura5 views
Reportar error

🚀 Introducción a los dNFTs: NFTs que Cobran Vida

Los Tokens No Fungibles (NFTs) han revolucionado la forma en que pensamos sobre la propiedad digital, el arte y la coleccionabilidad. Sin embargo, la mayoría de los NFTs tradicionales son estáticos: una vez acuñados, sus metadatos y representaciones visuales suelen permanecer inmutables. Aquí es donde entran los dNFTs, o Tokens No Fungibles Dinámicos.

Los dNFTs son NFTs con la capacidad de cambiar sus metadatos, su apariencia o incluso sus características con el tiempo, en respuesta a ciertos eventos o condiciones. Imagina un NFT de un personaje de juego que evoluciona a medida que gana experiencia, una obra de arte digital que cambia según el clima del mundo real, o un NFT de un boleto que actualiza su estado de 'válido' a 'usado' tras un evento. Las posibilidades son infinitas y abren un nuevo abanico de casos de uso para la tecnología blockchain.

¿Por qué dNFTs?

La principal ventaja de los dNFTs es su capacidad para añadir una capa de interactividad y evolución que los NFTs estáticos no pueden ofrecer. Esto los hace ideales para:

  • Juegos: Personajes que suben de nivel, equipamiento que mejora, cartas coleccionables que evolucionan.
  • Arte Generativo: Obras que cambian con el tiempo, la interacción del usuario o datos externos.
  • Identidad Descentralizada: NFTs que representan logros o credenciales que se actualizan.
  • Ticketing y Eventos: Boletos que cambian de estado, pases VIP que otorgan diferentes beneficios.
  • Activos del Mundo Real (RWA): NFTs que reflejan el estado actual de un activo físico.
📌 Nota: La dinámica de un dNFT puede ser impulsada por datos on-chain (otras transacciones, estado de contratos) o por datos off-chain (precios de mercados, resultados deportivos, eventos climáticos) a través de oráculos.

🛠️ Herramientas Necesarias

Para seguir este tutorial, necesitarás lo siguiente:

  • Solidity: Lenguaje de programación para contratos inteligentes en Ethereum.
  • Hardhat o Foundry: Entornos de desarrollo para Ethereum para compilar, desplegar y probar tus contratos.
  • MetaMask: Una billetera de Ethereum para interactuar con la blockchain.
  • Un editor de código: Como Visual Studio Code.
  • Chainlink VRF: Para generar aleatoriedad verificable on-chain, que usaremos como un disparador para la dinámica de nuestro dNFT. Necesitarás algunos LINK para solicitar aleatoriedad en testnets.
🔥 Importante: Trabajaremos en una red de prueba (testnet) como Sepolia para evitar costos reales de gas y LINK.

📖 Entendiendo la Aleatoriedad Verificable con Chainlink VRF

Un componente clave para muchos dNFTs dinámicos es la capacidad de introducir aleatoriedad de forma segura y verificable. Aquí es donde Chainlink VRF (Verifiable Random Function) brilla. La aleatoriedad generada por la blockchain es un desafío conocido, ya que los mineros/validadores podrían manipularla. Chainlink VRF resuelve esto al proporcionar una fuente de aleatoriedad demostrablemente imparcial y a prueba de manipulaciones.

¿Cómo funciona Chainlink VRF?

  1. Tu contrato solicita aleatoriedad: Tu contrato inteligente llama a la función requestRandomWords del contrato coordinador de VRF de Chainlink, pasando una keyHash, un subscriptionId, y otros parámetros.
  2. El oráculo Chainlink genera un número aleatorio: Un nodo Chainlink VRF monitorea estas solicitudes. Cuando detecta una, genera un número aleatorio fuera de la cadena utilizando su clave privada, lo cual es verificable por cualquier persona usando la clave pública del nodo. El nodo luego envía una transacción de vuelta a tu contrato.
  3. Tu contrato recibe el número aleatorio: Tu contrato inteligente implementa la interfaz VRFConsumerBaseV2 y recibe el número aleatorio a través de la función fulfillRandomWords.
Contrato Inteligente Coordinador VRF Nodo Chainlink 3. Generación Off-chain y Prueba 1. Solicitar 2. Evento 4. Transacción + Prueba 5. fulfillRandomWords Flujo de Aleatoriedad Verificable (VRF) de Chainlink

Conceptos Clave de Chainlink VRF

  • keyHash: Un identificador único para el tipo de VRF que estás utilizando. Cada red y cada versión de VRF tiene su propio keyHash.
  • subscriptionId: Una cuenta gestionada por Chainlink donde depositas tokens LINK para pagar las solicitudes de VRF. Cada solicitud consume una pequeña cantidad de LINK.
  • minimumRequestConfirmations: El número mínimo de bloques que deben confirmarse antes de que el oráculo Chainlink envíe la respuesta. Esto ayuda a mitigar ataques de reordenamiento.
  • callbackGasLimit: El límite de gas para la llamada de retorno a tu contrato. Es crucial establecerlo lo suficientemente alto para que tu función fulfillRandomWords no se quede sin gas.
⚠️ Advertencia: Un `callbackGasLimit` demasiado bajo puede hacer que la llamada a `fulfillRandomWords` falle, perdiendo los LINK gastados en la solicitud. Asegúrate de que tu lógica dentro de `fulfillRandomWords` sea eficiente.

🧑‍💻 Diseño del dNFT: Un NFT que Evoluciona por Aleatoriedad

Para nuestro ejemplo, crearemos un dNFT simple que representa un 'Cristal Mágico'. Este cristal tendrá diferentes 'niveles' o 'formas', y su forma cambiará aleatoriamente cuando el propietario decida 'despertarlo' (activar la aleatoriedad). Cada forma tendrá un URI de metadatos diferente, que podría apuntar a una imagen diferente.

Estructura del Contrato

Nuestro contrato necesitará:

  1. Funcionalidad ERC-721: Para que sea un NFT estándar.
  2. Integración con Chainlink VRF: Para obtener aleatoriedad.
  3. Lógica para el estado dinámico: Para cambiar la forma del cristal.
  4. Almacenamiento de URI de metadatos: Para diferentes formas.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";
import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol";

contract DynamicMagicCrystal is ERC721, Ownable, VRFConsumerBaseV2 {

    // Chainlink VRF variables
    VRFCoordinatorV2Interface immutable i_vrfCoordinator;
    uint64 immutable i_subscriptionId;
    bytes32 immutable i_keyHash;
    uint32 constant private CALLBACK_GAS_LIMIT = 200000; // Suficiente gas para fulfillRandomWords
    uint16 constant private REQUEST_CONFIRMATIONS = 3;
    uint32 constant private NUM_WORDS = 1;

    // Mapping de token ID a su forma actual (ej. 0: base, 1: evolucionado 1, 2: evolucionado 2)
    mapping(uint256 => uint256) public crystalForms;

    // Mapping de solicitud de VRF ID a token ID (para saber qué token se está actualizando)
    mapping(uint256 => uint256) public s_requestIdToTokenId;

    // URIs para las diferentes formas del cristal
    string[] public tokenUris;

    // Contador de tokens
    uint256 private _nextTokenId;

    event CrystalFormChanged(uint256 indexed tokenId, uint256 oldForm, uint256 newForm);
    event CrystalAwakeningRequested(uint256 indexed tokenId, uint256 requestId);

    constructor(
        uint64 subscriptionId,
        address vrfCoordinator,
        bytes32 keyHash
    ) ERC721("Dynamic Magic Crystal", "DMC") VRFConsumerBaseV2(vrfCoordinator) Ownable(msg.sender) {
        i_vrfCoordinator = VRFCoordinatorV2Interface(vrfCoordinator);
        i_subscriptionId = subscriptionId;
        i_keyHash = keyHash;

        // Inicializar con URIs de ejemplo para 3 formas
        tokenUris.push("ipfs://QmaT8hBqE6pB7gC2fX7dY8Z0vV5wM4jQ2yR3xS4tU5vW6a"); // Forma Base
        tokenUris.push("ipfs://QmaT8hBqE6pB7gC2fX7dY8Z0vV5wM4jQ2yR3xS4tU5vW6b"); // Forma Brillante
        tokenUris.push("ipfs://QmaT8hBqE6pB7gC2fX7dY8Z0vV5wM4jQ2yR3xS4tU5vW6c"); // Forma Radiante
    }

    // Función para acuñar un nuevo cristal
    function mintCrystal() public onlyOwner returns (uint256) {
        uint256 newTokenId = _nextTokenId++;
        _mint(msg.sender, newTokenId);
        crystalForms[newTokenId] = 0; // Se inicializa en la forma base (0)
        return newTokenId;
    }

    // Permite al propietario del token solicitar una 'despertar' (cambio de forma)
    function awakenCrystal(uint256 tokenId) public {
        require(_isApprovedOrOwner(msg.sender, tokenId), "Not owner nor approved");

        uint256 requestId = i_vrfCoordinator.requestRandomWords(
            i_keyHash,
            i_subscriptionId,
            REQUEST_CONFIRMATIONS,
            CALLBACK_GAS_LIMIT,
            NUM_WORDS
        );
        s_requestIdToTokenId[requestId] = tokenId;
        emit CrystalAwakeningRequested(tokenId, requestId);
    }

    // Función de callback de Chainlink VRF
    function fulfillRandomWords(
        uint256 requestId,
        uint256[] memory randomWords
    ) internal override {
        uint256 tokenId = s_requestIdToTokenId[requestId];
        require(tokenId != 0 || _nextTokenId == 0, "Request ID not found or tokenId 0 already exists"); // tokenId 0 podría existir

        // Usa el número aleatorio para determinar la nueva forma
        uint256 newForm = randomWords[0] % tokenUris.length;
        uint256 oldForm = crystalForms[tokenId];
        crystalForms[tokenId] = newForm;

        delete s_requestIdToTokenId[requestId]; // Limpiar el mapping

        emit CrystalFormChanged(tokenId, oldForm, newForm);
    }

    // Sobrescribe la función tokenURI para que devuelva el URI de la forma actual
    function tokenURI(uint256 tokenId) public view override returns (string memory) {
        _requireOwned(tokenId);
        uint256 currentForm = crystalForms[tokenId];
        return tokenUris[currentForm];
    }

    // Función para que el owner del contrato pueda añadir o cambiar URIs de formas
    function setTokenUri(uint256 formIndex, string memory newUri) public onlyOwner {
        require(formIndex < tokenUris.length, "Form index out of bounds");
        tokenUris[formIndex] = newUri;
    }

    // Función para añadir una nueva forma
    function addTokenUri(string memory newUri) public onlyOwner {
        tokenUris.push(newUri);
    }

    // Opcional: Función para ver la forma actual de un cristal
    function getCurrentCrystalForm(uint256 tokenId) public view returns (uint256) {
        return crystalForms[tokenId];
    }
}
💡 Consejo: Considera que los `tokenUris` son solo punteros. La imagen o los metadatos reales vivirán en un sistema de almacenamiento descentralizado como IPFS, y su contenido deberá actualizarse o ser generado dinámicamente.

⚙️ Configuración del Entorno de Desarrollo (Hardhat)

1. Inicializar un Proyecto Hardhat

Si no tienes uno, crea un nuevo proyecto Hardhat:

npx hardhat init

Elige Create a basic sample project y sigue las indicaciones.

2. Instalar Dependencias

Necesitarás @openzeppelin/contracts para el estándar ERC-721 y @chainlink/contracts para la integración de VRF.

npm install --save-dev @openzeppelin/contracts @chainlink/contracts

3. Configurar hardhat.config.js

Asegúrate de que tu hardhat.config.js esté configurado para la red de prueba (ej. Sepolia). Necesitarás una clave privada y una URL de RPC (por ejemplo, de Infura o Alchemy).

require("@nomicfoundation/hardhat-toolbox");
require("@nomicfoundation/hardhat-ethers"); // Asegúrate de tener esto para ethers.js

const SEPOLIA_RPC_URL = process.env.SEPOLIA_RPC_URL || "https://sepolia.infura.io/v3/YOUR_INFURA_PROJECT_ID";
const PRIVATE_KEY = process.env.PRIVATE_KEY || "0xac0974bec39a17e36ba4a6b4d2386ff00000000000000000000000000000000"; // Replace with your actual private key

module.exports = {
  solidity: "0.8.19",
  networks: {
    sepolia: {
      url: SEPOLIA_RPC_URL,
      accounts: PRIVATE_KEY !== undefined ? [PRIVATE_KEY] : [],
      chainId: 11155111,
    },
  },
  // Configuración de gas opcional
  gasReporter: {
    enabled: process.env.REPORT_GAS !== undefined,
    currency: "USD",
  },
};

Crea un archivo .env en la raíz de tu proyecto y añade tus credenciales:

SEPOLIA_RPC_URL="https://sepolia.infura.io/v3/YOUR_INFURA_PROJECT_ID"
PRIVATE_KEY="YOUR_METAMASK_PRIVATE_KEY"
⚠️ Advertencia: Nunca uses tu clave privada de una billetera principal en un entorno de desarrollo. Usa una clave privada de una billetera de testnet con fondos ficticios.

🚀 Despliegue del Contrato y Configuración de Chainlink VRF

1. Obtener Fondos de Testnet

2. Crear una Suscripción Chainlink VRF

Ve al panel de Chainlink VRF (asegúrate de que estás en la red Sepolia). Crea una nueva suscripción y añade fondos LINK a ella. Anota el Subscription ID.

3. Obtener VRF Coordinator Address y Key Hash

Para Sepolia (u otras testnets), puedes encontrar estos valores en la documentación de Chainlink VRF: docs.chain.link/vrf/v2/direct-funding/supported-networks

Para Sepolia, los valores comunes son:

  • VRF Coordinator Address: 0x8103B0A8A00be2DDC778e6e7eaa21791Cd364625
  • Key Hash: 0x474e236d8b3ce47cd01aed05e262ce65703a2b0177f1b9f71c327de5462703bb

4. Script de Despliegue

Crea un archivo deploy.js en la carpeta scripts:

const { ethers } = require("hardhat");

async function main() {
  const [deployer] = await ethers.getSigners();

  console.log("Desplegando contratos con la cuenta:", deployer.address);

  // Sustituye estos valores por los tuyos
  const SUBSCRIPTION_ID = 42; // Tu ID de suscripción de Chainlink VRF
  const VRF_COORDINATOR_ADDRESS = "0x8103B0A8A00be2DDC778e6e7eaa21791Cd364625"; // Chainlink VRF Coordinator en Sepolia
  const KEY_HASH = "0x474e236d8b3ce47cd01aed05e262ce65703a2b0177f1b9f71c327de5462703bb"; // Key Hash para Sepolia

  const DynamicMagicCrystal = await ethers.getContractFactory("DynamicMagicCrystal");
  const dynamicMagicCrystal = await DynamicMagicCrystal.deploy(
    SUBSCRIPTION_ID,
    VRF_COORDINATOR_ADDRESS,
    KEY_HASH
  );

  await dynamicMagicCrystal.waitForDeployment();

  console.log("DynamicMagicCrystal desplegado en:", await dynamicMagicCrystal.getAddress());

  // Añadir el contrato como un 'consumer' a tu suscripción de Chainlink VRF
  // Esto DEBE hacerse en la interfaz de Chainlink VRF o programáticamente.
  // Aquí, simularemos la interacción para mostrar el concepto. En producción, usarías un script dedicado.
  console.log("Por favor, añade la dirección del contrato (", await dynamicMagicCrystal.getAddress(), ") a tu suscripción VRF en https://vrf.chain.link/");
  console.log("Asegúrate de tener suficientes LINK en tu suscripción.");
}

main()
  .then(() => process.exit(0))
  .catch((error) => {
    console.error(error);
    process.exit(1);
  });

¡Importante! Después de desplegar el contrato, DEBES ir al panel de Chainlink VRF, seleccionar tu suscripción y añadir la dirección de tu contrato DynamicMagicCrystal como un Consumer. Sin este paso, tu contrato no podrá recibir las respuestas de VRF.

5. Desplegar el Contrato

npx hardhat run scripts/deploy.js --network sepolia

Guarda la dirección del contrato desplegado.


🧪 Interacción con el dNFT: ¡Haciéndolo Dinámico!

Ahora que nuestro contrato está desplegado, podemos interactuar con él para ver el dNFT en acción.

1. Acuñar un Cristal Mágico

Primero, necesitamos acuñar un nuevo cristal. Como la función mintCrystal es onlyOwner, podemos llamarla desde la cuenta que desplegó el contrato.

// scripts/interact.js (Ejemplo, puedes adaptarlo a un script de prueba o usar Hardhat Console)
const { ethers } = require("hardhat");

async function interact() {
    const contractAddress = "YOUR_DEPLOYED_CONTRACT_ADDRESS"; // Reemplaza con tu dirección
    const [deployer] = await ethers.getSigners();

    const dynamicMagicCrystal = await ethers.getContractAt("DynamicMagicCrystal", contractAddress);

    console.log("Acuñando un cristal mágico...");
    const mintTx = await dynamicMagicCrystal.mintCrystal();
    await mintTx.wait();
    const tokenId = await dynamicMagicCrystal.callStatic.mintCrystal(); // Obtener el ID del token acuñado si no se devuelve en el evento
    console.log("Cristal acuñado con ID:", tokenId); // Esto puede variar, el ID real será el _nextTokenId antes del incremento

    // Para obtener el tokenID de forma fiable, deberíamos parsear el evento Transfer.
    // Simplificamos aquí asumiendo que el primer token es 0.
    const firstTokenId = 0; // Asumimos que es el primer token acuñado
    console.log("Forma inicial del cristal (ID %s): %s", firstTokenId, await dynamicMagicCrystal.getCurrentCrystalForm(firstTokenId));
    console.log("URI inicial del cristal (ID %s): %s", firstTokenId, await dynamicMagicCrystal.tokenURI(firstTokenId));
}

// Para ejecutar: npx hardhat run scripts/interact.js --network sepolia
// Ajusta `interact` para que puedas pasar el token ID acuñado.
// O más fácil, usa hardhat console:
/*
  npx hardhat console --network sepolia
  const DynamicMagicCrystal = await ethers.getContractFactory("DynamicMagicCrystal");
  const dmc = DynamicMagicCrystal.attach("YOUR_DEPLOYED_CONTRACT_ADDRESS");
  await dmc.mintCrystal(); // Esto acuña un nuevo token, el ID será 0 si es el primero
  console.log(await dmc.getCurrentCrystalForm(0));
  console.log(await dmc.tokenURI(0));
*/

2. Despertar el Cristal (Solicitar Aleatoriedad)

Ahora, llamemos a awakenCrystal para que el dNFT cambie su forma. Esto enviará una solicitud de VRF.

// Continuando desde el ejemplo de Hardhat Console
// Asegúrate de que tienes un token ID (ej. 0)
const tokenIdToAwaken = 0; 
console.log("Solicitando despertar para el cristal ID", tokenIdToAwaken);
const awakenTx = await dmc.awakenCrystal(tokenIdToAwaken);
await awakenTx.wait();

console.log("Solicitud de despertar enviada. Esperando a que Chainlink VRF responda...");
// La respuesta de VRF puede tardar unos segundos o minutos dependiendo de la red.
// Para ver la actualización, puedes monitorear los eventos en Etherscan o simplemente:
// Volver a consultar la forma y URI después de un tiempo
// Después de un minuto o dos, ejecuta:
console.log("Nueva forma del cristal (ID %s): %s", tokenIdToAwaken, await dmc.getCurrentCrystalForm(tokenIdToAwaken));
console.log("Nuevo URI del cristal (ID %s): %s", tokenIdToAwaken, await dmc.tokenURI(tokenIdToAwaken));

Verás cómo la forma (el número entero) y el tokenURI asociado han cambiado, reflejando el número aleatorio generado por Chainlink VRF. Cada vez que llames a awakenCrystal, el NFT tiene la posibilidad de cambiar a una nueva forma (o quedarse en la misma, ya que la aleatoriedad es pura).

Usuario Contrato NFT Chainlink VRF 1. mintCrystal() 2. Acuña NFT 3. awakenCrystal(tokenId) 4. solicita VRF 5. fulfillRandomWords 6. Actualiza forms y tokenUris 7. tokenURI(tokenId) Nuevo Estado Proceso de Evolución Dinámica mediante Azar On-chain

🎨 Metadatos Dinámicos y Contenido de NFT

Nuestro ejemplo actual cambia la URL base del URI de los metadatos. En un sistema real de dNFTs, los metadatos en sí mismos tendrían que ser dinámicos. Hay varias formas de lograr esto:

1. Servidor Centralizado con API Dinámica (Menos Descentralizado)

El tokenURI apuntaría a un servidor web centralizado (https://api.mygame.com/nft/{id}). Este servidor leería el estado on-chain del NFT (ej. getCurrentCrystalForm(id)) y generaría el JSON de metadatos y la imagen correspondientes al vuelo.

Pros:

  • Fácil de implementar y actualizar.
  • Permite gráficos complejos y lógicas off-chain.

Contras:

  • Punto de centralización: el servidor podría caer, censurar o manipular los metadatos.

2. Metadatos Generados en IPFS con Actualizaciones (Híbrido)

El tokenURI apuntaría a un CID de IPFS. Cuando el estado del dNFT cambia, el propietario (o un oráculo autorizado) podría:

a) Generar un nuevo JSON de metadatos y una nueva imagen para la nueva forma. b) Subirlos a IPFS, obteniendo un nuevo CID. c) Si el contrato tiene una función setTokenURI (que solo el owner del contrato o un oráculo autorizado pueda llamar), actualizar el tokenURI del NFT en el contrato para apuntar al nuevo CID.

En nuestro ejemplo, tokenUris es un array string[] public tokenUris, y la función setTokenUri(uint256 formIndex, string memory newUri) es onlyOwner. Esto significa que el dueño del contrato es quien gestiona las URIs para cada forma posible. Cuando la forma del cristal cambia por VRF, el tokenURI del NFT apunta automáticamente a la URI predefinida para esa nueva forma.

Pros:

  • Los metadatos están en IPFS, descentralizado.
  • El contrato controla qué URI se asocia a cada forma.

Contras:

  • Requiere que el owner del contrato o un oráculo actualice los CID de IPFS para las formas, o que las imágenes y metadatos sean pre-generados para todas las formas posibles.

3. Metadatos On-Chain (Más Descentralizado)

Almacenar los metadatos directamente en la blockchain, quizás codificados en Base64 Data URI. Cuando el estado del NFT cambia, la función tokenURI genera el JSON de metadatos y la imagen SVG al vuelo basándose en el estado actual on-chain.

Pros:

  • Completamente descentralizado y resistente a la censura.
  • Los metadatos evolucionan directamente con el NFT en la cadena.

Contras:

  • Costoso en gas para almacenar y generar datos complejos on-chain.
  • Limitado a gráficos y lógicas más simples (ej. SVG para imágenes).
💡 Consejo: Para gráficos más complejos con metadatos on-chain, puedes generar SVG con datos dinámicos. Por ejemplo, un SVG que cambie de color según la forma o tenga diferentes elementos visibles.

🔄 Casos de Uso Avanzados y Consideraciones

dNFTs Impulsados por Oráculos (Chainlink Data Feeds)

En lugar de aleatoriedad, los dNFTs pueden reaccionar a datos del mundo real. Por ejemplo:

  • NFT del Clima: Un NFT de un paisaje que cambia de soleado a lluvioso según un feed de datos meteorológicos de Chainlink.
  • NFT de Rendimiento Bursátil: Un NFT que representa una acción y cambia de color según el precio de la acción (usando Chainlink Price Feeds).

La lógica sería similar a VRF, pero en lugar de requestRandomWords, usarías requestData del contrato Chainlink Oracle para obtener los datos específicos.

dNFTs Basados en Interacción del Usuario o Otros Contratos

Un dNFT podría evolucionar basándose en:

  • Transacciones del propietario: Si el propietario realiza ciertas acciones (ej. feedPetNFT()).
  • Interacciones con otros contratos: Un NFT de un personaje que sube de nivel al interactuar con un contrato de juego.
  • Tiempo: Un NFT que cambia después de un período de tiempo determinado.

Seguridad y Reentrada

Como cualquier contrato inteligente, los dNFTs deben ser auditados cuidadosamente. Presta especial atención a:

  • _isApprovedOrOwner: Asegúrate de que las funciones sensibles (awakenCrystal) solo puedan ser llamadas por el propietario o un operador aprobado del token.
  • Oráculos: Si usas oráculos, asegúrate de que la fuente de datos sea confiable y que tu lógica maneje correctamente los datos desactualizados o errores.
  • Gas Limits: Como se mencionó, un callbackGasLimit insuficiente en VRF puede causar problemas.

Costos de Gas

Cada cambio de estado en un dNFT (iniciado por una transacción de solicitud, y luego por la transacción de respuesta del oráculo) incurre en costos de gas. Para dNFTs que cambian frecuentemente, esto puede ser una consideración importante para la economía del proyecto.

⚠️ Advertencia: El diseño de dNFTs puede volverse complejo rápidamente. Prioriza la seguridad y la eficiencia del gas desde el principio.

✅ Conclusión y Próximos Pasos

Has aprendido los fundamentos para crear y gestionar Tokens No Fungibles Dinámicos (dNFTs) en Ethereum, utilizando Solidity y la funcionalidad de Chainlink VRF. Hemos cubierto:

  • La conceptualización de dNFTs y sus ventajas.
  • La integración de Chainlink VRF para aleatoriedad on-chain verificable.
  • Un ejemplo práctico de un contrato dNFT que cambia su forma.
  • Consideraciones sobre metadatos dinámicos y casos de uso avanzados.

Los dNFTs abren la puerta a una nueva generación de activos digitales, con aplicaciones en juegos, arte, identidad y más. Te animamos a experimentar con diferentes tipos de dinámicas y a explorar cómo otros oráculos de Chainlink pueden enriquecer aún más tus creaciones.

Ideas para Experimentar:

  • Añadir más formas: Crea más URIs para diferentes evoluciones del cristal.
  • Condiciones para el cambio: Haz que el cristal solo pueda despertar una vez cada cierto tiempo, o solo si el msg.sender es un contrato de juego específico.
  • Metadatos on-chain: Intenta generar un SVG dinámico para el tokenURI directamente en el contrato.
  • Integrar Chainlink Data Feeds: Cambia el estado del NFT basándote en un precio de criptomoneda o un feed de clima.

¡El mundo de los dNFTs es vasto y emocionante! ¡Feliz codificación! 👨‍💻✨

Tutoriales relacionados

Comentarios (0)

Aún no hay comentarios. ¡Sé el primero!