Sol.College

Full lesson

Epochnotes

What it does

From the project README:

Explore the registry · Ask your AI agent · Found in the field · Get started · Run the demo · Visual identity
Original
mskrad/Epochnotes
SuperStack fork
Blockchains/Epochnotes @ b9401ae
Stars
0
Last push (original)
2026-11-04
Languages
TypeScript, HTML, JavaScript, Rust, Solidity, Go
Detected stack
@solana/kitAnchor
Categories
Other
Licence
MIT

Architecture

144 source files. By extension: .ts ×112, .sol ×13, .rs ×11, .go ×4, .js ×2, .py ×2.

Top-level directorySource files
packages91
corpus47
(root)3
programs3

On-chain programs: programs/registry, programs/rent-example

Dapp: devnet deploy pending

⏳ Devnet deploy pending — goes live when the devnet wallet is topped up. This fork's own dapp is not deployed yet, so there is no program address or transaction to show. It is queued in dapp-queue.txt; once devnet SOL is available it is deployed, exercised with real devnet transactions, and this section switches to the live dapp at /dapps/epochnotes/. Until then, the lesson and step-by-step guide below are complete, and you can 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.

mskrad/Epochnotes · programs/registry/src/lib.rs L145–168 @ b9401ae · MIT · original
    /// The publisher's latest version when the entry was withdrawn.    pub at_version: u64,    pub slot: u64,    pub bump: u8,} #[derive(Accounts)]pub struct Initialize<'info> {    #[account(init, payer = admin, space = 8 + Config::INIT_SPACE, seeds = [b"config"], bump)]    pub config: Account<'info, Config>,    #[account(mut)]    pub admin: Signer<'info>,    pub system_program: Program<'info, System>,} #[derive(Accounts)]#[instruction(authority: Pubkey)]pub struct RegisterPublisher<'info> {    #[account(seeds = [b"config"], bump = config.bump, has_one = admin @ RegistryError::NotAdmin)]    pub config: Account<'info, Config>,    #[account(init, payer = admin, space = 8 + Publisher::INIT_SPACE, seeds = [b"publisher", authority.as_ref()], bump)]    pub publisher: Account<'info, Publisher>,    #[account(mut)]    pub admin: Signer<'info>,
  1. Line 148 pub bump: u8,: Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve.
  2. Line 153 #[account(init, payer = admin, space = 8 + Config::INIT_SPACE, seeds = [b"config"], bump)]: Declares the PDA seeds. Anchor re-derives the address and rejects the account if it doesn't match.
  3. Line 153 #[account(init, payer = admin, space = 8 + Config::INIT_SPACE, seeds = [b"config"], bump)]: Creates and pays for a new account. Space and payer must be specified.
  4. Line 156 pub admin: Signer<'info>,: Requires this account to have signed the transaction.
  5. Line 163 #[account(seeds = [b"config"], bump = config.bump, has_one = admin @ RegistryError::NotAdm: Checks that a stored pubkey field matches the passed account.
mskrad/Epochnotes · programs/rent-example/src/lib.rs L13–36 @ b9401ae · MIT · original
     pub fn initialize(ctx: Context<Initialize>) -> Result<()> {        ctx.accounts.vault.authority = ctx.accounts.authority.key();        Ok(())    }     pub fn withdraw_excess(ctx: Context<WithdrawExcess>) -> Result<()> {        withdraw_excess::withdraw_excess(ctx)    }} #[derive(Accounts)]pub struct Initialize<'info> {    #[account(init, payer = authority, space = 8 + Vault::INIT_SPACE, seeds = [b"vault", authority.key().as_ref()], bump)]    pub vault: Account<'info, Vault>,    #[account(mut)]    pub authority: Signer<'info>,    pub system_program: Program<'info, System>,} #[account]#[derive(InitSpace)]pub struct Vault {    pub authority: Pubkey,
  1. Line 26 #[account(init, payer = authority, space = 8 + Vault::INIT_SPACE, seeds = [b"vault", autho: Declares the PDA seeds. Anchor re-derives the address and rejects the account if it doesn't match.
  2. Line 26 #[account(init, payer = authority, space = 8 + Vault::INIT_SPACE, seeds = [b"vault", autho: Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve.
  3. Line 26 #[account(init, payer = authority, space = 8 + Vault::INIT_SPACE, seeds = [b"vault", autho: Creates and pays for a new account. Space and payer must be specified.
  4. Line 29 pub authority: Signer<'info>,: Requires this account to have signed the transaction.
mskrad/Epochnotes · programs/rent-example/src/withdraw_excess.rs L13–36 @ b9401ae · MIT · original
 use crate::Vault; #[derive(Accounts)]pub struct WithdrawExcess<'info> {    /// Only the authority stored in the account may withdraw.    #[account(mut, has_one = authority @ WithdrawExcessError::NotAuthority)]    pub account: Account<'info, Vault>,    #[account(mut)]    pub authority: Signer<'info>,} pub fn withdraw_excess(ctx: Context<WithdrawExcess>) -> Result<()> {    let account = ctx.accounts.account.to_account_info();    // The minimum is asked from the cluster at run time. A rate compiled into the program goes stale at every    // step of the reduction, and the reduction is not guaranteed to be one-way.    let minimum = Rent::get()?.minimum_balance(account.data_len());    let excess = account.lamports().saturating_sub(minimum);    require!(excess > 0, WithdrawExcessError::NothingToWithdraw);     // The program owns the account, so it may debit it directly; the account stays rent-exempt by construction.    **account.try_borrow_mut_lamports()? -= excess;    **ctx.accounts.authority.to_account_info().try_borrow_mut_lamports()? += excess;    Ok(())
  1. Line 19 #[account(mut, has_one = authority @ WithdrawExcessError::NotAuthority)]: Checks that a stored pubkey field matches the passed account.
  2. Line 22 pub authority: Signer<'info>,: Requires this account to have signed the transaction.
  3. Line 31 require!(excess > 0, WithdrawExcessError::NothingToWithdraw);: An explicit validation that aborts the instruction with an error.
mskrad/Epochnotes · packages/core/src/rent-template.ts L73–96 @ b9401ae · MIT · original
 use crate::${accountType}; #[derive(Accounts)]pub struct WithdrawExcess<'info> {    /// Only the authority stored in the account may withdraw.    #[account(mut, has_one = ${authorityField} @ WithdrawExcessError::NotAuthority)]    pub account: Account<'info, ${accountType}>,    #[account(mut)]    pub ${authorityField}: Signer<'info>,} pub fn withdraw_excess(ctx: Context<WithdrawExcess>) -> Result<()> {    let account = ctx.accounts.account.to_account_info();    // The minimum is asked from the cluster at run time. A rate compiled into the program goes stale at every    // step of the reduction, and the reduction is not guaranteed to be one-way.    let minimum = Rent::get()?.minimum_balance(account.data_len());    let excess = account.lamports().saturating_sub(minimum);    require!(excess > 0, WithdrawExcessError::NothingToWithdraw);     // The program owns the account, so it may debit it directly; the account stays rent-exempt by construction.    **account.try_borrow_mut_lamports()? -= excess;    **ctx.accounts.${authorityField}.to_account_info().try_borrow_mut_lamports()? += excess;    Ok(())
  1. Line 79 #[account(mut, has_one = ${authorityField} @ WithdrawExcessError::NotAuthority)]: Checks that a stored pubkey field matches the passed account.
  2. Line 82 pub ${authorityField}: Signer<'info>,: Requires this account to have signed the transaction.
  3. Line 91 require!(excess > 0, WithdrawExcessError::NothingToWithdraw);: An explicit validation that aborts the instruction with an error.

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
.npm run buildtsc -b
.npm run testvitest run
.npm run lintnpm run typecheck:tests && eslint . && prettier --check . && node scripts/check-language.mjs
packages/clinpm run testvitest run --root ../.. packages/cli/test
packages/corenpm run testvitest run --root ../.. packages/core/test
.anchor buildcompile programs and generate IDLs
.anchor testlocal validator + test suite
.anchor run testnpx vitest run --config vitest.onchain.config.ts --reporter=verbose
.cargo buildRust workspace build
.cargo testRust tests

What you could build from it

Used in lessons