SPL Token Development (Solana)

We design and develop full-cycle blockchain solutions: from smart contract architecture to launching DeFi protocols, NFT marketplaces and crypto exchanges. Security audits, tokenomics, integration with existing infrastructure.
Showing 1 of 1 servicesAll 1306 services
SPL Token Development (Solana)
Medium
~2-3 business days
FAQ
Blockchain Development Services
Blockchain Development Stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1229
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1166
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    863
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1075
  • image_logo-advance_0.png
    B2B Advance company logo design
    561
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    829

SPL Token Development (Solana)

EVM developers coming to Solana usually expect an ERC-20 analogue with similar concepts. Reality is very different. In Solana there's no concept of "token contract" — there's Token Program (system program) managing all tokens, and Mint account — account with specific token metadata. Logic for customization is implemented not through contract inheritance, but through combination of Token-2022 extensions and separate programs (like Transfer Hook).

Token Program vs. Token-2022

On Solana exist two standards:

spl-token (Token Program) — original 2020 standard. Simple, battle-tested, supported by all wallets and DEX. Features: mint, burn, transfer, freeze, multisig authority.

Token-2022 (Token Extensions Program) — new standard with extensible architecture. Recommended for new projects. Key extensions:

Extension Purpose
TransferFee Fee on each transfer (like reflection/tax token)
TransferHook Call custom program on each transfer
ConfidentialTransfer Private balances via ZK proofs (ElGamal encryption)
PermanentDelegate Address with permanent right to burn/transfer tokens
MintCloseAuthority Ability to close Mint account (return rent)
NonTransferable Soulbound tokens — can't transfer
InterestBearingMint On-chain interest accrual
MetadataPointer + TokenMetadata Metadata right in Mint account

Creating Mint account

Using @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,            // maximum fee in lamports
) {
    const mintKeypair = Keypair.generate();
    
    // calculate account size with needed extensions
    const extensions = [ExtensionType.TransferFeeConfig];
    const mintLen = getMintLen(extensions);
    
    const lamports = await connection.getMinimumBalanceForRentExemption(mintLen);
    
    const transaction = new Transaction().add(
        // create account of needed size
        SystemProgram.createAccount({
            fromPubkey: payer.publicKey,
            newAccountPubkey: mintKeypair.publicKey,
            space: mintLen,
            lamports,
            programId: TOKEN_2022_PROGRAM_ID,
        }),
        // initialize TransferFee extension BEFORE mint init
        createInitializeTransferFeeConfigInstruction(
            mintKeypair.publicKey,
            payer.publicKey,       // transferFeeConfigAuthority
            payer.publicKey,       // withdrawWithheldAuthority
            feeBasisPoints,
            maxFee,
            TOKEN_2022_PROGRAM_ID,
        ),
        // initialize mint
        createInitializeMintInstruction(
            mintKeypair.publicKey,
            decimals,
            mintAuthority,
            null, // freeze authority — null if not needed
            TOKEN_2022_PROGRAM_ID,
        ),
    );
    
    await sendAndConfirmTransaction(connection, transaction, [payer, mintKeypair]);
    return mintKeypair.publicKey;
}

Critical moment: extensions are initialized before InitializeMint. Counterintuitive for EVM developers, but that's Token-2022 architecture — configure extensions first, then finalize mint.

Associated Token Accounts

In Solana each user must have separate Token Account for each token. Associated Token Account (ATA) — deterministic address derived from user wallet and mint address. ATA is created once, address always predictable:

import { getAssociatedTokenAddress, createAssociatedTokenAccountInstruction } from "@solana/spl-token";

const ata = await getAssociatedTokenAddress(
    mintAddress,
    walletAddress,
    false,                  // allowOwnerOffCurve — usually false
    TOKEN_2022_PROGRAM_ID,
);

// create ATA if it doesn't exist (idempotent)
const createATAIx = createAssociatedTokenAccountInstruction(
    payer.publicKey,   // who pays rent
    ata,
    walletAddress,     // owner
    mintAddress,
    TOKEN_2022_PROGRAM_ID,
);

Rent for Token Account (~0.002 SOL) is paid by creator — important UX moment. Many projects assume creating ATA for users on first operation (airdrop, purchase), including rent cost in operational expenses.

Transfer Hook: custom logic on transfers

Transfer Hook — most powerful extension, allows executing arbitrary logic on each transfer. This is Solana analogue of ERC-20 hooks or transfer callbacks.

Custom program (Transfer Hook program) is called automatically by Token-2022 on each transfer. In program you can implement: whitelist/blacklist check, royalty for tokens, transfer blocking in locked period, protocol state integration.

// Transfer Hook program (Anchor framework)
use anchor_lang::prelude::*;
use spl_transfer_hook_interface::instruction::ExecuteInstruction;

#[program]
pub mod transfer_hook {
    use super::*;
    
    // this function is called by Token-2022 on each transfer
    pub fn transfer_hook(ctx: Context<TransferHook>, amount: u64) -> Result<()> {
        let sender = &ctx.accounts.source_token;
        let receiver = &ctx.accounts.destination_token;
        
        // check whitelist
        let config = &ctx.accounts.hook_config;
        require!(
            config.whitelist.contains(&receiver.owner),
            TransferError::ReceiverNotWhitelisted
        );
        
        // log transfer for off-chain analysis
        emit!(TransferEvent {
            from: sender.owner,
            to: receiver.owner,
            amount,
            timestamp: Clock::get()?.unix_timestamp,
        });
        
        Ok(())
    }
}

Transfer Hook requires all additional accounts needed by hook to be passed in transaction beforehand. This complicates client code — you need to know which accounts the hook needs before sending transaction. SDK provides addExtraAccountMetasForExecute for automatic resolution.

Token metadata

Metadata (name, symbol, image, description) is stored two ways:

Metaplex Metadata Program — legacy approach, standard for NFTs and most fungible tokens today. Separate account with metadata, linked to mint. Wide wallet and marketplace support.

Token Metadata Extension (Token-2022) — new approach, metadata right in Mint account. Simpler architecturally, doesn't require Metaplex. Wallet support growing, but still less universal than Metaplex.

For production fungible token (DeFi, governance) in 2024–2025 Metaplex is recommended — maximum ecosystem compatibility (wallets, DEX, price aggregators).

Working with Anchor framework

Most Solana programs are written in Rust with Anchor framework. Anchor generates IDL (Interface Definition Language) — EVM ABI analogue — simplifying client integration:

anchor build   # compilation + IDL generation
anchor test    # tests on localnet
anchor deploy  # deploy on devnet/mainnet

For token without custom program Anchor isn't needed — @solana/spl-token SDK is enough. Anchor is necessary if building dApp on top of token with custom business logic (staking, vesting, governance).