Sol.College

Full lesson

Bisik

What it does

From the project README:

1. **Private reputation.** A scout proves GitHub activity with a zkTLS proof (Reclaim). The server verifies it **offchain**, so the username is never written onchain. Only a tier and a source-account nullifier hash go onchain. The scout joins an anonymous **Semaphore** group for that tier. 2. **Anonymous stake.** The scout stakes refundable USDC with a Groth16 group-membership proof, verified onchain by `groth16-solana` (~97k CU). The proof's scope is `(market, slot ≤ 3)`, so one scout gets at most 3 options per market without anyone learning who they are. The supported option is encrypted for
Original
scientivan/Bisik
SuperStack fork
Blockchains/Bisik @ 35cbcb7
Stars
0
Last push (original)
2026-10-13
Languages
TypeScript, Rust, CSS, JavaScript, HTML, Dockerfile
Detected stack
Anchorweb3.js
Categories
Other
Licence
MIT
Homepage
https://bisik.scientivan.dev

Architecture

131 source files. By extension: .ts ×78, .tsx ×43, .js ×6, .rs ×4.

Top-level directorySource files
apps86
packages16
scripts13
my-video8
contracts5
services3

On-chain programs: contracts/programs/bisik

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

scientivan/Bisik · contracts/programs/bisik/src/lib.rs L877–900 @ 35cbcb7 · MIT · original
            ctx.accounts.position.slashed = true;            let id = m.id.to_le_bytes();            let seeds: &[&[u8]] = &[MARKET_SEED, &id, &[m.bump]];            token::transfer(                CpiContext::new_with_signer(                    ctx.accounts.token_program.key(),                    Transfer {                        from: ctx.accounts.escrow.to_account_info(),                        to: ctx.accounts.charity_token.to_account_info(),                        authority: m.to_account_info(),                    },                    &[seeds],                ),                amount,            )?;        }        emit!(DisputeResolved { market: m.key(), nullifier: d.nullifier, upheld });        Ok(())    }     /// F9 step 1: reveal, per buyer, the total weight of that buyer's successful options.    pub fn compute_weights(ctx: Context<ComputeWeights>, computation_offset: u64) -> Result<()> {        let m = &mut ctx.accounts.market;        require!(m.status == status::OUTCOME && Clock::get()?.unix_timestamp >= m.outcome_end, BisikError::TooEarly);
  1. Line 879 let seeds: &[&[u8]] = &[MARKET_SEED, &id, &[m.bump]];: Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve.
  2. Line 880 token::transfer(: An SPL token transfer through the Token Program.
  3. Line 881 CpiContext::new_with_signer(: Makes a CPI signed by a PDA. The signer seeds prove the program controls that address.
  4. Line 893 emit!(DisputeResolved { market: m.key(), nullifier: d.nullifier, upheld });: Emits an Anchor event that clients can parse from the logs.
  5. Line 900 require!(m.status == status::OUTCOME && Clock::get()?.unix_timestamp >= m.outcome_end, Bis: An explicit validation that aborts the instruction with an error.
  6. Line 900 require!(m.status == status::OUTCOME && Clock::get()?.unix_timestamp >= m.outcome_end, Bis: Reads on-chain time from the Clock sysvar.
scientivan/Bisik · services/keeper/src/index.ts L157–180 @ 35cbcb7 · MIT · original
    return "settle_position";  }  return null;} /** * D6: after settlement, fold each position's hit/miss into the encrypted reputation table. * Skipped when the reputation account is not initialized (e.g. a deployment without D6). * One computation per tick to stay gentle on public RPCs. */const REP_FROM_MARKET = Number(process.env.KEEPER_REP_FROM_MARKET ?? 0); /** Returns true while settled positions of this market still await a reputation credit. */async function creditReputation(market: PublicKey, marketId: number): Promise<boolean> {  // Positions staked before the option/credit key fix cannot be decrypted correctly: skip them.  if (marketId < REP_FROM_MARKET) return false;  const rep = P.reputation();  const r: any = await program.account.reputation.fetchNullable(rep);  if (!r || !r.ready) return false;  const ps = await scan.account.position.all([{ memcmp: { offset: 8, bytes: market.toBase58() } }]);  for (const p of ps) {    if (!p.account.settled) continue;    const repCredit = P.repCredit(p.publicKey);    // `done = false` on an existing account means the MPC callback failed: retry it (init_if_needed).
  1. Line 171 // Positions staked before the option/credit key fix cannot be decrypted correctly: skip t: Touches staking state: the amount locked and when it was locked.
  2. Line 180 // `done = false` on an existing account means the MPC callback failed: retry it (init_if_: Creates the account only if it doesn't exist. Watch for re-initialisation bugs.
scientivan/Bisik · scripts/seed-demo.ts L1–24 @ 35cbcb7 · MIT · original
/** * Bisik demo seeder (task H1). All teams, scouts and reasons are fictional and labelled DEMO. * *   pnpm --filter @bisik/scripts seed            # setup + markets + anonymous stakes *   pnpm --filter @bisik/scripts seed bids <id>  # demo buyers place sealed bids (market in Auction) *   pnpm --filter @bisik/scripts seed select <id> ecosystem-a 0   # winner hides options (in rank order) *   pnpm --filter @bisik/scripts seed buyflat <id> ecosystem-c    # flat purchase of the remainder *   pnpm --filter @bisik/scripts seed claim <id> ayu 1            # scout claims to a fresh address *   pnpm --filter @bisik/scripts seed reveal <id> ecosystem-a      # D4: MPC-encrypted signal view for a buyer *   pnpm --filter @bisik/scripts seed v2init                     # existing deployment: D4/D6 comp defs + reputation *   SEED_ONLY_AUCTION=1 … seed                                    # only create the auction market * * Needs: program deployed (localnet via `arcium localnet`, or devnet), the API server running * with BISIK_DEMO=1, and the operator keypair at OPERATOR_KEYPAIR_PATH. * The keeper then drives the markets through their lifecycle. * Local demo state (buyer keys, scout identities, mint) is kept in scripts/.demo/ (gitignored). */import dotenv from "dotenv";import { fileURLToPath } from "node:url";import { homedir } from "node:os";import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";import { Connection, Keypair, PublicKey, SystemProgram, Transaction, sendAndConfirmTransaction } from "@solana/web3.js";import { createMint, getOrCreateAssociatedTokenAccount, mintTo, TOKEN_PROGRAM_ID } from "@solana/spl-token";import { ed25519 } from "@noble/curves/ed25519";
  1. Line 4 * pnpm --filter @bisik/scripts seed # setup + markets + anonymous stakes: Touches staking state: the amount locked and when it was locked.
  2. Line 22 import { Connection, Keypair, PublicKey, SystemProgram, Transaction, sendAndConfirmTransac: Submits the signed transaction to the cluster.

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 buildpnpm -r --filter=!./contracts run build
.npm run testpnpm -r --filter=!./contracts run test
packages/sdknpm run buildtsc -p . && mkdir -p dist/idl && cp src/idl/bisik.json dist/idl/bisik.json
packages/sharednpm run buildtsc -p .
packages/sharednpm run testtsx --test src/*.test.ts
packages/veritasnpm run buildtsc -p .
packages/veritasnpm run testtsx --test src/*.test.ts
packages/zknpm run buildtsc -p .
packages/zknpm run testtsx --test src/*.test.ts
services/keepernpm run starttsx src/index.ts
services/keepernpm run testtsx --test src/*.test.ts
my-videonpm run devremotion studio
my-videonpm run buildremotion bundle
my-videonpm run linteslint src && tsc
apps/webnpm run devvite --host 127.0.0.1
apps/webnpm run buildtsc --noEmit && vite build

What you could build from it

Used in lessons