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})();