11 min read
Introducción
¡Hola querido lector! Bienvenidos a una nueva guía de Solana.
Solana es una blockchain que promete mucho a la hora de intentar resolver los problemas de escalabilidad que podemos apreciar en otras blockchains, como Ethereum por ejemplo.
En esta guía, explicaremos paso a paso cómo crear un NFT en la red Solana.
Requisitos:
- NodeJS instalado
- Saber usar la Terminal / CLI
- Editor de texto
¿Qué es Solana?
Solana tiene un objetivo muy particular, escalar la tecnología blockchain para una adopción global. Solana Labs, los desarrolladores detrás de Solana Protocol, están haciendo unas cuantas cosas para poder alcanzar este sueño.
La tecnología de blockchain tiene unas cuantas vueltas cuando se trata de ser más performante. Una de ellas, es el mecanismo de consenso, que es la forma en la que los nodos se comunican entre sí y llegan a una conclusión idéntica para toda la red. Bitcoin utiliza un mecanismo conocido como Proof of Work (Prueba de Trabajo) o POW, BNB Smart Chain, tambien conocida como BSC, utiliza el mecanismo Proof of Staked Authority o PoSA, Ethereum esta actualmente migrando hacia Proof of Stake o Pos. Como puedes ver, el consenso no es un juego resuelto en este punto de la historia.
Solana utiliza un mecanismo de consenso llamado Proof of History, que funciona por medio de una marca de tiempo, cada transaccion tiene una marca de tiempo que permite su verificacion como una transaccion legitima por el resto de la red en cuestion de una fraccion de segundo.
Solana contiene ocho tecnologías principales que ellos mismos destacan de haberlos puesto en posición de ser las mas rapida, mas escalable y la más segura de todas las blockchains existentes.
Conectando con Solana
Nosotros usaremos Solana Devnet en esta guía. Solana tiene 3 redes diferentes, la principal (mainnet), la de testing (testnet) y otra más de desarrollo (devnet). La última, la devnet es un entorno de muy bajo riesgo donde puedes darte a ti mismo SOL (el token de SOLANA).
Antes de conectarnos a la devnet, necesitaremos realizar unos pasos para crear nuestro directorio e instalar las librerías principales.
mkdir SolanaNFT
cd SolanaNFT
touch index.js
npm i @solana/web3.js @solana/spl-token
Esta secuencia de comandos creará una nueva carpeta con el nombre SolanaNFT, entrar a esa nueva carpeta, crear un archivo llamado index.js e instalar dos librerías: @solana/web3.js @solana/spl-token
Con esto hecho, podemos comenzar a escribir un poco de Javascript para conectarnos a Solana! En el siguiente código, podemos observar cómo conectarnos Solana.
var web3 = require('@solana/web3.js');
var splToken = require('@solana/spl-token');
(async () => {
// Conectar al cluster
var connection = new web3.Connection(
web3.clusterApiUrl("devnet"),
'confirmed',
);
})
En las primeras dos líneas, estamos importando las librerías que instalamos al principio.
En la función, puedes ver que creamos una nueva instancia connection, acepta dos argumentos, el primero es la URL donde apunta a la red de Solana. En este caso, utilizamos un método muy conveniente web3.clusterApiUrl("devnet") para apuntar hacia la devnet de Solana.
Con la conexión establecida, ahora podemos crear el NFT y realizar los demás pasos necesarios.
Creando el NFT
Esta es la parte divertida! La novedad que está barriendo a toda la comunidad, el único e incomparable NFT! NFT, la abreviación para Non Fungible Token (Token no fungible), es un hash criptográfico que es único e irreplicable. Cuando se crea un NFT, es muy similar a crear un ERC20. Sin embargo, la diferencia primordial es que solamente se puede crear ese NFT una sola vez.
Para crear nuestro propio NFT, vamos a tener que replicar una serie de pasos. Podemos ver esta lista ahora y luego introducirnos a como programarla.
Lo que necesitaremos hacer:
- Crear una cuenta con una billetera para crear el NFT.
- Crear una cuenta con una billetera para enviarle el NFT.
- Crear el NFT y enviarlo.
Nota: Cada uno de los bloques de código van debajo del anterior, todo dentro de la función asíncrona.
Por lo general, el principio es un buen lugar para empezar. Comenzando por la creación de la wallet y la creación del NFT
// Generar una nueva wallet y generar nuevo SOL para esa wallet.
var fromWallet = web3.Keypair.generate();
var fromAirdropSignature = await connection.requestAirdrop(
fromWallet.publicKey,
web3.LAMPORTS_PER_SOL,
);
// Esperar por la confirmación de la generación de SOL hacia la wallet
while (true) {
const { value: statuses } = await connection.getSignatureStatuses([fromAirdropSignature]);
if (statuses[0] && statuses[0].confirmationStatus === 'confirmed' || statuses[0].confirmationStatus === 'finalized') {
break;
}
await new Promise(resolve => setTimeout(resolve, 1000));
}
// Crear un nuevo NFT
let mint = await splToken.Token.createMint(
connection,
fromWallet,
fromWallet.publicKey,
null,
9,
splToken.TOKEN_PROGRAM_ID,
);
// Obtener la cuenta del token desde la variable fromWallet que representa la dirección en Solana, si no existe, la crea
let fromTokenAccount = await mint.getOrCreateAssociatedAccountInfo(
fromWallet.publicKey,
);
He realizado un comentario en cada parte del código, pero vamos a revisar cada método y profundizar en los detalles sobre qué parámetros hay y cual es la función que cumplen.
- fromWallet - Crea un nuevo par de llaves públicas y privadas con el método Keypair.generate()
- fromAirDropSignature - El método requestAirdrop() toma una llave pública, una cantidad de lamports en SOL que quieres recibir. Lamports es el equivalente al wei de Ethereum pero en Solana, es la cantidad más pequeña en la que puede dividirse SOL. La mayoría de los métodos que requieren una cantidad, lo harán en lamports. En nuestro caso, LAMPORTS_PER_SOL es una constante que representa 1 SOL en lamports. Se espera que la transacción se confirme antes de continuar.
- mint - La función createMint es la que se encarga de crear nuestro token. Recibe 6 argumentos.
- La conexión con la red Solana (connection)
- La cuenta que pagará las comisiones (fromWallet)
- La llave pública de la cuenta que tiene la autoridad para mintear (generar) los tokens de este tipo (fromWallet.publicKey)
- La llave pública de la cuenta que tiene la autoridad para congelar los tokens de este tipo. Este argumento es opcional (null)
- El 'program id' del token, puedes leer mucho mas sobre que son estos 'program id' aqui
- fromTokenAccount - Esto crea o pide la cuenta asociada a la llave pública fromWallet.publicKey. Puedes ver la cadena de custodia como: NFT reside en la cuenta, y tu billetera (wallet) es dueña de esa cuenta.
Cadena de custodia: Llaves -> Wallet -> Cuenta
Con esto ya revisado, podemos movernos hacia el paso 2!
Ya tenemos una cuenta para enviar los NFT, ahora necesitamos una cuenta para recibir con los NFT.
Vamos al código para lograr esto:
// Generar una nueva wallet para recibir el recién creado token
var toWallet = web3.Keypair.generate();
// Obtener la cuenta del token de la direccion "toWallet", si no existe, se crea
var toTokenAccount = await mint.getOrCreateAssociatedAccountInfo(
toWallet.publicKey,
);
No hemos hecho demasiado en estos pasos. Repetimos los métodos que usamos anteriormente, por lo tanto, no voy a entrar en detalles aquí. El bloque de código anterior crea una wallet con una juego separado de llaves públicas/privadas y también, crea una nueva cuenta que está enlazada a nuestra variable mint.
Con estos dos pasos completados, podemos movernos hacia el paso número 3.
Es momento de crear de mintear el NFT y enviarlo!
// Minteando 1 nuevo token hacia "fromTokenAccount"
await mint.mintTo(
fromTokenAccount.address, //donde va a ir
fromWallet.publicKey, // quien tiene la autoridad de crear el token
[], // multisig
1000000000, // Cuanto
);
await mint.setAuthority(
mint.publicKey,
null,
"MintTokens",
fromWallet.publicKey,
[]
)
// Crear la transacción
var transaction = new web3.Transaction().add(
splToken.Token.createTransferInstruction(
splToken.TOKEN_PROGRAM_ID,
fromTokenAccount.address,
toTokenAccount.address,
fromWallet.publicKey,
[],
1,
),
);
// Firmar la transacción, emitirla y confirmar que se ha realizado con éxito
var signature = await web3.
sendAndConfirmTransaction(
connection,
transaction,
[fromWallet],
{commitment: 'confirmed'},
);
console.log('SIGNATURE', signature);
¡Espectacular! Dos nuevos métodos se encargan de la lógica para crear el NFT y los permisos del token. Los metodos sendAndConfirmTransaction() y Transaction().add() ya han sido explicados anteriormente en una guia anterior, si no estas familiarizado con esta guia, aqui la dejo: How to send a transaction in Solana, puede que quieras observar esta guia un poco para ver de que se trata.
Entonces, hay dos métodos para explicar, empecemos:
- mintTo() - Este método toma el token creado y crea algunos. Acepta 4 argumentos:
- El destino: es la dirección de la cuenta que va a recibir el token (fromTokenAccount.address) b. Es la llave pública de quien tiene autoridad sobre el token. (fromWallet.publicKey) c. Aquí es donde puedes pasar múltiples direcciones que firman la transacción, si tienes configurado el token para que sea multicuenta. En nuestro caso, no es así, por lo tanto pasamos un array vacío. d. Cuántos tokens queremos enviar. Como tenemos 9 decimales en este token en particular, estamos enviado exactamente 1 token a la dirección. (1000000000)
- setAuthority() - Esta es la parte más crucial de todo este proceso. Esta función va a revocar el privilegio para crear tokens y asegurarse de que no podamos crear más token adicionales de este tipo. Esta acción no se puede revertir y toma 5 argumentos:
- La cuenta del token (mint.publicKey) b. La nueva autoridad (null) c. El tipo de autoridad que la cuenta tiene actualmente (MintTokens) d. La llave pública de quien guarda actualmente el token (fromWallet.publicKey) e. Una colección de cuentas que pueden firmar. En nuestro caso, un array vacío. ([])
Con todo esto cubierto, la unica accion que nos queda por realizar es mirar el Explorador de Solana en Devnet
Si observas un poco más abajo, puedes ver como la cuenta tiene ahora exactamente 1 token y como hemos deshabilitado la posibilidad de crear nuevos tokens, ahora representa un NFT. Es oficialmente un token único en sí mismo!
Para evitar estar copiando cada bloque de código, voy a incluir uno con todo el código junto, por si acaso llegas a tener un inconveniente para poner todo junto
var web3 = require('@solana/web3.js');
var splToken = require('@solana/spl-token');
(async () => {
// Connect to cluster
var connection = new web3.Connection(
web3.clusterApiUrl("devnet"),
'confirmed',
);
// Generate a new wallet keypair and airdrop SOL
var fromWallet = web3.Keypair.generate();
var fromAirdropSignature = await connection.requestAirdrop(
fromWallet.publicKey,
web3.LAMPORTS_PER_SOL,
);
//wait for airdrop confirmation
while (true) {
const { value: statuses } = await connection.getSignatureStatuses([fromAirdropSignature]);
if (statuses[0] && statuses[0].confirmationStatus === 'confirmed' || statuses[0].confirmationStatus === 'finalized') {
break;
}
await new Promise(resolve => setTimeout(resolve, 1000));
}
//create new token mint
let mint = await splToken.Token.createMint(
connection,
fromWallet,
fromWallet.publicKey,
null,
9,
splToken.TOKEN_PROGRAM_ID,
);
//get the token account of the fromWallet Solana address, if it does not exist, create it
let fromTokenAccount = await mint.getOrCreateAssociatedAccountInfo(
fromWallet.publicKey,
);
// Generate a new wallet to receive newly minted token
var toWallet = web3.Keypair.generate();
//get the token account of the toWallet Solana address, if it does not exist, create it
var toTokenAccount = await mint.getOrCreateAssociatedAccountInfo(
toWallet.publicKey,
);
//minting 1 new token to the "fromTokenAccount" account we just returned/created
await mint.mintTo(
fromTokenAccount.address, //who it goes to
fromWallet.publicKey, // minting authority
[], // multisig
1000000000, // how many
);
await mint.setAuthority(
mint.publicKey,
null,
"MintTokens",
fromWallet.publicKey,
[]
)
// Add token transfer instructions to transaction
var transaction = new web3.Transaction().add(
splToken.Token.createTransferInstruction(
splToken.TOKEN_PROGRAM_ID,
fromTokenAccount.address,
toTokenAccount.address,
fromWallet.publicKey,
[],
1,
),
);
// Sign transaction, broadcast, and confirm
var signature = await web3.sendAndConfirmTransaction(
connection,
transaction,
[fromWallet],
{commitment: 'confirmed'},
);
console.log('SIGNATURE', signature);
})();
Conclusión
Si has llegado hasta aquí, has aprendido algunas cosas de este tutorial y te has divertido un poco con nuestras guías de Solana, así que, felicitaciones! Siguiendo esta guía, has creado un NFT en la Blockchain de Solana exitosamente. El siguiente paso que deberás seguir, es enlazar este token único e irrepetible con algo específico. En el mercado actual, esto es comúnmente una imagen que ha sido generada aleatoriamente con varias propiedades o una pieza única de arte. Si quieres aprender como hacer exactamente esto, puedes hacerlo en este tutorial!
Suscribete a nuestro newsletter para más artículos y guías en Ethereum. Si tienes algún tipo de comentario, se libre de comentarlos en nuestro Twitter. Siempre puedes hablar con nosotros en nuestro servidor de Discord, puedes encontrar algunos de los más geniales desarrolladores.