Explorando y Aplicando los Estándares de Metadatos Descentralizados para NFTs (ERC-721 y ERC-1155) en Web3 🎨
Este tutorial profundiza en los estándares de metadatos esenciales para NFTs, ERC-721 y ERC-1155. Aprenderás a estructurar y gestionar la información asociada a tus tokens no fungibles, garantizando su interoperabilidad y permanencia en el ecosistema Web3.
¡Bienvenido al fascinante mundo de los Metadatos NFT! 🎨
En el ecosistema Web3, un NFT (Token No Fungible) es mucho más que un simple identificador en la blockchain. Es un activo digital único que representa la propiedad de un elemento específico, ya sea arte, música, coleccionables, bienes raíces virtuales o cualquier otra cosa imaginable. Pero, ¿dónde reside toda la información sobre ese elemento? ¿Cómo sabemos qué imagen está asociada a un NFT, cuál es su descripción, sus propiedades o su autor?
Aquí es donde entran en juego los metadatos. Los metadatos son, literalmente, "datos sobre datos". Para los NFTs, son la información que describe el token en sí y el activo digital que representa. Sin metadatos, un NFT sería solo un número en un contrato inteligente, sin contexto ni valor significativo para los usuarios o las aplicaciones. Este tutorial te guiará a través de los estándares más comunes para la gestión de metadatos en NFTs, cómo se estructuran, dónde se almacenan y por qué son tan cruciales para la sostenibilidad de tus activos digitales.
¿Por Qué Son Cruciales los Metadatos en los NFTs? 💡
Los metadatos son el corazón de la utilidad y el significado de cualquier NFT. Permiten que las aplicaciones (dApps), las carteras (wallets) y los mercados (marketplaces) de NFT entiendan y muestren la información correcta sobre un token. Imagina comprar un NFT de un artista famoso y que tu cartera solo muestre un número de token, sin la imagen, el título o la descripción. ¡Sería frustrante y sin sentido!
Los metadatos resuelven problemas como:
- Representación Visual: Mostrar la imagen, video o audio asociado al NFT.
- Contexto: Proporcionar una descripción, título y otros detalles del activo.
- Propiedades: Incluir atributos únicos (rareza, estadísticas de juego, etc.).
- Interoperabilidad: Permitir que diferentes plataformas muestren el mismo NFT de manera consistente.
- Autenticidad: Ayudar a verificar la proveniencia y características del activo.
Estándares de Metadatos NFT: ERC-721 y ERC-1155 📖
Existen dos estándares principales de tokens en Ethereum que definen cómo se gestionan los NFTs y sus metadatos: ERC-721 y ERC-1155. Ambos tienen especificaciones para metadatos, aunque con ligeras diferencias debido a la naturaleza de los tokens que representan.
ERC-721: El Estándar para Tokens Únicos 🖼️
El estándar ERC-721 es el más conocido para los NFTs "tradicionales", donde cada token es completamente único e indivisible. Piensa en una obra de arte original o un objeto coleccionable específico. Cada token ERC-721 tiene un tokenId único y una URL asociada que apunta a sus metadatos.
La especificación de metadatos de ERC-721 se define a través de la función tokenURI(uint256 _tokenId) en el contrato inteligente. Esta función debe devolver una URL que apunte a un archivo JSON que contiene los metadatos del token. Este archivo JSON debe seguir un esquema específico.
Esquema de Metadatos ERC-721 (Ejemplo)
El formato JSON recomendado para los metadatos ERC-721 se parece a esto:
{
"name": "Mi NFT Increíble",
"description": "Esta es la descripción de mi primer NFT, ¡es una pieza única de arte digital!",
"image": "ipfs://QmTfNqWjNqJqQjQjQjQjQjQjQjQjQjQjQjQjQjQjQjQj/nft-image.png",
"external_url": "https://miwebsite.com/nft/123",
"attributes": [
{
"trait_type": "Fondo",
"value": "Azul Celeste"
},
{
"trait_type": "Estado",
"value": "Nuevo"
},
{
"display_type": "number",
"trait_type": "Generación",
"value": 1
},
{
"display_type": "boost_number",
"trait_type": "Poder de Ataque",
"value": 10,
"max_value": 100
}
]
}
Campos Clave Explicados:
name(string): El nombre del activo (ej. "CryptoPunk #1234").description(string): Una descripción más detallada del activo.image(string): ¡Crucial! Una URL que apunta a la imagen (o video, audio, etc.) del activo. Esta puede ser una URL HTTP, IPFS o Arweave.external_url(string, opcional): Un enlace externo a una página web donde se puede ver más información sobre el activo.attributes(array de objetos, opcional): Un array de objetos que describen propiedades del activo. Cada objeto puede tener:trait_type(string): El nombre de la característica (ej. "Color de ojos").value(cualquier tipo): El valor de la característica (ej. "Azul").display_type(string, opcional): Sugiere cómo se debe mostrar el atributo (ej. "number", "boost_number", "date").max_value(number, opcional): Paradisplay_typecomo "number" o "boost_number", indica el valor máximo.
ERC-1155: El Estándar Multi-Token 📦
El estándar ERC-1155 fue diseñado para ser más eficiente y flexible, permitiendo que un solo contrato inteligente gestione múltiples tipos de tokens, tanto fungibles como no fungibles. Esto lo hace ideal para juegos o colecciones donde puedes tener diferentes rarezas de cartas, objetos o incluso monedas en el mismo contrato.
En ERC-1155, la función para los metadatos es uri(uint256 _id). A diferencia de ERC-721, esta función devuelve una cadena de URI donde _id es el tokenId. El URI debe contener la cadena {id} que será reemplazada por el tokenId real en hexadecimal, con cero a la izquierda y 64 caracteres de longitud.
Esquema de Metadatos ERC-1155 (Ejemplo)
El esquema JSON es muy similar al de ERC-721, pero la forma en que se accede al URI es diferente.
Por ejemplo, si uri devuelve ipfs://QmTfNqWj.../{id}.json, y el _id es 1, la URL final para los metadatos del token 1 sería ipfs://QmTfNqWj.../0000000000000000000000000000000000000000000000000000000000000001.json.
{
"name": "Espada Legendaria de Fuego",
"description": "Una espada imbuida con magia ancestral, capaz de quemar a los enemigos.",
"image": "ipfs://QmYxNqZ.../sword-legendary.png",
"attributes": [
{
"trait_type": "Tipo de Arma",
"value": "Espada"
},
{
"trait_type": "Rareza",
"value": "Legendaria"
},
{
"display_type": "boost_percentage",
"trait_type": "Daño de Fuego",
"value": 25
}
]
}
¿Por qué el formato `{id}` en ERC-1155?
Esta característica permite almacenar metadatos para múltiples tokens utilizando una única plantilla de URI, lo que es muy eficiente para colecciones grandes o tokens con variaciones mínimas. El reemplazo del `{id}` asegura que cada token específico (incluso dentro del mismo contrato ERC-1155) pueda tener un archivo de metadatos distinto. Es crucial formatear el ID a 64 caracteres hexadecimales con ceros a la izquierda para asegurar uniformidad.Almacenamiento Descentralizado de Metadatos 💾
La descentralización es un pilar fundamental de Web3. Si la blockchain es descentralizada, ¿no deberían serlo también los metadatos de los NFTs? Absolutamente. Almacenar metadatos en un servidor centralizado (HTTP) presenta varios riesgos:
- Censura: El servidor podría ser atacado, censurado o apagado.
- Volatilidad: El enlace podría romperse (enlace roto) o el contenido podría modificarse sin previo aviso.
- Falta de Permanencia: Los NFTs con metadatos en servidores centralizados corren el riesgo de perder su significado si el servidor desaparece.
Por estas razones, el almacenamiento descentralizado es la opción preferida y recomendada para los metadatos NFT.
IPFS (InterPlanetary File System) ✨
IPFS es un protocolo peer-to-peer para almacenar y compartir datos en un sistema de archivos distribuido. Es la solución de almacenamiento descentralizado más popular para metadatos NFT. Cuando subes un archivo a IPFS, se le asigna un Content Identifier (CID) único, que es un hash criptográfico del contenido.
Ventajas de IPFS:
- Inmutabilidad: Una vez que un archivo se sube y se le asigna un CID, el contenido es fijo.
- Resistencia a la censura: No hay un punto central de fallo; los datos están distribuidos entre múltiples nodos.
- Permanencia: Con servicios de "pinning" (fijación), puedes asegurar que tus datos permanezcan disponibles indefinidamente.
¿Cómo funciona IPFS con NFTs?
- Sube tu imagen/archivo multimedia a IPFS: Obtienes un CID (ej.
QmTfNqWjNqJqQjQjQjQjQjQjQjQjQjQjQjQjQjQjQjQj). - Crea tu archivo JSON de metadatos: Incluye el CID de tu imagen en el campo
image("image": "ipfs://QmTfNqWjNqJqQjQjQjQjQjQjQjQjQjQjQjQjQjQjQjQj/nft-image.png"). - Sube tu archivo JSON a IPFS: Obtienes un nuevo CID para tu JSON (ej.
QmXYZABCDEF...). - Actualiza tu contrato NFT: La función
tokenURI(ERC-721) ouri(ERC-1155) devuelve la URL IPFS de tu JSON (ej.ipfs://QmXYZABCDEF...).
Servicios como Pinata, Web3.Storage o NFT.Storage facilitan el "pinning" de archivos en IPFS, asegurando su disponibilidad continua.
Arweave ⏳
Arweave es otra solución de almacenamiento descentralizado que se posiciona como una "unidad de disco duro permanente". A diferencia de IPFS, donde los datos necesitan ser "fijados" (pinned) activamente para permanecer accesibles, Arweave almacena los datos de forma permanente a cambio de una tarifa única.
Ventajas de Arweave:
- Permanencia garantizada: Los datos están diseñados para persistir para siempre.
- Sin necesidad de pinning: No se requiere intervención constante para mantener los datos disponibles.
Los URIs de Arweave se ven así: ar://[TRANSACTION_ID], donde [TRANSACTION_ID] es el ID de la transacción de Arweave que contiene el archivo.
Caso Práctico: Desplegando un NFT ERC-721 con Metadatos Descentralizados 🛠️
Vamos a crear un contrato ERC-721 simple y asociarle metadatos alojados en IPFS. Usaremos Hardhat para el desarrollo y Pinata para el "pinning" en IPFS.
1. Preparación del Entorno 💻
Si no lo has hecho ya, configura tu proyecto Hardhat:
npm init -y
npm install --save-dev hardhat @nomicfoundation/hardhat-toolbox @openzeppelin/contracts
npx hardhat
Selecciona "Create a JavaScript project" y sigue las instrucciones.
2. Contrato ERC-721 Básico
Crearemos un contrato simple MyNFT.sol en la carpeta contracts/.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
contract MyNFT is ERC721, Ownable {
using Counters for Counters.Counter;
Counters.Counter private _tokenIdCounter;
constructor(string memory name, string memory symbol) ERC721(name, symbol) Ownable(msg.sender) {
}
function safeMint(address to) public onlyOwner returns (uint256) {
uint256 tokenId = _tokenIdCounter.current();
_tokenIdCounter.increment();
_safeMint(to, tokenId);
return tokenId;
}
// Esta función es crucial para los metadatos. La implementaremos después.
function _baseURI() internal pure override returns (string memory) {
return ""; // Lo actualizaremos con la base URI de IPFS
}
}
3. Subiendo Metadatos a IPFS con Pinata ⬆️
- Crea una cuenta en Pinata: Ve a pinata.cloud y crea una cuenta gratuita.
- Sube tu imagen: Sube la imagen que quieres asociar a tu NFT. Una vez subida, copia su
CID(ej.QmXyZAbC...). - Crea el archivo JSON de metadatos: En tu proyecto Hardhat, crea una carpeta
metadata/y dentro un archivomy-first-nft.json.
{
"name": "Mi NFT Brillante",
"description": "Un NFT único creado para este tutorial, ¡brilla con luz propia!",
"image": "ipfs://QmXyZAbC.../my-nft-image.png",
"attributes": [
{
"trait_type": "Color",
"value": "Dorado"
},
{
"trait_type": "Rareza",
"value": "Común"
}
]
}
**Reemplaza `QmXyZAbC...` con el CID real de tu imagen en Pinata.**
4. Sube el archivo JSON a Pinata: Sube my-first-nft.json a Pinata. Una vez subido, copia su CID. Este será tu BASE_URI para el contrato, ya que OpenZeppelin asume que tokenURI construirá la URL de los metadatos como baseURI + tokenId (aunque esto puede variar dependiendo de cómo se implemente tokenURI). Para un NFT único, simplemente devolveremos la URI completa del JSON.
Por ejemplo, si el CID de tu JSON es `QmbCdEfG...`, tu URI será `ipfs://QmbCdEfG...`. Si tuvieras múltiples NFTs y cada uno con un JSON diferente (ej. `QmbCdEfG.../1.json`, `QmbCdEfG.../2.json`), entonces tu `baseURI` sería `ipfs://QmbCdEfG.../`.
Para este ejemplo simple de un solo NFT, devolveremos la URI completa en `tokenURI`.
4. Modificando el Contrato para Metadatos
Modificaremos MyNFT.sol para que tokenURI apunte a nuestro JSON en IPFS. OpenZeppelin ERC721 implementa tokenURI llamando a _baseURI() y añadiéndole el tokenId. Para nuestro caso, haremos que _baseURI devuelva la URL completa de nuestro JSON.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
contract MyNFT is ERC721, Ownable {
using Counters for Counters.Counter;
Counters.Counter private _tokenIdCounter;
// Variable para almacenar la URI base de los metadatos (ej. IPFS CID)
string private _baseTokenURI;
constructor(string memory name, string memory symbol, string memory baseTokenURI_)
ERC721(name, symbol)
Ownable(msg.sender)
{
_baseTokenURI = baseTokenURI_;
}
function safeMint(address to) public onlyOwner returns (uint256) {
uint256 tokenId = _tokenIdCounter.current();
_tokenIdCounter.increment();
_safeMint(to, tokenId);
return tokenId;
}
// Sobrescribimos _baseURI para que devuelva nuestra URI base de metadatos
function _baseURI() internal view override returns (string memory) {
return _baseTokenURI;
}
// Opcional: Función para actualizar la base URI si fuera necesario (solo propietario)
function setBaseURI(string memory baseTokenURI_) public onlyOwner {
_baseTokenURI = baseTokenURI_;
}
// Para obtener la URI de un token específico, solo necesitamos la baseURI
// ya que nuestro JSON contiene todos los metadatos.
// Si tuvieras un JSON por token (ej. 1.json, 2.json), la implementación por defecto de OZ
// funcionaría: "baseURI + tokenId".
// En este ejemplo simple, el tokenURI completo es la baseURI.
function tokenURI(uint256 tokenId) public view override returns (string memory) {
require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
return _baseTokenURI;
}
}
5. Script de Despliegue y Minteo 🚀
Crea un script deploy.js en la carpeta scripts/.
const hre = require("hardhat");
async function main() {
// Reemplaza con el CID de tu JSON de metadatos subido a Pinata.
// Ejemplo: "ipfs://QmbCdEfG..."
const BASE_TOKEN_URI = "ipfs://<TU_CID_DEL_JSON>";
const [deployer] = await hre.ethers.getSigners();
console.log("Desplegando contratos con la cuenta:", deployer.address);
const MyNFT = await hre.ethers.getContractFactory("MyNFT");
const myNFT = await MyNFT.deploy("Mi NFT Tutorial", "MNT", BASE_TOKEN_URI);
await myNFT.waitForDeployment();
console.log("MyNFT desplegado en:", await myNFT.getAddress());
// Mintear un NFT para el desplegador
const tokenId = await myNFT.safeMint(deployer.address);
console.log("NFT minteado con ID:", tokenId);
// Verificar el tokenURI
const tokenUri = await myNFT.tokenURI(0); // Suponiendo que el primer token minteado es 0
console.log("Token URI para el NFT minteado:", tokenUri);
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
¡No olvides reemplazar "ipfs://<TU_CID_DEL_JSON>" con el CID real de tu archivo JSON de metadatos en Pinata!
6. Desplegar y Probar
npx hardhat run scripts/deploy.js --network localhost
Esto desplegará tu contrato en la red local de Hardhat. Verás el tokenURI impreso en la consola, que debería apuntar a tu archivo JSON en IPFS. Luego, puedes usar un explorador de bloques local o una herramienta como Etherscan para verificar el contrato y la información del token.
Buenas Prácticas y Consideraciones Avanzadas ✅
Inmutabilidad y Persistencia
- IPFS con Pinning: Siempre usa un servicio de pinning confiable (Pinata, Web3.Storage) o tu propio nodo IPFS para asegurar que tus metadatos estén siempre disponibles. Sin pinning, los datos en IPFS pueden desaparecer si los nodos que los almacenan dejan de estar en línea.
- Arweave: Si la permanencia absoluta es crítica y estás dispuesto a pagar el costo único, Arweave es una excelente opción.
- Evita HTTP: Para metadatos de NFTs a largo plazo, evita almacenar el archivo JSON o la imagen principal en servidores HTTP tradicionales debido a los riesgos de centralización y volatilidad.
Off-Chain vs. On-Chain Metadatos
- Off-Chain (La Norma): La mayoría de los metadatos se almacenan off-chain (en IPFS, Arweave) y solo su URI se guarda en la blockchain. Esto es eficiente en costos y espacio, ya que almacenar datos directamente en la blockchain es muy caro.
- On-Chain (Raro): Es posible almacenar metadatos directamente en la blockchain (en el contrato inteligente). Esto garantiza la máxima descentralización y permanencia, pero es extremadamente costoso y generalmente solo se hace para proyectos muy específicos con metadatos muy pequeños (ej. CryptoPunks originales, donde los metadatos se "cocinaban" en el contrato). Para la gran mayoría de los NFTs, no es práctico.
Metadatos Dinámicos
Algunos NFTs tienen metadatos que cambian con el tiempo (ej. NFTs de juegos cuyas estadísticas evolucionan). Para estos casos:
- Proxy Contracts: El contrato inteligente puede ser un proxy que apunta a una implementación que se puede actualizar, permitiendo cambiar cómo se genera el
tokenURIo los atributos. - Servidores Centralizados con Firmas: A veces, se usa un servidor centralizado para servir metadatos dinámicos, pero con un mecanismo de firma criptográfica para probar que los datos provienen de una fuente autorizada. Esto introduce un punto de centralización, pero es una compensación por la dinamismo.
- Oráculos: En casos complejos, se pueden usar oráculos descentralizados para alimentar datos al contrato que luego influyen en cómo se generan o acceden a los metadatos.
Consideraciones de Accesibilidad y Formato
- Estándar ERC-721/ERC-1155: Adherirse a los esquemas JSON estándar es crucial para que los NFTs se muestren correctamente en plataformas como OpenSea, Rarible, etc.
animation_urlyyoutube_url: Si tu NFT es un video o una experiencia interactiva, usa estos campos en los metadatos JSON.propertiesvs.attributes: El campoattributeses el estándar de facto para propiedades. Evitapropertiesa menos que sea necesario para compatibilidad con sistemas heredados.
Conclusión 🏁
Comprender y aplicar correctamente los estándares de metadatos es fundamental para cualquier persona que desee crear, coleccionar o trabajar con NFTs en el ecosistema Web3. Los metadatos no solo dan vida a tus tokens, sino que también aseguran su interoperabilidad, permanencia y valor a largo plazo.
Al elegir el almacenamiento descentralizado como IPFS o Arweave y adherirte a los esquemas ERC-721/ERC-1155, estarás construyendo sobre una base sólida para el futuro de tus activos digitales. ¡Ahora estás listo para crear NFTs significativos y duraderos!
Tutoriales relacionados
- Creando y Utilizando un Mercado NFT Descentralizado con IPFS y Smart Contracts 🌐intermediate20 min
- Tokenización de Activos del Mundo Real (RWA) en Blockchain: Una Guía Práctica 🌎intermediate15 min
- Explorando y Usando Oráculos Descentralizados en dApps: Conectando Web3 con el Mundo Real 🔗intermediate20 min
- Decodificando el Futuro: Explorando y Utilizando Identidades Descentralizadas (DID) en Web3 🔑intermediate15 min
- Tokenización de Activos Fungibles en Web3: Creando un Token ERC-20 con OpenZeppelin y Hardhat 💰intermediate20 min
Comentarios (0)
Aún no hay comentarios. ¡Sé el primero!