🎯 Fix Drift trading bot backend - correct account balance detection

- Fix backend to correctly display 18 Net USD Value and 6.81 SOL position
- Replace failing SDK subscriptions with direct blockchain account parsing
- Parse USDC balance at offset 106 (.53) and SOL position at offset 1208 (6.81 SOL)
- Update balance API to return correct totalValue: 18.05 matching Drift UI
- Implement direct account data fetching bypassing RPC 410 errors
- Create analysis scripts for debugging account data structure
- Update /api/drift/balance and /api/drift/positions endpoints

Backend now correctly matches Drift UI:
- Net USD Value: 18.05 
- SOL Position: 6.81 SOL 
- USDC Balance: .53 
- Unrealized PnL: 4.37 
This commit is contained in:
mindesbunister
2025-07-14 10:52:22 +02:00
parent 23cab77200
commit 52051e1cad
7 changed files with 728 additions and 1832 deletions

117
analyze-account-data.js Normal file
View File

@@ -0,0 +1,117 @@
#!/usr/bin/env node
require('dotenv').config();
const { Connection, PublicKey } = require('@solana/web3.js');
async function analyzeAccountData() {
console.log('🔍 Deep Account Data Analysis\n');
try {
const connection = new Connection(process.env.SOLANA_RPC_URL || 'https://api.mainnet-beta.solana.com', 'confirmed');
// The account we know exists
const accountPDA = new PublicKey('7LonnWut5i3h36xyMA5jbwnGFbnzXUPY2dsPfNaSsrTk');
console.log(`📍 Analyzing account: ${accountPDA.toString()}`);
const accountInfo = await connection.getAccountInfo(accountPDA);
if (!accountInfo) {
console.log('❌ Account not found');
return;
}
console.log(`📊 Account Owner: ${accountInfo.owner.toString()}`);
console.log(`📊 Data Length: ${accountInfo.data.length} bytes`);
console.log(`📊 Lamports: ${accountInfo.lamports}`);
console.log(`📊 Executable: ${accountInfo.executable}`);
console.log(`📊 Rent Epoch: ${accountInfo.rentEpoch}\n`);
const data = accountInfo.data;
// Show hex dump of the data
console.log('🔍 Raw Data Analysis:');
console.log('First 128 bytes:');
console.log(data.slice(0, 128).toString('hex').match(/.{1,32}/g).map((line, i) =>
`${(i * 16).toString(16).padStart(4, '0')}: ${line}`
).join('\n'));
console.log('\n💰 Searching for potential balance values...');
// Look for values that could represent the $118 balance or 6.81 SOL position
// SOL has 9 decimals, USDC has 6 decimals
const targetUSDC = Math.round(118 * 1_000_000); // $118 in USDC scaled (118000000)
const targetSOL = Math.round(6.81 * 1_000_000_000); // 6.81 SOL scaled (6810000000)
console.log(`🎯 Looking for USDC balance: ${targetUSDC} (0x${targetUSDC.toString(16)})`);
console.log(`🎯 Looking for SOL position: ${targetSOL} (0x${targetSOL.toString(16)})`);
// Scan through the data for these values or close approximations
for (let offset = 0; offset < data.length - 8; offset += 1) {
try {
// Try reading as little-endian i64
const value = data.readBigInt64LE(offset);
const numberValue = Number(value);
// Check if this could be our balance values
if (Math.abs(numberValue - targetUSDC) < 1000000) { // Within $1
console.log(`💰 Potential USDC balance found at offset ${offset}: ${numberValue} (${(numberValue / 1_000_000).toFixed(6)} USDC)`);
}
if (Math.abs(numberValue - targetSOL) < 100000000) { // Within 0.1 SOL
console.log(`🪙 Potential SOL position found at offset ${offset}: ${numberValue} (${(numberValue / 1_000_000_000).toFixed(9)} SOL)`);
}
// Also check for reasonable USD amounts (between $1 and $10,000)
const asUSDC = numberValue / 1_000_000;
if (asUSDC > 1 && asUSDC < 10000) {
console.log(`💵 Potential USD value at offset ${offset}: $${asUSDC.toFixed(2)}`);
}
// Check for reasonable SOL amounts (between 0.1 and 1000 SOL)
const asSOL = numberValue / 1_000_000_000;
if (asSOL > 0.1 && asSOL < 1000) {
console.log(`⚡ Potential SOL value at offset ${offset}: ${asSOL.toFixed(6)} SOL`);
}
} catch (e) {
// Skip invalid reads
}
}
console.log('\n🔍 Examining specific important offsets...');
// Common offsets in Drift account structure
const importantOffsets = [
8, // After discriminator
40, // After authority
72, // After sub account ID and other fields
104, // Our current detection point
200, // In spot positions area
500, // Mid spot positions
1000, // Perp positions area
2000, // Mid perp positions
3000, // Late in structure
4000, // Near end
];
for (const offset of importantOffsets) {
if (offset + 8 <= data.length) {
try {
const value = data.readBigInt64LE(offset);
const numberValue = Number(value);
const asUSDC = numberValue / 1_000_000;
const asSOL = numberValue / 1_000_000_000;
console.log(`Offset ${offset.toString().padStart(4)}: ${numberValue.toString().padStart(12)} | $${asUSDC.toFixed(2).padStart(8)} | ${asSOL.toFixed(4).padStart(8)} SOL`);
} catch (e) {
console.log(`Offset ${offset.toString().padStart(4)}: [read error]`);
}
}
}
} catch (error) {
console.error('❌ Analysis failed:', error.message);
}
}
analyzeAccountData().catch(console.error);