Vest platform: a client for Vest Markets, traded on a session the extension relays

Vest (next.vestmarkets.com) is a perps prop firm: index, metal and energy
perps on CME hours, plus stocks, FX and crypto. It joins as a fourth
platform, 'vest', on the DXtrade engine paths. Those are now keyed by
isNotionalPlatform() instead of === 'dxtrade': the firm's own symbols,
percent fees, notional sizing from volatility, and a scheduler lane of its
own.

- Login is relayed, not stored. Vest signs people in with Google through
  Privy and renews the session with a device key the browser won't export.
  Extension 0.17.0's vest-relay.js reads the token the Vest app renews for
  itself (~15 min). It renews nothing, so the tab is never logged out. The
  background script posts that token to POST /api/vest/session, which holds
  it in memory only. With no Vest tab open on a machine that trades Vest,
  the extension opens one.
- The firm's credential is the Vest login's wallet address. The dashboard's
  form offers the relayed wallet with one click.
- VestClient (lib/vest-class.ts), mapped from the web app's traffic and code
  since Vest publishes no API:
  - Reads the capital accounts, balances (free amount plus position
    collateral), positions and open orders with the user token.
  - Mints per-account tokens for orders and transactions.
  - Names accounts for their rules (V50K-E-D3-T10-34, V50K-F-D3-34,
    V25K-I-7) so account-type prefixes can match.
  - Takes Vest's own max-drawdown and daily-loss floors. dayStartBalance =
    floor + the type's limit, so the engine's room is never more than
    Vest's.
  - Uses each symbol's taker fee and margin rate from exchangeInfo, and
    hourly volatility over in-session hours only.
  - Places take-profit and stop as position legs, which Vest cancels as an
    OCO pair.
- Daily P&L and fund rows come from /v3/transactions by Vest's 20:00 ET
  day. A books check holds an account, naming the transaction types, when
  the balance and the transactions disagree.
- scripts/check-vest.mjs (in npm run check): Vest's day across DST, account
  names, parsing, volatility gaps, market hours, the session store.

Not yet run against Vest with a live session: the order and exit bodies
come from the app's code, and the transaction classification from its enum.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Brandon Li
2026-10-26 14:19:31 -05:00
co-authored by Claude Opus 5.5
parent 5ec5abde6e
commit 96fdd9ca23
22 changed files with 2520 additions and 28 deletions
+106
View File
@@ -12,6 +12,9 @@
* ready at all times; a run happens because someone asked for one.
*
* On a firm site, the person's 2FA code for it shows in a corner chip.
*
* A signed-in Vest tab's session is relayed to the dashboard, whose Vest client
* trades with it (relayVestSession).
*/
const DEFAULTS = {
@@ -1185,6 +1188,109 @@ async function tick() {
} catch (err) {
await setState({ connected: true, error: `2FA chip: ${err.message}` });
}
try {
await relayVestSession(cfg);
} catch (err) {
await setState({ connected: true, vest: `Vest relay: ${err.message}` });
}
}
// ── Vest: relay the signed-in tab's session to the dashboard ────────────────
//
// Vest signs people in through Google in the browser and renews the session
// with a device key the browser won't hand out, so the dashboard cannot log in
// by itself. vest-relay.js, in the Vest tab, keeps the latest access token the
// Vest app renewed for itself (~15 minutes each); this lifts it and posts it to
// the dashboard whenever it changes. Nothing here renews or signs anything: the
// session stays the app's.
const VEST_PATTERN = 'https://next.vestmarkets.com/*';
const VEST_URL = 'https://next.vestmarkets.com/portfolio';
const VEST_EVERY_MS = 10_000;
/** A Vest tab opened for the relay isn't opened again for this long. */
const VEST_REOPEN_MS = 10 * 60_000;
let vestLastCheck = 0;
let vestLastRelayed = '';
let vestOpenedAt = 0;
/** Runs in the Vest tab's MAIN world: the session vest-relay.js holds, while
* it has life left. Self-contained. */
function pageVestSession() {
const s = window.__afVestSession;
return { hooked: window.__afVestHook === true, session: s && s.expiresAt > Date.now() + 30000 ? s : null };
}
/** The wallets the dashboard's Vest firms trade; [] from an older dashboard. */
async function fetchVestWanted(cfg) {
try {
const res = await fetch(`${cfg.apiBase}/api/vest/session`, { cache: 'no-store' });
if (!res.ok) return [];
const body = await res.json();
return Array.isArray(body.wanted) ? body.wanted : [];
} catch {
return [];
}
}
async function relayVestSession(cfg) {
const now = Date.now();
if (now - vestLastCheck < VEST_EVERY_MS) return;
vestLastCheck = now;
const tabs = (await chrome.tabs.query({ url: VEST_PATTERN })).filter((t) => /^https:/.test(t.url || ''));
if (tabs.length === 0) {
// This machine trades Vest: open the app in the background. It signs
// itself back in from its 30-day session, and the hook catches that.
const wanted = await fetchVestWanted(cfg);
if (wanted.length === 0) return;
if (now - vestOpenedAt > VEST_REOPEN_MS) {
vestOpenedAt = now;
await chrome.tabs.create({ url: VEST_URL, active: false });
await setState({ vest: 'Opened a Vest tab to relay its session' });
} else {
await setState({ vest: 'No Vest tab open' });
}
return;
}
let found = null;
for (const tab of tabs) {
// A discarded tab stops renewing the session; keep Chrome from it.
if (tab.autoDiscardable !== false) chrome.tabs.update(tab.id, { autoDiscardable: false }).catch(() => {});
const [injection] = await chrome.scripting.executeScript({
target: { tabId: tab.id }, world: 'MAIN', func: pageVestSession,
}).catch(() => [null]);
const out = injection?.result;
if (out && !out.hooked) {
// A tab open from before this build: hook it now, and its app's
// next renewal is caught.
await chrome.scripting.executeScript({ target: { tabId: tab.id }, world: 'MAIN', files: ['vest-relay.js'] }).catch(() => {});
}
if (out?.session) { found = out.session; break; }
}
if (!found) {
await setState({ vest: 'Vest tab open — waiting for its session (sign in there if it shows Log In)' });
return;
}
const fingerprint = `${found.expiresAt}:${found.accessToken.length}:${found.accessToken.slice(-16)}`;
if (fingerprint === vestLastRelayed) return;
const res = await fetch(`${cfg.apiBase}/api/vest/session`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
accessToken: found.accessToken, expiresAt: found.expiresAt, primaryAddr: found.primaryAddr, userId: found.userId,
}),
});
const body = await res.json().catch(() => ({}));
if (res.status === 404) throw new Error('this dashboard is too old for the Vest relay');
if (!res.ok) throw new Error(`dashboard refused the session: ${body.reason || body.error || `HTTP ${res.status}`}`);
vestLastRelayed = fingerprint;
const short = `${found.primaryAddr.slice(0, 6)}…${found.primaryAddr.slice(-4)}`;
const mins = Math.max(0, Math.round((found.expiresAt - Date.now()) / 60000));
await setState({ vest: `Relayed ${short}${body.used ? '' : ' (no Vest firm here uses this wallet)'} · good ${mins}m` });
}
// ── 2FA: the person's authenticator code for the firm site you are on ───────