The dapp
The TIDE web app is the product. There is no separate “marketing site” and “app” — the same surface explains the thesis, shows the pool’s live state, and lets you transact against it. A first-time visitor should grasp the core idea (holding the token is providing liquidity) in seconds; a holder lives on /claim watching fees accrue and claiming them.
This page covers the stack and the five pages. For the two transactional surfaces in depth, see Collection & your position and the Claim dashboard.
The dapp is a Next 14 App Router static export — output: 'export' with trailingSlash, producing a fully static out/ directory and no server runtime. Pages are server components that wrap "use client" data components; all on-chain interaction happens in the browser. It is deployed on Cloudflare Pages.
| Layer | Choice |
|---|---|
| Framework | Next 14 App Router, static export (output: 'export') |
| Wallet / chain | wagmi + viem + RainbowKit (terracotta accent via lightTheme) |
| Data fetching | @tanstack/react-query — staleTime: 10_000, retry: 2, no refetch on window focus |
| Fonts | next/font/google — Fraunces (serif), Archivo, Spline Sans Mono |
| Styling | Hand-written CSS design system + CSS Modules (no Tailwind) |
Reads: one client, batched multicall
Section titled “Reads: one client, batched multicall”All reads go through a single module-level viem publicClient defined in src/lib/tide.ts. The transport batches and the client coalesces calls through multicall:
transport: http(RPC_URL, { batch: true }),batch: { multicall: { wait: 16, batchSize: 1024 } },Per-NFT reads (token URIs, owners, pending fees) fan out through multicall with allowFailure, so one burned or unreachable token never breaks a page. useNftBatch caches decoded metadata by token id. The read hooks live in src/lib/hooks/reads.ts — useProtocolStats, useUserPosition, useOwnedTokens, usePendingFees, usePoolPrice, useActivity, useTreasury — each with its own polling interval.
The dapp also reads protocol parameters live rather than hardcoding them: feeWindow1, feeWindow2, vestingDuration, and prizeActivationWindow are multicalled off the hook, so the same UI renders correctly whether durations are compressed (Sepolia test values) or full production values. Only the fee tiers (25% / 10% / 5%) are hardcoded constants. See Addresses & network.
Writes: the transaction lifecycle
Section titled “Writes: the transaction lifecycle”Every write goes through useTx (src/lib/hooks/useTx.ts), built on wagmi’s useWriteContract + waitForTransactionReceipt. It surfaces a four-stage lifecycle as toasts:
- Confirm in your wallet — waiting for signature.
- Transaction submitted — includes the hash and an Etherscan link (
explorer.tx(hash)). - Confirming on-chain — awaiting the receipt.
- Success / error / reverted — a final toast; reverted transactions are reported honestly as “mined but failed”.
A per-action pendingKey drives a spinner on the specific button pressed, and a useRef mutex prevents a fast double-click from sending two transactions. describeError maps viem and custom-contract errors to friendly text.
Header & status banner
Section titled “Header & status banner”The header (Header.tsx) carries the tide. wordmark, primary nav (Stats · Claim · Collection · Protocol), a RainbowKit connect button, a mobile hamburger drawer, and — whenever CHAIN_ID !== 1 — a “Sepolia testnet” chip.
A top StatusBanner appears only on real problems, never as decoration:
| Condition | Banner |
|---|---|
Misconfiguration (!CONFIG_OK) | Configuration error |
| Wallet on the wrong network | Wrong network, with a switchChain button |
Contracts unreachable (useDeployStatus false) | Unreachable, with Retry |
The pages
Section titled “The pages”/ — Landing
Section titled “/ — Landing”Marketing plus a live readout, all in one scroll. The hero states the thesis (“Holding is providing liquidity.”) with CTAs to Get TIDE (/claim/) and How it works (/protocol/). Below it:
HomeStats— the live readout: aFeeGauge, supply minted as Tide-LP (totalMintedout of10000with a progress meter), live shares (totalShares), circulating TIDE, and pool status. Has its own skeletons and Retry.Pillars— the three modules: V4 protocol · DN404 mechanism · TIDE-LP positions.HowItWorks— a numbered, exploded walkthrough of the flow.TrustBand— the no-rug summary, shared with/protocol.
/claim — Claim dashboard
Section titled “/claim — Claim dashboard”The transactional home base, gated on a connected wallet. A position summary (your TIDE, Tide-LP held, accrued-unclaimed fees), a lottery panel (only when you have a pending prize), a vesting card (withdraw vested, sync fees, convert owed), and a fees-by-position list with per-NFT and Claim all buttons. The sidebar holds the in-app SwapWidget, a launch-fee FeeGauge, and a wallet readout. Full detail in Claim dashboard.
/collection — Collection & your position
Section titled “/collection — Collection & your position”The generative-NFT explorer. A segmented toggle switches between All tides (the public gallery of every minted Tide-LP, each card showing the on-chain SVG, traits, and owner) and My tides (your own collection, wallet-gated). An address lookup field renders any holder’s position read-only. The My position banner computes your exact shortfall to the next whole TIDE (and thus the next NFT). Full detail in Collection & your position.
/stats — Protocol dashboard
Section titled “/stats — Protocol dashboard”A read-only, wallet-agnostic dashboard in four sections of tiles:
- Positions — Tide-LP created (
totalMinted), in circulation (totalShares), burned (minted − circ), circulating TIDE. - Market — price (TIDE/ETH from
usePoolPrice), notional market cap, the current swap fee + tier name, pool status. - Rewards distributed — lifetime fees per position (from
accFeesPerShareETH/TIDE / ACC_SCALE), approximate total ETH/TIDE legs, and Treasury queued-to-burn (pendingBurn). - Activity — a trailing block-window summary from
useActivity: volume + swaps, fees generated + pokes, lottery awards, NFTs minted/burned + claims.
/protocol — Deep explainer
Section titled “/protocol — Deep explainer”The full mechanism, for readers who want it all:
Mechanics— the six trustless mechanics, explained.ProtocolLive— protocol parameters read live from the chain (fixed supply; the25% → 10% → 5%schedule;feeWindow1/feeWindow2,vestingDuration,prizeActivationWindowformatted viaformatDuration; the10%buyback slippage floor), with a note that Sepolia runs compressed test durations.- Treasury card — queued-to-burn, the guardian address, and the no-rug invariant stated plainly: withdrawal path: none; only action: buyback-burn, with a link to verified source.
TrustBand— the shared no-rug summary.
For the trust model behind these claims, see Trust model & no-rug and the openly documented Known limitations.