Токени з дозволами за допомогою Token ACL (sRFC37)

Token ACL (Access Control List) — це програма Solana, яка забезпечує відповідність вимогам та керування доступом до токенів без шкоди для користувацького досвіду. Вона реалізує sRFC37, дозволяючи підприємствам створювати токени з функціональністю списків дозволів/блокувань, зберігаючи при цьому безперебійний UX, якого очікують користувачі.

Проблема

Підприємствам потрібні токени, що відповідають вимогам і можуть:

  1. Забезпечувати виконання вимог KYC/AML
  2. Блокувати адреси під санкціями
  3. Обмежувати передачу токенів лише авторизованим сторонам

Традиційний підхід використовує розширення DefaultAccountState Token-2022 для створення облікових записів у замороженому стані, що вимагає ручного втручання для розморожування кожного облікового запису:

┌─────────────────────────────────────────────────────┐
│ 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 │
│ │
└─────────────────────────────────────────────────────┘

Це створює значні труднощі та нівелює переваги миттєвих транзакцій у блокчейні без потреби в дозволах.

Рішення

Token ACL забезпечує розморожування без дозволів — користувачі можуть автоматично розморожувати власні облікові записи, якщо відповідають критеріям, визначеним 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 │
│ │
└─────────────────────────────────────────────────────┘

Навчальна референсна реалізація

Цей посібник містить повну робочу реалізацію, яку можна запустити локально. Вихідний код надає референсні реалізації для дослідження та навчальних цілей.

Код програм ACL доступний у репозиторії token-acl, а ABL Gate Program доступна у репозиторії abl-gate-program.

Важливо: ABL (Allow Block List) Gate Program, використана в цьому посібнику, є референсною реалізацією. Незважаючи на те, що вона пройшла аудит і готова до використання в продакшені, емітенти мають право створювати власні Gate Programs, що краще відповідають їхнім конкретним потребам у сфері відповідності. Ви зобов'язані дотримуватися лише специфікації Token ACL (sRFC37), а не цього конкретного дизайну Gate Program.

НЕ використовуйте цей код безпосередньо у продакшені без:

  • Комплексних аудитів безпеки
  • Належних систем управління ключами
  • Перевірки відповідності нормативним вимогам
  • Юридичної консультації

Чому Token ACL?

АспектТрадиційне заморожуванняToken ACL
Активація облікового записуВручну (хвилини/дні)Миттєво (самообслуговування)
Користувацький досвідПоганийБезперебійний
Контроль відповідностіПовнийПовний
Блокування санкційВручнуАвтоматично через Gate Program
Зусилля для інтеграціїВисокіНизькі (доступний SDK)
КомпонованістьОбмеженаПовна (сумісна з DeFi)

Token ACL проти Transfer Hooks

І Token ACL, і Transfer Hooks є рішеннями Token-2022 для додавання власної логіки до токенів, але вони слугують різним цілям і мають різні компроміси:

АспектToken ACLTransfer Hooks
Коли виконується логікаЛише під час операцій заморожування/розморожуванняПри кожній передачі
Накладні витрати на передачуВідсутні — передачі є стандартнимиДодаткові CU + облікові записи при кожній передачі
Залежності облікових записівЛише під час активації облікового записуНеобхідні при кожній транзакції передачі
Компонованість у DeFiПовна — протоколи працюють в звичайному режиміОбмежена — багато протоколів вносять до чорного списку
Найкраще підходить дляKYC/AML, санкції, списки дозволів/блокуваньРоялті, власна перевірка передач
Складність для користувачівНизька — одноразова операція розморожуванняВища — кожна передача потребує додаткових даних

Коли використовувати Token ACL

Обирайте Token ACL, коли потрібно контролювати хто може тримати ваш токен:

  • Відповідність KYC/AML — перевіряйте власників перед тим, як вони зможуть отримати токени
  • Перевірка санкцій — блокування конкретних адрес
  • Обмеження для акредитованих інвесторів — обмежуйте власників токенів лише перевіреними сторонами
  • Блокування PDA — заборона смарт-контрактам тримати токени

Коли використовувати Transfer Hooks

Обирайте Transfer Hooks, коли потрібно контролювати як переміщуються токени:

  • Роялті для NFT — стягуйте комісії за кожну передачу
  • Обмеження передач — обмежуйте суми або частоту передач
  • Власна логіка передач — виконуйте код при кожному переміщенні
  • Аналітика в мережі — відстежуйте всі переміщення токенів

Взаємодоповнюючі рішення

Token ACL і Transfer Hooks можна використовувати разом. Наприклад, можна використовувати Token ACL для контролю того, хто може тримати ваш токен (відповідність вимогам), тоді як Transfer Hooks застосовувати для забезпечення виплати роялті при кожній передачі.

Огляд архітектури

Token ACL складається з трьох основних компонентів:

  1. Token ACL Program: Основна програма, що керує делегуванням повноважень заморожування та операціями без дозволів
  2. Gate Program: Власна логіка, яка визначає, хто може розморожувати/заморожувати (наприклад, ABL Gate Program для списків дозволів/блокувань)
  3. MintConfig: Конфігурація для кожного мінту, що зберігає налаштування та делегує повноваження заморожування
┌─────────────────────────────────────────────────────────────────┐
│ 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 │ │
│ └─────────┘ └─────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘

Ключові концепції

  1. Делегування повноважень заморожування: Коли ви створюєте конфігурацію Token ACL, повноваження заморожування мінту передаються MintConfig PDA. Це дозволяє Token ACL керувати операціями заморожування/розморожування.

  2. Gate Programs: Зовнішні програми, що реалізують логіку дозволів/блокувань. ABL (Allow Block List) Gate Program є референсною реалізацією — емітенти можуть створювати власні Gate Programs з іншою логікою (наприклад, перевірка KYC в мережі, перевірка санкцій на основі оракулів або інтеграція з протоколами ідентифікації).

  3. Операції без дозволів: Користувачі можуть розморожувати власні облікові записи без втручання емітента, за умови схвалення з боку Gate Program.

  4. Інтеграція з TokenMetadata: Додавання поля token_acl до метаданих вашого мінту дозволяє автоматично виявляти його гаманцями та SDK, наприклад @solana/token-helpers.

Автовиявлення за допомогою TokenMetadata

Коли ви додаєте поле token_acl до розширення TokenMetadata вашого мінту, що вказує на адресу Gate Program, SDK на кшталт @solana/token-helpers можуть автоматично виявляти мінти Token ACL та включати інструкції розморожування під час створення токен-акаунтів.

Режими ABL Gate Program

ABL є референсною реалізацією

ABL Gate Program, показана тут, є референсною реалізацією, що охоплює поширені випадки використання списків дозволів/блокувань. Однак ви не прив'язані до цього дизайну. Специфікація Token ACL (sRFC37) визначає лише інтерфейс між Token ACL та Gate Programs — ви можете створювати власні Gate Programs з:

  • Інтеграцією з протоколами ідентифікації/KYC в мережі
  • Перевіркою санкцій у реальному часі на основі оракулів
  • Робочими процесами підтвердження через мульти-підпис
  • Правилами доступу на основі часу або умов
  • Будь-якою іншою власною логікою відповідності

Єдина вимога — реалізація інтерфейсу Gate Program, визначеного в sRFC37.

ABL (Allow Block List) Gate Program підтримує декілька режимів:

РежимОписВипадок використання
AllowAllEoasУсі звичайні гаманці (не PDA) можуть розморожуватиВідкриті токени з блокуванням PDA
AllowРозморожувати можуть лише гаманці зі списку дозволівТокени з обов'язковим KYC
BlockУсі гаманці, КРІМ тих, що у списку блокувань, можуть розморожуватиВідповідність санкційним вимогам
КомбінованийПоєднання списків дозволів і блокуваньПовне налаштування відповідності

Пріоритет списку блокувань

При використанні комбінованих списків список блокувань завжди має пріоритет. Гаманець, що знаходиться одночасно у списку дозволів І списку блокувань, НЕ зможе розморозити свій обліковий запис.

Адреси програм

Для зручності програми вже розгорнуті в devnet. Ви можете використовувати наведені нижче адреси. Реліз у mainnet відбудеться після завершення аудитів.

ПрограмаАдреса
Token ACLTACLkU6CiCdkQN2MjoyDkVg2yAH9zkxiHDsiztQ52TP
ABL Gate ProgramGATEzzqxhJnsWF6vHRsgtixxSB8PaQdcqGEVTEHWiULz

Попередні вимоги

Щоб запустити приклади локально, переконайтеся, що клоновано програми у ваш локальний validator:

  1. Solana CLI

    (Для локального запуску використовуйте версію 2.x, НЕ 3.x — наразі існує відома проблема з метаданими Token-2022, яка призводить до помилки на кроці додавання додаткових метаданих)

    solana --version
  2. Node.js 18+ та pnpm

  3. Локальний validator з необхідними програмами:

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

Повна реалізація

Крок 1: Встановлення залежностей

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

Крок 2: Створення токена за допомогою Token ACL

Ось повний приклад, що створює токен з відповідністю вимогам за допомогою 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;
}

Крок 3: Створення конфігурації Token ACL

Після створення мінту створіть конфігурацію 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;
}

Крок 4: Налаштування ABL Gate Program

Створіть ABL-список і налаштуйте додаткові мета-дані:

// 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");
}

Крок 5: Увімкнення розморожування без дозволів

Надайте користувачам можливість розморожувати власні облікові записи:

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");
}

Крок 6: Користувач розморожує свій обліковий запис

Тепер користувачі можуть розморожувати власні облікові записи за допомогою 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!");
}

Використання @solana/token-helpers для автоматичного розморожування

SDK @solana/token-helpers може автоматично виявляти мінти Token ACL та додавати інструкції розморожування:

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}`);

Вимога до TokenMetadata

Для коректного автовиявлення через @solana/token-helpers ваш мінт повинен мати:

  1. Ініціалізоване розширення TokenMetadata
  2. Поле additionalMetadata з ключем token_acl та значенням, встановленим на адресу Gate Program

Комбіновані списки дозволів і блокувань

Для максимального контролю відповідності поєднуйте списки дозволів і блокувань:

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");
}

Поведінка комбінованого списку

┌─────────────────────────────────────────────────────┐
│ 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! │
│ │
└─────────────────────────────────────────────────────┘

Випадки використання

1. Цінні папери (вимагають KYC)

Використовуйте список дозволів, щоб гарантувати, що лише інвестори, які пройшли KYC, можуть тримати токени:

// 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. Відповідність санкційним вимогам

Використовуйте список блокувань, щоб заборонити адресам під санкціями отримувати токени:

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

3. Відкритий токен із захистом PDA

Використовуйте AllowAllEoas, щоб дозволити всім звичайним гаманцям тримати токени, блокуючи при цьому PDA (смарт-контракти):

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

4. Повна корпоративна відповідність

Поєднуйте список дозволів + список блокувань для повного контролю:

  • Список дозволів: інвестори, які пройшли KYC
  • Список блокувань: адреси під санкціями, звільнені співробітники тощо

Міркування щодо продакшену

Перед розгортанням у продакшені:

  1. Аудити безпеки: Замовте професійні аудити безпеки вашої реалізації та будь-яких власних Gate Programs

  2. Управління ключами: Використовуйте належні засоби зберігання для ключів авторизації. Розгляньте можливість мульти-підпису для чутливих операцій

  3. Регуляторна відповідність: Проконсультуйтеся з юридичними експертами щодо регулювання цінних паперів, вимог KYC/AML та відповідності санкційним вимогам

  4. Управління списками: Створіть надійні системи для управління списками дозволів/блокувань, включно з:

    • Інтеграцією з автоматизованою перевіркою санкцій
    • Інтеграцією з KYC-провайдером
    • Журналюванням аудиту
  5. Моніторинг: Запровадьте моніторинг для:

    • Невдалих спроб розморожування (потенційні проблеми з відповідністю)
    • Змін у списках
    • Використання ключів авторизації
  6. Аварійне відновлення: Плануйте ротацію ключів, відновлення списків та процедури екстреного заморожування

Версія Solana CLI

Token ACL з TokenMetadata вимагає Solana CLI 2.x. Існує відома проблема з CLI 3.x, яка порушує функцію автоматичного розширення TokenMetadata. Завжди перевіряйте версію вашого CLI перед розгортанням.

Інтерфейс командного рядка (CLI)

Як Token ACL, так і ABL Gate Program надають CLI для керування конфігураціями та списками без написання коду. Це зручно для операційних команд.

Token ACL CLI

Token ACL CLI керує конфігураціями мінтів та операціями заморожування/розморожування.

Встановлення

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

Команди Token ACL

КомандаОпис
create-configСтворює нову конфігурацію мінту (передає повноваження заморожування)
delete-configВидаляє конфігурацію мінту
set-authorityВстановлює авторизацію конфігурації мінту
set-gating-programВстановлює програму шлюзування для конфігурації мінту
set-instructionsУвімкнути/вимкнути безозвільне розморожування/заморожування
thawРозморожує token account (потрібні повноваження)
freezeЗаморожує token account (потрібні повноваження)
thaw-permissionlessРозморожує token account без необхідності дозволу
freeze-permissionlessЗаморожує token account без необхідності дозволу
create-ata-and-thaw-permissionlessСтворює ATA та розморожує однією командою

Створення конфігурації Token ACL

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

Увімкнення безозвільного розморожування

# 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>

Операції розморожування/заморожування

# 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>

Створення ATA та розморожування однією командою

# 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)

ABL Gate CLI керує списками дозволів/блокувань та записами гаманців.

Встановлення

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

Команди ABL Gate

КомандаОпис
create-listСтворює новий список дозволів/блокувань
delete-listВидаляє список
add-walletДодає гаманець до списку
remove-walletВидаляє гаманець зі списку
apply-lists-to-mintНалаштовує, які списки застосовуються до мінту

Створення списку

# 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

Команда виводить PDA-адресу list_config та seedзбережіть їх!

Керування гаманцями у списках

# 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>

Застосування списків до мінту

# 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>

Глобальні параметри CLI

Обидва CLI підтримують такі параметри:

ПараметрОпис
-u, --url <URL>RPC URL (за замовчуванням: із конфігурації Solana)
-k, --payer <KEYPAIR>Файл keypair платника або апаратний гаманець
-C, --config <PATH>Шлях до файлу конфігурації Solana
-v, --verboseВідображати додаткову інформацію

Приклад повного робочого процесу CLI

Ось повний робочий процес із використанням усіх CLI для налаштування сумісного токена з нуля:

# ============================================================================
# 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

Метадані токена для автоматичного визначення

Додавання поля метаданих token_acl є критично важливим для інтеграції з гаманцями. Коли гаманці на зразок Phantom або SDK на зразок @solana/token-helpers виявляють це поле, вони автоматично включають інструкції розморожування під час створення token account.

spl-token update-metadata $MINT token_acl GATEzzqxhJnsWF6vHRsgtixxSB8PaQdcqGEVTEHWiULz

Наступні кроки

  1. Спробуйте воркшоп: Клонуйте репозиторій token-acl та запустіть демонстраційні приклади. Ознайомтеся з реалізацією ACL та ABL Gate Program.

  2. Створіть власні програми шлюзування: ABL Gate Program — це лише референсна реалізація. Створіть власну програму шлюзування для інтеграції з наявною інфраструктурою відповідності, постачальниками ідентифікації або реалізуйте власну логіку відповідно до ваших конкретних вимог

  3. Інтеграція з DeFi: Токени Token ACL повністю компонуються з протоколами DeFi

  4. Ознайомтеся зі специфікацією: Перегляньте sRFC37 для ознайомлення з повною технічною специфікацією та приєднайтеся до обговорення sRFC37

Висновок

Token ACL (sRFC37) надає потужне рішення для підприємств, яким потрібні сумісні, дозволені токени без жертвування користувацьким досвідом, що робить блокчейн цінним. Ключові переваги:

  • Миттєва активація: Користувачі можуть самостійно розморозити свої рахунки
  • Повний контроль відповідності: Списки дозволів, списки блокувань або власна логіка
  • Гнучкі програми шлюзування: Використовуйте референсну реалізацію ABL або створіть власні програми шлюзування з інтеграцією у вашу інфраструктуру відповідності
  • Безшовна інтеграція: SDK автоматично обробляє складність
  • Компонованість: Сумісний з наявними протоколами DeFi
  • Перевірено аудитом: Програми, готові до використання в продакшні, розгорнуті в мейннеті

Поєднання розширення DefaultAccountState Token-2022 з безозвільними операціями Token ACL створює нову парадигму для випуску сумісних токенів на Solana.

Is this page helpful?

Зміст

ПроблемаРішенняЧому Token ACL?Token ACL проти Transfer HooksКоли використовувати Token ACLКоли використовувати Transfer HooksОгляд архітектуриКлючові концепціїРежими ABL Gate ProgramАдреси програмПопередні вимогиПовна реалізаціяКрок 1: Встановлення залежностейКрок 2: Створення токена за допомогою Token ACLКрок 3: Створення конфігурації Token ACLКрок 4: Налаштування ABL Gate ProgramКрок 5: Увімкнення розморожування без дозволівКрок 6: Користувач розморожує свій обліковий записВикористання @solana/token-helpers для автоматичного розморожуванняКомбіновані списки дозволів і блокуваньПоведінка комбінованого спискуВипадки використання1. Цінні папери (вимагають KYC)2. Відповідність санкційним вимогам3. Відкритий токен із захистом PDA4. Повна корпоративна відповідністьМіркування щодо продакшенуІнтерфейс командного рядка (CLI)Token ACL CLIВстановленняКоманди Token ACLСтворення конфігурації Token ACLУвімкнення безозвільного розморожуванняОперації розморожування/заморожуванняСтворення ATA та розморожування однією командоюABL Gate CLI (allow-block-list)ВстановленняКоманди ABL GateСтворення спискуКерування гаманцями у спискахЗастосування списків до мінтуГлобальні параметри CLIПриклад повного робочого процесу CLIНаступні крокиВисновок
Редагувати сторінку