RugPlay X

Automate selling/buying on RugPlay

// ==UserScript==
// @name         RugPlay X
// @namespace    http://tampermonkey.net/
// @version      1.02
// @description  Automate selling/buying on RugPlay
// @author       4koy
// @match        https://rugplay.com/*
// @match        https://*.rugplay.com/*
// @match        http://rugplay.com/*
// @match        http://*.rugplay.com/*
// @grant        none
// @run-at       document-end
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // Configuration
    const CONFIG = {
        SELL_DELAY: 100,        // Delay between sell actions (ms)
        BUY_DELAY: 150,         // Delay between buy actions (ms)
        MAX_RETRIES: 50,        // Maximum number of sell attempts
        CONFIRM_DELAY: 150,     // Delay before confirming actions
        AUTO_CONFIRM: false,    // Set to true to auto-confirm transactions
        BUY_AMOUNT: 1000,       // Default buy amount in dollars
        API_ENABLED: true,      // Enable API features
        REFRESH_INTERVAL: 2000  // Portfolio refresh interval (ms)
    };

    let isRunning = false;
    let currentAction = null;
    let actionCount = 0;
    let portfolioData = null;
    let apiHeaders = null;

    // Initialize API headers from browser cookies
    function initializeApiHeaders() {
        try {
            const cookies = document.cookie.split(';').reduce((acc, cookie) => {
                const [key, value] = cookie.trim().split('=');
                if (key && value) {
                    acc[key] = decodeURIComponent(value);
                }
                return acc;
            }, {});

            console.log('Available cookies:', Object.keys(cookies));

            // Try different possible cookie names for session token
            const sessionTokenNames = [
                '__Secure-better-auth.session_token',
                'better-auth.session_token',
                'session_token',
                'auth_token',
                'sessionToken'
            ];

            const cfClearanceNames = [
                'cf_clearance',
                'cf-clearance',
                'cloudflare_clearance'
            ];

            let sessionToken = null;
            let cfClearance = null;

            // Find session token
            for (const name of sessionTokenNames) {
                if (cookies[name]) {
                    sessionToken = cookies[name];
                    console.log(`Found session token: ${name}`);
                    break;
                }
            }

            // Find cloudflare clearance
            for (const name of cfClearanceNames) {
                if (cookies[name]) {
                    cfClearance = cookies[name];
                    console.log(`Found CF clearance: ${name}`);
                    break;
                }
            }

            // For now, proceed even without cookies to test API endpoints
            apiHeaders = {
                'accept': '*/*',
                'accept-language': 'en-US,en;q=0.9',
                'content-type': 'application/json',
                'origin': 'https://rugplay.com',
                'referer': window.location.href,
                'sec-ch-ua': '"Chromium";v="134", "Not:A-Brand";v="24"',
                'sec-ch-ua-mobile': '?0',
                'sec-ch-ua-platform': '"Linux"',
                'sec-fetch-dest': 'empty',
                'sec-fetch-mode': 'cors',
                'sec-fetch-site': 'same-origin',
                'user-agent': navigator.userAgent
            };

            if (sessionToken && cfClearance) {
                console.log('🔗 API headers initialized with full authentication');
                return true;
            } else if (sessionToken || cfClearance) {
                console.log('🔗 API headers initialized with partial authentication');
                return true;
            } else {
                console.log('⚠️ No authentication cookies found, trying without auth');
                return true; // Still try API calls without auth
            }
        } catch (error) {
            console.log('❌ Error initializing API headers:', error);
            return false;
        }
    }

    // Fetch recent trades from API
    async function fetchRecentTrades() {
        if (!apiHeaders) return null;

        try {
            const response = await fetch('https://rugplay.com/api/trades/recent?limit=100', {
                method: 'GET',
                headers: apiHeaders,
                credentials: 'include'
            });

            if (response.ok) {
                const data = await response.json();
                return data.trades || [];
            } else {
                console.log('⚠️ API trades request failed:', response.status);
                return null;
            }
        } catch (error) {
            console.log('❌ Error fetching trades:', error);
            return null;
        }
    }

    // Fetch portfolio data from API (if endpoint exists)
    async function fetchPortfolioData() {
        if (!apiHeaders) return null;

        try {
            // Try common portfolio endpoints
            const endpoints = [
                '/api/portfolio',
                '/api/user/portfolio',
                '/api/account/portfolio',
                '/api/holdings'
            ];

            for (const endpoint of endpoints) {
                try {
                    const response = await fetch(`https://rugplay.com${endpoint}`, {
                        method: 'GET',
                        headers: apiHeaders,
                        credentials: 'include'
                    });

                    if (response.ok) {
                        const data = await response.json();
                        console.log('📊 Portfolio data fetched from', endpoint);
                        return data;
                    }
                } catch (e) {
                    // Continue to next endpoint
                }
            }

            return null;
        } catch (error) {
            console.log('❌ Error fetching portfolio:', error);
            return null;
        }
    }

    // Enhanced cash detection using API data
    async function getAvailableCashEnhanced() {
        // First try API method
        if (CONFIG.API_ENABLED && apiHeaders) {
            const portfolio = await fetchPortfolioData();
            if (portfolio) {
                // Try common field names for cash/balance
                const cashFields = ['cash', 'balance', 'availableBalance', 'totalValue', 'usdBalance'];
                for (const field of cashFields) {
                    if (portfolio[field] !== undefined) {
                        const amount = parseFloat(portfolio[field]);
                        if (!isNaN(amount)) {
                            console.log(`💰 Found cash via API (${field}):`, amount);
                            return amount;
                        }
                    }
                }
            }
        }

        // Fallback to DOM scraping
        return getAvailableCash();
    }

    // Function to get available cash from the sidebar
    function getAvailableCash() {
        try {
            // Method 1: Look for the Cash field specifically (PRIORITY)
            const textElements = document.querySelectorAll('.text-muted-foreground .flex.justify-between');
            for (const element of textElements) {
                const spans = element.querySelectorAll('span');
                if (spans.length >= 2 && spans[0].textContent.trim() === 'Cash:') {
                    const cashSpan = spans[1];
                    if (cashSpan && cashSpan.classList.contains('font-mono')) {
                        const cashText = cashSpan.textContent.replace(/[$,]/g, '').trim();
                        const cashAmount = parseFloat(cashText);
                        if (!isNaN(cashAmount)) {
                            console.log('Found Cash amount:', cashAmount);
                            return cashAmount;
                        }
                    }
                }
            }

            // Method 2: Look for Cash pattern in sidebar content
            const sidebarContent = document.querySelector('div[data-slot="sidebar-group-content"]');
            if (sidebarContent) {
                // Look for the specific structure with "Cash:" text
                const cashElements = sidebarContent.querySelectorAll('div.flex.justify-between');
                for (const element of cashElements) {
                    const spans = element.querySelectorAll('span');
                    if (spans.length >= 2 && spans[0].textContent.trim() === 'Cash:') {
                        const cashText = spans[1].textContent.replace(/[$,]/g, '').trim();
                        const cashAmount = parseFloat(cashText);
                        if (!isNaN(cashAmount)) {
                            console.log('Found Cash in sidebar:', cashAmount);
                            return cashAmount;
                        }
                    }
                }

                // Look for any span with font-mono class containing cash
                const monoSpans = sidebarContent.querySelectorAll('span.font-mono');
                for (const span of monoSpans) {
                    const parent = span.parentElement;
                    if (parent && parent.textContent.includes('Cash:')) {
                        const cashText = span.textContent.replace(/[$,]/g, '').trim();
                        const cashAmount = parseFloat(cashText);
                        if (!isNaN(cashAmount) && cashAmount > 0) {
                            console.log('Found Cash via font-mono:', cashAmount);
                            return cashAmount;
                        }
                    }
                }

                // Broader search for cash patterns
                const allText = sidebarContent.textContent;
                const cashMatch = allText.match(/Cash:\s*\$?([\d,]+\.?\d*)/i);
                if (cashMatch) {
                    const cashAmount = parseFloat(cashMatch[1].replace(/,/g, ''));
                    if (!isNaN(cashAmount)) {
                        console.log('Found Cash via regex:', cashAmount);
                        return cashAmount;
                    }
                }
            }

            // Method 3: Fallback to Total Value structure if Cash not found
            const portfolioElements = document.querySelectorAll('div.flex.items-center.justify-between');
            for (const element of portfolioElements) {
                const textSpan = element.querySelector('span.text-sm.font-medium');
                if (textSpan && textSpan.textContent.trim().includes('Total Value')) {
                    const amountBadge = element.querySelector('span[data-slot="badge"].font-mono');
                    if (amountBadge) {
                        const cashText = amountBadge.textContent.replace(/[$,]/g, '').trim();
                        const cashAmount = parseFloat(cashText);
                        if (!isNaN(cashAmount)) {
                            console.log('Fallback - Found Total Value:', cashAmount);
                            return cashAmount;
                        }
                    }
                }
            }

            // Method 4: Look for any span with font-mono class that contains a dollar amount
            const monoSpans = document.querySelectorAll('span.font-mono');
            for (const span of monoSpans) {
                const text = span.textContent.trim();
                if (text.includes('$') && text.match(/\$[\d,]+\.?\d*/)) {
                    const parent = span.parentElement;
                    // Prioritize if parent contains "Cash:"
                    if (parent && parent.textContent.includes('Cash:')) {
                        const cashText = text.replace(/[$,]/g, '').trim();
                        const cashAmount = parseFloat(cashText);
                        if (!isNaN(cashAmount) && cashAmount > 0) {
                            console.log('Found cash amount via font-mono search:', cashAmount);
                            return cashAmount;
                        }
                    }
                }
            }

            console.log('Cash not found with any method');
            return 0;
        } catch (error) {
            console.log('Error getting cash amount:', error);
            return 0;
        }
    }

    // Function to update cash display periodically
    async function updateCashDisplay() {
        const cashElement = document.getElementById('available-cash');
        if (cashElement) {
            // Try enhanced cash detection first (with API fallback)
            const currentCash = await getAvailableCashEnhanced();
            cashElement.textContent = currentCash.toFixed(2);

            // Update the color based on amount
            const cashDisplay = cashElement.parentElement;
            if (currentCash > 0) {
                cashDisplay.style.color = '#28a745';
            } else {
                cashDisplay.style.color = '#dc3545';
            }
        }
    }

    // Create modern control panel with glassmorphism
    function createControlPanel() {
        // Check if panel already exists
        if (document.getElementById('rugplay-auto-trader')) {
            console.log('🚀 Panel already exists, skipping creation');
            return;
        }

        console.log('🚀 Creating control panel...');

        // Add custom CSS styles
        const style = document.createElement('style');
        style.textContent = `
            @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');

            #rugplay-auto-trader {
                font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
                backdrop-filter: blur(20px);
                -webkit-backdrop-filter: blur(20px);
                background: rgba(255, 255, 255, 0.15);
                border: 1px solid rgba(255, 255, 255, 0.2);
                box-shadow:
                    0 20px 40px rgba(0, 0, 0, 0.1),
                    0 0 0 1px rgba(255, 255, 255, 0.1),
                    inset 0 1px 0 rgba(255, 255, 255, 0.3);
                transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
            }

            #rugplay-auto-trader:hover {
                transform: translateY(-2px);
                background: rgba(255, 255, 255, 0.2);
                box-shadow:
                    0 25px 50px rgba(0, 0, 0, 0.15),
                    0 0 0 1px rgba(255, 255, 255, 0.15),
                    inset 0 1px 0 rgba(255, 255, 255, 0.35);
            }

            .trader-header {
                color: rgba(255, 255, 255, 0.95);
                font-weight: 600;
                font-size: 16px;
                margin: 0;
                cursor: grab;
                user-select: none;
                letter-spacing: 0.5px;
                text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8), 0 0 4px rgba(0, 0, 0, 0.6);
            }

            .trader-header:active {
                cursor: grabbing;
            }

            .trader-input {
                background: rgba(0, 0, 0, 0.08);
                border: 1px solid rgba(0, 0, 0, 0.15);
                border-radius: 8px;
                padding: 8px 12px;
                color: rgba(255, 255, 255, 0.9);
                font-size: 13px;
                outline: none;
                transition: all 0.2s ease;
                width: 80px;
                backdrop-filter: blur(10px);
                text-shadow: 0 1px 1px rgba(0, 0, 0, 0.7);
            }

            .trader-input:focus {
                background: rgba(0, 0, 0, 0.12);
                border-color: rgba(0, 0, 0, 0.25);
                box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.1);
            }

            .trader-checkbox {
                accent-color: rgba(0, 0, 0, 0.7);
                margin-right: 8px;
            }

            .trader-label {
                color: rgba(255, 255, 255, 0.85);
                font-size: 13px;
                font-weight: 500;
                display: flex;
                align-items: center;
                cursor: pointer;
                text-shadow: 0 1px 1px rgba(0, 0, 0, 0.7);
            }

            .trader-btn {
                border: none;
                border-radius: 10px;
                padding: 12px 20px;
                font-weight: 500;
                font-size: 12px;
                cursor: pointer;
                transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
                position: relative;
                overflow: hidden;
                text-transform: uppercase;
                letter-spacing: 0.8px;
                display: flex;
                align-items: center;
                justify-content: center;
                gap: 6px;
                min-width: 110px;
                backdrop-filter: blur(10px);
                -webkit-backdrop-filter: blur(10px);
            }

            .trader-btn:hover {
                transform: translateY(-1px);
                box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15);
            }

            .trader-btn:active {
                transform: translateY(0);
            }

            .trader-btn:disabled {
                opacity: 0.4;
                cursor: not-allowed;
                transform: none !important;
            }

            .sell-btn {
                background: rgba(255, 255, 255, 0.25);
                color: #ff4757;
                border: 1px solid rgba(255, 71, 87, 0.3);
                text-shadow: 0 1px 1px rgba(0, 0, 0, 0.6);
            }

            .sell-btn:hover {
                background: rgba(255, 255, 255, 0.35);
                border-color: rgba(255, 71, 87, 0.4);
                color: #ff3742;
            }

            .buy-btn {
                background: rgba(255, 255, 255, 0.25);
                color: #2ed573;
                border: 1px solid rgba(46, 213, 115, 0.3);
                text-shadow: 0 1px 1px rgba(0, 0, 0, 0.6);
            }

            .buy-btn:hover {
                background: rgba(255, 255, 255, 0.35);
                border-color: rgba(46, 213, 115, 0.4);
                color: #26d464;
            }

            .buy-btn:disabled {
                background: rgba(255, 255, 255, 0.15);
                color: rgba(46, 213, 115, 0.4);
                border-color: rgba(46, 213, 115, 0.2);
            }

            .stop-btn {
                background: rgba(255, 255, 255, 0.25);
                color: rgba(255, 255, 255, 0.8);
                border: 1px solid rgba(255, 255, 255, 0.3);
                text-shadow: 0 1px 1px rgba(0, 0, 0, 0.6);
            }

            .stop-btn:hover {
                background: rgba(255, 255, 255, 0.35);
                border-color: rgba(255, 255, 255, 0.4);
                color: rgba(255, 255, 255, 0.95);
            }

            .trader-status {
                background: rgba(255, 255, 255, 0.2);
                border: 1px solid rgba(0, 0, 0, 0.15);
                border-radius: 10px;
                padding: 12px;
                font-size: 11px;
                height: 80px;
                overflow-y: auto;
                overflow-x: hidden;
                color: rgba(255, 255, 255, 0.9);
                font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;
                line-height: 1.4;
                word-wrap: break-word;
                word-break: break-word;
                white-space: pre-wrap;
                max-width: 100%;
                backdrop-filter: blur(10px);
                -webkit-backdrop-filter: blur(10px);
                text-shadow: 0 1px 1px rgba(0, 0, 0, 0.7);
            }

            .trader-status::-webkit-scrollbar {
                width: 4px;
            }

            .trader-status::-webkit-scrollbar-track {
                background: rgba(0, 0, 0, 0.1);
                border-radius: 2px;
            }

            .trader-status::-webkit-scrollbar-thumb {
                background: rgba(0, 0, 0, 0.3);
                border-radius: 2px;
            }

            .trader-status::-webkit-scrollbar-thumb:hover {
                background: rgba(0, 0, 0, 0.4);
            }

            .trader-counter {
                color: rgba(255, 255, 255, 0.7);
                font-size: 11px;
                font-weight: 500;
                text-shadow: 0 1px 1px rgba(0, 0, 0, 0.7);
            }

            .trader-counter span {
                color: rgba(255, 255, 255, 0.95);
                font-weight: 600;
            }

            .drag-handle {
                position: absolute;
                top: 8px;
                right: 12px;
                color: rgba(255, 255, 255, 0.5);
                cursor: grab;
                font-size: 12px;
                text-shadow: 0 1px 1px rgba(0, 0, 0, 0.6);
            }

            .drag-handle:active {
                cursor: grabbing;
            }

            .max-btn {
                background: rgba(255, 255, 255, 0.25);
                color: rgba(255, 255, 255, 0.9);
                border: 1px solid rgba(255, 255, 255, 0.2);
                border-radius: 8px;
                padding: 8px 14px;
                font-weight: 500;
                font-size: 12px;
                cursor: pointer;
                transition: all 0.2s ease;
                display: flex;
                align-items: center;
                justify-content: center;
                text-transform: uppercase;
                letter-spacing: 0.5px;
                backdrop-filter: blur(10px);
                text-shadow: 0 1px 1px rgba(0, 0, 0, 0.6);
            }

            .max-btn:hover {
                background: rgba(255, 255, 255, 0.35);
                border-color: rgba(255, 255, 255, 0.3);
                color: rgba(255, 255, 255, 1);
            }

            .cash-display {
                font-size: 13px;
                color: #2ed573;
                font-weight: 600;
                margin-top: 8px;
                display: flex;
                align-items: center;
                gap: 4px;
                text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8);
            }

            .cash-icon {
                width: 14px;
                height: 14px;
                fill: #2ed573;
                filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.6));
            }

            /* Tab System Styles */
            .tab-container {
                margin-bottom: 20px;
            }

            .tab-nav {
                display: flex;
                border-bottom: 1px solid rgba(0, 0, 0, 0.2);
                margin-bottom: 16px;
                backdrop-filter: blur(5px);
            }

            .tab-btn {
                flex: 1;
                background: rgba(255, 255, 255, 0.1);
                border: none;
                padding: 12px 8px;
                color: rgba(255, 255, 255, 0.7);
                font-size: 12px;
                font-weight: 500;
                cursor: pointer;
                transition: all 0.2s ease;
                text-transform: uppercase;
                letter-spacing: 0.5px;
                border-bottom: 2px solid transparent;
                text-shadow: 0 1px 1px rgba(0, 0, 0, 0.6);
            }

            .tab-btn:hover {
                color: rgba(255, 255, 255, 0.9);
                background: rgba(255, 255, 255, 0.2);
            }

            .tab-btn.active {
                color: rgba(255, 255, 255, 1);
                background: rgba(255, 255, 255, 0.25);
                border-bottom-color: rgba(255, 255, 255, 0.8);
            }

            .tab-content {
                display: none;
                animation: fadeIn 0.3s ease;
            }

            .tab-content.active {
                display: block;
            }

            @keyframes fadeIn {
                from { opacity: 0; transform: translateY(10px); }
                to { opacity: 1; transform: translateY(0); }
            }

            .tab-section {
                margin-bottom: 16px;
            }

            .section-title {
                color: rgba(255, 255, 255, 0.9);
                font-size: 13px;
                font-weight: 600;
                margin-bottom: 12px;
                text-transform: uppercase;
                letter-spacing: 0.5px;
                text-shadow: 0 1px 1px rgba(0, 0, 0, 0.7);
            }
        `;
        document.head.appendChild(style);

        const panel = document.createElement('div');
        panel.id = 'rugplay-auto-trader';
        panel.style.cssText = `
            position: fixed;
            top: 20px;
            right: 20px;
            border-radius: 20px;
            padding: 24px;
            z-index: 10000;
            width: 340px;
            max-width: 340px;
            min-width: 340px;
            box-sizing: border-box;
            user-select: none;
        `;

        panel.innerHTML = `
            <div class="drag-handle">⋮⋮</div>

            <div style="text-align: center; margin-bottom: 20px;">
                <h3 class="trader-header">RugPlay Trader Pub</h3>
            </div>

            <!-- Tab Navigation -->
            <div class="tab-container">
                <div class="tab-nav">
                    <button class="tab-btn active" data-tab="trading">Trading</button>
                    <button class="tab-btn" data-tab="settings">Settings</button>
                </div>

                <!-- Trading Tab -->
                <div class="tab-content active" id="trading">
                    <div class="tab-section">
                        <div class="section-title">Trading Controls</div>
                        <div style="display: flex; gap: 16px; margin-bottom: 20px; align-items: center;">
                            <div style="flex: 1;">
                                <label class="trader-label" style="margin-bottom: 6px; display: block;">
                                    Delay (ms)
                                </label>
                                <input type="number" id="delay-input" value="${CONFIG.SELL_DELAY}" class="trader-input">
                            </div>
                            <div style="flex: 1;">
                                <label class="trader-label">
                                    <input type="checkbox" id="auto-confirm" ${CONFIG.AUTO_CONFIRM ? 'checked' : ''} class="trader-checkbox">
                                    Auto-confirm
                                </label>
                            </div>
                        </div>

                        <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 16px;">
                            <button id="sell-all-btn" class="trader-btn sell-btn">
                                Sell All
                            </button>
                            <button id="buy-btn" class="trader-btn buy-btn">
                                Buy
                            </button>
                        </div>

                        <div style="margin-bottom: 16px;">
                            <label class="trader-label" style="margin-bottom: 6px; display: block;">
                                Buy Amount ($)
                            </label>
                            <div style="display: flex; gap: 8px; align-items: center;">
                                <input type="number" id="buy-amount-input" value="${CONFIG.BUY_AMOUNT}" class="trader-input" style="flex: 1; max-width: 120px;" step="0.01" min="0.01" placeholder="Enter amount">
                                <button id="max-buy-btn" class="max-btn" type="button">
                                    Max
                                </button>
                            </div>
                        </div>

                        <button id="stop-btn" class="trader-btn stop-btn" style="width: 100%" disabled>
                            Stop Trading
                        </button>
                    </div>

                    <div class="tab-section">
                        <div class="section-title">Portfolio Info</div>
                        <div style="margin-top: 16px; text-align: center;">
                            <div class="cash-display">
                                <svg class="cash-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8 8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-1-13h2v6h-2zm0 8h2v2h-2z"/></svg>
                                Available Cash: $<span id="available-cash">${getAvailableCash().toFixed(2)}</span>
                            </div>
                        </div>
                    </div>
                </div>

                <!-- Settings Tab -->
                <div class="tab-content" id="settings">
                    <div class="tab-section">
                        <div class="section-title">System Settings</div>
                        <div style="margin-bottom: 16px;">
                            <label class="trader-label" style="margin-bottom: 6px; display: block;">
                                Refresh Interval (ms)
                            </label>
                            <input type="number" id="refresh-interval" value="${CONFIG.REFRESH_INTERVAL}" class="trader-input">
                        </div>

                        <div style="margin-bottom: 16px;">
                            <label class="trader-label">
                                <input type="checkbox" id="api-enabled" ${CONFIG.API_ENABLED ? 'checked' : ''} class="trader-checkbox">
                                Enable API features
                            </label>
                        </div>
                    </div>

                    <div class="tab-section">
                        <div class="section-title">Trading Limits</div>
                        <div style="margin-bottom: 16px;">
                            <label class="trader-label" style="margin-bottom: 6px; display: block;">
                                Max Retries
                            </label>
                            <input type="number" id="max-retries" value="${CONFIG.MAX_RETRIES}" class="trader-input" min="1" max="100">
                        </div>

                        <div style="margin-bottom: 16px;">
                            <label class="trader-label" style="margin-bottom: 6px; display: block;">
                                Confirm Delay (ms)
                            </label>
                            <input type="number" id="confirm-delay" value="${CONFIG.CONFIRM_DELAY}" class="trader-input" min="50" max="2000">
                        </div>
                    </div>
                </div>
            </div>

            <!-- Status and Counter (Always Visible) -->
            <div style="margin-top: 20px;">
                <div id="status" class="trader-status">
                    <div>System ready for trading...</div>
                </div>

                <div style="text-align: center; margin-top: 16px;" class="trader-counter">
                    Actions completed: <span id="action-counter">0</span>
                </div>
            </div>
        `;

        document.body.appendChild(panel);
        makeDraggable(panel);
        setupEventListeners();
    }

    // Make panel draggable
    function makeDraggable(element) {
        let isDragging = false;
        let currentX;
        let currentY;
        let initialX;
        let initialY;
        let xOffset = 0;
        let yOffset = 0;

        const header = element.querySelector('.trader-header');
        const dragHandle = element.querySelector('.drag-handle');

        [header, dragHandle].forEach(handle => {
            if (handle) {
                handle.addEventListener('mousedown', dragStart);
                handle.addEventListener('touchstart', dragStart);
            }
        });

        function dragStart(e) {
            if (e.type === 'touchstart') {
                initialX = e.touches[0].clientX - xOffset;
                initialY = e.touches[0].clientY - yOffset;
            } else {
                initialX = e.clientX - xOffset;
                initialY = e.clientY - yOffset;
            }

            if (e.target === header || e.target === dragHandle) {
                isDragging = true;
                element.style.transition = 'none';
                document.addEventListener('mousemove', drag);
                document.addEventListener('touchmove', drag);
                document.addEventListener('mouseup', dragEnd);
                document.addEventListener('touchend', dragEnd);
            }
        }

        function drag(e) {
            if (!isDragging) return;

            e.preventDefault();

            if (e.type === 'touchmove') {
                currentX = e.touches[0].clientX - initialX;
                currentY = e.touches[0].clientY - initialY;
            } else {
                currentX = e.clientX - initialX;
                currentY = e.clientY - initialY;
            }

            xOffset = currentX;
            yOffset = currentY;

            // Allow free movement anywhere - no viewport constraints
            element.style.transform = `translate(${xOffset}px, ${yOffset}px)`;
        }

        function dragEnd() {
            isDragging = false;
            element.style.transition = 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)';

            document.removeEventListener('mousemove', drag);
            document.removeEventListener('touchmove', drag);
            document.removeEventListener('mouseup', dragEnd);
            document.removeEventListener('touchend', dragEnd);
        }
    }

    function setupEventListeners() {
        document.getElementById('sell-all-btn').addEventListener('click', startSelling);
        document.getElementById('buy-btn').addEventListener('click', startBuying);
        document.getElementById('stop-btn').addEventListener('click', stopAction);

        document.getElementById('delay-input').addEventListener('change', (e) => {
            CONFIG.SELL_DELAY = parseInt(e.target.value) || 200;
            CONFIG.BUY_DELAY = CONFIG.SELL_DELAY * 1.25;
        });

        document.getElementById('auto-confirm').addEventListener('change', (e) => {
            CONFIG.AUTO_CONFIRM = e.target.checked;
        });

        document.getElementById('buy-amount-input').addEventListener('change', (e) => {
            CONFIG.BUY_AMOUNT = parseFloat(e.target.value) || 100;
        });

        document.getElementById('max-buy-btn').addEventListener('click', () => {
            const availableCash = getAvailableCash();
            // Round down to nearest dollar since exchange doesn't accept cents
            const maxAmount = Math.floor(availableCash);
            document.getElementById('buy-amount-input').value = maxAmount;
            CONFIG.BUY_AMOUNT = maxAmount;
            updateStatus(`Set buy amount to maximum: $${maxAmount} (rounded down from $${availableCash.toFixed(2)})`);
        });

        document.getElementById('refresh-interval').addEventListener('change', (e) => {
            CONFIG.REFRESH_INTERVAL = parseInt(e.target.value) || 2000;
            updateStatus(`Refresh interval set to ${CONFIG.REFRESH_INTERVAL} ms`);
        });

        document.getElementById('api-enabled').addEventListener('change', (e) => {
            CONFIG.API_ENABLED = e.target.checked;
            updateStatus(`API features ${CONFIG.API_ENABLED ? 'enabled' : 'disabled'}`);
        });

        // Tab navigation
        const tabButtons = document.querySelectorAll('.tab-btn');
        const tabContents = document.querySelectorAll('.tab-content');

        tabButtons.forEach(button => {
            button.addEventListener('click', () => {
                const targetTab = button.getAttribute('data-tab');

                // Update active tab button
                tabButtons.forEach(btn => {
                    btn.classList.remove('active');
                });
                button.classList.add('active');

                // Show/hide tab contents
                tabContents.forEach(content => {
                    if (content.id === targetTab) {
                        content.classList.add('active');
                    } else {
                        content.classList.remove('active');
                    }
                });
            });
        });
    }

    function updateStatus(message) {
        const status = document.getElementById('status');
        const timestamp = new Date().toLocaleTimeString();
        const messageDiv = document.createElement('div');
        messageDiv.innerHTML = `<span style="color: rgba(255,255,255,0.5);">[${timestamp}]</span> ${message}`;
        status.appendChild(messageDiv);
        status.scrollTop = status.scrollHeight;

        // Keep only last 10 messages to prevent memory issues
        while (status.children.length > 10) {
            status.removeChild(status.firstChild);
        }
    }

    function updateCounter() {
        document.getElementById('action-counter').textContent = actionCount;
    }

    function setButtonStates(running) {
        document.getElementById('sell-all-btn').disabled = running;
        document.getElementById('buy-btn').disabled = running;
        document.getElementById('stop-btn').disabled = !running;
    }

    // Generic function to find buttons by text content
    function findButtonByText(texts) {
        const buttons = document.querySelectorAll('button, input[type="button"], input[type="submit"], [role="button"]');

        for (const button of buttons) {
            const buttonText = button.textContent.toLowerCase().trim();
            const isVisible = button.offsetParent !== null;
            const isEnabled = !button.disabled;

            if (isVisible && isEnabled && texts.some(text => buttonText.includes(text.toLowerCase()))) {
                return button;
            }
        }
        return null;
    }

    // Enhanced button finding with multiple selectors
    function findSellButton() {
        // First try specific RugPlay selectors based on the HTML structure
        const rugplaySelectors = [
            'button[data-slot="button"]:has(svg.lucide-trending-down)',
            'button[data-slot="button"]:has(.lucide-trending-down)'
        ];

        for (const selector of rugplaySelectors) {
            try {
                const element = document.querySelector(selector);
                if (element && element.offsetParent !== null) {
                    // Return the button regardless of disabled state, we'll check separately
                    return element;
                }
            } catch (e) {
                // CSS :has() might not be supported in all browsers
            }
        }

        // Try finding by data-slot and checking for trending-down icon
        const buttons = document.querySelectorAll('button[data-slot="button"]');
        for (const button of buttons) {
            const text = button.textContent.toLowerCase();
            const hasDownIcon = button.querySelector('.lucide-trending-down');
            const isVisible = button.offsetParent !== null;

            if (isVisible && (text.includes('sell') || hasDownIcon)) {
                // Return the button regardless of disabled state
                return button;
            }
        }

        // Fallback to text-based search - also return regardless of disabled state
        const fallbackButtons = document.querySelectorAll('button, input[type="button"], input[type="submit"], [role="button"]');
        const sellTexts = ['sell', 'verkopen', 'vendre', 'продать'];

        for (const button of fallbackButtons) {
            const buttonText = button.textContent.toLowerCase().trim();
            const isVisible = button.offsetParent !== null;

            if (isVisible && sellTexts.some(text => buttonText.includes(text.toLowerCase()))) {
                return button;
            }
        }

        return null;
    }

    // New function to check if we can still sell
    function canSell() {
        const sellButton = findSellButton();
        if (!sellButton) {
            return false; // No sell button found
        }

        // Check if button is disabled
        const isDisabled = sellButton.disabled || sellButton.hasAttribute('disabled') ||
                          sellButton.getAttribute('aria-disabled') === 'true';

        return !isDisabled;
    }

    function findConfirmButton() {
        // Look specifically in dialog content for confirmation buttons
        const dialogContent = document.querySelector('div[data-slot="dialog-content"]');
        if (dialogContent) {
            // Look for the final action buttons in the dialog footer
            const footerButtons = dialogContent.querySelectorAll('div[data-slot="dialog-footer"] button[data-slot="button"]');

            for (const button of footerButtons) {
                const text = button.textContent.toLowerCase().trim();
                const isVisible = button.offsetParent !== null;
                const isEnabled = !button.disabled;

                // Skip cancel buttons, look for action buttons
                if (isVisible && isEnabled && !text.includes('cancel') &&
                    (text.includes('buy') || text.includes('sell') ||
                     text.includes('confirm') || text.includes('proceed'))) {
                    return button;
                }
            }
        }

        // Fallback to checking all visible buttons in dialogs
        const modalButtons = document.querySelectorAll('div[role="dialog"] button[data-slot="button"], .modal button[data-slot="button"]');
        for (const button of modalButtons) {
            const text = button.textContent.toLowerCase().trim();
            const isVisible = button.offsetParent !== null;
            const isEnabled = !button.disabled;

            if (isVisible && isEnabled && !text.includes('cancel') &&
                (text.includes('buy ') || text.startsWith('buy') ||
                 text.includes('sell ') || text.startsWith('sell') ||
                 text.includes('confirm') || text.includes('yes') ||
                 text.includes('ok') || text.includes('proceed') ||
                 text.includes('continue'))) {
                return button;
            }
        }

        return findButtonByText(['confirm', 'bevestigen', 'confirmer', 'подтвердить', 'yes', 'ok', 'proceed', 'continue']);
    }

    function findBuyButton() {
        // First try specific RugPlay selectors
        const rugplaySelectors = [
            'button[data-slot="button"]:has(svg.lucide-trending-up)',
            'button[data-slot="button"]:has(.lucide-trending-up)'
        ];

        for (const selector of rugplaySelectors) {
            try {
                const element = document.querySelector(selector);
                if (element && element.offsetParent !== null && !element.disabled) {
                    return element;
                }
            } catch (e) {
                // CSS selectors might not be supported
            }
        }

        // Try finding by data-slot and checking for trending-up icon
        const buttons = document.querySelectorAll('button[data-slot="button"]');
        for (const button of buttons) {
            const text = button.textContent.toLowerCase();
            const hasUpIcon = button.querySelector('.lucide-trending-up');
            const isVisible = button.offsetParent !== null;
            const isEnabled = !button.disabled;

            if (isVisible && isEnabled && (text.includes('buy') || hasUpIcon)) {
                return button;
            }
        }

        return findButtonByText(['buy', 'kopen', 'acheter', 'купить']);
    }

    function findMaxButton() {
        // Look specifically for Max button in the dialog content
        const dialogContent = document.querySelector('div[data-slot="dialog-content"]');
        if (dialogContent) {
            // Look for the Max button next to the amount input
            const maxButtons = dialogContent.querySelectorAll('button[data-slot="button"]');
            for (const button of maxButtons) {
                const text = button.textContent.toLowerCase().trim();
                const isVisible = button.offsetParent !== null;
                const isEnabled = !button.disabled;

                if (isVisible && isEnabled && text === 'max') {
                    return button;
                }
            }
        }

        // Fallback to searching all buttons
        const allButtons = document.querySelectorAll('button[data-slot="button"]');
        for (const button of allButtons) {
            const text = button.textContent.toLowerCase().trim();
            const isVisible = button.offsetParent !== null;
            const isEnabled = !button.disabled;

            if (isVisible && isEnabled && text === 'max') {
                return button;
            }
        }

        return null;
    }

    function findAmountInput() {
        // Look specifically in the dialog for the amount input
        const dialogContent = document.querySelector('div[data-slot="dialog-content"]');
        if (dialogContent) {
            const amountInput = dialogContent.querySelector('input[id="amount"]') ||
                             dialogContent.querySelector('input[type="number"]');
            if (amountInput && amountInput.offsetParent !== null) {
                return amountInput;
            }
        }

        // Fallback to general search
        return document.querySelector('input[type="number"]#amount') ||
               document.querySelector('input[placeholder="0.00"]') ||
               document.querySelector('input[type="number"]');
    }

    async function startSelling() {
        if (isRunning) return;

        isRunning = true;
        currentAction = 'sell';
        actionCount = 0;
        setButtonStates(true);

        updateStatus('Starting auto-sell process...');

        try {
            await performSellCycle();
        } catch (error) {
            updateStatus(`Error: ${error.message}`);
        } finally {
            stopAction();
        }
    }

    async function performSellCycle() {
        for (let i = 0; i < CONFIG.MAX_RETRIES && isRunning; i++) {
            updateStatus(`Attempt ${i + 1}/${CONFIG.MAX_RETRIES}...`);

            // Check if we can still sell before attempting
            if (!canSell()) {
                updateStatus('Sell button is disabled - no more holdings to sell');
                break;
            }

            const sellButton = findSellButton();
            if (!sellButton) {
                updateStatus('No sell button found');
                break;
            }

            // Click sell button to open modal
            sellButton.click();
            updateStatus('Clicked sell button, waiting for modal...');

            // Wait for modal to appear
            await sleep(CONFIG.CONFIRM_DELAY);

            // Look for Max button and click it
            const maxButton = findMaxButton();
            if (maxButton) {
                maxButton.click();
                updateStatus('Clicked Max button');
                await sleep(200); // Short delay for amount to populate
            } else {
                updateStatus('Max button not found, checking if amount is already set...');
            }

            // Additional wait for the amount to be populated
            await sleep(CONFIG.CONFIRM_DELAY);

            // Find and click the final sell confirmation button
            if (CONFIG.AUTO_CONFIRM) {
                const confirmButton = findConfirmButton();
                if (confirmButton) {
                    confirmButton.click();
                    updateStatus('Auto-confirmed sell transaction');
                    actionCount++;
                    updateCounter();
                } else {
                    updateStatus('Sell confirm button not found - manual confirmation needed');
                    // Still count as an action since we opened the modal
                    actionCount++;
                    updateCounter();
                }
            } else {
                updateStatus('Waiting for manual confirmation...');
                actionCount++;
                updateCounter();
            }

            // Wait before next iteration
            await sleep(CONFIG.SELL_DELAY);

            // Check again after the transaction to see if we're done
            if (!canSell()) {
                updateStatus('All holdings sold - sell button now disabled');
                break;
            }

            if (!isRunning) break;
        }

        if (actionCount >= CONFIG.MAX_RETRIES) {
            updateStatus('Reached maximum retry limit');
        } else if (!canSell()) {
            updateStatus('✅ Selling complete - no more holdings detected');
        }
    }

    async function startBuying() {
        if (isRunning) return;

        isRunning = true;
        currentAction = 'buy';
        actionCount = 0;
        setButtonStates(true);

        updateStatus('Starting auto-buy process...');

        try {
            const buyButton = findBuyButton();
            if (!buyButton) {
                updateStatus('Buy button not found');
                stopAction();
                return;
            }

            // Click buy button to open modal
            buyButton.click();
            updateStatus('Clicked buy button, waiting for modal...');

            // Wait for modal to appear
            await sleep(CONFIG.CONFIRM_DELAY);

            // Set the custom buy amount from the input field
            const buyAmountInput = document.getElementById('buy-amount-input');
            const customAmount = parseFloat(buyAmountInput.value) || CONFIG.BUY_AMOUNT;

            const amountInput = findAmountInput();
            if (amountInput) {
                amountInput.value = customAmount;
                amountInput.dispatchEvent(new Event('input', { bubbles: true }));
                amountInput.dispatchEvent(new Event('change', { bubbles: true }));
                updateStatus(`Set buy amount to: $${customAmount}`);
                await sleep(200); // Short delay for amount to populate
            } else {
                updateStatus('Amount input not found in dialog');
            }

            await sleep(CONFIG.CONFIRM_DELAY);

            // Find and click the final buy confirmation button
            if (CONFIG.AUTO_CONFIRM) {
                const confirmButton = findConfirmButton();
                if (confirmButton) {
                    confirmButton.click();
                    updateStatus('Auto-confirmed buy transaction');
                    actionCount++;
                    updateCounter();
                } else {
                    updateStatus('Confirm button not found - manual confirmation needed');
                    actionCount++;
                    updateCounter();
                }
            } else {
                updateStatus('Waiting for manual confirmation...');
                actionCount++;
                updateCounter();
            }

        } catch (error) {
            updateStatus(`Buy error: ${error.message}`);
        } finally {
            stopAction();
        }
    }

    function stopAction() {
        isRunning = false;
        currentAction = null;
        setButtonStates(false);
        updateStatus(`Stopped. Total actions: ${actionCount}`);
    }

    function sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }

    // Initialize when page loads
    function init() {
        console.log('RugPlay X: Script loading...');
        console.log('Current URL:', window.location.href);

        // Initialize API headers for enhanced features
        if (CONFIG.API_ENABLED) {
            setTimeout(() => {
                const apiInitialized = initializeApiHeaders();
                if (apiInitialized) {
                    updateStatus('API integration enabled');
                } else {
                    updateStatus('API features unavailable - using DOM fallback');
                }
            }, 2000);
        }

        // Force create panel after a delay to ensure DOM is ready
        setTimeout(() => {
            console.log('RugPlay X: Creating control panel...');
            createControlPanel();
            console.log('RugPlay X: Control panel created!');

            // Start periodic cash updates
            setInterval(updateCashDisplay, CONFIG.REFRESH_INTERVAL);
        }, 1000);

        // Also try when DOM is ready
        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', () => {
                console.log('RugPlay X: DOM loaded, creating panel...');
                if (!document.getElementById('rugplay-auto-trader')) {
                    createControlPanel();
                    setTimeout(() => {
                        setInterval(updateCashDisplay, CONFIG.REFRESH_INTERVAL);
                    }, 500);
                }
            });
        }

        // And try when window is fully loaded
        window.addEventListener('load', () => {
            console.log('RugPlay X: Window loaded, ensuring panel exists...');
            if (!document.getElementById('rugplay-auto-trader')) {
                createControlPanel();
                setTimeout(() => {
                    setInterval(updateCashDisplay, CONFIG.REFRESH_INTERVAL);
                }, 500);
            }
        });
    }

    // Emergency stop with Escape key
    document.addEventListener('keydown', (e) => {
        if (e.key === 'Escape' && isRunning) {
            stopAction();
            updateStatus('Emergency stop activated');
        }
    });

    init();
})();