🚀 Fix Drift Protocol integration - Connection now working

 Key fixes:
- Bypass problematic SDK subscription that caused 410 Gone errors
- Use direct account verification without subscription
- Add fallback modes for better reliability
- Switch to Helius RPC endpoint for better rate limits
- Implement proper error handling and retry logic

🔧 Technical changes:
- Enhanced drift-trading.ts with no-subscription approach
- Added Drift API endpoints (/api/drift/login, /balance, /positions)
- Created DriftAccountStatus and DriftTradingPanel components
- Updated Dashboard.tsx to show Drift account status
- Added comprehensive test scripts for debugging

📊 Results:
- Connection Status: Connected 
- Account verification: Working 
- Balance retrieval: Working  (21.94 total collateral)
- Private key authentication: Working 
- User account: 3dG7wayp7b9NBMo92D2qL2sy1curSC4TTmskFpaGDrtA

🌐 RPC improvements:
- Using Helius RPC for better reliability
- Added fallback RPC options in .env
- Eliminated rate limiting issues
This commit is contained in:
mindesbunister
2025-07-13 00:20:01 +02:00
parent a9bbcc7b5f
commit e985a9ec6f
32 changed files with 3875 additions and 771 deletions

View File

@@ -647,6 +647,7 @@ export class TradingViewAutomation {
// CRITICAL: Look for and click "Email" button if present (TradingView uses this pattern)
console.log('🔍 Looking for Email login option...')
// First try Playwright locator approach
const emailTriggers = [
'button:has-text("Email")',
'button:has-text("email")',
@@ -675,6 +676,49 @@ export class TradingViewAutomation {
continue
}
}
// If locator approach failed, use manual button enumeration (like old working code)
if (!emailFormVisible) {
console.log('🔄 Locator approach failed, trying manual button search...')
try {
// Wait for buttons to be available
await this.page.waitForSelector('button', { timeout: 10000 })
// Get all buttons and check their text content
const buttons = await this.page.locator('button').all()
console.log(`🔍 Found ${buttons.length} buttons to check`)
for (let i = 0; i < buttons.length; i++) {
try {
const button = buttons[i]
if (await button.isVisible({ timeout: 1000 })) {
const text = await button.textContent() || ''
const trimmedText = text.trim().toLowerCase()
console.log(`📝 Button ${i + 1}: "${trimmedText}"`)
if (trimmedText.includes('email') ||
trimmedText.includes('continue with email') ||
trimmedText.includes('sign in with email')) {
console.log(`🎯 Found email button: "${trimmedText}"`)
await button.click()
console.log('✅ Clicked email button')
// Wait for email form to appear
await this.page.waitForTimeout(3000)
emailFormVisible = true
break
}
}
} catch (e) {
console.log(`⚠️ Error checking button ${i + 1}:`, e)
continue
}
}
} catch (e) {
console.log('❌ Manual button search failed:', e)
}
}
// Check if email input is now visible
if (!emailFormVisible) {
@@ -683,6 +727,7 @@ export class TradingViewAutomation {
'input[type="email"]',
'input[name*="email"]',
'input[name*="username"]',
'input[name="username"]', // TradingView often uses this
'input[placeholder*="email" i]',
'input[placeholder*="username" i]'
]
@@ -702,6 +747,20 @@ export class TradingViewAutomation {
if (!emailFormVisible) {
await this.takeDebugScreenshot('no_email_form')
// Additional debugging: show what elements are available
const availableElements = await this.page.evaluate(() => {
const buttons = Array.from(document.querySelectorAll('button')).map(btn => btn.textContent?.trim()).filter(Boolean)
const inputs = Array.from(document.querySelectorAll('input')).map(input => ({
type: input.type,
name: input.name,
placeholder: input.placeholder
}))
const forms = Array.from(document.querySelectorAll('form')).length
return { buttons, inputs, forms }
})
console.log('🔍 Available elements:', JSON.stringify(availableElements, null, 2))
throw new Error('Could not find or activate email login form')
}
@@ -709,8 +768,8 @@ export class TradingViewAutomation {
console.log('📧 Looking for email input field...')
const emailSelectors = [
'input[name="username"]', // TradingView commonly uses this
'input[type="email"]',
'input[name="username"]',
'input[name="email"]',
'input[name="id_username"]',
'input[placeholder*="email" i]',
@@ -734,6 +793,42 @@ export class TradingViewAutomation {
}
}
if (!emailInput) {
// Try manual search like the old code
console.log('🔄 Selector approach failed, trying manual input search...')
try {
const inputs = await this.page.locator('input').all()
console.log(`🔍 Found ${inputs.length} inputs to check`)
for (let i = 0; i < inputs.length; i++) {
try {
const input = inputs[i]
if (await input.isVisible({ timeout: 1000 })) {
const type = await input.getAttribute('type') || ''
const name = await input.getAttribute('name') || ''
const placeholder = await input.getAttribute('placeholder') || ''
console.log(`📝 Input ${i + 1}: type="${type}" name="${name}" placeholder="${placeholder}"`)
if (type === 'email' ||
name.toLowerCase().includes('email') ||
name.toLowerCase().includes('username') ||
placeholder.toLowerCase().includes('email') ||
placeholder.toLowerCase().includes('username')) {
console.log(`🎯 Found email input manually: ${name || type || placeholder}`)
emailInput = `input:nth-of-type(${i + 1})`
break
}
}
} catch (e) {
continue
}
}
} catch (e) {
console.log('❌ Manual input search failed:', e)
}
}
if (!emailInput) {
await this.takeDebugScreenshot('no_email_input')
throw new Error('Could not find email input field')
@@ -847,6 +942,40 @@ export class TradingViewAutomation {
}
}
if (!submitButton) {
// Try manual search like the old code
console.log('🔄 Selector approach failed, trying manual button search for submit...')
try {
const buttons = await this.page.locator('button').all()
console.log(`🔍 Found ${buttons.length} buttons to check for submit`)
for (let i = 0; i < buttons.length; i++) {
try {
const button = buttons[i]
if (await button.isVisible({ timeout: 1000 })) {
const text = (await button.textContent() || '').toLowerCase()
const type = await button.getAttribute('type') || ''
console.log(`📝 Submit Button ${i + 1}: "${text}" type="${type}"`)
if (type === 'submit' ||
text.includes('sign in') ||
text.includes('login') ||
text.includes('submit')) {
console.log(`🎯 Found submit button manually: "${text}"`)
submitButton = `button:nth-of-type(${i + 1})`
break
}
}
} catch (e) {
continue
}
}
} catch (e) {
console.log('❌ Manual submit button search failed:', e)
}
}
if (!submitButton) {
await this.takeDebugScreenshot('no_submit_button')
throw new Error('Could not find submit button')
@@ -861,23 +990,70 @@ export class TradingViewAutomation {
console.log('⏳ Waiting for login to complete...')
try {
// Wait for one of several success indicators with longer timeout
await Promise.race([
// Wait to navigate away from login page
this.page.waitForFunction(
() => !window.location.href.includes('/accounts/signin') &&
!window.location.href.includes('/signin'),
{ timeout: 30000 }
),
// Wait for user-specific elements to appear
this.page.waitForSelector(
'[data-name="watchlist-button"], .tv-header__user-menu-button:not(.tv-header__user-menu-button--anonymous), [data-name="user-menu"]',
{ timeout: 30000 }
)
])
// Wait for login completion without using waitForFunction (CSP violation)
// Instead, check URL and elements periodically
let attempts = 0
let maxAttempts = 15 // Reduced to 15 seconds with 1 second intervals
let loginDetected = false
console.log('🎉 Navigation/elements suggest login success!')
while (attempts < maxAttempts && !loginDetected) {
await this.page.waitForTimeout(1000) // Wait 1 second
attempts++
console.log(`🔄 Login check attempt ${attempts}/${maxAttempts}`)
// Check if we navigated away from login page
const currentUrl = await this.page.url()
console.log(`📍 Current URL: ${currentUrl}`)
const notOnLoginPage = !currentUrl.includes('/accounts/signin') && !currentUrl.includes('/signin')
// Check for user-specific elements
let hasUserElements = false
try {
const userElement = await this.page.locator(
'[data-name="watchlist-button"], .tv-header__user-menu-button:not(.tv-header__user-menu-button--anonymous), [data-name="user-menu"]'
).first()
hasUserElements = await userElement.isVisible({ timeout: 500 })
if (hasUserElements) {
console.log('✅ Found user-specific elements')
}
} catch (e) {
// Element not found, continue checking
}
// Check for error messages
try {
const errorSelectors = [
'.tv-dialog__error',
'.error-message',
'[data-testid="error"]',
'.alert-danger'
]
for (const selector of errorSelectors) {
if (await this.page.locator(selector).isVisible({ timeout: 500 })) {
const errorText = await this.page.locator(selector).textContent()
console.log(`❌ Login error detected: ${errorText}`)
throw new Error(`Login failed: ${errorText}`)
}
}
} catch (e) {
if (e instanceof Error && e.message.includes('Login failed:')) {
throw e
}
// Continue if just element not found
}
if (notOnLoginPage || hasUserElements) {
loginDetected = true
console.log('🎉 Navigation/elements suggest login success!')
break
}
}
if (!loginDetected) {
throw new Error('Login verification timeout - no success indicators found')
}
// Additional wait for page to fully load
await this.page.waitForTimeout(5000)
@@ -930,40 +1106,50 @@ export class TradingViewAutomation {
return true
}
console.log('🔐 Not logged in, proceeding with manual login...')
console.log('⚠️ IMPORTANT: Manual intervention required due to captcha protection.')
console.log('📱 Please log in manually in a browser and the session will be saved for future use.')
console.log('🔐 Not logged in, starting automated login process...')
// Navigate to login page for manual login
await this.page.goto('https://www.tradingview.com/accounts/signin/', {
waitUntil: 'domcontentloaded',
timeout: 30000
})
// Try automated login first
console.log('🤖 Attempting automated login...')
const autoLoginSuccess = await this.login(credentials)
// Wait and give user time to manually complete login
console.log('⏳ Waiting for manual login completion...')
console.log('💡 You have 2 minutes to complete login manually in the browser.')
if (autoLoginSuccess) {
console.log('✅ Automated login successful! Saving session for future use.')
this.isAuthenticated = true
await this.saveSession()
return true
}
// Check every 10 seconds for login completion
let attempts = 0
const maxAttempts = 12 // 2 minutes
console.log('❌ Automated login failed, this is likely due to captcha protection.')
console.log('⚠️ In Docker environment, manual login is not practical.')
console.log('<27> Checking if we can proceed with session persistence...')
while (attempts < maxAttempts) {
await this.page.waitForTimeout(10000) // Wait 10 seconds
attempts++
console.log(`🔄 Checking login status (attempt ${attempts}/${maxAttempts})...`)
const loggedIn = await this.checkLoginStatus()
if (loggedIn) {
console.log('✅ Manual login detected! Saving session for future use.')
this.isAuthenticated = true
await this.saveSession()
return true
// Try to check if there are any existing valid session cookies
const sessionInfo = await this.testSessionPersistence()
if (sessionInfo.isValid) {
console.log('✅ Found valid session data, attempting to use it...')
try {
// Navigate to main TradingView page to test session
await this.page.goto('https://www.tradingview.com/', {
waitUntil: 'domcontentloaded',
timeout: 30000
})
await this.page.waitForTimeout(5000)
const nowLoggedIn = await this.checkLoginStatus()
if (nowLoggedIn) {
console.log('✅ Session persistence worked! Login successful.')
this.isAuthenticated = true
await this.saveSession()
return true
}
} catch (e) {
console.log('❌ Session persistence test failed:', e)
}
}
console.log('⏰ Timeout waiting for manual login.')
console.log('❌ All login methods failed. This may require manual intervention.')
console.log('💡 To fix: Log in manually in a browser with the same credentials and restart the application.')
return false
} catch (error) {