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:
20
.env
20
.env
@@ -31,18 +31,24 @@ API_SECRET_KEY=2a344f0149442c857fb56c038c0c7d1b113883b830bec792c76f1e0efa15d6bb
|
||||
|
||||
# Solana RPC URL (Required for blockchain access)
|
||||
#
|
||||
# CRITICAL: Primary RPC for all trading operations
|
||||
# Current: Alchemy (300M compute units/month free tier)
|
||||
# CRITICAL: Primary RPC for normal trading operations
|
||||
# Current: Alchemy (300M compute units/month free tier, excellent stability)
|
||||
SOLANA_RPC_URL=https://solana-mainnet.g.alchemy.com/v2/5A0iA5UYpsmP9gkuezYeg
|
||||
|
||||
# Fallback RPC URL (Optional but HIGHLY recommended)
|
||||
# Automatically switches to fallback after 2 consecutive rate limits
|
||||
# Use a different provider than primary for best redundancy
|
||||
SOLANA_FALLBACK_RPC_URL=https://mainnet.helius-rpc.com/v1/?api-key=dcca4bf0-0b91-4f6a-8d12-1c5a4c1c6e5b
|
||||
#
|
||||
# SMART STRATEGY (DISABLED - Helius API key issue):
|
||||
# 1. Bot STARTS with fallback (Helius) - handles startup burst better (10 req/sec sustained)
|
||||
# 2. After init, SWITCHES to primary (Alchemy) - more stable for trading operations
|
||||
# 3. On 429 errors, falls back to Helius temporarily, then returns to Alchemy
|
||||
#
|
||||
# TEMPORARILY DISABLED: Set to empty until Helius API key fixed
|
||||
# SOLANA_FALLBACK_RPC_URL=https://mainnet.helius-rpc.com/?api-key=dcca4bf0-0b91-4f6a-8d12-1c5a4c1c6e5b
|
||||
SOLANA_FALLBACK_RPC_URL=
|
||||
|
||||
# RPC Provider Comparison (as of Nov 2025):
|
||||
# ✅ Alchemy: 300M CU/month, excellent for primary (CURRENT PRIMARY)
|
||||
# ⚠️ Helius: 10 req/sec sustained (free tier), good for fallback only
|
||||
# ✅ Alchemy: 300M CU/month, excellent for trading operations (PRIMARY)
|
||||
# ✅ Helius: 10 req/sec sustained, perfect for startup bursts (STARTUP + FALLBACK)
|
||||
# QuickNode: Paid plans, very reliable
|
||||
# Ankr/Public: Unreliable, not recommended
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user