Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# AGENTS.md

Guidance for AI coding agents working in Fate-EVM-Frontend, the EVM frontend for
Fate Protocol.

## Project Stack

Next.js 15 (App Router), React 19, TypeScript 5, TailwindCSS with shadcn/ui,
wagmi 2 + viem 2, RainbowKit. Statically exported.

## Commands

```bash
npm run dev # dev server on http://localhost:3000
npm run build # static export to out/ — this is ALSO the type check
npm run lint # eslint
```

There is no test runner and no standalone `tsc` script. "Verify a change" means
`npm run lint`, `npm run build`, and driving the flow in a browser with a wallet.

**`build` and `dev` share `distDir: "out"`.** After running a build, delete
`out/` and `.next/` before returning to `npm run dev`, or dev crashes on the
export artifacts.

## Architecture Constraints

- `output: "export"` in `next.config.mjs`. There are **no server components
fetching data and no API routes**. Every contract read and write happens in
the browser. Anything touching chain data needs `"use client"`.
- **ABIs are hand-maintained TypeScript consts** in `src/utils/abi/`. They are
not generated from the contracts repo. If a contract's external surface
changes, edit the const by hand, then `src/utils/addresses.ts` after a
redeploy.
- **Adding or enabling a chain touches five files** and changing only one fails
silently: `src/utils/wagmiConfig.ts`, `src/utils/chainConfig.ts`,
`src/utils/addresses.ts`, `src/utils/chains/*.ts`, `src/data/tokens/*.json`.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
- **Three numeric scales are in play and must not be conflated.** Base-token
amounts use the token's own decimals, read on-chain, never assume 18. Oracle
prices and sentiment ratios are WAD (1e18). Contract fees use
`DENOMINATOR = 100000`. Check which one a value is in before doing arithmetic.

## Code Style Conventions

- Path alias `@/*` maps to `src/*`.
- Prefer **wagmi + viem**. ethers v6 remains only in `src/lib/prices.ts` and
`src/lib/vaultUtils.ts`. Extend the viem path; do not add new ethers code.
- For batched reads outside React, use
`createPublicClient({ transport: http(), batch: { multicall: true } })`.
- Reuse the shadcn/ui primitives in `src/components/ui` rather than adding new
component libraries.
- Log through `src/lib/logger.ts` and handle errors through
`src/lib/errorHandler.ts`. Do not use raw `console.*`.
- Access IndexedDB through the `useIndexedDB` hook. `src/lib/fatePoolHook.ts` is
a legacy compatibility wrapper; do not build on it. Schema changes require
bumping `DATABASE_CONFIG.version` in `src/lib/indexeddb/config.ts`.

## Boundaries

- Never commit `.env.local` or any secret. `NEXT_PUBLIC_PROJECT_ID` is required
to run the app locally.
- Never edit `node_modules/`, `.next/`, or `out/`.
- Do not modify `next.config.mjs`, `tsconfig.json`, or `package.json` unless
explicitly asked. The webpack `resolve.fallback` and `alias` entries there stub
out `fs`, `net`, `tls` and React Native async-storage, and the static export
breaks without them.
- Do not introduce a server-side data path. The app must remain statically
exportable.
- Brand assets exist twice on purpose: `brand/` is the canonical kit and `public/`
is what the app serves. Changing one means changing both. Do not delete the
`public/` copies; `Navbar.tsx` imports `public/logo.svg` directly, and
`manifest.json` and `layout.tsx` reference the icons by path.

## Git Workflow

- Branch from `main` with a `feat/`, `fix/`, `docs/` or `chore/` prefix.
- One pull request per concern.
- Commit subjects: imperative, roughly 50 characters, capitalized, no trailing
period. One line, no body.
- Pull requests go against `main` on the upstream repository, from a fork.
266 changes: 266 additions & 0 deletions BestPracticesChecklist.md

Large diffs are not rendered by default.

96 changes: 96 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Contributing to Fate-EVM-Frontend

Thanks for taking the time to contribute. This is the EVM frontend for Fate
Protocol, a decentralized perpetual prediction market.

## Discord Project Channel

Questions, ideas, or help with a first contribution:

- **Fate channel**: https://discord.com/channels/995968619034984528/1324064370883301386

## Development Setup

1. **Fork and clone:**

```bash
git clone https://github.com/<your-username>/Fate-EVM-Frontend.git
cd Fate-EVM-Frontend
git remote add upstream https://github.com/StabilityNexus/Fate-EVM-Frontend.git
```

2. **Install dependencies** (Node.js 18 or later):

```bash
npm install
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
```

3. **Configure environment:**

```bash
cp env.example .env.local
```

`NEXT_PUBLIC_PROJECT_ID` is a Reown project ID, free from
<https://cloud.reown.com>. Wallet connection will not work without it. RPC
endpoints are not required: keyless public defaults per chain live in
`src/utils/rpcTransport.ts`.

4. **Run the dev server:**

```bash
npm run dev
```

The app runs at `http://localhost:3000`.

> `npm run build` and `npm run dev` share `distDir: "out"`. After a build,
> delete `out/` and `.next/` before going back to dev, or dev will fail on the
> export artifacts.

## Verifying a Change

There is no test runner in this repository. Before opening a pull request:

- `npm run lint`
- `npm run build` — this is also the type check; there is no standalone `tsc` script
- Exercise the flow in a browser with a wallet on Sepolia or Ethereum Classic

## Coding Style

- TypeScript throughout. The path alias `@/*` maps to `src/*`.
- The app is a static export, so anything reading chain data runs in the
browser. Mark those components `"use client"`.
- Prefer **wagmi + viem**. ethers v6 survives only in `src/lib/prices.ts` and
`src/lib/vaultUtils.ts`; extend the viem path rather than adding new ethers
code.
- UI is shadcn/ui with Tailwind. Reuse the primitives in `src/components/ui`.
- Log through `src/lib/logger.ts` and handle errors through
`src/lib/errorHandler.ts` rather than raw `console` calls.
- Base-token amounts use the token's own decimals, read on-chain. Never assume
18. Oracle prices are WAD (1e18) and contract fees use `DENOMINATOR = 100000`.
These three scales are distinct, so check which one a value is in before doing
arithmetic on it.

## Changing Contract Calls

ABIs are hand-maintained TypeScript consts in `src/utils/abi/`, not generated.
If a contract's external surface changes, update the matching const, and update
`src/utils/addresses.ts` after a redeploy.

## Pull Request Process

1. Branch from `main` with a `feat/`, `fix/`, `docs/` or `chore/` prefix.
2. Keep one pull request to one concern.
3. Write commit subjects in the imperative, roughly 50 characters, capitalized,
with no trailing period.
4. Push to your fork and open a pull request against `main` on the upstream
repository.
5. Fill in the pull request template, including the AI usage disclosure.
6. CodeRabbit reviews automatically. Address its comments alongside maintainer
feedback.

## Reporting Issues

Open an issue with a clear description, steps to reproduce, the chain and wallet
you used, and any console output or screenshots.
20 changes: 6 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,20 +237,12 @@ npm run start

## Contributing

We welcome contributions of all kinds! To contribute:
We welcome contributions of all kinds. See **[CONTRIBUTING.md](CONTRIBUTING.md)**
for development setup, coding style, and the pull request process.

1. Fork the repository and create your feature branch (`git checkout -b feature/AmazingFeature`).
2. Commit your changes (`git commit -m 'Add some AmazingFeature'`).
3. Run the development workflow commands to ensure code quality:
- `npm run lint`
4. Push your branch (`git push origin feature/AmazingFeature`).
5. Open a Pull Request for review.

If you encounter bugs, need help, or have feature requests:

- Please open an issue in this repository providing detailed information.
- Describe the problem clearly and include any relevant logs or screenshots.

We appreciate your feedback and contributions!
Questions and ideas are welcome in our
[Discord channel](https://discord.com/channels/995968619034984528/1324064370883301386).
If you hit a bug, please open an issue with clear steps to reproduce and any
relevant logs or screenshots.

© 2025 The Stable Order.
133 changes: 133 additions & 0 deletions brand/Brand.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# Fate Protocol Brand Kit

This folder is the canonical source for Fate Protocol's visual identity: logo, favicons and icons,
colour palette, and typography. The assets referenced below live in this `brand/` folder; the copies
under `public/` are what the deployed application serves, and the two are kept identical.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

## Logo

| Asset | File |
| --- | --- |
| Fate Protocol mark (SVG) | [`logo.svg`](./logo.svg) |
| Stability Nexus org logo (animated GIF) | [`../public/Animated/logo-animated.gif`](../public/Animated/logo-animated.gif) |

The mark is a hexagonal badge containing two animals in profile: a pale bear above and a dark bull
below, representing the bearCoin and bullCoin sides of every prediction pool. The hexagon is filled
dark and outlined with a heavy dark stroke.

`logo.svg` is a `0 0 1230 1280` viewBox built from 14 paths in five fixed greys. It carries no
`currentColor` and no animation, so it renders identically in every context.

### Using the mark on a background

The mark is **two-tone with a dark silhouette**, which constrains what it can sit on. Measured
contrast of the mark's own values against candidate grounds:

| Ground | vs `#121212` (hex fill) | vs `#F1F1F1` (bear) |
| --- | --- | --- |
| `#0A0A0A` near-black | 1.06 : 1 | 17.53 : 1 |
| `#6B6B6B` mid grey | 3.52 : 1 | 4.72 : 1 |
| `#FFFFFF` white | 18.73 : 1 | 1.13 : 1 |

- **Prefer light or mid grounds.** On white the pale bear is low-contrast in isolation but stays
legible because it is *contained* by the dark hexagon fill, so the badge reads as a whole.
- **Avoid near-black grounds.** At 1.06 : 1 the hexagon's silhouette dissolves and only the bear
remains visible. The mark still appears in the app's dark navbar, which is an accepted trade-off,
but new placements should not repeat it.
- This is why the social preview card (`public/og-image.png`) uses a light `#F7F8FA` ground rather
than matching the app's dark theme.

One asset serves both light and dark themes. A dark-specific variant was evaluated and deliberately
declined, to keep a single canonical mark.

## Favicons & Icons

Generated from `logo.svg` at the sizes browsers and mobile platforms actually request:

| File | Size | Use |
| --- | --- | --- |
| [`favicon.ico`](./favicon.ico) | 16 / 32 / 48 (multi-res) | Classic browser favicon |
| [`apple-touch-icon.png`](./apple-touch-icon.png) | 180×180 | iOS home screen |
| [`icon-192.png`](./icon-192.png) | 192×192 | PWA manifest, Android |
| [`icon-512.png`](./icon-512.png) | 512×512 | PWA manifest, splash |

`favicon.ico` is a genuine three-entry ICO container. Chrome requires both a 192 and a 512 PNG for
installability, so those two are not optional and must not be collapsed into the SVG.

The ICO frames are cut with **zero padding**. The inked mark is taller than it is wide, so height is
the binding dimension and any inset costs visible size at 16px.

## Colour Palette

### Mark palette

Sourced directly from `logo.svg`. The mark is deliberately achromatic so it never competes with the
semantic colours below.

| Swatch | Name | Hex | Usage in mark |
| --- | --- | --- | --- |
| ⬛ | Ink | `#121212` | Hexagon fill, bull body |
| ⬛ | Ink Light | `#242424` | Hexagon stroke |
| ⬛ | Graphite | `#444444` | Bull shading, interior detail |
| ⬜ | Silver | `#C0C0C0` | Bear shading |
| ⬜ | Bone | `#F1F1F1` | Bear body |

### Application palette

What the interface actually renders. Colour here is **semantic, not decorative**: green and red
carry directional meaning and must not be used for ornament.

| Swatch | Role | Light | Dark |
| --- | --- | --- | --- |
| 🟩 | Bull, gains, upward movement | `#16a34a` (green-600) | `#4ade80` (green-400) |
| 🟥 | Bear, losses, downward movement | `#ef4444` (red-500) | `#f87171` (red-400) |
| 🟨 | Accent, active state, warnings | `#eab308` (yellow-500) | `#eab308` |
| ⬜ | Page background | `#FFFFFF` | `#0A0A0A` |
| ⬛ | Body text | `#171717` | `#EDEDED` |
| ⬛ | Mobile navigation bar | `#1A1B1F` | `#1A1B1F` |

Surfaces, borders and secondary text use Tailwind's `gray` and `neutral` scales (Tailwind v3.4
defaults). Both scales are currently in use across the codebase; new work should prefer `neutral`
and existing `gray` usage should migrate as files are touched.

### Organisation accents

Inherited from Stability Nexus and used where Fate appears as part of the wider organisation, such
as the README badge and the social preview rule.

| Swatch | Name | Hex |
| --- | --- | --- |
| 🟨 | Stability Gold | `#FFC517` |
| 🟩 | Forest Green | `#228B22` |

### Contrast requirement

All text pairings must meet WCAG 2.1 AA, 4.5 : 1 for body text and 3 : 1 for large text and
non-text indicators. `#171717` on `#FFFFFF` gives 17.93 : 1 and `#EDEDED` on `#0A0A0A` gives
16.91 : 1, so both defaults have ample headroom. Take care with the yellow accent: `#eab308` on
white is only 1.92 : 1, so it must be reserved for icons, borders and fills, never for small text on
a light ground.

## Typography

**Brand typeface: Geist.** Loaded through `next/font/google` in `src/app/layout.tsx`, which exposes
it as the CSS variables `--font-geist-sans` and `--font-geist-mono`.

| Role | Face | Use |
| --- | --- | --- |
| Interface | Geist | All UI text, headings, body, labels |
| Numeric and code | Geist Mono | Addresses, hashes, contract values |
| Fallback stack | `system-ui, -apple-system, "Segoe UI", Roboto, sans-serif` | When Geist is unavailable |

Guidance: headings bold and tight; body regular; monospace with tabular figures for any column of
token amounts or prices, so digits align.

> **Known gap.** Geist is loaded but not yet applied. `tailwind.config.ts` has no `fontFamily`
> extension consuming the two CSS variables, and `src/app/globals.css` sets
> `body { font-family: Arial, Helvetica, sans-serif; }`, which wins. The deployed app therefore
> renders Arial today. Closing this is a two-line change and is tracked separately, so that the
> visual change is reviewed on its own rather than inside this brand kit.

The wordmark on the social preview card is set in Arial Bold, chosen for guaranteed availability in
the image-generation step rather than as a brand choice. It should be regenerated in Geist once the
gap above is closed.
Binary file added brand/apple-touch-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added brand/favicon.ico
Binary file not shown.
Binary file added brand/icon-192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added brand/icon-512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading