diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..775f03a --- /dev/null +++ b/.env.example @@ -0,0 +1,40 @@ +# Cloud state +BLOB_READ_WRITE_TOKEN= +PMA_STATE_PATH=shared/state.json + +# Live-money feature gate +# Keep false until legal/compliance approval, provider credentials, wallet signing, +# payment rails, and audit logging are production-ready. +LIVE_TRADING_ENABLED=false + +# Eligibility / compliance provider +KYC_PROVIDER= +KYC_API_KEY= +KYC_WEBHOOK_SECRET= +RESTRICTED_JURISDICTIONS=US,CA-NY,CA-ON + +# Wallet / deposit-wallet provider +WALLET_PROVIDER= +WALLET_PROJECT_ID= +WALLET_API_KEY= +DEPOSIT_WALLET_ADDRESS= +POLYMARKET_SIGNATURE_TYPE=3 + +# Payments / deposits / withdrawals +PAYMENTS_PROVIDER= +PAYMENTS_API_KEY= +PAYMENTS_WEBHOOK_SECRET= +SETTLEMENT_ASSET=pUSD +SETTLEMENT_CHAIN=polygon + +# Polymarket CLOB credentials +POLYMARKET_CLOB_HOST=https://clob.polymarket.com +POLYMARKET_CHAIN_ID=137 +POLYMARKET_CLOB_API_KEY= +POLYMARKET_CLOB_SECRET= +POLYMARKET_CLOB_PASSPHRASE= + +# Audit / monitoring +AUDIT_LOG_STORE= +ADMIN_ALERT_EMAIL= +RISK_ADMIN_WALLET= diff --git a/.gitignore b/.gitignore index c79010a..e393216 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ node_modules/ .vercel .claude/ .env* +!.env.example diff --git a/README.md b/README.md index 7f9b660..a57507a 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,17 @@ -# 📊 Polymarket Analyst — standalone website +# Polymarket Analyst -A **single-file website**. Everything (fetching live Polymarket data, the -analysis engine, and the ten AI paper-trading agents) runs in your browser. The -paper portfolio is saved in your browser's local storage. No server, no keys. +A Vercel-hosted Polymarket agent arena with shared paper-trading state, agent +return charts, paper accounts, market browsing, and live-money readiness rails. ## Just look at it now -Double-click **`index.html`** — it opens in your browser and works immediately. -On first open it fetches live markets, generates today's suggestions, and the -agents run a seven-day backtest, then begin live tracking. It auto-refreshes -once per day; the **Run cycle** button forces a refresh anytime. + +Open the deployed site: + +https://polymarket-site-eta.vercel.app + +The site fetches live Polymarket markets, generates agent suggestions, lets you +run hourly paper cycles, and syncs the shared arena state through the Vercel API +when `BLOB_READ_WRITE_TOKEN` is configured. ## Put it online (free) so you can reach it from any device @@ -28,8 +31,20 @@ Pick one — all give you a public URL: 1. → Add New → Project → import this GitHub repo under the `theodore_song` Vercel account (or use the `vercel` CLI in this folder) → Deploy. +## Configuration + +Use `.env.example` as the setup template. + +- `BLOB_READ_WRITE_TOKEN` enables cross-device shared state. +- `/api/live` reports whether KYC, payments, wallet/deposit-wallet, Polymarket + CLOB, audit, and monitoring providers are configured. +- `LIVE_TRADING_ENABLED` should stay `false` until legal review, provider setup, + wallet signing, reconciliation, and dry-run testing are complete. +- See `REAL_MONEY_ROADMAP.md` for the launch requirements before any real funds + or live order execution are enabled. + ## Notes -- Paper trading only — no real money, nothing places real orders. +- Paper trading only right now — no real money, nothing places real orders. - The analysis is a transparent heuristic, **not financial advice**. -- Because the portfolio lives in your browser, each browser/device keeps its - own portfolio. Clearing site data resets it (so does the **Reset** button). +- The shared arena uses cloud state when configured. Individual paper accounts + still use local browser storage unless a backend account database is added. diff --git a/REAL_MONEY_ROADMAP.md b/REAL_MONEY_ROADMAP.md index 193237d..f62ae6c 100644 --- a/REAL_MONEY_ROADMAP.md +++ b/REAL_MONEY_ROADMAP.md @@ -4,6 +4,17 @@ This app is currently paper trading only. The Live Money tab and `/api/live` endpoint are readiness scaffolding: they make the required product and backend interfaces visible without moving funds or placing orders. +## What is configured now + +- `.env.example` lists the environment variables the production app needs. +- `/api/live` reports which live-money providers are configured or missing. +- `/api/live` accepts order intents only as dry-runs and returns an audit event. +- The Live Money tab shows launch checks, wallet/deposit settings, agent risk + limits, a dry-run order console, and an audit preview. + +The app still refuses to place live orders. That is intentional until the legal, +provider, wallet-signing, reconciliation, and monitoring steps below are done. + ## Required before live deposits or trading 1. Legal and eligibility @@ -42,15 +53,56 @@ interfaces visible without moving funds or placing orders. ## Environment variables expected by `/api/live` +Copy `.env.example` into your local environment for development, then add the +same variables in Vercel Project Settings -> Environment Variables for +production. + - `KYC_PROVIDER` +- `KYC_API_KEY` +- `KYC_WEBHOOK_SECRET` - `PAYMENTS_PROVIDER` +- `PAYMENTS_API_KEY` +- `PAYMENTS_WEBHOOK_SECRET` - `WALLET_PROVIDER` +- `WALLET_PROJECT_ID` +- `WALLET_API_KEY` +- `DEPOSIT_WALLET_ADDRESS` +- `POLYMARKET_SIGNATURE_TYPE=3` +- `POLYMARKET_CHAIN_ID=137` +- `SETTLEMENT_ASSET=pUSD` +- `SETTLEMENT_CHAIN=polygon` - `POLYMARKET_CLOB_API_KEY` - `POLYMARKET_CLOB_SECRET` - `POLYMARKET_CLOB_PASSPHRASE` - `AUDIT_LOG_STORE` -- `LIVE_TRADING_ENABLED=true` +- `ADMIN_ALERT_EMAIL` +- `LIVE_TRADING_ENABLED=true` only after final approval and end-to-end testing Even when all variables are present, live order placement remains intentionally unimplemented until wallet signing, compliance approval, and safe order routing are completed. + +## Polymarket integration notes + +Polymarket's public docs describe trading as non-custodial. Orders are signed +and matched through the CLOB, and new API users generally use the deposit-wallet +flow with signature type `3`. + +Useful official docs: + +- Trading overview: https://docs.polymarket.com/trading/overview +- Trading quickstart: https://docs.polymarket.com/trading/quickstart +- Deposit wallets: https://docs.polymarket.com/trading/deposit-wallets + +## Final setup checklist + +1. Choose and contract the KYC / eligibility provider. +2. Choose the deposit and withdrawal provider. +3. Choose the wallet or embedded-wallet provider and create a deposit wallet. +4. Derive or create Polymarket CLOB credentials for the approved signing flow. +5. Create durable append-only audit storage. +6. Add all environment variables in Vercel. +7. Run dry-runs against `/api/live` and verify audit events. +8. Complete legal review, terms, restricted jurisdiction rules, and support + procedures. +9. Only then set `LIVE_TRADING_ENABLED=true`. diff --git a/api/live.js b/api/live.js index e6fafe6..0c7a0e3 100644 --- a/api/live.js +++ b/api/live.js @@ -1,11 +1,22 @@ const REQUIRED_ENV = [ ["KYC_PROVIDER", "KYC / eligibility provider"], + ["KYC_API_KEY", "KYC provider API key"], + ["KYC_WEBHOOK_SECRET", "KYC webhook secret"], ["PAYMENTS_PROVIDER", "Deposit and withdrawal provider"], + ["PAYMENTS_API_KEY", "Payments provider API key"], + ["PAYMENTS_WEBHOOK_SECRET", "Payments webhook secret"], ["WALLET_PROVIDER", "Wallet or deposit-wallet provider"], + ["WALLET_PROJECT_ID", "Wallet provider project ID"], + ["WALLET_API_KEY", "Wallet provider API key"], + ["DEPOSIT_WALLET_ADDRESS", "Polymarket deposit-wallet address"], + ["POLYMARKET_SIGNATURE_TYPE", "Polymarket signature type"], ["POLYMARKET_CLOB_API_KEY", "Polymarket CLOB API key"], ["POLYMARKET_CLOB_SECRET", "Polymarket CLOB API secret"], ["POLYMARKET_CLOB_PASSPHRASE", "Polymarket CLOB passphrase"], + ["SETTLEMENT_ASSET", "Settlement asset"], + ["SETTLEMENT_CHAIN", "Settlement chain"], ["AUDIT_LOG_STORE", "Durable audit log store"], + ["ADMIN_ALERT_EMAIL", "Admin alert destination"], ]; function providerStatus() { @@ -13,23 +24,43 @@ function providerStatus() { key, label, configured: Boolean(process.env[key]), + expected: key === "POLYMARKET_SIGNATURE_TYPE" ? "3 for new deposit-wallet API users" : undefined, })); } function liveTradingReady() { - return providerStatus().every((x) => x.configured) && process.env.LIVE_TRADING_ENABLED === "true"; + const requiredConfigured = providerStatus().every((x) => x.configured); + const liveFlagEnabled = process.env.LIVE_TRADING_ENABLED === "true"; + const signatureTypeOk = String(process.env.POLYMARKET_SIGNATURE_TYPE || "") === "3"; + const chainOk = String(process.env.POLYMARKET_CHAIN_ID || "137") === "137"; + return requiredConfigured && liveFlagEnabled && signatureTypeOk && chainOk; } function baseStatus() { const providers = providerStatus(); + const liveFlagEnabled = process.env.LIVE_TRADING_ENABLED === "true"; + const signatureTypeOk = String(process.env.POLYMARKET_SIGNATURE_TYPE || "") === "3"; + const chainOk = String(process.env.POLYMARKET_CHAIN_ID || "137") === "137"; + const missing = providers.filter((x) => !x.configured).map((x) => x.label); + if (!liveFlagEnabled) missing.push("LIVE_TRADING_ENABLED=true after final approval"); + if (!signatureTypeOk) missing.push("POLYMARKET_SIGNATURE_TYPE=3 for deposit-wallet users"); + if (!chainOk) missing.push("POLYMARKET_CHAIN_ID=137"); return { ok: true, live_trading_enabled: liveTradingReady(), + live_flag_enabled: liveFlagEnabled, + signature_type_ok: signatureTypeOk, + chain_ok: chainOk, locked_reason: liveTradingReady() ? null - : "Live trading is locked until KYC, payments, wallet signing, CLOB credentials, audit storage, and LIVE_TRADING_ENABLED=true are configured.", + : "Live trading is locked until eligibility, payments, wallet/deposit-wallet signing, Polymarket CLOB credentials, audit storage, monitoring, and LIVE_TRADING_ENABLED=true are configured.", providers, - next_required: providers.filter((x) => !x.configured).map((x) => x.label), + next_required: missing, + docs: { + polymarket_overview: "https://docs.polymarket.com/trading/overview", + polymarket_quickstart: "https://docs.polymarket.com/trading/quickstart", + deposit_wallets: "https://docs.polymarket.com/trading/deposit-wallets", + }, }; } diff --git a/index.html b/index.html index 959a17e..fc286b5 100644 --- a/index.html +++ b/index.html @@ -2259,8 +2259,9 @@ function renderLiveBackendStatus(){ const root=$("liveBackendStatus");if(!root)return; const s=LIVE_BACKEND_STATUS; if(!s){root.innerHTML="Checking backend readiness...";return;} - const providers=(s.providers||[]).map(p=>`
${esc(p.label)}${p.configured?"configured":"missing"}
`).join(""); - root.innerHTML=`${s.live_trading_enabled?"Live trading unlocked":"Live trading locked"}
${esc(s.locked_reason||"All required backend providers are configured.")}
${providers}`; + const providers=(s.providers||[]).map(p=>`
${esc(p.label)}${p.expected?`
${esc(p.expected)}
`:""}
${p.configured?"configured":"missing"}
`).join(""); + const next=(s.next_required||[]).slice(0,8).map(x=>`
  • ${esc(x)}
  • `).join(""); + root.innerHTML=`${s.live_trading_enabled?"Live trading unlocked":"Live trading locked"}
    ${esc(s.locked_reason||"All required backend providers are configured.")}
    ${providers}${next?`
    Next setup items
    `:""}
    Live execution stays disabled until every provider is configured and final approval flips LIVE_TRADING_ENABLED=true.
    `; } async function dryRunLiveOrderIntent(){ const s=loadLiveState();