x402-smartperps / tree / src/lite.js ยท raw (this view has old GitHub links rewritten for the mirror; raw is byte-exact)
// SmartPerps client used by the stdio MCP server (and the npm package once publishing resumes). Free tier: the hosted
// preview (bias label, cohort traders long/short, snapshot age; 10/min per IP). Notional, flows, liquidation price bands,
// top positions, scans and wallet profiles: paid API over x402 (see paid.js).
import { withDeadline } from './deadline.js';

export const API_BASE = 'https://api.youraitools.co/smartperps';
export const FALLBACK_API_BASE = 'https://smartperps.agentgate.workers.dev';
export const PAID_URL = `${API_BASE}/v1/coin`;
export const PRICES = { lite: '$0.003', coin: '$0.02', scan: '$0.03', wallet: '$0.01' };
export const DISCLAIMER = 'Not financial advice. Past performance does not guarantee future results. Read-only analytics of public Hyperliquid positions; SmartPerps never trades, holds funds or keys.';
export const FULL_DETAILS = `Notional and flows: paid API ${API_BASE}/v1/lite?symbol=<ticker> (${PRICES.lite}); entries, leverage, liquidation price bands and top positions: /v1/coin (${PRICES.coin}); market scan /v1/scan (${PRICES.scan}); account profile /v1/wallet?address=0x... (${PRICES.wallet}). USDC over x402 or a prepaid credits key.`;

/** Validate the symbol argument locally (no network). Returns { symbol } or { error }. */
export function toSymbol(args = {}) {
  const v = args.symbol ?? args.coin ?? args.asset ?? args.ticker;
  if (typeof v !== 'string' || !v.trim()) return { error: '"symbol" is required: a Hyperliquid perp ticker, e.g. BTC' };
  let s = v.trim().replace(/[\s_/]+/g, '-');
  if (!/^k[A-Z0-9]+$/.test(s)) s = s.toUpperCase();
  s = s.replace(/-?(PERP|PERPETUAL|SWAP)$/i, '').replace(/-?(USDT|USDC|USD)$/i, '').replace(/-+$/, '');
  if (!/^k?[A-Z0-9]{1,15}$/.test(s)) return { error: '"symbol" must be a ticker like BTC, ETH, SOL or HYPE' };
  return { symbol: s };
}
export function toAddress(args = {}) {
  const v = args.address ?? args.user ?? args.wallet;
  if (typeof v !== 'string' || !/^0x[0-9a-fA-F]{40}$/.test(v.trim())) return { error: '"address" must be a Hyperliquid account (0x + 40 hex)' };
  return { address: v.trim().toLowerCase() };
}

/** Free hosted preview. Returns the preview JSON or { error, message }. */
export async function preview(symbol, { fetchImpl = globalThis.fetch, apiBase = API_BASE, ms = 30000 } = {}) {
  try {
    const res = await withDeadline(fetchImpl(`${apiBase.replace(/\/+$/, '')}/v1/preview?symbol=${encodeURIComponent(symbol)}`, { headers: { accept: 'application/json', 'user-agent': 'smartperps-mcp' } }), ms, 'SmartPerps preview');
    const j = await res.json().catch(() => null);
    if (!res.ok) return { error: j?.error || `http_${res.status}`, message: j?.message || `SmartPerps preview answered HTTP ${res.status}` };
    return j;
  } catch (e) { return { error: 'network', message: String(e?.message || e).slice(0, 200) }; }
}

agentgate-source: code mirror on Cloudflare Pages. All repos