---
title: Quick Start
description:
  Learn how to use the litesvm-token crate for testing with SPL tokens
---

<div className="flex items-center gap-3 mb-6">
  <a
    href="https://crates.io/crates/litesvm-token"
    target="_blank"
    rel="noopener noreferrer"
    className="inline-flex items-center gap-2 px-3 py-1.5 bg-fd-muted/50 hover:bg-fd-muted rounded-lg text-sm font-medium transition-colors border border-fd-border/50"
  >
    <svg
      xmlns="http://www.w3.org/2000/svg"
      viewBox="0 0 512 512"
      className="w-4 h-4"
      fill="currentColor"
    >
      <path d="M239.1 6.3l-208 78c-18.7 7-31.1 25-31.1 45v225.1c0 18.2 10.3 34.8 26.5 42.9l208 104c13.5 6.8 29.4 6.8 42.9 0l208-104c16.3-8.1 26.5-24.8 26.5-42.9V129.3c0-20-12.4-37.9-31.1-44.9l-208-78C262 2.2 250 2.2 239.1 6.3zM256 68.4l192 72v1.1l-192 78-192-78v-1.1l192-72zm32 356V275.5l160-65v133.9l-160 80z" />
    </svg>
    View <code>litesvm-token</code> on crates.io
  </a>
</div>

## Installation

Make sure you have all the needed dependencies:

```bash
cargo add --dev litesvm litesvm-token solana-sdk spl-token spl-associated-token-account
```

## SPL Token Basics

In Solana, creating a token account is a two step process.

<Steps>
<Step>
**Create a `Mint Account`**
- Has no token balance 
- Holds all the global information of the token, like the total supply, decimals, authority, etc.
- There is one Mint Account per token
- The Owner is the Token Program (TokenKeg or Token 2022)
</Step>

<Step>
**Create a `Token Account`**
- Stores the balance for a specific SPL token 
- Holds the Mint Account to define which SPL token is in this account 
- There can be several token accounts for one Mint Account 
- The owner is who has control over the tokens inside this account 
</Step>
</Steps>

## Types of Token Accounts

### Regular Token Account

A token account stores your balance for a specific SPL token:

```rust
// Can create token accounts at ANY address
let token_account = Keypair::new();  // Random address
let create_ix = system_instruction::create_account(
    &payer.pubkey(),
    &token_account.pubkey(),  // Any address you want
    rent,
    165,  // Token account size
    &spl_token::id(),
);
let init_ix = spl_token::instruction::initialize_account(
    &spl_token::id(),
    &token_account.pubkey(),
    &mint,
    &owner.pubkey(),
)?;
```

<div className="grid grid-cols-1 md:grid-cols-2 gap-2 my-3">
  <div className="bg-gray-50 dark:bg-gray-950/20 border border-gray-200 dark:border-gray-800 rounded-lg px-2 pt-0.5 pb-2">
    <h4 className="text-xs font-semibold text-gray-800 dark:text-gray-300 mb-1.5 flex items-center gap-1.5">
      <span className="text-sm">✓</span> Pros
    </h4>
    <ul className="space-y-1 text-xs text-gray-900 dark:text-gray-200">
      <li className="flex items-start gap-1.5">
        <span className="text-gray-600 dark:text-gray-400 mt-0.5">•</span>
        <span>Can create multiple accounts for same mint/owner</span>
      </li>
      <li className="flex items-start gap-1.5">
        <span className="text-gray-600 dark:text-gray-400 mt-0.5">•</span>
        <span>Flexible - can use any address</span>
      </li>
    </ul>
  </div>

  <div className="bg-gray-50 dark:bg-gray-950/20 border border-gray-200 dark:border-gray-800 rounded-lg px-2 pt-0.5 pb-2">
    <h4 className="text-xs font-semibold text-gray-800 dark:text-gray-300 mb-1.5 flex items-center gap-1.5">
      <span className="text-sm">✗</span> Cons
    </h4>
    <ul className="space-y-1 text-xs text-gray-900 dark:text-gray-200">
      <li className="flex items-start gap-1.5">
        <span className="text-gray-600 dark:text-gray-400 mt-0.5">•</span>
        <span>Not deterministic - need to track addresses manually</span>
      </li>
      <li className="flex items-start gap-1.5">
        <span className="text-gray-600 dark:text-gray-400 mt-0.5">•</span>
        <span>Recipient must tell you which account to send to</span>
      </li>
      <li className="flex items-start gap-1.5">
        <span className="text-gray-600 dark:text-gray-400 mt-0.5">•</span>
        <span>Creates confusion with multiple accounts</span>
      </li>
    </ul>
  </div>
</div>

<Callout type="info">
  **When to use:** Temporary/escrow accounts, program-owned accounts with custom
  logic, when you need multiple accounts for the same token, advanced DeFi
  strategies.
</Callout>

### Associated Token Account (ATA)

An ATA is a token account at a deterministic PDA address:

```rust
// ATA address is ALWAYS the same for owner + mint
let ata = get_associated_token_address(&owner.pubkey(), &mint);
// Address derived from: [owner_pubkey, token_program_id, mint]
```

How the ATA address is derived:

```rust
// ATA is a PDA owned by the Associated Token Program
let (ata, bump) = Pubkey::find_program_address(
    &[
        owner.as_ref(),
        spl_token::id().as_ref(),
        mint.as_ref(),
    ],
    &spl_associated_token_account::id(),  // ATA program
);
```

<div className="grid grid-cols-1 md:grid-cols-2 gap-2 my-3">
  <div className="bg-gray-50 dark:bg-gray-950/20 border border-gray-200 dark:border-gray-800 rounded-lg px-2 pt-0.5 pb-2">
    <h4 className="text-xs font-semibold text-gray-800 dark:text-gray-300 mb-1.5 flex items-center gap-1.5">
      <span className="text-sm">✓</span> Pros
    </h4>
    <ul className="space-y-1 text-xs text-gray-900 dark:text-gray-200">
      <li className="flex items-start gap-1.5">
        <span className="text-gray-600 dark:text-gray-400 mt-0.5">•</span>
        <span>One canonical account per owner/mint pair</span>
      </li>
      <li className="flex items-start gap-1.5">
        <span className="text-gray-600 dark:text-gray-400 mt-0.5">•</span>
        <span>Deterministic - anyone can calculate the address</span>
      </li>
      <li className="flex items-start gap-1.5">
        <span className="text-gray-600 dark:text-gray-400 mt-0.5">•</span>
        <span>Simplifies payments - just need wallet address + mint</span>
      </li>
      <li className="flex items-start gap-1.5">
        <span className="text-gray-600 dark:text-gray-400 mt-0.5">•</span>
        <span>Standard convention across all Solana apps</span>
      </li>
    </ul>
  </div>

  <div className="bg-gray-50 dark:bg-gray-950/20 border border-gray-200 dark:border-gray-800 rounded-lg px-2 pt-0.5 pb-2">
    <h4 className="text-xs font-semibold text-gray-800 dark:text-gray-300 mb-1.5 flex items-center gap-1.5">
      <span className="text-sm">✗</span> Cons
    </h4>
    <ul className="space-y-1 text-xs text-gray-900 dark:text-gray-200">
      <li className="flex items-start gap-1.5">
        <span className="text-gray-600 dark:text-gray-400 mt-0.5">•</span>
        <span>Can only have ONE ATA per owner/mint (by design)</span>
      </li>
    </ul>
  </div>
</div>

<Callout type="info">
  **Recommended for most cases:** Wallet applications, DeFi protocols, NFT
  holdings, payment systems, and any user-facing token transfers.
</Callout>

## Quick Example

Here's a complete example of creating a token mint and minting tokens:

```rust
use litesvm::LiteSVM;
use litesvm_token::{
    get_spl_account,
    spl_token::{native_mint::DECIMALS, state::Account as TokenAccount},
    CreateAccount, CreateMint, MintTo, Transfer,
};
use solana_sdk::{
    native_token::LAMPORTS_PER_SOL,
    signature::{Keypair, Signer},
};

#[test]
fn test_create_and_mint_tokens() {
    let mut svm = LiteSVM::new();

    // Create payer account and fund it
    let payer = Keypair::new();
    svm.airdrop(&payer.pubkey(), 10 * LAMPORTS_PER_SOL).unwrap();

    // Create a new SPL token mint with the payer as the mint authority
    let mint = CreateMint::new(&mut svm, &payer)
        .authority(&payer.pubkey())
        .decimals(DECIMALS)
        .send()
        .unwrap();

    // Create a token account for the payer
    let token_account = CreateAccount::new(&mut svm, &payer, &mint)
        .owner(&payer.pubkey())
        .send()
        .unwrap();

    // Mint tokens into the payer's token account
    MintTo::new(&mut svm, &payer, &mint, &token_account, 1000)
        .owner(&payer)
        .send()
        .unwrap();

    // Verify balance
    let token_account: TokenAccount = get_spl_account(&svm, &token_account).unwrap();
    let account_balance = token_account.amount;
    assert_eq!(account_balance, 1000)
}
```

## Key Concepts

### Token Decimals

Most tokens use decimals to represent fractional amounts:

```rust
// SOL has 9 decimals
let one_sol = 10_u64.pow(9);  // 1_000_000_000 lamports

// USDC has 6 decimals
let one_usdc = 10_u64.pow(6); // 1_000_000 micro-USDC

// Always account for decimals in calculations
let amount_tokens = 100;
let amount_raw = amount_tokens * 10_u64.pow(decimals as u32);
```

### Account Relationships

Understanding the relationships between accounts is crucial:

- **Mint Account**: Defines the token (supply, decimals, authorities)
- **Token Account**: Holds tokens for a specific owner
- **Associated Token Account**: Deterministic token account for an owner+mint
  pair
- **Mint Authority**: Can create new tokens
- **Freeze Authority**: Can freeze token accounts (optional)

## Troubleshooting

### Common Errors

| Error                       | Cause                                               | Solution                                |
| --------------------------- | --------------------------------------------------- | --------------------------------------- |
| `AccountNotFound`           | Trying to use an account that doesn't exist         | Ensure account is created before use    |
| `AccountAlreadyInitialized` | Trying to initialize an already initialized account | Check if account exists before creating |
| `InsufficientFunds`         | Not enough lamports for rent or tokens for transfer | Ensure sufficient funding/minting       |
| `OwnerMismatch`             | Account owned by wrong program                      | Verify correct program ID when creating |
