Cabin Sol
Solana development tutor and builder. Teaches program development through challenges, Anchor framework, Token-2022, Compressed NFTs, and security best practices. "Return to primitive computing."
Solana development tutor and builder. Teaches program development through challenges, Anchor framework, Token-2022, Compressed NFTs, and security best practices. "Return to primitive computing."
Real data. Real impact.
Growing
Developers
Per week
Open source
Skills give you superpowers. Install in 30 seconds.
"Return to primitive computing."
A comprehensive Solana development guide for AI agents. Build programs with Anchor, master the account model, and avoid the gotchas that wreck most developers.
ACCOUNTS ARE EVERYTHING ON SOLANA.
Unlike Ethereum where contracts have internal storage, Solana programs are stateless. All data lives in accounts that programs read and write.
For EVERY feature, ask:
npx create-solana-dapp@latest # Select: Next.js + next-tailwind-counter cd my-project npm install npm run anchor localnet # Terminal 1 npm run anchor build && npm run anchor deploy # Terminal 2 npm run dev # Terminal 3
anchor init my_program cd my_program solana-test-validator # Terminal 1 anchor build && anchor deploy # Terminal 2 anchor test
my-solana-dapp/ āāā anchor/ # Solana programs (Rust) ā āāā programs/ ā ā āāā my_program/ ā ā āāā src/lib.rs # Your Rust program ā āāā tests/ # TypeScript tests ā āāā Anchor.toml # Anchor config āāā src/ # Next.js frontend ā āāā app/ ā āāā components/ āāā package.json
Learn Solana through progressive challenges:
| # | Challenge | Core Concept |
|---|---|---|
| 0 | Hello Solana | First Anchor program, accounts |
| 1 | SPL Token | Fungible tokens, ATAs, minting |
| 2 | NFT Metaplex | NFT standard, metadata, collections |
| 3 | PDA Escrow | PDAs, program authority, escrow |
| 4 | Staking | Time-based rewards, deposits |
| 5 | Token-2022 | Transfer hooks, extensions |
| 6 | Compressed NFTs | State compression, Merkle trees |
| 7 | Oracle (Pyth) | Price feeds, staleness checks |
| 8 | AMM Swap | Constant product, liquidity pools |
| 9 | Blinks & Actions | Shareable transactions |
// Each value has ONE owner let s1 = String::from("hello"); let s2 = s1; // s1 MOVED to s2 // println!("{}", s1); // ERROR!// Borrowing lets you use without owning fn get_length(s: &String) -> usize { s.len() // Borrow, don't own }
// Result for errors pub fn do_thing(ctx: Context<DoThing>) -> Result<()> { let value = some_operation().ok_or(ErrorCode::Failed)?; Ok(()) }// Option for nullable let maybe: Option<u64> = Some(42); let value = maybe.unwrap_or(0); // Safe default
use anchor_lang::prelude::*;declare_id!("YourProgramId11111111111111111111111111111");
#[program] pub mod my_program { use super::*;
pub fn initialize(ctx: Context<Initialize>, data: u64) -> Result<()> { ctx.accounts.my_account.data = data; ctx.accounts.my_account.authority = ctx.accounts.authority.key(); Ok(()) }}
#[derive(Accounts)] pub struct Initialize<'info> { #[account( init, payer = authority, space = 8 + 8 + 32, // discriminator + u64 + Pubkey )] pub my_account: Account<'info, MyAccount>, #[account(mut)] pub authority: Signer<'info>, pub system_program: Program<'info, System>, }
#[account] pub struct MyAccount { pub data: u64, pub authority: Pubkey, }
// Initialize new account #[account(init, payer = payer, space = 8 + SIZE)] pub new_account: Account<'info, Data>,// Mutable existing #[account(mut)] pub existing: Account<'info, Data>,
// Verify ownership #[account(has_one = authority)] pub owned: Account<'info, Data>,
// PDA with seeds #[account( seeds = [b"vault", user.key().as_ref()], bump, )] pub vault: Account<'info, Vault>,
// Initialize PDA #[account( init, payer = user, space = 8 + 64, seeds = [b"user", user.key().as_ref()], bump, )] pub user_data: Account<'info, UserData>,
// Close and reclaim rent #[account(mut, close = recipient)] pub closing: Account<'info, Data>,
// PDAs are deterministic addresses with no private key // Your program can "sign" for them// Find PDA let (pda, bump) = Pubkey::find_program_address( &[b"vault", user.key().as_ref()], &program_id, );
// Sign with PDA in CPI let seeds = &[b"vault", user.key().as_ref(), &[bump]]; let signer = &[&seeds[..]];
token::transfer( CpiContext::new_with_signer( ctx.accounts.token_program.to_account_info(), Transfer { from, to, authority: vault }, signer, ), amount, )?;
Programs are stateless. ALL data lives in accounts.
Derived deterministically from seeds. Only the program can sign.
Each token needs its own account per wallet (Associated Token Account).
Accounts need SOL to exist. Rent-exempt = 2 years upfront (~0.002 SOL).
Fixed budget: 200k default, 1.4M max. Request more if needed.
ALWAYS add 8 bytes for Anchor's discriminator!
// WRONG space = 8 + 32 // Forgot discriminator? NO!// RIGHT space = 8 + 8 + 32 // 8 (discriminator) + 8 (u64) + 32 (Pubkey)
// BAD let result = a + b; // Can panic!// GOOD let result = a.checked_add(b).ok_or(ErrorCode::Overflow)?;
Separate program ID from SPL Token! Check which one you're using.
// Already configured in create-solana-dapp! import { useWallet, useConnection } from '@solana/wallet-adapter-react'; import { WalletMultiButton } from '@solana/wallet-adapter-react-ui';function App() { const { publicKey } = useWallet(); return ( <> <WalletMultiButton /> {publicKey && <p>Connected: {publicKey.toBase58()}</p>} </> ); }
import { Program, AnchorProvider, BN } from '@coral-xyz/anchor';const program = new Program(idl, provider);
// Write await program.methods .initialize(new BN(42)) .accounts({ myAccount: keypair.publicKey, authority: wallet.publicKey, systemProgram: SystemProgram.programId, }) .signers([keypair]) .rpc();
// Read const account = await program.account.myAccount.fetch(pubkey); console.log(account.data.toNumber());
spl-token create-token spl-token create-account <MINT> spl-token mint <MINT> 1000
Extensions: transfer hooks, confidential transfers, interest-bearing, non-transferable.
spl-token create-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb
Standard NFT metadata, collections, royalties.
Merkle tree storage. 1M NFTs for ~$100 instead of $1M.
import * as anchor from '@coral-xyz/anchor'; import { expect } from 'chai';describe('my-program', () => { const provider = anchor.AnchorProvider.env(); anchor.setProvider(provider); const program = anchor.workspace.MyProgram;
it('initializes', async () => { const account = anchor.web3.Keypair.generate();
await program.methods .initialize(new anchor.BN(42)) .accounts({ myAccount: account.publicKey }) .signers([account]) .rpc(); const data = await program.account.myAccount.fetch(account.publicKey); expect(data.data.toNumber()).to.equal(42);}); });
# Devnet solana config set --url devnet solana airdrop 2 anchor build && anchor deployMainnet (costs ~2-5 SOL)
solana config set --url mainnet-beta anchor deploy --provider.cluster mainnet
"They put me in the cloud. I wanted the forest." š²
No automatic installation available. Please visit the source repository for installation instructions.
View Installation Instructions1,500+ AI skills, agents & workflows. Install in 30 seconds. Part of the Torly.ai family.
Ā© 2026 Torly.ai. All rights reserved.