import { Connection } from '@solana/web3.js'; const RPC_ENDPOINTS = [ process.env.SOLANA_RPC_URL_PRIMARY, process.env.SOLANA_RPC_URL_SECONDARY, process.env.SOLANA_RPC_URL_TERTIARY, process.env.SOLANA_RPC_URL_BACKUP, ].filter(Boolean); // Remove any undefined/empty URLs let currentRpcIndex = 0; let activeConnection = null; /** * Creates a Solana connection with automatic failover to backup RPCs */ export async function createConnectionWithFailover() { for (let attempt = 0; attempt < RPC_ENDPOINTS.length; attempt++) { const rpcUrl = RPC_ENDPOINTS[currentRpcIndex]; if (!rpcUrl) { currentRpcIndex = (currentRpcIndex + 1) % RPC_ENDPOINTS.length; continue; } try { console.log(`Attempting to connect to RPC: ${rpcUrl.replace(/\/\/.*@/, '//*****@')}`); const connection = new Connection(rpcUrl, 'confirmed'); // Test the connection by getting the latest blockhash await connection.getLatestBlockhash(); console.log(`Successfully connected to RPC: ${rpcUrl.replace(/\/\/.*@/, '//*****@')}`); activeConnection = connection; return connection; } catch (error) { console.warn(`RPC ${rpcUrl.replace(/\/\/.*@/, '//*****@')} failed:`, error.message); // Move to next RPC endpoint currentRpcIndex = (currentRpcIndex + 1) % RPC_ENDPOINTS.length; } } throw new Error('All RPC endpoints failed. Unable to establish connection.'); } /** * Gets the current active connection or creates a new one */ export async function getConnection() { if (activeConnection) { try { // Test if current connection is still working await activeConnection.getLatestBlockhash(); return activeConnection; } catch (error) { console.warn('Active connection failed, attempting failover...'); activeConnection = null; } } return createConnectionWithFailover(); } /** * Executes a function with automatic RPC failover */ export async function executeWithFailover(operation, maxRetries = 3) { let lastError = null; for (let retry = 0; retry < maxRetries; retry++) { try { const connection = await getConnection(); return await operation(connection); } catch (error) { lastError = error; console.warn(`Operation failed (attempt ${retry + 1}/${maxRetries}):`, error.message); // Force connection refresh on next attempt activeConnection = null; // Move to next RPC endpoint currentRpcIndex = (currentRpcIndex + 1) % RPC_ENDPOINTS.length; // Wait a bit before retrying if (retry < maxRetries - 1) { await new Promise(resolve => setTimeout(resolve, 1000 * (retry + 1))); } } } throw new Error(`Operation failed after ${maxRetries} attempts. Last error: ${lastError?.message}`); } /** * Get information about current RPC status */ export function getRpcStatus() { return { availableEndpoints: RPC_ENDPOINTS.length, currentEndpoint: RPC_ENDPOINTS[currentRpcIndex]?.replace(/\/\/.*@/, '//*****@'), hasActiveConnection: !!activeConnection }; }