Skip to main content
ExACup

Provably fair

Safety & Fairness

Your trust is our priority. Every outcome on ExA Cup is random, resistant to tampering, and open to verification by anyone. We commit to each result before you play and reveal the proof afterwards, so you never have to take our word for it.

Verify an open

Paste the values from your pack-opening history (dashboard, Wallet tab) and recompute the ticket right here in your browser. The server seed is revealed once you rotate your seed pair.

Verify an open right here

Paste the client seed, server seed and nonce from your opening history (dashboard, Wallet tab) and recompute the ticket in your browser. Add the seed hash and ticket number to check them too. Nothing is sent to our servers

How we ensure fairness

Single pack opens

We combine a secret server seed, your client seed, and a nonce into one string, hash it with SHA-512, and normalize it to a ticket number between 1 and 1,000,000. That ticket falls inside exactly one item's published range, which decides what you win. Pass the same three inputs into our getTicketNumber function and you reproduce the result yourself.

Terms & definitions

Ticket number

An integer between 1 and 1,000,000 produced from the client seed, server seed, and nonce. It looks up the resulting item by that item's ticket range, shown in the pack details.

Client seed

A string known to you before a result is generated. You can rotate it from your wallet fairness panel before future pack opens.

Server seed

A secret string our servers generate. We show you its SHA-512 hash before any purchase and reveal the raw seed after, so you can re-hash it and confirm it matches what you were shown.

Nonce

An auto-incrementing number that gives a unique result when the server and client seeds stay the same, as when opening several packs in one purchase.

Reference implementation

import { createHash } from "crypto";

// 1..1,000,000 ticket from your client seed + our server seed + a nonce
export const sha512 = (v: string) =>
  createHash("sha512").update(v).digest("hex");

export const combineSeeds = (
  clientSeed: string,
  serverSeed: string,
  nonce: number,
) => sha512(`${clientSeed}:${serverSeed}:${nonce}`);

export const getTicketNumber = (hash: string) => {
  const hashInt = BigInt("0x" + hash);
  const maxInt = BigInt(1_000_000);
  return Number((hashInt % maxInt) + BigInt(1));
};