Token ACL(アクセス制御リスト)は、ユーザーエクスペリエンスを損なうことなくコンプライアンスに準拠したパーミッション付きトークンを実現するSolanaプログラムです。sRFC37を実装しており、企業がシームレスなUXを維持しながら許可/ブロックリスト機能を持つトークンを作成できます。
課題
企業は以下を実現できるコンプライアンス準拠のトークンを必要としています:
- KYC/AML要件の適用
- 制裁対象アドレスのブロック
- 承認済み当事者へのトークン転送の制限
従来のアプローチでは、Token-2022のDefaultAccountState拡張機能を使用してアカウントを凍結状態で作成し、各アカウントを解凍するために手動での対応が必要でした:
┌─────────────────────────────────────────────────────┐│ 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(許可/ブロックリスト)Gate Programはリファレンス実装です。監査済みで本番環境対応ですが、発行者は特定のコンプライアンス要件に合わせたカスタムGate Programを自由に作成できます。Token ACL仕様(sRFC37)にのみ従う必要があり、特定のGate Programの設計に縛られることはありません。
以下を実施せずに本番環境でこのコードを直接使用しないでください:
- 包括的なセキュリティ監査
- 適切な鍵管理システム
- 法規制コンプライアンスのレビュー
- 法的相談
Token ACLを選ぶ理由
| 項目 | 従来の凍結方式 | Token ACL |
|---|---|---|
| アカウントの有効化 | 手動(数分〜数日) | 即時(セルフサービス) |
| ユーザーエクスペリエンス | 低い | シームレス |
| コンプライアンス制御 | 完全 | 完全 |
| 制裁対象のブロック | 手動 | Gate Programによる自動化 |
| 統合の手間 | 高い | 低い(SDK利用可能) |
| コンポーザビリティ | 限定的 | 完全(DeFiと連携可能) |
Token ACL vs Transfer Hooks
Token ACLとTransfer HooksはどちらもToken-2022のソリューションでトークンにカスタムロジックを追加できますが、それぞれ異なる目的を持ち、トレードオフが異なります:
| 項目 | Token ACL | Transfer 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は3つの主要コンポーネントで構成されています:
- Token ACL Program: 凍結権限の委任とパーミッションレス操作を管理するコアプログラム
- Gate Program: 誰が解凍/凍結できるかを決定するカスタムロジック(例:許可/ブロックリスト用ABL Gate Program)
- 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 │ ││ └─────────┘ └─────────┘ ││ │└─────────────────────────────────────────────────────────────────┘
主要概念
-
凍結権限の委任: Token ACL設定を作成すると、ミントの凍結権限がMintConfig PDAに転送されます。これによりToken ACLが凍結/解凍操作を管理できるようになります。
-
Gate Programs: 許可/ブロックロジックを実装する外部プログラムです。ABL(許可/ブロックリスト)Gate Programはリファレンス実装であり、発行者は異なるロジック(例:オンチェーンKYC検証、オラクルベースの制裁チェック、ID プロトコルとの統合)を持つカスタムGate Programを構築できます。
-
パーミッションレス操作: Gate Programが承認する限り、ユーザーは発行者の介入なしに自分自身のアカウントを解凍できます。
-
TokenMetadata統合: ミントのメタデータに
token_aclフィールドを追加すると、ウォレットや@solana/token-helpersなどのSDKによる自動検出が有効になります。
TokenMetadataによる自動検出
ミントのTokenMetadata拡張機能にGate ProgramアドレスへのポインタとなるTokenMetadataフィールドを追加すると、@solana/token-helpersなどのSDKがToken ACLミントを自動検出し、トークンアカウント作成時に解凍instructionsを含めることができます。
ABL Gate Programのモード
ABLはリファレンス実装です
ここで紹介するABL Gate Programは、一般的な許可/ブロックリストのユースケースをカバーするリファレンス実装です。ただし、この設計に縛られる必要はありません。Token ACL仕様(sRFC37)はToken ACLとGate Programs間のインターフェースのみを定義しており、以下のようなカスタムGate Programを作成できます:
- オンチェーンID/KYCプロトコルとの統合
- オラクルベースのリアルタイム制裁スクリーニング
- マルチシグ承認ワークフロー
- 時間ベースまたは条件付きアクセスルール
- その他あらゆるカスタムコンプライアンスロジック
唯一の要件は、sRFC37で定義されたGate Programインターフェースを実装することです。
ABL(許可/ブロックリスト)Gate Programはいくつかのモードをサポートしています:
| モード | 説明 | ユースケース |
|---|---|---|
AllowAllEoas | すべての通常ウォレット(非PDA)が解凍可能 | PDAブロッキング付きオープントークン |
Allow | 許可リスト上のウォレットのみ解凍可能 | KYC必須トークン |
Block | ブロックリスト上のウォレットを除くすべてが解凍可能 | 制裁コンプライアンス |
| 複合 | 許可リストとブロックリストを組み合わせ | 完全なコンプライアンス設定 |
ブロックリストの優先順位
複合リストを使用する場合、ブロックリストが常に優先されます。許可リストとブロックリストの両方に登録されているウォレットは解凍できません。
プログラムアドレス
便宜上、各プログラムはすでにdevnetにデプロイされています。以下のアドレスを使用できます。メインネットへのリリースは監査完了後に行われます。
| プログラム | アドレス |
|---|---|
| Token ACL | TACLkU6CiCdkQN2MjoyDkVg2yAH9zkxiHDsiztQ52TP |
| ABL Gate Program | GATEzzqxhJnsWF6vHRsgtixxSB8PaQdcqGEVTEHWiULz |
前提条件
サンプルをローカルで実行するには、必要なプログラムをローカルvalidatorにクローンしてください:
-
Solana CLI
(ローカル実行には2.xを使用してください。3.xは使用しないでください。現時点ではToken-2022メタデータに既知の問題があり、追加メタデータの追加ステップで失敗します)
solana --version -
Node.js 18以上およびpnpm
-
ローカル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 SDKimport {getCreateConfigInstruction,findMintConfigPda,getTogglePermissionlessInstructionsInstruction,findThawExtraMetasAccountPda} from "@token-acl/sdk";// ABL Gate Program SDKimport {getCreateListInstruction,getSetupExtraMetasInstruction,getAddWalletInstruction,findListConfigPda,findWalletEntryPda,ABL_PROGRAM_ADDRESS,Mode} from "@token-acl/abl-sdk";// TLV sizes for Token-2022 extensionsconst TYPE_SIZE = 2;const LENGTH_SIZE = 2;async function createTokenACLMint() {// Setup RPCconst rpc = createSolanaRpc("http://localhost:8899");const rpcSubscriptions = createSolanaRpcSubscriptions("ws://localhost:8900");const sendAndConfirm = sendAndConfirmTransactionFactory({rpc,rpcSubscriptions});// Load your payer keypairconst payer = await loadKeypair("~/.config/solana/id.json");// Generate mint keypairconst mint = await generateKeyPairSigner();console.log(`🪙 Mint: ${mint.address}`);// TokenMetadata config - includes 'token_acl' for auto-detectionconst TOKEN_NAME = "Compliant Token";const TOKEN_SYMBOL = "COMP";const TOKEN_URI = "";const TOKEN_ACL_KEY = "token_acl";// Define extensionsconst defaultAccountStateExtension = extension("DefaultAccountState", {state: AccountState.Frozen});const metadataPointerExtension = extension("MetadataPointer", {authority: payer.address,metadataAddress: mint.address});const extensions = [defaultAccountStateExtension, metadataPointerExtension];// Calculate mint sizeconst 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 rentconst mintRent = await rpc.getMinimumBalanceForRentExemption(BigInt(totalSpace)).send();// Get extension pre-initialization instructionsconst extensionInstructions = getPreInitializeInstructionsForMintExtensions(mint.address,extensions);// Build transactionconst { 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 sendconst 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 automaticallyasync function setupAllowAllEoas(mintAddress: Address,mintConfigPda: Address,payer: TransactionSigner) {const listSeed = mintAddress; // Use mint as seedconst [listConfigPda] = await findListConfigPda({authority: payer.address,seed: listSeed});const createListIx = getCreateListInstruction({authority: payer,listConfig: listConfigPda,mode: Mode.AllowAllEoas, // All EOAs can thawseed: 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 SDKconst accountRetriever = async (addr: Address) => {return await fetchEncodedAccount(rpc, addr);};// The SDK handles all the complexity of fetching extra metasconst thawIx =await createThawPermissionlessIdempotentInstructionWithExtraMetas(payer, // authority (signer)userAta, // token account to thawmintAddress, // mintuserAddress, // token account ownerTOKEN_ACL_PROGRAM_ADDRESS, // Token ACL programaccountRetriever // account fetcher);// Send transaction signed by payer...console.log("✅ Account thawed permissionlessly!");}
@solana/token-helpersを使った自動解凍
@solana/token-helpers SDKはToken ACLミントを自動検出し、解凍instructionsを含めることができます:
import { createAndConfirmAssociatedTokenAccount } from "@solana/token-helpers";// This automatically includes thaw instruction if mint has 'token_acl' metadataconst { 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の自動検出を機能させるには、ミントに以下が必要です:
TokenMetadata拡張機能の初期化- キーが
token_acl、値がGate ProgramアドレスのadditionalMetadataフィールド
複合許可リスト+ブロックリスト
最大限のコンプライアンス制御のために、許可リストとブロックリストを組み合わせます:
async function setupCompositeLists(mintAddress: Address,mintConfigPda: Address,payer: TransactionSigner) {// Create ALLOW listconst 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 listconst 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 listsconst [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 listconst createListIx = getCreateListInstruction({authority: issuer,listConfig: allowListPda,mode: Mode.Allow,seed: mintAddress});// After KYC verification, add investorawait addToAllowList(allowListPda, kycVerifiedInvestor, issuer);
2. 制裁コンプライアンス
ブロックリストを使用して、制裁対象のアドレスがトークンを受け取れないようにします:
// Create block listconst createListIx = getCreateListInstruction({authority: complianceOfficer,listConfig: blockListPda,mode: Mode.Block,seed: mintAddress});// Block sanctioned addressawait addToBlockList(blockListPda, sanctionedAddress, complianceOfficer);
3. PDA保護付きオープントークン
AllowAllEoasを使用して、すべての通常ウォレットを許可しながらPDA(スマートコントラクト)をブロックします:
const createListIx = getCreateListInstruction({authority: payer,listConfig: listConfigPda,mode: Mode.AllowAllEoas, // Regular wallets OK, PDAs blockedseed: mintAddress});
4. 完全な企業向けコンプライアンス
完全な制御のために許可リスト+ブロックリストを組み合わせます:
- 許可リスト:KYC認証済み投資家
- ブロックリスト:制裁対象アドレス、退職済み従業員など
本番環境への考慮事項
本番環境にデプロイする前に:
-
セキュリティ監査:実装およびカスタムGate Programについて、専門家によるセキュリティ監査を受けてください
-
鍵管理:権限鍵には適切なカストディソリューションを使用してください。重要な操作にはマルチシグの検討を
-
法規制コンプライアンス:証券規制、KYC/AML要件、制裁コンプライアンスについて法律専門家に相談してください
-
リスト管理:許可/ブロックリストを管理するための堅牢なシステムを構築してください。以下を含みます:
- 制裁スクリーニングの自動化統合
- KYCプロバイダーの統合
- 監査ログ
-
モニタリング:以下についてのモニタリングを実装してください:
- 解凍失敗の試み(コンプライアンス上の問題の可能性)
- リストの変更
- 権限鍵の使用状況
-
ディザスタリカバリ:鍵のローテーション、リストの復旧、緊急凍結手順を計画してください
Solana CLIのバージョン
TokenMetadataを使用したToken ACLには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.iocargo install token-acl-cli# Verify installationtoken-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 | associated token accountの作成とサンド解除を1コマンドで実行する |
トークン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-freezetoken-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>
associated token accountの作成とサンド解除を1コマンドで実行する
# Creates associated token account and thaws it automaticallytoken-acl create-ata-and-thaw-permissionless --mint <MINT_ADDRESS> --owner <WALLET_ADDRESS>
ABL Gate CLI(allow-block-list)
ABL Gate CLIは、許可リスト・ブロックリストおよびウォレットエントリを管理します。
インストール
# Install from crates.iocargo 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
コマンドはlist_config PDAアドレスと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 listallow-block-list remove-wallet <LIST_ADDRESS> <WALLET_ADDRESS>
ミントへのリストの適用
# Apply a single list to a mintallow-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-detectionspl-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 commandsMINT=7KzLwpXMzKa8JiqYr2ookFjxLx1xMF4xM4YhVqPJpump# Initialize the token metadataspl-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 thawspl-token update-metadata $MINT token_acl GATEzzqxhJnsWF6vHRsgtixxSB8PaQdcqGEVTEHWiULz# Verify the token was created correctlyspl-token display $MINT# ============================================================================# STEP 3: Create Token ACL Config# ============================================================================# This transfers freeze authority from your wallet to the Token ACL MintConfig PDAtoken-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 complianceallow-block-list create-list --mode block# Output:# list_config: 5HnJkLmNoPqRsTuVwXyZ987654321defghijk# seed: 3AbCdEfGhIjKlMnOpQrStUvWxYz123456789# Save the block list addressBLOCK_LIST=5HnJkLmNoPqRsTuVwXyZ987654321defghijk# ============================================================================# STEP 5: Apply Lists to Mint# ============================================================================# Configure the block list to be used for this mint's permissionless operationsallow-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 freezetoken-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-outfileUSER_WALLET=$(solana address) # Uses your configured wallettoken-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 accountspl-token mint $MINT 1000 --recipient-owner $USER_WALLET# Verify balancespl-token balance $MINT
自動検出のためのトークンメタデータ
token_aclメタデータフィールドの追加は、ウォレット統合において非常に重要です。PhantomなどのウォレットやSDK(@solana/token-helpersなど)がこのフィールドを検出すると、token accountの作成時にサンド解除のinstructionsが自動的に含まれます。
spl-token update-metadata $MINT token_acl GATEzzqxhJnsWF6vHRsgtixxSB8PaQdcqGEVTEHWiULz
次のステップ
-
ワークショップを試す:token-aclリポジトリをクローンし、デモサンプルを実行してください。ACLとABL Gateプログラムの実装をお読みください。
-
カスタムゲートプログラムの構築:ABL Gateプログラムはあくまで参照実装です。既存のコンプライアンスインフラやIDプロバイダーと統合するか、特定の要件に合わせたカスタムロジックを実装した独自のゲートプログラムを構築してください。
-
DeFiとの統合:Token ACLトークンはDeFiプロトコルと完全にコンポーザブルです。
-
仕様を読む:完全な技術仕様についてはsRFC37を参照し、sRFC37のディスカッションにご参加ください。
まとめ
Token ACL(sRFC37)は、ブロックチェーンの価値であるユーザー体験を損なうことなく、準拠した許可型トークンを必要とする企業向けに強力なソリューションを提供します。主なメリット:
- 即時アクティベーション:ユーザーは自分でアカウントのサンド解除を行えます
- 完全なコンプライアンス制御:許可リスト、ブロックリスト、またはカスタムロジック
- 柔軟なゲートプログラム:ABL参照実装を使用するか、コンプライアンスインフラと統合したカスタムゲートプログラムを構築できます
- シームレスな統合:SDKが複雑さを自動的に処理します
- コンポーザブル:既存のDeFiプロトコルと連携します
- 監査済み:メインネットにデプロイされた本番環境対応のプログラム
Token-2022のDefaultAccountState拡張機能とToken ACLのパーミッションレスオペレーションの組み合わせにより、Solana上における準拠トークン発行の新しいパラダイムが生まれます。
Is this page helpful?