Snapshot Inputs
Wallet asset snapshot + active multipliers
The raffle uses deterministic, verifiable random selection. Everyone can reproduce the same winner list from the same inputs.
Tickets are based on your wallet holdings at the September 1, 2025 snapshot.
Wallet asset snapshot + active multipliers
Each signup materializes a deterministic ticket list
Draw seed comes from a published block hash
Unique winner tickets are selected and stored by rank
For each wallet, assets are grouped by type. Every type uses an active multiplier. Fractional results use round-half-up via round.
function buildTicketBreakdown(assets, multipliersByType) {
const countByType = countAssetsByType(assets)
const rows = []
for each (type, count) in countByType {
multiplier = multipliersByType[type]
rawTickets = count * multiplier
ticketsInt = round(rawTickets)
rows.push({ type, count, multiplier, rawTickets, ticketsInt })
}
totalTickets = sum(rows.ticketsInt)
return { rows, totalTickets }
}The wallet signature is hashed, then combined with each ticket index. Every ticket value is a deterministic keccak256 hash.
function materializeTickets(signature, totalTickets) {
signatureHash = keccak256(signature)
tickets = []
for (index = 0; index < totalTickets; index += 1) {
indexHex = pad32(toHex(index))
ticketSeed = concat(signatureHash, indexHex)
tickets.push(keccak256(ticketSeed))
}
return tickets
}The draw takes a published seed. Candidates are sampled by modulo index. Duplicate indexes are skipped to ensure unique winners.
function drawWinners(tickets, winnerCount, seed) {
selectedIndexes = set()
winners = []
cursor = 0
while (winners.length < winnerCount) {
value = nextUint(seed, cursor)
index = value mod tickets.length
cursor += 1
if (selectedIndexes.has(index)) continue
selectedIndexes.add(index)
winners.push(tickets[index])
}
return winners
}Anyone can re-run the same algorithm with the published draw metadata and compare regenerated winners against stored results.
function verifyDraw(storedWinners, currentTickets, drawMeta) {
regenerated = drawWinners(
currentTickets,
drawMeta.winnerCount,
drawMeta.seed
)
return storedWinners == regenerated
}