W3O1 v1-v3 · technical reference

Specification

Technical reference for on-chain proof of who won: committed W3O1 rules, replay semantics, operator security, and public API surface.

W3O1 v1-v3 solana devnet SHA-256 ed25519 deterministic replay
01

Rules

VRE commits binary W3O1 artifacts on-chain. The public input object is compiled into one of three currently active artifact families:

FieldTypeMeaning
W3O1 v1binaryWeighted-random single-winner artifacts.
W3O1 v2binaryWeighted-random multi-winner artifacts with ordered outcome_ids.
W3O1 v3binaryNative formula artifacts: weighted_random, rank_desc, rank_asc, first_n, closest_to.
runtime_idbytes16 / hexCommitted runtime identifier emitted in replay output.
compiled_artifact_hashsha256 hexCanonical hash of the compiled bytes bound before resolution.
outcome_idsstring[]Selected outputs in deterministic order. Single-winner flows also expose outcome_id.
02

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.

formula-config.json
{ "formula": "closest_to", "target": 22450, "winners_count": 2, "participants": [ { "id": "alice", "score": 22300 }, { "id": "bob", "score": 22610 }, { "id": "carol", "score": 22480 } ] }
03

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.

04

Replay Process

Given a transaction signature, the verifier performs:

  1. Fetch the transaction from any Solana RPC endpoint.
  2. Confirm it invokes the VRE program and is a resolve instruction.
  3. Extract runtime_id, compiled_artifact_hash, resolution seed, and claimed outputs.
  4. Fetch the referenced artifact-binding history; confirm the artifact was committed before resolution.
  5. Re-hash the compiled W3O1 bytes and confirm they match the committed artifact hash.
  6. 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.

05

Canonical Program

VRE operates a canonical Solana program on devnet. Any developer can integrate against this deployed program without deploying a separate instance.

Program ID
6QtLot4uztCfjUuPreoiYPc3e1gH2fg6pq8hKYyvCP6B
Cluster
Solana devnet (mainnet pending)
Upgrade authority
Single operator key (devnet). Mainnet governance decided separately.

ProgramConfig

Global configuration stored in a PDA at seeds ["outcome_program_config"]. ProgramConfig admin is separate from the program upgrade authority.

FieldTypeDescription
adminPubkeyAuthority allowed to update config. Current devnet value: Swig actor wallet E8wB17KxBi89Noz74eypjbcrAJXhmPeA7e7oYHZSbjzf.
allow_unreviewed_bindingboolWhether unreviewed artifacts can be bound.
fee_lamportsu64Protocol fee per resolveOutcome call. Current devnet value: 0.
treasuryPubkeyRecipient 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.

LayerMechanismAddress
Program upgradesSingle operator upgrade key on devnet. Mainnet governance (multisig / immutable / timelock) is decided separately at mainnet time.devnet: single operator key
Operator signingSwig 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 →

06

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.

response.json — single winner
{ "status": "MATCH", "code": "OK", "signature": "5KJp…9vW2", "cluster": "devnet", "commit_slot": 455663125, "resolve_slot": 455693113, "artifact_hash": "0x14f195…b4d8d", "winner": "7FHkp…3GnV", "replayed_winner": "7FHkp…3GnV", "elapsed_ms": 248 }
response.json — multi-winner (outputs: 3)
{ "status": "MATCH", "code": "OK", "signature": "9XAr…mQ3k", "winner": "7FHkp…3GnV", "outcome_ids": ["7FHkp…3GnV", "AkB2…vR9t", "9PLm…jJ1w"], "replayed_winner": "7FHkp…3GnV", "elapsed_ms": 261 }
07

Verification Reason Codes

Every verification returns a specific reason code. MATCH always carries OK. Any MISMATCH carries one of the error codes below.

CodeMeaning
OKAll transaction, account, artifact, randomness, outcome, and effects checks passed.
ERR_TX_NOT_FOUND_OR_NO_LOGSTransaction not found on RPC or its logs are unavailable.
ERR_PROGRAM_ID_MISMATCHThe expected program ID was not invoked, or the event came from a different program.
ERR_EVENT_DISCRIMINATOR_MISMATCHProgram data was present, but it did not match the expected outcome event format.
ERR_EVENT_NOT_FOUND_FOR_PROGRAMNo resolution event was found in logs for the requested program ID.
ERR_ARTIFACT_CHUNK_MISSINGOne or more committed artifact chunks are missing, unreadable, or inconsistent.
ERR_OUTCOME_CONFIG_NOT_FOUNDThe derived outcome config account is missing or cannot be decoded.
ERR_RESOLUTION_ACCOUNT_NOT_FOUNDThe derived outcome resolution account is missing or cannot be decoded.
ERR_ARTIFACT_HEADER_NOT_FOUNDThe approved artifact header account is missing or cannot be decoded.
ERR_CONFIG_HASH_MISMATCHConfig hash does not match the on-chain outcome config account.
ERR_RESOLUTION_HASH_MISMATCHResolution hash does not match the on-chain resolution account or event identity.
ERR_ARTIFACT_HASH_MISMATCHCompiled artifact hash does not match the committed on-chain artifact value.
ERR_ARTIFACT_NOT_FINALIZEDThe approved artifact account exists but was not finalized before verification.
ERR_ARTIFACT_STATUS_INVALIDThe artifact status does not allow binding under current program config.
ERR_RANDOMNESS_MISMATCHInput randomness does not match the recorded on-chain value.
ERR_INPUT_MISMATCHInput lamports differ between the event, account, and replay input.
ERR_OUTPUT_MISMATCHReplayed output does not match the recorded output value.
ERR_OUTCOME_ID_MISMATCHReplayed outcome id does not match the recorded outcome id.
ERR_EFFECTS_DIGEST_MISMATCHEffects count or effects digest does not match.
ERR_REPLAY_UNHANDLEDInternal error or unsupported artifact shape during replay.

Full reference on GitHub →

08

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

NameValue
NameVRE Outcome Verification Agent
Networksolana-devnet
Asset addressC3qM2VVxR5dyjzqEvv9qHaaUDfTDneEaJCMTKV9bxQLX
Mint tx429YX7c7…jj ↗
Registrationapi.metaplex.com ↗

Exposed services

TypeEndpointPurpose
web/verifyBrowser-based outcome verifier
replay-api/api/replayProgrammatic verification — call from any agent
web/playLive 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.

# Any agent verifies a VRE outcome curl -s https://verifiableoutcome.online/api/replay \ -H "content-type: application/json" \ -d '{"signature":"<resolve_tx_sig>","programId":"6QtLot4uztCfjUuPreoiYPc3e1gH2fg6pq8hKYyvCP6B"}' → { "ok": true, "replay": { "verification_result": "MATCH", "verification_reason": "OK", … } }

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.

09

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

  1. User connects Phantom on /play.html and optionally enables Require World ID.
  2. Frontend fetches POST /api/world-id/rp-context and starts a World ID 4.0 request through IDKit with RP signatures.
  3. Backend forwards the full IDKit result to POST https://developer.world.org/api/v4/verify/{rp_id}.
  4. Verified nullifier is reserved in-memory before /api/live-raffle executes and is rolled back if the raffle fails before completion.
  5. If World ID is not configured, the existing live raffle path still works without the optional toggle.
Env varMeaning
WORLD_APP_IDWorld app identifier (app_...) returned by the Developer Portal.
WORLD_RP_IDRelying-party identifier (rp_...) used by the v4 verify endpoint.
WORLD_RP_SIGNING_KEYServer-only RP signing key used to mint short-lived RP signatures.
WORLD_ACTION_IDAction scope for the one-human-per-entry flow. Default: vre-raffle-entry.
WORLD_ENVIRONMENTstaging 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.

10

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.

FieldTypeDescription
addressstringCaller’s Solana address. Entered in the draw pool.
requireWorldIdbool?If true, a valid World ID v4 proof is required (see §9). Default: false.
worldIdobject?Full IDKit proof payload. Required when requireWorldId is true.
request / response
# Enter the live draw pool curl -s https://verifiableoutcome.online/api/live-raffle \ -H "content-type: application/json" \ -d '{"address":"<your-wallet>"}' → { "ok": true, "sig": "5KJp…9vW2", "outcome": "<winner-address>", "outcome_id": "<winner-address>", "outcome_ids": ["<w1>", "<w2>", …] }

Rate limited: one call per IP per 60 seconds. The returned sig is immediately replayable on /verify or via POST /api/replay.

11

SDK

verifiable-outcome-sdk is the canonical TypeScript library for building and verifying outcomes. It targets Node ≥ 18 and any modern bundler.

install

npm install verifiable-outcome-sdk # v0.3.0

build + verify

import { buildArtifact, verifyOutcome } from "verifiable-outcome-sdk"; // Compile a ruleset into an artifact hash const artifact = await buildArtifact({ version: "1.0", mode: "raffle", participants: ["Alice", "Bob", "Carol"], weights: [1, 1, 1], }); // → { artifact_hash: "0x…", … } // Verify a resolved transaction const result = await verifyOutcome({ signature: "5KJp…9vW2", programId: "6QtLot4uztCfjUuPreoiYPc3e1gH2fg6pq8hKYyvCP6B", }); // → { status: "MATCH", code: "OK", winner: "…", … }

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.

12

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.

EndpointMethodDescription
GET /api/resolutionsGETReturns 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/participantGETReturns all resolutions where ?address=<wallet> appears in outcome_ids. Useful for wallet-level "did I ever win?" lookups.

authentication

# All partner endpoints require x-api-key header curl https://verifiableoutcome.online/api/resolutions \ -H "x-api-key: vresk_<32-hex-chars>" # Without a key: 401 Unauthorized # Config absent on host: 503 Partner API not configured
Key formatStorageProvisioning
vresk_ prefix + 32 hex charsServer-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.

FieldTypeRequiredDescription
formulastringYesOne of weighted_random, rank_desc, rank_asc, first_n, closest_to.
participantsobject[]Yes2–100 unique participant objects. Each item must contain id; score and weight depend on the selected formula.
winners_countintegerNoNumber of winners to select (1–10). Defaults to 1. Must be ≤ participants.length.
targetintegerNo*Required only for closest_to. Signed safe integer, usually a pre-scaled score target.
labelstringNoHuman-readable label for the draw (max 80 chars). Auto-generated if omitted.
use_casestringNoOne of raffle, airdrop, competition. Informational only.
Response fieldTypeDescription
okbooleantrue on success.
signaturestringSolana transaction signature of the resolution tx.
outcome_idstringPrimary selected participant id.
outcome_idsstring[]All selected participant ids (length = winners_count).
replay_urlstringPublic verifier URL for independent replay.
artifact_slotnumber | nullSlot when the artifact was committed on-chain (null if lookup failed).
resolution_slotnumber | nullSlot 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 statusMeaning
200Draw completed successfully.
400Validation error (bad formula, bad participant ids, duplicates, invalid score / weight / target, invalid winners_count or use_case).
401Missing or unknown API key.
403Valid key but draw_enabled is not true for this partner.
429Rate limit exceeded; retry after 60 s.
504Devnet timeout; retry.
POST /api/partner/draw
curl -s -X POST https://verifiableoutcome.online/api/partner/draw \ -H "Content-Type: application/json" \ -H "x-api-key: vresk_YOUR_KEY" \ -d '{"formula":"closest_to","target":22450,"participants":[{"id":"alice","score":22449},{"id":"bob","score":22460},{"id":"carol","score":22451}],"winners_count":1,"label":"Price Prediction"}' # 200 response: { "ok": true, "signature": "5xYz...", "outcome_id": "carol", "outcome_ids": ["carol"], "replay_url": "https://verifiableoutcome.online/verify?sig=5xYz...", "artifact_slot": 340123456, "resolution_slot": 340123512 }

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.

curl — one call
curl -s -X POST https://verifiableoutcome.online/api/conditions/score \ -H "content-type: application/json" -d '{ "fixtures": [ { "fixture_id": 1, "stats": [{"stat_key":1,"value":2},{"stat_key":2,"value":0}] }, { "fixture_id": 2, "stats": [{"stat_key":1,"value":1},{"stat_key":2,"value":1}] } ], "entrants": [ { "wallet": "HvVt…UUava", "tier": 50, "entered_at": 100, "fixture_index": [0,1], "legs": [ {"stat_key_a":1,"stat_key_b":2,"op":2,"comparison":0,"odds_milli":2150}, {"stat_key_a":1,"stat_key_b":2,"op":1,"comparison":1,"line_x2":5,"odds_milli":1850} ]} ] }'
response
{ "ok": true, "formula": "conditions", "formula_code": 7, "format_version": 9, "winners_count": 1, "winning_score_sum": 39775, "ranking": [ { "rank": 1, "wallet": "HvVt…", "all_hit": true, "score": 3.9775, "score_fixed": 39775, "slip_hash": "4dc5…" } ], "artifact": { "hash": "a084be42…", "bytes": 148, "hex": "57334f31…" } }

Leg encoding (partner compiles market labels to these codes): op1=Add (totals), 2=Subtract (1x2); comparison0=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.

13

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 fieldTypeDescription
magicbytes[4]Always "W3O1".
format_versionu163 for formula-native artifacts.
min_input_lamports / max_input_lamportsu64 / u64Replay and on-chain input bounds, unchanged from v1/v2.
outcome_count / effect_countu16 / u16Outcome directory and effect directory lengths.
winners_countu16Number of winners to select.
formula_codeu81=weighted_random, 2=rank_desc, 3=rank_asc, 4=first_n, 5=closest_to.
reservedbytes[5]Must be zero.
target_scorei64Used by closest_to; 0 otherwise.
Outcome fieldTypeDescription
outcome_id_lenu8Length of the canonical printable-ASCII id.
outcome_idbytes[64]Participant id padded with zeroes.
weightu32Weighted-random weight. For deterministic formulas current API writes 1.
scorei64Signed score for ranking / closest formulas; 0 when unused.
orderu16Stable input order for first_n and all deterministic tie-breaks.
first_effect_index / effect_countu16 / u16Effect 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.

14

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 caseFormulaHow 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

SponsorRoleIntegration
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

ProjectUse caseIntegration
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)
15

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).

VersionPathTaskStatus
v1.3.2global-Ω resolve / replay-by-signaturecanonical · default
v1.4.0Sortition-by-ClaimPROTOCOL-INFRA-011canonical
v1.4.1Sortition economics (fee layer)PROTOCOL-INFRA-013canonical
B8Unicorn-G entropy sourcePROTOCOL-INFRA-014-B8canonical · 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:

  1. prepare (prepare_rng_v2) — the operator opens a draw, posts a stake, and commits the target future slots.
  2. 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.
  3. 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.
  4. 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.