Overview
Block-Sena is an on-chain lottery in which ticket purchases, round lock, draw execution, and prize distribution are recorded on the blockchain. The protocol uses a two-phase flow: blockSenaPauseDraw (locks the round and records the commitment) and blockSenaDrawPay (reveals, draws, and pays).
Goal
Guarantee an auditable, reproducible process with transparent payout rules for every round.
Auditability
Anyone can verify inputs (commit, salt, target block), seed calculation, drawn numbers, and settlement events.
Commit-Reveal (2 Phases)
The function blockSenaPauseDraw(usdValuePoolSnapshot, commitHash) locks the round for new purchases, sets the future target block, and stores only the secret salt hash.
The function blockSenaDrawPay(salt) validates that keccak256(salt) == commitHash, uses the target-block blockhash, generates the 6 unique numbers, and executes payouts.
The blockhash can only be read for ~256 blocks. If it expires, the round needs an operational reset. This reset is a rare fail-safe with on-chain timeout, and every use stays public on-chain.
Salt Commitment
Target Block
Draw Flow (21:00 UTC -> +5 blocks -> DrawPay)
The Block-Sena operational flow clearly separates ticket closing from generation of the 6 numbers. This separation removes the risk of buying tickets after the result is known or trying to adjust tickets to match the drawn numbers.
The function blockSenaPauseDraw(usdValuePoolSnapshot, commitHash) locks the round, blocks new purchases, records the commitHash, defines targetBlock = block.number + 5, and stores the pool snapshot in USD.
After PauseDraw, no new ticket can enter that round. At that moment, blockhash(targetBlock) still does not exist, so the final 6 numbers cannot yet be predicted or calculated.
The function blockSenaDrawPay(salt) validates the salt against the commit, reads the target-block blockhash, generates the 6 unique numbers, and executes per-token payouts. If called before the target block, the transaction reverts on-chain.
Anyone can verify in the explorer: the blockSenaPauseDraw tx, targetBlock, the blockSenaDrawPay tx, revealed salt, drawn numbers, and settlement/payout events.
It is not possible to buy a ticket after seeing the 6 numbers of the round, because the round was already locked in blockSenaPauseDraw before the draw was executed.
It is not possible to know the 6 numbers at lock time, because the formula depends on a future block (targetBlock) that does not exist yet at that moment.
It is not possible to execute the draw before the technical time, because blockSenaDrawPay requires on-chain that the current block is already past the targetBlock.
blockSenaResetDraw exists only to prevent a round from being permanently stuck if a long infrastructure failure happens (for example: RPC outages, service maintenance, network/infra outages, or prolonged operational issues) and DrawPay cannot be executed before blockhash(targetBlock) expires.
In the normal flow, the expected behavior is to execute DrawPay a few blocks after PauseDraw (target at +5 blocks). Reset is a liveness safeguard, not part of the normal draw flow.
Mathematical Draw Formula (6 unique numbers)
The draw seed is derived from the combination of a future block, the committed salt, and round data. From it, the contract generates numbers from 1 to 30, discarding duplicates until it reaches 6 unique numbers.
In operational security terms: because tickets are already frozen in the PauseDraw phase before that future block exists, the draw cannot be "crafted" to match a ticket inserted later, and no participant can bet in the same round after knowing the result.
Draw Seed
Generation of Each Number
This procedure prevents repeated numbers in the final result and keeps the draw within the valid range 1..30.
Multiple-Pick Ticket (6 to 10 numbers) and Combinatorial Quotas
In Block-Sena, a ticket can contain from 6 to 10 numbers. This ticket represents multiple equivalent combinations of 6 numbers. Prize calculation is based on winning quotas (combinations), not just “people”.
Total Combinations for a Ticket with k Numbers
Winning quotas by tier (4/5/6)
Consider a ticket with k numbers and x matches inside the 6 drawn numbers.
Example (10-number ticket with the 6 drawn numbers inside the 10)
q6 = 1, q5 = 24, q4 = 90. The same ticket can win simultaneously in all 3 tiers.
Multi-Token Payout (Per-Token Settlement)
Each pool token (e.g., native, USDC, USDT) is settled independently. The contract calculates winners and prizes by round and by token, maintaining exact history in RoundTokenStats.
Tier Split
Prize per winning quota
If there are no winners
The amount for that tier is not lost: it becomes carry-over for that token in the next round.
If there are multiple winners
The prize is divided by winning quotas. The same wallet may receive several quotas aggregated into a single payment per token.
How to Audit a Round (Step by Step)
- Find the blockSenaPauseDraw tx and note the commitHash and targetBlock.
- After the target block, find the blockSenaDrawPay tx and read the submitted salt.
- Recalculate keccak256(salt) and confirm it matches the commitHash.
- Read blockhash(targetBlock) in the explorer and the prevrandao from the draw tx block.
- Reproduce the seed and the 6-number generation routine (discarding duplicates) and compare with DrawExecuted.
- If a rare operational failure happened, inspect DrawReset (roundId, targetBlock, reset block) to validate timeout and reset traceability.
- Check RoundTokenSettled events for pools, per-tier payouts, and per-token carry-over.
- Confirm native/ERC20 transfers to validate payments to winners.
Guarantees, Transparency and Operational Limits
Block-Sena was designed so that a round result is auditable, reproducible, and transparent. Commit-reveal combined with a future block significantly reduces the possibility of manual result manipulation.
In technical terms, the model makes the result unpredictable at lock time, because the round is closed before the blockhash(targetBlock) used in the seed exists. This keeps the formula public and auditable without allowing later bets based on the result.
What is guaranteed on-chain
Draw rules, quota calculations, tier payout split (80/15/5), per-token history, events, and traceability of each step.
Emergency operation
There is a draw reset function for rare technical scenarios (e.g., blockhash expiration caused by prolonged infra/network failure). It can only be executed with the round locked and after on-chain timeout. Every use is public, recorded on-chain, and auditable in the explorer.
Reset does not move funds, delete tickets, or alter the pool. It only unlocks the round cycle to allow a new draw attempt for the same round in a rare failure scenario.
Prize funds remain in the contract until the draw and automatic payouts to winners. If there are no winners in a tier, the value remains accounted as carry-over for the next round. The owner does not have a function to withdraw funds already accounted in the prize pool.
The rescueAll function exists only to rescue unaccounted surplus (e.g., mistaken direct transfers), calculating real balance - accounted pool. It does not reach prize funds already accounted for the pool.
In other words: Block-Sena does not ask for blind trust. It delivers a flow that can be observed, mathematically reproduced, and verified on-chain by anyone at any time.