A standalone simulator that lets anyone explore how different QF calculation settings reshape matching outcomes for the ETH Security QF round.
Built by TheDAO, powered by Giveth's QF stack. Quantstamp and CertiK are featured as major round donors.
The dashboard is a single-page Next.js 16 app that runs entirely in the browser — no analytics, no per-user backend, no donor PII.
The app expects a CSV at public/data.csv. This file is fetched at runtime
by the dashboard and never leaves the browser.
The CSV must include (at minimum):
| Column | Purpose |
|---|---|
project_name |
Project display name and grouping key. |
donor_label |
Donor identifier. Accepted aliases: userId, donor_id, donor. |
amount_usd |
USD value of the donation. Accepted aliases: amountUSD, amount usd. |
currency |
Currency code, e.g. USDC, ETH, TIK. |
amount_native |
Native token amount (used to display CertiK Tokens received). |
isBadgeholder |
Boolean flag — was the donor a badge holder at donation time. |
isMatchingIncluded |
Boolean flag — does this donation pass the round's sybil / humanness check. |
Aliases are matched case-insensitively. Additional columns are ignored.
The loader refuses to start if the CSV still contains non-empty values in any of these forbidden columns:
emailvoterpayoutAddresssafeTransactionIdtokenAddressrecurringDonationId
Scrub these before exporting. If the donor column upstream is a raw wallet
address, the loader will deterministically remap it to opaque labels
(Donor 1, Donor 2, …) at load time.
npm install
npm run devOpen http://localhost:3000. If public/data.csv is missing or
mis-shaped, the error state explains what to fix.
- Algorithms: Regular QF and COCM (Markov style, harsh mode OFF).
Both are direct ports of
fundingutils.pyfrom the v6 calculator. - Badge holder boost: Off (1×) or 4× multiplier on every badge holder donation that enters the QF math.
- Sybil / humanness: Toggle between "all donors qualify" and
"QF-eligible only" (
isMatchingIncluded). - Matching limits: None · 5% per-project cap · 0.333 ETH per-project
floor · both. Cap is applied first, then the floor is funded by surplus
from non-capped projects above the floor — identical to
apply_max_first_then_surplus_floorin the Python. - Anti-gaming: 80% cap per donor per project, applied as the very first pre-processing step. Excess is discarded.
- CertiK Tokens (TIK): Own column, sortable. Plus a "TIK only" toggle to see what the distribution looks like if only TIK donations counted.
- Comparison: Side-by-side scenarios with a Δ% column per project.
src/
app/ Next 16 routing + theme
components/ Dashboard, ScenarioPanel, ResultsTable, branding, Footer
lib/
csv.ts Minimal CSV parser
loader.ts Fetch /data.csv + PII guardrail + donor abstraction
eth.ts getETHPrice() — currently returns a fixed $2150
types.ts Donation, Settings, RoundConfig, ScenarioResult
qf/
matrix.ts Sparse donation matrix
standardQf.ts Regular QF
cocm.ts COCM (Markov, harsh togglable)
matchingLimits.ts apply_max_first_then_surplus_floor port
runner.ts Pipeline orchestration
All matching math runs in the main thread. With a 120-project / 10k-donation dataset the typical end-to-end compute for COCM is well under a second on a modern laptop; the dashboard shows a "Computing…" banner while it runs.
standard_qf→standardQf— direct port (sum of sqrt minus sum).COCM (calcstyle='markov', harsh=False)→cocm— direct port with sparse optimisations for browser performance. Cluster dataframe is identified with the donation dataframe (same convention as the v6 calculator).apply_max_first_then_surplus_floor→applyMaxFirstThenSurplusFloor— byte-for-byte translation including epsilon checks and infeasibility errors.
If the cap/floor combination is infeasible the runner falls back to a no-cap, no-floor distribution and surfaces the reason as a scenario warning instead of crashing the dashboard.
npm run build then npm start. Static hosts work fine — the only runtime
requirement is that /data.csv is served alongside the bundle. Set the
getETHPrice() value in src/lib/eth.ts (currently 2150) when you want a
live feed.