8.2 KiB
8.2 KiB
SPL Token Program - Overview and Fundamentals
Overview of SPL Token Program fundamentals including program types, account structures (Mint and Token accounts), and Associated Token Accounts (ATAs) with derivation and creation patterns.
For additional token topics, see:
- tokens-operations.md - Create, mint, transfer, burn, close operations
- tokens-validation.md - Account validation patterns
- tokens-2022.md - Token Extensions Program features
- tokens-patterns.md - Common patterns and security
Table of Contents
Token Program Overview
SPL Token vs Token-2022
SPL Token (Original):
- Program ID:
TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA - Production-ready, stable, widely adopted
- No new features planned
- Use for standard fungible tokens
Token-2022 (Token Extensions Program):
- Program ID:
TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb - Backwards-compatible with SPL Token
- Supports extensions (transfer fees, confidential transfers, metadata pointers, etc.)
- Use for advanced token features
Key Concepts
┌─────────────────────────────────────────┐
│ Mint Account │
├─────────────────────────────────────────┤
│ - Defines a token type │
│ - Controls supply │
│ - Has mint authority (can create tokens)│
│ - Has freeze authority (can freeze accts)│
└─────────────────────────────────────────┘
│
│ Creates
▼
┌─────────────────────────────────────────┐
│ Token Account │
├─────────────────────────────────────────┤
│ - Holds token balance │
│ - Owned by a wallet or program │
│ - Associated with specific Mint │
│ - Can be frozen/delegated │
└─────────────────────────────────────────┘
Required Dependencies
For Anchor:
[dependencies]
anchor-lang = "0.32.1"
anchor-spl = "0.32.1"
[features]
idl-build = [
"anchor-lang/idl-build",
"anchor-spl/idl-build",
]
For Native Rust:
[dependencies]
spl-token = "6.0"
spl-associated-token-account = "6.0"
solana-program = "2.1"
Token Account Structures
Mint Account
Size: 82 bytes
pub struct Mint {
/// Optional authority to mint new tokens (Pubkey or None)
pub mint_authority: COption<Pubkey>, // 36 bytes
/// Total supply of tokens
pub supply: u64, // 8 bytes
/// Number of decimals (0 for NFTs, typically 6-9 for fungible)
pub decimals: u8, // 1 byte
/// Is initialized?
pub is_initialized: bool, // 1 byte
/// Optional authority to freeze token accounts
pub freeze_authority: COption<Pubkey>, // 36 bytes
}
COption Format:
pub enum COption<T> {
None, // Represented as [0, 0, 0, 0, ...]
Some(T), // Represented as [1, followed by T bytes]
}
Token Account
Size: 165 bytes
pub struct Account {
/// The mint associated with this account
pub mint: Pubkey, // 32 bytes
/// The owner of this account
pub owner: Pubkey, // 32 bytes
/// The amount of tokens this account holds
pub amount: u64, // 8 bytes
/// If `delegate` is `Some` then `delegated_amount` represents
/// the amount authorized by the delegate
pub delegate: COption<Pubkey>, // 36 bytes
/// The account's state
pub state: AccountState, // 1 byte
/// If is_native.is_some, this is a native token, and the value logs the
/// rent-exempt reserve
pub is_native: COption<u64>, // 12 bytes
/// The amount delegated
pub delegated_amount: u64, // 8 bytes
/// Optional authority to close the account
pub close_authority: COption<Pubkey>, // 36 bytes
}
pub enum AccountState {
Uninitialized,
Initialized,
Frozen,
}
Associated Token Accounts
What are ATAs?
Associated Token Accounts (ATAs) are PDAs that map a wallet address to a token account for a specific mint.
Derivation:
ATA = PDA(
seeds: [wallet_address, TOKEN_PROGRAM_ID, mint_address],
program: ASSOCIATED_TOKEN_PROGRAM_ID
)
Benefits:
- Deterministic: Same wallet + mint always produces same ATA
- Discoverable: Easy to find a user's token accounts
- Standard: All wallets use this convention
Constants:
// Token Program ID
pub const TOKEN_PROGRAM_ID: Pubkey = pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
// Associated Token Program ID
pub const ASSOCIATED_TOKEN_PROGRAM_ID: Pubkey = pubkey!("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL");
Finding ATA Address
Using Anchor
use anchor_spl::associated_token::get_associated_token_address;
// In client code or tests
let ata_address = get_associated_token_address(
&wallet_address,
&mint_address,
);
Using Native Rust
use spl_associated_token_account::get_associated_token_address;
// Derive ATA address
let ata_address = get_associated_token_address(
&wallet_address,
&mint_address,
);
Creating Associated Token Accounts
Using Anchor
use anchor_spl::associated_token::AssociatedToken;
use anchor_spl::token_interface::{Mint, TokenAccount, TokenInterface};
#[derive(Accounts)]
pub struct CreateTokenAccount<'info> {
#[account(
init,
payer = payer,
associated_token::mint = mint,
associated_token::authority = owner,
associated_token::token_program = token_program,
)]
pub token_account: InterfaceAccount<'info, TokenAccount>,
pub mint: InterfaceAccount<'info, Mint>,
/// CHECK: Can be any account
pub owner: UncheckedAccount<'info>,
#[account(mut)]
pub payer: Signer<'info>,
pub token_program: Interface<'info, TokenInterface>,
pub associated_token_program: Program<'info, AssociatedToken>,
pub system_program: Program<'info, System>,
}
pub fn create_ata(ctx: Context<CreateTokenAccount>) -> Result<()> {
// ATA is automatically created by Anchor constraints
Ok(())
}
Using Native Rust
use spl_associated_token_account::instruction::create_associated_token_account;
use solana_program::{
account_info::AccountInfo,
entrypoint::ProgramResult,
program::invoke,
};
pub fn create_ata(
payer: &AccountInfo,
wallet: &AccountInfo,
mint: &AccountInfo,
ata: &AccountInfo,
system_program: &AccountInfo,
token_program: &AccountInfo,
associated_token_program: &AccountInfo,
) -> ProgramResult {
invoke(
&create_associated_token_account(
payer.key,
wallet.key,
mint.key,
token_program.key,
),
&[
payer.clone(),
ata.clone(),
wallet.clone(),
mint.clone(),
system_program.clone(),
token_program.clone(),
associated_token_program.clone(),
],
)?
;
Ok(())
}
Next Steps
- Token Operations: See tokens-operations.md for creating mints, minting, transferring, burning, and closing accounts
- Validation: See tokens-validation.md for account validation patterns
- Token-2022: See tokens-2022.md for Token Extensions Program features
- Patterns & Security: See tokens-patterns.md for common patterns and security best practices