Sol.College

Full lesson

anchor

⚓ Solana Program Framework

What it does

From the project README:

Anchor is a framework providing several convenient developer tools for writing Solana programs (sometimes called 'smart contracts').
Original
otter-sec/anchor
SuperStack fork
Blockchains/anchor @ 541295d
Stars
5,166
Last push (original)
2026-11-02
Languages
Rust, TypeScript, JavaScript, Astro, Shell, CSS
Detected stack
AnchorNext.jsweb3.js
Categories
Infrastructure & Tooling
Licence
Apache-2.0
Homepage
https://anchor-lang.com

Architecture

749 source files. By extension: .ts ×353, .rs ×348, .js ×33, .tsx ×15.

Top-level directorySource files
tests204
ts201
lang113
docs-v2109
cli42
spl31
docs15
examples14

On-chain programs: examples/tutorial/basic-0/programs/basic-0, examples/tutorial/basic-1/programs/basic-1, examples/tutorial/basic-2/programs/basic-2, examples/tutorial/basic-3/programs/puppet, examples/tutorial/basic-3/programs/puppet-master, examples/tutorial/basic-4/programs/basic-4, examples/tutorial/basic-5/programs/basic-5, tests/account-generation-test/programs/account-generation-test

Dapp: deploying

This fork is queued for its own live dapp on Sol.College, with a Devnet/Mainnet switch. It appears here, at /dapps/anchor/, once it is deployed and checked on devnet. Until then, run it locally with the commands below.

Key code, explained

Excerpts chosen automatically where the code uses the most Solana concepts, pinned to the fork's commit.

otter-sec/anchor · docs-v2/src/content/docs/v1/tokens/spl-token-basics/_transfer-tokens/lib_pda.rs L37–60 @ 541295d · Apache-2.0 · original
            authority: ctx.accounts.sender_token_account.to_account_info(),        };        let cpi_program = ctx.accounts.token_program.to_account_info();        let cpi_context = CpiContext::new(cpi_program, cpi_accounts).with_signer(signer_seeds);        token_interface::transfer_checked(cpi_context, amount, decimals)?;        Ok(())    }} #[derive(Accounts)]pub struct CreateAndMintTokens<'info> {    #[account(mut)]    pub signer: Signer<'info>,    #[account(        init,        payer = signer,        mint::decimals = 6,        mint::authority = mint,        mint::freeze_authority = mint,        seeds = [b"mint"],        bump    )]    pub mint: InterfaceAccount<'info, Mint>,    #[account(
  1. Line 40 let cpi_context = CpiContext::new(cpi_program, cpi_accounts).with_signer(signer_seeds);: Makes a cross-program invocation into another program.
  2. Line 41 token_interface::transfer_checked(cpi_context, amount, decimals)?;: A checked token transfer, which also verifies the mint and decimals.
  3. Line 47 pub struct CreateAndMintTokens<'info> {: Mints new tokens. The mint authority must sign.
  4. Line 49 pub signer: Signer<'info>,: Requires this account to have signed the transaction.
  5. Line 51 init,: Creates and pays for a new account. Space and payer must be specified.
  6. Line 56 seeds = [b"mint"],: Declares the PDA seeds. Anchor re-derives the address and rejects the account if it doesn't match.
  7. Line 57 bump: Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve.
otter-sec/anchor · cli/src/template.rs L157–180 @ 541295d · Apache-2.0 · original
         ctx.accounts.counter.count += 1;        msg!("Hello, world! Counter is now {{}}", ctx.accounts.counter.count);        Ok(())    }}}} #[derive(Accounts)]pub struct Initialize<'info> {{    #[account(mut)]    pub payer: Signer<'info>,    #[account(        init,        payer = payer,        space = 8 + Counter::INIT_SPACE,        seeds = [COUNTER_SEED],        bump    )]    pub counter: Account<'info, Counter>,    pub system_program: Program<'info, System>,}} #[derive(Accounts)]pub struct Increment<'info> {{
  1. Line 159 msg!("Hello, world! Counter is now {{}}", ctx.accounts.counter.count);: Logs to the program log, which is visible in explorers and the test output.
  2. Line 167 pub payer: Signer<'info>,: Requires this account to have signed the transaction.
  3. Line 169 init,: Creates and pays for a new account. Space and payer must be specified.
  4. Line 172 seeds = [COUNTER_SEED],: Declares the PDA seeds. Anchor re-derives the address and rejects the account if it doesn't match.
  5. Line 173 bump: Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve.
otter-sec/anchor · examples/tutorial/basic-5/programs/basic-5/src/lib.rs L49–72 @ 541295d · Apache-2.0 · original
    }} #[derive(Accounts)]pub struct Create<'info> {    // init means to create action_state account    // bump to use unique address for action_state account    #[account(        init,        payer = user,        space = 8 + ActionState::INIT_SPACE,        seeds = [b"action-state", user.key().as_ref()],        bump    )]    pub action_state: Account<'info, ActionState>,    // mut makes it changeable (mutable)    #[account(mut)]    pub user: Signer<'info>,    pub system_program: Program<'info, System>,} #[derive(Accounts)]pub struct Walk<'info> {    // Only the user on account action_state, should be able to change state
  1. Line 55 // bump to use unique address for action_state account: Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve.
  2. Line 57 init,: Creates and pays for a new account. Space and payer must be specified.
  3. Line 60 seeds = [b"action-state", user.key().as_ref()],: Declares the PDA seeds. Anchor re-derives the address and rejects the account if it doesn't match.
  4. Line 66 pub user: Signer<'info>,: Requires this account to have signed the transaction.
otter-sec/anchor · examples/tutorial/basic-4/programs/basic-4/src/lib.rs L25–48 @ 541295d · Apache-2.0 · original
            ctx.accounts.authority.key(),            ctx.accounts.counter.authority,            ErrorCode::Unauthorized        );         ctx.accounts.counter.count += 1;        Ok(())    }} #[derive(Accounts)]pub struct Initialize<'info> {    #[account(        init,        payer = authority,        space = Counter::SIZE,        seeds = [b"counter"],        bump    )]    counter: Account<'info, Counter>,    #[account(mut)]    authority: Signer<'info>,    system_program: Program<'info, System>,}
  1. Line 38 init,: Creates and pays for a new account. Space and payer must be specified.
  2. Line 41 seeds = [b"counter"],: Declares the PDA seeds. Anchor re-derives the address and rejects the account if it doesn't match.
  3. Line 42 bump: Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve.
  4. Line 46 authority: Signer<'info>,: Requires this account to have signed the transaction.

How to run, build and test

These commands come from the repo's own manifests (package.json scripts, Anchor.toml, Cargo, go.mod, Makefile). Check the README for prerequisites and environment variables.

DirectoryCommandRuns
docsnpm run devnext dev
docsnpm run startnext start
docsnpm run buildnext build
examples/tutorialnpm run lintprettier */*.js "*/**/*{.js,.ts}" --check
ts/testsnpm run testrimraf dist && tsc -p . && ts-node dist
docs-v2npm run devastro dev
docs-v2npm run startastro dev
docs-v2npm run buildastro check && astro build
testsnpm run lintprettier */*.js "*/**/*{.js,.ts}" --check
tests/relations-derivationnpm run testanchor test
tests/accountloader-reallocnpm run testanchor test
tests/reallocnpm run testanchor test
tests/pda-derivationnpm run testanchor test
tests/custom-programnpm run testanchor test
tests/typescriptnpm run testanchor test
tests/lockupnpm run testanchor test

What you could build from it

Used in lessons