En este tutorial, nuestro principal objetivo es guiarte en la creación de tu propio token personalizado en Solana.
Un token es una unidad de valor digital que representa activos o derechos en una blockchain o tecnología de registro distribuido (DLT). Son digitales, programables, transferibles y pueden representar una amplia variedad de activos, desde dinero hasta activos únicos como obras de arte. Los tokens desempeñan papeles cruciales en las blockchains, incluyendo acceso a servicios, votaciones en gobernanza, recompensas en DeFi y mucho más. Son la base de innovaciones en las tecnologías blockchain y en la economía digital.
En general, los tokens tienen como finalidad la representación de posesión de diversos activos, ya sean valores financieros o activos digitales. Para crear un token con éxito, es fundamental cumplir con algunos requisitos esenciales, que incluyen la capacidad de crear y configurar tokens, realizar operaciones de minting para generar nuevos tokens y efectuar transferencias.
Los programas Solana son esencialmente contratos inteligentes o aplicaciones descentralizadas (dApps) que se ejecutan en la red Solana. Están escritos en el lenguaje de programación Rust y compilados en formato binario. Un Token Program es un programa estándar en la blockchain Solana que define una implementación común para tokens fungibles y no fungibles. El Token Program es responsable de la creación, gestión y operaciones relacionadas con tokens en la red, permitiendo la creación y operación eficiente de activos digitales.
El primer paso para iniciar la construcción de un token en Solana es la preparación del entorno de desarrollo. Esto implica la creación de un directorio de proyecto y la instalación de las bibliotecas necesarias. Aquí tienes un resumen del paso inicial:
mkdir token-spl
npm init
Para interactuar con tokens en Solana, necesitarás instalar las bibliotecas apropiadas. Usa los siguientes comandos npm para instalar las bibliotecas requeridas:
npm install @solana/spl-token
npm install @solana/web3.js
npm install bs58
npm install dotenv
Con estos pasos iniciales completados, estás listo para comenzar a construir tu token en la blockchain Solana. El directorio del proyecto está configurado, y tienes las bibliotecas necesarias a tu disposición para facilitar el desarrollo. Ahora, puedes proceder con la configuración, desarrollo e implementación de tu token personalizado.
La Devnet es la red de desarrollo de Solana, que permite probar y desarrollar aplicaciones y scripts sin gastar activos reales. Para obtenerla:
solana-cli
.
solana config set --url https://api.devnet.solana.com
Ahora puedes crear un archivo JavaScript para el script y configurar el package.json
para hacerlo ejecutable:
airdrop.js
en el directorio de tu proyecto. Este archivo contendrá el código JavaScript para el airdrop.
// Decodifica la clave privada de la variable de entorno PRIVATE_KEY_1 usando el formato base58
var secretKey1 = bs58.decode(process.env.PRIVATE_KEY_1)
// Crea un par de claves (clave pública y clave privada) a partir de la clave privada decodificada
const key = Keypair.fromSecretKey(secretKey1)
// Imprime la clave pública en formato base58 en la consola
console.log("KEY", key.publicKey.toBase58())
// Crea una conexión con la red Solana (en el entorno de desarrollo Devnet)
const connection = new Connection(
clusterApiUrl('devnet'),
'confirmed'
)
// Solicita un airdrop (distribución gratuita de Solana) para la clave pública de la cuenta
const airdropSignature = await connection.requestAirdrop(
key.publicKey,
LAMPORTS_PER_SOL, // Cantidad de lamports (la unidad más pequeña de Solana)
)
// Obtiene el hash del bloque más reciente en la red Solana
const latestBlockHash = await prog.provider.connection.getLatestBlockhash()
// Confirma la transacción del airdrop, especificando el bloque, la altura del bloque y la firma
await prog.provider.connection.confirmTransaction({
blockhash: latestBlockHash.blockhash,
lastValidBlockHeight: latestBlockHash.lastValidBlockHeight,
signature: airdropSignature,
})
package.json
en el directorio de tu proyecto.
package.json
, encuentra la sección "scripts"
y agrega un nuevo script llamado "airdrop" que ejecutará el archivo airdrop.js
:
"scripts": {
"airdrop": "node airdrop.js"
}
Ahora que has configurado el script, puedes ejecutarlo fácilmente usando npm
:
package.json
.
npm run airdrop
Esto ejecutará el script airdrop.js
y realizará las operaciones especificadas en el código del script. Asegúrate de que el script esté configurado correctamente para ejecutar las acciones deseadas, como airdrop de tokens, y que tu cuenta Solana en Devnet tenga los recursos necesarios para realizar las transacciones. Nota: Esta configuración puede emplearse para la ejecución de los próximos scripts en el proyecto de creación del token.
La creación de un token en la red Solana es un proceso detallado que implica varias etapas.
// Decodifica la clave privada de la variable de entorno PRIVATE_KEY_1 usando el formato base58
var secretKey1 = bs58.decode(process.env.PRIVATE_KEY_1)
// Crea un par de claves (clave pública y clave privada) a partir de la clave privada decodificada
const key = Keypair.fromSecretKey(secretKey1)
// Imprime la clave pública en formato base58 en la consola
console.log("KEY", key.publicKey.toBase58())
// Crea una conexión con la red Solana (en el entorno de desarrollo Devnet)
const connection = new Connection(
clusterApiUrl('devnet'),
'confirmed'
)
// Obtiene el saldo de la cuenta asociada a la clave pública
const vl = await connection.getBalance(key.publicKey)
console.log("Balance", vl)
// Define el "pagador" de la creación del token
const payer = key
// Define la autoridad de creación del token (mintAuthority) y la autoridad de congelamiento (freezeAuthority) como la misma clave
const mintAuthority = key
const freezeAuthority = key
// Crea un token fungible con 9 decimales (para cumplir con el estándar de la CLI)
const mintToken = await token.createMint(
connection,
payer,
mintAuthority.publicKey,
freezeAuthority.publicKey,
9
)
El código es un ejemplo de cómo crear un token fungible utilizando SPL Token, una biblioteca de código abierto para Solana. Aquí tienes una descripción resumida de lo que está ocurriendo en este código:
createMint
: demuestra la creación del token fungible. Para ello, estás utilizando la función createMint
, que requiere varios parámetros: connection
: La conexión a la red Solana. payer
: La cuenta que pagará las tarifas de la transacción. mintAuthority.publicKey
: La clave pública de la autoridad de creación del token. freezeAuthority.publicKey
: La clave pública de la autoridad de congelamiento (opcional). 9
: El número de decimales del token.
connection
: La conexión a la red Solana.
payer
: La cuenta que pagará las tarifas de la transacción.
mintAuthority.publicKey
: La clave pública de la autoridad de creación del token.
freezeAuthority.publicKey
: La clave pública de la autoridad de congelamiento (opcional).
9
: El número de decimales del token.
Los tokens, cuando se crean inicialmente mediante spl-token, no tienen “supply”.
Recuerda que este es un ejemplo simplificado. La creación y gestión de tokens en Solana implica más detalles, como la gestión de autoridades, configuración de políticas de emisión y seguridad. Asegúrate de entender completamente el proceso y sus implicaciones antes de crear tokens en la red Solana.
Realizar el "mint" (emisión) de tokens en la red Solana es un paso fundamental para crear y distribuir estos activos digitales.
// Decodifica la clave privada de la variable de entorno PRIVATE_KEY_1 usando el formato base58
var secretKey1 = bs58.decode(process.env.PRIVATE_KEY_1)
// Crea un par de claves (clave pública y clave privada) a partir de la clave privada decodificada
const key = web3.Keypair.fromSecretKey(secretKey1)
// Imprime la clave pública en formato base58 en la consola
console.log("KEY", key.publicKey.toBase58())
// Crea una conexión con la red Solana (en el entorno de desarrollo Devnet)
const connection = new web3.Connection(
web3.clusterApiUrl('devnet'),
'confirmed'
)
// Obtiene el saldo de la cuenta asociada a la clave pública
const vl = await connection.getBalance(key.publicKey)
console.log("Balance", vl)
// Define la cuenta del usuario como la clave pública de la clave
const user = key
// Define la cuenta de destino como la clave pública de la clave
const to = key.publicKey
// Define la dirección de la cuenta token
let tokenAddr = '9RE5hEQV5SLRwr7PANryxYMZsootEkY5txxJyRNU4FYR'
const tokenAccount = new web3.PublicKey(tokenAddr)
// Obtiene información sobre el token asociado a la dirección de la cuenta token
const mintInfo = await token.getMint(
connection,
tokenAccount
)
// Crea u obtiene la cuenta de token asociada a la cuenta del usuario
const tokenMint = await token.getOrCreateAssociatedTokenAccount(
connection,
user,
mintInfo.address,
key.publicKey
)
// Define la autoridad de minting del token como la cuenta del usuario
const mintAuthority = user
// Realiza el minting de tokens en la cuenta del usuario
await token.mintTo(
connection,
user,
mintInfo.address,
tokenMint.address,
mintAuthority,
100000000000 // debido a la configuración de 9 decimales para el token
)
El código anterior demuestra la ejecución de este proceso, y aquí tienes una descripción de lo que está ocurriendo:
Para añadir 1000 tokens a la cuenta “tokenMint.address”, es necesario ejecutar la operación de "minting" con los siguientes pasos:
Antes de realizar el minting, es importante crear una cuenta para mantener el saldo del nuevo token. En este caso, la cuenta de saldo es "tokenMint.address".
El código utiliza la función token.mintTo
para crear 1000 tokens y agregarlos a la cuenta "tokenMint.address". Esto implica los siguientes parámetros:
connection
: La conexión a la red Solana.
user
: La cuenta que va a pagar la transacción.
mintInfo.address
: La dirección del mint (token) a ser creada.
tokenMint.address
: La dirección destino de los tokens después del mint (token que será emitido).
mintAuthority
: La autoridad que controla el minting.
100000000000
: El número de tokens a ser creados, considerando que el token posee 9 decimales.
Después de la ejecución de este código, la cuenta "tokenMint.address" tendrá 1000 tokens mintados en ella, listos para ser usados o distribuidos según sea necesario.
El minting de tokens es un procedimiento fundamental para crear activos digitales en Solana, y esta operación permite el control y distribución de estos activos de forma eficaz en la red.
La creación de metadatos para tokens Solana con Metaplex es un proceso esencial para asociar información y características específicas a los activos digitales que estás emitiendo. A continuación, se resumen los pasos para realizar esta tarea:
Paso 1: Importación de la Clave Privada
Paso 2: Instalación de Paquetes Necesarios
Para crear los metadatos del token con Metaplex, necesitarás instalar algunas dependencias:
npm install @metaplex-foundation/js
npm install typescript ts-node
Paso 3: Uso de Metaplex para la Creación de Metadatos
Ahora que tienes las dependencias instaladas, puedes usar Metaplex para crear los metadatos del token:
.ts
) que utilice las funcionalidades de Metaplex para crear los metadatos del token. Puedes crear un nuevo archivo, por ejemplo, metadata.ts
, y escribir el código necesario en él. La creación de metadatos puede involucrar configuraciones específicas, como imágenes, descripciones y otros detalles asociados a tus tokens. Primero verifica en tu wallet o en Solscan cómo está representado tu token.
En el código siguiente, estás creando una cuenta de metadatos asociada a un token en Solana y cargando información sobre el token, como nombre, símbolo, descripción e imagen. Los pasos incluyen la configuración de información del token, la carga de una imagen, la carga de metadatos y la creación de la cuenta de metadatos en la blockchain.
// Decodifica la clave privada de la variable de entorno PRIVATE_KEY_1
var secretKey = bs58.decode(process.env.PRIVATE_KEY_1 as string)
// Crea un objeto Keypair a partir de la clave privada decodificada
const user = web3.Keypair.fromSecretKey(secretKey)
// Imprime la clave pública del usuario
console.log("KEY", user.publicKey.toBase58())
// Define información inicial del token (nombre, símbolo, descripción e imagen)
const MY_TOKEN_METADATA: UploadMetadataInput = {
name: "Happy",
symbol: "•‿•",
description: "Happy - distribute happiness",
image: "TO_UPDATE_LATER" // reemplaza con la URL pública de la imagen
}
// Crea un objeto ON_CHAIN_METADATA basado en la información inicial del token
const ON_CHAIN_METADATA = {
name: MY_TOKEN_METADATA.name,
symbol: MY_TOKEN_METADATA.symbol,
uri: 'TO_UPDATE_LATER',
sellerFeeBasisPoints: 0,
creators: null,
collection: null,
uses: null
} as DataV2
// Crea una conexión con la red Solana (en el entorno de desarrollo Devnet)
const connection = new web3.Connection(
web3.clusterApiUrl('devnet'),
'confirmed'
)
// Crea una instancia de Metaplex para interactuar con los contratos Metaplex
const metaplex = Metaplex.make(connection)
.use(keypairIdentity(user))
.use(bundlrStorage({
address: 'https://devnet.bundlr.network',
providerUrl: web3.clusterApiUrl('devnet'),
timeout: 60000,
}))
// Carga un archivo de imagen desde el sistema de archivos
const imageFile = "happy.png"
const buffer = fs.readFileSync("img/" + imageFile)
// Convierte el buffer de la imagen en un formato compatible con Metaplex
const file = toMetaplexFile(buffer, imageFile)
// Carga la imagen en un servicio de almacenamiento y obtiene el URI de la imagen
const imageUri = await metaplex.storage().upload(file)
console.log("image uri:", imageUri)
// Actualiza el URI de la imagen en los metadatos del token
MY_TOKEN_METADATA.image = imageUri
// Carga los metadatos y obtiene el URI de los metadatos
const metaURI = await metaplex.nfts().uploadMetadata(MY_TOKEN_METADATA)
console.log(`Arweave URL: `, metaURI)
// Actualiza el URI de los metadatos ON_CHAIN_METADATA
ON_CHAIN_METADATA.uri = metaURI.uri
// Define la dirección de la cuenta del token
let mitTokenAddr = '9RE5hEQV5SLRwr7PANryxYMZsootEkY5txxJyRNU4FYR'
const mintAccount = new web3.PublicKey(mitTokenAddr)
// Obtiene información sobre la cuenta del token
const mintKeypair = await getMint(
connection,
mintAccount
)
console.log(mintKeypair.address)
// Obtiene información sobre la cuenta PDA (Program Derived Address) de los metadatos
const metadataPDA = await metaplex.nfts().pdas().metadata({ mint: mintKeypair.address })
// Crea una transacción para crear una nueva cuenta de metadatos en la blockchain Solana
const createNewMetadataTransaction = new web3.Transaction().add(
createCreateMetadataAccountV3Instruction({
metadata: metadataPDA,
mint: mintKeypair.address,
mintAuthority: user.publicKey,
payer: user.publicKey,
updateAuthority: user.publicKey,
}, {
createMetadataAccountArgsV3: {
data: ON_CHAIN_METADATA,
isMutable: true,
collectionDetails: null
}
})
)
// Obtiene el bloque más reciente y define la transacción recentBlockhash
let { lastValidBlockHeight, blockhash } = await connection.getLatestBlockhash('finalized');
createNewMetadataTransaction.recentBlockhash = blockhash;
createNewMetadataTransaction.lastValidBlockHeight = lastValidBlockHeight;
createNewMetadataTransaction.feePayer = user.publicKey;
// Envía y confirma la transacción
const transactionId = await web3.sendAndConfirmTransaction(connection, createNewMetadataTransaction, [user]);
metadata.ts
, puedes ejecutarlo de la siguiente manera:
ts-node metadata.ts
Recuerda que la creación de metadatos puede involucrar configuraciones específicas, como imágenes, descripciones y otros detalles asociados a tus tokens. Asegúrate de seguir las directrices y documentación de Metaplex para crear metadatos precisos y completos para tus tokens Solana.
La transferencia de tokens en la red Solana implica la movilización de activos digitales de una cuenta a otra. Para realizar este proceso, puedes seguir los siguientes pasos:
Identificación de las Cuentas
Para iniciar una transferencia de tokens, necesitas tener la siguiente información:
Creación de la Transacción
Necesitarás crear una transacción que especifique la transferencia de tokens. Esto implica la construcción de una transacción Solana que incluya la información necesaria:
También puedes incluir una tarifa de transacción (fee) para pagar por los recursos de red utilizados en la transferencia.
Firma de la Transacción
La transacción debe ser firmada con la clave privada de la cuenta de origen para autenticar la operación. Esto asegura que solo el propietario de la cuenta pueda efectuar la transferencia.
Envío de la Transacción
La transacción firmada es enviada a la red Solana para ser procesada. Puedes usar solana-web3.js
para enviar la transacción a la red.
Confirmación de la Transacción
La red Solana procesará la transacción y, una vez confirmada, la cantidad especificada de tokens será transferida de la cuenta de origen a la cuenta de destino. Puedes verificar el estado de la transacción para garantizar que la transferencia se haya completado con éxito.
Un ejemplo
Ahora, ejemplificaré el uso de los métodos de transferencia y la creación de cuentas asociadas. Con la biblioteca SPL-Token, todos los pasos detallados anteriormente serán simplificados y ejecutados internamente en el método "transfer".
Primero, el receptor debe crear una cuenta de token asociada para el tipo Token. Esto es necesario para recibir los tokens. El destinatario obtiene la dirección de la billetera y la proporciona al remitente. El código a continuación demuestra cómo crear estas cuentas asociadas:
// Define el valor de la cantidad que deseas transferir (50 tokens, en este caso)
let amount = 50 * 10 ** mintInfo.decimals
// Crea la cuenta de token asociada para el remitente
const fromTokenAccount = await token.getOrCreateAssociatedTokenAccount(
solConnection,
from,
mint,
from.publicKey
)
// Crea la cuenta de token asociada para el destinatario (proporciona la dirección toPublicKey)
const toTokenAccount = await token.getOrCreateAssociatedTokenAccount(
solConnection,
from,
mint,
toPublicKey
)
Una vez que las cuentas de token asociadas hayan sido creadas, puedes proceder con la transferencia de los tokens. El código a continuación demuestra cómo realizar la transferencia:
// Realiza la transferencia de los tokens de la cuenta "fromTokenAccount" a la cuenta "toTokenAccount"
let signature = await token.transfer(
solConnection,
from,
fromTokenAccount.address,
toTokenAccount.address,
from.publicKey,
amount
)
En este ejemplo, la función token.transfer
está siendo utilizada para efectuar la transferencia de los tokens de la cuenta "fromTokenAccount" a la cuenta "toTokenAccount". Asegúrate de que las cuentas asociadas hayan sido configuradas correctamente antes de ejecutar la transferencia. La variable "signature" contendrá la firma de la transacción tras la finalización de la transferencia.
En este código, utilizamos la biblioteca Solana JavaScript (@solana/web3.js) para interactuar con la blockchain Solana y consultar el saldo de tokens asociados a la clave pública key.publicKey
.
// Obtiene todas las cuentas de tokens asociadas a la clave pública
const tokenAccounts = await connection.getTokenAccountsByOwner(
key.publicKey,
{
programId: token.TOKEN_PROGRAM_ID, // Programa de token estándar de Solana
}
)
// Imprime un encabezado para la lista de tokens y saldos
console.log("Token Balance");
console.log("------------------------------------------------------------");
// Itera sobre todas las cuentas de tokens devueltas
tokenAccounts.value.forEach((tokenAccount) => {
// Decodifica los datos de la cuenta para obtener información sobre el token
const accountData = token.AccountLayout.decode(tokenAccount.account.data);
// Imprime la dirección del token (mint) y el saldo de la cuenta
console.log(`${new web3.PublicKey(accountData.mint)} ${accountData.amount}`);
})
Cómo funciona el código:
const tokenAccounts = await connection.getTokenAccountsByOwner(key.publicKey, { programId: token.TOKEN_PROGRAM_ID })
: Esta línea solicita a la red Solana información sobre todas las cuentas de tokens asociadas a la clave pública especificada. El parámetro programId
asegura que solo se devuelvan las cuentas relacionadas con el programa de token.
tokenAccounts.value.forEach((tokenAccount) => { ... }
: Iteramos por las cuentas de tokens devueltas y realizamos las siguientes acciones para cada una de ellas:
a. Decodificamos los datos de la cuenta usando token.AccountLayout.decode(tokenAccount.account.data)
. Esto nos permite obtener información sobre el token, incluyendo el mint (tipo de token) y el saldo.
b. Imprimimos la dirección del token (mint) y el saldo de la cuenta en la tabla formateada.
En este tutorial, exploramos la creación de un token en la blockchain Solana, utilizando la biblioteca SPL-Token. Aprendimos a crear tokens, configurar sus propiedades y realizar transferencias. Sin embargo, este es solo el comienzo. Solana ofrece innumerables oportunidades para la innovación, y puedes explorar aún más, creando aplicaciones personalizadas, tokens no fungibles únicos y mucho más. Continúa aprendiendo, experimentando y contribuyendo a la evolución de la blockchain Solana.
Jorge García
Fullstack developer