Tokens con Permisos mediante Token ACL (sRFC37)

Token ACL (Lista de Control de Acceso) es un programa de Solana que permite tokens con permisos y cumplimiento normativo sin sacrificar la experiencia del usuario. Implementa sRFC37, lo que permite a las empresas crear tokens con funcionalidad de listas de permitidos/bloqueados manteniendo la experiencia de usuario fluida que los usuarios esperan.

El Problema

Las empresas necesitan tokens conformes que puedan:

  1. Aplicar requisitos KYC/AML
  2. Bloquear direcciones sancionadas
  3. Restringir las transferencias de tokens a partes aprobadas

El enfoque tradicional utiliza la extensión DefaultAccountState de Token-2022 para crear cuentas en estado congelado, lo que requiere intervención manual para descongelar cada cuenta:

┌─────────────────────────────────────────────────────┐
│ TRADITIONAL FROZEN TOKENS │
├─────────────────────────────────────────────────────┤
│ │
│ 1. User creates token account │
│ └─> Account is FROZEN ❄️ │
│ │
│ 2. User contacts issuer support │
│ └─> "Please whitelist my wallet" │
│ │
│ 3. Issuer manually verifies KYC │
│ └─> Delays, friction, poor UX │
│ │
│ 4. Issuer thaws account │
│ └─> Finally can receive tokens │
│ │
│ ❌ Bad UX - users wait hours/days │
│ │
└─────────────────────────────────────────────────────┘

Esto genera una fricción significativa y contradice la promesa de transacciones blockchain instantáneas y sin permisos.

La Solución

Token ACL habilita la descongelación sin permisos: los usuarios pueden descongelar automáticamente sus propias cuentas si cumplen los criterios definidos por un Gate Program:

┌─────────────────────────────────────────────────────┐
│ TOKEN ACL FLOW │
├─────────────────────────────────────────────────────┤
│ │
│ 1. User creates token account │
│ └─> Account is FROZEN ❄️ │
│ │
│ 2. User calls permissionless thaw │
│ └─> Token ACL checks Gate Program │
│ │
│ 3. Gate Program validates user │
│ ├─> On allow list? ✅ THAW │
│ ├─> On block list? ❌ STAY FROZEN │
│ └─> AllowAllEoas mode? ✅ THAW │
│ │
│ 4. Account thawed instantly! │
│ └─> User can receive tokens immediately │
│ │
│ ✅ Great UX - instant, self-service │
│ │
└─────────────────────────────────────────────────────┘

Implementación de Referencia Educativa

Esta guía incluye una implementación funcional completa que puedes ejecutar localmente. El código fuente proporciona implementaciones de referencia para exploración y fines educativos.

El código de los programas ACL está disponible en el repositorio token-acl y el ABL Gate Program está disponible en el repositorio abl-gate-program.

Importante: El ABL (Allow Block List) Gate Program utilizado en esta guía es una implementación de referencia. Aunque está auditado y listo para producción, los emisores son libres de crear Gate Programs personalizados que se adapten mejor a sus necesidades específicas de cumplimiento. Solo estás vinculado por la especificación Token ACL (sRFC37), no por este diseño particular de Gate Program.

NO uses este código directamente en producción sin:

  • Auditorías de seguridad exhaustivas
  • Sistemas adecuados de gestión de claves
  • Revisión de cumplimiento normativo
  • Consulta legal

¿Por qué Token ACL?

AspectoCongelado TradicionalToken ACL
Activación de CuentaManual (minutos/días)Instantánea (autoservicio)
Experiencia de UsuarioDeficienteFluida
Control de CumplimientoTotalTotal
Bloqueo de SancionesManualAutomático mediante Gate Program
Esfuerzo de IntegraciónAltoBajo (SDK disponible)
ComponibilidadLimitadaTotal (compatible con DeFi)

Token ACL vs Transfer Hooks

Tanto Token ACL como los Transfer Hooks son soluciones Token-2022 para añadir lógica personalizada a los tokens, pero sirven para distintos propósitos y tienen diferentes ventajas e inconvenientes:

AspectoToken ACLTransfer Hooks
Cuándo se Ejecuta la LógicaSolo en operaciones de congelado/descongeladoEn cada transferencia
Sobrecarga de TransferenciaNinguna: las transferencias son estándarCUs adicionales + cuentas en cada transferencia
Dependencias de CuentaSolo durante la activación de la cuentaRequeridas en cada transacción de transferencia
Componibilidad DeFiTotal: los protocolos funcionan con normalidadLimitada: muchos protocolos los bloquean
Mejor ParaKYC/AML, sanciones, listas de permitidos/bloqueadosRegalías, validación de transferencias personalizadas
Complejidad para UsuariosBaja: operación de descongelado únicaMayor: cada transferencia requiere datos adicionales

Cuándo Usar Token ACL

Elige Token ACL cuando necesites controlar quién puede mantener tu token:

  • Cumplimiento KYC/AML: verifica a los titulares antes de que puedan recibir tokens
  • Filtrado de sanciones: bloquea direcciones específicas
  • Restricciones para inversores acreditados: limita los titulares de tokens a partes verificadas
  • Bloqueo de PDA: impide que los contratos inteligentes mantengan tokens

Cuándo Usar Transfer Hooks

Elige Transfer Hooks cuando necesites controlar cómo se mueven los tokens:

  • Regalías de NFT: cobra comisiones en cada transferencia
  • Restricciones de transferencia: limita los importes o la frecuencia de las transferencias
  • Lógica de transferencia personalizada: ejecuta código en cada movimiento
  • Analítica onchain: rastrea todos los movimientos de tokens

Soluciones Complementarias

Token ACL y Transfer Hooks pueden usarse juntos. Por ejemplo, podrías usar Token ACL para controlar quién puede mantener tu token (cumplimiento normativo) mientras usas Transfer Hooks para la aplicación de regalías en cada transferencia.

Visión General de la Arquitectura

Token ACL consta de tres componentes principales:

  1. Programa Token ACL: El programa principal que gestiona la delegación de autoridad de congelado y las operaciones sin permisos
  2. Gate Program: Lógica personalizada que determina quién puede descongelar/congelar (p. ej., ABL Gate Program para listas de permitidos/bloqueados)
  3. MintConfig: Configuración por mint que almacena los ajustes y delega la autoridad de congelado
┌─────────────────────────────────────────────────────────────────┐
│ TOKEN ACL ARCHITECTURE │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ delegates ┌─────────────────┐ │
│ │ Token Mint │ ──────────────────→ │ MintConfig │ │
│ │ (Token-22) │ freeze authority │ (Token ACL) │ │
│ └──────────────┘ └────────┬────────┘ │
│ │ │
│ │ calls │
│ ▼ │
│ ┌──────────────┐ validates ┌─────────────────┐ │
│ │ User │ ◄─────────────────── │ Gate Program │ │
│ │ (wallet) │ │ (ABL/Custom) │ │
│ └──────────────┘ └─────────────────┘ │
│ │ │
│ ┌────────┴────────┐ │
│ │ │ │
│ ┌────▼────┐ ┌─────▼───┐ │
│ │ Allow │ │ Block │ │
│ │ Lists │ │ Lists │ │
│ └─────────┘ └─────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘

Conceptos Clave

  1. Delegación de Autoridad de Congelado: Al crear una configuración Token ACL, la autoridad de congelado del mint se transfiere al PDA de MintConfig. Esto permite que Token ACL gestione las operaciones de congelado/descongelado.

  2. Gate Programs: Programas externos que implementan la lógica de permitidos/bloqueados. El ABL (Allow Block List) Gate Program es una implementación de referencia: los emisores pueden construir Gate Programs personalizados con lógica diferente (p. ej., verificación KYC onchain, comprobaciones de sanciones basadas en oráculos, o integración con protocolos de identidad).

  3. Operaciones sin Permisos: Los usuarios pueden descongelar sus propias cuentas sin intervención del emisor, siempre que el Gate Program lo apruebe.

  4. Integración con TokenMetadata: Añadir un campo token_acl a los metadatos de tu mint permite la detección automática por parte de wallets y SDKs como @solana/token-helpers.

Detección Automática con TokenMetadata

Cuando añades un campo token_acl a la extensión TokenMetadata de tu mint apuntando a la dirección del Gate Program, los SDKs como @solana/token-helpers pueden detectar automáticamente los mints de Token ACL e incluir instrucciones de descongelado al crear cuentas de token.

Modos del ABL Gate Program

ABL es una Implementación de Referencia

El ABL Gate Program que se muestra aquí es una implementación de referencia que cubre casos de uso comunes de listas de permitidos/bloqueados. Sin embargo, no estás limitado a este diseño. La especificación Token ACL (sRFC37) define únicamente la interfaz entre Token ACL y los Gate Programs; puedes crear Gate Programs personalizados con:

  • Integración con protocolos de identidad/KYC onchain
  • Filtrado de sanciones en tiempo real basado en oráculos
  • Flujos de aprobación multi-firma
  • Reglas de acceso temporales o condicionales
  • Cualquier otra lógica de cumplimiento personalizada

El único requisito es implementar la interfaz de Gate Program definida en sRFC37.

El ABL (Allow Block List) Gate Program admite varios modos:

ModoDescripciónCaso de Uso
AllowAllEoasTodas las wallets regulares (no PDAs) pueden descongelarTokens abiertos con bloqueo de PDA
AllowSolo las wallets en la lista de permitidos pueden descongelarTokens con KYC obligatorio
BlockTodas las wallets EXCEPTO las de la lista de bloqueados pueden descongelarCumplimiento de sanciones
CompuestoCombinar listas de permitidos + bloqueadosConfiguración de cumplimiento completo

Precedencia de la Lista de Bloqueados

Al usar listas compuestas, la lista de bloqueados siempre tiene precedencia. Una wallet que esté tanto en la lista de permitidos como en la de bloqueados NO podrá descongelar.

Direcciones de Programas

Para facilitar el proceso, los programas ya están desplegados en devnet. Puedes usar las siguientes direcciones. El lanzamiento en mainnet se realizará tras las auditorías.

ProgramaDirección
Token ACLTACLkU6CiCdkQN2MjoyDkVg2yAH9zkxiHDsiztQ52TP
ABL Gate ProgramGATEzzqxhJnsWF6vHRsgtixxSB8PaQdcqGEVTEHWiULz

Requisitos Previos

Para ejecutar los ejemplos localmente, asegúrate de clonar los programas en tu validator local:

  1. Solana CLI

    (Para ejecutarlo localmente usa la versión 2.x, NO la 3.x: existe un problema conocido con los metadatos de Token-2022 en este momento, que fallaría en el paso de añadir metadatos adicionales)

    solana --version
  2. Node.js 18+ y pnpm

  3. validator local con los programas requeridos:

    solana-test-validator \
    --clone TACLkU6CiCdkQN2MjoyDkVg2yAH9zkxiHDsiztQ52TP \
    --clone GEC5tu9eaZQrNS7ohERwZRqyvLvV8k2iVZqqt6VuwvJu \
    --clone GATEzzqxhJnsWF6vHRsgtixxSB8PaQdcqGEVTEHWiULz \
    --clone D2GUvBwbnkFu3R5s1rz5dcBJ81UsqY3nvHbLdeJLtSx5 \
    --url devnet \
    --reset

Implementación Completa

Paso 1: Instalar Dependencias

pnpm add @solana/kit @solana-program/token-2022 @solana-program/system \
@solana-program/compute-budget @token-acl/sdk @token-acl/abl-sdk \
@solana/spl-token-metadata @solana/web3.js ws

Paso 2: Crear un Token con Token ACL

A continuación se muestra un ejemplo completo que crea un token con cumplimiento normativo mediante Token ACL:

import {
createSolanaRpc,
createSolanaRpcSubscriptions,
sendAndConfirmTransactionFactory,
getSignatureFromTransaction,
generateKeyPairSigner,
pipe,
createTransactionMessage,
setTransactionMessageFeePayer,
setTransactionMessageLifetimeUsingBlockhash,
appendTransactionMessageInstructions,
signTransactionMessageWithSigners,
lamports
} from "@solana/kit";
import { getCreateAccountInstruction } from "@solana-program/system";
import { getSetComputeUnitLimitInstruction } from "@solana-program/compute-budget";
import {
TOKEN_2022_PROGRAM_ADDRESS,
getInitializeMintInstruction,
getInitializeTokenMetadataInstruction,
getUpdateTokenMetadataFieldInstruction,
tokenMetadataField,
AccountState,
getMintSize,
getPreInitializeInstructionsForMintExtensions,
extension
} from "@solana-program/token-2022";
import { pack } from "@solana/spl-token-metadata";
import { PublicKey } from "@solana/web3.js";
// Token ACL SDK
import {
getCreateConfigInstruction,
findMintConfigPda,
getTogglePermissionlessInstructionsInstruction,
findThawExtraMetasAccountPda
} from "@token-acl/sdk";
// ABL Gate Program SDK
import {
getCreateListInstruction,
getSetupExtraMetasInstruction,
getAddWalletInstruction,
findListConfigPda,
findWalletEntryPda,
ABL_PROGRAM_ADDRESS,
Mode
} from "@token-acl/abl-sdk";
// TLV sizes for Token-2022 extensions
const TYPE_SIZE = 2;
const LENGTH_SIZE = 2;
async function createTokenACLMint() {
// Setup RPC
const rpc = createSolanaRpc("http://localhost:8899");
const rpcSubscriptions = createSolanaRpcSubscriptions("ws://localhost:8900");
const sendAndConfirm = sendAndConfirmTransactionFactory({
rpc,
rpcSubscriptions
});
// Load your payer keypair
const payer = await loadKeypair("~/.config/solana/id.json");
// Generate mint keypair
const mint = await generateKeyPairSigner();
console.log(`🪙 Mint: ${mint.address}`);
// TokenMetadata config - includes 'token_acl' for auto-detection
const TOKEN_NAME = "Compliant Token";
const TOKEN_SYMBOL = "COMP";
const TOKEN_URI = "";
const TOKEN_ACL_KEY = "token_acl";
// Define extensions
const defaultAccountStateExtension = extension("DefaultAccountState", {
state: AccountState.Frozen
});
const metadataPointerExtension = extension("MetadataPointer", {
authority: payer.address,
metadataAddress: mint.address
});
const extensions = [defaultAccountStateExtension, metadataPointerExtension];
// Calculate mint size
const baseMintSize = getMintSize(extensions);
const metadataForSizing = {
mint: new PublicKey(mint.address),
name: TOKEN_NAME,
symbol: TOKEN_SYMBOL,
uri: TOKEN_URI,
additionalMetadata: [[TOKEN_ACL_KEY, ABL_PROGRAM_ADDRESS]] as [
string,
string
][]
};
const metadataLen = pack(metadataForSizing).length;
const totalSpace = baseMintSize + metadataLen + TYPE_SIZE + LENGTH_SIZE;
// Get rent
const mintRent = await rpc
.getMinimumBalanceForRentExemption(BigInt(totalSpace))
.send();
// Get extension pre-initialization instructions
const extensionInstructions = getPreInitializeInstructionsForMintExtensions(
mint.address,
extensions
);
// Build transaction
const { value: blockhash } = await rpc.getLatestBlockhash().send();
const createMintTx = pipe(
createTransactionMessage({ version: 0 }),
(tx) => setTransactionMessageFeePayer(payer.address, tx),
(tx) => setTransactionMessageLifetimeUsingBlockhash(blockhash, tx),
(tx) =>
appendTransactionMessageInstructions(
[
getSetComputeUnitLimitInstruction({ units: 400_000 }),
getCreateAccountInstruction({
payer,
newAccount: mint,
lamports: lamports(mintRent),
space: baseMintSize,
programAddress: TOKEN_2022_PROGRAM_ADDRESS
}),
...extensionInstructions,
getInitializeMintInstruction({
mint: mint.address,
decimals: 6,
mintAuthority: payer.address,
freezeAuthority: payer.address
}),
getInitializeTokenMetadataInstruction({
metadata: mint.address,
updateAuthority: payer.address,
mint: mint.address,
mintAuthority: payer,
name: TOKEN_NAME,
symbol: TOKEN_SYMBOL,
uri: TOKEN_URI
}),
getUpdateTokenMetadataFieldInstruction({
metadata: mint.address,
updateAuthority: payer,
field: tokenMetadataField("Key", [TOKEN_ACL_KEY]),
value: ABL_PROGRAM_ADDRESS
})
],
tx
)
);
// Sign and send
const signedTx = await signTransactionMessageWithSigners(createMintTx);
await sendAndConfirm(signedTx, { commitment: "confirmed" });
console.log("✅ Mint created with TokenMetadata");
return mint.address;
}

Paso 3: Crear la Configuración de Token ACL

Después de crear el mint, crea la configuración de Token ACL:

async function createTokenACLConfig(
mintAddress: Address,
payer: TransactionSigner
) {
const [mintConfigPda] = await findMintConfigPda({ mint: mintAddress });
console.log(`📋 MintConfig PDA: ${mintConfigPda}`);
const createConfigIx = getCreateConfigInstruction({
payer: payer.address,
authority: payer,
mint: mintAddress,
mintConfig: mintConfigPda,
gatingProgram: ABL_PROGRAM_ADDRESS
});
const { value: blockhash } = await rpc.getLatestBlockhash().send();
const tx = pipe(
createTransactionMessage({ version: 0 }),
(tx) => setTransactionMessageFeePayer(payer.address, tx),
(tx) => setTransactionMessageLifetimeUsingBlockhash(blockhash, tx),
(tx) => appendTransactionMessageInstructions([createConfigIx], tx)
);
const signedTx = await signTransactionMessageWithSigners(tx);
await sendAndConfirm(signedTx, { commitment: "confirmed" });
console.log("✅ Token ACL config created");
console.log(" Freeze authority transferred to MintConfig PDA");
return mintConfigPda;
}

Paso 4: Configurar el ABL Gate Program

Crea una lista ABL y configura los metadatos adicionales:

// AllowAllEoas - All regular wallets can thaw automatically
async function setupAllowAllEoas(
mintAddress: Address,
mintConfigPda: Address,
payer: TransactionSigner
) {
const listSeed = mintAddress; // Use mint as seed
const [listConfigPda] = await findListConfigPda({
authority: payer.address,
seed: listSeed
});
const createListIx = getCreateListInstruction({
authority: payer,
listConfig: listConfigPda,
mode: Mode.AllowAllEoas, // All EOAs can thaw
seed: listSeed
});
const [thawExtraMetasPda] = await findThawExtraMetasAccountPda(
{ mint: mintAddress },
{ programAddress: ABL_PROGRAM_ADDRESS }
);
const setupMetasIx = getSetupExtraMetasInstruction({
authority: payer,
tokenAclMintConfig: mintConfigPda,
mint: mintAddress,
extraMetas: thawExtraMetasPda,
lists: [listConfigPda]
});
// Send transaction with both instructions...
console.log("✅ ABL list created with AllowAllEoas mode");
}

Paso 5: Habilitar la Descongelación sin Permisos

Permite a los usuarios descongelar sus propias cuentas:

async function enablePermissionlessThaw(
mintConfigPda: Address,
authority: TransactionSigner
) {
const toggleIx = getTogglePermissionlessInstructionsInstruction({
authority,
mintConfig: mintConfigPda,
thawEnabled: true,
freezeEnabled: false // Optional: enable permissionless freeze too
});
// Send transaction...
console.log("✅ Permissionless thaw enabled");
}

Paso 6: El Usuario Descongela su Cuenta

Los usuarios ahora pueden descongelar sus propias cuentas usando el SDK:

import {
createThawPermissionlessIdempotentInstructionWithExtraMetas,
TOKEN_ACL_PROGRAM_ADDRESS
} from "@token-acl/sdk";
import { fetchEncodedAccount } from "@solana/kit";
async function userThawsAccount(
mintAddress: Address,
userAta: Address,
userAddress: Address,
payer: TransactionSigner
) {
// Account retriever function for the SDK
const accountRetriever = async (addr: Address) => {
return await fetchEncodedAccount(rpc, addr);
};
// The SDK handles all the complexity of fetching extra metas
const thawIx =
await createThawPermissionlessIdempotentInstructionWithExtraMetas(
payer, // authority (signer)
userAta, // token account to thaw
mintAddress, // mint
userAddress, // token account owner
TOKEN_ACL_PROGRAM_ADDRESS, // Token ACL program
accountRetriever // account fetcher
);
// Send transaction signed by payer...
console.log("✅ Account thawed permissionlessly!");
}

Uso de @solana/token-helpers para Descongelación Automática

El SDK @solana/token-helpers puede detectar automáticamente los mints de Token ACL e incluir instrucciones de descongelado:

import { createAndConfirmAssociatedTokenAccount } from "@solana/token-helpers";
// This automatically includes thaw instruction if mint has 'token_acl' metadata
const { signature, associatedTokenAddress } =
await createAndConfirmAssociatedTokenAccount(
rpc,
rpcSubscriptions,
payer,
user.address,
mintAddress,
true // idempotent
);
console.log(`✅ Account created AND thawed automatically!`);
console.log(` ATA: ${associatedTokenAddress}`);

Requisito de TokenMetadata

Para que la detección automática de @solana/token-helpers funcione, tu mint debe tener:

  1. La extensión TokenMetadata inicializada
  2. Un campo additionalMetadata con la clave token_acl y el valor configurado como la dirección del Gate Program

Listas Compuestas de Permitidos + Bloqueados

Para el máximo control de cumplimiento normativo, combina listas de permitidos y bloqueados:

async function setupCompositeLists(
mintAddress: Address,
mintConfigPda: Address,
payer: TransactionSigner
) {
// Create ALLOW list
const allowListSeed = /* unique seed for allow list */;
const [allowListPda] = await findListConfigPda({
authority: payer.address,
seed: allowListSeed,
});
const createAllowListIx = getCreateListInstruction({
authority: payer,
listConfig: allowListPda,
mode: Mode.Allow,
seed: allowListSeed,
});
// Create BLOCK list
const blockListSeed = /* unique seed for block list */;
const [blockListPda] = await findListConfigPda({
authority: payer.address,
seed: blockListSeed,
});
const createBlockListIx = getCreateListInstruction({
authority: payer,
listConfig: blockListPda,
mode: Mode.Block,
seed: blockListSeed,
});
// Setup extra metas with BOTH lists
const [thawExtraMetasPda] = await findThawExtraMetasAccountPda(
{ mint: mintAddress },
{ programAddress: ABL_PROGRAM_ADDRESS }
);
const setupMetasIx = getSetupExtraMetasInstruction({
authority: payer,
tokenAclMintConfig: mintConfigPda,
mint: mintAddress,
extraMetas: thawExtraMetasPda,
lists: [allowListPda, blockListPda], // Both lists!
});
// Send transaction...
console.log("✅ Composite lists created");
console.log(" - Allow list: Only whitelisted users can thaw");
console.log(" - Block list: Blocked users can NEVER thaw");
}

Comportamiento de las Listas Compuestas

┌─────────────────────────────────────────────────────┐
│ COMPOSITE LIST LOGIC │
├─────────────────────────────────────────────────────┤
│ │
│ User tries to thaw: │
│ │
│ 1. Check BLOCK list first │
│ └─> On block list? ❌ DENY (always) │
│ │
│ 2. Check ALLOW list │
│ └─> On allow list? ✅ ALLOW │
│ └─> Not on allow list? ❌ DENY │
│ │
│ Key insight: Block list ALWAYS wins! │
│ │
└─────────────────────────────────────────────────────┘

Casos de Uso

1. Tokens de Seguridad (KYC Obligatorio)

Usa una lista de permitidos para garantizar que solo los inversores verificados por KYC puedan mantener tokens:

// Create allow list
const createListIx = getCreateListInstruction({
authority: issuer,
listConfig: allowListPda,
mode: Mode.Allow,
seed: mintAddress
});
// After KYC verification, add investor
await addToAllowList(allowListPda, kycVerifiedInvestor, issuer);

2. Cumplimiento de Sanciones

Usa una lista de bloqueados para impedir que las direcciones sancionadas reciban tokens:

// Create block list
const createListIx = getCreateListInstruction({
authority: complianceOfficer,
listConfig: blockListPda,
mode: Mode.Block,
seed: mintAddress
});
// Block sanctioned address
await addToBlockList(blockListPda, sanctionedAddress, complianceOfficer);

3. Token Abierto con Protección PDA

Usa AllowAllEoas para permitir todas las wallets regulares mientras se bloquean los PDAs (contratos inteligentes):

const createListIx = getCreateListInstruction({
authority: payer,
listConfig: listConfigPda,
mode: Mode.AllowAllEoas, // Regular wallets OK, PDAs blocked
seed: mintAddress
});

4. Cumplimiento Empresarial Completo

Combina lista de permitidos + lista de bloqueados para un control total:

  • Lista de permitidos: inversores verificados por KYC
  • Lista de bloqueados: direcciones sancionadas, empleados dados de baja, etc.

Consideraciones para Producción

Antes de desplegar en producción:

  1. Auditorías de Seguridad: Realiza auditorías de seguridad profesionales de tu implementación y de cualquier Gate Program personalizado

  2. Gestión de Claves: Usa soluciones de custodia adecuadas para las claves de autoridad. Considera la multi-firma para operaciones sensibles

  3. Cumplimiento Normativo: Consulta a expertos legales sobre regulaciones de valores, requisitos KYC/AML y cumplimiento de sanciones

  4. Gestión de Listas: Construye sistemas robustos para administrar las listas de permitidos/bloqueados, incluyendo:

    • Integración automatizada de filtrado de sanciones
    • Integración con proveedores de KYC
    • Registro de auditoría
  5. Monitorización: Implementa monitorización para:

    • Intentos de descongelado fallidos (posibles problemas de cumplimiento)
    • Modificaciones de listas
    • Uso de claves de autoridad
  6. Recuperación ante Desastres: Planifica la rotación de claves, la recuperación de listas y los procedimientos de congelado de emergencia

Versión de Solana CLI

Token ACL con TokenMetadata requiere Solana CLI 2.x. Existe un problema conocido con la CLI 3.x que interrumpe la función de expansión automática de TokenMetadata. Verifica siempre tu versión de CLI antes de desplegar.

Interfaz de Línea de Comandos (CLI)

Tanto Token ACL como el ABL Gate Program ofrecen CLIs para gestionar configuraciones y listas sin necesidad de escribir código. Esto es útil para los equipos de operaciones.

CLI de Token ACL

La CLI de Token ACL gestiona las configuraciones de mint y las operaciones de congelado/descongelado.

Instalación

# Install from crates.io
cargo install token-acl-cli
# Verify installation
token-acl --version

Comandos de Token ACL

ComandoDescripción
create-configCrea una nueva configuración de mint (transfiere la autoridad de congelado)
delete-configElimina una configuración de mint
set-authorityEstablece la autoridad de una configuración de mint
set-gating-programEstablece el programa de control para una configuración de mint
set-instructionsHabilitar/deshabilitar thaw/freeze sin permisos
thawDescongela un token account (requiere autoridad)
freezeCongela un token account (requiere autoridad)
thaw-permissionlessDescongela un token account sin permisos
freeze-permissionlessCongela un token account sin permisos
create-ata-and-thaw-permissionlessCrea un associated token account y lo descongela en un solo comando

Crear una Configuración Token ACL

# Create a mint config (delegates freeze authority to Token ACL)
token-acl create-config <MINT_ADDRESS> \
--gating-program GATEzzqxhJnsWF6vHRsgtixxSB8PaQdcqGEVTEHWiULz

Habilitar Descongelación sin Permisos

# Enable permissionless thaw only (recommended for most use cases)
# - Users can self-service unfreeze after passing gate checks
# - Only authority can freeze accounts (security best practice)
token-acl set-instructions --enable-thaw --disable-freeze <MINT_ADDRESS>
# Enable both permissionless thaw AND freeze
# Use case: Allow anyone to freeze blocked users, or users to self-freeze
token-acl set-instructions --enable-thaw --enable-freeze <MINT_ADDRESS>
# Disable all permissionless operations (authority-only mode)
token-acl set-instructions --disable-thaw --disable-freeze <MINT_ADDRESS>

Operaciones de Descongelación/Congelación

# Thaw an account permissionlessly (user self-service)
token-acl thaw-permissionless <MINT_ADDRESS> <TOKEN_ACCOUNT_ADDRESS>
# Thaw using authority (issuer operation)
token-acl thaw <MINT_ADDRESS> <TOKEN_ACCOUNT_ADDRESS>
# Freeze using authority (compliance enforcement)
token-acl freeze <MINT_ADDRESS> <TOKEN_ACCOUNT_ADDRESS>

Crear ATA y Descongelar en un Solo Comando

# Creates associated token account and thaws it automatically
token-acl create-ata-and-thaw-permissionless --mint <MINT_ADDRESS> --owner <WALLET_ADDRESS>

ABL Gate CLI (allow-block-list)

El ABL Gate CLI gestiona las listas de permitidos/bloqueados y las entradas de billeteras.

Instalación

# Install from crates.io
cargo install token-acl-gate-cli
# Verify installation (binary is named 'allow-block-list')
allow-block-list --version

Comandos de ABL Gate

ComandoDescripción
create-listCrea una nueva lista de permitidos/bloqueados
delete-listElimina una lista
add-walletAgrega una billetera a una lista
remove-walletElimina una billetera de una lista
apply-lists-to-mintConfigura qué listas se aplican a un mint

Crear una Lista

# Create an ALLOW list (only whitelisted wallets can thaw)
allow-block-list create-list --mode allow
# Create a BLOCK list (blocked wallets cannot thaw)
allow-block-list create-list --mode block
# Create an ALLOW-ALL-EOAs list (all regular wallets can thaw)
allow-block-list create-list --mode allow-all-eoas

El comando genera la dirección PDA de list_config y el seed - ¡guárdalos!

Gestionar Billeteras en Listas

# Add wallet to a list (works for both allow and block lists)
allow-block-list add-wallet <LIST_ADDRESS> <WALLET_ADDRESS>
# Remove wallet from a list
allow-block-list remove-wallet <LIST_ADDRESS> <WALLET_ADDRESS>

Aplicar Listas a un Mint

# Apply a single list to a mint
allow-block-list apply-lists-to-mint <MINT_ADDRESS> <LIST_ADDRESS>
# Apply multiple lists (e.g., allow + block for composite compliance)
allow-block-list apply-lists-to-mint <MINT_ADDRESS> <ALLOW_LIST> <BLOCK_LIST>

Opciones Globales de CLI

Ambos CLIs admiten estas opciones:

OpciónDescripción
-u, --url <URL>URL de RPC (predeterminado: desde la configuración de Solana)
-k, --payer <KEYPAIR>Archivo keypair del pagador o billetera de hardware
-C, --config <PATH>Ruta del archivo de configuración de Solana
-v, --verboseMostrar información adicional

Ejemplo de Flujo de Trabajo Completo con CLI

A continuación se muestra un flujo de trabajo completo usando todos los CLIs para configurar un token compatible desde cero:

# ============================================================================
# STEP 1: Configure Solana CLI
# ============================================================================
solana config set --url localhost
# ============================================================================
# STEP 2: Create Token22 Mint with Metadata + DefaultAccountState Extensions
# ============================================================================
# Create the mint with:
# - Token-2022 program
# - Freeze authority enabled
# - Default account state = frozen (all new accounts start frozen)
# - Metadata extension with token_acl field for auto-detection
spl-token create-token \
--program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb \
--enable-freeze \
--default-account-state frozen \
--enable-metadata
# Output:
# Creating token 7KzLwpXMzKa8JiqYr2ookFjxLx1xMF4xM4YhVqPJpump
# Address: 7KzLwpXMzKa8JiqYr2ookFjxLx1xMF4xM4YhVqPJpump
# Save the mint address for use in subsequent commands
MINT=7KzLwpXMzKa8JiqYr2ookFjxLx1xMF4xM4YhVqPJpump
# Initialize the token metadata
spl-token initialize-metadata $MINT "Compliant Token" "COMP" "https://example.com/metadata.json"
# Add the token_acl field for wallet auto-detection
# This tells wallets/SDKs which gate program to use for thaw
spl-token update-metadata $MINT token_acl GATEzzqxhJnsWF6vHRsgtixxSB8PaQdcqGEVTEHWiULz
# Verify the token was created correctly
spl-token display $MINT
# ============================================================================
# STEP 3: Create Token ACL Config
# ============================================================================
# This transfers freeze authority from your wallet to the Token ACL MintConfig PDA
token-acl create-config $MINT \
--gating-program GATEzzqxhJnsWF6vHRsgtixxSB8PaQdcqGEVTEHWiULz
# Output:
# ✅ Config created for mint 7KzLwpXMzKa8JiqYr2ookFjxLx1xMF4xM4YhVqPJpump
# MintConfig PDA: 9xYzAbCdEfGhIjKlMnOpQrStUvWxYz123456789abc
# ============================================================================
# STEP 4: Create ABL Lists
# ============================================================================
# Create a block list for sanctions compliance
allow-block-list create-list --mode block
# Output:
# list_config: 5HnJkLmNoPqRsTuVwXyZ987654321defghijk
# seed: 3AbCdEfGhIjKlMnOpQrStUvWxYz123456789
# Save the block list address
BLOCK_LIST=5HnJkLmNoPqRsTuVwXyZ987654321defghijk
# ============================================================================
# STEP 5: Apply Lists to Mint
# ============================================================================
# Configure the block list to be used for this mint's permissionless operations
allow-block-list apply-lists-to-mint $MINT $BLOCK_LIST
# ============================================================================
# STEP 6: Enable Permissionless Thaw
# ============================================================================
# Allow users to thaw their own accounts (if not on block list)
# --enable-thaw: Users can self-service unfreeze after passing gate checks
# --disable-freeze: Only authority can freeze
token-acl set-instructions --enable-thaw --disable-freeze $MINT
# ============================================================================
# STEP 7: Manage Block List (Compliance Operations)
# ============================================================================
# To fully block a user, you need TWO steps:
# 1. Add to block list (prevents future thawing)
# 2. Freeze their token account (stops current usage)
# Step 7a: Add wallet to block list
# Replace with actual wallet address to block (must be valid base58 pubkey)
allow-block-list add-wallet $BLOCK_LIST <WALLET_TO_BLOCK>
# Step 7b: Freeze their existing token account (if they have one)
# This requires the token account address, not the wallet address
# spl-token address --verbose --token $MINT to get the token account address
# token-acl freeze <TOKEN_ACCOUNT_ADDRESS>
# Note: Adding to block list alone only prevents them from THAWING.
# If their account is already thawed, they can still use it until you freeze it!
# Later, if sanctions are lifted:
# 1. Remove from block list
# allow-block-list remove-wallet $BLOCK_LIST <WALLET_ADDRESS>
# 2. User can then thaw their account again
# ============================================================================
# STEP 8: User Creates Account and Thaws
# ============================================================================
# A user can now create their token account and thaw it in one command
# Use your own wallet or generate one: solana-keygen new --no-outfile
USER_WALLET=$(solana address) # Uses your configured wallet
token-acl create-ata-and-thaw-permissionless --mint $MINT --owner $USER_WALLET
# Output:
# ✅ Created ATA: 8AbCdEfGhIjKlMnOpQrStUvWxYz123456789xyz
# ✅ Thawed successfully!
# ============================================================================
# STEP 9: Mint Tokens to User
# ============================================================================
# Now the issuer can mint tokens to the user's thawed account
spl-token mint $MINT 1000 --recipient-owner $USER_WALLET
# Verify balance
spl-token balance $MINT

Metadatos de Token para Detección Automática

Agregar el campo de metadatos token_acl es fundamental para la integración con billeteras. Cuando billeteras como Phantom o SDKs como @solana/token-helpers detectan este campo, incluyen automáticamente instrucciones de descongelación al crear token accounts.

spl-token update-metadata $MINT token_acl GATEzzqxhJnsWF6vHRsgtixxSB8PaQdcqGEVTEHWiULz

Próximos Pasos

  1. Prueba el Workshop: Clona el repositorio token-acl y ejecuta los ejemplos de demostración. Lee la implementación del ACL y del ABL Gate Program.

  2. Crea Programas Gate Personalizados: El ABL Gate Program es solo una implementación de referencia. Crea tu propio Gate Program para integrarte con tu infraestructura de cumplimiento existente, proveedores de identidad, o implementa lógica personalizada que se ajuste a tus requisitos específicos

  3. Integración con DeFi: Los tokens Token ACL son totalmente componibles con protocolos DeFi

  4. Lee la Especificación: Revisa sRFC37 para la especificación técnica completa y únete a la discusión de sRFC37

Conclusión

Token ACL (sRFC37) ofrece una solución poderosa para empresas que necesitan tokens con permisos y cumplimiento normativo sin sacrificar la experiencia de usuario que hace valiosa a la blockchain. Beneficios clave:

  • Activación Instantánea: Los usuarios pueden descongelar sus cuentas de forma autónoma
  • Control Total de Cumplimiento: Listas de permitidos, listas de bloqueados o lógica personalizada
  • Programas Gate Flexibles: Usa la implementación de referencia ABL o crea Gate Programs personalizados que se integren con tu infraestructura de cumplimiento
  • Integración Transparente: Los SDKs gestionan la complejidad automáticamente
  • Componible: Compatible con los protocolos DeFi existentes
  • Auditado: Programas listos para producción desplegados en mainnet

La combinación de la extensión DefaultAccountState de Token-2022 con las operaciones sin permisos de Token ACL crea un nuevo paradigma para la emisión de tokens con cumplimiento normativo en Solana.

Is this page helpful?

Tabla de Contenidos

Editar Página