critical: Bug #82 EMERGENCY FIX - Disable Drift State Verifier automatic close
Problem: Verifier can't distinguish OLD positions from NEW positions at same symbol - User opened manual trade with SL working - Verifier detected 6 old closed DB records (150-1064 min ago) - All showed "15.45 tokens open on Drift" (user's CURRENT trade!) - Automatic retry close removed user's SL orders Root Cause: Lines 279-283 call closePosition() for every mismatch - No verification if Drift position is OLD (should close) or NEW (active trade) - No position ID/timestamp matching - Result: Closes ACTIVE trades when cleaning up old database records Solution: DISABLED automatic retry close (lines 276-298) - Added BUG #82 warning logs - Requires manual intervention if true orphan detected - Will add proper position verification in follow-up fix Impact: Stops SL removal on active trades User incident: After Bug #81 fix deployed, THIS bug was killing SLs Deployment: Dec 10, 2025 11:06 CET
This commit is contained in:
@@ -277,36 +277,51 @@ class DriftStateVerifier {
|
|||||||
const attemptTime = Date.now()
|
const attemptTime = Date.now()
|
||||||
this.recentCloseAttempts.set(mismatch.symbol, attemptTime)
|
this.recentCloseAttempts.set(mismatch.symbol, attemptTime)
|
||||||
|
|
||||||
const result = await closePosition({
|
// BUG #82 FIX (Dec 10, 2025): DISABLE automatic retry close
|
||||||
symbol: mismatch.symbol,
|
// Problem: Can't distinguish OLD position (should close) from NEW position at same symbol (should NOT touch)
|
||||||
percentToClose: 100,
|
// Result: Closes ACTIVE trades when trying to clean up old database records
|
||||||
slippageTolerance: 0.05 // 5% slippage tolerance for market order
|
// User incident: 6 old closed trades (150-1064 min ago) all showed "15.45 tokens" on Drift
|
||||||
})
|
// That was user's CURRENT manual trade, not 6 old ghosts
|
||||||
|
// Automatic close removed user's SL orders
|
||||||
|
// Solution: DISABLE automatic close until we add proper position ID/timestamp verification
|
||||||
|
|
||||||
if (result.success) {
|
console.warn(`⚠️ BUG #82 SAFETY: Automatic retry close DISABLED`)
|
||||||
console.log(` ✅ Close transaction confirmed: ${result.transactionSignature}`)
|
console.warn(` Would have closed ${mismatch.symbol} with 15.45 tokens`)
|
||||||
console.log(` P&L: $${result.realizedPnL?.toFixed(2) || 0}`)
|
console.warn(` But can't verify if it's OLD position or NEW active trade`)
|
||||||
console.log(` ⏳ Drift API may take up to 5 minutes to reflect closure`)
|
console.warn(` Manual intervention required if true orphan detected`)
|
||||||
|
return
|
||||||
|
|
||||||
// Update database with retry close timestamp to prevent loop
|
// ORIGINAL CODE (DISABLED):
|
||||||
await prisma.trade.update({
|
// const result = await closePosition({
|
||||||
where: { id: mismatch.tradeId },
|
// symbol: mismatch.symbol,
|
||||||
data: {
|
// percentToClose: 100,
|
||||||
exitOrderTx: result.transactionSignature || 'RETRY_CLOSE',
|
// slippageTolerance: 0.05 // 5% slippage tolerance for market order
|
||||||
realizedPnL: result.realizedPnL || 0,
|
// })
|
||||||
configSnapshot: {
|
//
|
||||||
...trade?.configSnapshot as any,
|
// if (result.success) {
|
||||||
retryCloseAttempted: true,
|
// console.log(` ✅ Close transaction confirmed: ${result.transactionSignature}`)
|
||||||
retryCloseTime: new Date(attemptTime).toISOString(),
|
// console.log(` P&L: $${result.realizedPnL?.toFixed(2) || 0}`)
|
||||||
}
|
// console.log(` ⏳ Drift API may take up to 5 minutes to reflect closure`)
|
||||||
}
|
//
|
||||||
})
|
// // Update database with retry close timestamp to prevent loop
|
||||||
|
// await prisma.trade.update({
|
||||||
console.log(` 📝 Cooldown recorded: ${mismatch.symbol} → ${new Date(attemptTime).toISOString()}`)
|
// where: { id: mismatch.tradeId },
|
||||||
} else {
|
// data: {
|
||||||
console.error(` ❌ Failed to close ${mismatch.symbol}: ${result.error}`)
|
// exitOrderTx: result.transactionSignature || 'RETRY_CLOSE',
|
||||||
// Keep cooldown even on failure to prevent spam
|
// realizedPnL: result.realizedPnL || 0,
|
||||||
}
|
// configSnapshot: {
|
||||||
|
// ...trade?.configSnapshot as any,
|
||||||
|
// retryCloseAttempted: true,
|
||||||
|
// retryCloseTime: new Date(attemptTime).toISOString(),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// console.log(` 📝 Cooldown recorded: ${mismatch.symbol} → ${new Date(attemptTime).toISOString()}`)
|
||||||
|
// } else {
|
||||||
|
// console.error(` ❌ Failed to close ${mismatch.symbol}: ${result.error}`)
|
||||||
|
// // Keep cooldown even on failure to prevent spam
|
||||||
|
// }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(` ❌ Error retrying close for ${mismatch.symbol}:`, error)
|
console.error(` ❌ Error retrying close for ${mismatch.symbol}:`, error)
|
||||||
// On error, still record attempt time to prevent rapid retries
|
// On error, still record attempt time to prevent rapid retries
|
||||||
|
|||||||
Reference in New Issue
Block a user