Pump.fun Trading Bot - Auto Buy, Sell & Sniper

Automated trading assistant with auto-buy, auto-sell, and token launch sniping features for Pump.fun

Size

29.8 KB

Version

1.2.1

Created

Jan 30, 2026

Updated

5 days ago

1// ==UserScript==
2// @name		Pump.fun Trading Bot - Auto Buy, Sell & Sniper
3// @description		Automated trading assistant with auto-buy, auto-sell, and token launch sniping features for Pump.fun
4// @version		1.2.1
5// @match		https://*.pump.fun/*
6// @icon		https://pump.fun/icon1.png?icon1.ee49a4c9.png
7// @grant		GM.getValue
8// @grant		GM.setValue
9// @grant		GM.xmlHttpRequest
10// @grant		GM.notification
11// ==/UserScript==
12(function() {
13    'use strict';
14
15    // Configuration and State
16    let config = {
17        autoBuy: {
18            enabled: false,
19            minMarketCap: 10000,
20            maxMarketCap: 100000,
21            buyAmount: 0.1,
22            maxSlippage: 5
23        },
24        autoSell: {
25            enabled: false,
26            profitTarget: 50, // percentage
27            stopLoss: 20, // percentage
28            trailingStop: false,
29            trailingStopPercent: 10
30        },
31        sniper: {
32            enabled: false,
33            buyAmount: 0.5,
34            maxSlippage: 10,
35            keywords: [] // keywords to filter new tokens
36        }
37    };
38
39    let monitoredTokens = new Map(); // token address -> purchase data
40    let isMonitoring = false;
41
42    // Utility Functions
43    function debounce(func, wait) {
44        let timeout;
45        return function executedFunction(...args) {
46            const later = () => {
47                clearTimeout(timeout);
48                func(...args);
49            };
50            clearTimeout(timeout);
51            timeout = setTimeout(later, wait);
52        };
53    }
54
55    async function loadConfig() {
56        try {
57            const saved = await GM.getValue('pumpfun_bot_config');
58            if (saved) {
59                config = JSON.parse(saved);
60                console.log('[Pump Bot] Config loaded:', config);
61            }
62            const tokens = await GM.getValue('pumpfun_monitored_tokens');
63            if (tokens) {
64                monitoredTokens = new Map(JSON.parse(tokens));
65                console.log('[Pump Bot] Monitored tokens loaded:', monitoredTokens.size);
66            }
67        } catch (error) {
68            console.error('[Pump Bot] Error loading config:', error);
69        }
70    }
71
72    async function saveConfig() {
73        try {
74            await GM.setValue('pumpfun_bot_config', JSON.stringify(config));
75            await GM.setValue('pumpfun_monitored_tokens', JSON.stringify(Array.from(monitoredTokens.entries())));
76            console.log('[Pump Bot] Config saved');
77        } catch (error) {
78            console.error('[Pump Bot] Error saving config:', error);
79        }
80    }
81
82    function showNotification(title, message, type = 'info') {
83        console.log(`[Pump Bot] ${type.toUpperCase()}: ${title} - ${message}`);
84        
85        // Create visual notification
86        const notification = document.createElement('div');
87        notification.style.cssText = `
88            position: fixed;
89            top: 80px;
90            right: 20px;
91            background: ${type === 'success' ? '#10b981' : type === 'error' ? '#ef4444' : '#3b82f6'};
92            color: white;
93            padding: 16px 20px;
94            border-radius: 8px;
95            box-shadow: 0 4px 12px rgba(0,0,0,0.3);
96            z-index: 100000;
97            max-width: 350px;
98            font-family: system-ui, -apple-system, sans-serif;
99            animation: slideIn 0.3s ease-out;
100        `;
101        notification.innerHTML = `
102            <div style="font-weight: 600; margin-bottom: 4px;">${title}</div>
103            <div style="font-size: 14px; opacity: 0.95;">${message}</div>
104        `;
105        document.body.appendChild(notification);
106
107        setTimeout(() => {
108            notification.style.animation = 'slideOut 0.3s ease-out';
109            setTimeout(() => notification.remove(), 300);
110        }, 5000);
111    }
112
113    // Trading Functions
114    async function executeBuy(tokenAddress, amount, slippage) {
115        console.log(`[Pump Bot] Executing buy: ${tokenAddress}, Amount: ${amount} SOL, Slippage: ${slippage}%`);
116        
117        try {
118            // Find buy button and input fields
119            const buyInput = document.querySelector('input[type="text"][placeholder*="SOL"], input[type="number"][placeholder*="SOL"]');
120            const buyButton = document.querySelector('button[data-testid*="buy"], button:has-text("Buy"), button[class*="buy"]');
121            
122            if (!buyInput || !buyButton) {
123                throw new Error('Buy interface not found. Please navigate to a token page.');
124            }
125
126            // Set amount
127            buyInput.value = amount.toString();
128            buyInput.dispatchEvent(new Event('input', { bubbles: true }));
129            buyInput.dispatchEvent(new Event('change', { bubbles: true }));
130
131            // Wait a bit for UI to update
132            await new Promise(resolve => setTimeout(resolve, 500));
133
134            // Click buy button
135            buyButton.click();
136            
137            // Store token for monitoring
138            monitoredTokens.set(tokenAddress, {
139                purchasePrice: 0, // Will be updated after transaction
140                purchaseTime: Date.now(),
141                amount: amount,
142                highestPrice: 0
143            });
144            await saveConfig();
145
146            showNotification('Buy Order Placed', `Buying ${amount} SOL of token`, 'success');
147            return true;
148        } catch (error) {
149            console.error('[Pump Bot] Buy error:', error);
150            showNotification('Buy Failed', error.message, 'error');
151            return false;
152        }
153    }
154
155    async function executeSell(tokenAddress, percentage = 100) {
156        console.log(`[Pump Bot] Executing sell: ${tokenAddress}, Percentage: ${percentage}%`);
157        
158        try {
159            const sellButton = document.querySelector('button[data-testid*="sell"], button:has-text("Sell"), button[class*="sell"]');
160            
161            if (!sellButton) {
162                throw new Error('Sell interface not found. Please navigate to the token page.');
163            }
164
165            if (percentage < 100) {
166                // Try to find percentage input or slider
167                const percentInput = document.querySelector('input[type="range"], input[placeholder*="%"]');
168                if (percentInput) {
169                    percentInput.value = percentage.toString();
170                    percentInput.dispatchEvent(new Event('input', { bubbles: true }));
171                    percentInput.dispatchEvent(new Event('change', { bubbles: true }));
172                }
173            }
174
175            await new Promise(resolve => setTimeout(resolve, 500));
176            sellButton.click();
177
178            if (percentage === 100) {
179                monitoredTokens.delete(tokenAddress);
180                await saveConfig();
181            }
182
183            showNotification('Sell Order Placed', `Selling ${percentage}% of token`, 'success');
184            return true;
185        } catch (error) {
186            console.error('[Pump Bot] Sell error:', error);
187            showNotification('Sell Failed', error.message, 'error');
188            return false;
189        }
190    }
191
192    // Monitoring Functions
193    async function checkTokenPrice(tokenAddress) {
194        try {
195            // Try to extract price from page
196            const priceElements = document.querySelectorAll('[class*="price"], [data-testid*="price"]');
197            for (const elem of priceElements) {
198                const text = elem.textContent;
199                const priceMatch = text.match(/\$?([\d,]+\.?\d*)/);
200                if (priceMatch) {
201                    return parseFloat(priceMatch[1].replace(/,/g, ''));
202                }
203            }
204            return null;
205        } catch (error) {
206            console.error('[Pump Bot] Error checking price:', error);
207            return null;
208        }
209    }
210
211    async function monitorTokens() {
212        if (!config.autoSell.enabled || monitoredTokens.size === 0) {
213            return;
214        }
215
216        console.log(`[Pump Bot] Monitoring ${monitoredTokens.size} tokens`);
217
218        for (const [tokenAddress, data] of monitoredTokens.entries()) {
219            const currentPrice = await checkTokenPrice(tokenAddress);
220            if (!currentPrice || !data.purchasePrice) continue;
221
222            const priceChange = ((currentPrice - data.purchasePrice) / data.purchasePrice) * 100;
223            
224            // Update highest price for trailing stop
225            if (currentPrice > data.highestPrice) {
226                data.highestPrice = currentPrice;
227                monitoredTokens.set(tokenAddress, data);
228            }
229
230            console.log(`[Pump Bot] Token ${tokenAddress}: Price change ${priceChange.toFixed(2)}%`);
231
232            // Check profit target
233            if (priceChange >= config.autoSell.profitTarget) {
234                showNotification('Profit Target Hit!', `Token up ${priceChange.toFixed(2)}%. Selling...`, 'success');
235                await executeSell(tokenAddress, 100);
236                continue;
237            }
238
239            // Check stop loss
240            if (priceChange <= -config.autoSell.stopLoss) {
241                showNotification('Stop Loss Triggered', `Token down ${Math.abs(priceChange).toFixed(2)}%. Selling...`, 'error');
242                await executeSell(tokenAddress, 100);
243                continue;
244            }
245
246            // Check trailing stop
247            if (config.autoSell.trailingStop && data.highestPrice > data.purchasePrice) {
248                const dropFromHigh = ((data.highestPrice - currentPrice) / data.highestPrice) * 100;
249                if (dropFromHigh >= config.autoSell.trailingStopPercent) {
250                    showNotification('Trailing Stop Triggered', `Price dropped ${dropFromHigh.toFixed(2)}% from high. Selling...`, 'error');
251                    await executeSell(tokenAddress, 100);
252                }
253            }
254        }
255    }
256
257    async function monitorNewTokens() {
258        if (!config.sniper.enabled) return;
259
260        try {
261            // Look for new token listings
262            const tokenCards = document.querySelectorAll('[class*="ticker-item"], [data-testid*="token-card"], .token-card');
263            
264            for (const card of tokenCards) {
265                const tokenName = card.querySelector('[class*="name"], [data-testid*="name"]')?.textContent || '';
266                const tokenAddress = card.querySelector('a')?.href?.split('/').pop() || '';
267                
268                if (!tokenAddress) continue;
269
270                // Check if we've already processed this token
271                const processedKey = `processed_${tokenAddress}`;
272                const alreadyProcessed = await GM.getValue(processedKey);
273                if (alreadyProcessed) continue;
274
275                // Check keywords filter
276                if (config.sniper.keywords.length > 0) {
277                    const matchesKeyword = config.sniper.keywords.some(keyword => 
278                        tokenName.toLowerCase().includes(keyword.toLowerCase())
279                    );
280                    if (!matchesKeyword) continue;
281                }
282
283                console.log(`[Pump Bot] New token detected: ${tokenName} (${tokenAddress})`);
284                showNotification('New Token Detected!', `Found: ${tokenName}. Attempting to snipe...`, 'info');
285
286                // Navigate to token page and buy
287                card.querySelector('a')?.click();
288                
289                // Wait for page load
290                await new Promise(resolve => setTimeout(resolve, 2000));
291                
292                // Execute buy
293                await executeBuy(tokenAddress, config.sniper.buyAmount, config.sniper.maxSlippage);
294                
295                // Mark as processed
296                await GM.setValue(processedKey, true);
297                
298                // Wait before checking next token
299                await new Promise(resolve => setTimeout(resolve, 1000));
300            }
301        } catch (error) {
302            console.error('[Pump Bot] Error monitoring new tokens:', error);
303        }
304    }
305
306    // Start monitoring loop
307    async function startMonitoring() {
308        if (isMonitoring) return;
309        isMonitoring = true;
310        
311        console.log('[Pump Bot] Starting monitoring loop');
312        
313        setInterval(async () => {
314            await monitorTokens();
315            await monitorNewTokens();
316        }, 5000); // Check every 5 seconds
317    }
318
319    // UI Creation
320    function createUI() {
321        // Add styles
322        const style = document.createElement('style');
323        style.textContent = `
324            @keyframes slideIn {
325                from { transform: translateX(400px); opacity: 0; }
326                to { transform: translateX(0); opacity: 1; }
327            }
328            @keyframes slideOut {
329                from { transform: translateX(0); opacity: 1; }
330                to { transform: translateX(400px); opacity: 0; }
331            }
332            .pump-bot-panel {
333                position: fixed;
334                top: 80px;
335                right: 20px;
336                width: 380px;
337                background: linear-gradient(135deg, #1e293b 0%, #0f172a 100%);
338                border: 1px solid #334155;
339                border-radius: 12px;
340                box-shadow: 0 8px 32px rgba(0,0,0,0.4);
341                z-index: 99999;
342                font-family: system-ui, -apple-system, sans-serif;
343                color: #e2e8f0;
344                max-height: calc(100vh - 100px);
345                overflow-y: auto;
346            }
347            .pump-bot-header {
348                background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
349                padding: 16px;
350                border-radius: 12px 12px 0 0;
351                display: flex;
352                justify-content: space-between;
353                align-items: center;
354                cursor: move;
355            }
356            .pump-bot-title {
357                font-size: 16px;
358                font-weight: 700;
359                color: white;
360            }
361            .pump-bot-close {
362                background: rgba(255,255,255,0.2);
363                border: none;
364                color: white;
365                width: 28px;
366                height: 28px;
367                border-radius: 6px;
368                cursor: pointer;
369                font-size: 18px;
370                display: flex;
371                align-items: center;
372                justify-content: center;
373                transition: background 0.2s;
374            }
375            .pump-bot-close:hover {
376                background: rgba(255,255,255,0.3);
377            }
378            .pump-bot-content {
379                padding: 16px;
380            }
381            .pump-bot-section {
382                background: #1e293b;
383                border: 1px solid #334155;
384                border-radius: 8px;
385                padding: 14px;
386                margin-bottom: 12px;
387            }
388            .pump-bot-section-header {
389                display: flex;
390                justify-content: space-between;
391                align-items: center;
392                margin-bottom: 12px;
393            }
394            .pump-bot-section-title {
395                font-size: 14px;
396                font-weight: 600;
397                color: #f1f5f9;
398            }
399            .pump-bot-toggle {
400                position: relative;
401                width: 44px;
402                height: 24px;
403                background: #475569;
404                border-radius: 12px;
405                cursor: pointer;
406                transition: background 0.3s;
407            }
408            .pump-bot-toggle.active {
409                background: #10b981;
410            }
411            .pump-bot-toggle::after {
412                content: '';
413                position: absolute;
414                top: 2px;
415                left: 2px;
416                width: 20px;
417                height: 20px;
418                background: white;
419                border-radius: 50%;
420                transition: transform 0.3s;
421            }
422            .pump-bot-toggle.active::after {
423                transform: translateX(20px);
424            }
425            .pump-bot-input-group {
426                margin-bottom: 10px;
427            }
428            .pump-bot-label {
429                display: block;
430                font-size: 12px;
431                color: #94a3b8;
432                margin-bottom: 4px;
433            }
434            .pump-bot-input {
435                width: 100%;
436                background: #0f172a;
437                border: 1px solid #334155;
438                border-radius: 6px;
439                padding: 8px 10px;
440                color: #e2e8f0;
441                font-size: 13px;
442                box-sizing: border-box;
443            }
444            .pump-bot-input:focus {
445                outline: none;
446                border-color: #3b82f6;
447            }
448            .pump-bot-button {
449                width: 100%;
450                background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
451                border: none;
452                border-radius: 6px;
453                padding: 10px;
454                color: white;
455                font-size: 13px;
456                font-weight: 600;
457                cursor: pointer;
458                transition: transform 0.2s, box-shadow 0.2s;
459                margin-top: 8px;
460            }
461            .pump-bot-button:hover {
462                transform: translateY(-1px);
463                box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4);
464            }
465            .pump-bot-button:active {
466                transform: translateY(0);
467            }
468            .pump-bot-stats {
469                display: grid;
470                grid-template-columns: 1fr 1fr;
471                gap: 8px;
472                margin-top: 12px;
473            }
474            .pump-bot-stat {
475                background: #0f172a;
476                border: 1px solid #334155;
477                border-radius: 6px;
478                padding: 8px;
479                text-align: center;
480            }
481            .pump-bot-stat-value {
482                font-size: 16px;
483                font-weight: 700;
484                color: #3b82f6;
485            }
486            .pump-bot-stat-label {
487                font-size: 11px;
488                color: #64748b;
489                margin-top: 2px;
490            }
491            .pump-bot-minimize {
492                position: fixed;
493                bottom: 20px;
494                right: 20px;
495                width: 60px;
496                height: 60px;
497                background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
498                border: none;
499                border-radius: 50%;
500                color: white;
501                font-size: 24px;
502                cursor: pointer;
503                box-shadow: 0 4px 16px rgba(59, 130, 246, 0.4);
504                z-index: 99998;
505                display: none;
506                align-items: center;
507                justify-content: center;
508                transition: transform 0.2s;
509            }
510            .pump-bot-minimize:hover {
511                transform: scale(1.1);
512            }
513        `;
514        document.head.appendChild(style);
515
516        // Create panel
517        const panel = document.createElement('div');
518        panel.className = 'pump-bot-panel';
519        panel.innerHTML = `
520            <div class="pump-bot-header">
521                <div class="pump-bot-title">🤖 Pump Trading Bot</div>
522                <button class="pump-bot-close" id="pumpBotClose">×</button>
523            </div>
524            <div class="pump-bot-content">
525                <!-- Auto Buy Section -->
526                <div class="pump-bot-section">
527                    <div class="pump-bot-section-header">
528                        <div class="pump-bot-section-title">🎯 Auto Buy</div>
529                        <div class="pump-bot-toggle" id="autoBuyToggle"></div>
530                    </div>
531                    <div class="pump-bot-input-group">
532                        <label class="pump-bot-label">Min Market Cap ($)</label>
533                        <input type="number" class="pump-bot-input" id="minMarketCap" value="${config.autoBuy.minMarketCap}">
534                    </div>
535                    <div class="pump-bot-input-group">
536                        <label class="pump-bot-label">Max Market Cap ($)</label>
537                        <input type="number" class="pump-bot-input" id="maxMarketCap" value="${config.autoBuy.maxMarketCap}">
538                    </div>
539                    <div class="pump-bot-input-group">
540                        <label class="pump-bot-label">Buy Amount (SOL)</label>
541                        <input type="number" step="0.01" class="pump-bot-input" id="buyAmount" value="${config.autoBuy.buyAmount}">
542                    </div>
543                    <div class="pump-bot-input-group">
544                        <label class="pump-bot-label">Max Slippage (%)</label>
545                        <input type="number" class="pump-bot-input" id="maxSlippage" value="${config.autoBuy.maxSlippage}">
546                    </div>
547                </div>
548
549                <!-- Auto Sell Section -->
550                <div class="pump-bot-section">
551                    <div class="pump-bot-section-header">
552                        <div class="pump-bot-section-title">💰 Auto Sell</div>
553                        <div class="pump-bot-toggle" id="autoSellToggle"></div>
554                    </div>
555                    <div class="pump-bot-input-group">
556                        <label class="pump-bot-label">Profit Target (%)</label>
557                        <input type="number" class="pump-bot-input" id="profitTarget" value="${config.autoSell.profitTarget}">
558                    </div>
559                    <div class="pump-bot-input-group">
560                        <label class="pump-bot-label">Stop Loss (%)</label>
561                        <input type="number" class="pump-bot-input" id="stopLoss" value="${config.autoSell.stopLoss}">
562                    </div>
563                    <div class="pump-bot-input-group">
564                        <label class="pump-bot-label">
565                            <input type="checkbox" id="trailingStop" ${config.autoSell.trailingStop ? 'checked' : ''}>
566                            Enable Trailing Stop
567                        </label>
568                    </div>
569                    <div class="pump-bot-input-group">
570                        <label class="pump-bot-label">Trailing Stop (%)</label>
571                        <input type="number" class="pump-bot-input" id="trailingStopPercent" value="${config.autoSell.trailingStopPercent}">
572                    </div>
573                </div>
574
575                <!-- Sniper Section -->
576                <div class="pump-bot-section">
577                    <div class="pump-bot-section-header">
578                        <div class="pump-bot-section-title">⚡ Token Sniper</div>
579                        <div class="pump-bot-toggle" id="sniperToggle"></div>
580                    </div>
581                    <div class="pump-bot-input-group">
582                        <label class="pump-bot-label">Snipe Amount (SOL)</label>
583                        <input type="number" step="0.01" class="pump-bot-input" id="snipeBuyAmount" value="${config.sniper.buyAmount}">
584                    </div>
585                    <div class="pump-bot-input-group">
586                        <label class="pump-bot-label">Max Slippage (%)</label>
587                        <input type="number" class="pump-bot-input" id="snipeMaxSlippage" value="${config.sniper.maxSlippage}">
588                    </div>
589                    <div class="pump-bot-input-group">
590                        <label class="pump-bot-label">Keywords (comma separated, optional)</label>
591                        <input type="text" class="pump-bot-input" id="sniperKeywords" value="${config.sniper.keywords.join(', ')}">
592                    </div>
593                </div>
594
595                <!-- Stats Section -->
596                <div class="pump-bot-section">
597                    <div class="pump-bot-section-title" style="margin-bottom: 8px;">📊 Statistics</div>
598                    <div class="pump-bot-stats">
599                        <div class="pump-bot-stat">
600                            <div class="pump-bot-stat-value" id="monitoredCount">${monitoredTokens.size}</div>
601                            <div class="pump-bot-stat-label">Monitored</div>
602                        </div>
603                        <div class="pump-bot-stat">
604                            <div class="pump-bot-stat-value" id="activeFeatures">0</div>
605                            <div class="pump-bot-stat-label">Active Features</div>
606                        </div>
607                    </div>
608                </div>
609
610                <button class="pump-bot-button" id="saveConfig">💾 Save Configuration</button>
611            </div>
612        `;
613
614        document.body.appendChild(panel);
615
616        // Create minimize button
617        const minimizeBtn = document.createElement('button');
618        minimizeBtn.className = 'pump-bot-minimize';
619        minimizeBtn.innerHTML = '🤖';
620        minimizeBtn.id = 'pumpBotMinimize';
621        document.body.appendChild(minimizeBtn);
622
623        // Setup event listeners
624        setupEventListeners(panel, minimizeBtn);
625        updateUI();
626    }
627
628    function setupEventListeners(panel, minimizeBtn) {
629        // Close/Minimize button
630        document.getElementById('pumpBotClose').addEventListener('click', () => {
631            panel.style.display = 'none';
632            minimizeBtn.style.display = 'flex';
633        });
634
635        minimizeBtn.addEventListener('click', () => {
636            panel.style.display = 'block';
637            minimizeBtn.style.display = 'none';
638        });
639
640        // Toggles
641        document.getElementById('autoBuyToggle').addEventListener('click', function() {
642            config.autoBuy.enabled = !config.autoBuy.enabled;
643            this.classList.toggle('active', config.autoBuy.enabled);
644            updateActiveFeatures();
645            saveConfig();
646            showNotification('Auto Buy', config.autoBuy.enabled ? 'Enabled' : 'Disabled', 'info');
647        });
648
649        document.getElementById('autoSellToggle').addEventListener('click', function() {
650            config.autoSell.enabled = !config.autoSell.enabled;
651            this.classList.toggle('active', config.autoSell.enabled);
652            updateActiveFeatures();
653            saveConfig();
654            showNotification('Auto Sell', config.autoSell.enabled ? 'Enabled' : 'Disabled', 'info');
655        });
656
657        document.getElementById('sniperToggle').addEventListener('click', function() {
658            config.sniper.enabled = !config.sniper.enabled;
659            this.classList.toggle('active', config.sniper.enabled);
660            updateActiveFeatures();
661            saveConfig();
662            showNotification('Token Sniper', config.sniper.enabled ? 'Enabled' : 'Disabled', 'info');
663        });
664
665        // Save button
666        document.getElementById('saveConfig').addEventListener('click', () => {
667            // Update config from inputs
668            config.autoBuy.minMarketCap = parseFloat(document.getElementById('minMarketCap').value);
669            config.autoBuy.maxMarketCap = parseFloat(document.getElementById('maxMarketCap').value);
670            config.autoBuy.buyAmount = parseFloat(document.getElementById('buyAmount').value);
671            config.autoBuy.maxSlippage = parseFloat(document.getElementById('maxSlippage').value);
672            
673            config.autoSell.profitTarget = parseFloat(document.getElementById('profitTarget').value);
674            config.autoSell.stopLoss = parseFloat(document.getElementById('stopLoss').value);
675            config.autoSell.trailingStop = document.getElementById('trailingStop').checked;
676            config.autoSell.trailingStopPercent = parseFloat(document.getElementById('trailingStopPercent').value);
677            
678            config.sniper.buyAmount = parseFloat(document.getElementById('snipeBuyAmount').value);
679            config.sniper.maxSlippage = parseFloat(document.getElementById('snipeMaxSlippage').value);
680            config.sniper.keywords = document.getElementById('sniperKeywords').value
681                .split(',')
682                .map(k => k.trim())
683                .filter(k => k.length > 0);
684
685            saveConfig();
686            showNotification('Configuration Saved', 'All settings have been saved successfully', 'success');
687        });
688
689        // Make panel draggable
690        makeDraggable(panel);
691    }
692
693    function updateUI() {
694        // Update toggles
695        document.getElementById('autoBuyToggle').classList.toggle('active', config.autoBuy.enabled);
696        document.getElementById('autoSellToggle').classList.toggle('active', config.autoSell.enabled);
697        document.getElementById('sniperToggle').classList.toggle('active', config.sniper.enabled);
698        
699        updateActiveFeatures();
700    }
701
702    function updateActiveFeatures() {
703        const activeCount = [config.autoBuy.enabled, config.autoSell.enabled, config.sniper.enabled].filter(Boolean).length;
704        document.getElementById('activeFeatures').textContent = activeCount;
705    }
706
707    function makeDraggable(element) {
708        let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
709        const header = element.querySelector('.pump-bot-header');
710        
711        header.onmousedown = dragMouseDown;
712
713        function dragMouseDown(e) {
714            e.preventDefault();
715            pos3 = e.clientX;
716            pos4 = e.clientY;
717            document.onmouseup = closeDragElement;
718            document.onmousemove = elementDrag;
719        }
720
721        function elementDrag(e) {
722            e.preventDefault();
723            pos1 = pos3 - e.clientX;
724            pos2 = pos4 - e.clientY;
725            pos3 = e.clientX;
726            pos4 = e.clientY;
727            element.style.top = (element.offsetTop - pos2) + "px";
728            element.style.left = (element.offsetLeft - pos1) + "px";
729            element.style.right = 'auto';
730        }
731
732        function closeDragElement() {
733            document.onmouseup = null;
734            document.onmousemove = null;
735        }
736    }
737
738    // Initialize
739    async function init() {
740        console.log('[Pump Bot] Initializing...');
741        
742        await loadConfig();
743        
744        // Wait for page to be ready
745        if (document.readyState === 'loading') {
746            document.addEventListener('DOMContentLoaded', createUI);
747        } else {
748            createUI();
749        }
750
751        // Start monitoring
752        startMonitoring();
753        
754        showNotification('Pump Trading Bot', 'Bot initialized and ready!', 'success');
755    }
756
757    // Start the bot
758    init();
759})();
Pump.fun Trading Bot - Auto Buy, Sell & Sniper | Robomonkey