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 | Squads governance plus vault PDA execution — proposals are approved via multisig, but the live program authority is the vault address. | 8o5a6hj22sEsmpsYTN8aM4GUwKGkR1YXKsgYQdiVkbgA |
| 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.
Live Governance Upgrade
The upgrade authority is not just configured — it has been exercised on-chain. VRE was upgraded via the full Squads proposal flow on devnet: create → approve → execute.
| Step | Transaction |
|---|---|
| 1. Vault tx create | 48de7Cy… |
| 2. Proposal create | 2dqUG4E… |
| 3. Proposal approve | 5AuwR1b… |
| 4. Execute (upgrade) | 2AKZBt5… |
Deployed at slot 459318657. Upgrade authority remained 8o5a6hj22sEsmpsYTN8aM4GUwKGkR1YXKsgYQdiVkbgA throughout — the Squads vault PDA, not any individual keypair. Evidence artifact: artifacts/squads_upgrade_evidence.json.
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. |
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 |
|---|---|---|
| Squads | Multisig | Program upgrade authority held by Squads vault PDA — proposals approved via multisig, executed on-chain |
| 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 post-hackathon) |
| GAS Grading | Trading card giveaways & pack breaks | Partner Draw API — weighted_random draws and slot allocation (planned post-hackathon) |
| 01 Pilot | Agent bounty payout verification | Partner Draw API — pre-committed task criteria before payout selection (planned post-hackathon) |
| UZPROOF | Sybil-filter + verifiable selection | UZPROOF filters wallets → VRE selects winner on-chain — end-to-end sybil-proof draw (planned post-hackathon) |
| AlphaDex | Trading competition leaderboard | Partner Draw API — rank_desc leaderboard pre-commitment (planned post-hackathon) |
| Zaebis.xyz | Price prediction contests | Partner Draw API — closest_to outcomes resolved on-chain (planned post-hackathon) |
| BharatFeed | Equities leaderboard | Partner Draw API — rank_desc leaderboard resolution (planned post-hackathon) |