diff --git a/js/walletxray.js b/js/walletxray.js index 0340469..c417415 100644 --- a/js/walletxray.js +++ b/js/walletxray.js @@ -6,8 +6,13 @@ 'use strict'; // ── Config ── - const RPC = 'https://api.mainnet-beta.solana.com'; - const RPC_BACKUP = 'https://rpc.ankr.com/solana'; + const RPC_ENDPOINTS = [ + 'https://solana-mainnet.g.alchemy.com/v2/demo', + 'https://solana.publicnode.com', + 'https://rpc.ankr.com/solana', + 'https://api.mainnet-beta.solana.com', + 'https://mainnet.helius-rpc.com/?api-key=1d8740dc-e5f4-421c-b823-e1bad1889eff' + ]; const JUP_PRICE = 'https://price.jup.ag/v6/price'; const JUP_TOKEN_LIST = 'https://token.jup.ag/all'; const SOLSCAN_TX = 'https://solscan.io/tx/'; @@ -30,7 +35,8 @@ // ── State ── let tokenListCache = null; let tokenMapCache = null; // mint → {name, symbol, logoURI, decimals} - let activeRpc = RPC; + let activeRpc = RPC_ENDPOINTS[0]; + let rpcIndex = 0; let scanning = false; // ── Helpers ── @@ -104,34 +110,44 @@ } // ── RPC Call ── - async function rpc(method, params, retries = 2) { + async function rpc(method, params, retries = 4) { + let lastError; for (let i = 0; i <= retries; i++) { + const url = RPC_ENDPOINTS[(rpcIndex + i) % RPC_ENDPOINTS.length]; try { - const url = i === 0 ? activeRpc : RPC_BACKUP; const res = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ jsonrpc: '2.0', id: 1, method, params }) }); - if (res.status === 429) { - await sleep(1000 * (i + 1)); + if (res.status === 429 || res.status === 403) { + lastError = new Error('Rate limited (HTTP ' + res.status + ')'); + await sleep(800 * (i + 1)); + continue; + } + if (!res.ok) { + lastError = new Error('HTTP ' + res.status); continue; } const json = await res.json(); if (json.error) { - if (json.error.code === -32429 || json.error.message?.includes('rate')) { - await sleep(1000 * (i + 1)); + if (json.error.code === -32429 || (json.error.message && json.error.message.includes('rate'))) { + lastError = new Error(json.error.message); + await sleep(800 * (i + 1)); continue; } throw new Error(json.error.message || 'RPC error'); } + // Success — remember this working RPC + rpcIndex = (rpcIndex + i) % RPC_ENDPOINTS.length; + activeRpc = RPC_ENDPOINTS[rpcIndex]; return json.result; } catch (e) { - if (i === retries) throw e; - activeRpc = RPC_BACKUP; - await sleep(500); + lastError = e; + if (i < retries) await sleep(500); } } + throw lastError || new Error('All RPC endpoints failed'); } function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }