Security
Attacks the contracts are built to refuse, and how.
Draw outcomes
| Attack |
Defence |
| Revert-postselection — call the draw, inspect the prize, revert unless it is good, retry free |
Payment settles in an earlier transaction than the outcome. By the time a result exists there is nothing left to revert. |
| Operator grinds a favourable sequence |
The chain is committed before any draw, and the player's seed is chosen after the commitment is published. |
| Player grinds a client seed |
The operator's seed is revealed only after the player's is fixed on-chain. |
| Seed reuse or reordering |
sha256(s) == currentTip enforces one-time, in-order consumption. |
| Modulo bias |
Rejection sampling above floor(2^256 / 1,000,000) × 1,000,000. |
| Double settlement |
A spin settles once; its state is deleted on settlement. |
| Insolvent payout |
A tier is payable only while the bankroll covers it, enforced in the contract. |
| Operator refuses to settle |
refundStale() is callable by the player one hour after the request. |
Funds
| Attack |
Defence |
| Hostile receiver blocks a payout |
Pull payments. Prizes and settlements credit a balance the recipient withdraws. |
| Frozen USDG address blocks settlement for others |
Same. A frozen address blocks only its own withdrawal. |
| Reentrancy on a fund path |
nonReentrant and checks-effects-interactions on every path that moves value. |
| Claiming another account's balance |
withdraw() takes no arguments and pays only the caller. |
Markets
| Attack |
Defence |
| Relayer holds a signed order and fills it at the worst price — a free option against the signer |
limitPrice is part of the signed payload and checked on-chain against the fill. |
| Self-liquidation for the keeper fee |
The fee comes from the liquidated side's own residual, so it is paid out of the liquidator's own collateral. |
| Order replay |
Per-order nonce and expiry. |
| Single compromised oracle signer moves a price |
N-of-M quorum, signatures required from distinct signers in sorted order. |
| Quorum moves a price abruptly |
Per-market deviation cap and a wall-clock minimum interval between posts. |
| Abandoned oracle strands collateral |
reclaimStale() after 7 days refunds each side its own margin with no PnL applied. |
| Settlement against a stale price |
Each market sets priceMaxAge, bounded to between 60 seconds and 1 hour. |
Collateral
| Attack |
Defence |
| Borrower pledges a token they minted themselves |
Only collections on an owner-set allowlist are accepted. |
| Seizure while repayment is still open |
The grace and seizure windows are exclusive. |
| Voucher replay or reuse by another address |
The voucher binds buyer, price, serial hash and deadline, and can be cancelled before it is spent. |
Chain entropy
block.prevrandao on Robinhood Chain is the constant 1 and blockhash is byte-identical across roughly 160 consecutive blocks. No VRF is available. Nothing on-chain is usable as a source of randomness, which is why draws use commit–reveal rather than an on-chain draw.
Not covered
The contracts are not independently audited. They are non-upgradeable, so a defect cannot be patched in place and requires redeployment and migration. Custody, insurance and item authentication are performed by third parties and are outside the contracts entirely.