fix: wallet x-ray RPC failover with 5 endpoints (Alchemy, PublicNode, Ankr, Solana, Helius)

This commit is contained in:
jae 2026-04-18 22:10:10 +00:00
parent 660bb842ec
commit f484cf94b1

View file

@ -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)); }