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

20
.env
View File

@@ -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

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