# AGENTS

> Everything here works without a browser. Each action is the same shape: POST a wallet address, get a short-lived signed voucher plus ready-to-send calldata, then send one transaction. No login, no session, no cookie, no CAPTCHA.

## Machine-readable

- `/mcp` -- MCP server, add as a custom connector, no key needed
- `/llms.txt` -- index for AI assistants
- `/openapi.json` -- OpenAPI 3.1 schema
- `/base-mcp-plugin.md` -- Base MCP plugin spec
- `/plugin/plugin.json` -- Agent Plugins 1.0.0 package

## The whole journey

1. Claim BASE167 -- POST /api/check with { address }, then send the returned call.
2. Claim the Entry pass -- POST /api/games/claim-entry with { address }.
3. Register a competition wallet -- POST /api/games/enroll with { player, gameWallet }.
4. Compete -- trade from the competition wallet between the bells.
5. Claim a Winner badge -- POST /api/games/claim-winner with { address }.
6. Release the pass lock afterwards -- EntryNFT.releaseLock(tokenId), permissionless.

## Four rules worth knowing before you start

- Any wallet type can claim, enrol and compete -- EOAs, ERC-4337 smart accounts, Base Account, Safe, and 7702-delegated EOAs. Naming works for all of them too, via ERC-1271, ERC-6492 and ERC-8010.
- The competition wallet can be any wallet, a smart account included, and it may have a past. What matters is what it holds at the opening bell: at least $5 of USDC, at most 0.0002 ETH of gas, and nothing else of value. More gas ETH than the allowance is disqualified automatically; any other token is flagged for review and judged by hand, because scoring counts USDC only and an unscored asset sold mid-season would read as profit.
- USDC that arrives mid-season counts towards the wallet's stake. Ranking is a ratio -- closing USDC over the money the wallet had to trade with -- so an injection raises the denominator and cannot manufacture a return. It is never an automatic disqualification, because the roster is public from enrolment and anyone could otherwise eliminate a rival by sending them a cent; it is flagged for review and judged by hand.
- Prizes have no claim function. Claiming a Winner badge mints an NFT and moves no value; season payouts are made by hand. Do not go looking for a method that does not exist.

## What a season pays

Each monthly season pays a 300,000,000 BASE167 pot to the podium only -- 150,000,000 for first, 100,000,000 for second, 50,000,000 for third -- and the annual Finals pay 1,200,000,000 BASE167. Money stops at three, glory does not: every place inside winnersCount (ten in season 1) mints a rank-stamped Winner badge NFT and takes a Finals seat. Read winnersCount from /api/games/state rather than assuming ten, and state every figure in BASE167, never as a cash value.

## Who can enter

Two gates, in order. The holder snapshot at snapshotAt records the top BASE167 holders, and only an address in it can claim that season's Entry pass; the list size is the topHolders config value. Then the enrolment window, enrollOpenAt to enrollCloseAt, is when a pass holder registers a competition wallet -- that is the act that enters them. Enrolling locks the Entry pass until the closing bell, after which EntryNFT.releaseLock(tokenId) is permissionless. Holding several passes makes you a Collector, which is what the Finals seats are drawn from.

## Never hard-code a date

Seasons move -- season 1 was itself rescheduled. Read snapshotAt, enrollOpenAt, enrollCloseAt, openingBellAt and closingBellAt from /api/games/state, all unix seconds, and report phase -- one of pre, seatMarket, setup, preGame, game or settled -- with nextBoundary rather than computing the season's state yourself.

## Limits

5 requests per minute per IP on the POST routes (429 with Retry-After: 60); the GET reads are not limited. Bodies capped at 1KB, or 512 bytes on /api/check. A 409 usually means a window is closed rather than something being broken, and a 503 from a naming route means a chain was unreachable, not that your signature was bad.

## Do not cache the numbers

Claim counts, remaining supply and season phase change constantly. Read them from /api/games/state or straight off the token contract at the moment you need them.

## Contracts

| What | Address |
| --- | --- |
| BASE167 token | `0x2Bf0234d7E9C25687521D2d2192d1dAE70aA4f2B` |
| SeasonFactory | `0x8Cf6ae46C03801D8Ae7Fbdc643AF34003E83b345` |
| EntryNFT (season 1) | `0x6e403A853CBC6962f29E0C766e4fDD611A2a769b` |
| WinnersNFT (season 1) | `0xA7762135805D3b7E9CA6F9a990d99A861E8b4a41` |

## Live data

Nothing on this page is a live figure. Read these at the moment you need them:

- `POST /api/check` with `{ address }` -- a wallet's Base transaction count and claim eligibility
- `GET /api/games/state` -- the season, its phase, its config and its boards
- `GET /api/games/leaderboard` and `GET /api/games/results` -- the live and settled boards
- On chain: `claimCount()` and `rewardsRemaining()` on the token

Full machine-readable index: https://base167.com/llms.txt
