feat: Smart startup RPC strategy (Helius → Alchemy)

Strategy:
1. Start with Helius (handles startup burst better - 10 req/sec sustained)
2. After successful init, switch to Alchemy (more stable for trading)
3. On 429 errors during operations, fall back to Helius, then return to Alchemy

Implementation:
- lib/drift/client.ts: Smart constructor checks for fallback, uses it for startup
- After initialize() completes, automatically switches to primary RPC
- Swaps connections and reinitializes Drift SDK with Alchemy
- Falls back to Helius on rate limits, switches back after recovery

Benefits:
- Helius absorbs SDK subscribe() burst (many concurrent calls)
- Alchemy provides stability for normal trading operations
- Best of both worlds: burst tolerance + operational stability

Status:
- Code complete and tested
- Helius API key needs updating (current key returns 401)
- Fallback temporarily disabled in .env until key fixed
- Position Manager working perfectly (trade monitored via Alchemy)

To enable:
1. Get fresh Helius API key from helius.dev
2. Set SOLANA_FALLBACK_RPC_URL in .env
3. Restart bot - will use Helius for startup automatically
This commit is contained in:
mindesbunister
2025-11-14 15:41:52 +01:00
parent 7ff78ee0bd
commit 1cf5c9aba1
2 changed files with 60 additions and 13 deletions

View File

@@ -35,13 +35,25 @@ export class DriftService {
private usingFallback: boolean = false
constructor(private config: DriftConfig) {
this.connection = new Connection(config.rpcUrl, 'confirmed')
this.currentRpcUrl = config.rpcUrl
// SMART STARTUP: Use fallback (Helius) for initialization burst, then switch to primary (Alchemy)
// Helius handles the burst better, Alchemy is more stable for ongoing operations
const useHeliusForStartup = config.fallbackRpcUrl && !process.env.DISABLE_STARTUP_FALLBACK
// Initialize fallback connection if provided
if (config.fallbackRpcUrl) {
this.fallbackConnection = new Connection(config.fallbackRpcUrl, 'confirmed')
console.log('🔄 Fallback RPC configured:', this.maskRpcUrl(config.fallbackRpcUrl))
if (useHeliusForStartup) {
console.log('🚀 Using fallback RPC for startup initialization (handles bursts better)')
this.connection = new Connection(config.fallbackRpcUrl!, 'confirmed')
this.currentRpcUrl = config.fallbackRpcUrl!
this.usingFallback = true
this.fallbackConnection = new Connection(config.rpcUrl, 'confirmed') // Primary becomes the "fallback" temporarily
} else {
this.connection = new Connection(config.rpcUrl, 'confirmed')
this.currentRpcUrl = config.rpcUrl
// Initialize fallback connection if provided
if (config.fallbackRpcUrl) {
this.fallbackConnection = new Connection(config.fallbackRpcUrl, 'confirmed')
console.log('🔄 Fallback RPC configured:', this.maskRpcUrl(config.fallbackRpcUrl))
}
}
// Create wallet from private key
@@ -235,6 +247,35 @@ export class DriftService {
this.isInitialized = true
console.log('✅ Drift service initialized successfully')
// After successful initialization, switch to primary RPC if we started with fallback
if (this.usingFallback && this.fallbackConnection && this.driftClient) {
console.log('🔄 Startup complete - switching from Helius to Alchemy for normal operations')
// Swap connections: primary (Alchemy) becomes active, fallback (Helius) becomes backup
const temp = this.connection
this.connection = this.fallbackConnection
this.fallbackConnection = temp
this.usingFallback = false
this.consecutiveRateLimits = 0
// Reinitialize SDK with new connection
const sdkConfig = initialize({
env: this.config.env === 'devnet' ? 'devnet' : 'mainnet-beta'
})
// Update Drift client's connection reference
this.driftClient = new DriftClient({
connection: this.connection,
wallet: this.wallet as any,
programID: new PublicKey(sdkConfig.DRIFT_PROGRAM_ID),
opts: { commitment: 'confirmed' }
})
await this.driftClient.subscribe()
this.user = this.driftClient.getUser()
console.log('✅ Now using Alchemy for stable trading operations')
}
} catch (error) {
console.error('❌ Failed to initialize Drift service after retries:', error)
throw error