- Fixed balance calculation: corrected precision factor for Drift scaledBalance (5.69 vs wrong 0,678.76) - Implemented multi-RPC failover system with 4 endpoints (Helius, Solana official, Alchemy, Ankr) - Updated automation page with balance sync, leverage-based position sizing, and removed daily trade limits - Added RPC status monitoring endpoint - Updated balance and positions APIs to use failover system - All Drift APIs now working correctly with accurate balance data
106 lines
3.1 KiB
JavaScript
106 lines
3.1 KiB
JavaScript
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
|
|
};
|
|
}
|