Modern, responsive block explorer for FairCoin. Vite + React SPA frontend with an Express API server (run with Bun) that talks JSON-RPC to a FairCoin node and caches responses in MongoDB. Real-time updates are pushed over WebSocket.
WebSocket (WS /api/ws) pushes change notifications (new blocks, mempool updates, network stats, transaction confirmations). Canonical blockchain data is always loaded over HTTP (GET /api/*) via React Query: the client invalidates (and optionally paints) caches on push, then refetches the full API shape. When the socket is down, live hooks fall back to a 30s HTTP poll. In local dev, Vite proxies /api with ws: true so the browser can upgrade /api/ws to the API server.
- Frontend: Vite, React 18, TypeScript, TanStack Query, Tailwind CSS 4, shadcn/Radix UI, react-router
- Backend: Express 5 (Bun runtime), WebSocket (
ws), MongoDB cache,@fairco.in/rpc-client - i18n: 8 languages (en, es, fr, de, ru, zh, ja, ko)
# 1) Install deps
npm i
# 2) Configure environment
cp .env.example .env
# edit .env with your RPC and MongoDB credentials
# 3) Run the API server (port 8080)
npm run server # or: npm run dev:server (watch mode, requires Bun)
# 4) Run the frontend dev server (port 5180, proxies /api to :8080)
npm run devFor production, build the SPA and let the API server serve it:
npm run build # outputs dist/
npm run server # serves dist/ + API + WebSocket on :8080MongoDB in production. The cache DB is a plain local MongoDB — point
MONGODB_URIatmongodb://localhost:27017/faircoin-explorer. On thefcexplorerhost it runs as a Docker container:docker run -d --name mongo --restart=always -p 127.0.0.1:27017:27017 -v mongo-exp:/data/db mongo:4.4. Usemongo:4.4on hosts whose kernel/CPU trips MongoDB 5+/8 (the box needs AVX for 5+, and Mongo 8 refuses kernel ≥6.19). The cache self-populates from the node's RPC on demand, so a fresh empty DB recovers on its own. Do not use a DigitalOcean managed cluster — that dependency was removed after the DO account was lost.
| Script | Description |
|---|---|
npm run dev |
Vite dev server (frontend, port 5180) |
npm run dev:server |
API server in watch mode (Bun, port 8080) |
npm run server |
API server (Bun) |
npm run build |
Typecheck + production build of the SPA |
npm run typecheck |
Typecheck frontend and server |
npm run sync-db |
Full blockchain sync into MongoDB (optional, Bun) |
npm run check-db |
MongoDB health/index check (Bun) |
# RPC Configuration (server-side only; never exposed to the browser)
FAIRCOIN_RPC_USER=fair
FAIRCOIN_RPC_PASS=change_me
FAIRCOIN_RPC_HOST=127.0.0.1
FAIRCOIN_RPC_PORT=46373
FAIRCOIN_RPC_SCHEME=http
# MongoDB
MONGODB_URI=mongodb://localhost:27017/faircoin-explorer
# WebSocket / realtime monitor
WEBSOCKET_ENABLED=true
WEBSOCKET_NETWORKS=mainnet # comma-separated; add testnet if you run a testnet node
BLOCKCHAIN_POLL_INTERVAL=4000 # block/mempool poll (ms); default 4s
WEBSOCKET_HEARTBEAT_INTERVAL=30000
WEBSOCKET_MAX_CONNECTIONS_PER_IP=5
WEBSOCKET_MAX_PAYLOAD_BYTES=65536
# Public site URL (MCP links, etc.). The JSON API allows any browser origin via CORS.
PUBLIC_BASE_URL=https://explorer.fairco.inSecurity: RPC credentials are only read server-side; all RPC calls are proxied through the API. The /api surface is rate-limited (a global limiter on /api, plus stricter limits on /api/search, /api/transaction, /api/address, /api/tx/broadcast, and the public /mcp endpoint, which can drive daemon-backed wallet tools). Expensive lookups are bounded: /api/price/history samples long windows in memory from a bounded, two-tier-pruned series, and /api/search on an address returns balance only (it no longer triggers an unbounded address-txid scan, so txCount is 0 there — use the address pages for full history). /api/peers is redacted (no raw peer addresses or topology).
Behind a reverse proxy (e.g. nginx/Cloudflare), set TRUSTED_PROXY_CIDRS to the proxy's IP/CIDR(s) so the rate limiter keys on the real client IP — X-Forwarded-For is trusted only from those peers, never from arbitrary clients. Leave it blank when the API is reached directly.
The Express server exposes a read-only JSON API under /api:
GET /api/blocks,/api/block/:hashOrHeight,/api/blockcountGET /api/transactions(paginated recent txs from mempool + recent blocks)GET /api/transaction/:txid,POST /api/tx/broadcastGET /api/address/:address,/api/address/:address/txs?page=&limit=,/api/address/:address/utxos(requires a node withaddressindexfor full data)GET /api/mempool,/api/masternodes,/api/peers,/api/stats,/api/network-info,/api/mining-infoGET /api/search?q=(block height/hash, txid, or address)GET /api/validate-address?address=,/api/fee-estimateGET /api/price,/api/price/history,/api/stats/historyGET /api/bridge/reserves(proxied WFAIR bridge reserves)WS /api/ws— push of chain changes (new-block,block-count,mempool-updatewith top-N txs,transaction-confirmed,network-stats). Canonical data still comes from HTTP/api/*; the socket tells the client when to refetch.
The explorer also speaks the Model Context Protocol, so AI assistants (Claude, ChatGPT, Cursor, …) can query the FairCoin blockchain directly.
- Endpoint:
https://explorer.fairco.in/mcp - Transport: Streamable HTTP, stateless (a fresh server is built per request — no session store).
POSTcarries the JSON-RPC request;GET/DELETEreturn405(there is no SSE stream or session to address). - Access: read-only. No API key required.
Every blockchain tool accepts an optional network argument ("mainnet" by default; "testnet" is also supported).
| Tool | Purpose |
|---|---|
search |
Resolve a block height, block hash, txid, or address into linkable { id, title, url } results (ChatGPT deep-research contract). |
fetch |
Given an id from search (e.g. tx:<hash>), return the full record as { id, title, text, url, metadata }. |
get_network_stats |
Height, difficulty, supply, connections, mempool size, masternode count, PoW/PoS phase. |
get_latest_blocks |
Most recent blocks (limit 1–50, default 10). |
get_block |
A full block by height or hash. |
get_transaction |
A full transaction by txid (with resolved prevouts and live confirmations). |
get_address |
Balance/summary for an address (full history needs a node with addressindex; degrades gracefully). |
get_mempool |
Current mempool size and recent pending transactions. |
get_masternodes |
Masternode list (by rank) plus aggregate stats. |
get_price |
Live FAIR price (via the WFAIR/USDC pool on Base). |
get_supply |
Circulating/max supply, block reward, percent mined. |
create_wallet |
Generate a new FairCoin keypair and return { address, privateKey (WIF) }. Non-custodial — the server stores nothing. |
get_balance |
Confirmed + unconfirmed balance and UTXO count for an address (needs a node with addressindex). |
send |
Send a FAIR amount from the address controlled by your privateKey (WIF) to toAddress. Returns { txid, amount, fee }. |
sweep |
Send the entire balance of your privateKey's address to toAddress (minus fee). Returns { txid, amount, fee }. |
The wallet tools let AI agents receive and spend FAIR autonomously on both mainnet and testnet, with a strictly non-custodial design:
create_walletgenerates a keypair in-process and returns the address and private key (WIF) once. The server keeps no copy — no database, no file, no in-memory cache. The agent is the sole holder of the key.get_balancereads an address balance + UTXOs from the node.send/sweepaccept the agent's WIF as a parameter, derive the from-address, build the raw transaction, and hand the key to the node'ssignrawtransaction(which signs without importing the key to the wallet) before broadcasting. The key is used transiently and never persisted.
Only key generation is done in-process (using the audited @noble/curves secp256k1 implementation); all transaction construction, signing, and broadcasting are delegated to the FairCoin node (createrawtransaction / signrawtransaction / sendrawtransaction) so FairCoin's exact transaction and sighash format is always correct. send and sweep use a flat 0.001 FAIR network fee; change below the dust threshold (0.0001 FAIR) is dropped into the fee rather than creating an uneconomical output.
Security caveat — the key is the holder's responsibility. The private key is returned to and supplied by the caller. The server never logs, echoes, or stores it, and it cannot recover a lost key. Anyone holding the key controls the funds. Store it securely.
send/sweepandget_balancerequire a FairCoin node started with-addressindex=1.
- Claude (Desktop/Code): add a custom connector / MCP server with URL
https://explorer.fairco.in/mcp(transport: HTTP/Streamable HTTP). - ChatGPT (deep research / connectors): add a connector pointing at the same URL. The required
searchandfetchtools are implemented, so it works out of the box. - Cursor / other clients: configure a Streamable HTTP MCP server with the same URL.
- Dashboard with live blocks, mempool, price and network stats
- Global recent transactions feed, charts/analytics, and tools (broadcast, address validator, API docs)
- Block, transaction and address pages (with paginated address history when the node has
addressindex) - Masternode list and reward stats, peers, network status
- Universal search (height, hash, txid, address)
- MongoDB-backed RPC caching with single-flight de-duplication and self-healing TTLs
- Real-time WebSocket updates
- Dark/light theme, 8 languages, responsive layout
- Realtime model: the server polls the FairCoin RPC (default every 4s) and pushes change events on
WS /api/ws. Clients should treat HTTP/api/*as the source of truth and use the socket to invalidate/refetch. - Address balances/history require a FairCoin node with
addressindex=1; without it the explorer degrades gracefully to validation-only data. - The MongoDB cache populates on demand;
bun run sync-db(full historical sync) is optional.