# Immoto
> Immoto is an exchange layer for hybrid NFT/token collections on Arc (Circle's L1, chain id 5042; testnet 5042002). Every collection is a DN-404 pair (ERC-20 + mirrored ERC-721) launched with zero capital into a single-sided Uniswap v4 pool whose liquidity can never be removed. Swap fees stream to staked units. The protocol's own 5,042 seats (token IMMOTO, NFT "Immoto") are the launch license and the revenue right of the whole platform. Tagline: liquidity that never moves.
This file is for language models and agents. Human docs: /docs · creator handbook: /handbook · source: the GitHub link in the footer.
## Key facts
- Unit: 1.0 token == 1 NFT while a wallet holds a whole unit (last-acquired dissolves first). Contracts skip NFTs by default; EIP-7702 delegated wallets do not.
- Supply: 5,042 IMMOTO (4,992 on the curve, 50 in the treasury). Collections: 100–100,000 units, all on their curve.
- Curve: three single-sided tranches 40% / 35% / 25% at [p0, 4·p0], [4·p0, 20·p0], [20·p0, ∞). IMMOTO p0 = 10 USDC. USDC or IMMOTO that enters the pool stays forever; the pool never sells out.
- Fees (at deployment; owner-tunable within caps, decision 16 — read `SeatsHook.configOf(poolId)` for live values): IMMOTO/USDC 3% (‰900 stakers / ‰50 dev / ‰50 protocol liquidity); router hop 1%; collection/IMMOTO 2% (‰650 collection stakers / ‰150 IMMOTO stakers / ‰100 creator / ‰50 POL / ‰50 dev); mint fee 10% of primary sales (IMMOTO: dev; collections: 5% dev / 5% creator); launch surcharge on buys 27% → 0 over the first minute (IMMOTO) / hour (collections, default), to stakers.
- Staking: stake(id) → position NFT, tenure weights ×1.0 / ×1.5 / ×2.0 / ×3.0 at 0 / 7 / 30 / 90 days; unstake → 3-day cooldown (zero weight, tenure reset) → withdraw returns exactly 1.0 unit with the same id. Rewards stream linearly over 7 days; pull-based `claim`; assets: native USDC (address(0)) and IMMOTO.
- Routing lock (permanent, no graduation): the token can only enter/leave the Uniswap PoolManager with the hook's per-transaction permission, so the canonical pool is the only AMM venue; any router/aggregator may swap there. Wallet-to-wallet and NFT transfers are free. There is no graduation.
- License: a collection is created by a wallet holding a **staked** IMMOTO seat that licenses no other collection; the seat is locked 30 days; the creator earns the creator share only while that seat stays staked and owned (else redirected to IMMOTO stakers; `relicense` with another staked seat restores it).
- Factory gate: `createCollection` opens once the IMMOTO/USDC pool reserve ≥ 100,000 USDC on mainnet (`SeatsFactory.OPEN_USDC`; lower on testnet); a latch — once open, open for life.
- Launch tokens (decision 15): `SeatsFactory.launchToken(LaunchParams{meta{name,symbol,description,image,xProfile,telegram}, supply (1e6–1e12 whole tokens), p0, quote, graduationQuote})` payable ≥ 1 USDC (launch fee → IMMOTO stakers; extra value = the creator's exempt first buy). Quote: IMMOTO, address(0) = native USDC, or an owner-allowlisted ERC-20 (`quoteAllowed`). Plain ERC-20 (`LaunchToken`), no NFT, no lock, tradable anywhere. Fee 2% of the quote leg: creator 1% · protocol 0.5% (‰700 IMMOTO stakers / ‰300 dev) · burn 0.5% (buys IMMOTO and sends it to `ImmotoSink`; IMMOTO quote sinks directly; other ERC-20 in kind). Surcharge 99% → 0 over 10 s on buys. Graduation = badge (`launchBacking(token)` → (backing, graduated)). Router: `buyExactIn(token, minOut, to, deadline)` payable (USDC- and IMMOTO-quoted), `buy`/`sell` (USDC-quoted, exact-out/exact-in), `sellChild` (IMMOTO-quoted → USDC), `buyWithQuote`/`sellForQuote` (ERC-20-quoted). Quoter: `quoteBuyExactIn`, `quoteBuy`, `quoteSell`, `quoteBuyWithQuote`, `quoteSellForQuote`. Creator hand-over: `SeatsHook.setCreator(token, to)`; metadata: `LaunchToken.setMetadata`.
- Art: set at creation (`CreateParams.renderer` or `liquidURI`/`positionURI`), else the protocol placeholder; changeable by the creator until `freezeMetadata`. Offchain: `.json`, ids 1…N, OpenSea metadata format; optional second root for staked/cooldown units. Onchain: a contract implementing `tokenURI(uint256 id, uint8 state, uint256 tenure) returns (string)` (state 0 liquid, 1 staked, 2 cooldown) returning a `data:application/json;base64,` URI.
- Royalty: ERC-2981, 5% default, ERC721-C validator (Limit Break) set by default; creator can change both until frozen.
- Owner powers: pause swaps/staking (self-disables 12 months after deploy; claims and withdrawals never pause), ban contract codehashes, `SeatsHook.setPoolFees` (fee ≤ 10%, mint ≤ 20%, split among a pool's existing destinations), `SeatsFactory.setLaunchDefaults` / `setChildDefaults` (bounded; `launchFee()` is the current launch fee), `allowQuote` for paired ERC-20s, factory defaults, IMMOTO metadata until frozen. Curve, tiers, supply, the sink, router and quoter are immutable. Liquidity can never be removed by anyone. Every owner action is an event (`PoolFeesSet`, `PausedSet`, `LaunchDefaultsSet`, `ChildDefaultsSet`, `QuoteAllowed`, `DefaultsSet`, `DevSet`), recorded in the indexer's `admin_action` table.
- Arc specifics: native gas is USDC with 18 decimals in the EVM (`msg.value`); native transfers to blocklisted addresses revert → failed reward payouts are deferred and re-claimable; `PREVRANDAO` = 0 (trait seed committed once by the renderer owner); ~0.5 s blocks.
## Contracts (addresses per network in /docs#contracts and deployments/.json)
- `Hybrid404` — the unit token: ERC-20 + mirror accounting, stake/unstake/withdraw(Many), routing lock, license lock. Views: `ownedLiquid(addr)`, `ownedPositions(addr)`, `positions(id)` → (owner, state, tenureStart, cooldownEnd), `tenureOf(id)`, `stateOf(id)`.
- `Mirror721` — the NFT: `tokenURI`, `setURIs(liquid, position)`, `setRenderer(addr)`, `setRoyalty(receiver, bps)`, `freezeMetadata()`, `metadataOwner`.
- `SeatsHook` — Uniswap v4 hook: fees, pots, `flush(poolId)` (permissionless), `claimDev`, `claimCreator`, `pots(poolId)`, `collPots(poolId)`, `quoteReserveOf(poolId)`, `launchExtraBps(poolId)`.
- `SeatsRouter` — `buySeat(seatOut, maxUsdcIn, to, deadline)` payable, `sellSeat(seatIn, minUsdcOut, to, deadline)`, `buyChild(collection, unitsOut, maxUsdcIn, to, deadline)` payable (USDC → IMMOTO → collection), `buyChildWithSeat`, `sellChild`, `sellChildForSeat`.
- `SeatsQuoter` — `quoteBuySeat(units)`, `quoteSellSeat(units)`, `quoteBuyChild(collection, units)`, `quoteBuyChildWithSeat`, `quoteSellChild`, `quoteSellChildForSeat`, `quoteBuySeatForUsdc(usdc)`.
- `SeatsFactory` — `createCollection(CreateParams{name, symbol, units, p0, licenseSeatId, renderer, liquidURI, positionURI})` → collection address; `relicense(collection, newSeatId)`; `collections(i)`, `collectionInfo(addr)`, `licenseOf(addr)`, `licenseActive(addr)`, `isOpen()`, `OPEN_USDC()`.
- `StakeRewards` (one per collection) — `earned(id, asset)`, `claim(ids[])`, `poke(id)`, `weightOf(id)`, `totalWeight()`.
- `POLVault` — `compound()` (permissionless: re-adds protocol fees as permanent single-sided liquidity).
- Onchain art: `SeatsRenderer` (IMMOTO portraits), `CollectionPlaceholder` (default art for new collections).
## How to launch a collection (summary; full guide at /handbook)
1. Buy 1 IMMOTO (Launch page or `SeatsRouter.buySeat`), stake it (`Hybrid404.stake(id)`).
2. Prepare art: either publish `1.json … N.json` under one base URI (IPFS/Arweave/HTTPS, ending with `/`), or deploy a renderer contract implementing `tokenURI(id, state, tenure)`.
3. Wait for the factory gate (`SeatsFactory.isOpen()`).
4. Call `createCollection` with name, symbol, units (100–100,000), p0 (start price in IMMOTO, 18 decimals), your staked seat id, and the art fields (zero address / empty strings for the placeholder). Gas ≈ 7.2M.
5. The pool is live in the same transaction; the 1-hour surcharge starts. Claim the creator share from the collection page (`SeatsHook.claimCreator(poolId)`); manage art/royalty on the same page.
## Programmatic access
- Indexer (Ponder): GraphQL at `/graphql`, SQL over HTTP at `/sql/*`, health at `/status`. Tables: pool (with backingQuote, burnedImmoto), swap, poolDay, stakeEvent, claim, flush, collection, launch, burn, quoteAsset, protocol, compound, seat, account.
- Quotes are exact: the router reverts if the pool moves beyond the quoted amount (slippage parameters).
- Any Uniswap v4 router can swap in the pools; the hook charges the same fee. Third-party swaps that specify the USDC amount (exact-in buys) pay the mint fee in the collection token.
## What Immoto is not
- Not affiliated with Circle, Arc, Uniswap Labs or any marketplace. No presale, no team tokens, nothing locked forever; IMMOTO is never burned by the protocol itself — the launchpad's burn share is IMMOTO sent to a sink nobody controls. No yield promise: rewards are swap fees and can be zero.