diff --git a/scripts/patch-clob-client.cjs b/scripts/patch-clob-client.cjs index 4d66dc3..92c08e5 100644 --- a/scripts/patch-clob-client.cjs +++ b/scripts/patch-clob-client.cjs @@ -8,6 +8,9 @@ * - Adds HttpsProxyAgent import to http-helpers/index.js * - Injects proxy agent into every axios request to polymarket.com * - Reads PROXY_URL from process.env at runtime + * + * Uses regex matching so it works regardless of code formatting + * (minified, prettified, different whitespace, etc.) */ const fs = require('fs'); @@ -37,14 +40,8 @@ if (code.includes('getProxyAgent')) { process.exit(0); } -// Find the line after the axios import to inject proxy code -const AXIOS_IMPORT = `require("axios")`; -if (!code.includes(AXIOS_IMPORT)) { - console.error('[patch] Could not find axios import in http-helpers — skipping'); - process.exit(0); -} +// ── Step 1: Inject proxy helper code ──────────────────────────────────────── -// Inject proxy imports and helper after axios import line const PROXY_CODE = ` // Proxy support for Polymarket API (auto-patched by scripts/patch-clob-client.cjs) const https_proxy_agent_1 = require("https-proxy-agent"); @@ -53,20 +50,45 @@ const getProxyAgent = () => { return new https_proxy_agent_1.HttpsProxyAgent(process.env.PROXY_URL); } return undefined; -};`; +}; +`; -// Insert after the browser_or_node require line -const INSERT_AFTER = `require("browser-or-node");`; -if (!code.includes(INSERT_AFTER)) { - console.error('[patch] Could not find browser-or-node import — skipping'); +// Try multiple insertion points — different versions format differently +const insertionPatterns = [ + // Pattern 1: require("browser-or-node") with semicolon + /require\s*\(\s*["']browser-or-node["']\s*\)\s*;/, + // Pattern 2: require("axios") line (fallback) + /require\s*\(\s*["']axios["']\s*\)\s*;/, + // Pattern 3: any require line near the top (last resort) + /const\s+\w+\s*=\s*require\s*\(\s*["']axios["']\s*\)/, +]; + +let inserted = false; +for (const pattern of insertionPatterns) { + const match = code.match(pattern); + if (match) { + code = code.replace(match[0], match[0] + PROXY_CODE); + console.log(`[patch] Injected proxy helper after: ${match[0].substring(0, 50)}...`); + inserted = true; + break; + } +} + +if (!inserted) { + console.error('[patch] Could not find insertion point for proxy code — skipping'); process.exit(0); } -code = code.replace(INSERT_AFTER, INSERT_AFTER + PROXY_CODE); +// ── Step 2: Patch the request config to inject proxy agent ────────────────── -// Patch the request function to inject proxy agent -const REQUEST_CONFIG = `const config = { method, url: endpoint, headers, data, params };`; -const PATCHED_CONFIG = `const config = { method, url: endpoint, headers, data, params }; +// Match: const config = { method, url: endpoint, headers, data, params } +// with any whitespace variation (spaces, newlines, tabs) +const configRegex = /const\s+config\s*=\s*\{\s*method\s*,\s*url\s*:\s*endpoint\s*,\s*headers\s*,\s*data\s*,\s*params\s*\}\s*;/; + +const configMatch = code.match(configRegex); + +if (configMatch) { + const PROXY_INJECT = `${configMatch[0]} // Add proxy agent for Polymarket API if (endpoint && endpoint.includes('polymarket.com')) { const agent = getProxyAgent(); @@ -75,13 +97,51 @@ const PATCHED_CONFIG = `const config = { method, url: endpoint, headers, data, p config.proxy = false; } }`; + code = code.replace(configMatch[0], PROXY_INJECT); + console.log('[patch] Injected proxy agent into request config'); +} else { + // Fallback: try to find any config object creation with method/endpoint + // and inject proxy after it + const fallbackRegex = /(?:const|let|var)\s+config\s*=\s*\{[^}]*method[^}]*endpoint[^}]*\}\s*;/; + const fallbackMatch = code.match(fallbackRegex); -if (!code.includes(REQUEST_CONFIG)) { - console.error('[patch] Could not find request config line — skipping'); - process.exit(0); + if (fallbackMatch) { + const PROXY_INJECT = `${fallbackMatch[0]} + // Add proxy agent for Polymarket API + if (endpoint && endpoint.includes('polymarket.com')) { + const agent = getProxyAgent(); + if (agent) { + config.httpsAgent = agent; + config.proxy = false; + } + }`; + code = code.replace(fallbackMatch[0], PROXY_INJECT); + console.log('[patch] Injected proxy agent into request config (fallback match)'); + } else { + // Last resort: find the axios request/call and inject before it + const axiosCallRegex = /axios_1\.default\s*\(\s*config\s*\)/; + const axiosMatch = code.match(axiosCallRegex); + + if (axiosMatch) { + const PROXY_INJECT = `// Add proxy agent for Polymarket API + if (config.url && config.url.includes('polymarket.com')) { + const agent = getProxyAgent(); + if (agent) { + config.httpsAgent = agent; + config.proxy = false; + } + } + ${axiosMatch[0]}`; + code = code.replace(axiosMatch[0], PROXY_INJECT); + console.log('[patch] Injected proxy agent before axios call (last resort)'); + } else { + console.error('[patch] Could not find request config or axios call — skipping'); + console.error('[patch] File content preview (first 2000 chars):'); + console.error(code.substring(0, 2000)); + process.exit(0); + } + } } -code = code.replace(REQUEST_CONFIG, PATCHED_CONFIG); - fs.writeFileSync(TARGET, code, 'utf8'); console.log('[patch] @polymarket/clob-client patched with proxy support ✅'); diff --git a/src/utils/proxy.js b/src/utils/proxy.js index 2520214..aac93de 100644 --- a/src/utils/proxy.js +++ b/src/utils/proxy.js @@ -86,6 +86,7 @@ export async function proxyFetch(url, opts = {}) { */ async function checkOutboundIP() { const IP_SERVICE = 'https://api.ipify.org?format=json'; + const GEOBLOCK_API = 'https://polymarket.com/api/geoblock'; // 1. Check VPS direct IP try { @@ -98,7 +99,22 @@ async function checkOutboundIP() { logger.warn('Could not detect VPS direct IP'); } - // 2. Check proxied IP (what Polymarket will see) + // 2. Check if VPS direct IP is geoblocked + try { + const geoResp = await fetch(GEOBLOCK_API, { signal: AbortSignal.timeout(10000) }); + if (geoResp.ok) { + const geo = await geoResp.json(); + if (geo.blocked) { + logger.warn(`VPS direct IP GEOBLOCKED — country: ${geo.country}, region: ${geo.region}`); + } else { + logger.info(`VPS direct IP NOT geoblocked — country: ${geo.country}`); + } + } + } catch { + logger.warn('Could not check VPS geoblock status'); + } + + // 3. Check proxied IP (what Polymarket will see) if (fetchDispatcher) { try { const proxyResp = await fetch(IP_SERVICE, { @@ -112,6 +128,28 @@ async function checkOutboundIP() { } catch { logger.warn('Could not detect proxy IP — proxy may not be working'); } + + // 4. Check if proxy IP is geoblocked + try { + const geoResp = await fetch(GEOBLOCK_API, { + dispatcher: fetchDispatcher, + signal: AbortSignal.timeout(10000), + }); + if (geoResp.ok) { + const geo = await geoResp.json(); + if (geo.blocked) { + logger.error('═══════════════════════════════════════════════════'); + logger.error(`PROXY IP GEOBLOCKED by Polymarket!`); + logger.error(`IP: ${geo.ip} | Country: ${geo.country} | Region: ${geo.region}`); + logger.error('Change PROXY_URL in .env to a proxy in an allowed region.'); + logger.error('═══════════════════════════════════════════════════'); + } else { + logger.success(`Proxy IP NOT geoblocked — country: ${geo.country} ✓`); + } + } + } catch { + logger.warn('Could not check proxy geoblock status'); + } } }