The draw: snapshot, VRF, payout
Sunday, minute by minute
Why ORAO VRF
Without a program of our own, the draw uses a public verifiable random function. ORAO VRF on Solana lets any wallet request randomness for a 32-byte seed; its oracles fulfil the request with a value and signatures stored on chain in the request account. Seeding it with the frozen list hash ties the randomness to the list: neither can be chosen after the other. If ORAO has not fulfilled within 15 minutes, the keeper uses Switchboard On-Demand randomness instead and says so in the vrf Memo.
Picking the ticket
Tickets are kept in thousandths so the sums are integers. The canonical list is every wallet with tickets, sorted by address, one address:tickets line each. The winning ticket is the first 16 bytes of the randomness, read as a big-endian integer, modulo the total. Walking the list and adding each wallet's tickets, the first wallet whose running sum passes the winning ticket wins.
Check a draw yourself
import { createHash } from "node:crypto";
const list = await (await fetch(WEEK_FILE_URL)).json(); // from /draws
const text = Object.keys(list.tickets).sort().map(o => o + ":" + list.tickets[o]).join("\n");
console.log(createHash("sha256").update(text).digest("hex")); // = the freeze Memo hash
const r = BigInt("0x" + RANDOMNESS_HEX.slice(0, 32)); // from the VRF account
let t = r % BigInt(list.total), acc = 0n;
for (const o of Object.keys(list.tickets).sort()) { acc += BigInt(list.tickets[o]); if (t < acc) { console.log(o); break; } }The payout
The pot wallet holds only the week's SOL. In the transaction after the draw it sends its whole balance less 0.01 SOL (kept for rent and fees) to the winner, with a payout Memo. The pot starts again from the next harvest. If no wallet holds tickets, or the pot holds less than 0.05 SOL above its reserve, the pot carries over to the next Sunday.
