This repository contains two protocol layers:
Zoltar: the forkable oracle base layerAugur Statoblast: the prediction-market application layer built on top of Zoltar
The codebase is split into these main areas:
solidity/contains contracts, protocol test support, tests, and generated contract artifactsui/contains the Preact frontend, organized by application shell, feature, and protocol-client boundariesshared/contains runtime-neutral TypeScript used by Solidity tooling and the UIdocs/contains the published protocol documentationscripts/contains repository-wide build, validation, and test orchestration
Inside ui/ts, route-specific code belongs under features/<domain>, cross-feature UI primitives remain in components, application composition belongs in app, and contract reads and writes belong in protocol.
Protocol documentation lives in docs/:
- Security model — normative guarantees, accepted economic assumptions, loss-allocation policies, and residual risks
- Security-review classification — audit orientation for intentionally unbounded oracle notional, permissionless paid forks, and paid rolling disputes
- Start here guide
The security-review classification distinguishes excluded guarantees from
vulnerabilities. It also identifies the
conditions that would turn each accepted design property into an implementation
defect or a deployment-blocking economic risk. The invariant catalog owns the
current requirement, status, and evidence for
EXT-05 recursive-fork gas behavior.
Deterministic deployment outputs live in
docs/mainnet-deployment-addresses.json.
The repo keeps that file as generated source-of-truth data instead of maintaining
a separate prose page for the same addresses.
- Bun 1.3+
- Foundry
anvilfor local chain work
On a fresh checkout, start with the root dependency install:
bun install --frozen-lockfileThen run the full bootstrap:
bun run setupInstall anvil if it is not already available:
bun run install:anvilImportant:
bun run setupis the fastest way to get to a working repo after the root install.- Standalone commands like
bun tsc,bun run tsc, andbun run testassume the root dependencies are already installed. - If you skip the initial
bun install --frozen-lockfile, fresh checkouts can fail with missing packages such asbun-types.
After completing Setup, start a local chain and launch the app:
- Start
anvil - Run
bun run app:serve
If you are iterating on the app and want rebuilds, use:
bun run app:watchThe UI read backend defaults to https://ethereum.dark.florist, but you can override it without changing code:
- Add
?rpcUrl=https://your-rpc.exampleto the app URL - Set
localStorage['zoltar.rpcUrl'] - Set
globalThis.__ZOLTAR_RPC_URL__before bootstrapping the app - Set the
ZOLTAR_RPC_URLenvironment variable for environments that injectprocess.env
The UI also supports a walletless browser-local simulation mode for manual QA. After completing Setup:
- Run
bun run app:serve - Open
http://localhost:12345/?simulate=1
This mode does not require a wallet extension or anvil. Instead, it boots a Tevm-backed in-browser chain, seeds the QA accounts with ETH, WETH, and REP, and leaves the application contracts undeployed so the UI starts on the deploy flow.
Simulation mode details:
- The activation flag is
?simulate=1 - The flag is intentionally not restricted to localhost or development builds; production deployments may expose it as a browser-local demo and manual-QA path
- Production users should treat any
?simulate=1URL as a local sandbox. Simulated balances, deployments, blocks, quotes, and transactions are local to the browser and are not evidence of mainnet state. - The default seeded scenario is
?simulate=1&simScenario=baseline - Supported seeded scenarios are
simScenario=baseline,simScenario=deployed,simScenario=security-pool,simScenario=securitypoolx2, andsimScenario=securitypoolx2-auction - The yellow simulation banner exposes developer-only controls for account switching, reset, block mining, time travel, blockchain time, block count, transaction count, and artificial transaction receipt delay
- Uniswap-backed REP pricing is intentionally disabled in simulation mode, so quote-dependent UI paths degrade instead of using mainnet liquidity
- Production quote-dependent flows rely on live RPC data and available Uniswap liquidity. If a quote is stale, unavailable, or unsupported, affected actions should remain blocked or degraded rather than falling back to simulated prices.
- The simulation chain is ephemeral and exists only in the current browser tab session
Run the full app in development mode. This includes contract generation and the frontend build pipeline:
bun run app:serveWatch and rebuild the full app pipeline:
bun run app:watchBuild the full app:
bun run app:buildRegenerate contract bindings and UI vendor assets:
bun run generateCompile the Solidity contracts:
bun run compile-contractsRun the full test suite:
bun run testRun the launch-focused fork, auction, and exit invariant gate:
bun run test:launch-invariantsRun coverage across every canonically discovered TypeScript test:
bun run coverageRun full coverage, including the slow Solidity bytecode trace phase:
bun run coverage:fullType-check the TypeScript code:
bun run tscFormat the codebase:
bun run formatRun linting:
bun run lintAuto-fix lint issues:
bun run lint:fixRun dead-code analysis:
bun run knipAuto-fix dead-code findings:
bun run knip:fixMeasure Solidity gas costs:
bun run gas-costsBy default, gas-costs starts an isolated Anvil node. To measure against an existing local node instead, start Anvil in one terminal:
anvil --host 127.0.0.1 --port 8545 --chain-id 1 --block-base-fee-per-gas 0 --gas-price 0 --no-priority-feeThen run gas-costs against it from another terminal:
ANVIL_RPC=http://127.0.0.1:8545 bun run gas-costsUse ANVIL_RPC=http://host.docker.internal:8545 bun run gas-costs when the command runs from a container that reaches the host through Docker routing.
bun run tscis a pure typecheck for the app TypeScript, the Solidity-side TypeScript utilities, and the Bun build/dev scripts. It does not regenerate shared assets or vendor output.bun run testruns the TypeScript check first, then executes the test suite.bun run test:launch-invariantsis the targeted pre-release gate for adversarial fork, truth-auction, unresolved escalation carry, and auction edge-case invariants.bun run coverageruns every canonically discovered TypeScript test, reports weighted coverage for UI, shared, and tooling source, counts statically identified executable lines and functions in unloaded source as zero-hit coverage, and checks product TypeScript from theorigin/mainmerge base through committed, staged, unstaged, and untracked task changes. SetCOVERAGE_BASE_REFor pass--base-refto the reporter to use another comparison ref. Usebun run coverage:fullto enforce the same policy with the slower Solidity bytecode trace phase.- The legacy
ui:*commands still exist as compatibility aliases, butapp:*names are the clearer entrypoints because they run more than frontend-only work. - The repo uses exact dependency versions for reproducible installs.