DEV Community

Cover image for Understanding Solana: From Account Model to Token Creation
yash sharma
yash sharma

Posted on

Understanding Solana: From Account Model to Token Creation

In these article have covered everything you need to know about solana, not only theory but also by proper example, code everything does not matter if you are new to solana or expert surely you will go by learning something

Why Solana Feels Different from Ethereum

Before touching a single concept, you need to understand the problem Solana was designed to solve. Everything else is a consequence of this.

The Fundamental Bottleneck of Blockchains

Ethereum processes roughly 15–30 transactions per second. The reason is not hardware. The reason is sequential execution — every transaction must be processed one after another because any two transactions might touch the same state.

Imagine a database with one global write lock. Every query waits for the previous one to finish. This is Ethereum's execution model. It is simple, safe, and slow.

Solana was founded in 2017 by Anatoly Yakovenko, a former Qualcomm engineer. The testnet launched in 2018, and the mainnet beta went live in March 2020.

A testnet is a testing network for developers, where assets have no real value, allowing us to experiment before deploying to the mainnet, where assets hold real value.

Yakovenko recognized that blockchain execution has the same structure as OS thread scheduling — and OS schedulers have solved parallel execution for decades using one key insight:

If two operations touch different memory regions, they can run simultaneously.

This is the entire intellectual foundation of Solana. Everything — the account model, the explicit account passing, the ownership system, the PDA architecture — exists to make this insight executable on a blockchain.

Solana is a Layer 1 blockchain, similar in category to Ethereum or Bitcoin, but specifically designed for smart contracts and decentralized applications, much like Ethereum. Bitcoin focuses primarily on storing and transferring value. Solana and Ethereum go further, enabling complex on-chain logic, DeFi protocols, NFT marketplaces, and more.

Both Solana and Ethereum use Proof of Stake (PoS) as their consensus mechanism. Validators stake their own assets as collateral to participate in block production. Honest validators earn rewards; malicious behavior is punished through slashing. This contrasts with Proof of Work (PoW) networks like Bitcoin, where miners compete by solving computationally expensive cryptographic puzzles to earn the right to produce a block.

Despite sharing the same consensus category, Solana and Ethereum differ significantly in almost every other dimension.


Language and Tooling

Ethereum smart contracts are primarily written in Solidity, a JavaScript-like language purpose-built for the EVM, or Vyper, a Python-like alternative focused on simplicity and auditability.

Solana programs are written in Rust — a systems programming language known for its memory safety, performance, and explicitness. Rust has a steeper learning curve than Solidity, but it gives developers precise control over memory and execution. Solana also has Anchor, a framework that significantly reduces boilerplate, enforces common security patterns, and makes program development more approachable — somewhat like how Hardhat or Foundry simplifies Ethereum development, but more deeply integrated.


Throughput and Execution Model

This is where the architectural difference is most visible.

Ethereum processes roughly 15–30 transactions per second at the base layer — around 900 to 1,800 transactions per minute. Solana, by contrast, is capable of processing over 65,000 transactions per second, exceeding 3,900,000 per minute under optimal conditions.

The reason comes down to execution architecture. Ethereum processes transactions sequentially, one after another, in a strict order. This is safe and simple, but it means every transaction waits for the one before it to complete, regardless of whether they share any state.

Solana executes transactions in parallel. Its runtime, called Sealevel, analyzes each transaction upfront to determine which accounts it will read and write. Transactions that touch completely different accounts have no dependencies on each other and can execute simultaneously across multiple CPU cores. Only transactions that share writable accounts need to be serialized.

This is the fundamental reason Solana is fast — it is not just better hardware, it is a fundamentally different execution model.


Where State Lives

This is the conceptual shift that surprises most developers coming from Ethereum.

In Ethereum, a smart contract is self-contained. The code and the state it manages live together at the same address. When you deploy a contract, it owns its own internal storage. Everything is bundled in one place.

Solana separates these two concerns completely. A program contains only logic — it is stateless and read-only once deployed. All persistent state lives in separate accounts, which are independent storage containers on the blockchain. Every time you call a Solana program, you must explicitly pass in every account the program needs to read or write. The program itself holds nothing between calls.

This separation is what makes parallel execution possible — Solana can inspect an instruction's account list before running it and schedule accordingly. It also means programs are reusable across many different state accounts, rather than each deployment being tied to its own isolated storage.


Rent and Storage Costs

Deploying a smart contract on Ethereum has no ongoing storage cost. You pay gas once at deployment, and the contract's storage persists indefinitely.

Solana uses a rent model. Every account on Solana — including programs and data accounts — must maintain a minimum SOL balance proportional to the amount of data it stores. This deposit is called the rent-exempt balance. It is not a fee that gets consumed; it is a refundable deposit that compensates the network for the validator resources required to store your data permanently.

When you close an account you no longer need, the rent-exempt deposit is returned to your wallet. The larger the account's data, the higher the deposit required. This creates a real economic incentive to keep on-chain data minimal and to clean up accounts when they are no longer needed.


Upgradeability

Ethereum smart contracts are immutable by default. Once deployed, the bytecode cannot be changed. Upgradeability is possible, but it requires deliberate architectural patterns — most commonly the proxy pattern, where a proxy contract delegates calls to a separate logic contract that can be swapped out. This adds complexity and introduces its own security risks.

Solana programs are upgradeable by default. The deployer retains an upgrade authority — a keypair that can push new versions of the program to the same program address. This makes iteration and bug fixes straightforward. However, upgradeability also means users must trust that the upgrade authority will not deploy malicious code. For protocols that want to signal trustlessness, the upgrade authority can be explicitly revoked, making the program permanently immutable — the best of both worlds when used deliberately.


Some Jargon of Solana

1. Mnemonic Key

A mnemonic phrase (or seed phrase) is a human-readable string of words used to generate a cryptographic seed. It is a 12-word, 18-word, or 24-word recovery phrase you write down when creating your wallet. Humans cannot safely remember or write long binary cryptographic values, so BIP-39 (Bitcoin Improvement Proposal 39) introduced mnemonic phrases.

GitHub link: bip-0039/english.txt


import { generateMnemonic } from 'bip-39';

const mnemonic = generateMnemonic();
console.log('Generated Mnemonic:', mnemonic);



Enter fullscreen mode Exit fullscreen mode

2. Seed

A seed is a 64-byte (512-bit) binary value derived from the mnemonic. The seed is the actual cryptographic binary value generated from the mnemonic. The mnemonic itself is NOT directly used for signing transactions — the seed is what cryptography actually uses internally.

import { generateMnemonic, mnemonicToSeedSync } from "bip39";

const mnemonic = generateMnemonic();
console.log("Generated Mnemonic:", mnemonic);
const seed = mnemonicToSeedSync(mnemonic);
Enter fullscreen mode Exit fullscreen mode

The mnemonic is what you back up (human-friendly), but the seed is what the wallet actually uses to generate all your keys.

3. dApps

First introduced on Ethereum, later adopted by Solana. dApps (decentralized applications) on Solana are applications built on the Solana blockchain that run on a distributed network rather than centralized servers.

A normal app:

Frontend → Backend Server → Database
Enter fullscreen mode Exit fullscreen mode

A dApp:

Frontend → Smart Contract → Blockchain State
Enter fullscreen mode Exit fullscreen mode

4. Wallet Extension

Wallet extensions are browser add-ons (like MetaMask, Phantom, Backpack) that let you interact with blockchains — storing your private keys, signing transactions, and connecting to decentralized applications (dApps).

Why are they extensions and not websites?

The core reason is security and trust. A browser extension runs locally on your device and can securely store your private keys in a way that a website fundamentally cannot.

Here's the problem with a website approach: if you entered your private key into a website, you'd be trusting that site's servers with complete control over your funds. The site could be compromised, the operators could be malicious, or the connection could be intercepted. Your keys would leave your device.

An extension solves this by keeping your keys local. When you visit a dApp and it needs you to sign a transaction, the dApp doesn't get your private key — instead, it sends a signing request to the extension. The extension shows you what you're approving, you confirm it, and the extension signs the transaction locally before sending only the signed result back. Your key never leaves your machine.

Extensions also have persistent access to inject code into web pages, which lets them provide a standardized interface (like window.solana) that any dApp can use to request connections and transactions.

5. RPC

In Solana, RPCs / RPC servers are basically the gateways your app uses to talk to the Solana blockchain. Think of them as Solana's "API servers."

What does RPC mean?

RPC = Remote Procedure Call (related to gRPC, tRPC, JSON-RPC).

It's a way for your app to say:

"Hey Solana node, can you fetch some data or submit this transaction for me?"

Instead of running a full Solana validator yourself, you send requests to an RPC server that already has the blockchain data.

Think of RPC as a waiter — you don't directly go to the chef in a restaurant to order food, you order via the waiter. The RPC is the middleman here.

6. Lamport

If you have 2 SOL in Phantom, that does not mean Phantom stores it as 2 SOL — it stores it in lamports. 1 lamport is the smallest unit of SOL you can have or send on Solana.

1 SOL = 10⁹ lamports
Enter fullscreen mode Exit fullscreen mode

When you send someone 0.1 SOL, you are actually sending them 10⁸ lamports. What's stored on the blockchain are always lamports, not the SOL value.

7. Transactions and Instructions

Instructions are the smallest unit of execution on Solana. Each instruction is essentially a command directed at a specific on-chain program (smart contract). An instruction contains three pieces of information:

  • The program ID it's targeting (which program should process this)
  • A list of accounts the instruction will read from or write to
  • An opaque byte array of data that serves as input to the program

For example, a single instruction might say "transfer 5 SOL from account A to account B" directed at the System Program.

Transactions refer to a bundle of instructions. Solana can run multiple transactions at once.

8. Gas Fees

For every transaction you do on the blockchain, you have to pay a transaction fee. The transaction fee on Solana is constant — 5000 lamports per signature in the transaction.

9. Stablecoins

If you have spent any time in crypto, you have seen names like USDC, USDT, or DAI. But what exactly are they, and why do they matter?

A stablecoin solves the volatility problem. It is a cryptocurrency designed to maintain a stable value, almost always pegged to a real-world currency — most commonly the US dollar. One USDC is always worth approximately one US dollar. One USDT is always worth approximately one US dollar. The price does not swing. The stability is the point.

Think of it this way: imagine you are sending money to a friend in another country. You could send them Bitcoin, but by the time they receive it and try to spend it, the value may have changed significantly. If you send them USDC instead, they receive exactly what you intended — the dollar value is preserved.

This is why stablecoins have become the backbone of decentralized finance, cross-border payments, and on-chain commerce.

Stablecoins can be either centralized or decentralized, depending on how they are issued, backed, and governed. The most popular stablecoins (like USDT and USDC) are centralized, whereas alternatives like DAI use a decentralized, algorithmic approach.


The System Program

Before any account exists on Solana — before a token account, before a PDA, before a program itself — something has to create it. That something is the System Program.

The System Program is the most fundamental program on Solana. It ships with the validator software. It has a fixed, well-known address — all ones, 11111111111111111111111111111111. You cannot deploy a replacement. You cannot modify it. It is as close to a law of physics as Solana has.

Every account on the network was created by the System Program at some point in its history. That is not a convention or a best practice — it is the only way accounts can come into existence. The runtime does not allow any other program to create brand new accounts from nothing.

What the System Program Actually Does

The System Program handles four things that everything else depends on:

  1. Creating accounts. When you need a new account — any account — you ask the System Program to allocate it. You specify the address, the size in bytes, how much SOL to deposit for rent exemption, and which program should own it. The System Program writes the account into the ledger. From that moment it exists.

  2. Transferring SOL. Moving SOL between wallet accounts is the System Program's job. When you send SOL to a friend, your wallet builds a Transfer instruction directed at the System Program, signed by your private key. The System Program verifies your signature, debits your account, credits theirs. No other program can debit a wallet account — only the System Program can, because wallet accounts are owned by the System Program.

  3. Assigning ownership. When an account is first created, the System Program owns it by default. Before any other program can write to it, ownership must be transferred. The assign instruction hands ownership from the System Program to whatever program you specify. In practice this usually happens as part of account initialization — create the account, assign it to your program, initialize its data, all in one transaction.

  4. Allocating space. You can resize an account's data field up to a limit, though this is less common than creating with the right size upfront.


Mint Account

Every token on Solana starts with a question the network needs answered before anything else can happen: what is this token? Not who owns it, not how much of it exists, just what is it? The Mint account is the answer to that question.

There is exactly one Mint account per token. One for USDC. One for BONK. One for whatever token you decide to create tomorrow. It is the canonical definition of the token's existence on-chain, and everything else — balances, transfers, burns — traces back to it.

What a Mint Actually Stores

A Mint account is 82 bytes. That's it. For something so foundational to how tokens work, it is remarkably small. Those 82 bytes decode into five fields:

pub struct Mint {
    pub mint_authority:   COption<Pubkey>,  // who can create new tokens
    pub supply:           u64,              // total tokens in existence
    pub decimals:         u8,               // decimal places for display
    pub is_initialized:   bool,             // has this been set up?
    pub freeze_authority: COption<Pubkey>,  // who can freeze token accounts
}
Enter fullscreen mode Exit fullscreen mode

Example flow

  1. Create Mint
  2. Create Token Account
  3. Mint Tokens
  4. Tokens appear in wallet

For example:

  • Create token: YASH
  • Mint 1000 tokens
  • Wallet now has 1000 YASH

Important distinction

Term Meaning
Token The asset itself
Mint The process/account that creates tokens
Minting Generating new supply

Minting is just the process of creating new tokens on the blockchain. Mint accounts do NOT store user balances. User balances live inside separate token accounts. The mint account only defines the token configuration and controls supply management.

In Solana, most fungible tokens are created using the SPL Token Program. Instead of deploying a completely custom token contract for every token, Solana uses a shared token infrastructure where all tokens follow the same standardized program.

Using Anchor, creating a mint account becomes relatively simple:

use anchor_lang::prelude::*;
use anchor_spl::token::{Mint, Token};

#[derive(Accounts)]
pub struct CreateMint<'info> {
    #[account(mut)]
    pub payer: Signer<'info>,

    #[account(
        init,
        payer = payer,
        mint::decimals = 6,
        mint::authority = payer.key(),
        mint::freeze_authority = payer.key(),
    )]
    pub mint: Account<'info, Mint>,
    pub token_program: Program<'info, Token>,
    pub system_program: Program<'info, System>,
    pub rent: Sysvar<'info, Rent>,
}

pub fn create_mint(ctx: Context<CreateMint>) -> Result<()> {
    msg!("Mint created: {}", ctx.accounts.mint.key());
    Ok(())
}
Enter fullscreen mode Exit fullscreen mode

The init constraint tells Anchor to create a brand new account. mint::decimals, mint::authority, and mint::freeze_authority tell it exactly how to initialize the Mint data. If the account already exists, the instruction fails — Anchor's init protects against reinitialization attacks automatically.

The rent deposit for a Mint account is roughly 0.00144 SOL. Small, but real. You get it back when you close the account — though most Mints are never closed.

You can write this code in TypeScript too through the web3 library. Must try by creating your own mint!


Token Program

The System Program creates accounts. It does not care what those accounts mean. A freshly created 165-byte account is just bytes — it could hold anything. The Token Program is what gives certain accounts the specific meaning of holding a token balance.

The Token Program lives at TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA. That address looks like a typo but it isn't — it is a legacy artifact from early Solana development that never changed because changing it would break every protocol on the network. Every wallet and every program that has ever touched a token knows this address.

Like the System Program, the Token Program ships with the validator and owns no state of its own. It is purely logic. All the state it manages lives in the Mint accounts and Token accounts it owns. The program itself is just a set of rules that govern how those accounts can be read and written.

Token-2022

There is a newer version called Token-2022, deployed at a different address: TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb. It supports extensions the original Token Program never had — transfer fees, confidential transfers, interest-bearing tokens, permanent delegates, and more.

Most established tokens use the original. Newer projects increasingly reach for Token-2022. The core model is identical — extensions just layer optional behavior on top. If you are writing a program that accepts arbitrary tokens, you will eventually need to handle both. If you are building something new and control the mint yourself, Token-2022 is worth serious consideration.


The Token Account

With the System Program and Token Program in mind, the Token account itself is simple to understand. It is a 165-byte account, created by the System Program, owned by the Token Program, that holds your balance of one specific token.

One token account per token type. Your USDC balance lives in a different account than your BONK balance. Your BONK balance lives in a different account than your JUP balance. Every token gets its own dedicated account with its own address, its own rent deposit, and its own independent lifecycle.

This feels more verbose than Ethereum, where your ERC-20 balance is just a number in a mapping inside the contract. But it means every balance is an independent on-chain object. Any program can read it directly. Any protocol can verify your holdings without asking you. The state is open and composable in a way that private contract storage fundamentally is not.

pub struct TokenAccount {
    pub mint:             Pubkey,          // which token this holds
    pub owner:            Pubkey,          // who controls this account
    pub amount:           u64,             // balance in raw units
    pub delegate:         COption<Pubkey>, // approved spender
    pub state:            AccountState,    // Initialized, Frozen, Uninitialized
    pub is_native:        COption<u64>,    // wrapped SOL only
    pub delegated_amount: u64,             // how much delegate can spend
    pub close_authority:  COption<Pubkey>, // who can close this account
}
Enter fullscreen mode Exit fullscreen mode

The Associated Token Account

You want to send USDC to a friend. In your bank app you type their email or phone number and the money arrives. The bank figures out the rest. On Solana, token balances don't live in wallets — they live in token accounts, and token accounts have their own addresses separate from the wallet. So when you want to send someone USDC, which address do you send it to? Their wallet address can't hold USDC directly. You need their USDC token account address specifically.

Now imagine every user has to manually create a token account for every token they want to receive, then share that address with anyone who might send them tokens. And every protocol, every DEX, every wallet app has to maintain a database mapping "Alice's wallet → Alice's USDC account → Alice's BONK account → Alice's JUP account." That falls apart immediately. It does not scale, it is not reliable, and it puts an unreasonable burden on users just to receive tokens.

The Associated Token Account (ATA) is the solution. The idea is simple: instead of letting token accounts have arbitrary addresses, derive the address deterministically from two things the sender already knows — the recipient's wallet and the token's mint. Same inputs, same address, every time, for everyone.

How the Address Is Derived

An ATA address is a PDA — a Program Derived Address. If you have read the PDA section, you know a PDA is just a hash of some seeds combined with a program ID, where the result lands off the Ed25519 curve so no private key can exist for it.

For an ATA, the seeds are always exactly three things in this order:

seeds = [
    wallet_address,    // whose tokens
    token_program_id,  // always TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
    mint_address,      // which token
]
program = ATA_program_id  // AtsydnkFdNkFHuBWVEZDSWVdNgNpNjFNSELAVGMnAsrk
Enter fullscreen mode Exit fullscreen mode

Feed those into the PDA derivation function and you get back one address. Always the same address. The ATA Program does not store a lookup table or maintain any database. It just re-derives the address on demand from the inputs.

Here is where it gets practical. When Yash sends USDC to Aryan for the first time:

1. Yash's wallet derives Aryan's ATA address
   (Aryan's wallet + USDC mint → one deterministic address)

2. Yash's wallet checks: does this account exist on-chain?

3. If no → Yash's wallet creates it in the same transaction
   Yash pays the 0.00203 SOL rent deposit
   Aryan's ATA now exists on-chain

4. The USDC transfer goes through
   Aryan's ATA balance goes from 0 to whatever Yash sent
Enter fullscreen mode Exit fullscreen mode

Creating the YASH Token — How Everything Works Together

I want to create a token. I am going to call it YASH. It will have a fixed supply of one million tokens, six decimal places, and you will send some to a friend.

Simple enough goal. But to make it happen, four different programs need to coordinate, five different accounts need to exist, and each one has a job that none of the others can do. By the end of this you will not just know what each piece is — you will understand why removing any single one breaks the entire thing.

The Cast

Before the story starts, meet the players:

  • System Program — the only program that can create new accounts from nothing. Without it nothing else can exist.
  • Token Program — the program that understands what a token is. It owns Mint accounts and Token accounts and enforces every rule about balances and transfers.
  • ATA Program — the program that creates token accounts at predictable, deterministic addresses.
  • Your wallet — the keypair you hold. You are the authority behind everything that happens here.

And the accounts that will come into existence:

  • Mint account — the on-chain definition of the YASH token. What it is, how many decimals, who can create more.
  • Your token account — where your YASH balance lives. Not in your wallet — in a separate account specifically for YASH.
  • Your friend's token account — where their YASH balance will live after you send them some.

None of these accounts exist yet. Let us build them one by one.

Step One — The Mint Account

The first thing Solana needs to know is: what is the YASH token? How many decimal places? Who has the right to mint new tokens? Who can freeze accounts? None of this exists anywhere yet. You need to create a Mint account.

Creating any account on Solana is a two-step process, always. First the System Program allocates the storage. Then the appropriate program initializes it with meaning.

For the Mint account, step one is asking the System Program to create an 82-byte account, transfer enough SOL for rent exemption — roughly 0.00144 SOL — and hand ownership to the Token Program. Step two is calling InitializeMint on the Token Program, which writes your settings into those 82 bytes.

Why does the System Program need to be involved at all? Because the Token Program can only modify accounts it already owns. It cannot create them from nothing. Only the System Program can do that. So you always go to the System Program first to allocate the account, assign it to the Token Program, then go to the Token Program to fill it with data.

You
 │
 ├──▶ System Program: create_account
 │         allocate 82 bytes
 │         deposit 0.00144 SOL
 │         assign owner = Token Program
 │         → Mint account now exists, empty
 │
 └──▶ Token Program: initialize_mint
           decimals = 6
           mint_authority = your wallet
           freeze_authority = your wallet
           → Mint account now has meaning
Enter fullscreen mode Exit fullscreen mode

After these two instructions — which you can bundle into a single transaction — the YASH Mint account exists on-chain. Its address is whatever keypair you generated for it. The total supply is zero. Nobody holds any YASH yet.

Step Two — Your Token Account

The Mint exists but your wallet cannot hold YASH directly. Your wallet is owned by the System Program. The System Program knows nothing about tokens — it only understands SOL. To hold YASH, you need a Token account.

A Token account is a separate 165-byte account, owned by the Token Program, that holds your balance of one specific token. You need one for YASH specifically. It will sit at its own address on-chain, completely separate from your wallet.

You could create a token account at a random keypair address. But then nobody would know where to find your YASH balance — they would have to ask you every time. Instead you create an Associated Token Account — a token account at a deterministic address derived from your wallet and the YASH mint. Anyone who knows your wallet address and the YASH mint address can compute exactly where your YASH lives.

Creating your ATA involves three programs working in sequence. The ATA Program orchestrates it, the System Program allocates the storage, and the Token Program initializes the token account data.

You
 │
 └──▶ ATA Program: create_associated_token_account
           derives address from (your wallet + YASH mint)
           │
           ├──▶ System Program: create_account
           │         allocate 165 bytes
           │         deposit 0.00203 SOL
           │         assign owner = Token Program
           │
           └──▶ Token Program: initialize_account
                     mint = YASH mint address
                     owner = your wallet
                     amount = 0
                     → Your ATA exists with zero balance
Enter fullscreen mode Exit fullscreen mode

Step Three — Minting Tokens Into Existence

Now you have a Mint account defining what YASH is, and a token account ready to hold it. But supply is still zero. Time to actually create some YASH.

You call MintTo on the Token Program. You pass it the Mint account, your ATA as the destination, and sign with your wallet — which holds the mint authority. The Token Program checks your signature against the mint_authority field in the Mint account. They match. It creates one million YASH tokens directly into your ATA.

Two things change simultaneously. The Mint account's supply field goes from 0 to 1,000,000,000,000 raw units — one million YASH at six decimals. Your ATA's amount field goes from 0 to 1,000,000,000,000. These two numbers are always kept in sync by the Token Program. You cannot credit a token account without the mint supply reflecting it.

At this point you have one million YASH sitting in your ATA. The Mint account shows a supply of one million. Nobody else holds any.

Now lock the supply. If you revoke the mint authority — setting it to None — nobody, including you, can ever mint more YASH.

One instruction, permanently verifiable on-chain. Anyone can look up the YASH Mint account and see mint_authority: None. The supply is fixed at one million forever.

Step Four — Sending YASH to Your Friend

You want to send 1,000 YASH to your friend. Their wallet address is public — you have it. But they have never held YASH before, so their ATA does not exist yet.

Your wallet derives their ATA address from their wallet and the YASH mint. You check on-chain — the account does not exist. Your transaction creates it first, then transfers. You pay the 0.00203 SOL rent deposit for their ATA. Small cost, but it comes out of your wallet.

You
 │
 ├── derive friend's ATA address
 │   (friend's wallet + YASH mint → deterministic address)
 │
 ├──▶ ATA Program: create friend's ATA  (if it doesn't exist)
 │         System Program allocates 165 bytes
 │         Token Program initializes with friend's wallet as owner
 │         friend's ATA balance = 0
 │
 └──▶ Token Program: transfer
           from:      your ATA
           to:        friend's ATA
           authority: your wallet (you sign)
           amount:    1,000 * 10^6 raw units
Enter fullscreen mode Exit fullscreen mode

The Token Program verifies: your ATA and your friend's ATA both reference the same YASH mint. Your balance is sufficient. You actually signed. Neither account is frozen. All checks pass. Your ATA goes from 1,000,000 to 999,000 YASH. Your friend's ATA goes from 0 to 1,000 YASH. The mint supply is unchanged — this is a transfer, not a mint.

Why You Cannot Remove Any Piece

Here is the question the whole story was building to. You needed four programs and five accounts. Why not fewer?

Why not skip the System Program and let the Token Program create accounts directly?

The Token Program is designed to manage token state — balances, authorities, supply. If it could also create arbitrary accounts, it would have unbounded power over the entire network's storage. The System Program exists as the single gatekeeper for account creation precisely so that power is controlled and auditable. Every program on Solana has a narrow job. The System Program's job is allocation. Nothing else does it.

Why not put your balance directly in your wallet instead of a separate Token account?

Your wallet is owned by the System Program. The System Program knows nothing about tokens — it only understands lamports. For the Token Program to enforce token rules — checking mints match, checking authorities, enforcing freeze status, tracking delegations — it needs to own the accounts storing token balances. Ownership is what gives it write access. If your token balance lived in your wallet, the Token Program could not touch it.

Why not skip the ATA Program and just use regular token accounts?

You could. Token accounts at random keypair addresses are valid. But then every wallet, every protocol, every DEX would need a separate database mapping wallets to their token accounts for every possible token. The ATA Program exists to make that coordination unnecessary. It establishes a universal standard: given a wallet and a mint, the token account address is always this specific derivation. One convention, followed by everyone, eliminates an entire class of infrastructure complexity.

Why does the Mint account need to exist at all? Why not store supply inside each token account?

Because supply is a global property of the token, not a property of any individual holder. If supply were stored across token accounts, minting would require updating every account simultaneously — impossible in a parallel system. The Mint account is the single source of truth for what the token is and how much of it exists. Every token account references it. Every transfer validates against it. It is the anchor point the entire system coordinates around.

The YASH Token Ecosystem

YASH TOKEN ECOSYSTEM
─────────────────────────────────────────────────────────

  System Program          Token Program          ATA Program
  (creates accounts)      (manages tokens)       (derives addresses)
       │                        │                      │
       │                        │                      │
       ▼                        ▼                      ▼

  ┌─────────────┐      ┌──────────────────┐    ┌──────────────────┐
  │ MINT ACCOUNT│◀─────│  Token Program   │    │  Your ATA        │
  │             │      │  owns this       │    │  derived from    │
  │ supply: 1M  │      └──────────────────┘    │  (you + mint)    │
  │ decimals: 6 │               │              │  amount: 999,000 │
  │ auth: None  │               │              └──────────────────┘
  └─────────────┘               │
        ▲                       │              ┌──────────────────┐
        │                       │              │  Friend's ATA    │
        │ both reference        │              │  derived from    │
        │ same mint             │              │  (friend + mint) │
        │                       │              │  amount: 1,000   │
        └───────────────────────┘              └──────────────────┘

  PROGRAMS              ROLE                   CAN IT BE REMOVED?
  ──────────────────────────────────────────────────────────────
  System Program        Creates all accounts   No - nothing else can
  Token Program         Enforces token rules   No - nobody else owns accounts
  ATA Program           Derives addresses      Technically yes, practically no
Enter fullscreen mode Exit fullscreen mode

Four programs. Five accounts. Each one doing exactly one thing that no other component can do. That is not accidental complexity — it is the account model working as designed. Separation of concerns, enforced at the protocol level, making every piece independently auditable, composable, and replaceable without touching anything else.


Program Derived Addresses and the Bump Seed

Every account on Solana has an address. For your wallet, that address comes from a keypair — a private key and a public key generated together. You hold the private key, and the public key becomes your address. When you sign a transaction, you are proving to the network that you hold the private key behind that public address. That proof is what gives you the right to spend SOL, transfer tokens, or authorize any action tied to your wallet.

This works perfectly for humans. Humans can hold private keys.

Programs cannot.

A program deployed on Solana has no private key. It is just code sitting at an address. It cannot sign anything. But programs frequently need to own accounts — a vault holding escrowed funds, a treasury storing a protocol's reserves, a state account that only the program itself should be able to modify. If owning an account requires signing for it, and programs cannot sign, how does a program ever control anything?

This is the exact problem Program Derived Addresses (PDAs) solve.

What a PDA Is

A PDA is an account address that was not generated from a keypair. Instead it was computed — derived mathematically from a combination of seeds you choose and the program's own ID. No private key was ever involved. No private key exists for it. Nobody in the world can sign for a PDA the way a wallet signs for its address.

But the program that derived it can authorize actions on its behalf through a mechanism the runtime provides. That mechanism is invoke_signed, and it is what makes PDAs genuinely powerful rather than just an interesting curiosity.

Before getting to signing, you need to understand the derivation itself — because the derivation is what everything else is built on.

How a PDA Is Derived

The derivation takes three inputs: your seeds, your program ID, and a number called the bump. It hashes them together and produces a 32-byte address.

PDA = hash(seeds + program_id + bump)
Enter fullscreen mode Exit fullscreen mode

Seeds are whatever you choose — a static string like b"vault", a user's public key, an order ID, a mint address. They are the inputs that make each PDA unique and meaningful.

The program ID is fixed — it is the address of your deployed program.

The bump is the piece that requires explanation.

The Bump — Why It Exists

Solana's keypairs use a cryptographic system called Ed25519. Every valid public key in this system is a point on a specific mathematical curve — the Ed25519 curve. The curve has a precise shape, and every point that lies on it has a corresponding private key somewhere.

This creates a problem. If you hash your seeds and program ID together and the result happens to land on the Ed25519 curve, then a private key theoretically exists for that address. Someone could potentially find it and sign for your PDA as if they were a normal wallet. The entire security model collapses.

So Solana adds a requirement: a PDA must be an off-curve point. The hash result must not lie on the Ed25519 curve. If it does, it is not a valid PDA.

The bump is how you push the result off the curve. It is a single number, starting at 255, that gets appended to your seeds before hashing. If the hash of your seeds plus 255 lands on the curve, you try 254. Then 253. Then 252. You keep decrementing until the result lands off the curve. That first value that produces a valid off-curve address is the canonical bump.

Thanks to #mlh fro their solana

Top comments (0)