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 directory | Source files |
|---|---|
apps | 79 |
tools | 61 |
packages | 51 |
programs | 32 |
encrypted-ixs | 3 |
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.
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>,- Line 305
pub authority: Signer<'info>,: Requires this account to have signed the transaction. - Line 307
seeds = [PlatformConfig::SEED],: Declares the PDA seeds. Anchor re-derives the address and rejects the account if it doesn't match. - Line 308
bump = config.bump,: Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve. - Line 309
has_one = authority,: Checks that a stored pubkey field matches the passed account. - Line 315
init,: Creates and pays for a new account. Space and payer must be specified.
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,- Line 17
pub owner: Signer<'info>,: Requires this account to have signed the transaction. - Line 20
has_one = owner @ GenoVaultError::NotDatasetOwner,: Checks that a stored pubkey field matches the passed account. - 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. - Line 22
bump = dataset.bump,: Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve. - Line 36
init,: Creates and pays for a new account. Space and payer must be specified.
programs/genovault/src/instructions/initialize.rs L1–24 @ ed59a67 · Apache-2.0 · originaluse 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.- Line 10
pub const TOKEN_2022_PROGRAM_ID: Pubkey = pubkey!("TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpP: Targets the Token-2022 program instead of the original Token Program. - Line 15
pub authority: Signer<'info>,: Requires this account to have signed the transaction. - Line 17
init,: Creates and pays for a new account. Space and payer must be specified. - Line 20
seeds = [PlatformConfig::SEED],: Declares the PDA seeds. Anchor re-derives the address and rejects the account if it doesn't match. - Line 21
bump,: Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve.
programs/genovault/src/instructions/dataset.rs L1–24 @ ed59a67 · Apache-2.0 · originaluse 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,- Line 18
pub owner: Signer<'info>,: Requires this account to have signed the transaction. - Line 20
init,: Creates and pays for a new account. Space and payer must be specified. - 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. - 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.
| Directory | Command | Runs |
|---|---|---|
. | npm run dev | pnpm -r --parallel dev |
. | npm run build | pnpm -r build |
. | npm run test | pnpm -r --parallel test |
. | npm run lint | biome check . |
apps/web | npm run dev | vite |
apps/web | npm run build | vite build |
apps/web | npm run test | vitest run |
apps/api | npm run dev | node --experimental-strip-types --watch src/server.ts |
apps/api | npm run start | node --experimental-strip-types src/server.ts |
apps/api | npm run test | vitest run |
packages/shared | npm run test | vitest run |
packages/sdk | npm run test | vitest run |
packages/crypto | npm run test | vitest run |
tools/gen-dataset | npm run test | vitest run |
tools/run-dispatcher | npm run test | vitest run |
tools/audit-verify | npm run test | vitest run |
What you could build from it
- Fork the SuperStack copy and extend it within the DeFi gaps listed on the idea page.
- Learn the pattern first: Program Derived Addresses (PDAs)
- Learn the pattern first: Cross-Program Invocations (CPIs)
- Learn the pattern first: SPL Tokens: mints, accounts and transfers