> For the complete documentation index, see [llms.txt](https://docs.trover.tech/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.trover.tech/engineering/verify-2026-09-13-opensea-pool-chain-history.md).

# Verify 2026-09-13: OpenSea key pool, chain history backfill, mint card, status bar

Migration status: **none**.

## Why

cat-street-broker opened at 15:25 UTC on 2026-09-12 and stayed "queued" for five hours: 5,978 collections were queued behind one OpenSea key (about 120 requests a minute), the sync was retried 336 times against the budget hold, and only the 4 sales after tracking began were indexed because the OpenSea Events backfill never got through. The same contract also carried a second row, `hashdogs-nft` (the collection's old OpenSea slug), holding 43 mints and 9 sales the page could not see.

## What changed

* **OpenSea key pool** (`packages/integrations/src/opensea.ts`): every key in `OPENSEA_API_KEYS` (comma separated) plus `OPENSEA_API_KEY` has its own block, pacing gate and shared Redis budget; each call goes to the key that is ready soonest. `health()` reports `keys` and per-key `blockedUntil`.
* **Chain history backfill** (`apps/worker/src/nft-collection-history.ts`, job `backfill_nft_collection_history`): when a terminal opens a collection (once per 6 h), the worker walks the contract's Transfer logs from its creation block (found by bisection on `getCode`): mints with their paid price, and sales by decoding Seaport `OrderFulfilled` in each transfer's receipt. Slices of 60 s / 1,500 receipts, cursor in Redis `trover:nft-history:v1:<collectionId>`, re-enqueues itself until the head. Same writers as the live scanners, so OpenSea reporting the same fill later does not double count.
* **Renamed collections merge**: `mergeDuplicateNftCollections` also folds a queued/failed named slug into the live named slug on the same contract.
* **Mint eligibility** `GET /v1/nft-market/collections/:slug/mint-eligibility` (`?chain&wallet`): `getMintStats(minter)` on the ERC721SeaDrop contract for the profile's active wallets (or a given wallet): minted count, remaining per stage, state `eligible | limit_reached | not_started | ended | sold_out | allowlist | unknown` (allowlist needs OpenSea's proof, so it says so).
* **Terminal**: mint card for a minting collection (active stage, price in ETH and USD, quantity stepper capped by the wallet's remaining, "mint N on opensea", limit per wallet, your minted count, eligibility chip, the schedule with USD prices and per-stage eligibility); 24h volume shows the ETH logo and a USD figure (falls back to the floor's ETH/USD rate); an orderbook-pending note under "no active listings"; **bottom status bar** (indexed block and age, chain head and lag, feed live/polling, provider synced/syncing/failed with the OpenSea retry time, orderbook state, events indexed); **OG / copycat** chip in the header, shown only when two or more contracts share the name (case and punctuation stripped, across chains); the one with the earliest indexed mint (else earliest row) is OG.
* Detail body gains `freshness` and `identity`.

## Checks run

`tsc --noEmit`: core, integrations, api, worker, web clean.

## Checks for you

1. Add more keys: `OPENSEA_API_KEYS=key2,key3` in the server `.env` (backup first), redeploy api and worker; `curl localhost:3001/v1/nft-market/health` (or the admin health) shows `keys: N`.
2. Open a fresh collection: the bottom bar shows "provider queued · chain data shown meanwhile", the mints tab fills from the chain within a minute or two (worker log "NFT history backfill …"), sales and candles include pre-tracking history.
3. cat-street-broker: mint card with WL and Public stage in USD, your wallet's "eligible / limit reached", OG chip absent unless a same-named contract exists; `hashdogs-nft` folded in on the next merge run (its 9 sales appear).
4. 24h volume tile: ETH logo plus `($…)`.

## Deploy

Frontend: pushed to `main`, Vercel builds. Backend (one at a time, detached):

```
ssh trevor-server
cd ~/trover && git pull --ff-only origin main
nohup bash -c 'set -x; docker compose -f docker-compose.yml -f docker-compose.production.yml build api worker && docker compose -f docker-compose.yml -f docker-compose.production.yml up -d --no-deps api worker; echo DEPLOY_EXIT=$?' > deploy-$(date +%Y%m%d-%H%M).log 2>&1 &
```

## Addendum: attention gate (same day)

The history walk and front-of-queue sync no longer follow every opened collection. `apps/api/src/nft-interest.ts` records page views by real browsers (agent reads and crawlers excluded by header and user agent) and top-three search results in Redis, and a collection qualifies when any of these hold: top five of the chain's trending list (flagged by the worker's discovery refresh), a viewer in the last ten minutes, three or more searches in the last hour, or views in six or more distinct hours of the last day (or twenty in total). Qualifying collections get `trover:nft-interest:v1` for thirty minutes; the worker checks that flag before every history slice and pauses the walk (cursor kept) when it lapses. Non-qualifying opens sync at priority 3 instead of 1 and are not walked. The three keys you pasted are in the pool (health reports `keys: 4`).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.trover.tech/engineering/verify-2026-09-13-opensea-pool-chain-history.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
