Cookie Chain claims sub-second finality. CookieBench measures what that actually means β from your browser, with real transactions anyone can verify on-chain.
Live app: https://opusstudiohq-max.github.io/cookiebench/ Source: https://github.com/opusstudiohq-max/cookiebench
Cookie Chain's pitch is speed and near-zero cost: "sub-second finality", "around 1 second block times", "minimal fees". Those are the headline claims on docs.cookiechain.wtf β but until now there was no public, reproducible way to check them.
CookieBench is that check. It is a measurement instrument, not a demo: it sends real Memo transactions through the public RPC, times each commitment transition with a high-resolution clock, reads the actual fee back from transaction metadata, and lets you publish a signed scorecard on-chain so the result is independently auditable.
1. Block production is faster than documented.
Measured slot cadence (the "~1s block time" claim)
β slots advanced 18 in 6.4s
β measured slot time 357 ms
Roughly 2β3Γ faster than the documented ~1 s. Repeat measurements land in a range rather than on a single figure β 357 ms and 363 ms from one machine, 444 ms and 549 ms from a browser elsewhere in the same session β because every sample includes the observer's network round-trip. The honest claim is a range, and even the slowest sample comfortably beats the documented figure.
2. "Sub-second finality" means sub-second confirmation, not finalization.
This is the finding that matters most, and it is easy to get wrong:
sample 1: slot 23971349 confirmed -> finalized in 18.36s (was 31 slots behind)
sample 2: slot 23971382 confirmed -> finalized in 12.70s (was 32 slots behind)
sample 3: slot 23971414 confirmed -> finalized in 15.77s (was 31 slots behind)
mean confirmed -> finalized: 15.61s
mean finality depth: 31.3 slots
The confirmed head tracks the chain head within about a single slot, so confirmation is
comfortably sub-second β and confirmation is what a user actually waits for. Finalization is a
different guarantee: it waits the usual ~32-slot consensus depth, so it lands ~15 s later by
design, exactly as on Solana.
CookieBench reports both and never conflates them. An earlier draft of this tool showed a transaction "finalized" in 690 ms; that was wrong, and measuring it properly is what caught it. Reporting only the flattering half would have been the easier and less useful thing to build.
Reproduce both findings in one command each β see Verify the chain.
Opens straight into live chain state so anyone (including a reviewer with no COOK) sees real data immediately: slot, block height, epoch progress, reachable validators, Agave version, total transactions, COOK supply, and a slot time measured live from your browser.
Takes the current confirmed head and times how long the finalized head needs to reach it.
That needs nothing but public RPC reads, so every visitor sees genuinely measured finality
rather than an empty panel. Reports median, p95, fastest, mean, and consensus depth in slots.
It keeps sampling while the tab is open, and keeps the samples in the browser between visits, so the picture sharpens the longer you leave it β one measurement is an anecdote, a hundred is a distribution. Sampling pauses while the tab is hidden, because polling a chain nobody is watching is just noise. There is a checkbox to stop it and a link to forget the stored samples.
This exists specifically because the transaction lab needs COOK. Without it, anyone without a funded wallet β most first-time visitors β would see no measured data at all.
A stopwatch races each transaction to confirmation against a fixed one-second scale, so the sub-second claim is legible at a glance: the bar does not reach the end before the run is done. Finalization is shown alongside it but deliberately kept off that scale β it is a seconds-scale guarantee, and putting it on a one-second track would misrepresent it.
No wallet or COOK? Press "Watch a simulated run." It replays the timings this tool actually
measured on Cookie Chain, so the tool can be evaluated end to end without spending anything. It
is labelled simulated replay on screen, sends no transaction, and produces no scorecard β only
a real run does that. The finalization wait is compressed so the replay does not stall for 15
seconds; the figure it displays is the real measured one.
Connect a wallet, choose a run count, and each run reports:
| Milestone | What it means |
|---|---|
| Submit | Client β RPC round-trip for sendRawTransaction |
| Processed | Transaction landed in a block |
| Confirmed | Supermajority voted on the block |
| Finalized | Irreversible β waits the ~32-slot consensus depth, so ~15 s, not milliseconds |
Results are reported as median / p95 / fastest, plus the real per-transaction fee, a latency histogram, and a run-over-run trend so outliers stay visible instead of being averaged away.
Publishing a scorecard writes a Memo transaction:
cookiebench:v1 score runs=5 p50=412 p95=530 best=388 fee=5000
The scoreboard is rebuilt by reading the Memo program's transaction history straight from the chain. There is no server and no database β every row links to its transaction, so nothing has to be taken on trust.
Accuracy here is the whole point, so the choices are deliberate:
- A
finalizedblockhash is fetched, and a Memo instruction is built with your address as a signer (this is what makes a scorecard attributable). - The wallet signs but does not broadcast. Using
signAndSendTransactionwould hand submission to the wallet's own RPC β the clock would start at an unknown moment against an unknown endpoint. CookieBench usessignTransactionand broadcasts through its ownConnection, which is what makes the timing attributable to Cookie Chain. - The clock starts immediately before
sendRawTransaction. Every milestone is measured from that instant, so the numbers reflect what a user actually waits. getSignatureStatusesis polled adaptively β every 50 ms while confirmation is pending, then every 500 ms while waiting out the ~32-slot finalization depth. Polling that second phase at 50 ms would issue hundreds of pointless calls.- The fee is read from the finalized transaction's metadata β measured, never estimated.
Latency includes your network round-trip to the RPC, which is why submit is reported as its own column: subtract it to approximate pure chain time. Results depend on your physical distance to the validator set, so treat them as a real-world measurement from where you are sitting rather than a controlled lab benchmark. The tool measures latency, not throughput.
Confirmation and finalization are different claims. Confirmation is sub-second and is what a user waits for. Finalization waits the ~32-slot consensus depth and takes seconds. Any tool that reports a single "finality" number is hiding one of the two.
Mapped to the bounty's required features:
| Requirement | Where |
|---|---|
| Wallet connection (Nightly supported) | Wallet Standard detection, Nightly listed first |
| Display connected wallet address | Header badge on the Finality lab |
| Transaction execution | Every measured run + scorecard publish |
| Transaction confirmation handling | Explicit processed β confirmed β finalized polling |
| Error handling and user feedback | Typed, human-readable errors; live phase text |
| Real-time transaction status | Phase updates stream during each run |
| View application-specific data | On-chain scoreboard + per-run results table |
| Analytics / charts / dashboards | Network pulse, observer, histogram, trend series, percentiles |
| Deployed and publicly accessible | GitHub Pages (link above) |
| Open source | MIT |
Detection goes through the Solana Wallet Standard via @wallet-standard/app, which is the approach Nightly's own docs recommend. Nightly is fully supported and sorted to the top of the picker; any other Wallet-Standard-compatible Solana wallet also works.
Nightly exposes signing as standard:signTransaction while the Wallet Standard Solana spec uses solana:signTransaction β CookieBench probes both, so it works either way.
| Setting | Value |
|---|---|
| RPC | https://rpc.cookiescan.io |
| WebSocket | wss://wss.cookiescan.io |
| Native token | COOK (9 decimals) |
In Nightly, add Cookie Chain as a custom SVM network with the RPC above. You need a small COOK balance β one Memo transaction costs a single base fee (5,000 lamports = 0.000005 COOK at the time of writing).
git clone https://github.com/opusstudiohq-max/cookiebench.git
cd cookiebench
npm install
npm run devThen open the printed local URL. The network pulse works immediately; the finality lab needs a wallet.
| Command | Purpose |
|---|---|
npm run dev |
Vite dev server |
npm run build |
Type-check then production build to dist/ |
npm run preview |
Serve the production build |
npm run typecheck |
TypeScript, no emit |
npm run verify:chain |
Independently verify every chain claim in this README |
npm run verify:memo |
Simulate the exact Memo transactions the app builds, spending nothing |
npm run measure:finality |
Measure real confirmed β finalized latency; no wallet, no funds |
npm run verify:chain has zero dependencies (native fetch only), needs no wallet and no keys, and makes only public JSON-RPC reads. It checks liveness, chain state, that all five genesis programs used or referenced are executable, measures live slot cadence, and counts indexed memos:
$ npm run verify:chain
Liveness
β getHealth ok
β Agave / solana-core 4.1.2
β genesis hash 9wDaBRDgArEUpvhHxGguNkwozsZh4UpGZB9o2EoEcBB2
Chain state
β absolute slot 23,943,236
β block height 23,499,588
β epoch 55 (183236/432000 slots)
β total transactions 87,382,712
β validators reachable 4
β COOK total supply 999,999,731 COOK
Genesis programs (executable accounts)
β SPL Token TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
β Token-2022 TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb
β Associated Token Account ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL
β Token Metadata metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s
β Memo (used by CookieBench) MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr
Measured slot cadence (the "~1s block time" claim)
β slots advanced 18 in 6.4s
β measured slot time 357 ms
All checks passed.
(Numbers above captured 2026-09-08; slot and epoch values naturally advance.)
npm run verify:memo builds the exact transactions the app sends, round-trips them through
the wire format a wallet would sign, and runs them through simulateTransaction with
sigVerify: false using an existing funded account as a stand-in fee payer. Nothing is signed,
nothing is broadcast, and no balance changes:
probe: "cookiebench:v1 probe n=1"
serialized 194 bytes
simulation error none
memo program ran yes
memo text echoed yes
| Program MemoSq4... invoke [1]
| Program log: Signed by 568tU9FMksJDxjkLBjWisSA4J4C5uPH87NCCkyREwrxe
| Program log: Memo (len 24): "cookiebench:v1 probe n=1"
| Program MemoSq4... consumed 23495 of 200000 compute units
| Program MemoSq4... success
RESULT: pass
Both the probe and the scorecard shape execute cleanly against Cookie Chain.
Being precise about this matters more than sounding finished:
- Verified against the live chain: every read path (network pulse, slot cadence, scoreboard indexing), all five genesis programs, and the on-chain execution of both transaction shapes, including signer attribution and compute cost.
- Not yet exercised end-to-end: the wallet signing round-trip and live broadcast, which need a
funded COOK wallet and a browser extension. The instruction encoding underneath is what
verify:memoproves; the remaining surface is the wallet handoff.
If you run the finality lab with a funded wallet, the scoreboard will record the first real measurement published on Cookie Chain.
src/
lib/
chain.ts Cookie Chain endpoints, shared Connection, network pulse reads
wallet.ts Wallet Standard detection, connect, sign-only transaction signing
bench.ts Measurement engine, memo encoding, on-chain scoreboard reader
format.ts Latency/COOK formatting, percentiles
components/
NetworkPulse.tsx Live dashboard (no wallet required)
FinalityObserver.tsx Measured finality with no wallet required
RaceTrack.tsx Confirmation stopwatch + simulated replay
FinalityLab.tsx Wallet connect, measured runs, results, publishing
Scoreboard.tsx On-chain scorecard leaderboard
Charts.tsx Dependency-free SVG histogram, trend line, meter
scripts/
verify-chain.mjs Zero-dependency chain verification
verify-memo-tx.mjs Simulates the app's real transactions, spends nothing
measure-finality-lag.mjs Wall-clock confirmed -> finalized measurement
Design constraints, on purpose:
- Only genesis programs. CookieBench writes exclusively through the SPL Memo program, already deployed at genesis. Nothing to deploy, no custom program to trust, no upgrade authority anywhere.
- No backend. All state lives on Cookie Chain. The scoreboard is derived from chain history.
- No charting dependency. Charts are hand-rolled SVG to keep the bundle small.
- Non-custodial. CookieBench never holds funds and never asks for a private key. It builds one Memo transaction at a time and asks your wallet to sign it.
Pushing to main triggers .github/workflows/deploy.yml, which type-checks, builds, and publishes to GitHub Pages.
The Vite base must match the Pages sub-path. It defaults to /cookiebench/; override for a custom domain:
BASE_PATH=/ npm run buildMIT β see LICENSE.
Built for the Create an App on Cookie Chain bounty. Resources: Cookie Chain Β· Docs Β· Explorer Β· Nightly