您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Add Demo Trading tab and functional demo trade panel
// ==UserScript== // @name Web3 OKX Demo Trade Addon // @namespace http://tampermonkey.net/ // @version 1.1 // @description Add Demo Trading tab and functional demo trade panel // @author mamiis // @match https://web3.okx.com/* // @grant none // @license MIT // ==/UserScript== (function() { 'use strict'; let demoMode = false; let demoBalance = 1000; let demoPanelVisible = false; let currentTokenPrice = 0.001; let currentSolPrice = 100; let currentTokenSymbol = 'TOKEN'; let currentTokenImage = ''; let totalPnL = 0; let totalPnLPercent = 0; let tokenPnL = 0; let tokenPnLPercent = 0; let currentSettings = { buySlippage: '15%', sellSlippage: '20%', buyAmounts: ['0.03', '0.05', '0.07'], sellPercents: ['50%', '75%', '100%'], serviceFee: '0.68%', marketFee: '0.0004-0.0009 SOL' }; // Customize amounts state let customizeMode = false; let tempBuyAmounts = [...currentSettings.buyAmounts]; let tempSellPercents = [...currentSettings.sellPercents]; let tempServiceFee = currentSettings.serviceFee; // Sayfa değişikliklerini izlemek için observer let pageObserver = null; // Geçmiş işlemleri takip etmek için yeni değişkenler // localStorage'dan portföyü yükle let demoPortfolio = JSON.parse(localStorage.getItem('demoPortfolio')) || { 'SOL': { amount: 10, avgPrice: 100 }, 'TOKEN': { amount: 0, avgPrice: 0 } }; let totalRealizedPnL = parseFloat(localStorage.getItem('totalRealizedPnL')) || 0; let totalTradeVolume = parseFloat(localStorage.getItem('totalTradeVolume')) || 0; let tradeHistory = JSON.parse(localStorage.getItem('tradeHistory')) || []; function initDemoTrading() { console.log('Initializing Demo Trading...'); addDemoTab(); addDemoButton(); setupDemoMode(); loadSettingsFromRealPanel(); startPriceUpdates(); startSolPriceUpdates(); setupPageObserver(); } function setupPageObserver() { // Eğer observer zaten varsa, önce onu durdur if (pageObserver) { pageObserver.disconnect(); } // Sayfa değişikliklerini izle pageObserver = new MutationObserver(function(mutations) { let shouldUpdate = false; mutations.forEach(function(mutation) { // Yeni node'lar eklendiğinde kontrol et if (mutation.addedNodes && mutation.addedNodes.length > 0) { for (let node of mutation.addedNodes) { if (node.nodeType === 1) { // Element node // Tab container değişti mi? if (node.querySelector && ( node.querySelector('.dex-tabs-pane-list-container') || node.querySelector('.Q68nJL__dex') || node.querySelector('.vP8ohB__dex') )) { shouldUpdate = true; break; } } } } // Attribute değişiklikleri (active tab değişimi) if (mutation.type === 'attributes' && (mutation.attributeName === 'class' || mutation.attributeName === 'data-pane-id')) { shouldUpdate = true; } }); if (shouldUpdate) { console.log('Page changed, updating demo components...'); setTimeout(updateDemoComponents, 500); } }); // Tüm sayfayı izle pageObserver.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['class', 'data-pane-id'] }); } function updateDemoComponents() { // Demo tab'ı kontrol et ve ekle if (!document.querySelector('[data-pane-id="demo_trading"]')) { addDemoTab(); } // Demo butonunu kontrol et ve ekle if (!document.querySelector('.demo-trade-button')) { addDemoButton(); } // Demo panel açıksa güncelle if (demoPanelVisible) { updateDemoPanelValues(); } // Aktif tab'ı güncelle updateActiveTab(); } function loadSettingsFromRealPanel() { const realPanel = document.querySelector('.cIknRK__dex:not(.demo-trade-panel)'); if (realPanel) { // Buy slippage const buySlippage = realPanel.querySelector('.Nox6EF__dex .font-500'); if (buySlippage) { currentSettings.buySlippage = buySlippage.textContent || '15%'; } // Sell slippage const sellSlippageElements = realPanel.querySelectorAll('.Nox6EF__dex .font-500'); if (sellSlippageElements.length > 1) { currentSettings.sellSlippage = sellSlippageElements[1].textContent || '20%'; } // Buy amounts const buyAmounts = realPanel.querySelectorAll('.H5f_ax__dex.Cg7h1c__dex .l5GPKh__dex'); if (buyAmounts.length >= 3) { currentSettings.buyAmounts = [ buyAmounts[0].textContent || '0.03', buyAmounts[1].textContent || '0.05', buyAmounts[2].textContent || '0.07' ]; } // Sell percents const sellPercents = realPanel.querySelectorAll('.H5f_ax__dex.ODJ17x__dex .l5GPKh__dex'); if (sellPercents.length >= 3) { currentSettings.sellPercents = [ sellPercents[0].textContent || '50%', sellPercents[1].textContent || '75%', sellPercents[2].textContent || '100%' ]; } } } function getCurrentPrices() { try { const previousTokenSymbol = currentTokenSymbol; let priceFound = false; console.log('--- COIN PRICE SEARCH STARTED ---'); // 1. TOKEN PRICE BULMA - GÜNCELLENMİŞ VERSİYON const priceDivs = document.querySelectorAll('.glKoFv__dex'); let priceValue = null; // Tüm glKoFv__dex div'lerini kontrol et for (let div of priceDivs) { const labelDiv = div.querySelector('.KMsU5K__dex'); if (labelDiv && labelDiv.textContent === 'Price') { const priceValueDiv = div.querySelector('.IMDFTB__dex'); if (priceValueDiv) { priceValue = priceValueDiv.textContent.trim(); console.log('✅ PRICE TEXT FOUND:', priceValue); break; } } } if (priceValue) { let cleanedPrice = priceValue.replace('$', '').trim(); // Özel subscript karakterlerini sıfırlara çevir const subscriptMap = { '₀': 0, '₁': 1, '₂': 2, '₃': 3, '₄': 4, '₅': 5, '₆': 6, '₇': 7, '₈': 8, '₉': 9 }; // "0.0₄17856" -> "0.000017856" formatını handle et if (cleanedPrice.startsWith('0.0')) { let finalPrice = '0.0'; let foundSubscript = false; // String'i karakter karakter işle for (let i = 2; i < cleanedPrice.length; i++) { const char = cleanedPrice[i]; if (subscriptMap.hasOwnProperty(char) && !foundSubscript) { // Subscript karakteri bulundu, bu kadar sıfır ekle const zeroCount = subscriptMap[char]; finalPrice += '0'.repeat(zeroCount); foundSubscript = true; } else { // Normal karakter, direkt ekle finalPrice += char; } } cleanedPrice = finalPrice; console.log('🔄 FORMATTED PRICE:', cleanedPrice); } // Parse etmeyi dene const parsedPrice = parseFloat(cleanedPrice); if (!isNaN(parsedPrice) && parsedPrice > 0) { currentTokenPrice = parsedPrice; priceFound = true; console.log('✅ PRICE SUCCESSFULLY PARSED:', { original: priceValue, formatted: cleanedPrice, parsed: currentTokenPrice }); } else { console.log('❌ Price parsing failed:', cleanedPrice); } } if (!priceFound) { console.log('❌ No valid token price found'); // Hemen hata gösterme, belki sayfa henüz yüklenmedi // Sadece debug için log bırak currentTokenPrice = 0.001; // Geçici olarak default değer } else { console.log('✅ FINAL TOKEN PRICE:', currentTokenPrice); } console.log('--- COIN PRICE SEARCH ENDED ---'); // Token sembolü güncelleme const tokenSymbolElement = document.querySelector('.B73M_W__dex'); if (tokenSymbolElement) { const symbol = tokenSymbolElement.textContent.trim(); if (symbol && symbol !== 'SOL' && symbol !== 'USDC' && symbol !== 'USDT') { /*if (previousTokenSymbol !== symbol) { showDemoNotification(`Switched to ${symbol}, resetting token portfolio`, 'info'); demoPortfolio.TOKEN.amount = 0; demoPortfolio.TOKEN.avgPrice = 0; totalRealizedPnL = 0; tradeHistory = []; }*/ currentTokenSymbol = symbol; const tokenImage = document.querySelector('.vP8ohB__dex img'); currentTokenImage = (tokenImage && tokenImage.src) ? tokenImage.src : 'https://web3.okx.com/cdn/web3/currency/token/large/501-FM6ZsWmVFA41D72NNNTk35ZrUSg2wkCerSNzg7Wjpump-108/type=default_90_0?v=1759520281357'; } } // PnL hesapla calculatePnL(); } catch (e) { console.error('❌ Price update error:', e); currentTokenPrice = 0.001; // Hata durumunda geçici default } } // SOL fiyatını API'den çek function fetchSolPrice() { fetch('https://api.coingecko.com/api/v3/simple/price?ids=solana&vs_currencies=usd') .then(response => response.json()) .then(data => { if (data.solana && data.solana.usd) { currentSolPrice = data.solana.usd; console.log('✅ SOL PRICE FROM API:', currentSolPrice); // Panel açıksa değerleri güncelle if (demoPanelVisible) { updateDemoPanelValues(); } } }) .catch(error => { console.log('❌ Coingecko API error, using default SOL price'); currentSolPrice = 100; // Fallback price }); } // SOL fiyatını periyodik olarak güncelle function startSolPriceUpdates() { // İlk güncellemeyi hemen yap fetchSolPrice(); // Sonra her 15 saniyede bir güncelle setInterval(fetchSolPrice, 15000); } function calculatePnL() { console.log('🔄 Calculating PnL with current data:', { tokenAmount: demoPortfolio.TOKEN.amount, avgPrice: demoPortfolio.TOKEN.avgPrice, currentPrice: currentTokenPrice, realizedPnL: totalRealizedPnL }); // Sıfırlama tokenPnL = 0; tokenPnLPercent = 0; totalPnL = 0; totalPnLPercent = 0; // Aktif Token PnL - DOĞRU HESAPLAMA if (demoPortfolio.TOKEN.amount > 0 && demoPortfolio.TOKEN.avgPrice > 0) { const currentTokenValue = demoPortfolio.TOKEN.amount * currentTokenPrice; const tokenCostBasis = demoPortfolio.TOKEN.amount * demoPortfolio.TOKEN.avgPrice; tokenPnL = currentTokenValue - tokenCostBasis; tokenPnLPercent = tokenCostBasis > 0 ? (tokenPnL / tokenCostBasis) * 100 : 0; console.log('📊 Token PnL calculated:', { currentValue: currentTokenValue, costBasis: tokenCostBasis, pnl: tokenPnL, percent: tokenPnLPercent }); } // Total PnL = Aktif Token PnL + Realize Edilen PnL totalPnL = tokenPnL + totalRealizedPnL; // Total PnL Percent - BAŞLANGIÇ BAKİYESİNE GÖRE HESAPLA const initialBalance = 1000; // Başlangıç bakiyesi totalPnLPercent = initialBalance > 0 ? (totalPnL / initialBalance) * 100 : 0; // NaN ve hata kontrolleri if (isNaN(totalPnL)) totalPnL = 0; if (isNaN(totalPnLPercent)) totalPnLPercent = 0; if (isNaN(tokenPnL)) tokenPnL = 0; if (isNaN(tokenPnLPercent)) tokenPnLPercent = 0; console.log('✅ Final PnL values:', { tokenPnL: tokenPnL, tokenPnLPercent: tokenPnLPercent.toFixed(2) + '%', totalPnL: totalPnL, totalPnLPercent: totalPnLPercent.toFixed(2) + '%', totalRealizedPnL: totalRealizedPnL }); savePortfolioToStorage(); } function savePortfolioToStorage() { localStorage.setItem('demoPortfolio', JSON.stringify(demoPortfolio)); localStorage.setItem('totalRealizedPnL', totalRealizedPnL.toString()); localStorage.setItem('totalTradeVolume', totalTradeVolume.toString()); localStorage.setItem('tradeHistory', JSON.stringify(tradeHistory)); console.log('Portfolio saved to localStorage'); } function startPriceUpdates() { // İlk fiyat güncellemesini hemen yap getCurrentPrices(); fetchSolPrice(); // Sonra periyodik olarak devam et - 0.5 SANİYE setInterval(() => { if (demoMode) { getCurrentPrices(); if (demoPanelVisible) { updateDemoPanelValues(); } } }, 500); // 0.5 saniye } function addDemoTab() { const tabList = document.querySelector('.dex-tabs-pane-list-container'); if (!tabList) { setTimeout(addDemoTab, 1000); return; } if (document.querySelector('[data-pane-id="demo_trading"]')) { return; } const demoTabHTML = ` <div class="dex-tabs-pane dex-tabs-pane-lg dex-tabs-pane-blue dex-tabs-pane-underline AV2oC5__dex" data-pane-id="demo_trading" id=":r2if:-demo_trading" role="tab" aria-selected="false" tabindex="-1"> <h2 class="font-inherit">Demo Trading</h2> </div> `; const lastTab = tabList.querySelector('.dex-tabs-pane:last-child'); if (lastTab) { lastTab.insertAdjacentHTML('beforebegin', demoTabHTML); addTabClickHandler(); } } function addDemoButton() { const buttonContainer = document.querySelector('.Q68nJL__dex'); if (!buttonContainer) { setTimeout(addDemoButton, 1000); return; } if (document.querySelector('.demo-trade-button')) { return; } const demoButtonHTML = ` <div data-testid="okd-popup" class="dex dex-popup-var dex-popup dex-coach-popover dex-coachmark-var demo-trade-button"> <button type="button" class="dex-plain-button peM48g__dex MovYo___dex q7TVYE__dex demo-mode-toggle"> <span class="zGJMLt__dex MovYo___dex"> <i class="icon iconfont dex-okx-defi-dex-quick-filled uZT0ej__dex" role="img" aria-hidden="true"></i> <span>Demo Trade</span> </span> </button> </div> `; const instantTradeBtn = buttonContainer.querySelector('[data-testid="okd-popup"]:last-child'); if (instantTradeBtn) { instantTradeBtn.insertAdjacentHTML('beforebegin', demoButtonHTML); addButtonClickHandler(); } } function addTabClickHandler() { const demoTab = document.querySelector('[data-pane-id="demo_trading"]'); if (demoTab) { demoTab.addEventListener('click', function() { switchToDemoMode(); updateActiveTab(); showDemoPanel(); }); } } function addButtonClickHandler() { const demoButton = document.querySelector('.demo-mode-toggle'); if (demoButton) { demoButton.addEventListener('click', function(e) { e.stopPropagation(); demoMode = !demoMode; updateDemoButton(); if (demoMode) { //showDemoNotification('Demo mode activated! Starting balance: $' + demoBalance, 'success'); showDemoPanel(); } else { //showDemoNotification('Demo mode deactivated', 'info'); hideDemoPanel(); } }); } } function switchToDemoMode() { demoMode = true; updateDemoButton(); showDemoPanel(); } function updateDemoButton() { const demoButton = document.querySelector('.demo-mode-toggle'); if (demoButton) { if (demoMode) { demoButton.style.backgroundColor = ''; demoButton.querySelector('span span').textContent = 'Demo Active'; } else { demoButton.style.backgroundColor = ''; demoButton.querySelector('span span').textContent = 'Demo Trade'; } } } function updateActiveTab() { const tabs = document.querySelectorAll('.dex-tabs-pane'); tabs.forEach(tab => { tab.classList.remove('dex-tabs-pane-underline-active', 'p0ZfTr__dex'); }); const activeTab = document.querySelector('[data-pane-id="demo_trading"]'); if (activeTab) { activeTab.classList.add('dex-tabs-pane-underline-active', 'p0ZfTr__dex'); } } function showDemoPanel() { if (demoPanelVisible) return; loadSettingsFromRealPanel(); getCurrentPrices(); const demoPanelHTML = ` <div class="cIknRK__dex gRJpse__dex demo-trade-panel" role="button" tabindex="-1" style="left: 400px; top: 200px; opacity: 1; transition: all 0.2s; cursor: default; z-index: 1007;"> <div class="vM9Rz8__dex F_UE_X__dex" role="button" tabindex="0" aria-disabled="false" aria-roledescription="draggable"> <div class="bSH5VS__dex" aria-label="drag-to-move-dialog"><i class="icon iconfont cenOGi__dex dex-okx-defi-dex-drag" role="img" aria-hidden="true"></i></div> <div> <div class="NZD_dv__dex"> <div class="dex dex-select-var dex-select select-text Hp9ZjI__dex demo-default-select"> <div class="dex-select-value-box display-area pm_IiY__dex"> <div class="LFH5He__dex"> <div class="D3fk1I__dex">Default</div> <i class="icon iconfont dex-okds-chevron-down icon-sign select-up dex-select-reference-icon dex-select-reference-icon-md" role="img" aria-label="" aria-hidden="true"></i> </div> </div> <div data-testid="okd-popup" class="dex dex-popup-var dex-popup select-popup-reference"></div> </div> </div> </div> <div class="aynava__dex"> <!-- RESET BUTON - ICON DÜZELTİLDİ --> <div data-testid="okd-popup" class="dex dex-popup-var dex-popup dex-tooltip dex-tooltip-var dex-tooltip-neutral"> <button type="button" class="dex-plain-button hs2qqD__dex demo-reset-balance"> <i class="icon iconfont McyHpj__dex dex-okx-defi-dex-reset" role="img" aria-label="Reset Demo"></i> </button> </div> <!-- CUSTOMIZE BUTON - SORUN ÇÖZÜLDÜ --> <div data-testid="okd-popup" class="dex dex-popup-var dex-popup"> <button type="button" class="dex-plain-button hs2qqD__dex demo-customize-btn ${customizeMode ? 'QzYi7N__dex' : ''}"> <i class="icon iconfont McyHpj__dex ${customizeMode ? 'dex-okx-defi-dex-check' : 'dex-okx-defi-marketplace-edit'}" role="img" aria-label="Customize amounts"></i> </button> </div> <!-- SETTINGS BUTON --> <div data-testid="okd-popup" class="dex dex-popup-var dex-popup dex-tooltip dex-tooltip-var dex-tooltip-neutral"> <button type="button" class="dex-plain-button hs2qqD__dex demo-settings-btn"> <i class="icon iconfont McyHpj__dex dex-okx-defi-dex-keyboard" role="img" aria-label="Click to activate hotkeys"></i> </button> </div> <i class="icon iconfont vuymPd__dex dex-okx-defi-marketplace-close dex-a11y-button demo-panel-close" role="button" aria-label="Close" tabindex="0"></i> </div> </div> <div class="JlS9Ws__dex"> <div> <div class="flex justify-between items-center uyKNVr__dex"> <div class="dex dex-select-var dex-select select-text lnOLCt__dex instant-trade-token-selector-buy demo-buy-select"> <div class="dex-select-value-box display-area NC4WG2__dex"> <div class="e4mTHT__dex flex items-center font-12"> <span class="ioQevx__dex">Buy with</span> <span class="font-500 UE7t1T__dex">SOL</span> <i class="icon iconfont dex-okx-defi-dex-market-sort-down RQGYJ6__dex" role="img" aria-hidden="true"></i> </div> </div> <div data-testid="okd-popup" class="dex dex-popup-var dex-popup select-popup-reference"></div> </div> <div class="flex items-center"> <span class="VHD_xh__dex">${demoPortfolio.SOL.amount.toFixed(4)}</span> <picture class="dex dex-picture dex-picture-font"><source srcset="https://web3.okx.com/cdn/web3/currency/token/501-11111111111111111111111111111111-1.png/type=default_350_0?v=1734571825920&x-oss-process=image/format,webp/ignore-error,1"><img width="16" height="16" class="Lrw8Qc__dex" alt="" src="https://web3.okx.com/cdn/web3/currency/token/501-11111111111111111111111111111111-1.png/type=default_350_0?v=1734571825920" style="width: 16px; height: 16px;"></picture> </div> </div> <div class="flex justify-between lFouoK__dex"> <div class="k_jil0__dex xr2g7U__dex"> <div class="ThQSDh__dex options-wrapper"> ${customizeMode ? ` <!-- CUSTOMIZE MODE: INPUT ALANLARI --> <div class="dex dex-input-var dex-input dex-input-md __XCfV__dex mW93WY__dex"> <div class="dex-input-box auto-size E_NN8J__dex utlHnK__dex" role="none"> <input autocomplete="off" readonly="" type="hidden" style="display: none;"> <input inputmode="decimal" enable_thousands="true" min="0" max="9007199254740991" autocomplete="off" step="1" id="demo-buy-input-1" class="dex-input-input PfVQrS__dex demo-buy-input" autocapitalize="off" autocorrect="off" type="text" value="${tempBuyAmounts[0]}" name="demo_buy_input_1"> <div class="dex-input-suffix"></div> </div> </div> <div class="dex dex-input-var dex-input dex-input-md __XCfV__dex mW93WY__dex"> <div class="dex-input-box auto-size E_NN8J__dex utlHnK__dex" role="none"> <input autocomplete="off" readonly="" type="hidden" style="display: none;"> <input inputmode="decimal" enable_thousands="true" min="0" max="9007199254740991" autocomplete="off" step="1" id="demo-buy-input-2" class="dex-input-input PfVQrS__dex demo-buy-input" autocapitalize="off" autocorrect="off" type="text" value="${tempBuyAmounts[1]}" name="demo_buy_input_2"> <div class="dex-input-suffix"></div> </div> </div> <div class="dex dex-input-var dex-input dex-input-md __XCfV__dex mW93WY__dex"> <div class="dex-input-box auto-size E_NN8J__dex utlHnK__dex" role="none"> <input autocomplete="off" readonly="" type="hidden" style="display: none;"> <input inputmode="decimal" enable_thousands="true" min="0" max="9007199254740991" autocomplete="off" step="1" id="demo-buy-input-3" class="dex-input-input PfVQrS__dex demo-buy-input" autocapitalize="off" autocorrect="off" type="text" value="${tempBuyAmounts[2]}" name="demo_buy_input_3"> <div class="dex-input-suffix"></div> </div> </div> ` : ` <!-- NORMAL MODE: BUTONLAR --> <div class="flex items-center kw6r9M__dex"> <div class="H5f_ax__dex Cg7h1c__dex VmOKPA__dex demo-buy-quick" data-amount="${parseFloat(currentSettings.buyAmounts[0]) || 0.03}" style="cursor: pointer;"> <div class="l5GPKh__dex ellipsis">${currentSettings.buyAmounts[0] || '0.03'}</div> </div> </div> <div class="flex items-center kw6r9M__dex"> <div class="H5f_ax__dex Cg7h1c__dex VmOKPA__dex demo-buy-quick" data-amount="${parseFloat(currentSettings.buyAmounts[1]) || 0.05}" style="cursor: pointer;"> <div class="l5GPKh__dex ellipsis">${currentSettings.buyAmounts[1] || '0.05'}</div> </div> </div> <div class="flex items-center kw6r9M__dex"> <div class="H5f_ax__dex Cg7h1c__dex VmOKPA__dex demo-buy-quick" data-amount="${parseFloat(currentSettings.buyAmounts[2]) || 0.07}" style="cursor: pointer;"> <div class="l5GPKh__dex ellipsis">${currentSettings.buyAmounts[2] || '0.07'}</div> </div> </div> `} </div> </div> </div> <div class="flex justify-start Nox6EF__dex"> <div class="flex items-center Fb9n18__dex" role="presentation"> <i class="icon iconfont dex-okx-defi-dex-slippage GuPJu7__dex" role="img" aria-hidden="true"></i> <span class="font-12 ml-4 font-500">${currentSettings.buySlippage}</span> <span class="ROEGPH__dex"></span> <i class="icon iconfont dex-okx-defi-dex-fee GuPJu7__dex" role="img" aria-hidden="true"></i> <span class="font-12 ml-4 font-500">Market</span> <span class="ROEGPH__dex"></span> <div data-testid="okd-popup" class="dex dex-popup-var dex-popup dex-tooltip dex-tooltip-var dex-tooltip-neutral "><div class="flex items-center"><i class="icon iconfont dex-okx-defi-web3-shield Xm6VIO__dex" role="img" aria-label="config-item"></i><span class="Or4Gzq__dex">Auto</span></div></div> <i class="icon iconfont dex-okx-defi-marketplace-chevron-right C0NIv2__dex demo-buy-settings" role="img" aria-hidden="true" style="cursor: pointer;"></i> </div> </div> </div> <div class="QwqNAT__dex"> <div class="flex justify-between items-center uyKNVr__dex"> <div class="dex dex-select-var dex-select select-text lnOLCt__dex instant-trade-token-selector-sell demo-sell-select"> <div class="dex-select-value-box display-area NC4WG2__dex"> <div class="e4mTHT__dex flex items-center font-12"> <span class="ioQevx__dex">Sell for</span> <span class="font-500 UE7t1T__dex">${currentTokenSymbol}</span> <i class="icon iconfont dex-okx-defi-dex-market-sort-down RQGYJ6__dex" role="img" aria-hidden="true"></i> </div> </div> <div data-testid="okd-popup" class="dex dex-popup-var dex-popup select-popup-reference"></div> </div> <div class="flex items-center"> <span class="VHD_xh__dex">${demoPortfolio.TOKEN.amount.toFixed(4)}</span> <picture class="dex dex-picture dex-picture-font"><source srcset="${currentTokenImage || 'https://web3.okx.com/cdn/web3/currency/token/large/501-FM6ZsWmVFA41D72NNNTk35ZrUSg2wkCerSNzg7Wjpump-108/type=default_90_0?v=1759520281357'}&x-oss-process=image/format,webp/ignore-error,1"><img width="16" height="16" class="Lrw8Qc__dex" alt="" src="${currentTokenImage || 'https://web3.okx.com/cdn/web3/currency/token/large/501-FM6ZsWmVFA41D72NNNTk35ZrUSg2wkCerSNzg7Wjpump-108/type=default_90_0?v=1759520281357'}" style="width: 16px; height: 16px;"></picture> </div> </div> <div class="flex justify-between lFouoK__dex"> <div class="k_jil0__dex xr2g7U__dex"> <div class="ThQSDh__dex options-wrapper"> ${customizeMode ? ` <!-- CUSTOMIZE MODE: INPUT ALANLARI --> <div class="dex dex-input-var dex-input dex-input-md __XCfV__dex mW93WY__dex"> <div class="dex-input-box auto-size E_NN8J__dex utlHnK__dex" role="none"> <input autocomplete="off" readonly="" type="hidden" style="display: none;"> <input inputmode="decimal" enable_thousands="true" min="0" max="100" autocomplete="off" step="1" id="demo-sell-input-1" class="dex-input-input PfVQrS__dex demo-sell-input" autocapitalize="off" autocorrect="off" type="text" value="${tempSellPercents[0]}" name="demo_sell_input_1"> <div class="dex-input-suffix"></div> </div> </div> <div class="dex dex-input-var dex-input dex-input-md __XCfV__dex mW93WY__dex"> <div class="dex-input-box auto-size E_NN8J__dex utlHnK__dex" role="none"> <input autocomplete="off" readonly="" type="hidden" style="display: none;"> <input inputmode="decimal" enable_thousands="true" min="0" max="100" autocomplete="off" step="1" id="demo-sell-input-2" class="dex-input-input PfVQrS__dex demo-sell-input" autocapitalize="off" autocorrect="off" type="text" value="${tempSellPercents[1]}" name="demo_sell_input_2"> <div class="dex-input-suffix"></div> </div> </div> <div class="dex dex-input-var dex-input dex-input-md __XCfV__dex mW93WY__dex"> <div class="dex-input-box auto-size E_NN8J__dex utlHnK__dex" role="none"> <input autocomplete="off" readonly="" type="hidden" style="display: none;"> <input inputmode="decimal" enable_thousands="true" min="0" max="100" autocomplete="off" step="1" id="demo-sell-input-3" class="dex-input-input PfVQrS__dex demo-sell-input" autocapitalize="off" autocorrect="off" type="text" value="${tempSellPercents[2]}" name="demo_sell_input_3"> <div class="dex-input-suffix"></div> </div> </div> ` : ` <!-- NORMAL MODE: BUTONLAR --> <div class="flex items-center kw6r9M__dex"> <div class="H5f_ax__dex ODJ17x__dex VmOKPA__dex demo-sell-quick" data-percent="50" style="cursor: pointer;"> <div class="l5GPKh__dex ellipsis">${currentSettings.sellPercents[0] || '50%'}</div> </div> </div> <div class="flex items-center kw6r9M__dex"> <div class="H5f_ax__dex ODJ17x__dex VmOKPA__dex demo-sell-quick" data-percent="75" style="cursor: pointer;"> <div class="l5GPKh__dex ellipsis">${currentSettings.sellPercents[1] || '75%'}</div> </div> </div> <div class="flex items-center kw6r9M__dex"> <div class="H5f_ax__dex ODJ17x__dex VmOKPA__dex demo-sell-quick" data-percent="100" style="cursor: pointer;"> <div class="l5GPKh__dex ellipsis">${currentSettings.sellPercents[2] || '100%'}</div> </div> </div> `} </div> </div> </div> <div class="flex justify-start Nox6EF__dex"> <div class="flex items-center Fb9n18__dex" role="presentation"> <i class="icon iconfont dex-okx-defi-dex-slippage GuPJu7__dex" role="img" aria-hidden="true"></i> <span class="font-12 ml-4 font-500">${currentSettings.sellSlippage}</span> <span class="ROEGPH__dex"></span> <i class="icon iconfont dex-okx-defi-dex-fee GuPJu7__dex" role="img" aria-hidden="true"></i> <span class="font-12 ml-4 font-500">Market</span> <span class="ROEGPH__dex"></span> <div data-testid="okd-popup" class="dex dex-popup-var dex-popup dex-tooltip dex-tooltip-var dex-tooltip-neutral "><div class="flex items-center"><i class="icon iconfont dex-okx-defi-web3-shield Xm6VIO__dex" role="img" aria-label="config-item"></i><span class="Or4Gzq__dex">Auto</span></div></div> <i class="icon iconfont dex-okx-defi-marketplace-chevron-right C0NIv2__dex demo-sell-settings" role="img" aria-hidden="true" style="cursor: pointer;"></i> </div> </div> </div> <div class="MEKLl5__dex LAaFhW__dex"> <div data-testid="okd-popup" class="dex dex-popup-var dex-popup dex-tooltip dex-tooltip-var dex-tooltip-neutral cursor-pointer flex items-center underline-dash vgre7c__dex"><span class="Nx6sMk__dex">Service fee</span></div> ${customizeMode ? ` <div class="dex dex-input-var dex-input dex-input-sm" style="width: 80px; display: inline-block;"> <div class="dex-input-box auto-size" role="none"> <input autocomplete="off" readonly="" type="hidden" style="display: none;"> <input inputmode="decimal" enable_thousands="true" min="0" max="100" autocomplete="off" step="0.01" id="demo-service-fee-input" class="dex-input-input demo-service-fee-input" autocapitalize="off" autocorrect="off" type="text" value="${tempServiceFee}" name="demo_service_fee_input"> <div class="dex-input-suffix"></div> </div> </div> ` : `<span>${currentSettings.serviceFee}</span>`} <span class="JBwvD1__dex">DEMO</span> <div class="demo-pnl-display" style="margin-left: auto; display: flex; flex-direction: column; align-items: flex-end; font-size: 11px; font-weight: 500; gap: 2px;"> <div style="color: ${tokenPnL >= 0 ? '#00a86b' : '#ff4444'}"> Token PnL: ${tokenPnL >= 0 ? '+' : ''}$${tokenPnL.toFixed(2)} (${tokenPnL >= 0 ? '+' : ''}${tokenPnLPercent.toFixed(2)}%) </div> <div style="color: ${totalPnL >= 0 ? '#00a86b' : '#ff4444'}"> Total PnL: ${totalPnL >= 0 ? '+' : ''}$${totalPnL.toFixed(2)} (${totalPnL >= 0 ? '+' : ''}${totalPnLPercent.toFixed(2)}%) </div> </div> </div> </div> </div> `; hideDemoPanel(); document.body.insertAdjacentHTML('beforeend', demoPanelHTML); setTimeout(() => { try { setupDemoPanelEvents(); setupAdvancedDragAndDrop(); setupDropdowns(); setupDropdownEvents(); updateDemoPanelValues(); } catch (error) { console.error('Error setting up demo panel:', error); } }, 200); demoPanelVisible = true; } function hideDemoPanel() { const demoPanel = document.querySelector('.demo-trade-panel'); if (demoPanel) { demoPanel.remove(); } demoPanelVisible = false; } function setupAdvancedDragAndDrop() { const demoPanel = document.querySelector('.demo-trade-panel'); if (!demoPanel) return; let isDragging = false; let startX, startY, initialX, initialY; const dragHandle = demoPanel.querySelector('.vM9Rz8__dex'); const dragStart = (e) => { if (e.target.closest('.vM9Rz8__dex')) { isDragging = true; startX = e.clientX || e.touches[0].clientX; startY = e.clientY || e.touches[0].clientY; const rect = demoPanel.getBoundingClientRect(); initialX = rect.left; initialY = rect.top; demoPanel.style.cursor = 'grabbing'; demoPanel.style.transition = 'none'; demoPanel.style.opacity = '0.8'; e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation(); } }; const drag = (e) => { if (!isDragging) return; const currentX = e.clientX || e.touches[0].clientX; const currentY = e.clientY || e.touches[0].clientY; const deltaX = currentX - startX; const deltaY = currentY - startY; demoPanel.style.left = (initialX + deltaX) + 'px'; demoPanel.style.top = (initialY + deltaY) + 'px'; e.preventDefault(); e.stopPropagation(); }; const dragEnd = () => { if (!isDragging) return; isDragging = false; demoPanel.style.cursor = 'default'; demoPanel.style.transition = 'all 0.2s'; demoPanel.style.opacity = '1'; }; dragHandle.addEventListener('mousedown', dragStart, true); dragHandle.addEventListener('touchstart', dragStart, { passive: false }); document.addEventListener('mousemove', drag, true); document.addEventListener('touchmove', drag, { passive: false }); document.addEventListener('mouseup', dragEnd, true); document.addEventListener('touchend', dragEnd, true); document.addEventListener('mouseleave', dragEnd, true); } function setupDropdowns() { // Default select dropdown const defaultSelect = document.querySelector('.demo-default-select'); if (defaultSelect) { const popupReference = defaultSelect.querySelector('.select-popup-reference'); if (popupReference) { popupReference.innerHTML = ` <div class="dex dex-popup-var dex-popup-layer dex-popup-layer-visible" style="z-index: 10000; visibility: hidden; position: absolute; left: 0px; top: 0px; margin: 0px; transform: translate(0px, 40px);" data-popper-placement="bottom-start"> <div class="dex-popup-layer-content" style="width: 140px;"> <div class="dex-select-var dex-select-option dex-select-option-pc yip61W__dex align-left drop-mode option-md"> <div class="dex-select-option-box"> <div class="pc-option-scroll" style="max-height: 200px;"> <div class="dex-select-item-container dex-select-item-container-real"> <div class="dex-select-item dex-select-item-active dex-dropdown-option demo-default-option" role="option" aria-selected="true" data-value="Default"> <div class="flex justify-between items-center Be9HsZ__dex"> <div class="vZhXdm__dex">Default</div> <i class="icon iconfont dex-okx-defi-dex-check DaCpQM__dex qriW7s__dex" role="img" aria-hidden="true"></i> </div> </div> <div class="dex-select-item dex-dropdown-option demo-default-option" role="option" aria-selected="false" data-value="Meme"> <div class="flex justify-between items-center Be9HsZ__dex"> <div class="vZhXdm__dex">Meme</div> <i class="icon iconfont dex-okx-defi-dex-check DaCpQM__dex" role="img" aria-hidden="true"></i> </div> </div> <div class="dex-select-item dex-dropdown-option demo-default-option" role="option" aria-selected="false" data-value="AMV"> <div class="flex justify-between items-center Be9HsZ__dex"> <div class="vZhXdm__dex">AMV/20%/FA</div> <i class="icon iconfont dex-okx-defi-dex-check DaCpQM__dex" role="img" aria-hidden="true"></i> </div> </div> <div class="dex-select-item dex-dropdown-option demo-default-option" role="option" aria-selected="false" data-value="MEV1"> <div class="flex justify-between items-center Be9HsZ__dex"> <div class="vZhXdm__dex">MEV/30%/FA</div> <i class="icon iconfont dex-okx-defi-dex-check DaCpQM__dex" role="img" aria-hidden="true"></i> </div> </div> <div class="dex-select-item dex-dropdown-option demo-default-option" role="option" aria-selected="false" data-value="MEV2"> <div class="flex justify-between items-center Be9HsZ__dex"> <div class="vZhXdm__dex">MEV/30%/TURB</div> <i class="icon iconfont dex-okx-defi-dex-check DaCpQM__dex" role="img" aria-hidden="true"></i> </div> </div> </div> </div> <div class="pc-option-footer"> <div class="ViayfB__dex"> <button type="button" class="dex-plain-button ViayfB__dex demo-edit-settings"> <i class="icon iconfont dex-okx-defi-dex-web3-settings cQG_ch__dex" role="img" aria-hidden="true"></i> <span>Edit</span> </button> </div> </div> </div> </div> </div> </div> `; } } // Buy token select dropdown const buySelect = document.querySelector('.demo-buy-select'); if (buySelect) { const popupReference = buySelect.querySelector('.select-popup-reference'); if (popupReference) { const solBalance = demoPortfolio.SOL.amount.toFixed(4); const solValue = (demoPortfolio.SOL.amount * currentSolPrice).toFixed(2); popupReference.innerHTML = ` <div class="dex dex-popup-var dex-popup-layer dex-popup-layer-visible" style="z-index: 10001; visibility: hidden; position: absolute; left: 0px; top: 0px; margin: 0px; transform: translate(0px, 40px);" data-popper-placement="bottom-start"> <div class="dex-popup-layer-content" style="width: 308px;"> <div class="dex-select-var dex-select-option dex-select-option-pc WFwMwa__dex instant-trade-token-selector-option-cont-buy align-left drop-mode option-md"> <div class="dex-select-option-box"> <div class="pc-option-scroll" style="max-height: 208px;"> <div class="dex-select-item-container dex-select-item-container-real"> <div class="dex-select-item dex-select-item-active dex-dropdown-option demo-buy-option" role="option" aria-selected="true" data-value="SOL"> <div class="flex justify-between items-center G9BMtd__dex"> <div class="flex items-center"> <picture class="dex dex-picture dex-picture-font"> <source srcset="https://web3.okx.com/cdn/web3/currency/token/501-11111111111111111111111111111111-1.png/type=default_350_0?v=1734571825920&x-oss-process=image/format,webp/ignore-error,1"> <img width="28" height="28" class="jxzKU9__dex" alt="" src="https://web3.okx.com/cdn/web3/currency/token/501-11111111111111111111111111111111-1.png/type=default_350_0?v=1734571825920" style="width: 28px; height: 28px;"> </picture> <div class="flex flex-col"> <span class="tiQWEG__dex">SOL</span> <span class="inAvcR__dex">Solana</span> </div> </div> <div class="flex flex-col tsKlgJ__dex"> <span class="tiQWEG__dex">${solBalance}</span> <span class="inAvcR__dex">$${solValue}</span> </div> </div> </div> <div class="dex-select-item dex-dropdown-option demo-buy-option" role="option" aria-selected="false" data-value="USDC"> <div class="flex justify-between items-center G9BMtd__dex"> <div class="flex items-center"> <picture class="dex dex-picture dex-picture-font"> <source srcset="https://web3.okx.com/cdn/web3/currency/token/large/637-0xbae207659db88bea0cbead6da0ed00aac12edcdda169e591cd41c94180b46f3b-107/type=default_90_0?v=1756203256814&x-oss-process=image/format,webp/ignore-error,1"> <img width="28" height="28" class="jxzKU9__dex" alt="" src="https://web3.okx.com/cdn/web3/currency/token/large/637-0xbae207659db88bea0cbead6da0ed00aac12edcdda169e591cd41c94180b46f3b-107/type=default_90_0?v=1756203256814" style="width: 28px; height: 28px;"> </picture> <div class="flex flex-col"> <span class="tiQWEG__dex">USDC</span> <span class="inAvcR__dex">USD Coin</span> </div> </div> <div class="flex flex-col tsKlgJ__dex"> <span class="tiQWEG__dex">0</span> <span class="inAvcR__dex">$0.00</span> </div> </div> </div> </div> </div> <div class="pc-option-footer"> <div class="CnFTM4__dex"> <span>If you wish to trade other tokens, switch to <button type="button" class="dex-plain-button k3rUid__dex demo-swap-btn">Swap</button></span> </div> </div> </div> </div> </div> </div> `; } } // Sell token select dropdown const sellSelect = document.querySelector('.demo-sell-select'); if (sellSelect) { const popupReference = sellSelect.querySelector('.select-popup-reference'); if (popupReference) { const tokenBalance = demoPortfolio.TOKEN.amount.toFixed(4); const tokenValue = (demoPortfolio.TOKEN.amount * currentTokenPrice).toFixed(2); const solBalance = demoPortfolio.SOL.amount.toFixed(4); const solValue = (demoPortfolio.SOL.amount * currentSolPrice).toFixed(2); popupReference.innerHTML = ` <div class="dex dex-popup-var dex-popup-layer dex-popup-layer-visible" style="z-index: 10002; visibility: hidden; position: absolute; left: 0px; top: 0px; margin: 0px; transform: translate(0px, 40px);" data-popper-placement="bottom-start"> <div class="dex-popup-layer-content" style="width: 308px;"> <div class="dex-select-var dex-select-option dex-select-option-pc WFwMwa__dex instant-trade-token-selector-option-cont-sell align-left drop-mode option-md"> <div class="dex-select-option-box"> <div class="pc-option-scroll" style="max-height: 208px;"> <div class="dex-select-item-container dex-select-item-container-real"> <div class="dex-select-item dex-select-item-active dex-dropdown-option demo-sell-option" role="option" aria-selected="true" data-value="${currentTokenSymbol}"> <div class="flex justify-between items-center G9BMtd__dex"> <div class="flex items-center"> <picture class="dex dex-picture dex-picture-font"> <source srcset="${currentTokenImage || 'https://web3.okx.com/cdn/web3/currency/token/large/501-FM6ZsWmVFA41D72NNNTk35ZrUSg2wkCerSNzg7Wjpump-108/type=default_90_0?v=1759520281357'}&x-oss-process=image/format,webp/ignore-error,1"> <img width="28" height="28" class="jxzKU9__dex" alt="" src="${currentTokenImage || 'https://web3.okx.com/cdn/web3/currency/token/large/501-FM6ZsWmVFA41D72NNNTk35ZrUSg2wkCerSNzg7Wjpump-108/type=default_90_0?v=1759520281357'}" style="width: 28px; height: 28px;"> </picture> <div class="flex flex-col"> <span class="tiQWEG__dex">${currentTokenSymbol}</span> <span class="inAvcR__dex">Current Token</span> </div> </div> <div class="flex flex-col tsKlgJ__dex"> <span class="tiQWEG__dex">${tokenBalance}</span> <span class="inAvcR__dex">$${tokenValue}</span> </div> </div> </div> <div class="dex-select-item dex-dropdown-option demo-sell-option" role="option" aria-selected="false" data-value="SOL"> <div class="flex justify-between items-center G9BMtd__dex"> <div class="flex items-center"> <picture class="dex dex-picture dex-picture-font"> <source srcset="https://web3.okx.com/cdn/web3/currency/token/501-11111111111111111111111111111111-1.png/type=default_350_0?v=1734571825920&x-oss-process=image/format,webp/ignore-error,1"> <img width="28" height="28" class="jxzKU9__dex" alt="" src="https://web3.okx.com/cdn/web3/currency/token/501-11111111111111111111111111111111-1.png/type=default_350_0?v=1734571825920" style="width: 28px; height: 28px;"> </picture> <div class="flex flex-col"> <span class="tiQWEG__dex">SOL</span> <span class="inAvcR__dex">Solana</span> </div> </div> <div class="flex flex-col tsKlgJ__dex"> <span class="tiQWEG__dex">${solBalance}</span> <span class="inAvcR__dex">$${solValue}</span> </div> </div> </div> </div> </div> <div class="pc-option-footer"> <div class="CnFTM4__dex"> <span>If you wish to trade other tokens, switch to <button type="button" class="dex-plain-button k3rUid__dex demo-swap-btn">Swap</button></span> </div> </div> </div> </div> </div> </div> `; } } } function setupDropdownEvents() { console.log('Setting up dropdown events...'); // Default select const defaultSelect = document.querySelector('.demo-default-select .dex-select-value-box'); if (defaultSelect) { defaultSelect.addEventListener('click', function(e) { e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation(); const popup = this.closest('.dex-select').querySelector('.dex-popup-layer'); if (popup) { const isVisible = popup.style.visibility === 'visible'; // Tüm popup'ları kapat document.querySelectorAll('.dex-popup-layer').forEach(p => { p.style.visibility = 'hidden'; p.style.zIndex = '-1'; }); // Bu popup'ı aç if (!isVisible) { popup.style.visibility = 'visible'; popup.style.zIndex = '10008'; } } return false; }, true); } // Buy select const buySelect = document.querySelector('.demo-buy-select .dex-select-value-box'); if (buySelect) { buySelect.addEventListener('click', function(e) { e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation(); const popup = this.closest('.dex-select').querySelector('.dex-popup-layer'); if (popup) { const isVisible = popup.style.visibility === 'visible'; document.querySelectorAll('.dex-popup-layer').forEach(p => { p.style.visibility = 'hidden'; p.style.zIndex = '-1'; }); if (!isVisible) { popup.style.visibility = 'visible'; popup.style.zIndex = '10009'; } } return false; }, true); } // Sell select const sellSelect = document.querySelector('.demo-sell-select .dex-select-value-box'); if (sellSelect) { sellSelect.addEventListener('click', function(e) { e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation(); const popup = this.closest('.dex-select').querySelector('.dex-popup-layer'); if (popup) { const isVisible = popup.style.visibility === 'visible'; document.querySelectorAll('.dex-popup-layer').forEach(p => { p.style.visibility = 'hidden'; p.style.zIndex = '-1'; }); if (!isVisible) { popup.style.visibility = 'visible'; popup.style.zIndex = '10009'; } } return false; }, true); } // Dropdown options setTimeout(() => { document.querySelectorAll('.demo-default-option').forEach(option => { option.addEventListener('click', function(e) { e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation(); const value = this.getAttribute('data-value'); const display = document.querySelector('.demo-default-select .D3fk1I__dex'); if (display) display.textContent = value; document.querySelectorAll('.dex-popup-layer').forEach(p => { p.style.visibility = 'hidden'; p.style.zIndex = '-1'; }); showDemoNotification(`Mode changed to: ${value}`, 'info'); return false; }, true); }); document.querySelectorAll('.demo-buy-option').forEach(option => { option.addEventListener('click', function(e) { e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation(); const value = this.getAttribute('data-value'); const display = document.querySelector('.demo-buy-select .UE7t1T__dex'); if (display) display.textContent = value; document.querySelectorAll('.dex-popup-layer').forEach(p => { p.style.visibility = 'hidden'; p.style.zIndex = '-1'; }); showDemoNotification(`Buy with: ${value}`, 'info'); return false; }, true); }); document.querySelectorAll('.demo-sell-option').forEach(option => { option.addEventListener('click', function(e) { e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation(); const value = this.getAttribute('data-value'); const display = document.querySelector('.demo-sell-select .UE7t1T__dex'); if (display) display.textContent = value; document.querySelectorAll('.dex-popup-layer').forEach(p => { p.style.visibility = 'hidden'; p.style.zIndex = '-1'; }); showDemoNotification(`Sell for: ${value}`, 'info'); return false; }, true); }); // SOL action butonları için event listener ekle document.querySelectorAll('.demo-sol-action').forEach(button => { button.addEventListener('click', function(e) { e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation(); const action = this.getAttribute('data-action'); handleSolAction(action); // Popup'ı kapat document.querySelectorAll('.dex-popup-layer').forEach(p => { p.style.visibility = 'hidden'; p.style.zIndex = '-1'; }); return false; }, true); }); // Custom SOL input için event const customSolInput = document.getElementById('demo-sol-custom'); if (customSolInput) { customSolInput.addEventListener('keypress', function(e) { if (e.key === 'Enter') { e.preventDefault(); e.stopPropagation(); handleSolAction('custom'); document.querySelectorAll('.dex-popup-layer').forEach(p => { p.style.visibility = 'hidden'; p.style.zIndex = '-1'; }); return false; } }, true); // Input'a tıklama olayını da engelle customSolInput.addEventListener('click', function(e) { e.stopPropagation(); }, true); } }, 100); // Document click to close dropdowns - daha spesifik hale getir document.addEventListener('click', function(e) { // Sadece demo dropdown'ları değilse kapat if (!e.target.closest('.demo-default-select') && !e.target.closest('.demo-buy-select') && !e.target.closest('.demo-sell-select') && !e.target.closest('.dex-popup-layer')) { document.querySelectorAll('.dex-popup-layer').forEach(popup => { popup.style.visibility = 'hidden'; popup.style.zIndex = '-1'; }); } }, true); } function setupDemoPanelEvents() { console.log('Setting up demo panel events...'); // Kapat butonu const closeBtn = document.querySelector('.demo-panel-close'); if (closeBtn) { closeBtn.addEventListener('click', function(e) { e.preventDefault(); e.stopPropagation(); hideDemoPanel(); return false; }, true); } // Reset butonu - ICON DÜZELTİLDİ const resetBtn = document.querySelector('.demo-reset-balance'); if (resetBtn) { resetBtn.addEventListener('click', function(e) { e.preventDefault(); e.stopPropagation(); resetDemoAccount(); return false; }, true); } const customizeBtn = document.querySelector('.demo-customize-btn'); if (customizeBtn) { console.log('Customize button found, setting up click event...'); // Tüm event listener'ları temizle const newCustomizeBtn = customizeBtn.cloneNode(true); customizeBtn.parentNode.replaceChild(newCustomizeBtn, customizeBtn); // Yeni butona direkt onclick event ekle newCustomizeBtn.onclick = function(e) { console.log('✅ CUSTOMIZE BUTTON CLICKED! Mode:', customizeMode); e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation(); // Customize modunu değiştir toggleCustomizeMode(); return false; }; // Tooltip özelliklerini kaldır if (newCustomizeBtn.parentNode.classList.contains('dex-tooltip')) { newCustomizeBtn.parentNode.classList.remove('dex-tooltip', 'dex-tooltip-neutral', 'dex-tooltip-var'); } } // Settings butonu const settingsBtn = document.querySelector('.demo-settings-btn'); if (settingsBtn) { settingsBtn.addEventListener('click', function(e) { e.preventDefault(); e.stopPropagation(); showDemoNotification('Demo settings - Real-time prices active', 'info'); return false; }, true); } // Buy settings butonu const buySettings = document.querySelector('.demo-buy-settings'); if (buySettings) { buySettings.addEventListener('click', function(e) { e.preventDefault(); e.stopPropagation(); showDemoNotification(`Buy settings: ${currentSettings.buySlippage} slippage`, 'info'); return false; }, true); } // Sell settings butonu const sellSettings = document.querySelector('.demo-sell-settings'); if (sellSettings) { sellSettings.addEventListener('click', function(e) { e.preventDefault(); e.stopPropagation(); showDemoNotification(`Sell settings: ${currentSettings.sellSlippage} slippage`, 'info'); return false; }, true); } // Hızlı alım butonları (sadece customize mode kapalıyken) if (!customizeMode) { const buyButtons = document.querySelectorAll('.demo-buy-quick'); buyButtons.forEach(btn => { btn.addEventListener('click', function(e) { e.preventDefault(); e.stopPropagation(); const amount = parseFloat(this.getAttribute('data-amount')) || 0.03; executeDemoBuy(amount); return false; }, true); }); } // Hızlı satış butonları (sadece customize mode kapalıyken) if (!customizeMode) { const sellButtons = document.querySelectorAll('.demo-sell-quick'); sellButtons.forEach(btn => { btn.addEventListener('click', function(e) { e.preventDefault(); e.stopPropagation(); const percent = parseInt(this.getAttribute('data-percent')) || 50; executeDemoSell(percent); return false; }, true); }); } // Input event'leri (sadece customize mode açıkken) if (customizeMode) { const buyInputs = document.querySelectorAll('.demo-buy-input'); buyInputs.forEach((input, index) => { // Input'u clone ederek temizle const newInput = input.cloneNode(true); input.parentNode.replaceChild(newInput, input); newInput.addEventListener('input', function(e) { tempBuyAmounts[index] = this.value; console.log(`Buy amount ${index + 1} updated: ${this.value}`); }); newInput.addEventListener('blur', function(e) { tempBuyAmounts[index] = this.value; console.log(`Buy amount ${index + 1} saved: ${this.value}`); }); newInput.addEventListener('change', function(e) { tempBuyAmounts[index] = this.value; }); }); const sellInputs = document.querySelectorAll('.demo-sell-input'); sellInputs.forEach((input, index) => { // Input'u clone ederek temizle const newInput = input.cloneNode(true); input.parentNode.replaceChild(newInput, input); newInput.addEventListener('input', function(e) { tempSellPercents[index] = this.value; console.log(`Sell percent ${index + 1} updated: ${this.value}`); }); newInput.addEventListener('blur', function(e) { tempSellPercents[index] = this.value; console.log(`Sell percent ${index + 1} saved: ${this.value}`); }); newInput.addEventListener('change', function(e) { tempSellPercents[index] = this.value; }); }); // Service fee input event'i const serviceFeeInput = document.querySelector('.demo-service-fee-input'); if (serviceFeeInput) { const newServiceFeeInput = serviceFeeInput.cloneNode(true); serviceFeeInput.parentNode.replaceChild(newServiceFeeInput, serviceFeeInput); newServiceFeeInput.addEventListener('input', function(e) { tempServiceFee = this.value; console.log(`Service fee updated: ${this.value}`); }); newServiceFeeInput.addEventListener('blur', function(e) { tempServiceFee = this.value; console.log(`Service fee saved: ${this.value}`); }); newServiceFeeInput.addEventListener('change', function(e) { tempServiceFee = this.value; }); } } } function toggleCustomizeMode() { console.log('Toggling customize mode. Current mode:', customizeMode); customizeMode = !customizeMode; if (customizeMode) { // Geçici değerleri mevcut ayarlarla doldur tempBuyAmounts = [...currentSettings.buyAmounts]; tempSellPercents = [...currentSettings.sellPercents]; tempServiceFee = currentSettings.serviceFee; showDemoNotification('Customize amounts mode activated - Edit buy amounts, sell percentages and service fee', 'info'); } else { // Değişiklikleri kaydet currentSettings.buyAmounts = [...tempBuyAmounts]; currentSettings.sellPercents = [...tempSellPercents]; currentSettings.serviceFee = tempServiceFee; showDemoNotification('Custom amounts and service fee saved successfully!', 'success'); } // PANELİ YENİDEN OLUŞTUR - BU KISIM ÇOK ÖNEMLİ if (demoPanelVisible) { // Mevcut panel pozisyonunu kaydet const currentPanel = document.querySelector('.demo-trade-panel'); let panelStyle = {}; if (currentPanel) { panelStyle = { left: currentPanel.style.left, top: currentPanel.style.top }; } // Panel'i yeniden oluştur showDemoPanel(); // Pozisyonu geri yükle if (panelStyle.left && panelStyle.top) { const newPanel = document.querySelector('.demo-trade-panel'); if (newPanel) { newPanel.style.left = panelStyle.left; newPanel.style.top = panelStyle.top; } } console.log('Panel rebuilt with customize mode:', customizeMode); } } function resetDemoAccount() { if (confirm('Are you sure you want to reset your demo account? All portfolio data will be lost.')) { demoBalance = 1000; demoPortfolio = { 'SOL': { amount: 10, avgPrice: 100 }, 'TOKEN': { amount: 0, avgPrice: 0 } }; totalPnL = 0; totalPnLPercent = 0; tokenPnL = 0; tokenPnLPercent = 0; totalRealizedPnL = 0; totalTradeVolume = 0; tradeHistory = []; // localStorage'ı da temizle savePortfolioToStorage(); updateDemoPanelValues(); showDemoNotification('Demo account reset! Balance: $1000, SOL: 10', 'success'); } } // Rastgele SOL fee hesaplama fonksiyonu function calculateRandomSolFee() { const min = 0.0004; const max = 0.0009; return (Math.random() * (max - min) + min).toFixed(6); } // Service fee hesaplama fonksiyonu function calculateServiceFee(amount, feePercentage) { const percentage = parseFloat(feePercentage.replace('%', '')) / 100; return amount * percentage; } function executeDemoBuy(amount) { // Fiyat kontrolü - sadece 0 veya NaN ise engelle if (!currentTokenPrice || currentTokenPrice <= 0 || isNaN(currentTokenPrice)) { showDemoNotification('Cannot execute buy - token price not available! Please wait for price data to load.', 'error'); return; } if (!demoMode) { showDemoNotification('Please activate demo mode first!', 'error'); return; } const solCost = amount; if (solCost > demoPortfolio.SOL.amount) { showDemoNotification(`Insufficient SOL! Need ${solCost.toFixed(4)} SOL but only have ${demoPortfolio.SOL.amount.toFixed(4)} SOL`, 'error'); return; } console.log('Executing buy:', { solCost: solCost, currentSolPrice: currentSolPrice, currentTokenPrice: currentTokenPrice }); // Service fee ve market fee hesapla const serviceFeeAmount = calculateServiceFee(solCost, currentSettings.serviceFee); const marketFeeAmount = parseFloat(calculateRandomSolFee()); const totalFees = serviceFeeAmount + marketFeeAmount; // Toplam SOL maliyeti (işlem + fee'ler) const totalSolCost = solCost + totalFees; if (totalSolCost > demoPortfolio.SOL.amount) { showDemoNotification(`Insufficient SOL for fees! Need ${totalSolCost.toFixed(6)} SOL but only have ${demoPortfolio.SOL.amount.toFixed(4)} SOL`, 'error'); return; } // Doğru token miktarı hesaplama: SOL miktarı * (SOL fiyatı / Token fiyatı) const tokenAmount = (solCost * currentSolPrice) / currentTokenPrice; const usdValue = solCost * currentSolPrice; console.log('Buy calculation:', { tokenAmount: tokenAmount, usdValue: usdValue, serviceFee: serviceFeeAmount, marketFee: marketFeeAmount, totalFees: totalFees }); // Geçmiş işleme ekle tradeHistory.push({ type: 'BUY', tokenAmount: tokenAmount, solAmount: solCost, tokenPrice: currentTokenPrice, solPrice: currentSolPrice, usdValue: usdValue, serviceFee: serviceFeeAmount, marketFee: marketFeeAmount, totalFees: totalFees, timestamp: new Date() }); totalTradeVolume += usdValue; // ÖNCE: Mevcut portföy değerlerini kaydet const previousTokenAmount = demoPortfolio.TOKEN.amount; const previousAvgPrice = demoPortfolio.TOKEN.avgPrice; const previousTotalValue = previousTokenAmount * previousAvgPrice; // Yeni token ekle const newTokenValue = tokenAmount * currentTokenPrice; const totalTokenAmount = previousTokenAmount + tokenAmount; // SONRA: Weighted average ile YENİ ORTALAMA FİYAT hesapla if (totalTokenAmount > 0) { demoPortfolio.TOKEN.avgPrice = (previousTotalValue + newTokenValue) / totalTokenAmount; } // Portföyü güncelle (fee'leri de çıkar) demoPortfolio.SOL.amount -= totalSolCost; demoPortfolio.TOKEN.amount = totalTokenAmount; console.log('After buy portfolio update:', { newAvgPrice: demoPortfolio.TOKEN.avgPrice, newTokenAmount: demoPortfolio.TOKEN.amount, remainingSOL: demoPortfolio.SOL.amount, feesPaid: totalFees }); calculatePnL(); updateDemoPanelValues(); showDemoNotification(`Bought ${tokenAmount.toFixed(2)} ${currentTokenSymbol} for ${solCost.toFixed(4)} SOL | Fees: ${serviceFeeAmount.toFixed(6)} SOL (${currentSettings.serviceFee}) + ${marketFeeAmount.toFixed(6)} SOL (Market)`, 'success'); } function executeDemoSell(percent) { if (!demoMode) { showDemoNotification('Please activate demo mode first!', 'error'); return; } if (demoPortfolio.TOKEN.amount <= 0) { showDemoNotification(`No ${currentTokenSymbol} to sell! Buy some tokens first.`, 'error'); return; } const tokenAmount = demoPortfolio.TOKEN.amount * (percent / 100); // Doğru SOL kazancı hesaplama: Token miktarı * (Token fiyatı / SOL fiyatı) const solRevenue = (tokenAmount * currentTokenPrice) / currentSolPrice; const usdValue = tokenAmount * currentTokenPrice; // Service fee ve market fee hesapla const serviceFeeAmount = calculateServiceFee(solRevenue, currentSettings.serviceFee); const marketFeeAmount = parseFloat(calculateRandomSolFee()); const totalFees = serviceFeeAmount + marketFeeAmount; // Net SOL kazancı (işlem - fee'ler) const netSolRevenue = solRevenue - totalFees; if (netSolRevenue < 0) { showDemoNotification(`Fees exceed revenue! Cannot complete transaction.`, 'error'); return; } // Realize edilen PnL'yi hesapla - MEVCUT ORTALAMA FİYAT kullan const costBasis = tokenAmount * demoPortfolio.TOKEN.avgPrice; const realizedPnL = usdValue - costBasis; console.log('Sell calculation:', { tokenAmount: tokenAmount, avgPrice: demoPortfolio.TOKEN.avgPrice, costBasis: costBasis, usdValue: usdValue, realizedPnL: realizedPnL, serviceFee: serviceFeeAmount, marketFee: marketFeeAmount, totalFees: totalFees, netRevenue: netSolRevenue }); // Geçmiş işleme ekle tradeHistory.push({ type: 'SELL', tokenAmount: tokenAmount, solAmount: solRevenue, netSolAmount: netSolRevenue, tokenPrice: currentTokenPrice, solPrice: currentSolPrice, usdValue: usdValue, realizedPnL: realizedPnL, serviceFee: serviceFeeAmount, marketFee: marketFeeAmount, totalFees: totalFees, timestamp: new Date() }); totalTradeVolume += usdValue; totalRealizedPnL += realizedPnL; // Satış işlemi (net kazancı ekle) demoPortfolio.SOL.amount += netSolRevenue; demoPortfolio.TOKEN.amount -= tokenAmount; // Eğer tüm tokenlar satıldıysa average price'ı sıfırla if (demoPortfolio.TOKEN.amount === 0) { demoPortfolio.TOKEN.avgPrice = 0; } calculatePnL(); updateDemoPanelValues(); const pnlPercent = costBasis > 0 ? (realizedPnL / costBasis) * 100 : 0; const pnlText = realizedPnL >= 0 ? `Profit: +$${realizedPnL.toFixed(2)} (${pnlPercent.toFixed(2)}%)` : `Loss: $${Math.abs(realizedPnL).toFixed(2)} (${Math.abs(pnlPercent).toFixed(2)}%)`; showDemoNotification(`Sold ${tokenAmount.toFixed(2)} ${currentTokenSymbol} for ${netSolRevenue.toFixed(4)} SOL (after fees) | ${pnlText} | Fees: ${serviceFeeAmount.toFixed(6)} SOL (${currentSettings.serviceFee}) + ${marketFeeAmount.toFixed(6)} SOL (Market)`, 'success'); } function updateDemoPanelValues() { const demoPanel = document.querySelector('.demo-trade-panel'); if (!demoPanel) return; // Balance hesapla const totalBalance = (demoPortfolio.SOL.amount * currentSolPrice) + (demoPortfolio.TOKEN.amount * currentTokenPrice); demoBalance = totalBalance; // Token görüntülerini güncelle const buyTokenDisplay = demoPanel.querySelector('.instant-trade-token-selector-buy + .flex.items-center .VHD_xh__dex'); const sellTokenDisplay = demoPanel.querySelector('.instant-trade-token-selector-sell + .flex.items-center .VHD_xh__dex'); const sellTokenSymbol = demoPanel.querySelector('.instant-trade-token-selector-sell .UE7t1T__dex'); const sellTokenImage = demoPanel.querySelector('.instant-trade-token-selector-sell + .flex.items-center img'); const pnlDisplay = demoPanel.querySelector('.demo-pnl-display'); if (buyTokenDisplay) buyTokenDisplay.textContent = demoPortfolio.SOL.amount.toFixed(4); if (sellTokenDisplay) sellTokenDisplay.textContent = demoPortfolio.TOKEN.amount.toFixed(4); if (sellTokenSymbol) sellTokenSymbol.textContent = currentTokenSymbol; if (sellTokenImage) { sellTokenImage.src = currentTokenImage || 'https://web3.okx.com/cdn/web3/currency/token/large/501-FM6ZsWmVFA41D72NNNTk35ZrUSg2wkCerSNzg7Wjpump-108/type=default_90_0?v=1759520281357'; sellTokenImage.srcset = `${currentTokenImage || 'https://web3.okx.com/cdn/web3/currency/token/large/501-FM6ZsWmVFA41D72NNNTk35ZrUSg2wkCerSNzg7Wjpump-108/type=default_90_0?v=1759520281357'}&x-oss-process=image/format,webp/ignore-error,1`; } // PnL display kısmını güncelle if (pnlDisplay) { pnlDisplay.innerHTML = ` <div style="color: ${tokenPnL >= 0 ? '#00a86b' : '#ff4444'}"> Token PnL: ${tokenPnL >= 0 ? '+' : ''}$${tokenPnL.toFixed(2)} (${tokenPnL >= 0 ? '+' : ''}${tokenPnLPercent.toFixed(2)}%) </div> <div style="color: ${totalPnL >= 0 ? '#00a86b' : '#ff4444'}"> Total PnL: ${totalPnL >= 0 ? '+' : ''}$${totalPnL.toFixed(2)} (${totalPnL >= 0 ? '+' : ''}${totalPnLPercent.toFixed(2)}%) </div> `; } // Dropdown içeriklerini güncelle setupDropdowns(); } function showDemoNotification(message, type = 'info') { // Mevcut bildirim container'ını bul veya oluştur let notificationContainer = document.querySelector('.dex-notification-container'); if (!notificationContainer) { notificationContainer = document.createElement('div'); notificationContainer.className = 'dex-notification-container'; notificationContainer.style.cssText = ` position: fixed; top: 80px; left: 50%; transform: translateX(-50%); z-index: 10000; display: flex; flex-direction: column; align-items: center; gap: 4px; max-width: 400px; width: 100%; `; document.body.appendChild(notificationContainer); // CSS animasyonlarını ekle addNotificationStyles(); } // Maksimum bildirim sayısı kontrolü (2'den fazla ise en eski bildirimleri temizle) const currentNotifications = notificationContainer.querySelectorAll('.dex-notification-box'); if (currentNotifications.length >= 2) { // 2'den fazla varsa, fazla olanları hızlıca temizle const notificationsToRemove = Array.from(currentNotifications).slice(0, currentNotifications.length - 1); notificationsToRemove.forEach((notification, index) => { // Stagger effect - her birini biraz gecikmeli kaldır setTimeout(() => { notification.style.animation = 'quickFadeOut 0.3s ease-out forwards'; setTimeout(() => { if (notification.parentNode) { notification.parentNode.removeChild(notification); } }, 300); }, index * 80); // 80ms gecikme ile sırayla }); } // Bildirim ID'si oluştur const notificationId = 'demo-notification-' + Date.now(); // Tip'e göre stil ve icon belirle let iconClass, boxClass, iconLabel; switch(type) { case 'error': iconClass = 'dex-okds-fail-circle-fill'; boxClass = 'error'; iconLabel = 'Error'; break; case 'success': iconClass = 'dex-okds-success-circle-fill'; boxClass = 'success'; iconLabel = 'Success'; break; case 'warning': iconClass = 'dex-okds-warning-circle-fill'; boxClass = 'warning'; iconLabel = 'Warning'; break; case 'info': default: iconClass = 'dex-okds-info-circle-fill'; boxClass = 'info'; iconLabel = 'Info'; break; } // Bildirim HTML'i oluştur const notificationHTML = ` <div class="dex-notification-var dex-notification-box ${boxClass} auto-width" id="${notificationId}" role="alert" aria-live="polite" style="animation: lightSlideIn 0.4s ease-out;"> <span class="dex-notification-icon-circle-container"> <i class="icon iconfont dex-notification-icon-new ${iconClass}" role="img" aria-label="${iconLabel}"></i> </span> <div class="dex-notification-content"> <div class="dex-notification-title-box"> <span class="dex-notification-title">${message}</span> </div> </div> </div> `; // Bildirimi container'a EKLE (üste değil, alta ekleyeceğiz) notificationContainer.insertAdjacentHTML('beforeend', notificationHTML); // 4 saniye sonra bildirimi kaldır setTimeout(() => { const notification = document.getElementById(notificationId); if (notification) { notification.style.animation = 'lightSlideOut 0.35s ease-in forwards'; setTimeout(() => { if (notification.parentNode) { notification.parentNode.removeChild(notification); } }, 350); } }, 4000); } // CSS animasyonlarını ekleyen fonksiyon function addNotificationStyles() { if (document.querySelector('#notification-styles')) return; const style = document.createElement('style'); style.id = 'notification-styles'; style.textContent = ` @keyframes lightSlideIn { 0% { transform: translateY(-15px); opacity: 0; scale: 0.98; } 70% { transform: translateY(-5px); opacity: 0.8; scale: 0.99; } 100% { transform: translateY(0); opacity: 1; scale: 1; } } @keyframes lightSlideOut { 0% { transform: translateY(0); opacity: 1; scale: 1; } 100% { transform: translateY(-15px); opacity: 0; scale: 0.98; } } @keyframes quickFadeOut { 0% { transform: translateY(0); opacity: 1; } 100% { transform: translateY(-10px); opacity: 0; } } .dex-notification-box { transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); position: relative; will-change: transform, opacity; } .dex-notification-container { transition: all 0.3s ease-in-out; } /* Daha hafif geçişler */ .dex-notification-box.shifting { transition: transform 0.25s ease-out; } `; document.head.appendChild(style); } function setupDemoMode() { console.log('Demo trading mode initialized'); } // Sayfa yüklendiğinde başlat if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initDemoTrading); } else { initDemoTrading(); } // URL değişikliklerini dinle (SPA'lar için) let lastUrl = location.href; new MutationObserver(() => { const url = location.href; if (url !== lastUrl) { lastUrl = url; console.log('URL changed, reinitializing demo trading...'); setTimeout(initDemoTrading, 1000); } }).observe(document, { subtree: true, childList: true }); })();