Sol.College

Full lesson

GenoVault

Medical and genomic data marketplace where data never leaves encryption — Arcium MPC on Solana, consent enforced on-chain.

What it does

From the project README:

A marketplace for medical and genomic data where the data never leaves encryption. A clinic, a biobank or an individual puts a dataset to work without handing over the records; the owner's consent is a condition of execution, not a clause in a contract; and the fee for a run is split among those whose data actually went into it.
Original
GenoVault/GenoVault
SuperStack fork
Blockchains/GenoVault @ ed59a67
Stars
0
Last push (original)
2026-10-28
Languages
TypeScript, Rust, Shell, HTML, JavaScript, CSS
Detected stack
@solana/kitAnchorweb3.js
Categories
DeFiInfrastructure & Tooling
Licence
Apache-2.0
Homepage
https://genovault.github.io/GenoVault/

Architecture

226 source files. By extension: .ts ×166, .rs ×35, .tsx ×22, .js ×3.

Top-level directorySource files
apps79
tools61
packages51
programs32
encrypted-ixs3

On-chain programs: programs/genovault

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

GenoVault/GenoVault · programs/genovault/src/instructions/request_run.rs L301–324 @ ed59a67 · Apache-2.0 · original
/// одного виклику в скрипті розгортання.#[derive(Accounts)]pub struct InitializeVault<'info> {    #[account(mut)]    pub authority: Signer<'info>,    #[account(        seeds = [PlatformConfig::SEED],        bump = config.bump,        has_one = authority,        has_one = mint,    )]    pub config: Account<'info, PlatformConfig>,    pub mint: InterfaceAccount<'info, Mint>,    #[account(        init,        payer = authority,        seeds = [PlatformConfig::VAULT_SEED],        bump,        token::mint = mint,        token::authority = config,        token::token_program = token_program,    )]    pub vault: InterfaceAccount<'info, TokenAccount>,    pub token_program: Interface<'info, TokenInterface>,
  1. Line 305 pub authority: Signer<'info>,: Requires this account to have signed the transaction.
  2. Line 307 seeds = [PlatformConfig::SEED],: Declares the PDA seeds. Anchor re-derives the address and rejects the account if it doesn't match.
  3. Line 308 bump = config.bump,: Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve.
  4. Line 309 has_one = authority,: Checks that a stored pubkey field matches the passed account.
  5. Line 315 init,: Creates and pays for a new account. Space and payer must be specified.
GenoVault/GenoVault · programs/genovault/src/instructions/consent.rs L13–36 @ ed59a67 · Apache-2.0 · original
 #[derive(Accounts)]pub struct SetConsent<'info> {    #[account(mut)]    pub owner: Signer<'info>,    #[account(        mut,        has_one = owner @ GenoVaultError::NotDatasetOwner,        seeds = [Dataset::SEED, owner.key().as_ref(), dataset.dataset_id.as_bytes()],        bump = dataset.bump,    )]    pub dataset: Account<'info, Dataset>,    /// Попередня версія згоди — або `None` для першої.    ///    /// Акаунт приймається як `Option`, а не як окремий набір інструкцій: так    /// ланцюг версій будує сама програма, і клієнт не може зв'язати нову    /// згоду з довільною чужою.    #[account(        seeds = [Consent::SEED, dataset.key().as_ref(), &dataset.consent_version.to_le_bytes()],        bump = previous_consent.bump,    )]    pub previous_consent: Option<Account<'info, Consent>>,    #[account(        init,
  1. Line 17 pub owner: Signer<'info>,: Requires this account to have signed the transaction.
  2. Line 20 has_one = owner @ GenoVaultError::NotDatasetOwner,: Checks that a stored pubkey field matches the passed account.
  3. Line 21 seeds = [Dataset::SEED, owner.key().as_ref(), dataset.dataset_id.as_bytes()],: Declares the PDA seeds. Anchor re-derives the address and rejects the account if it doesn't match.
  4. Line 22 bump = dataset.bump,: Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve.
  5. Line 36 init,: Creates and pays for a new account. Space and payer must be specified.
GenoVault/GenoVault · programs/genovault/src/instructions/initialize.rs L1–24 @ ed59a67 · Apache-2.0 · original
use anchor_lang::prelude::*; use crate::errors::GenoVaultError;use crate::state::{PlatformConfig, MAX_FEE_BPS}; /// Мінт із конфіденційним розширенням буває лише в Token-2022: у класичному/// SPL Token розширень немає взагалі. Перевірка власника акаунта відсікає/// найдешевшу помилку розгортання — конфігурацію на звичайний мінт, з якою/// `FR-021` тихо стає недосяжним аж до `T054`.pub const TOKEN_2022_PROGRAM_ID: Pubkey = pubkey!("TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"); #[derive(Accounts)]pub struct Initialize<'info> {    #[account(mut)]    pub authority: Signer<'info>,    #[account(        init,        payer = authority,        space = 8 + PlatformConfig::INIT_SPACE,        seeds = [PlatformConfig::SEED],        bump,    )]    pub config: Account<'info, PlatformConfig>,    /// CHECK: тут перевіряється лише те, що акаунт належить Token-2022.
  1. Line 10 pub const TOKEN_2022_PROGRAM_ID: Pubkey = pubkey!("TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpP: Targets the Token-2022 program instead of the original Token Program.
  2. Line 15 pub authority: Signer<'info>,: Requires this account to have signed the transaction.
  3. Line 17 init,: Creates and pays for a new account. Space and payer must be specified.
  4. Line 20 seeds = [PlatformConfig::SEED],: Declares the PDA seeds. Anchor re-derives the address and rejects the account if it doesn't match.
  5. Line 21 bump,: Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve.
GenoVault/GenoVault · programs/genovault/src/instructions/dataset.rs L1–24 @ ed59a67 · Apache-2.0 · original
use anchor_lang::prelude::*; use crate::errors::GenoVaultError;use crate::state::{Dataset, DatasetStatus, DATASET_ID_MAX_LEN}; #[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)]pub struct RegisterDatasetArgs {    pub dataset_id: String,    pub content_hash: [u8; 32],    pub record_count_claimed: u64,    pub price_per_1k: u64,} #[derive(Accounts)]#[instruction(args: RegisterDatasetArgs)]pub struct RegisterDataset<'info> {    #[account(mut)]    pub owner: Signer<'info>,    #[account(        init,        payer = owner,        space = 8 + Dataset::INIT_SPACE,        seeds = [Dataset::SEED, owner.key().as_ref(), args.dataset_id.as_bytes()],        bump,
  1. Line 18 pub owner: Signer<'info>,: Requires this account to have signed the transaction.
  2. Line 20 init,: Creates and pays for a new account. Space and payer must be specified.
  3. Line 23 seeds = [Dataset::SEED, owner.key().as_ref(), args.dataset_id.as_bytes()],: Declares the PDA seeds. Anchor re-derives the address and rejects the account if it doesn't match.
  4. Line 24 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 -r --parallel dev
.npm run buildpnpm -r build
.npm run testpnpm -r --parallel test
.npm run lintbiome check .
apps/webnpm run devvite
apps/webnpm run buildvite build
apps/webnpm run testvitest run
apps/apinpm run devnode --experimental-strip-types --watch src/server.ts
apps/apinpm run startnode --experimental-strip-types src/server.ts
apps/apinpm run testvitest run
packages/sharednpm run testvitest run
packages/sdknpm run testvitest run
packages/cryptonpm run testvitest run
tools/gen-datasetnpm run testvitest run
tools/run-dispatchernpm run testvitest run
tools/audit-verifynpm run testvitest run

What you could build from it

Used in lessons