The 10% fee is a constant compiled into the contract. There is no function to change it, no proxy to swap the logic, and no path for anyone — including the admin — to move participant funds out. You do not have to take that on trust: it is readable on a block explorer.
A round is a function of time. There is no procedure to open one and none to close one — so there is no procedure that can fail, stall, or be withheld.
Fixed price, no cap on how many are sold. Ticket numbers are assigned in purchase order — there are no numbers to pick.
The deadline closes sales because the time arrived, not because someone called a function.
The drand round that round will use was fixed at deployment. You can read the one a year out, today.
Once that drand round publishes, anyone may submit it. The contract verifies the BLS signature on-chain before it counts.
Winning numbers are keccak256(randomness, i) mod total tickets — one jackpot plus small prizes, all drawn from tickets that were actually sold.
The winner claims against their own purchase record. There is no deadline to claim.
If a round does not reach its minimum ticket count, it refunds in full and each participant withdraws.
Settlement needs exactly one call. Because the deadline and the beacon round were both fixed in advance, the same tickets are drawn no matter who calls it or when.
Conventional lotteries hand back about half of what participants paid; the rest goes to operating organizations, retail networks and public funds. BOR has no retail network to pay, so the fee stays at 10% — and it stays there because it is a constant, not a policy.
A payout rate and a prize ceiling are easy to announce. These two are different — they hold because of what the code does not contain, and that is visible from outside.
10% is a constant in the compiled contract. No setter exists to raise it, no proxy exists to replace the logic that reads it, and no path exists for anyone to withdraw participant funds. That is a property of the deployed bytecode, not a promise about future behaviour.
Each future draw's drand round is computed from immutable values, so you can read the round a draw a year from now will use — today. It does not exist yet when sales close, which is precisely why the last buyer cannot see the result before buying.
No call sequence moves a deadline or a beacon round. Settlement is idempotent in the way that matters: whoever calls draw(), and whenever they call it, the same tickets win.
No third party has audited this contract. Saying so is the first line of the section, not a footnote at the bottom. What follows is the self-testing that exists in its place, stated so you can reproduce it.
| What was checked | Result |
|---|---|
| Test suite | 143 tests pass |
| Deep randomized runs | Fuzz 5,000 runs; invariants 512 runs × 128 depth — all pass |
| RFC 9380 conformance | Official vectors parsed straight out of the RFC (K.1, J.9.1) and passed — not transcribed by hand |
| Cross-implementation differential | The RFC, noble-curves, py_ecc and the on-chain BLS.sol agree across 82 vectors |
| Symbolic execution | halmos proves the bounds, the schedule and purchase accounting over all inputs, not sampled ones |
| On-chain beacon verification | Forged, tampered and round-mismatched signatures are all rejected |
| No funds can be stranded | After random call sequences everyone withdraws and the balance reaches zero |
| Admin parameter space | Fuzzed — no combination of admin settings locks funds |
| Payout rate in settlement | prize × 10 == sales × 9 holds in actual settlement, not just in the description |
For developers: the contract verifies the drand quicknet beacon over BLS12-381 on EIP-2537 precompiles, at roughly 166k gas per verification, and exposes the chain hash and group public key it checks against — so you can compare them with what drand publishes without reading bytecode.
Marketing copy inflates when it is repeated. This list exists so the claims above stay attached to what is actually true.