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 directory | Source files |
|---|---|
apps | 86 |
packages | 16 |
scripts | 13 |
my-video | 8 |
contracts | 5 |
services | 3 |
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.
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);- 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. - Line 880
token::transfer(: An SPL token transfer through the Token Program. - Line 881
CpiContext::new_with_signer(: Makes a CPI signed by a PDA. The signer seeds prove the program controls that address. - Line 893
emit!(DisputeResolved { market: m.key(), nullifier: d.nullifier, upheld });: Emits an Anchor event that clients can parse from the logs. - 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. - Line 900
require!(m.status == status::OUTCOME && Clock::get()?.unix_timestamp >= m.outcome_end, Bis: Reads on-chain time from the Clock sysvar.
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).- 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. - 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.
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";- Line 4
* pnpm --filter @bisik/scripts seed # setup + markets + anonymous stakes: Touches staking state: the amount locked and when it was locked. - 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.
| Directory | Command | Runs |
|---|---|---|
. | npm run build | pnpm -r --filter=!./contracts run build |
. | npm run test | pnpm -r --filter=!./contracts run test |
packages/sdk | npm run build | tsc -p . && mkdir -p dist/idl && cp src/idl/bisik.json dist/idl/bisik.json |
packages/shared | npm run build | tsc -p . |
packages/shared | npm run test | tsx --test src/*.test.ts |
packages/veritas | npm run build | tsc -p . |
packages/veritas | npm run test | tsx --test src/*.test.ts |
packages/zk | npm run build | tsc -p . |
packages/zk | npm run test | tsx --test src/*.test.ts |
services/keeper | npm run start | tsx src/index.ts |
services/keeper | npm run test | tsx --test src/*.test.ts |
my-video | npm run dev | remotion studio |
my-video | npm run build | remotion bundle |
my-video | npm run lint | eslint src && tsc |
apps/web | npm run dev | vite --host 127.0.0.1 |
apps/web | npm run build | tsc --noEmit && vite build |
What you could build from it
- Fork the SuperStack copy and extend it within the Other gaps listed on the idea page.
- Learn the pattern first: Program Derived Addresses (PDAs)
- Learn the pattern first: Cross-Program Invocations (CPIs)