Full lesson
Bakedtruth
What it does
From the project README:
On-Chain Campaigns the chain answers. Join YES or NO with SOL. Winners split the pot. No vote, no judge. Proof > Promises.
- Original
- 0x4cb-caramelo/Bakedtruth
- SuperStack fork
- Blockchains/Bakedtruth @
30b0d91 - Stars
- 0
- Last push (original)
- 2026-11-02
- Languages
- TypeScript, Rust, CSS, JavaScript, HTML, Shell
- Detected stack
- @solana/kitNext.jsPinocchioweb3.js
- Categories
- Other
- Licence
- MIT
Architecture
1292 source files. By extension: .ts ×813, .rs ×236, .js ×141, .tsx ×102.
| Top-level directory | Source files |
|---|---|
tests | 262 |
programs | 235 |
app | 226 |
services | 217 |
packages | 155 |
scripts | 129 |
prototype-lab | 65 |
.claude | 3 |
On-chain programs: programs/brot-markets, tests/programs/cpi-proxy
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/bakedtruth/. 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/brot-markets/src/events/self_cpi.rs L37–60 @ 30b0d91 · MIT · original/// Never inlined: the buffer and the CPI structures take their own stack frame instead of/// adding to the handler's, which SBF caps at 4 KiB per frame.#[inline(never)]pub fn emit<E: Event>( event: &E, event_authority: &AccountView, program: &AccountView, program_id: &Address,) -> ProgramResult { checks::event_accounts(event_authority, program, program_id)?; let mut buffer = [0u8; EVENT_BUFFER_LEN]; let data = event_data(event, &mut buffer)?; let accounts = [InstructionAccount::readonly_signer(&EVENT_AUTHORITY)]; let instruction = InstructionView { program_id, accounts: &accounts, data, }; let bump = [EVENT_AUTHORITY_BUMP]; let seeds = [Seed::from(EVENT_AUTHORITY_SEED), Seed::from(&bump)]; invoke_signed(&instruction, &[event_authority], &[Signer::from(&seeds)])} /// Writes `[EVENT_IX_TAG, E::DISCRIMINATOR, event bytes]` at the start of `buffer` and returns- Line 55
let bump = [EVENT_AUTHORITY_BUMP];: Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve. - Line 56
let seeds = [Seed::from(EVENT_AUTHORITY_SEED), Seed::from(&bump)];: Declares the PDA seeds. Anchor re-derives the address and rejects the account if it doesn't match. - Line 57
invoke_signed(&instruction, &[event_authority], &[Signer::from(&seeds)]): Makes a CPI signed by a PDA. The signer seeds prove the program controls that address.
app/features/campaign-page/recheck-commands.ts L1–24 @ 30b0d91 · MIT · original/** * Purpose: the re-check panel's commands (BR-23, "Anyone can re-check. Same account, same answer"; proposal §2.9): one * JSON-RPC request that fetches the bytes the reader reads, at the reader's offsets, through any RPC; the * Solana CLI's dump of the same account; and the SDK's `recheck(campaign, rpcUrl)` for a recorded result. * Each command names only public data: the account, the campaign and an RPC URL with no key. * Version: 0.1.0 * Sprint: 11 (site: campaign page and entry) * * Offsets follow the program's readers (programs/brot-markets/src/readers/*.rs) and the SDK's copies of them: a * `PriceUpdateV2` with Full verification has its price at byte 73; a classic mint its supply at 36 after the mint * authority's 36 bytes; a DAMM v2 pool its permanently locked liquidity at 552. A stake pool is Borsh with options, * so its field moves and the whole account is fetched; the epoch stake is a syscall, shown by `getVoteAccounts`. */import type { KindName } from "./proof"; export type Command = { label: "curl" | "Solana CLI" | "SDK"; text: string }; /** The bytes each reader reads: [offset, length], or the whole account. */export const SLICE: Record<KindName, readonly [number, number] | null> = { price: [73, 28], // price i64 · confidence u64 · exponent i32 · publish time i64 burn: [0, 44], // mint authority COption (4 + 32) · supply u64 at 36 lock: [552, 16], // permanent_lock_liquidity u128 pool: null, stake: null,- Line 10
* `PriceUpdateV2` with Full verification has its price at byte 73; a classic mint its supp: Reads a Pyth price and enforces a maximum age. - Line 11
* authority's 36 bytes; a DAMM v2 pool its permanently locked liquidity at 552. A stake po: Touches staking state: the amount locked and when it was locked.
programs/brot-markets/src/constants.rs L25–48 @ 30b0d91 · MIT · originalpub const ENTRY_SEED: &[u8] = b"entry"; /// `["join", campaign, baker, index]`: one account per join (founder decision, 2026-10-09).pub const JOIN_SEED: &[u8] = b"join";/// `["referral", referee]`: one `ReferralLink` per referee, signed once (Sprint 14).pub const REFERRAL_SEED: &[u8] = b"referral";/// `["sealed", campaign, sponsor]`: one `SealedFee` per sponsor and campaign (Sprint 15).pub const SEALED_FEE_SEED: &[u8] = b"sealed";/// The PDA that signs the program's self-CPI events (T4): `["__event_authority"]`.pub const EVENT_AUTHORITY_SEED: &[u8] = b"__event_authority"; /// The event authority of this program id, derived once and checked by a host test.pub const EVENT_AUTHORITY: Address = address!("CmNehEdy55jRh7waxt2u5vbwLwe3jmRuZXv3AHi1qGwx");/// Its canonical bump.pub const EVENT_AUTHORITY_BUMP: u8 = 254; // --- Other programs ---------------------------------------------------------------------------- /// The BPF upgradeable loader, owner of the program's ProgramData account.pub const BPF_LOADER_UPGRADEABLE_ID: Address = address!("BPFLoaderUpgradeab1e11111111111111111111111");/// The Pyth receiver whose `PriceUpdateV2` accounts the price reader trusts (upgraded Core).pub const PYTH_RECEIVER_ID: Address = address!("rec2HHDDnjLfj4kE7VyEtFA1HPGQLK33259532cRyHp");/// The Pyth push oracle that derives the sponsored price accounts: seeds `[shard u16 LE, feed_id]`.- Line 38
/// Its canonical bump.: Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve. - Line 46
/// The Pyth receiver whose `PriceUpdateV2` accounts the price reader trusts (upgraded Cor: Reads a Pyth price and enforces a maximum age.
programs/brot-markets/src/checks.rs L97–120 @ 30b0d91 · MIT · original bump: u8, program_id: &Address,) -> ProgramResult { // X0.9 pda let derived = Address::derive_address(seeds, Some(bump), program_id); require(derived == *address, BrotError::PdaMismatch)} /// At creation: the account's address is the canonical PDA of `seeds` (the highest valid bump),/// returned for storing (`PdaMismatch` otherwise). A non-canonical bump would let a second/// account exist for the same seeds and defeat the retry guard (T17).pub fn canonical_pda( account: &AccountView, seeds: &[&[u8]], program_id: &Address,) -> Result<u8, ProgramError> { let (canonical, bump) = Address::try_find_program_address(seeds, program_id).ok_or(BrotError::PdaMismatch)?; // X0.9 canonical_pda require(*account.address() == canonical, BrotError::PdaMismatch)?; Ok(bump)} /// The slot holds the System Program (`WrongSystemProgram`), before any System Program CPI.- Line 97
bump: u8,: Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve. - Line 114
Address::try_find_program_address(seeds, program_id).ok_or(BrotError::PdaMismatch)?;: Derives a PDA from seeds and the program ID and returns the address with its canonical bump.
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 | bun --filter @pred-provable/app dev |
. | npm run test | bun test tests/ app/ services/ |
. | npm run lint | prettier --check "tests/**/*.ts" "scripts/**/*.ts" "packages/**/*.ts" && bun run lint:sdk |
app | npm run dev | next dev |
app | npm run start | next start |
app | npm run build | next build |
app | npm run lint | eslint |
services/rpc | npm run start | bun src/main.ts |
services/rpc | npm run test | bun test services/rpc |
services/indexer | npm run start | bun src/main.ts |
services/indexer | npm run test | bun test services/indexer tests/indexer |
services/api | npm run start | bun src/main.ts |
services/api | npm run test | bun test services/api |
services/keeper | npm run start | bun src/main.ts |
services/keeper | npm run test | bun test services/keeper |
. | cargo build | Rust workspace 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)