{"version":3,"file":"rpc-provider.mjs","names":[],"sources":["../../../src/services/rpc-provider.ts"],"sourcesContent":["/**\n * Multi-RPC Provider — fault-tolerant RPC access with automatic failover.\n *\n * Supports multiple RPC providers per chain, with:\n * - Priority-ordered provider list\n * - Automatic failover on error or timeout (>2s)\n * - Rate limit detection (429) with exponential backoff\n * - Circuit breaker (5 failures in 60s → skip provider for 5 min)\n * - User-configurable via plugin config\n */\n\nimport { createPublicClient, http, type PublicClient, type Chain } from 'viem';\nimport { base, mainnet, arbitrum, optimism, polygon } from 'viem/chains';\n\n// ── Types ───────────────────────────────────────────────────────────────────\n\nexport interface RpcProviderConfig {\n  url: string;\n  name: string;\n  priority: number; // lower = higher priority\n  apiKeyEnv?: string; // env var name for API key (appended to URL)\n  fullUrlEnv?: string; // env var that provides the complete URL (e.g. QuickNode endpoints)\n}\n\ninterface ProviderHealth {\n  failures: number;\n  lastFailure: number;\n  circuitOpenUntil: number; // timestamp — skip until this time\n  backoffMs: number;\n  lastRateLimited: number;\n}\n\nexport interface RpcManagerConfig {\n  /** Provider overrides per chain ID. Key is chain ID number as string. */\n  providers?: Record<string, RpcProviderConfig[]>;\n  /** Global timeout for RPC calls in ms. Default 3000. */\n  timeoutMs?: number;\n  /** Max consecutive failures before circuit opens. Default 5. */\n  circuitThreshold?: number;\n  /** How long circuit stays open in ms. Default 300_000 (5 min). */\n  circuitResetMs?: number;\n  /** Enable MEV protection via private transaction RPCs (Flashbots, MEV Blocker).\n   *  When true, write transactions on supported chains route through private mempools.\n   *  Default: true. */\n  mevProtection?: boolean;\n}\n\n// ── Default Providers ───────────────────────────────────────────────────────\n\n// ── Custom & QuickNode RPC env vars ─────────────────────────────────────────\n// Users can set these env vars to override RPC endpoints:\n//   RPC_URL               — custom RPC for all chains (lowest priority custom)\n//   RPC_URL_BASE          — custom RPC for Base (overrides RPC_URL for Base)\n//   RPC_URL_ETH           — custom RPC for Ethereum\n//   RPC_URL_ARB           — custom RPC for Arbitrum\n//   RPC_URL_OP            — custom RPC for Optimism\n//   RPC_URL_POLYGON       — custom RPC for Polygon\n//   QUICKNODE_ENDPOINT    — QuickNode endpoint URL for all chains\n//   QUICKNODE_ENDPOINT_BASE, _ETH, _ARB, _OP, _POLYGON — per-chain QuickNode\n\nconst CUSTOM_RPC_ENV: Record<number, string> = {\n  8453: 'RPC_URL_BASE',\n  1: 'RPC_URL_ETH',\n  42161: 'RPC_URL_ARB',\n  10: 'RPC_URL_OP',\n  137: 'RPC_URL_POLYGON',\n};\n\nconst QUICKNODE_ENV: Record<number, string> = {\n  8453: 'QUICKNODE_ENDPOINT_BASE',\n  1: 'QUICKNODE_ENDPOINT_ETH',\n  42161: 'QUICKNODE_ENDPOINT_ARB',\n  10: 'QUICKNODE_ENDPOINT_OP',\n  137: 'QUICKNODE_ENDPOINT_POLYGON',\n};\n\nconst DEFAULT_PROVIDERS: Record<number, RpcProviderConfig[]> = {\n  // Base (8453)\n  [8453]: [\n    { url: '', name: 'QuickNode', priority: 1, fullUrlEnv: 'QUICKNODE_ENDPOINT_BASE' },\n    { url: 'https://base-mainnet.g.alchemy.com/v2/', name: 'Alchemy', priority: 2, apiKeyEnv: 'ALCHEMY_API_KEY' },\n    { url: 'https://base.llamarpc.com', name: 'LlamaNodes', priority: 3 },\n    { url: 'https://mainnet.base.org', name: 'Base Public', priority: 4 },\n    { url: 'https://base.drpc.org', name: 'dRPC', priority: 5 },\n    { url: 'https://base.meowrpc.com', name: 'MeowRPC', priority: 6 },\n    { url: 'https://1rpc.io/base', name: '1RPC', priority: 7 },\n  ],\n  // Ethereum (1)\n  [1]: [\n    { url: '', name: 'QuickNode', priority: 1, fullUrlEnv: 'QUICKNODE_ENDPOINT_ETH' },\n    { url: 'https://eth-mainnet.g.alchemy.com/v2/', name: 'Alchemy', priority: 2, apiKeyEnv: 'ALCHEMY_API_KEY' },\n    { url: 'https://eth.llamarpc.com', name: 'LlamaNodes', priority: 3 },\n    { url: 'https://ethereum.publicnode.com', name: 'PublicNode', priority: 4 },\n    { url: 'https://eth.drpc.org', name: 'dRPC', priority: 5 },\n    { url: 'https://1rpc.io/eth', name: '1RPC', priority: 6 },\n    { url: 'https://rpc.ankr.com/eth', name: 'Ankr', priority: 7 },\n  ],\n  // Arbitrum (42161)\n  [42161]: [\n    { url: '', name: 'QuickNode', priority: 1, fullUrlEnv: 'QUICKNODE_ENDPOINT_ARB' },\n    { url: 'https://arb-mainnet.g.alchemy.com/v2/', name: 'Alchemy', priority: 2, apiKeyEnv: 'ALCHEMY_API_KEY' },\n    { url: 'https://arbitrum.llamarpc.com', name: 'LlamaNodes', priority: 3 },\n    { url: 'https://arb1.arbitrum.io/rpc', name: 'Arbitrum Public', priority: 4 },\n    { url: 'https://arbitrum.drpc.org', name: 'dRPC', priority: 5 },\n    { url: 'https://1rpc.io/arb', name: '1RPC', priority: 6 },\n  ],\n  // Optimism (10)\n  [10]: [\n    { url: '', name: 'QuickNode', priority: 1, fullUrlEnv: 'QUICKNODE_ENDPOINT_OP' },\n    { url: 'https://opt-mainnet.g.alchemy.com/v2/', name: 'Alchemy', priority: 2, apiKeyEnv: 'ALCHEMY_API_KEY' },\n    { url: 'https://optimism.llamarpc.com', name: 'LlamaNodes', priority: 3 },\n    { url: 'https://mainnet.optimism.io', name: 'OP Public', priority: 4 },\n    { url: 'https://optimism.drpc.org', name: 'dRPC', priority: 5 },\n    { url: 'https://1rpc.io/op', name: '1RPC', priority: 6 },\n  ],\n  // Polygon (137)\n  [137]: [\n    { url: '', name: 'QuickNode', priority: 1, fullUrlEnv: 'QUICKNODE_ENDPOINT_POLYGON' },\n    { url: 'https://polygon-mainnet.g.alchemy.com/v2/', name: 'Alchemy', priority: 2, apiKeyEnv: 'ALCHEMY_API_KEY' },\n    { url: 'https://polygon.llamarpc.com', name: 'LlamaNodes', priority: 3 },\n    { url: 'https://polygon-rpc.com', name: 'Polygon Public', priority: 4 },\n    { url: 'https://polygon.drpc.org', name: 'dRPC', priority: 5 },\n    { url: 'https://1rpc.io/matic', name: '1RPC', priority: 6 },\n  ],\n};\n\nconst CHAIN_MAP: Record<number, Chain> = {\n  1: mainnet,\n  8453: base,\n  42161: arbitrum,\n  10: optimism,\n  137: polygon,\n};\n\nconst CHAIN_NAME_TO_ID: Record<string, number> = {\n  ethereum: 1, eth: 1, mainnet: 1,\n  base: 8453,\n  arbitrum: 42161, arb: 42161,\n  optimism: 10, op: 10,\n  polygon: 137, matic: 137,\n};\n\n// ── MEV Protection RPCs ─────────────────────────────────────────────────────\n// Private transaction RPCs that submit to block builders directly, bypassing\n// the public mempool. Protects against sandwich attacks and frontrunning.\n\nexport interface MevRpcConfig {\n  url: string;\n  name: string;\n  /** Which chain IDs this MEV RPC supports */\n  chains: number[];\n}\n\nconst MEV_PROTECTION_RPCS: MevRpcConfig[] = [\n  {\n    url: 'https://rpc.flashbots.net',\n    name: 'Flashbots Protect',\n    chains: [1], // Ethereum mainnet only\n  },\n  {\n    url: 'https://rpc.mevblocker.io',\n    name: 'MEV Blocker',\n    chains: [1], // Ethereum mainnet only\n  },\n  {\n    url: 'https://rpc.flashbots.net/fast',\n    name: 'Flashbots Fast',\n    chains: [1], // Ethereum mainnet, faster inclusion\n  },\n  {\n    url: 'https://base.flashbots.net',\n    name: 'Flashbots Base',\n    chains: [8453], // Base\n  },\n];\n\n// ── Circuit Breaker State ───────────────────────────────────────────────────\n\nconst healthMap = new Map<string, ProviderHealth>();\n\nfunction getHealth(key: string): ProviderHealth {\n  let h = healthMap.get(key);\n  if (!h) {\n    h = { failures: 0, lastFailure: 0, circuitOpenUntil: 0, backoffMs: 0, lastRateLimited: 0 };\n    healthMap.set(key, h);\n  }\n  return h;\n}\n\nfunction recordFailure(key: string, isRateLimit: boolean, config: { circuitThreshold: number; circuitResetMs: number }): void {\n  const h = getHealth(key);\n  h.failures++;\n  h.lastFailure = Date.now();\n\n  if (isRateLimit) {\n    h.lastRateLimited = Date.now();\n    h.backoffMs = Math.min((h.backoffMs || 1000) * 2, 60_000);\n  }\n\n  if (h.failures >= config.circuitThreshold) {\n    h.circuitOpenUntil = Date.now() + config.circuitResetMs;\n  }\n}\n\nfunction recordSuccess(key: string): void {\n  const h = getHealth(key);\n  h.failures = 0;\n  h.backoffMs = 0;\n  h.circuitOpenUntil = 0;\n}\n\nfunction isAvailable(key: string): boolean {\n  const h = healthMap.get(key);\n  if (!h) return true;\n  if (h.circuitOpenUntil > Date.now()) return false;\n  if (h.lastRateLimited > 0 && Date.now() - h.lastRateLimited < h.backoffMs) return false;\n  return true;\n}\n\n// ── RPC Manager ─────────────────────────────────────────────────────────────\n\nexport class RpcManager {\n  private config: Required<RpcManagerConfig>;\n  private clientCache = new Map<string, PublicClient>();\n\n  constructor(userConfig: RpcManagerConfig = {}) {\n    this.config = {\n      providers: userConfig.providers ?? {},\n      timeoutMs: userConfig.timeoutMs ?? 3000,\n      circuitThreshold: userConfig.circuitThreshold ?? 5,\n      circuitResetMs: userConfig.circuitResetMs ?? 300_000,\n      mevProtection: userConfig.mevProtection ?? true,\n    };\n  }\n\n  /** Resolve a chain name or ID to a numeric chain ID. */\n  resolveChainId(chainInput: string | number): number {\n    if (typeof chainInput === 'number') return chainInput;\n    const num = parseInt(chainInput, 10);\n    if (!isNaN(num)) return num;\n    return CHAIN_NAME_TO_ID[chainInput.toLowerCase()] ?? 8453; // default Base\n  }\n\n  /** Get the ordered list of providers for a chain, filtered by health. */\n  getProviders(chainId: number): RpcProviderConfig[] {\n    // 1. Custom RPC URL from env vars (highest priority)\n    const custom: RpcProviderConfig[] = [];\n\n    // Per-chain custom RPC (e.g. RPC_URL_BASE)\n    const chainEnv = CUSTOM_RPC_ENV[chainId];\n    if (chainEnv && process.env[chainEnv]) {\n      custom.push({ url: process.env[chainEnv]!, name: 'Custom', priority: 0 });\n    }\n\n    // Generic custom RPC (e.g. RPC_URL) — only if no per-chain custom set\n    if (custom.length === 0 && process.env.RPC_URL) {\n      custom.push({ url: process.env.RPC_URL, name: 'Custom', priority: 0 });\n    }\n\n    // Generic QuickNode endpoint (QUICKNODE_ENDPOINT) — used when no per-chain\n    // QuickNode env var is set. Injected at priority 0.5 (after custom, before defaults).\n    const qnChainEnv = QUICKNODE_ENV[chainId];\n    const hasPerChainQn = qnChainEnv && process.env[qnChainEnv];\n    if (!hasPerChainQn && process.env.QUICKNODE_ENDPOINT) {\n      custom.push({ url: process.env.QUICKNODE_ENDPOINT, name: 'QuickNode', priority: 0 });\n    }\n\n    // 2. User config overrides or defaults\n    const userProviders = this.config.providers[String(chainId)];\n    const defaults = DEFAULT_PROVIDERS[chainId] ?? [];\n    const base = userProviders ?? defaults;\n\n    // Merge custom + base\n    const providers = [...custom, ...base];\n\n    return providers\n      .filter((p) => {\n        // Skip providers that need an API key we don't have\n        if (p.apiKeyEnv && !process.env[p.apiKeyEnv]) return false;\n        // Skip providers with fullUrlEnv when the env var isn't set\n        if (p.fullUrlEnv && !process.env[p.fullUrlEnv]) return false;\n        // Skip circuit-broken providers\n        const key = `${chainId}:${p.name}`;\n        return isAvailable(key);\n      })\n      .sort((a, b) => a.priority - b.priority);\n  }\n\n  /** Build the full RPC URL for a provider (append API key if needed). */\n  buildUrl(provider: RpcProviderConfig): string {\n    // Full URL from env var (e.g. QuickNode endpoint, custom RPC)\n    if (provider.fullUrlEnv) {\n      const fullUrl = process.env[provider.fullUrlEnv];\n      if (fullUrl) return fullUrl;\n    }\n    // API key appended to base URL (e.g. Alchemy)\n    if (provider.apiKeyEnv) {\n      const key = process.env[provider.apiKeyEnv];\n      if (key) return `${provider.url}${key}`;\n    }\n    return provider.url;\n  }\n\n  /**\n   * Get a viem PublicClient for the given chain.\n   * Tries providers in priority order, failing over on errors.\n   */\n  async getClient(chainInput: string | number = 'base'): Promise<PublicClient> {\n    const chainId = this.resolveChainId(chainInput);\n    const providers = this.getProviders(chainId);\n\n    if (providers.length === 0) {\n      throw new Error(\n        `No available RPC providers for chain ${chainId}. ` +\n        `Set ALCHEMY_API_KEY or configure custom providers.`,\n      );\n    }\n\n    // Try each provider in order\n    let lastError: Error | null = null;\n\n    for (const provider of providers) {\n      const cacheKey = `${chainId}:${provider.name}`;\n\n      // Return cached client if healthy\n      const cached = this.clientCache.get(cacheKey);\n      if (cached) return cached;\n\n      try {\n        const url = this.buildUrl(provider);\n        const chain = CHAIN_MAP[chainId];\n\n        const transport = http(url, { timeout: this.config.timeoutMs });\n        const client = createPublicClient({\n          chain,\n          transport,\n        });\n\n        // Validate with a quick call\n        await client.getBlockNumber();\n\n        recordSuccess(cacheKey);\n        this.clientCache.set(cacheKey, client as PublicClient);\n        return client as PublicClient;\n      } catch (err) {\n        lastError = err as Error;\n        // H9: Sanitize any API keys that may appear in error messages\n        if (lastError.message) {\n          lastError.message = lastError.message.replace(\n            /[?&/][a-zA-Z0-9_\\-]{20,}/g,\n            '/[REDACTED]'\n          );\n        }\n        const isRateLimit = lastError.message.includes('429') ||\n          lastError.message.toLowerCase().includes('rate limit');\n\n        recordFailure(cacheKey, isRateLimit, {\n          circuitThreshold: this.config.circuitThreshold,\n          circuitResetMs: this.config.circuitResetMs,\n        });\n\n        // Remove cached client on failure\n        this.clientCache.delete(cacheKey);\n      }\n    }\n\n    // H9: Sanitize API keys from error messages before exposing to LLM\n    const sanitizedError = lastError?.message?.replace(\n      /[?&/][a-zA-Z0-9_\\-]{20,}/g,\n      '/[REDACTED]'\n    ) ?? 'Unknown error';\n    throw new Error(\n      `All RPC providers failed for chain ${chainId}. Last error: ${sanitizedError}`,\n    );\n  }\n\n  /** Clear all cached clients (useful when switching chains). */\n  clearCache(): void {\n    this.clientCache.clear();\n  }\n\n  /** Get health status of all providers (for diagnostics). */\n  getHealthReport(chainId: number): Array<{\n    name: string;\n    url: string;\n    available: boolean;\n    failures: number;\n    circuitOpen: boolean;\n  }> {\n    const providers = DEFAULT_PROVIDERS[chainId] ?? [];\n    return providers.map((p) => {\n      const key = `${chainId}:${p.name}`;\n      const h = healthMap.get(key);\n      return {\n        name: p.name,\n        url: p.url,\n        available: isAvailable(key),\n        failures: h?.failures ?? 0,\n        circuitOpen: (h?.circuitOpenUntil ?? 0) > Date.now(),\n      };\n    });\n  }\n\n  /** List supported chain IDs. */\n  getSupportedChains(): number[] {\n    return Object.keys(DEFAULT_PROVIDERS).map(Number);\n  }\n\n  // ── MEV Protection ──────────────────────────────────────────────────────\n\n  /** Check if MEV protection is enabled. */\n  isMevProtectionEnabled(): boolean {\n    return this.config.mevProtection;\n  }\n\n  /**\n   * Get MEV-protected RPC URLs for a chain.\n   * Returns private transaction RPCs that bypass the public mempool.\n   * Falls back to empty array if no MEV RPCs are available for the chain.\n   */\n  getMevRpcs(chainId: number): MevRpcConfig[] {\n    if (!this.config.mevProtection) return [];\n    return MEV_PROTECTION_RPCS.filter(r => r.chains.includes(chainId));\n  }\n\n  /**\n   * Get a viem http transport configured for MEV-protected submission.\n   * Uses Flashbots Protect (primary) with MEV Blocker as fallback.\n   * Returns null if no MEV RPCs are available for the chain.\n   */\n  getMevTransport(chainId: number): ReturnType<typeof http> | null {\n    const rpcs = this.getMevRpcs(chainId);\n    if (rpcs.length === 0) return null;\n\n    // Use first available MEV RPC, with health check filtering\n    for (const rpc of rpcs) {\n      const key = `mev:${chainId}:${rpc.name}`;\n      if (isAvailable(key)) {\n        return http(rpc.url, { timeout: this.config.timeoutMs });\n      }\n    }\n\n    // All circuit-broken — return first anyway (circuit will reset eventually)\n    return http(rpcs[0]!.url, { timeout: this.config.timeoutMs });\n  }\n\n  /**\n   * Record a MEV RPC failure (for circuit breaker tracking).\n   */\n  recordMevFailure(chainId: number, rpcName: string, isRateLimit = false): void {\n    const key = `mev:${chainId}:${rpcName}`;\n    recordFailure(key, isRateLimit, {\n      circuitThreshold: this.config.circuitThreshold,\n      circuitResetMs: this.config.circuitResetMs,\n    });\n  }\n\n  /**\n   * Record a MEV RPC success.\n   */\n  recordMevSuccess(chainId: number, rpcName: string): void {\n    recordSuccess(`mev:${chainId}:${rpcName}`);\n  }\n}\n\n// ── Singleton ───────────────────────────────────────────────────────────────\n\nlet _instance: RpcManager | null = null;\n\nexport function getRpcManager(config?: RpcManagerConfig): RpcManager {\n  if (!_instance) {\n    _instance = new RpcManager(config);\n  }\n  return _instance;\n}\n\nexport function resetRpcManager(): void {\n  _instance = null;\n  healthMap.clear();\n}\n"],"mappings":"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"}