Розробка SPL-токена (Solana)
EVM-розробники, які приходять на Solana, зазвичай очікують аналога ERC-20 з подібними концепціями. Реальність сильно відрізняється. На Solana немає концепції "контракту токена" як такої — є Token Program (системна програма), що управляє всіма токенами, та Mint account — аккаунт з метаданими конкретного токена. Логіка налаштування та кастомізації реалізується не через спадкування контракту, а через комбінацію розширень Token-2022 та окремих програм (наприклад, Transfer Hook).
Token Program vs. Token-2022
На Solana існує два стандарти:
spl-token (Token Program) — оригінальний стандарт 2020 року. Простий, перевірений часом, підтримується всіма кошельками та DEX. Можливості: mint, burn, transfer, freeze, multisig authority.
Token-2022 (Token Extensions Program) — новий стандарт з розширюваною архітектурою. Рекомендований для нових проектів. Ключові розширення:
| Розширення | Призначення |
|---|---|
TransferFee |
Комісія на кожен transfer (аналог reflection/tax token) |
TransferHook |
Виклик кастомної програми при кожному transfer |
ConfidentialTransfer |
Приватні баланси через ZK proofs (ElGamal шифрування) |
PermanentDelegate |
Адреса з постійним правом спалювати/переводити токени |
MintCloseAuthority |
Можливість закрити Mint account (повернути rent) |
NonTransferable |
Soulbound токени — не можна передати |
InterestBearingMint |
Начислення процентів on-chain |
MetadataPointer + TokenMetadata |
Метаданні прямо в Mint account |
Створення Mint account
Використовуючи @solana/spl-token (TypeScript SDK):
import {
createMint,
createAssociatedTokenAccount,
mintTo,
TOKEN_2022_PROGRAM_ID,
ExtensionType,
getMintLen,
createInitializeMintInstruction,
createInitializeTransferFeeConfigInstruction,
} from "@solana/spl-token";
import { Connection, Keypair, SystemProgram, Transaction } from "@solana/web3.js";
async function createTokenWithTransferFee(
connection: Connection,
payer: Keypair,
mintAuthority: PublicKey,
decimals: number,
feeBasisPoints: number, // 100 = 1%
maxFee: bigint, // максимальна комісія в lamports
) {
const mintKeypair = Keypair.generate();
// вичисляємо розмір аккаунту з потрібними розширеннями
const extensions = [ExtensionType.TransferFeeConfig];
const mintLen = getMintLen(extensions);
const lamports = await connection.getMinimumBalanceForRentExemption(mintLen);
const transaction = new Transaction().add(
// створюємо аккаунт потрібного розміру
SystemProgram.createAccount({
fromPubkey: payer.publicKey,
newAccountPubkey: mintKeypair.publicKey,
space: mintLen,
lamports,
programId: TOKEN_2022_PROGRAM_ID,
}),
// ініціалізуємо розширення TransferFee ДО ініціалізації mint
createInitializeTransferFeeConfigInstruction(
mintKeypair.publicKey,
payer.publicKey, // transferFeeConfigAuthority
payer.publicKey, // withdrawWithheldAuthority
feeBasisPoints,
maxFee,
TOKEN_2022_PROGRAM_ID,
),
// ініціалізуємо mint
createInitializeMintInstruction(
mintKeypair.publicKey,
decimals,
mintAuthority,
null, // freeze authority — null якщо не потрібна
TOKEN_2022_PROGRAM_ID,
),
);
await sendAndConfirmTransaction(connection, transaction, [payer, mintKeypair]);
return mintKeypair.publicKey;
}
Критично важливий момент: розширення ініціалізуються до InitializeMint. Це контринтуїтивно для EVM-розробників, але така архітектура Token-2022 — спочатку налаштовуємо розширення, потім фіналізуємо mint.
Associated Token Accounts
На Solana кожний користувач повинен мати окремий Token Account для кожного токена. Associated Token Account (ATA) — детерміністична адреса, похідна від гаманця користувача та адреси mint. ATA створюється один раз, адреса завжди передбачувана:
import { getAssociatedTokenAddress, createAssociatedTokenAccountInstruction } from "@solana/spl-token";
const ata = await getAssociatedTokenAddress(
mintAddress,
walletAddress,
false, // allowOwnerOffCurve — зазвичай false
TOKEN_2022_PROGRAM_ID,
);
// створюємо ATA якщо не існує (idempotent)
const createATAIx = createAssociatedTokenAccountInstruction(
payer.publicKey, // хто платить rent
ata,
walletAddress, // власник
mintAddress,
TOKEN_2022_PROGRAM_ID,
);
Rent за Token Account (~0.002 SOL) платить сторона, що створює — це важливий UX момент. Багато проектів беруть на себе створення ATA для користувачів при першій операції (airdrop, покупка), включаючи вартість rent у свої операційні витрати.
Transfer Hook: кастомна логіка при переводах
Transfer Hook — найпотужніше розширення, дозволяє виконувати довільну логіку при кожному transfer. Це Solana-аналог ERC-20 hooks або transfer callbacks.
Кастомна програма (Transfer Hook program) викликається автоматично Token-2022 при кожному transfer. У програмі можна реалізувати: перевірку whitelist/blacklist, royalty для токенів, блокування переводів у заблокованому періоді, інтеграцію зі станом протоколу.
// Transfer Hook program (Anchor framework)
use anchor_lang::prelude::*;
use spl_transfer_hook_interface::instruction::ExecuteInstruction;
#[program]
pub mod transfer_hook {
use super::*;
// ця функція викликається Token-2022 при кожному transfer
pub fn transfer_hook(ctx: Context<TransferHook>, amount: u64) -> Result<()> {
let sender = &ctx.accounts.source_token;
let receiver = &ctx.accounts.destination_token;
// перевіряємо whitelist
let config = &ctx.accounts.hook_config;
require!(
config.whitelist.contains(&receiver.owner),
TransferError::ReceiverNotWhitelisted
);
// логуємо transfer для off-chain аналізу
emit!(TransferEvent {
from: sender.owner,
to: receiver.owner,
amount,
timestamp: Clock::get()?.unix_timestamp,
});
Ok(())
}
}
Transfer Hook потребує, щоб усі додаткові аккаунти, потрібні для hook, були передані в транзакцію заздалегідь. Це ускладнює клієнтський код — потрібно знати які аккаунти потрібні hook перед відправкою транзакції. SDK надає addExtraAccountMetasForExecute для автоматичного розв'язання цих аккаунтів.
Метаданні токена
Метаданні (назва, символ, зображення, опис) зберігаються двома способами:
Metaplex Metadata Program — legacy підхід, стандарт для NFT та більшості fungible токенів сьогодні. Окремий аккаунт з метаданими, пов'язаний з mint. Широка підтримка кошельками та маркетплейсами.
Token Metadata Extension (Token-2022) — новий підхід, метаданні прямо в Mint account. Архітектурно простіше, не потребує Metaplex. Підтримка кошельками зростає, але поки менш універсальна ніж Metaplex.
Для production fungible токена (DeFi, governance) у 2024–2025 році Metaplex рекомендується — максимальна сумісність із екосистемою (кошельки, DEX, агрегатори цін).
Робота з Anchor framework
Більшість Solana-програм пишуться на Rust з Anchor framework. Anchor генерує IDL (Interface Definition Language) — аналог ABI в EVM — що спрощує клієнтську інтеграцію:
anchor build # компіляція + генерація IDL
anchor test # тести на localnet
anchor deploy # розгортання на devnet/mainnet
Для токена без кастомної програми Anchor не потрібен — достатньо @solana/spl-token SDK. Anchor необхідний, якщо будується dApp поверх токена з кастомною бізнес-логікою (staking, vesting, governance).







