Rules
VRE commits binary W3O1 artifacts on-chain. The public input object is compiled into one of three currently active artifact families:
| Field | Type | Meaning |
|---|---|---|
| W3O1 v1 | binary | Weighted-random single-winner artifacts. |
| W3O1 v2 | binary | Weighted-random multi-winner artifacts with ordered outcome_ids. |
| W3O1 v3 | binary | Native formula artifacts: weighted_random, rank_desc, rank_asc, first_n, closest_to. |
| runtime_id | bytes16 / hex | Committed runtime identifier emitted in replay output. |
| compiled_artifact_hash | sha256 hex | Canonical hash of the compiled bytes bound before resolution. |
| outcome_ids | string[] | Selected outputs in deterministic order. Single-winner flows also expose outcome_id. |
Input Schema
The human-facing config stays JSON, but the serialized on-chain contract is W3O1. Public API inputs differ by formula and artifact version.
Determinism
The kernel is a pure mapping f(seed, artifact) → outcome_ids. Three guarantees:
- Referential transparency. Same inputs always yield the same output, forever.
- No hidden state. Replay reads only public RPC data plus the committed W3O1 bytes.
- Platform-neutral. Browser, Node, and on-chain logic agree on weights, scores, stable order, and targets.
W3O1 v3 adds deterministic formulas without changing replay semantics: the verifier still reconstructs the exact committed bytes and compares replay output with the resolved transaction.
Replay Process
Given a transaction signature, the verifier performs:
- Fetch the transaction from any Solana RPC endpoint.
- Confirm it invokes the VRE program and is a resolve instruction.
- Extract runtime_id, compiled_artifact_hash, resolution seed, and claimed outputs.
- Fetch the referenced artifact-binding history; confirm the artifact was committed before resolution.
- Re-hash the compiled W3O1 bytes and confirm they match the committed artifact hash.
- Run f(seed, artifact) locally; compare the replayed outputs with the on-chain record.
For W3O1 v3 responses, replay additionally exposes resolution_formula, target, per-outcome score, and stable order. If all checks pass: MATCH / OK.
Canonical Program
VRE operates a canonical Solana program on devnet. Any developer can integrate against this deployed program without deploying a separate instance.
ProgramConfig
Global configuration stored in a PDA at seeds ["outcome_program_config"]. ProgramConfig admin is separate from the program upgrade authority.
| Field | Type | Description |
|---|---|---|
| admin | Pubkey | Authority allowed to update config. Current devnet value: Swig actor wallet E8wB17KxBi89Noz74eypjbcrAJXhmPeA7e7oYHZSbjzf. |
| allow_unreviewed_binding | bool | Whether unreviewed artifacts can be bound. |
| fee_lamports | u64 | Protocol fee per resolveOutcome call. Current devnet value: 0. |
| treasury | Pubkey | Recipient of protocol fees when fee_lamports > 0. Current devnet value: ESjxDsMvG2SkPpK1FdcD6Lce4RUfMM8Bvg6sfFBUsXkT. |
Operator Security
VRE separates two security concerns: who can upgrade the program and who can operate it.
| Layer | Mechanism | Address |
|---|---|---|
| Program upgrades | Single operator upgrade key on devnet. Mainnet governance (multisig / immutable / timelock) is decided separately at mainnet time. | devnet: single operator key |
| Operator signing | Swig smart wallet — delegated key scoped to VRE program with daily SOL spending cap. Master keypair kept offline. | Actor: E8wB17KxBi89Noz74eypjbcrAJXhmPeA7e7oYHZSbjzf |
Swig — why it matters
The canonical operator runs as a Swig smart wallet actor. The hot delegate key is scoped to the VRE program only and carries a daily SOL spending cap — a compromised delegate cannot drain the treasury or invoke unrelated programs. The master keypair that controls the Swig wallet is kept offline. This means every live raffle on /play is signed by a key that has no broader permissions than running VRE.
Upgrade authority (devnet)
On devnet the program upgrade authority is a single operator key — multisig governance is not used on devnet, as it added ceremony without protecting real value while the protocol iterates. Mainnet governance (multisig / immutable / timelock) is decided separately at mainnet time and is not implied by the devnet setup.
Protocol Fee
Each resolveOutcome call may collect a protocol fee from the calling operator. The transfer happens before resolution; if the operator wallet cannot pay, the transaction fails and no outcome is recorded.
Current devnet fee: 0 lamports. The value is configurable through ProgramConfig.fee_lamports by the program admin without a program upgrade.
Verification is always free: /api/replay, SDK verify, and verify.html do not require a wallet. Large platforms can deploy a dedicated instance under a partner agreement. Contact us →
Output
Every vre verify call returns a stable JSON shape. winner / replayed_winner carry the single selected address; outcome_ids carries the ordered list when outputs > 1.
Verification Reason Codes
Every verification returns a specific reason code. MATCH always carries OK. Any MISMATCH carries one of the error codes below.
| Code | Meaning |
|---|---|
| OK | All transaction, account, artifact, randomness, outcome, and effects checks passed. |
| ERR_TX_NOT_FOUND_OR_NO_LOGS | Transaction not found on RPC or its logs are unavailable. |
| ERR_PROGRAM_ID_MISMATCH | The expected program ID was not invoked, or the event came from a different program. |
| ERR_EVENT_DISCRIMINATOR_MISMATCH | Program data was present, but it did not match the expected outcome event format. |
| ERR_EVENT_NOT_FOUND_FOR_PROGRAM | No resolution event was found in logs for the requested program ID. |
| ERR_ARTIFACT_CHUNK_MISSING | One or more committed artifact chunks are missing, unreadable, or inconsistent. |
| ERR_OUTCOME_CONFIG_NOT_FOUND | The derived outcome config account is missing or cannot be decoded. |
| ERR_RESOLUTION_ACCOUNT_NOT_FOUND | The derived outcome resolution account is missing or cannot be decoded. |
| ERR_ARTIFACT_HEADER_NOT_FOUND | The approved artifact header account is missing or cannot be decoded. |
| ERR_CONFIG_HASH_MISMATCH | Config hash does not match the on-chain outcome config account. |
| ERR_RESOLUTION_HASH_MISMATCH | Resolution hash does not match the on-chain resolution account or event identity. |
| ERR_ARTIFACT_HASH_MISMATCH | Compiled artifact hash does not match the committed on-chain artifact value. |
| ERR_ARTIFACT_NOT_FINALIZED | The approved artifact account exists but was not finalized before verification. |
| ERR_ARTIFACT_STATUS_INVALID | The artifact status does not allow binding under current program config. |
| ERR_RANDOMNESS_MISMATCH | Input randomness does not match the recorded on-chain value. |
| ERR_INPUT_MISMATCH | Input lamports differ between the event, account, and replay input. |
| ERR_OUTPUT_MISMATCH | Replayed output does not match the recorded output value. |
| ERR_OUTCOME_ID_MISMATCH | Replayed outcome id does not match the recorded outcome id. |
| ERR_EFFECTS_DIGEST_MISMATCH | Effects count or effects digest does not match. |
| ERR_REPLAY_UNHANDLED | Internal error or unsupported artifact shape during replay. |
Metaplex Agent Registry
VRE is registered in the Metaplex Agent Registry as a verification service. Other agents and dApps can discover VRE through the registry and call its endpoints to verify outcomes without trusting the operator.
Agent Identity
| Name | Value |
|---|---|
| Name | VRE Outcome Verification Agent |
| Network | solana-devnet |
| Asset address | C3qM2VVxR5dyjzqEvv9qHaaUDfTDneEaJCMTKV9bxQLX |
| Mint tx | 429YX7c7…jj ↗ |
| Registration | api.metaplex.com ↗ |
Exposed services
| Type | Endpoint | Purpose |
|---|---|---|
| web | /verify | Browser-based outcome verifier |
| replay-api | /api/replay | Programmatic verification — call from any agent |
| web | /play | Live demo with active devnet signatures |
Agent-to-agent use
Any agent that selects a winner, assigns a task, or picks a DAO proposal can call POST /api/replay with the resolve transaction signature. VRE replays the outcome from public RPC and returns MATCH / OK — or an error code if the result was tampered with. No oracle, no operator trust required.
Partner API access
Partner discovery endpoints GET /api/resolutions and GET /api/participant are not part of the public SDK surface. They require a partner-issued API key in x-api-key: vresk_... and are provisioned during partner onboarding.
Missing or unknown keys return 401 Unauthorized. If partner config is absent on the host, the endpoints fail closed with 503 Partner API not configured.
Sybil-Proof Participants
VRE can optionally require a World ID 4.0 proof before a live raffle is sent on-chain. This blocks one human from entering the same action repeatedly through many wallets, while keeping the core raffle, replay semantics, and blessed signatures unchanged.
Flow
- User connects Phantom on /play.html and optionally enables Require World ID.
- Frontend fetches POST /api/world-id/rp-context and starts a World ID 4.0 request through IDKit with RP signatures.
- Backend forwards the full IDKit result to POST https://developer.world.org/api/v4/verify/{rp_id}.
- Verified nullifier is reserved in-memory before /api/live-raffle executes and is rolled back if the raffle fails before completion.
- If World ID is not configured, the existing live raffle path still works without the optional toggle.
| Env var | Meaning |
|---|---|
| WORLD_APP_ID | World app identifier (app_...) returned by the Developer Portal. |
| WORLD_RP_ID | Relying-party identifier (rp_...) used by the v4 verify endpoint. |
| WORLD_RP_SIGNING_KEY | Server-only RP signing key used to mint short-lived RP signatures. |
| WORLD_ACTION_ID | Action scope for the one-human-per-entry flow. Default: vre-raffle-entry. |
| WORLD_ENVIRONMENT | staging for simulator/testing or production for real World App traffic. |
Evidence Artifact
Public reviewer evidence for this optional integration lives in artifacts/world_id_evidence.json and records the configured app/RP IDs, action, environment, and a staging nullifier placeholder for the first simulator-backed proof.
Phantom — "Did I Win?"
Phantom is supported on the /verify page for a read-only wallet check. After connecting, the page compares the connected address against outcome_ids in the resolved artifact and shows one of three states: You won, In the draw — not selected, or Not in this draw. No transaction signing is required — Phantom is used for address read only.
Live Raffle API
POST /api/live-raffle is the single-call path for the play.html demo. The server commits, resolves, and returns a blessed transaction signature — no operator wallet required from the caller.
| Field | Type | Description |
|---|---|---|
| address | string | Caller’s Solana address. Entered in the draw pool. |
| requireWorldId | bool? | If true, a valid World ID v4 proof is required (see §9). Default: false. |
| worldId | object? | Full IDKit proof payload. Required when requireWorldId is true. |
Rate limited: one call per IP per 60 seconds. The returned sig is immediately replayable on /verify or via POST /api/replay.
SDK
verifiable-outcome-sdk is the canonical TypeScript library for building and verifying outcomes. It targets Node ≥ 18 and any modern bundler.
install
build + verify
Both functions are pure — no on-chain writes. buildArtifact runs the same deterministic kernel used by the Solana program. verifyOutcome fetches the transaction from any public RPC and replays it locally. See build.html for the full operator integration guide.
Partner API
Two discovery endpoints are gated behind a partner-issued API key. They allow external platforms to query resolution history and check participant outcomes without running their own indexer.
| Endpoint | Method | Description |
|---|---|---|
| GET /api/resolutions | GET | Returns the N most recent resolved outcomes on the canonical program. Includes signature, outcome_id, outcome_ids, participants_count, artifact_hash, commit_slot, resolve_slot. |
| GET /api/participant | GET | Returns all resolutions where ?address=<wallet> appears in outcome_ids. Useful for wallet-level "did I ever win?" lookups. |
authentication
| Key format | Storage | Provisioning |
|---|---|---|
| vresk_ prefix + 32 hex chars | Server-side config/partners.json (not committed). Never sent to the client. | Issued during partner onboarding. Contact us → |
Partner API endpoints are distinct from the public SDK surface (/api/replay, /api/live-raffle). The public endpoints are rate-limited but require no key. Partner endpoints carry higher rate limits and return richer indexer data suitable for dashboards and integrations.
Sybil detection data feed: /api/resolutions and /api/participant were built as a structured data source for sybil-detection models. A model can observe which wallets appear repeatedly across participant lists, correlate on-chain behavior with resolution outcomes, and use commit-slot vs resolution-slot timing as a signal. These endpoints are the integration point for Proof of Human Network — feeding high-quality on-chain participation data into their LLM-based sybil classifier.
POST /api/partner/draw
Submit a formula-driven participant list and receive a verifiable on-chain transaction signature. The draw runs against the canonical devnet program using the operator wallet. Requires "draw_enabled": true in the partner config entry.
| Field | Type | Required | Description |
|---|---|---|---|
| formula | string | Yes | One of weighted_random, rank_desc, rank_asc, first_n, closest_to. |
| participants | object[] | Yes | 2–100 unique participant objects. Each item must contain id; score and weight depend on the selected formula. |
| winners_count | integer | No | Number of winners to select (1–10). Defaults to 1. Must be ≤ participants.length. |
| target | integer | No* | Required only for closest_to. Signed safe integer, usually a pre-scaled score target. |
| label | string | No | Human-readable label for the draw (max 80 chars). Auto-generated if omitted. |
| use_case | string | No | One of raffle, airdrop, competition. Informational only. |
| Response field | Type | Description |
|---|---|---|
| ok | boolean | true on success. |
| signature | string | Solana transaction signature of the resolution tx. |
| outcome_id | string | Primary selected participant id. |
| outcome_ids | string[] | All selected participant ids (length = winners_count). |
| replay_url | string | Public verifier URL for independent replay. |
| artifact_slot | number | null | Slot when the artifact was committed on-chain (null if lookup failed). |
| resolution_slot | number | null | Slot when the resolution tx landed (null if lookup failed). |
Rate limit: one draw per partner key per 60 seconds. Exceeding the limit returns HTTP 429 with retry_after_ms.
| HTTP status | Meaning |
|---|---|
| 200 | Draw completed successfully. |
| 400 | Validation error (bad formula, bad participant ids, duplicates, invalid score / weight / target, invalid winners_count or use_case). |
| 401 | Missing or unknown API key. |
| 403 | Valid key but draw_enabled is not true for this partner. |
| 429 | Rate limit exceeded; retry after 60 s. |
| 504 | Devnet timeout; retry. |
POST /api/conditions/score — one-call scoring (public)
The fastest way to integrate: a public, no-key, off-chain endpoint for the conditions mode (parlay / prediction scoring). Send committed slips (conditions + odds) and proven facts, get back a verifiable per-entrant score S, the round ranking, per-slip commitment hashes, and the exact fc7 artifact that on-chain resolve_conditions recomputes to MATCH. Scoring is deterministic and bit-for-bit identical on-chain and off-chain. VRE proves the winner ranking; payout is pro-rata and executed by the partner — no fund custody.
Leg encoding (partner compiles market labels to these codes): op — 1=Add (totals), 2=Subtract (1x2); comparison — 0=GT, 1=LT, 2=EQ; line_x2 = round(line×2), totals only. Full-match goals: stat_key 1=P1, 2=P2. For an on-chain attestation, the same fc7 artifact is resolved via the canonical program's resolve_conditions instruction (SDK sdk/conditions.ts).
POST /api/partner/conditions/{commit, resolve} — VRE-operated on-chain (partner key)
When you want the outcome on-chain without running any keys yourself: VRE does all on-chain work with its own key. Two calls, gated by an x-api-key partner key. Live on the canonical program 6QtLot4uztCfjUuPreoiYPc3e1gH2fg6pq8hKYyvCP6B.
- commit (at slate open) — anchor the round rules on-chain before the outcome. Body: { round_id, fixtures:[{fixture_id}], entrants:[{wallet, tier, entered_at, fixture_index[], legs:[…]}] }. Returns { commitment_ref, commit_signature, committed_at_slot }. No facts yet.
- resolve (after the match) — reveal facts; VRE builds the full fc7, submits + finalizes + self-reviews + binds an OutcomeConfig + calls resolve_conditions. Body: { round_id, fixtures:[{fixture_id, event_stat_root, stats:[{stat_key, value}]}] }. Returns { signature, verify_url, winners, ranking, winning_score_sum, artifact }. Resolve checks that the rules equal the ones committed at commit (facts cannot change the rules).
The returned signature replays to MATCH at /verify?sig=… — same deterministic scoring as the off-chain endpoint, now attested on-chain. VRE proves the winner ranking; escrow and pro-rata payout stay with the partner — no fund custody.
W3O1 v3 Native Formula Layout
Formula draws are committed natively inside the artifact bytes. Old v1/v2 artifacts stay valid; v3 adds explicit formula metadata, signed scores, stable input order, and optional target support for closest_to.
| Header field | Type | Description |
|---|---|---|
| magic | bytes[4] | Always "W3O1". |
| format_version | u16 | 3 for formula-native artifacts. |
| min_input_lamports / max_input_lamports | u64 / u64 | Replay and on-chain input bounds, unchanged from v1/v2. |
| outcome_count / effect_count | u16 / u16 | Outcome directory and effect directory lengths. |
| winners_count | u16 | Number of winners to select. |
| formula_code | u8 | 1=weighted_random, 2=rank_desc, 3=rank_asc, 4=first_n, 5=closest_to. |
| reserved | bytes[5] | Must be zero. |
| target_score | i64 | Used by closest_to; 0 otherwise. |
| Outcome field | Type | Description |
|---|---|---|
| outcome_id_len | u8 | Length of the canonical printable-ASCII id. |
| outcome_id | bytes[64] | Participant id padded with zeroes. |
| weight | u32 | Weighted-random weight. For deterministic formulas current API writes 1. |
| score | i64 | Signed score for ranking / closest formulas; 0 when unused. |
| order | u16 | Stable input order for first_n and all deterministic tie-breaks. |
| first_effect_index / effect_count | u16 / u16 | Effect slice for this outcome. |
Formula rules: rank_desc sorts by score desc, rank_asc by score asc, first_n by order asc, and closest_to by abs(score-target) asc. All deterministic ties break by order asc.
Use Cases & Integrations
Real-world patterns that map directly to W3O1 formulas. Each use case commits rules before resolution — anyone can replay from the transaction signature and confirm the outcome.
| Use case | Formula | How it works |
|---|---|---|
| Raffle / NFT drop | weighted_random | Each ticket holder is a participant with weight equal to their ticket count. The artifact commits weights before the draw — no backend can adjust probabilities after the list is published. |
| Trading competition | rank_desc | Participants are registered with their final PnL as score. Top-N are selected deterministically. Anyone verifies the leaderboard is correct. |
| Prediction market / oracle contest | closest_to | Participants submit predicted values. The target (e.g. actual price or temperature) is committed alongside scores. Winners are those closest to the target — provably, not just claimed. |
| Airdrop (first-come) | first_n | Participants are ordered by registration timestamp encoded in order. First N wallets receive the drop. Order is locked on-chain before snapshot. |
| Pack break / loot drop | weighted_random | Each slot in a card pack or loot pool is a weighted outcome. The full slot list and weights are committed before the break — viewers can verify no slot was swapped after the stream started. |
| Lowest-bid contest | rank_asc | Participants submit bids or scores; the lowest value wins. Scores are locked in the artifact — no late entries or score adjustments possible after commit. |
Sponsor integrations
| Sponsor | Role | Integration |
|---|---|---|
| Swig | Operator | Delegated operator key scoped to VRE program with daily SOL cap — master keypair kept offline |
| Metaplex Agent Registry | Agent | VRE registered as verifiable-outcome agent — discoverable by other agents and dApps |
| World ID | Sybil resistance | World ID 4.0 proof gating — one wallet per human before raffle entry (pending World App approval) |
Live integrations
| Project | Use case | Integration |
|---|---|---|
| Proof of Human | Sybil detection data feed | /api/resolutions + /api/participant — outcome data feeds into PoH LLM sybil classifier |
| NanoCommando | Game leaderboard verification | Partner Draw API — rank_desc pre-commitment for GHOST tier leaderboard (planned) |
| GAS Grading | Trading card giveaways & pack breaks | Partner Draw API — weighted_random draws and slot allocation (planned) |
| 01 Pilot | Agent bounty payout verification | Partner Draw API — pre-committed task criteria before payout selection (planned) |
| UZPROOF | Sybil-filter + verifiable selection | UZPROOF filters wallets → VRE selects winner on-chain — end-to-end sybil-proof draw (planned) |
| AlphaDex | Trading competition leaderboard | Partner Draw API — rank_desc leaderboard pre-commitment (planned) |
| Zaebis.xyz | Price prediction contests | Partner Draw API — closest_to outcomes resolved on-chain (planned) |
| BharatFeed | Equities leaderboard | Partner Draw API — rank_desc leaderboard resolution (planned) |
Resolution Paths & Versions
The protocol carries several resolution paths, all canonical on the one devnet program 6QtLot…. Replay-by-signature stays the default; the others are canonical alternatives selected per draw. Default entropy is SlotHashes — Unicorn-G is opt-in. On 2026-06-25 the whole protocol was promoted to this single canonical program (no separate isolated program).
| Version | Path | Task | Status |
|---|---|---|---|
| v1.3.2 | global-Ω resolve / replay-by-signature | — | canonical · default |
| v1.4.0 | Sortition-by-Claim | PROTOCOL-INFRA-011 | canonical |
| v1.4.1 | Sortition economics (fee layer) | PROTOCOL-INFRA-013 | canonical |
| B8 | Unicorn-G entropy source | PROTOCOL-INFRA-014-B8 | canonical · opt-in |
global-Ω resolve — two-phase settle (v1.3.x)
The default path, and the biggest change after the hackathon. Earlier single-phase rng_v2 resolutions (standard 1.2.1) were replaced by the v1.3.2 two-phase settle, which separates determining the outcome from recording it:
- prepare (prepare_rng_v2) — the operator opens a draw, posts a stake, and commits the target future slots.
- seal (seal_randomness, permissionless) — once the target slot window opens, anyone may seal. The outcome is determined the moment this lands, from future SlotHashes-derived entropy; the sealer earns a bounty. Validator slot rotation cannot abort an open draw.
- attest (attest_winners, allowlisted operator / attester) — records the official OutcomeResolution, reveals the operator secret for audit, charges the snapshotted protocol fee, and refunds the stake.
- expire (expire_rng_v2, permissionless) — a prepared-but-never-sealed draw refunds the stake to the operator and slashes the bounty to the protocol treasury (anti-regrind: every roll costs a bounty).
Solves. Producer last-look / last-revealer bias — the outcome is fixed by future SlotHashes unknown at prepare time — and abort resistance: permissionless seal plus expire-slash make aborting a disliked draw costly, not free. This is the "unpredictable + unabortable" guarantee.
Use case. A single global winner (global-Ω) where the operator must be unable to re-roll or abort: raffles, airdrops, and prize draws run by an untrusted operator. Note: single-phase resolve_outcome* executes the SOL transfer directly; two-phase (seal → attest) and sortition are attestation-only (they prove the winner; payout is a separate step).
Sortition-by-Claim (v1.4.0)
A commit-reveal ticket draw. Entrants register a commitment sha256(secret ‖ ticket_id ‖ draw_id) before a deadline; the draw seals against three future SlotHashes-derived slots to fix omega; each entrant self-claims by revealing secret and wins iff sha256(secret ‖ omega) < threshold.
- Lifecycle. create → register → seal → claim; claim costs under 10k CU.
- Coverage. 5/5 negative cases pass.
- Distribution. 200 draws · 100 tickets · expected 10 winners → observed mean 9.7, variance 8.76 (binomial mean 10, variance 9).
Solves. Scale and operator cost. Winners self-claim, so the operator never pays per-winner compute or transactions; the future-slot seal keeps the draw unpredictable and unabortable at any entrant count.
Use case. Large draws — thousands of entrants — where computing or paying out every winner on-chain from the operator side is too expensive: token airdrops, whitelist lotteries, mass reward selection.
Sortition economics (v1.4.1)
An optional fee layer on a sortition draw, byte-compatible with 1.4.0 draws (fee fields 0 = disabled). The fee_mode bitflags select a flat entry_fee_lamports charged at register and/or a close_skim_bps skim taken on close; the fields are carved from previously reserved bytes.
- Rent conservation. close_split(rent, skim_bps) guarantees refund + skim == rent by construction, into a dedicated treasury.
- Coverage. positive path OK; 9/9 negative cases pass.
- CU. register (paid) 18,096 · init economics 5,234 · close 9,643 · sweep(2) 18,459.
Solves. Monetization without custody. An entry fee and/or a close-skim let an operator or partner earn from a draw while rent is conserved (refund + skim == rent) and funds route to a dedicated treasury — no pooled prize custody by the protocol.
Use case. Recurring / daily draws run by a partner who wants a revenue share. Byte-compatible with 1.4.0, so an existing sortition draw opts in with fee fields set (or stays free with fields 0).
Unicorn-G entropy source (B8) — opt-in
An alternative global-Ω entropy source: a VDF output y verified on-chain via an embedded Groth16 verifier and bound to the resolution commit. Default entropy stays SlotHashes; Unicorn-G is opt-in and relies on a Groth16 trusted setup (devnet RSA modulus) — a multi-party ceremony is the path to a stronger setup before any mainnet use.
- Seal. integrated on-chain Groth16 verify + commit binding: 247,476 CU. Attest: 61,466 CU.
- Rejection. a wrong proof fails as InvalidUnicornGProof (error 6035), simulation 143,069 CU.
- Localnet e2e. seal 209,226 CU · prover wall 37.4 s · peak RSS 4.3 GB · tampered y rejected.
Solves. Residual entropy bias. SlotHashes alone still leaves a validator with some last-revealer influence over the seed; a VDF output verified on-chain removes it — even a colluding operator and validators cannot bias the outcome, only refuse to produce it.
Use case. High-stakes global-Ω single-winner draws where SlotHashes-level entropy is not strong enough and cryptographic unbiasability is required. Opt-in, because it carries a trusted-setup dependency and a heavier off-chain prover.
Full history and measured numbers live in CHANGELOG.md; the reviewer-facing evidence bundle is artifacts/public_evidence_summary.json. Mainnet is a separate, later effort; these statuses describe the canonical devnet protocol.