Hackathon submission for Canteen × Circle. A Polymarket-style web app that lets users pay micro USDC on Arc Testnet via the x402 protocol to unlock an AI-driven research report (TikHub multi-source intelligence + DeepSeek reasoning), then trade directly on Polymarket V2 CLOB (Polygon Mainnet).
Production: https://canteen-hackthon.vercel.app
Live Video Demo: https://www.loom.com/share/128d01e85cdf490f9829f1fdc2e60403
Pre-flight (about 3 minutes):
- Connect a wallet (MetaMask or any WalletConnect-compatible wallet).
- Sign in once on polymarket.com with the same wallet so a funding wallet gets provisioned.
- Deposit at least $1 pUSD on polymarket.com (the first deposit auto-configures on-chain approvals).
- Top up the wallet with:
- Arc Testnet: a few cents of USDC — that's both the unlock fee and the native gas (Arc settles gas in USDC directly, no separate gas token). 0.10 USDC is plenty for many unlocks.
- Polygon: ≥ 0.05 POL (gas only) + at least $1 pUSD on polymarket.com to place a real order.
- In our app: pick any market →
Unlock AI Insight · 0.01 USDC→ read the AI report →Trade YES / NO→ done.
- 🔐 x402 on-chain payment — 0.01 USDC unlock on Arc (USDC also doubles as native gas), verified by the
Paidlog on-chain plus KV double-replay protection. - 🤖 Two-agent AI orchestration — Topic Curator selects the hottest markets, Deep Analyzer streams a research report with calibrated YES probability, confidence and suggested size.
- 📰 TikHub multi-source intelligence — TikTok + X + YouTube + Google News fetched in parallel; any single feed failing doesn't break the bundle.
- 💱 Polymarket V2 zero-friction trading — automatic wallet-kind detection (EOA / Safe / Proxy / Deposit), automatic API-key derivation, $1-min FAK market buy. Users never have to paste an API key.
- 🌐 HKG Edge reverse proxy — bypasses Polymarket CLOB's CORS + US-IP restrictions.
- 🛡️ Hardened fallbacks — TikHub / DeepSeek / Gamma / CLOB outages all degrade gracefully via stubs / cache / deep-link.
Browser (Next.js 14 + wagmi v2 + RainbowKit v2)
│ ▲
│ POST /api/insight/[id] │ SSE: status / evidence / delta / verdict
▼ │
Vercel Edge / Serverless Functions ──┘
│ │ │ │
▼ ▼ ▼ ▼
[Arc Testnet] [TikHub] [DeepSeek] [Polymarket]
PaymentVault multi-fetch streaming Gamma + CLOB V2
(Edge HKG proxy)
canteen-hackthon/
├── apps/web/ # Next.js 14 App Router app
│ ├── app/
│ │ ├── api/insight/[id]/ # x402 3-leg handshake + AI SSE stream
│ │ ├── api/markets/hot/ # Polymarket Gamma proxy + AI ranking
│ │ └── api/trade/
│ │ ├── clob-proxy/ # CLOB API reverse-proxy (Edge / HKG)
│ │ └── polymarket-profile/ # funding-wallet lookup
│ ├── components/
│ │ ├── insight/ # UnlockButton / InsightReport / EvidencePanel
│ │ └── trade/TradeDialog.tsx # ⭐ Polymarket V2 trade dialog
│ └── lib/
│ ├── ai/ # Topic Curator + Deep Analyzer
│ ├── tikhub/ # multi-source aggregator + ledger
│ ├── x402/ # protocol implementation
│ └── polymarket/ # ⭐ V2 CLOB integration (see below)
├── packages/shared/ # cross-package types + ABI + protocol consts
├── contracts/ # Foundry workspace - PaymentVault.sol
├── scripts/deploy-vercel.sh # one-shot Vercel deploy
└── README.md / README.zh.md # this file (EN / 中文)
| File | Purpose |
|---|---|
constants.ts |
V2 contract addresses (CTF Exchange V2 / NegRisk V2 / pUSD / CollateralOnramp) |
gamma.ts |
Polymarket Gamma API client |
clob.ts |
CLOB host + deep-link builder |
wallet-type.ts |
⭐ on-chain wallet-kind probe (EOA / Safe / Proxy / Deposit) → maps to sigType |
deposit-wallet.ts |
funding-wallet lookup via the polymarket.com profile endpoint |
approvals.ts |
V2 approval status (pUSD + V2 Exchange) |
onramp.ts |
USDC.e → pUSD wrap helper (CollateralOnramp.wrap) |
viem-signer.ts |
viem WalletClient → SDK ClobSigner adapter |
- Node.js ≥ 20
- pnpm 9 (
corepack enable && corepack prepare pnpm@9.12.0 --activate) - Foundry (
curl -L https://foundry.paradigm.xyz | bash && foundryup)
git clone <repo>
cd canteen-hackthon
pnpm install
cp .env.example .env.local
# fill in DEEPSEEK_API_KEY / TIKHUB_API_KEY / NEXT_PUBLIC_ARC_* / NEXT_PUBLIC_*_ADDRESS, etc.
pnpm dev
# open http://localhost:3000Offline fallback: without
DEEPSEEK_API_KEY/TIKHUB_API_KEY, the analyzer switches to a deterministic stub stream so the demo flow always completes end-to-end.
pnpm contracts:test # forge test -vv (7 cases)
pnpm contracts:deploy:arc # deploy to Arc Testnet
# copy the printed address into NEXT_PUBLIC_PAYMENT_VAULT_ADDRESSpnpm build
pnpm start./scripts/deploy-vercel.sh --prodThe script will:
- Verify the vercel CLI is logged in.
vercel linkthe project (first time only).- Sync every entry in
apps/web/.env.localto all three Vercel environments (production / preview / development). vercel deploy --prodto ship.
pnpm install -g vercel
vercel login
vercel link
# configure env vars in the Vercel dashboard (see .env.example)
vercel deploy --prod-
Keep Edge Runtime + HKG region. Both
/api/trade/clob-proxy/[...path]and/api/trade/polymarket-profiledeclareruntime = "edge"+preferredRegion = ["hkg1"]. This is what bypasses Polymarket's US-IP block. Do not switch to the Node runtime — Vercel will route you through US PoPs and Polymarket will respond with403 region-restricted. -
Vercel KV is mandatory in production. x402 nonce replay-protection and Gamma cache rely on Upstash Redis via Vercel KV. Local dev falls back to in-memory KV, which is fine for dev but unacceptable in production (cold starts wipe state).
-
Sync env vars after every change. Vercel does not auto-pull from the repo. After editing
.env.local, run./scripts/deploy-vercel.sh --env-onlyor update the dashboard manually. -
WalletConnect Project ID is required. Without
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID, mobile QR-code login crashes immediately. -
Isolate contract addresses per environment. Once
PaymentVaultis deployed on Arc Testnet, setNEXT_PUBLIC_PAYMENT_VAULT_ADDRESSseparately for each of the three Vercel environments (prod / preview / dev). This prevents preview deploys from polluting the production payment trail. -
No CLOB API key on the server. Polymarket's L2 API key is derived from the user's wallet signature (EIP-712), cached in the browser's
localStorage, and never touches our backend. We hold zero user secrets.
Full list in .env.example. Key entries:
| Variable | Purpose |
|---|---|
NEXT_PUBLIC_ARC_CHAIN_ID / _ARC_RPC_URL |
Arc Testnet config (x402 settlement) |
NEXT_PUBLIC_PAYMENT_VAULT_ADDRESS |
Deployed PaymentVault address |
NEXT_PUBLIC_USDC_ARC_ADDRESS |
USDC ERC20 on Arc Testnet |
NEXT_PUBLIC_INSIGHT_PRICE_USDC |
Per-event unlock price (production default: 0.01) |
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID |
RainbowKit / WalletConnect |
NEXT_PUBLIC_POLYGON_RPC_URL |
Polygon RPC (use your own Alchemy/Quicknode in prod) |
DEEPSEEK_API_KEY / _BASE_URL / _MODEL |
DeepSeek streaming chat |
TIKHUB_API_KEY / _BASE_URL |
TikHub multi-source intel |
GAMMA_BASE_URL |
Polymarket Gamma API (defaults to public) |
KV_REST_API_URL / _TOKEN |
Vercel KV (Upstash Redis) |
- Home page · AI Picked rail. Live Polymarket markets, sorted by AI hotness, refreshed every minute.
- Open an event. YES/NO duo-color hero, volume / liquidity / category — all from Polymarket Gamma.
- Click
Unlock AI Insight · 0.01 USDC.- Wallet pops twice:
approveUSDC →PaymentVault.pay(). - Server replies 402 → verifies the on-chain
Paidlog → opens SSE. - The right rail fills with TikHub evidence cards while the left rail streams the markdown report.
- Wallet pops twice:
- Read the AI verdict KPIs: YES probability, confidence, suggested side, suggested size.
- Click
Trade YES / NO on Polymarket.- Wallet auto-switches to Polygon.
- We probe the funding wallet → probe wallet-kind → auto-derive API key → one EIP-712 signature → order placed.
- No API key copy-paste required at any point.
Next.js 14 · TypeScript · Tailwind · shadcn-style components · Zustand
viem · wagmi v2 · RainbowKit v2 · Solidity 0.8.24 · Foundry · OpenZeppelin
DeepSeek (deepseek-chat) · TikHub · Polymarket V2 Gamma + CLOB (@polymarket/clob-client-v2) · Vercel + Vercel KV.
MIT