Add live money configuration setup

This commit is contained in:
Theodore Song
2026-07-12 16:58:10 -04:00
parent c4acfd047a
commit f66155da69
6 changed files with 157 additions and 17 deletions
+40
View File
@@ -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=
+1
View File
@@ -3,3 +3,4 @@ node_modules/
.vercel
.claude/
.env*
!.env.example
+26 -11
View File
@@ -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. <https://vercel.com> → 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.
+53 -1
View File
@@ -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`.
+34 -3
View File
@@ -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",
},
};
}
+3 -2
View File
@@ -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=>`<div class="leader-row"><span>${esc(p.label)}</span><b class="${p.configured?"pos-val":"neg-val"}">${p.configured?"configured":"missing"}</b></div>`).join("");
root.innerHTML=`<b>${s.live_trading_enabled?"Live trading unlocked":"Live trading locked"}</b><div class="small muted" style="margin:6px 0">${esc(s.locked_reason||"All required backend providers are configured.")}</div>${providers}`;
const providers=(s.providers||[]).map(p=>`<div class="leader-row"><span>${esc(p.label)}${p.expected?`<div class="small muted">${esc(p.expected)}</div>`:""}</span><b class="${p.configured?"pos-val":"neg-val"}">${p.configured?"configured":"missing"}</b></div>`).join("");
const next=(s.next_required||[]).slice(0,8).map(x=>`<li>${esc(x)}</li>`).join("");
root.innerHTML=`<b>${s.live_trading_enabled?"Live trading unlocked":"Live trading locked"}</b><div class="small muted" style="margin:6px 0">${esc(s.locked_reason||"All required backend providers are configured.")}</div>${providers}${next?`<div class="locked-panel" style="margin-top:10px"><b>Next setup items</b><ul>${next}</ul></div>`:""}<div class="small muted" style="margin-top:8px">Live execution stays disabled until every provider is configured and final approval flips LIVE_TRADING_ENABLED=true.</div>`;
}
async function dryRunLiveOrderIntent(){
const s=loadLiveState();