---
name: rohme-games-interface
description: Build a games/casino interface for a DAO launched on the ROHME Launchpad (Robinhood Chain, 4663) — coin flip, dice, and future vetted games played against the DAO's GameHouse bankroll. V1 is SAME-TOKEN (wager and payout are the same treasury reserve asset: USDG/USDG, WETH/WETH, COIN/COIN), plus the founder's bankroll-and-markets dashboard. Use when the user wants a betting/games UI for their DAO or a games lobby across DAOs.
---

# Build a games interface for a ROHME-launched DAO

You are building the betting surface for a DAO's **GameHouse** — the bankroll
vault its treasury games play against. Games are ROHME-vetted shared contracts
(CoinFlip, DiceRoll today); each DAO's house decides which games run, in which
reserve assets, at what limits, and what rake the DAO earns. Randomness is
Quiver's two-party commit-reveal (results arrive in a keeper callback seconds
after the bet — the UI must handle the pending state). Everything reads from
public RPC; no API keys.

**V1 IS SAME-TOKEN ONLY.** A market's wager and payout are the same reserve
asset — the provably-fair, price-free lane. Cross-asset markets (e.g. USDG
wagers paying the COIN stock RWA) are DEFERRED to v2: a security audit found
they need short-window-TWAP + deviation-gated oracle pricing that does not exist
yet. The contracts reject a cross-asset market, so do not build UI for one.

First, ask the user for their **launchId**. For a full DAO site too, use the
companion skill `rohme-dao-interface`. This skill covers only the games surface.

## Setup: chain, addresses, ABIs

Use the same custom viem chain as the companion skills (id 4663, RPC
`https://rpc.mainnet.chain.robinhood.com`, the `multicall3` entry at
`0xcA11bde05977b3631167028862bE2a173976CA11` is required — see
`rohme-dao-interface` for the full `defineChain` block).

Fetch and commit these at setup (never transcribe or guess):

- Singleton addresses: `https://forum.rohme.capital/skills/launchpad.4663.json`
  — the games keys are `gamePluginRegistry`, `gameHouseFactory`,
  `gameHouseBeacon`, `coinFlip`, `diceRoll`. **If `gameHouseFactory` is absent
  the games lane is not deployed yet — stop and tell the user; do not guess.**
- ABIs from `https://forum.rohme.capital/skills/abi/`: `game-house.json`,
  `game-house-factory.json`, `coin-flip.json`, `dice-roll.json`,
  `game-plugin-registry.json` (plus `launch-factory.json`, `treasury.json`).

## Resolve the house

`gameHouseFactory.houseOf(launchId)` → the DAO's house. Zero address ⇒ no house
yet: `deployHouse(launchId)` is PERMISSIONLESS and configuration-free (binds the
DAO's treasury, Timelock, creator off the launch record) — offer it as one
click. A fresh house is inert until the creator/Senate configures it. Validate
any house address you display with `gameHouseFactory.isHouse(house)`.

House reads: `treasury()`, `paused()`, `gameEnabled(game)`,
`marketConfig(game, token)`, `availableBankroll(token)`, `getRound(roundId)`,
`lockedPayout(token)`, `claimable(player, token)`.

## The market model (same-token)

A **market** is one `(game, token)` pair with config
`{enabled, rakeBps, maxWagerBps, maxExposureBps, maxPayoutX, minWager}`. `token`
is a treasury RESERVETOKEN (USDG, WETH, a tokenized stock like COIN). No oracle
is in the loop — payouts are pure token units. Discover markets from the house's
`MarketSet` / `GameEnabled` event logs, keeping enabled markets of enabled games.

**Odds are rake-net.** A win pays fair odds on `wager − rake`. Standard rake 500
bps ⇒ payouts price on 95% of the wager. Show it honestly:
- CoinFlip win: `2 × (wager − wager·rakeBps/1e4)` — a 100 USDG flip at 5% pays
  190, not 200.
- DiceRoll: pick `chanceBps ∈ [100, 9500]`; win pays
  `(wager − rake) × 10000 / chanceBps`.

Max bet to display: `availableBankroll(token) × maxWagerBps / 10000`; the payout
lock is capped by `maxExposureBps` of the bankroll and by `maxPayoutX × wager`.
Quote the house's reverts rather than re-deriving edges: `CapExceeded`,
`HousePaused`, `WagerBelowMin`, `GameKilled`.

## The bet flow

1. Approve the **HOUSE** (not the game) for the token — one approval per token.
2. Quote `game.playFee()` and forward it as `msg.value` (0 on this chain today —
   always quote live; excess is refunded).
3. `userRandom`: fresh `crypto.getRandomValues` bytes32 per bet (public calldata).
4. The player must be the transaction sender: the house requires
   `player == tx.origin`, so call the game directly from the player's EOA (no
   router/multicall wrapper).
5. `coinFlip.flip(house, token, wager, heads, minPayout, userRandom)` or
   `diceRoll.roll(house, token, wager, chanceBps, minPayout, userRandom)`. Pass a
   non-zero `minPayout` (the smallest win you'll accept) so an ops rake change
   can't silently worsen the bet.
6. Read the house's `RoundOpened(roundId, game, player, token, wager, maxPayout,
   rakeBps)` from the receipt. Show the LOCKED `maxPayout` — never re-quote.
7. Show a resolving state; watch for `RoundSettled(roundId, player, payout,
   rake)` (win when `payout > 0`) or poll `getRound(roundId).status` (1 Open,
   2 Settled, 3 Voided).
8. If a settle failed transiently (a paused token), anyone can call
   `game.retrySettle(seq)` — surface it. A win credited to `claimable` (a
   blocklisted/paused recipient) is withdrawn with `house.claim(token)`; show a
   claimable balance and a claim button.
9. A round Open past `VOID_AFTER` (3 days) ⇒ anyone may `house.voidStale(roundId)`
   — refunds the wager MINUS the rake. Show a countdown + reclaim button.

## The founder dashboard (creator or DAO Timelock)

The creator is a day-to-day ops seat; the DAO Timelock is `admin`. Ops levers:
`setGameEnabled(game, bool)` (vetted + not killed), `setMarket(game, token,
cfg)`, `drawFromTreasury(token, amount)`, `returnToTreasury(token, amount)`,
`fundBankroll(token, amount)` (permissionless), `setPaused(true)`. **Admin-only**
(Timelock): `setRiskBudget(token, bps)`, `setMintBudget(bps)`, `setPaused(false)`
(unpause), `setCreator`, `transferAdmin`/`acceptAdmin`.

Arming the treasury valve is a one-time Senate decree (target = the DAO's
`lister`): `lister.relay(treasury, treasury.enable(RESERVEMANAGER=3, house))`.
Draws then stay bounded by BOTH the admin-set `riskBudgetBps` and the treasury's
own 25%/7-day leaky bucket. Distinguish `RiskBudgetExceeded` vs
`ManageRateLimited` in the UI.

## Shipping and verification

Static-hostable; public RPC only. Verify READ-ONLY against mainnet: the house
resolves (or the deploy offer renders), same-token markets enumerate from logs,
max bets/payouts render, and a `flip` simulation (`eth_call`) passes for a small
wager. Never send funds to verify.

## What NOT to do

- Never build cross-asset market UI — v1 is same-token; the contract reverts it.
- Never display gross-odds payouts (2× the full wager) — odds are rake-net.
- Never re-quote a placed bet — show the round's locked `maxPayout`.
- Never have players approve the game — wagers pull from the HOUSE allowance.
- Never hardcode the play fee, rake, or caps — read them live per market.
- Never blank a screen because logs lag — render from RPC state reads alone.
- Never guess game or house addresses — only the manifest and `houseOf`/`isHouse`.
