Ir al contenido principal

Uso de la extensión «Scaled UI Amount Token» en Solana

Actualizado el
12 de noviembre de 2025

41 minutos de lectura

Esta guía está disponible en las versiones de Solana Web3.js (versión heredada 1.x) y Solana Kit (v. 2.x). Selecciona la pestaña correspondiente para ver los fragmentos de código y las instrucciones de la biblioteca que prefieras:

Resumen

El programa Solana Token-2022 introdujo potentes ampliaciones que mejoran la funcionalidad de los tokens más allá del programa SPL Token original. Una de estas ampliaciones es la «Scaled UI Amount», que permite a los emisores de tokens definir un multiplicador que influye en cómo se muestran los saldos de los tokens a los usuarios sin modificar los importes brutos subyacentes almacenados en la cadena. Esta ampliación permite potentes casos de uso, entre los que se incluyen:


  • Divisiones y agrupaciones de acciones
  • Tokens que generan rendimiento y en los que se puede ver cómo se acumulan los intereses
  • Dividendos y repartos
  • Reajuste de los tokens que modifican el suministro total

Para desarrollar con la extensión «Scaled UI Amount», los desarrolladores deben comprender cómo funciona y cómo implementarla en sus aplicaciones. Esta guía te guiará a lo largo del proceso de creación de un token con la extensión «Scaled UI Amount», la emisión de tokens, su transferencia y la actualización del multiplicador de la cantidad en la interfaz de usuario para ver cómo afecta a los saldos mostrados.

En esta guía, crearemos un script de demostración completo que:


  1. Crea un token Token-2022 con la extensión «Scaled UI Amount»
  2. Acredeita a un titular
  3. Transfiere tokens entre cuentas
  4. Actualiza el multiplicador de la interfaz de usuario
  5. Muestra cómo varía el importe que se muestra en la interfaz de usuario, mientras que los saldos brutos se mantienen constantes
  6. Crea y transfiere tokens adicionales para observar los efectos del multiplicador actualizado

El objetivo final será generar una tabla resumen que muestre claramente la relación entre las cantidades brutas y las de la interfaz de usuario en cada paso de la demostración:

=== RESUMEN DE LA DEMOSTRACIÓN ===
┌─────────┬───────────────────────────┬──────────────┬────────────┬─────────────┬────────────┐
│ (índice) │ Paso │ Marca de tiempo │ Multiplicador │ Saldo bruto │ Saldo de la interfaz de usuario │
├─────────┼───────────────────────────┼──────────────┼────────────┼─────────────┼────────────┤
│ 0 │ «Configuración inicial» │ «15:02:16» │ 1 │ «n/a» │ «n/a» │
│ 1 │ «Tras la emisión inicial» │ «15:02:17» │ 1 │ «100000000» │ «100» │
│ 2 │ «Tras la transferencia n.º 1» │ «3:02:18 p. m.» │ 1 │ «90000000» │ «90» │
│ 3 │ «Tras la actualización del multiplicador» │ «3:02:19 p. m.» │ 2 │ «90000000» │ «180» │
│ 4 │ «Tras la segunda emisión» │ «3:02:20 p. m.» │ 2 │ «190000000» │ «380» │
│ 5 │ «Tras la transferencia n.º 2» │ «3:02:21 p. m.» │ 2 │ «180000000» │ «360» │
└─────────┴───────────────────────────┴──────────────┴────────────┴─────────────┴────────────┘

¡Empecemos!

Requisitos previos

Antes de empezar este tutorial, asegúrate de que dispones de:


  • Node.js (v22 o posterior)
  • Solana CLI v 2.2.x o superior (Nota: si ya tienes una versión anterior, puedes actualizarla con agave-install init 2.2.14 o la versión más reciente, la que sea)
  • Conocimientos básicos sobre Solana y TypeScript
  • Conocimiento del programa Solana Token-2022 y de los conceptos relacionados con los tokens SPL

Comprender la extensión «Scaled UI Amount»

Antes de entrar en detalles sobre la implementación, veamos qué es la extensión «Scaled UI Amount» y cómo funciona. La extensión «Scaled UI Amount» define un multiplicador que se aplica a la cantidad bruta de tokens para determinar la cantidad que se muestra a los usuarios en la interfaz de usuario. Esto permite una economía de tokens flexible sin modificar las cantidades brutas subyacentes.

Entre bastidores

La extensión también permite actualizar el multiplicador en el futuro, lo que da lugar a funciones como aumentos graduales o cambios programados. A continuación se muestra la estructura de la configuración de «Scaled UI Amount»:

pub struct ScaledUiAmountConfig {
pub authority: OptionalNonZeroPubkey,
pub multiplier: PodF64,
pub new_multiplier_effective_timestamp: UnixTimestamp,
pub new_multiplier: PodF64,
}

(Fuente: Programa Solana Token-2022)

La configuración incluye:

  • autoridad: Clave pública autorizada que puede establecer el importe de la escalación
  • multiplicador: El multiplicador actual aplicado al importe bruto
  • marca_de_tiempo_del_nuevo_multiplicador_efectivo: La fecha y hora en la que entra en vigor el nuevo multiplicador
  • nuevo_multiplicador: El nuevo multiplicador que se aplicará una vez que se alcance la marca de tiempo efectiva

La extensión «Scaled UI Amount» introduce dos nuevas instrucciones:

  • inicializar: Inicializa la extensión «Scaled UI Amount» para una casa de moneda (src)
  • multiplicador_de_actualización: Actualiza el multiplicador de una moneda (src)

Conceptos clave

La extensión «Scaled UI Amount» introduce varios conceptos clave que es importante comprender:

  1. Importe bruto frente a importe de la prestación por desempleo:

    • La «cantidad bruta» es el número real de tokens almacenados en la cadena.
    • Importe de la prestación por desempleo es lo que ven los usuarios, y se calcula como Importe bruto × Multiplicador actual
  2. Multiplicador:

    • Se establece al crear el token
    • Puede ser actualizado por la autoridad del token
    • Se puede programar para futuras actualizaciones
  3. Cambios en el importe de la prestación por desempleo:

    • Cuando cambia el multiplicador, el importe que aparece en la interfaz de usuario cambia proporcionalmente.
    • Las cantidades brutas no varían

Nuestra demostración mostrará cómo funcionan estos conceptos en la práctica.

Aplicaciones en la vida real

A continuación se muestran algunas aplicaciones prácticas de la extensión «Scaled UI Amount»:

Caso de usoDescripciónEnfoque de implementación
Divisiones y agrupaciones de accionesDivisión de las acciones existentes en varias acciones o en acciones fraccionariasAjustar el multiplicador para que refleje el nuevo número de acciones
Tokens que generan rendimientoTokens que muestran visualmente cómo se acumulan los intereses con el paso del tiempoAumentar gradualmente el multiplicador en función de la tasa de rendimiento
Distribución de dividendosDistribución de dividendos a los titulares de tokensAjustar el multiplicador para reflejar el reparto de dividendos
Cambios en la denominaciónConversión entre diferentes unidades de medida de un mismo activoCambia el multiplicador para que refleje la nueva denominación
Reajuste de los tokensTokens cuyo suministro total aumenta o disminuye en función de factores externos (como las stablecoins algorítmicas)Ajustar periódicamente el multiplicador para reflejar los cambios en la oferta

Repercusiones en los proyectos en curso

La implementación de la extensión «Scaled UI Amount» requiere un análisis minucioso de la arquitectura y la funcionalidad de tu aplicación. Aunque tu caso concreto pueda ser único, a continuación se indican algunas consideraciones comunes:


  • Consideraciones sobre el diseño de UI/UX: Las aplicaciones deben actualizarse para mostrar a los usuarios el importe de la interfaz de usuario escalado, al tiempo que se gestionan los importes sin procesar en el backend (se han añadido varios métodos útiles a la biblioteca de programas de tokens SPL, por ejemplo, amountToUiAmount, uiAmountToAmount)). Esto requiere un diseño cuidadoso de la experiencia de usuario (UX) para evitar la confusión de los usuarios, especialmente durante los cambios de multiplicador. Se recomienda añadir información emergente o indicadores cuando los tokens utilicen esta extensión.
  • Gestión de datos históricos: Los servicios deberían considerar la posibilidad de indexar tanto los importes brutos como los de la interfaz de usuario, así como los valores históricos de los multiplicadores, para mostrar correctamente el historial de transacciones y los gráficos de precios. Esto es especialmente importante en el caso de los tokens cuyos multiplicadores cambian con frecuencia.
  • Procesamiento de transacciones: Al procesar los datos introducidos por los usuarios para transferencias o intercambios, las aplicaciones deben convertir los importes de la interfaz de usuario (lo que introducen los usuarios) en importes sin procesar (los que utilizan los procesadores en cadena) antes de enviar las transacciones. Los problemas de redondeo deben resolverse redondeando siempre a la baja para evitar fallos en las transacciones.
  • Integración de fuentes de precios: Los servicios de precios deben proporcionar fuentes de precios tanto escaladas como no escaladas para adaptarse a las diferentes necesidades de los clientes. En el caso de los proveedores de datos de mercado, los cálculos de la oferta total y la capitalización bursátil deben tener en cuenta el multiplicador actual para mostrar información precisa.

Configuración del proyecto

¿Prefieres ir directamente al código? ¡Echa un vistazo a nuestro repositorio de ejemplos en GitHub para ver el código completo de esta guía!

Antes de empezar, recapitulemos lo que vamos a crear. Vamos a crear un script de demostración sencillo que:


  1. Crea un token Token-2022 con la extensión «Scaled UI Amount»
  2. Acredeita a un titular
  3. Transfiere tokens entre cuentas
  4. Actualiza el multiplicador de la interfaz de usuario
  5. Genera y transfiere tokens adicionales para observar los efectos del multiplicador actualizado
  6. Registra el estado en cada paso y muestra una tabla resumen en la que se refleja la relación entre el multiplicador, el importe bruto y el importe de la prestación por desempleo.

Empecemos por crear la estructura de nuestro proyecto:

mkdir solana-scaled-token-demo && cd solana-scaled-token-demo

Inicializar un nuevo proyecto de Node.js:

npm init -y

Instala las dependencias necesarias:

npm install @solana/web3.js@1 @solana/spl-token

Y otras dependencias de desarrollo:

npm install --save-dev typescript ts-node @types/node

Crear un tsconfig.json archivo:

{
"compilerOptions": {
"target": "es2020",
"module": "commonjs",
"lib": ["es2020"],
"declaration": true,
"outDir": "./dist",
"rootDir": "./",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true
},
"include": ["*.ts"],
"exclude": ["node_modules", "dist"]
}

Actualiza tu package.json scripts:

"scripts": {
"start": "ts-node token-creator.ts",
"build": "tsc"
}

Crea un directorio para almacenar los pares de claves:

mkdir -p keys

Crea nuevos pares de claves de Solana para el pagador, la autoridad de acuñación, el titular del token y la acuñación:

solana-keygen new -s --no-bip39-passphrase -o keys/payer.json && \
solana-keygen new -s --no-bip39-passphrase -o keys/mint-authority.json && \
solana-keygen new -s --no-bip39-passphrase -o keys/holder.json && \
solana-keygen new -s --no-bip39-passphrase -o keys/mint.json

Esto debería crear cuatro archivos de pares de claves en el claves directorio.

Aplicación

Vamos a crear nuestro token-creator.ts archivo y compilarlo paso a paso:

Importaciones y configuración

Empieza por las importaciones y la configuración necesarias:

import {
Connection,
Keypair,
LAMPORTS_PER_SOL,
PublicKey,
SystemProgram,
Transaction,
sendAndConfirmTransaction
} from '@solana/web3.js';

import {
ExtensionType,
TOKEN_2022_PROGRAM_ID,
createInitializeMintInstruction,
createInitializeScaledUiAmountConfigInstruction,
getMintLen,
getOrCreateAssociatedTokenAccount,
mintTo,
updateMultiplier,
getScaledUiAmountConfig,
unpackMint,
createTransferInstruction
} from '@solana/spl-token';

import * as fs from 'fs';
import * as path from 'path';

const CONFIG = {
DECIMAL_PLACES: 6,
INITIAL_UI_AMOUNT_MULTIPLIER: 1.0,
MODIFIED_UI_AMOUNT_MULTIPLIER: 2.0,
TOKEN_NAME: "Scaled Demo Token",
TOKEN_SYMBOL: "SDT",
MINT_AMOUNT: 100,
TRANSFER_AMOUNT: 10,
CONNECTION_URL: 'http://127.0.0.1:8899',
KEYPAIR_DIR: path.join(__dirname, 'keys')
};

Con esto se establece nuestra configuración básica, que incluye:

  • Parámetros del token (decimales, multiplicador, nombre, símbolo)
  • Importe a acuñar y transferir
  • Datos de conexión (para esta demostración utilizaremos nuestro validador de prueba local de Solana)
  • Directorio para almacenar pares de claves

Funciones de registro de estado

A continuación, vamos a añadir un sistema de registro de estado para realizar un seguimiento de los cambios a lo largo de nuestra demostración:

interface StatusLog {
step: string;
timestamp: string;
multiplier: number;
rawBalance: string;
uiBalance: string;
description: string;
}

const demoLogs: StatusLog[] = [];

async function getTokenMultiplier(
connection: Connection,
mintPublicKey: PublicKey
): Promise<number> {
const mintInfo = await connection.getAccountInfo(mintPublicKey);
if (!mintInfo) {
throw new Error(`Mint account not found: ${mintPublicKey.toString()}`);
}

const unpackedMint = unpackMint(mintPublicKey, mintInfo, TOKEN_2022_PROGRAM_ID);
const extensionData = getScaledUiAmountConfig(unpackedMint);
if (!extensionData) {
return 1.0; // Default if no extension data
} else {
const currentTime = Date.now();
// Solana times are in whole seconds (see Clock::get() etc)
if (Number(extensionData.newMultiplierEffectiveTimestamp) * 1000 < currentTime) {
return extensionData.newMultiplier;
} else {
return extensionData.multiplier;
}
}
}

async function getTokenBalance(
connection: Connection,
tokenAccount: PublicKey,
): Promise<{ rawAmount: string, uiAmount: string }> {
try {
const balanceDetail = await connection.getTokenAccountBalance(tokenAccount);
return {
rawAmount: balanceDetail.value.amount,
uiAmount: balanceDetail.value.uiAmountString || '0'
};
} catch (error) {
return {
rawAmount: 'n/a',
uiAmount: 'n/a'
};
}
}

async function logStatus(
connection: Connection,
step: string,
mintPublicKey: PublicKey,
tokenAccount: PublicKey | null,
description: string
): Promise<void> {
const now = new Date();
const timestamp = now.toLocaleTimeString();

const multiplier = await getTokenMultiplier(connection, mintPublicKey);

let rawBalance = 'n/a';
let uiBalance = 'n/a';

if (tokenAccount) {
const balance = await getTokenBalance(connection, tokenAccount);
rawBalance = balance.rawAmount;
uiBalance = balance.uiAmount;
}

demoLogs.push({
step,
timestamp,
multiplier,
rawBalance,
uiBalance,
description
});
}

function printSummaryTable(): void {
console.log("\n=== DEMONSTRATION SUMMARY ===");
console.table(demoLogs.map(log => ({
Step: log.step,
Timestamp: log.timestamp,
Multiplier: log.multiplier,
"Raw Balance": log.rawBalance,
"UI Balance": log.uiBalance
})));
}

Analicemos aquí las funciones clave:

  • getTokenMultiplier: Obtiene el multiplicador actual de una moneda determinada. Utiliza la descomprimirMint y getScaledUiAmountConfig funciones auxiliares de @solana/spl-token para obtener los datos de prórroga de la casa de la moneda (multiplicador y marca de tiempo efectiva).
  • getTokenBalance: Obtiene los saldos brutos y de la interfaz de usuario de una cuenta de token determinada. Utiliza la getTokenAccountBalance método de la biblioteca web3.js de Solana.
  • logStatus: Registra el estado de cada paso, incluyendo el multiplicador actual, el saldo bruto y el saldo de la interfaz de usuario. Además, almacena esta información en el demoLogs matriz para su posterior visualización.
  • imprimirTablaResumen: Muestra una tabla resumen de todos los pasos registrados, en la que se muestra la relación entre el multiplicador, el saldo bruto y el saldo de la interfaz de usuario.

Funciones de utilidad

Ahora, añadamos algunas funciones de utilidad para gestionar las confirmaciones de transacciones y la gestión de pares de claves:

async function waitForTransaction(
connection: Connection,
signature: string,
timeout = 30000,
transactionNote: string
): Promise<string> {
const startTime = Date.now();
return new Promise((resolve, reject) => {
(async () => {
try {
let done = false;
while (!done && Date.now() - startTime < timeout) {
const status = await connection.getSignatureStatus(signature);

if (status?.value?.confirmationStatus === 'confirmed' ||
status?.value?.confirmationStatus === 'finalized') {
done = true;
console.log(` ✅ Transaction ${transactionNote} confirmed: ${signature}`);
resolve(signature);
} else {
await new Promise(resolve => setTimeout(resolve, 1000));
}
}

if (!done) {
reject(new Error(` ❌ Transaction confirmation timeout after ${timeout}ms`));
}
} catch (error) {
reject(error);
}
})();
});
}

async function getOrCreateKeypair(keyPath: string, label: string): Promise<Keypair> {
try {
if (fs.existsSync(keyPath)) {
const keyData = JSON.parse(fs.readFileSync(keyPath, 'utf-8'));
const keypair = Keypair.fromSecretKey(new Uint8Array(keyData));
return keypair;
} else {
const keypair = Keypair.generate();
fs.writeFileSync(keyPath, JSON.stringify(Array.from(keypair.secretKey)));
return keypair;
}
} catch (error) {
const keypair = Keypair.generate();
console.log(`Generated new ${label} keypair as fallback: ${keypair.publicKey.toString()}`);
return keypair;
}
}

Aquí vamos a crear dos funciones de utilidad:

  • waitForTransaction - Esperar a que se confirmen las transacciones (con gestión de tiempos de espera)
  • getOrCreateKeypair - Obtener o crear pares de claves y guardarlos en archivos para poder reutilizarlos

Funcionalidad básica

A continuación, vamos a añadir las funciones principales para nuestra demostración. Añade el configuración Añade esta función a tu archivo para gestionar la transferencia directa de SOL a la cuenta del pagador:

async function setup(connection: Connection, payer: Keypair) {
try {
const airdropSignature = await connection.requestAirdrop(
payer.publicKey,
2 * LAMPORTS_PER_SOL
);
await waitForTransaction(connection, airdropSignature, 30000, "airdrop");
} catch (error) {
console.error('Error funding payer account:', error);
console.log('If you are not using a local validator, you need to fund the payer account manually.');
}
}

A continuación, vamos a crear el createScaledToken Función para crear un nuevo token con la extensión «Scaled UI Amount»:

async function createScaledToken(connection: Connection, payer: Keypair, mint: Keypair, mintAuthority: Keypair) {
try {
// Calculate space needed for the mint account with Scaled UI Amount extension
const extensions = [ExtensionType.ScaledUiAmountConfig];
const mintLen = getMintLen(extensions);

// Calculate lamports needed for rent-exemption
const mintLamports = await connection.getMinimumBalanceForRentExemption(mintLen);

// Create a new token with Token-2022 program & Scaled UI Amount extension
const transaction = new Transaction().add(
// Create account for the mint
SystemProgram.createAccount({
fromPubkey: payer.publicKey,
newAccountPubkey: mint.publicKey,
space: mintLen,
lamports: mintLamports,
programId: TOKEN_2022_PROGRAM_ID,
}),
// Initialize Scaled UI Amount extension
createInitializeScaledUiAmountConfigInstruction(
mint.publicKey,
mintAuthority.publicKey,
CONFIG.INITIAL_UI_AMOUNT_MULTIPLIER,
TOKEN_2022_PROGRAM_ID
),
// Initialize the mint
createInitializeMintInstruction(
mint.publicKey,
CONFIG.DECIMAL_PLACES,
mintAuthority.publicKey,
mintAuthority.publicKey,
TOKEN_2022_PROGRAM_ID
)
);

const createMintSignature = await sendAndConfirmTransaction(
connection,
transaction,
[payer, mint],
{ commitment: 'confirmed' }
);

console.log(` ✅ Token created! Transaction signature: ${createMintSignature}`);
console.log(` Mint address: ${mint.publicKey.toString()}`);

return;
} catch (error) {
console.error('Error creating token:', error);
throw error;
}
}

Esta función crea y envía una transacción con tres instrucciones clave:

  1. createAccount: Crea una nueva cuenta para la casa de moneda con el espacio y los lamports necesarios en función de las extensiones (en este caso, solo la extensión «Scaled UI Amount»).
  2. createInitializeScaledUiAmountConfigInstruction: Inicializa la extensión «Scaled UI Amount» para la casa de la moneda
  3. createInitializeMintInstruction: Inicializa la casa de moneda con los decimales y la autoridad especificados

Puedes encontrar más información sobre estos pasos en la documentación del programa Solana.

Ahora, vamos a añadir un updateScaledUiAmountMultiplier Función para actualizar el multiplicador de la cantidad en la interfaz de usuario:

async function updateScaledUiAmountMultiplier(
connection: Connection,
mint: Keypair,
mintAuthority: Keypair,
payer: Keypair,
newMultiplier: number,
startTimestamp: number = 0 // default, 0, is effective immediately
): Promise<string> {
try {
const signature = await updateMultiplier(
connection,
payer,
mint.publicKey,
mintAuthority,
newMultiplier,
BigInt(startTimestamp),
[payer, mintAuthority],
undefined,
TOKEN_2022_PROGRAM_ID
);

await waitForTransaction(connection, signature, 30000, "multiplier update");

return signature;
} catch (error) {
console.error(' Error updating UI amount multiplier:', error);
throw error;
}
}

Aquí simplemente estamos utilizando el multiplicador de actualización función de la @solana/spl-token biblioteca para actualizar el multiplicador de la casa de la moneda (ten en cuenta que estamos pasando 0 (como marca de tiempo de inicio de nuestro nuevo multiplicador, lo que significa que entrará en vigor de inmediato) y espera a que se confirme la transacción antes de continuar.

A continuación, vamos a añadir un elemento reutilizable transferTokens Función para gestionar la transferencia de tokens entre cuentas. La utilizaremos para mostrar cómo se realiza la transferencia de tokens antes y después de la actualización del multiplicador:

async function transferTokens(
connection: Connection,
payer: Keypair,
source: PublicKey,
sourceOwner: Keypair,
mint: PublicKey
): Promise<string> {
try {
const amount = CONFIG.TRANSFER_AMOUNT * (10 ** CONFIG.DECIMAL_PLACES);

const destinationOwner = Keypair.generate();
const destinationAccount = await getOrCreateAssociatedTokenAccount(
connection,
payer,
mint,
destinationOwner.publicKey,
false,
'confirmed',
{},
TOKEN_2022_PROGRAM_ID
);

const tx = new Transaction().add(
createTransferInstruction(
source,
destinationAccount.address,
sourceOwner.publicKey,
amount,
[sourceOwner],
TOKEN_2022_PROGRAM_ID
)
);

const transferSignature = await sendAndConfirmTransaction(
connection,
tx,
[payer, sourceOwner],
{ commitment: 'confirmed' }
);

console.log(` ✅ Tokens transferred! Transaction signature: ${transferSignature}`);

return transferSignature;
} catch (error) {
console.error(' ❌ Error transferring tokens');
throw error;
}
}

Esta función se encarga de:

  • Configuración de un nuevo monedero de destino y una nueva cuenta de tokens para la transferencia (se trata simplemente de una cuenta temporal para la demostración)
  • Creación de una operación de transferencia con el createTransferInstruction función
  • Enviar la transacción y esperar la confirmación

Función principal de demostración

Ahora, vamos a crear el archivo principal demonstrateScaledToken función paso a paso. En primer lugar, añade una función provisional con tareas pendientes para cada paso:

async function demonstrateScaledToken(): Promise<void> {
try {
console.log(`=== SCALED TOKEN DEMONSTRATION ===`);
console.log(`\n=== Setup ===`);
// TODO Add setup

console.log(`\n=== Step 1: Creating Token Mint ===`);
// TODO Create Token Mint with UI Amount Scaled extension

console.log(`\n=== Step 2: Creating Holder's Token Account ===`);
// TODO Create Holder's Token Account

console.log(`\n=== Step 3: Minting Initial Tokens ===`);
// TODO Mint Initial Tokens to Holder

console.log(`\n=== Step 4: Transferring Tokens ===`);
// TODO Transfer Tokens to another account

console.log(`\n=== Step 5: Updating Scale Multiplier ===`);
// TODO Update Scale Multiplier

console.log(`\n=== Step 6: Minting Additional Tokens ===`);
// TODO Mint Additional Tokens to Holder

console.log(`\n=== Step 7: Transferring Additional Tokens ===`);
// TODO Transfer Tokens to another account

} catch (error) {
console.error('Error in scaled token demonstration:', error);
}
}

Vamos a rellenar cada apartado:

Configuración

Sustituir // TODO Add setup con:

    const conexión = new Conexión(CONFIG.CONNECTION_URL, 'confirmed');
const pago = await getOrCreateKeypair(ruta.unir(CONFIG.KEYPAIR_DIR, 'payer.json'), 'payer');
const autoridad de emisión = await getOrCreateKeypair(ruta.unir(CONFIG.KEYPAIR_DIR, 'mint-authority.json'), 'autoridad de emisión');
const casa de la moneda = await getOrCreateKeypair(ruta.unir(CONFIG.KEYPAIR_DIR, 'mint.json'), 'mint');
const contenedor = await getOrCreateKeypair(ruta.unir(CONFIG.KEYPAIR_DIR, 'holder.json'), 'titular del token');
await configuración(conexión, pagador);

En este paso, hacemos lo siguiente:

  1. Establecer una conexión con la red Solana
  2. Cargar o crear pares de claves para todas las cuentas que vayamos a necesitar
  3. Ejecuta nuestro configuración función para transferir fondos desde la cuenta del pagador

Paso 1: Creación de la emisión de tokens

Sustituir // TODO Create Token Mint with UI Amount Scaled extension con:

    esperar createScaledToken(conexión, pagador, casa de la moneda, autoridad de acuñación);

esperar logStatus(
conexión,
"1. Tras la inicialización del token",
crea.clavePública,
null,
«Token creado con la extensión Scaled UI Amount»
);

Esta sección:

  1. Crea un nuevo token Token-2022 con la extensión «Scaled UI Amount»
  2. Registra el estado inicial (ten en cuenta que todavía no hay ninguna cuenta de token)

Paso 2: Creación de la cuenta de tokens del titular

Sustituir // TODO Create Holder's Token Account con:

    const holderTokenAccount = await getOrCreateAssociatedTokenAccount(
connection,
payer,
mint.publicKey,
holder.publicKey,
false,
'confirmed',
{},
TOKEN_2022_PROGRAM_ID
);

console.log(` ✅ Holder's token account created: ${holderTokenAccount.address.toString()}`);
await logStatus(
connection,
"2. After ATA Created",
mint.publicKey,
holderTokenAccount.address,
"Holder's token account created"
);

Aquí estamos creando una cuenta de token asociada para el titular utilizando el getOrCreateAssociatedTokenAccount función. Esto nos permitirá acuñar tokens directamente en la cuenta del titular. Ten en cuenta que estamos utilizando el ID de programa Token-2022.

Paso 3: Emisión de los tokens iniciales

Sustituir // TODO Mint Initial Tokens to Holder con:

    const initialMintAmount = CONFIG.MINT_AMOUNT * (10 ** CONFIG.DECIMAL_PLACES);

const mintToSignature = await mintTo(
connection,
payer,
mint.publicKey,
holderTokenAccount.address,
mintAuthority,
initialMintAmount,
[],
{},
TOKEN_2022_PROGRAM_ID
);

await waitForTransaction(connection, mintToSignature, 30000, "initial mint");

await logStatus(
connection,
"3. After Mint #1",
mint.publicKey,
holderTokenAccount.address,
`Minted ${CONFIG.MINT_AMOUNT} tokens with initial multiplier`
);

En este paso, hacemos lo siguiente:

  1. Calcula la cantidad bruta que se va a acuñar (incluidos los decimales)
  2. Acreditar tokens en la cuenta del titular
  3. Espera a que se confirme la transacción
  4. Anota el estado después

Paso 4: Transferencia de tokens

Sustituir // TODO Transfer Tokens to another account con:

    await transferTokens(
connection,
payer,
holderTokenAccount.address,
holder,
mint.publicKey
);

await logStatus(
connection,
"4. After Transfer #1",
mint.publicKey,
holderTokenAccount.address,
`Transferred ${CONFIG.TRANSFER_AMOUNT} tokens to another account`
);

Esta sección:

  1. Transfiere tokens del titular a una nueva cuenta (recuerda que nuestra instrucción de transferencia utiliza la constante CONFIG.TRANSFER_AMOUNT para determinar cuántos tokens se deben transferir; utilizaremos la misma cantidad bruta para ambas transferencias y compararemos cómo varían las cantidades que aparecen en la interfaz de usuario).
  2. Registra el estado tras la transferencia

Paso 5: Actualización del multiplicador de escala

Sustituir // TODO Update Scale Multiplier con:

    await updateScaledUiAmountMultiplier(
connection,
mint,
mintAuthority,
payer,
CONFIG.MODIFIED_UI_AMOUNT_MULTIPLIER
);

await logStatus(
connection,
"5. After Multiplier Update",
mint.publicKey,
holderTokenAccount.address,
`Updated multiplier to ${CONFIG.MODIFIED_UI_AMOUNT_MULTIPLIER}x`
);

Aquí nosotros:

  1. Actualiza el multiplicador de la cantidad en la interfaz de usuario utilizando el updateScaledUiAmountMultiplier función
  2. Registra el estado para ver cómo varía el importe que aparece en la interfaz de usuario

Paso 6: Emisión de tokens adicionales

Sustituir // TODO Mint Additional Tokens to Holder con:

    const additionalMintSignature = await mintTo(
connection,
payer,
mint.publicKey,
holderTokenAccount.address,
mintAuthority,
initialMintAmount, // Same raw amount as before
[],
{},
TOKEN_2022_PROGRAM_ID
);

await waitForTransaction(connection, additionalMintSignature, 30000, "additional mint");

await logStatus(
connection,
"6. After Mint #2",
mint.publicKey,
holderTokenAccount.address,
`Minted additional ${CONFIG.MINT_AMOUNT} tokens with current multiplier`
);

Esta sección:

  1. Genera la misma cantidad de materia prima que antes
  2. Registra el estado para comprobar cómo varía el valor de la interfaz de usuario con el nuevo multiplicador

Paso 7: Transferencia de tokens adicionales

Sustituir // TODO Transfer Tokens to another account con:

    await transferTokens(
connection,
payer,
holderTokenAccount.address,
holder,
mint.publicKey
);

await logStatus(
connection,
"7. After Transfer #2",
mint.publicKey,
holderTokenAccount.address,
`Transferred ${CONFIG.TRANSFER_AMOUNT} tokens to another account (with multiplier)`
);

printSummaryTable();

Por último, nosotros:

  1. Vuelve a transferir tokens utilizando la misma cantidad bruta
  2. Registra el estado para que podamos ver cómo varía el importe de la interfaz de usuario con respecto a la transferencia anterior.
  3. Imprimir una tabla resumen con todos los pasos

Incorporación de la llamada a la función principal

Al final de tu archivo, añade:

if (require.main === module) {
console.log('Starting the Token-2022 Scaled UI Amount demonstration...');
demonstrateScaledToken()
.then(() => console.log(`=== DEMONSTRATION COMPLETED ===`))
.catch(error => console.error('Demonstration failed with error:', error));
}

Ejecución de la demostración

Para ejecutar la demostración:


  1. Abre una nueva ventana de terminal e inicia un validador de prueba local:
solana-test-validator -r

  1. A continuación, en la terminal de tu proyecto principal, ejecuta el script:
npm start

Comprender el resultado

Esto es lo que deberías ver en el resultado:

=== RESUMEN DE LA DEMOSTRACIÓN ===
┌─────────┬───────────────────────────┬──────────────┬────────────┬─────────────┬────────────┐
│ (índice) │ Paso │ Marca de tiempo │ Multiplicador │ Saldo bruto │ Saldo de la interfaz de usuario │
├─────────┼───────────────────────────┼──────────────┼────────────┼─────────────┼────────────┤
│ 0 │ «Configuración inicial» │ «3:02:16 p. m.» │ 1 │ «n/a» │ «n/a» │
│ 1 │ «Tras la emisión inicial» │ «15:02:17» │ 1 │ «100000000» │ «100» │
│ 2 │ «Tras la transferencia n.º 1» │ «3:02:18 p. m.» │ 1 │ «90000000» │ «90» │
│ 3 │ «Tras la actualización del multiplicador» │ «3:02:19 p. m.» │ 2 │ «90000000» │ «180» │
│ 4 │ «Tras la segunda emisión» │ «3:02:20 p. m.» │ 2 │ «190000000» │ «380» │
│ 5 │ «Tras la transferencia n.º 2» │ «3:02:21 p. m.» │ 2 │ «180000000» │ «360» │
└─────────┴───────────────────────────┴──────────────┴────────────┴─────────────┴────────────┘
=== DEMOSTRACIÓN FINALIZADA ===

Analicemos con más detalle los puntos clave de la demostración:


  • Tras la emisión inicial, el importe en la interfaz de usuario = importe bruto / 10^decimales, ya que nuestro multiplicador es 1,0.
  • Tras la transferencia n.º 1, las cantidades «en bruto» y «UI» disminuyen proporcionalmente
  • Tras la actualización del multiplicador: el importe bruto no ha variado, pero el importe que aparece en la interfaz de usuario se ha duplicado (por ejemplo, como si se tratara de una división de acciones 2:1).
  • Tras la segunda acuñación: la cantidad bruta aumenta como antes, pero la cantidad que aparece en la interfaz de usuario se incrementa en dicha cantidad multiplicada por el nuevo multiplicador (+ 100 * 2,0).
  • Tras la transferencia n.º 2, la cantidad inicial disminuye en la misma cantidad que antes, pero la cantidad de la interfaz de usuario ahora se reduce en esa cantidad multiplicada por el nuevo multiplicador (-10 * 2,0).

¡Es hora de crecer!

¡Enhorabuena! Has implementado con éxito la extensión «Scaled UI Amount» en un programa Token-2022 de Solana. Ahora dispones de una demostración funcional que muestra cómo crear un token, acuñar y transferir tokens, y actualizar el multiplicador de la cantidad en la interfaz de usuario.

La extensión «Scaled UI Amount» ofrece a los emisores de tokens un potente mecanismo para controlar cómo se muestran los saldos a los usuarios sin modificar los importes brutos subyacentes. Esto abre nuevas posibilidades para crear modelos económicos innovadores para los tokens en Solana.

Puntos clave:


  • La extensión «Scaled UI Amount» de Token-2022 permite aplicaciones avanzadas de la economía de tokens, como divisiones de acciones, dividendos, rendimientos y rebasing.
  • Al utilizar multiplicadores, los importes brutos no varían, mientras que los importes de la prestación por desempleo se ajustan en función del multiplicador.
  • Las aplicaciones deben gestionar adecuadamente la conversión entre los importes sin procesar y los de la interfaz de usuario.
  • Los proveedores de datos históricos deberían plantearse indexar las variaciones del multiplicador para ofrecer datos históricos precisos.

Recursos adicionales


Si tienes alguna duda o necesitas ayuda, únete al servidor de Discord de Quicknode o síguenos en Twitter.

¡Nos encanta recibir comentarios!

Si tienes algún comentario o sugerencia sobre nuevos temas, no dudes en hacérnoslo saber. Nos encantaría saber tu opinión.

Comparte esta guía