Sol.College

Full lesson

Vetra

Chrome extension (MV3) that assesses Solana transactions before signing. Wraps window.solana, runs local heuristics, shows risk score and reasons. Optional on-chain attestations via Anchor with reputation/stake for signal providers. Privacy by default.

What it does

From the project README:

1. Open `chrome://extensions/` 2. Enable "Developer mode" 3. Click "Load unpacked" → Select `frontend/extension/dist`
Original
williamhnyohei/Vetra
SuperStack fork
Blockchains/Vetra @ c6b3071
Stars
2
Last push (original)
2026-09-24
Languages
TypeScript, JavaScript, Python, HTML, Rust, CSS
Detected stack
Anchorweb3.js
Categories
Infrastructure & Tooling
Licence
MIT

Architecture

143 source files. By extension: .js ×53, .ts ×46, .py ×18, .tsx ×16, .rs ×10.

Top-level directorySource files
frontend64
backend59
vetra_mas18
(root)1
scripts1

On-chain programs: backend/programs/attestation

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/vetra/. 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.

williamhnyohei/Vetra · backend/programs/attestation/src/instructions/stake_reputation.rs L1–24 @ c6b3071 · MIT · original
use anchor_lang::prelude::*;use anchor_lang::system_program;use crate::state::SignalProvider;use crate::errors::AttestationError; #[derive(Accounts)]pub struct StakeReputation<'info> {    #[account(mut)]    pub authority: Signer<'info>,     #[account(        init_if_needed,        payer = authority,        space = 8 + SignalProvider::MAX_SIZE,        seeds = [b"provider", authority.key().as_ref()],        bump    )]    pub provider: Account<'info, SignalProvider>,     pub system_program: Program<'info, System>,} pub fn handler(ctx: Context<StakeReputation>, amount: u64) -> Result<()> {    require!(amount >= SignalProvider::MIN_STAKE, AttestationError::InsufficientStake);
  1. Line 9 pub authority: Signer<'info>,: Requires this account to have signed the transaction.
  2. Line 12 init_if_needed,: Creates the account only if it doesn't exist. Watch for re-initialisation bugs.
  3. Line 15 seeds = [b"provider", authority.key().as_ref()],: Declares the PDA seeds. Anchor re-derives the address and rejects the account if it doesn't match.
  4. Line 16 bump: Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve.
  5. Line 24 require!(amount >= SignalProvider::MIN_STAKE, AttestationError::InsufficientStake);: An explicit validation that aborts the instruction with an error.
williamhnyohei/Vetra · backend/programs/attestation/src/instructions/create_attestation.rs L1–24 @ c6b3071 · MIT · original
use anchor_lang::prelude::*;use crate::state::{Attestation, SignalProvider};use crate::errors::AttestationError; #[derive(Accounts)]#[instruction(transaction_hash: [u8; 32])]pub struct CreateAttestation<'info> {    #[account(mut)]    pub provider_authority: Signer<'info>,     #[account(        mut,        seeds = [b"provider", provider_authority.key().as_ref()],        bump = provider.bump,        constraint = provider.stake >= SignalProvider::MIN_STAKE @ AttestationError::InsufficientStake    )]    pub provider: Account<'info, SignalProvider>,     #[account(        init,        payer = provider_authority,        space = 8 + Attestation::MAX_SIZE,        seeds = [            b"attestation",
  1. Line 9 pub provider_authority: Signer<'info>,: Requires this account to have signed the transaction.
  2. Line 13 seeds = [b"provider", provider_authority.key().as_ref()],: Declares the PDA seeds. Anchor re-derives the address and rejects the account if it doesn't match.
  3. Line 14 bump = provider.bump,: Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve.
  4. Line 15 constraint = provider.stake >= SignalProvider::MIN_STAKE @ AttestationError::InsufficientS: Touches staking state: the amount locked and when it was locked.
  5. Line 20 init,: Creates and pays for a new account. Space and payer must be specified.
williamhnyohei/Vetra · backend/programs/attestation/src/instructions/withdraw_stake.rs L1–23 @ c6b3071 · MIT · original
use anchor_lang::prelude::*;use crate::state::SignalProvider;use crate::errors::AttestationError; #[derive(Accounts)]pub struct WithdrawStake<'info> {    #[account(mut)]    pub authority: Signer<'info>,     #[account(        mut,        seeds = [b"provider", authority.key().as_ref()],        bump = provider.bump,        constraint = provider.authority == authority.key() @ AttestationError::Unauthorized    )]    pub provider: Account<'info, SignalProvider>,     pub system_program: Program<'info, System>,} pub fn handler(ctx: Context<WithdrawStake>, amount: u64) -> Result<()> {    let provider = &mut ctx.accounts.provider;    let clock = Clock::get()?;
  1. Line 8 pub authority: Signer<'info>,: Requires this account to have signed the transaction.
  2. Line 12 seeds = [b"provider", authority.key().as_ref()],: Declares the PDA seeds. Anchor re-derives the address and rejects the account if it doesn't match.
  3. Line 13 bump = provider.bump,: Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve.
  4. Line 23 let clock = Clock::get()?;: Reads on-chain time from the Clock sysvar.
williamhnyohei/Vetra · backend/programs/attestation/src/instructions/vote_attestation.rs L1–24 @ c6b3071 · MIT · original
use anchor_lang::prelude::*;use crate::state::{Attestation, SignalProvider}; #[derive(Accounts)]pub struct VoteAttestation<'info> {    pub voter: Signer<'info>,     #[account(mut)]    pub attestation: Account<'info, Attestation>,     #[account(        mut,        seeds = [b"provider", attestation.provider.as_ref()],        bump = provider.bump    )]    pub provider: Account<'info, SignalProvider>,} pub fn handler(ctx: Context<VoteAttestation>, is_accurate: bool) -> Result<()> {    let attestation = &mut ctx.accounts.attestation;    let provider = &mut ctx.accounts.provider;     // Update vote counts    if is_accurate {
  1. Line 6 pub voter: Signer<'info>,: Requires this account to have signed the transaction.
  2. Line 13 seeds = [b"provider", attestation.provider.as_ref()],: Declares the PDA seeds. Anchor re-derives the address and rejects the account if it doesn't match.
  3. Line 14 bump = provider.bump: Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve.

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 devpnpm --filter @vetra/extension dev
.npm run buildpnpm -r build
.npm run testpnpm -r test
.npm run lintpnpm -r lint
frontend/extensionnpm run devvite
frontend/extensionnpm run buildvite build && node copy-icons.cjs
frontend/extensionnpm run testvitest run
frontend/extensionnpm run linteslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0
backendnpm run devnodemon src/server.js
backendnpm run startnode src/server.js
backendnpm run buildecho 'No build step required'
backendnpm run testjest
backendnpm run linteslint src/
backend/programsanchor buildcompile programs and generate IDLs
backend/programsanchor testlocal validator + test suite
backend/programsanchor run testyarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts

What you could build from it

Used in lessons