---
name: rohme-dao-interface
description: Build and ship a dedicated web interface for ONE DAO launched on the ROHME Launchpad (Robinhood Chain, 4663) — its swap, staking, bonds, governance, treasury, and rage-quit surfaces, branded for that community. Use when the user is a DAO founder or member who wants their own standalone site for their specific DAO.
---

# Build an interface for one ROHME-launched DAO

You are building a standalone site for a single DAO that was launched on the
ROHME Launchpad. The DAO is a complete on-chain organism — token, rebasing
staking, bond markets, an OpenZeppelin Governor + Timelock, a treasury with
real backing, and an always-on redemption (rage-quit) floor. Everything reads
from public RPC; no API keys.

First, ask the user for their **launchId** (a small integer) or their **token
address** if they don't know it. Everything else is derived on-chain.

If they want an interface for the whole launchpad instead, use the companion
skill `rohme-launchpad-interface`
(https://forum.rohme.capital/skills/rohme-launchpad-interface/SKILL.md).

## Setup: chain, addresses, ABIs

Chain — define a custom viem chain (not in `viem/chains`); the `multicall3`
entry is required or batched reads break:

```ts
import { defineChain } from "viem";
export const robinhood = defineChain({
  id: 4663,
  name: "Robinhood Chain",
  nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
  rpcUrls: { default: {
    http: ["https://rpc.mainnet.chain.robinhood.com"],
    webSocket: ["wss://feed.mainnet.chain.robinhood.com"],
  }},
  blockExplorers: { default: {
    name: "Blockscout",
    url: "https://robinhoodchain.blockscout.com",
    apiUrl: "https://robinhoodchain.blockscout.com/api",
  }},
  contracts: { multicall3: { address: "0xcA11bde05977b3631167028862bE2a173976CA11" } },
});
```

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

- Launchpad singleton addresses (factory, lens, locker, hook, WETH, gROHM,
  tickSpacing): `https://forum.rohme.capital/skills/launchpad.4663.json`
- ABIs from `https://forum.rohme.capital/skills/abi/`:
  `launch-factory.json`, `launchpad-lens.json`, `launch-token.json`,
  `staking.json`, `bond-depository.json`, `treasury.json`,
  `redemption-module.json`, `rohme-governor.json`, `timelock-controller.json`,
  `grohm.json`, `universal-router.json`, `launch-locker.json`

If any fetch fails, stop and tell the user; do not substitute guessed ABIs.

## Resolve the DAO

One read gives you every address:
`factory.getLaunch(launchId)` returns a struct containing `token`, `treasury`,
`staking`, `stakedToken` (the rebasing sTOKEN), `govToken` (the 18-dec
ERC20Votes gTOKEN), `bondDepository`, `redemptionModule`, `governor`,
`timelock`, `policyGuard`, `poolIdWeth`, `poolIdGRohm`, `receipt`,
`metadataURI`, `name`, `symbol`, and the launch economics. Use the hosted ABI
for exact field order. If the user only knows the token address, iterate
`launchId = 1..factory.launchCount()` comparing `getLaunch(id).token`.

Check `factory.isOpened(launchId)` — if false the DAO exists but is not
trading yet; render a "pre-open" state rather than broken panels.

Decimals: TOKEN and sTOKEN are 9-dec; gTOKEN and gROHM are 18-dec; USD values
across the protocol are 9-dec (`1e9 == $1.00`).

## The six surfaces to build

**1 · Overview.** `lens.launchView(launchId)` (the LaunchpadLens address is in
the manifest) returns the dashboard numbers in one call; `lens.tokenUsd9`
gives the display price (display-only by design — never derive economics from
it). Backing truth: `treasury.totalReserves()` and `treasury.excessReserves()`
(the mint gate — staking emissions and bond capacity are both gated on it).

**2 · Swap.** The DAO trades on two v4 pools; TOKEN is always `currency0`:
`{currency0: token, currency1: WETH or gROHM (manifest), fee: 0x800000,
tickSpacing: manifest, hooks: manifest hook}`.

v4 infra: PoolManager `0x8366a39CC670B4001A1121B8F6A443A643e40951`, V4Quoter
`0x8Dc178eFB8111BB0973Dd9d722ebeFF267c98F94` (stock), Permit2
`0x000000000022D473030F116dDEE9F6B43aC78BA3`, UniversalRouter
`0x8876789976dEcBfCbBbe364623C63652db8C0904` — **modified router, canonical
(a stock look-alike exists on-chain; don't use it)**. Its swap structs carry an
extra `uint256 minHopPriceX36` between the amount bounds and `hookData`
(`0` disables). **Stock Uniswap SDK calldata mis-decodes against it** — encode
`execute()` yourself from the hosted `universal-router.json`. Command
`V4_SWAP = 0x10`; actions `SWAP_EXACT_IN_SINGLE = 0x06`, `SETTLE_ALL = 0x0c`,
`TAKE_ALL = 0x0f` (all stock values). ERC20 legs go through Permit2 — approve
token→Permit2, then `permit2.approve(token, router, amount, expiration)`, and
**validate the expiration, not just the amount** (an expired MAX allowance
reverts `AllowanceExpired 0xd81b2f2e`). The LP fee is dynamic — read
`lens.currentFee` and show it; right after open it can be up to ~30%, decaying
to ~1% over ~120 seconds.

**3 · Stake.** ERC20-approve TOKEN to `staking`, then
`staking.stake(to, amount, rebasing, claim)` — `rebasing=true` mints the
rebasing sTOKEN, `rebasing=false` mints gTOKEN directly (how members get
voting power in one step). `staking.unstake(to, amount, trigger, rebasing)`
exits. `staking.index()` tracks accrued rebases; `wrap`/`unwrap` convert
sTOKEN↔gTOKEN. Show the epoch cadence from `staking.epoch()` — emissions are
excess-reserve-gated, so a young DAO legitimately rebases zero; show that
state honestly rather than as an error.

**4 · Bonds.** On `bondDepository`: `liveMarkets()` enumerates open markets,
`marketPrice(id)` prices one, `deposit(id, amount, maxPrice, user, referral)`
buys (payout vests as a gTOKEN note), `indexesFor(user)` + 
`redeem(user, indexes, sendGov)` claims matured notes. Markets are
excess-reserve-gated: open-but-unfillable until the treasury holds excess
backing — surface capacity honestly.

**5 · Govern.** gTOKEN is the vote unit (timestamp clock, not block numbers).
`govToken.delegate(self)` before voting. On `governor`: standard OZ surface —
`propose`, `castVote`/`castVoteWithReason`, `state`, `proposalDeadline`,
`queue` + `execute` through the timelock. Quorum uses a floor plus a
percentage of non-excluded supply — read `quorum(timepoint)` live rather than
computing it. New DAOs commonly sit below reachable quorum until staking
participation grows; show quorum progress against the live number.

**6 · Rage-quit.** The `redemptionModule` is the always-on floor: holders
redeem pro-rata from the liquid reserves, oracle-independently. Call
`previewRedeem(amount)` to show "what you'd get right now" before the user
signs `redeem`. This surface must never be hidden — it is the DAO's core safety
promise.

Optional but appreciated: a "crank" button calling
`locker.collectAndSplit(launchId)` (permissionless) that settles accrued LP
fees — half to this DAO's treasury as backing.

## Branding

Pull `name`, `symbol`, and `metadataURI` (a hosted image URL, possibly empty)
from `getLaunch` and build the site's identity around them. This is the DAO's
own site: let the user pick colors/typography, but keep protocol numbers
(price, backing, quorum, fees) unedited and honestly labeled.

## Shipping and verification

Static-hostable; no backend or secrets required (public RPC only). Deploy to
the user's host of choice. Before calling it done, verify READ-ONLY against
mainnet: `getLaunch` resolves, the overview renders live numbers, a swap
simulation (`eth_call` of router `execute()`) passes for a small hop, staking
and bond panels populate, and the redemption quote renders. Never send funds
as part of verification.

## What NOT to do

- Never blank a screen because an indexer or API is down — every panel must
  render from RPC alone.
- Never hardcode fees, prices, quorum, or the launch fee — read them live.
- Never use a stock Uniswap router SDK on this chain, never re-sort PoolKey
  currencies, and never route through the look-alike router.
- Never derive backing or bond math from the display price.
