// PlantUSDT Mini App - JavaScript (Polygon Network) const API_BASE = 'https://plantusdt.ddns.net'; window.API_BASE = API_BASE; let tg = window.Telegram.WebApp; let tgUser = tg.initDataUnsafe ? tg.initDataUnsafe.user : null; const PROJECT_WALLET = '0x6b2672E8b8A3D610AD3C148C70627f3b79D5cF76'; const NETWORK = 'Polygon'; const USDT_CONTRACT = '0xc2132D05D31c914a87C6611C10748AEb04B58e8F'; let timerInterval = null; let giveawayTimerInterval = null; let lastAdTime = 0; const AD_COOLDOWN = 5000; let interstitialAdsDisabled = false; let isLoading = false; let isDataLoaded = false; window.selectedCurrency = window.selectedCurrency || 'usdt'; window._latestAdCount = null; window._adCountTimestamp = null; window._isBanned = false; // ============================================ // BAN SCREEN // ============================================ function showBanScreen(reason) { if (window._isBanned) return; window._isBanned = true; try { if (timerInterval) { clearInterval(timerInterval); timerInterval = null; } if (giveawayTimerInterval) { clearInterval(giveawayTimerInterval); giveawayTimerInterval = null; } } catch (e) {} var ids = ['appContent','loadingMessage','fieldsContainer','dashboardStats','historyList']; ids.forEach(function(id) { var el = document.getElementById(id); if (el) el.style.display = 'none'; }); var banOverlay = document.createElement('div'); banOverlay.id = 'banScreen'; banOverlay.style.cssText = 'position:fixed;top:0;left:0;right:0;bottom:0;background:#0a0e17;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:32px 24px;text-align:center;z-index:999999;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;color:#ccd6f0;'; banOverlay.innerHTML = '
๐Ÿšซ
' + '
Account Suspended
' + '
' + 'Your PlantUSDT account has been suspended.

' + (reason ? '' + reason + '

' : '') + 'If you believe this is a mistake, please contact support.
' + '๐Ÿ’ฌ Contact Support' + '
๐ŸŸฃ PlantUSDT ยท Polygon Network
'; document.body.appendChild(banOverlay); console.log('๐Ÿšซ Ban screen displayed'); } // ============================================ // GRAM (TON) ADDRESS VALIDATION // ============================================ function isValidTonAddress(address) { if (!address) return false; return /^(UQ|EQ)[A-Za-z0-9_-]{46}$/.test(address) || /^-?\d+:[a-fA-F0-9]{64}$/.test(address); } // ============================================ // MATH CAPTCHA // ============================================ let mathCaptchaAnswer = null; let mathCaptchaQuestion = null; let pendingAdCallback = null; function generateMathCaptcha() { const num1 = Math.floor(Math.random() * 10) + 1; const num2 = Math.floor(Math.random() * 10) + 1; const operators = ['+', '-']; const op = operators[Math.floor(Math.random() * operators.length)]; let answer, question; if (op === '+') { answer = num1 + num2; question = `${num1} + ${num2} = ?`; } else { const bigger = Math.max(num1, num2); const smaller = Math.min(num1, num2); answer = bigger - smaller; question = `${bigger} - ${smaller} = ?`; } mathCaptchaQuestion = question; mathCaptchaAnswer = answer; return { question: mathCaptchaQuestion, answer: mathCaptchaAnswer }; } // ============================================ // DEVICE FINGERPRINT // NOTE: userAgent is deliberately excluded โ€” it contains OS version which // changes on updates and causes false-positive anomaly flags. // ============================================ function getDeviceFingerprint() { try { const scr = `${window.screen.width}x${window.screen.height}x${window.screen.colorDepth}`; const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone; const language = navigator.language; return `${scr}|${timezone}|${language}`; } catch (e) { return 'unknown'; } } function showMathCaptcha(callback) { const captcha = generateMathCaptcha(); const userAnswer = prompt(`๐Ÿงฎ Verify You're Human\n\nSolve this simple math question:\n\n${captcha.question}\n\nEnter your answer:`); if (userAnswer === null) { callback(false, null, null); return; } const parsed = parseInt(userAnswer); if (!isNaN(parsed) && parsed === captcha.answer) { callback(true, captcha.answer, captcha.question); } else { tg.showPopup({ title: 'โŒ Wrong Answer', message: 'Incorrect. Please try again.', buttons: [{type: 'ok'}] }); callback(false, null, null); } } // ============================================ // SAFE POPUP // ============================================ function safePopup(options) { try { if (typeof tg !== 'undefined' && tg.showPopup) tg.showPopup(options); else alert(typeof options === 'string' ? options : options.title + '\n\n' + options.message); } catch (e) { alert('An error occurred. Please try again.'); } } function safePopupWithCallback(options, callback) { try { if (typeof tg !== 'undefined' && tg.showPopup) tg.showPopup(options, callback); else { const message = options.title + '\n\n' + options.message; if (confirm(message)) { if (callback) callback('confirm'); } else { if (callback) callback('cancel'); } } } catch (e) { alert('An error occurred. Please try again.'); if (callback) callback('cancel'); } } function showInterstitialIfNeeded() { if (window._isBanned) return; if (interstitialAdsDisabled) return; var now = Date.now(); if (now - lastAdTime < AD_COOLDOWN) return; lastAdTime = now; if (window.showInterstitialAd && typeof window.showInterstitialAd === 'function') { setTimeout(function() { window.showInterstitialAd().catch(() => {}); }, 500); } } // ============================================ // TAB SWITCHING (bottom nav) โ€” silent on non-tabbed pages // ============================================ function switchTab(tab) { try { var hasNav = document.getElementById('bottomNav') !== null; var sections = document.querySelectorAll('.tab-section'); var buttons = document.querySelectorAll('.nav-btn'); for (var i = 0; i < sections.length; i++) sections[i].classList.remove('active'); for (var j = 0; j < buttons.length; j++) buttons[j].classList.remove('active'); var section = document.getElementById('section-' + tab); var btn = document.querySelector('.nav-btn[data-tab="' + tab + '"]'); if (section) { section.classList.add('active'); } else if (hasNav) { console.warn('โš ๏ธ switchTab: no section found for tab "' + tab + '"'); } if (btn) { btn.classList.add('active'); } else if (hasNav) { console.warn('โš ๏ธ switchTab: no nav button found for tab "' + tab + '"'); } try { localStorage.setItem('activeTab', tab); } catch (e) {} try { if (window.scrollY > 50) window.scrollTo({ top: 0, behavior: 'smooth' }); } catch (e) {} } catch (e) { console.error('switchTab error:', e); } } // ============================================ // PAGE NAVIGATION // ============================================ document.addEventListener('DOMContentLoaded', function() { try { tg.ready(); tg.expand(); var navButtons = document.querySelectorAll('.nav-btn'); for (var n = 0; n < navButtons.length; n++) { navButtons[n].addEventListener('click', function() { switchTab(this.getAttribute('data-tab')); }); } var hasBottomNav = document.getElementById('bottomNav') !== null; if (hasBottomNav) { switchTab('home'); } function initializeApp() { if (tgUser) { loadUserData(); loadSavedWallet(); setupEventListeners(); startCountdownTimer(); startGiveawayTimer(); loadAdStats(); loadTasks(); loadReferralProgress(); } else { setTimeout(initializeApp, 100); } } initializeApp(); } catch (e) { console.log('Error initializing app'); } document.addEventListener('click', function(e) { if (window._isBanned) return; var target = e.target.closest('button'); if (!target) return; if (target.classList.contains('back-btn') || target.classList.contains('no-ad') || target.id === 'watchAdBtn' || target.classList.contains('currency-btn') || target.classList.contains('nav-btn')) return; if (target.type === 'submit' && target.closest('#withdrawForm')) return; showInterstitialIfNeeded(); }); }); function navigateTo(page) { if (window._isBanned) return; const pages = {'dashboard':'dashboard.html','deposit':'deposit.html','withdraw':'withdraw.html','history':'history.html','index':'index.html'}; if (pages[page]) { showInterstitialIfNeeded(); window.location.href = pages[page]; } } function goBack() { if (window.history.length > 1) { window.history.back(); } else { window.location.href = 'index.html'; } } // ============================================ // CURRENCY SELECTION (usdt / bep20 / gram) // ============================================ function selectCurrency(currency) { window.selectedCurrency = currency; var usdtBtn = document.getElementById('usdtBtn'); var bep20Btn = document.getElementById('bep20Btn'); var gramBtn = document.getElementById('gramBtn'); var usdtGroup = document.getElementById('usdtAddressGroup'); var bep20Group = document.getElementById('bep20AddressGroup'); var gramGroup = document.getElementById('gramAddressGroup'); var networkLabel = document.getElementById('networkLabel'); if (usdtBtn) usdtBtn.classList.remove('active'); if (bep20Btn) bep20Btn.classList.remove('active'); if (gramBtn) gramBtn.classList.remove('active'); if (usdtGroup) usdtGroup.style.display = 'none'; if (bep20Group) bep20Group.style.display = 'none'; if (gramGroup) gramGroup.style.display = 'none'; if (currency === 'usdt') { if (usdtBtn) usdtBtn.classList.add('active'); if (usdtGroup) usdtGroup.style.display = 'block'; if (networkLabel) networkLabel.textContent = 'Polygon'; } else if (currency === 'bep20') { if (bep20Btn) bep20Btn.classList.add('active'); if (bep20Group) bep20Group.style.display = 'block'; if (networkLabel) networkLabel.textContent = 'BNB Chain'; } else if (currency === 'gram') { if (gramBtn) gramBtn.classList.add('active'); if (gramGroup) gramGroup.style.display = 'block'; if (networkLabel) networkLabel.textContent = 'TON'; } var feeNetEl = document.getElementById('feeNet'); if (feeNetEl) { var currentText = feeNetEl.textContent.replace('~', '').replace(' in GRAM', ''); if (currency === 'gram') { feeNetEl.textContent = '~' + currentText + ' in GRAM'; } else { feeNetEl.textContent = currentText; } } } // ============================================ // USER DATA // ============================================ async function loadUserData(retries = 3) { if (window._isBanned) return; if (isLoading) return; isLoading = true; try { const userId = tgUser ? tgUser.id : '0'; const response = await fetch(`${API_BASE}/api/user?telegram_id=${userId}`); if (response.status === 403) { let bannedData = null; try { bannedData = await response.json(); } catch (e) {} const msg = (bannedData && bannedData.message) ? bannedData.message : ''; if (msg.toLowerCase().includes('suspended') || msg.toLowerCase().includes('banned')) { isLoading = false; showBanScreen(msg); return; } } const data = await response.json(); if (data.success) { interstitialAdsDisabled = data.interstitial_ads_disabled || false; isDataLoaded = true; updateUI(data); updateFields(data); updateReferral(data); updateDashboardUI(data); updateDailyEarnings(data); await updateReferralStats(userId); await updateWelcomeBonusButton(data); updateTierButtons(data); updateClaimReferralButton(data); updateGiveawayProgress(data); var loadingEl = document.getElementById('loadingMessage'); var appContent = document.getElementById('appContent'); if (loadingEl) loadingEl.style.display = 'none'; if (appContent) appContent.style.display = 'block'; if (data.interstitial_ads_disabled) { const disableBtn = document.getElementById('disableAdsBtn'); if (disableBtn) { disableBtn.textContent = 'โœ… Ads Disabled'; disableBtn.disabled = true; disableBtn.style.opacity = '0.5'; } } loadAdStats(); loadReferralProgress(); } } catch (error) { if (retries > 0 && !window._isBanned) setTimeout(() => loadUserData(retries - 1), 1000); } finally { isLoading = false; } } function refreshData() { if (window._isBanned) return; showInterstitialIfNeeded(); var balanceEl = document.getElementById('balance'); var totalEarningsEl = document.getElementById('totalEarnings'); if (balanceEl) balanceEl.textContent = 'โณ ...'; if (totalEarningsEl) totalEarningsEl.textContent = 'โณ ...'; setTimeout(function() { loadUserData(); loadSavedWallet(); loadAdStats(); loadTasks(); loadReferralProgress(); }, 300); } async function updateReferralStats(userId) { if (window._isBanned) return; try { const response = await fetch(`${API_BASE}/api/referral_stats/${userId}`); const data = await response.json(); if (data.success) { var rc = document.getElementById('referralCount'); var re = document.getElementById('referralEarned'); var lc = document.getElementById('level1Count'); var le = document.getElementById('level1Earnings'); if (rc) rc.textContent = data.total_referrals || 0; if (re) re.textContent = '$' + Number(data.total_earnings || 0).toFixed(3); if (lc) lc.textContent = data.level1_count || 0; if (le) le.textContent = '$' + Number(data.level1_earnings || 0).toFixed(3); } } catch (error) {} } function updateUI(data) { var b = document.getElementById('balance'); if (b) b.textContent = '$' + Number(data.balance || 0).toFixed(3); var te = document.getElementById('totalEarnings'); if (te) te.textContent = '$' + Number(data.total_earnings || 0).toFixed(3); var ie = document.getElementById('investmentEarnings'); if (ie) ie.textContent = '$' + Number(data.investment_earnings || 0).toFixed(3); var rd = document.getElementById('referralEarningsDisplay'); if (rd) rd.textContent = '$' + Number(data.referral_earned || 0).toFixed(3); var ad = document.getElementById('adEarningsDisplay'); if (ad) ad.textContent = '$' + Number(data.total_ad_earnings || 0).toFixed(3); var tsk = document.getElementById('tasksEarningsDisplay'); if (tsk) tsk.textContent = '$' + Number(data.tasks_earnings || 0).toFixed(3); } function updateDashboardUI(data) { var ids = {'dashBalance':'balance','dashInvested':'total_invested','dashEarned':'total_earnings','dashDeposited':'total_deposited','dashAdEarnings':'total_ad_earnings','dashTasksEarnings':'tasks_earnings'}; for (var id in ids) { var el = document.getElementById(id); if (el) el.textContent = '$' + Number(data[ids[id]] || 0).toFixed(3); } var dr = document.getElementById('dashReferrals'); if (dr) dr.textContent = data.referrals || 0; } function updateDailyEarnings(data) { var dailyEl = document.getElementById('dailyEarnings'); if (dailyEl) dailyEl.textContent = '+$' + Number(data.expected_daily_earnings || 0).toFixed(2) + ' / day'; } // ============================================ // GIVEAWAY PROGRESS + RESET TIMER // ============================================ function getNextFridayUTC() { const now = new Date(); const utcDay = now.getUTCDay(); let daysUntilFri = (5 - utcDay + 7) % 7; if (daysUntilFri === 0) daysUntilFri = 7; return Date.UTC( now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() + daysUntilFri, 0, 0, 0, 0 ); } function formatGiveawayCountdown(ms) { if (ms < 0) ms = 0; const totalSec = Math.floor(ms / 1000); const d = Math.floor(totalSec / 86400); const h = Math.floor((totalSec % 86400) / 3600); const m = Math.floor((totalSec % 3600) / 60); const s = totalSec % 60; const pad = function(n) { return String(n).padStart(2, '0'); }; if (d > 0) return d + 'd ' + pad(h) + 'h ' + pad(m) + 'm ' + pad(s) + 's'; return pad(h) + 'h ' + pad(m) + 'm ' + pad(s) + 's'; } function tickGiveawayTimer() { const el = document.getElementById('giveawayResetTimer'); if (!el) return; const diff = getNextFridayUTC() - Date.now(); el.textContent = 'โณ Resets in ' + formatGiveawayCountdown(diff); } function startGiveawayTimer() { if (giveawayTimerInterval) clearInterval(giveawayTimerInterval); tickGiveawayTimer(); giveawayTimerInterval = setInterval(tickGiveawayTimer, 1000); } function updateGiveawayProgress(data) { var cycleAds = Number(data.ads_watched_this_cycle || 0); var progressBar = document.getElementById('giveawayProgressBar'); var progressText = document.getElementById('giveawayProgressText'); var statusEl = document.getElementById('giveawayStatus'); var timerEl = document.getElementById('giveawayResetTimer'); if (cycleAds >= 150) { if (progressText) progressText.textContent = '150 / 150'; if (progressBar) { progressBar.style.width = '100%'; progressBar.style.background = 'linear-gradient(90deg,#ffd93d,#f9a825)'; } if (statusEl) { statusEl.textContent = '๐Ÿ† QUALIFIED FOR THIS WEEK\'S DRAW'; statusEl.style.color = '#ffd93d'; statusEl.style.fontWeight = '700'; } if (timerEl) { timerEl.style.color = '#ffd93d'; } } else { var pct = Math.min((cycleAds / 150) * 100, 100); if (progressText) progressText.textContent = cycleAds + ' / 150'; if (progressBar) { progressBar.style.width = pct + '%'; progressBar.style.background = 'linear-gradient(90deg,#8247E5,#00ff87)'; } if (statusEl) { statusEl.textContent = 'Watch 150 ads to qualify (' + (150 - cycleAds) + ' remaining)'; statusEl.style.color = '#8892b0'; statusEl.style.fontWeight = '400'; } if (timerEl) { timerEl.style.color = '#8892b0'; } } } function updateWelcomeBonusButton(data) { const btn = document.getElementById('claimWelcomeBtn'); if (!btn) return; if (data.has_received_welcome_bonus) { btn.remove(); } } function updateClaimReferralButton(data) { var btn = document.getElementById('claimReferralEarningsBtn'); if (!btn) return; var pending = Number(data.pending_referral_rewards || 0); if (pending > 0) { btn.textContent = '๐Ÿ’ฐ Available Earnings: $' + pending.toFixed(3) + ' (Claim)'; btn.disabled = false; btn.style.background = 'linear-gradient(135deg,#00ff87,#00cc6a)'; btn.style.color = '#0a0e17'; btn.style.cursor = 'pointer'; btn.style.opacity = '1'; } else { btn.textContent = '๐Ÿ’ฐ Available Earnings: $0.000'; btn.disabled = true; btn.style.background = '#495670'; btn.style.color = '#ccd6f0'; btn.style.cursor = 'not-allowed'; btn.style.opacity = '0.6'; } } function updateTierButtons(data) { const userTier = data.referral_tier || 'free'; const tierOrder = ['free', 'bronze', 'silver', 'gold', 'diamond']; document.querySelectorAll('.tier-card').forEach(card => { const btn = card.querySelector('.tier-btn'); if (!btn) return; const nameEl = card.querySelector('.tier-name'); if (!nameEl) return; const tierName = nameEl.textContent.toLowerCase(); if (tierName === userTier) { btn.textContent = 'Current'; btn.disabled = true; btn.className = 'tier-btn current'; btn.style.background = '#495670'; btn.style.color = 'white'; btn.style.cursor = 'default'; btn.onclick = null; } else { const userIndex = tierOrder.indexOf(userTier); const cardIndex = tierOrder.indexOf(tierName); if (cardIndex > userIndex) { btn.textContent = 'Upgrade'; btn.disabled = false; btn.className = 'tier-btn'; btn.style.background = ''; btn.style.color = ''; btn.style.cursor = 'pointer'; } else { btn.textContent = 'Locked'; btn.disabled = true; btn.className = 'tier-btn locked'; btn.style.background = '#2a2a2a'; btn.style.color = '#555'; btn.style.cursor = 'default'; btn.onclick = null; } } }); } function updateFields(data) { var fields = data.fields || []; window.fieldData = {}; for (var i = 1; i <= 3; i++) { var statusEl = document.getElementById('field' + i + 'Status'); var amountEl = document.getElementById('field' + i + 'Amount'); var daysEl = document.getElementById('field' + i + 'Days'); var earnedEl = document.getElementById('field' + i + 'Earned'); var progressEl = document.getElementById('field' + i + 'Progress'); var cardEl = document.getElementById('field' + i); var btnEl = document.getElementById('field' + i + 'Btn'); var timerEl = document.getElementById('field' + i + 'Timer'); if (!statusEl || !amountEl || !daysEl || !earnedEl || !progressEl || !cardEl || !btnEl || !timerEl) continue; var field = fields.find(function(f) { return f.field_number === i; }); if (field) { var lockPeriod = field.lock_period || 30; var isLocked = field.is_locked || false; var unlockDate = new Date(field.unlock_date); var now = new Date(); var daysRemaining = Math.max(0, Math.ceil((unlockDate - now) / (1000 * 60 * 60 * 24))); var daysElapsed = lockPeriod - daysRemaining; window.fieldData[i] = { unlock_date: field.unlock_date, is_locked: isLocked, lock_period: lockPeriod, is_ready: false }; amountEl.textContent = '$' + field.amount.toFixed(3); daysEl.textContent = isLocked ? daysElapsed + '/' + lockPeriod + ' days' : lockPeriod + '/' + lockPeriod + ' days'; var displayEarned = isLocked ? field.expected_return || 0 : field.paid_out || 0; earnedEl.textContent = '$' + displayEarned.toFixed(3); var progress = isLocked ? ((lockPeriod - daysRemaining) / lockPeriod) * 100 : 100; progressEl.style.width = Math.min(progress, 100) + '%'; cardEl.className = 'field-card active'; btnEl.textContent = '๐Ÿ”’ Locked'; btnEl.disabled = true; btnEl.style.opacity = '0.5'; btnEl.style.cursor = 'not-allowed'; btnEl.onclick = null; } else { statusEl.textContent = 'โœ… Available'; statusEl.className = 'field-status available'; statusEl.style.color = '#8247E5'; amountEl.textContent = '$0.000'; daysEl.textContent = '0 days'; earnedEl.textContent = '$0.000'; progressEl.style.width = '0%'; cardEl.className = 'field-card'; btnEl.textContent = '๐ŸŒฑ Plant Now'; btnEl.disabled = false; btnEl.style.opacity = '1'; btnEl.style.cursor = 'pointer'; btnEl.onclick = (function(fn) { return function() { showInterstitialIfNeeded(); investField(fn); }; })(i); window.fieldData[i] = null; } } } let claimInProgress = false; async function claimInvestment(fieldNumber) { if (window._isBanned) return; if (claimInProgress) return; claimInProgress = true; const userId = tgUser ? tgUser.id : '0'; if (!userId || userId === '0') { safePopup({ title: 'โŒ Error', message: 'User not authenticated.', buttons: [{type: 'ok'}] }); claimInProgress = false; return; } const btn = document.getElementById('field' + fieldNumber + 'Btn'); const originalText = btn ? btn.textContent : ''; if (btn) { btn.textContent = 'โณ Processing...'; btn.disabled = true; btn.style.opacity = '0.7'; } safePopupWithCallback({ title: '๐ŸŒพ Claim Investment', message: 'Are you sure you want to claim Field #' + fieldNumber + '?', buttons: [{id:'cancel',type:'cancel'},{id:'confirm',type:'ok',text:'โœ… Claim'}] }, async function(buttonId) { if (buttonId === 'confirm') { try { const response = await fetch(`${API_BASE}/api/claim_investment`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ telegram_id: userId, field_number: fieldNumber }) }); const data = await response.json(); if (data.success) { safePopup({ title: 'โœ… Claimed!', message: 'You claimed $' + data.amount.toFixed(2) + ' USDT from Field #' + fieldNumber + '!', buttons: [{type: 'ok'}] }); setTimeout(function() { loadUserData(); loadAdStats(); loadTasks(); loadReferralProgress(); claimInProgress = false; if (btn) { btn.textContent = originalText; btn.disabled = false; btn.style.opacity = '1'; } }, 3000); } else { safePopup({ title: 'โŒ Error', message: data.message || 'Failed to claim.', buttons: [{type: 'ok'}] }); claimInProgress = false; if (btn) { btn.textContent = originalText; btn.disabled = false; btn.style.opacity = '1'; } } } catch (error) { safePopup({ title: 'โŒ Error', message: 'Network error. Please try again.', buttons: [{type: 'ok'}] }); claimInProgress = false; if (btn) { btn.textContent = originalText; btn.disabled = false; btn.style.opacity = '1'; } } } else { claimInProgress = false; if (btn) { btn.textContent = originalText; btn.disabled = false; btn.style.opacity = '1'; } } }); } function updateFieldTimers() { if (window._isBanned) return; if (document.getElementById('historyList')) return; var now = new Date(); var utcNow = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), now.getUTCHours(), now.getUTCMinutes(), now.getUTCSeconds()); for (var i = 1; i <= 3; i++) { var timerEl = document.getElementById('field' + i + 'Timer'); var statusEl = document.getElementById('field' + i + 'Status'); var btnEl = document.getElementById('field' + i + 'Btn'); if (!timerEl || !statusEl || !btnEl) continue; var fieldData = window.fieldData ? window.fieldData[i] : null; if (!fieldData || !fieldData.unlock_date) { timerEl.textContent = 'โณ Payout: --:--:-- UTC'; timerEl.className = 'field-timer'; continue; } var isLocked = fieldData.is_locked === true; var lockPeriod = fieldData.lock_period || 30; var unlockDateStr = fieldData.unlock_date; if (unlockDateStr.endsWith('Z')) unlockDateStr = unlockDateStr.slice(0, -1); var unlockDate = new Date(unlockDateStr + 'Z').getTime(); var timeLeft = unlockDate - utcNow; var isReady = (isLocked === true) && (timeLeft <= 0); fieldData.is_ready = isReady; if (isReady) { timerEl.textContent = '๐ŸŸข READY TO CLAIM!'; timerEl.className = 'field-timer ready'; timerEl.style.color = '#ffd93d'; timerEl.style.animation = 'pulse-gold 1.5s infinite'; btnEl.textContent = '๐ŸŒพ Claim Now!'; btnEl.disabled = false; btnEl.style.opacity = '1'; btnEl.style.cursor = 'pointer'; btnEl.style.background = 'linear-gradient(135deg, #ffd93d, #f9a825)'; btnEl.style.color = '#0a0e17'; btnEl.onclick = (function(fn) { return function() { claimInvestment(fn); }; })(i); statusEl.textContent = 'โœ… Ready to Claim!'; statusEl.className = 'field-status ready'; statusEl.style.color = '#ffd93d'; } else if (isLocked === true && timeLeft > 0) { var days = Math.floor(timeLeft / (1000 * 60 * 60 * 24)); var hours = Math.floor((timeLeft % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); var minutes = Math.floor((timeLeft % (1000 * 60 * 60)) / (1000 * 60)); var seconds = Math.floor((timeLeft % (1000 * 60)) / 1000); var timeString = days > 0 ? days + 'd ' + String(hours).padStart(2,'0') + ':' + String(minutes).padStart(2,'0') + ':' + String(seconds).padStart(2,'0') : String(hours).padStart(2,'0') + ':' + String(minutes).padStart(2,'0') + ':' + String(seconds).padStart(2,'0'); timerEl.textContent = '๐Ÿ”„ Unlock in: ' + timeString + ' UTC'; timerEl.className = 'field-timer countdown'; btnEl.textContent = '๐Ÿ”’ Locked'; btnEl.disabled = true; btnEl.style.opacity = '0.5'; btnEl.style.cursor = 'not-allowed'; btnEl.onclick = null; statusEl.textContent = '๐Ÿ”’ Locked'; statusEl.className = 'field-status locked'; statusEl.style.color = '#ff6b6b'; } else if (isLocked === false) { timerEl.textContent = '๐ŸŸข Available (UTC)'; timerEl.className = 'field-timer'; btnEl.textContent = '๐ŸŒฑ Plant Now'; btnEl.disabled = false; btnEl.style.opacity = '1'; btnEl.style.cursor = 'pointer'; btnEl.onclick = (function(fn) { return function() { showInterstitialIfNeeded(); investField(fn); }; })(i); statusEl.textContent = 'โœ… Available'; statusEl.className = 'field-status available'; statusEl.style.color = '#8247E5'; } } } var style = document.createElement('style'); style.textContent = `@keyframes pulse-gold { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }`; document.head.appendChild(style); function startCountdownTimer() { updateFieldTimers(); if (timerInterval) clearInterval(timerInterval); timerInterval = setInterval(updateFieldTimers, 1000); } function stopCountdownTimer() { if (timerInterval) { clearInterval(timerInterval); timerInterval = null; } } async function updateReferral(data) { if (window._isBanned) return; var referralLink = document.getElementById('referralLinkText'); var walletText = document.getElementById('walletText'); var isConnected = walletText ? walletText.textContent.includes('Connected') : false; if (!referralLink) return; if (isConnected) { var userId = tgUser ? tgUser.id : '0'; try { var response = await fetch(API_BASE + '/api/get_referral_code?telegram_id=' + userId + '&t=' + Date.now()); var result = await response.json(); if (result.success && result.referral_code) { referralLink.textContent = 'https://t.me/PlantUSDT_bot?start=' + result.referral_code; referralLink.style.color = '#ccd6f0'; } else { referralLink.textContent = 'Error loading referral link'; referralLink.style.color = '#ff6b6b'; } } catch (error) { referralLink.textContent = 'Error loading referral link'; referralLink.style.color = '#ff6b6b'; } } else { referralLink.textContent = 'โš ๏ธ Save wallet to get referral link'; referralLink.style.color = '#ff6b6b'; } } async function copyReferral() { if (window._isBanned) return; showInterstitialIfNeeded(); var userId = tgUser ? tgUser.id : '0'; var referralLinkEl = document.getElementById('referralLinkText'); try { var response = await fetch(API_BASE + '/api/get_referral_code?telegram_id=' + userId + '&t=' + Date.now()); var data = await response.json(); if (data.success && data.referral_code) { var referralLink = 'https://t.me/PlantUSDT_bot?start=' + data.referral_code; if (referralLinkEl) { referralLinkEl.textContent = referralLink; referralLinkEl.style.color = '#ccd6f0'; } var copied = false; try { await navigator.clipboard.writeText(referralLink); copied = true; } catch (e) {} if (!copied) { var textArea = document.createElement('textarea'); textArea.value = referralLink; textArea.style.position = 'fixed'; textArea.style.left = '-9999px'; document.body.appendChild(textArea); textArea.focus(); textArea.select(); try { if (document.execCommand('copy')) copied = true; } catch (e) {} document.body.removeChild(textArea); } if (!copied) { safePopup({ title: '๐Ÿ“‹ Copy Referral Link', message: 'Copy manually:\n\n' + referralLink, buttons: [{type:'ok'}] }); return; } safePopup({ title: 'โœ… Copied!', message: 'Referral link copied! Share it with friends! ๐ŸŽ‰', buttons: [{type: 'ok'}] }); } else { safePopup({ title: 'โŒ Error', message: 'Could not get referral link.', buttons: [{type: 'ok'}] }); } } catch (error) { safePopup({ title: 'โŒ Error', message: 'Network error.', buttons: [{type: 'ok'}] }); } } async function claimReferralRewards() { if (window._isBanned) return; const userId = tgUser ? tgUser.id : '0'; safePopupWithCallback({ title: '๐Ÿ’ฐ Claim Referral Rewards', message: 'Claim all available referral earnings to your balance?', buttons: [{id: 'cancel', type: 'cancel'}, {id: 'confirm', type: 'ok', text: 'โœ… Claim'}] }, async function(buttonId) { if (buttonId === 'confirm') { try { const response = await fetch(`${API_BASE}/api/claim_referral_rewards`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ telegram_id: userId }) }); const data = await response.json(); if (data.success) { safePopup({ title: '๐ŸŽ‰ Claimed!', message: data.message + '\n\nNew balance: $' + data.new_balance.toFixed(3), buttons: [{type: 'ok'}] }); loadUserData(); } else { safePopup({ title: 'โŒ Error', message: data.message || 'Failed to claim.', buttons: [{type: 'ok'}] }); } } catch (error) { safePopup({ title: 'โŒ Error', message: 'Network error.', buttons: [{type: 'ok'}] }); } } }); } async function saveWallet() { if (window._isBanned) return; showInterstitialIfNeeded(); var userId = tgUser ? tgUser.id : '0'; var walletInput = document.getElementById('walletInput'); var walletAddress = walletInput ? walletInput.value.trim() : ''; if (!walletAddress) { safePopup({title:'โŒ Error', message:'Please enter a Polygon wallet address.', buttons:[{type:'ok'}]}); return; } if (!walletAddress.startsWith('0x') || walletAddress.length !== 42) { safePopup({title:'โŒ Invalid Address', message:'Please enter a valid Polygon wallet address.', buttons:[{type:'ok'}]}); return; } if (walletAddress.toLowerCase() === PROJECT_WALLET.toLowerCase()) { safePopup({title:'โŒ Invalid Wallet', message:'This is the project wallet.', buttons:[{type:'ok'}]}); return; } try { var response = await fetch(API_BASE + '/api/save_wallet', { method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({telegram_id:userId, wallet_address:walletAddress}) }); var data = await response.json(); if (data.success) { safePopup({title:'โœ… Wallet Saved!', message:'Wallet saved: ' + walletAddress.slice(0,6) + '...' + walletAddress.slice(-4), buttons:[{type:'ok'}]}); updateWalletUI(walletAddress); loadUserData(); } else { safePopup({title:'โŒ Error', message:data.message || 'Failed to save wallet.', buttons:[{type:'ok'}]}); } } catch (error) { safePopup({title:'โŒ Error', message:'Failed to save wallet.', buttons:[{type:'ok'}]}); } } function updateWalletUI(address) { var statusText = document.getElementById('walletText'); var addressDisplay = document.getElementById('walletAddressDisplay'); var walletInput = document.getElementById('walletInput'); var saveBtn = document.getElementById('saveWalletBtn'); var disconnectBtn = document.getElementById('disconnectWalletBtn'); if (statusText) { statusText.textContent = 'โœ… Polygon Wallet Connected'; statusText.className = 'connected'; } if (addressDisplay) { addressDisplay.textContent = '๐Ÿ“ ' + address + ' (Polygon)'; addressDisplay.style.display = 'block'; } if (walletInput) { walletInput.value = address; walletInput.disabled = true; walletInput.style.opacity = '0.6'; } if (saveBtn) saveBtn.style.display = 'none'; if (disconnectBtn) disconnectBtn.style.display = 'flex'; loadUserData(); setTimeout(function() { var userId = tgUser ? tgUser.id : '0'; fetch(API_BASE + '/api/user?telegram_id=' + userId).then(r => r.json()).then(data => updateReferral(data)); }, 500); } function resetWalletUI() { var statusText = document.getElementById('walletText'); var addressDisplay = document.getElementById('walletAddressDisplay'); var walletInput = document.getElementById('walletInput'); var saveBtn = document.getElementById('saveWalletBtn'); var disconnectBtn = document.getElementById('disconnectWalletBtn'); if (statusText) { statusText.textContent = 'Polygon wallet not connected'; statusText.className = 'disconnected'; } if (addressDisplay) addressDisplay.style.display = 'none'; if (walletInput) { walletInput.value = ''; walletInput.disabled = false; walletInput.style.opacity = '1'; } if (saveBtn) saveBtn.style.display = 'flex'; if (disconnectBtn) disconnectBtn.style.display = 'none'; loadUserData(); } async function disconnectWallet() { if (window._isBanned) return; showInterstitialIfNeeded(); var userId = tgUser ? tgUser.id : '0'; safePopupWithCallback({ title:'๐Ÿ”“ Disconnect Wallet', message:'Are you sure you want to disconnect your Polygon wallet?', buttons:[{id:'cancel',type:'cancel'},{id:'confirm',type:'ok',text:'Disconnect'}] }, async function(buttonId) { if (buttonId === 'confirm') { try { var response = await fetch(API_BASE + '/api/save_wallet', { method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({telegram_id:userId, wallet_address:''}) }); var data = await response.json(); if (data.success) { resetWalletUI(); safePopup({title:'โœ… Disconnected', message:'Polygon wallet disconnected.', buttons:[{type:'ok'}]}); } else { safePopup({title:'โŒ Error', message:'Failed to disconnect.', buttons:[{type:'ok'}]}); } } catch (error) { safePopup({title:'โŒ Error', message:'Failed to disconnect.', buttons:[{type:'ok'}]}); } } }); } async function loadSavedWallet() { if (window._isBanned) return; var userId = tgUser ? tgUser.id : '0'; try { var response = await fetch(API_BASE + '/api/get_wallet?telegram_id=' + userId); var data = await response.json(); if (data.success && data.wallet_address) updateWalletUI(data.wallet_address); } catch (error) {} } async function setWallet() { if (window._isBanned) return; showInterstitialIfNeeded(); var userId = tgUser ? tgUser.id : '0'; try { var response = await fetch(API_BASE + '/api/get_wallet?telegram_id=' + userId); var data = await response.json(); if (data.success && data.wallet_address) { var withdrawAddress = document.getElementById('withdrawAddress'); if (withdrawAddress) { withdrawAddress.value = data.wallet_address; safePopup({title:'โœ… Wallet Loaded!', message:'Wallet loaded.', buttons:[{type:'ok'}]}); } } else { safePopup({ title: 'โŒ No Wallet Found', message: 'Please save a wallet first.', buttons: [{type: 'ok'}] }); } } catch (error) { safePopup({ title: 'โŒ Error', message: 'Failed to load wallet.', buttons: [{type: 'ok'}] }); } } // ============================================ // INVESTMENT MATH (v92: 1% / 8% / 35%) // ============================================ function calculateReturn(amount, days) { const multipliers = {1: 1.01, 7: 1.08, 30: 1.35}; return amount * (multipliers[days] || 1.35); } function getLockOptions() { return [{days:1,returnPercent:1},{days:7,returnPercent:8},{days:30,returnPercent:35}]; } async function investFieldWithLock(fieldNumber) { if (window._isBanned) return; showInterstitialIfNeeded(); const userId = tgUser ? tgUser.id : '0'; const amount = prompt('Enter amount to invest in Field #' + fieldNumber + ' (min $5.00, max $100.00):'); if (!amount) return; const amountNum = parseFloat(amount.replace('$', '').trim()); if (isNaN(amountNum) || amountNum < 5 || amountNum > 100) { safePopup({title:'โŒ Invalid Amount', message:'Please enter between $5.00 and $100.00.', buttons:[{type:'ok'}]}); return; } const options = getLockOptions(); let message = '๐Ÿ“Š Choose lock period:\n\n'; options.forEach(opt => { const returnAmount = calculateReturn(amountNum, opt.days); const profit = returnAmount - amountNum; message += 'โ€ข ' + opt.days + ' day' + (opt.days > 1 ? 's' : '') + ': +' + opt.returnPercent + '% โ†’ $' + returnAmount.toFixed(2) + ' (+$' + profit.toFixed(2) + ')\n'; }); message += '\n\nEnter 1, 7, or 30:'; const lockPeriod = prompt(message); if (!lockPeriod) return; const days = parseInt(lockPeriod); if (![1, 7, 30].includes(days)) { safePopup({title:'โŒ Invalid Option', message:'Please enter 1, 7, or 30.', buttons:[{type:'ok'}]}); return; } const expectedReturn = calculateReturn(amountNum, days); const profit = expectedReturn - amountNum; safePopupWithCallback({ title: '๐Ÿ“Š Confirm Investment', message: 'Field #' + fieldNumber + '\n\n๐Ÿ’ฐ Amount: $' + amountNum.toFixed(2) + '\nโฑ๏ธ Lock: ' + days + ' days\n๐Ÿ“ˆ Return: $' + expectedReturn.toFixed(2) + '\nโœ… Profit: +$' + profit.toFixed(2), buttons: [{id:'cancel',type:'cancel'},{id:'confirm',type:'ok',text:'โœ… Confirm'}] }, async function(buttonId) { if (buttonId === 'confirm') { try { const response = await fetch(API_BASE + '/api/invest_locked', { method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({ telegram_id: userId, field_number: fieldNumber, amount: amountNum, lock_period: days }) }); if (!response.ok) { safePopup({ title:'โŒ Error', message:'Something went wrong.', buttons:[{type:'ok'}] }); return; } const data = await response.json(); if (data.success) { safePopup({ title:'โœ… Success!', message:'Invested $' + amountNum.toFixed(2) + ' in Field #' + fieldNumber + '!\n๐Ÿ”’ Locked for ' + days + ' days.\n๐Ÿ“ˆ Expected return: $' + expectedReturn.toFixed(2), buttons:[{type:'ok'}] }); loadUserData(); } else { safePopup({ title:'โŒ Error', message:data.message || 'Investment failed.', buttons:[{type:'ok'}] }); } } catch (error) { safePopup({ title:'โŒ Error', message:'Network error.', buttons:[{type:'ok'}] }); } } }); } async function investField(fieldNumber) { await investFieldWithLock(fieldNumber); } function copyAddress() { if (window._isBanned) return; showInterstitialIfNeeded(); var addressElement = document.getElementById('addressText'); var address = addressElement ? addressElement.textContent.trim() : ''; if (!address) { var displayElement = document.querySelector('.address'); if (displayElement) address = displayElement.textContent.trim(); } address = address.replace(/\s+/g, '').trim(); if (address && address.startsWith('0x') && address.length === 42) { if (navigator.clipboard && navigator.clipboard.writeText) { navigator.clipboard.writeText(address).then(function() { safePopup({ title: 'โœ… Copied!', message: 'Address copied.', buttons: [{type: 'ok'}] }); }).catch(function() { var textArea = document.createElement('textarea'); textArea.value = address; document.body.appendChild(textArea); textArea.select(); document.execCommand('copy'); document.body.removeChild(textArea); safePopup({ title: 'โœ… Copied!', message: 'Address copied.', buttons: [{type: 'ok'}] }); }); } else { var textArea = document.createElement('textarea'); textArea.value = address; document.body.appendChild(textArea); textArea.select(); document.execCommand('copy'); document.body.removeChild(textArea); safePopup({ title: 'โœ… Copied!', message: 'Address copied.', buttons: [{type: 'ok'}] }); } } else { safePopup({ title: 'โŒ Error', message: 'Invalid address.', buttons: [{type: 'ok'}] }); } } async function checkDeposit() { if (window._isBanned) return; var statusDiv = document.getElementById('depositStatus'); if (statusDiv) { statusDiv.textContent = '๐Ÿ” Checking Polygon for deposits...'; try { var userId = tgUser ? tgUser.id : '0'; var response = await fetch(API_BASE + '/api/check_deposit?telegram_id=' + userId); var data = await response.json(); if (data.success) { statusDiv.textContent = 'โœ… Deposit detected!'; loadUserData(); } else { statusDiv.textContent = 'โณ No new deposits found.'; } } catch (error) { statusDiv.textContent = 'โŒ Error checking deposits.'; } } } async function checkDepositWithAmount() { if (window._isBanned) return; showInterstitialIfNeeded(); const userId = tgUser?.id || '0'; const amountInput = document.getElementById('depositAmount'); const amount = amountInput?.value; if (!amount || parseFloat(amount) < 5) { safePopup({ title: 'โš ๏ธ Invalid Amount', message: 'Please enter at least $5 USDT.', buttons: [{type: 'ok'}] }); return; } const statusDiv = document.getElementById('depositStatus'); if (statusDiv) { statusDiv.textContent = '๐Ÿ” Checking Polygon for deposits...'; statusDiv.className = 'deposit-status pending'; statusDiv.style.display = 'block'; try { const response = await fetch(`${API_BASE}/api/check_deposit_with_amount?telegram_id=${userId}&expected_amount=${parseFloat(amount)}`); const data = await response.json(); if (data.success) { statusDiv.textContent = 'โœ… ' + data.message; statusDiv.className = 'deposit-status success'; setTimeout(() => { window.location.reload(); }, 2000); } else { statusDiv.textContent = 'โณ ' + data.message; statusDiv.className = 'deposit-status pending'; } } catch (error) { statusDiv.textContent = 'โŒ Error checking deposits.'; statusDiv.className = 'deposit-status error'; } } } function filterHistory(type) { if (window._isBanned) return; var activeButton = null; var buttons = document.querySelectorAll('.filter-btn'); for (var i = 0; i < buttons.length; i++) { var btnText = buttons[i].textContent.toLowerCase(); if (btnText === type || btnText.includes(type)) { activeButton = buttons[i]; break; } } if (!activeButton && buttons.length > 0) activeButton = buttons[0]; for (var i = 0; i < buttons.length; i++) buttons[i].classList.remove('active'); if (activeButton) activeButton.classList.add('active'); var historyList = document.getElementById('historyList'); if (!historyList) return; historyList.textContent = 'Loading...'; var userId = tgUser ? tgUser.id : '0'; var url1 = API_BASE + '/api/real_history?telegram_id=' + userId; var url2 = API_BASE + '/api/investments/' + userId; Promise.all([fetch(url1), fetch(url2)]) .then(function(responses) { return Promise.all(responses.map(function(r) { return r.json(); })); }) .then(function(data) { var allTransactions = []; if (data[0].transactions && data[0].transactions.length > 0) allTransactions = allTransactions.concat(data[0].transactions); if (data[1].transactions && data[1].transactions.length > 0) { data[1].transactions.forEach(function(tx) { tx.type = 'investment'; }); allTransactions = allTransactions.concat(data[1].transactions); } if (allTransactions.length === 0) { historyList.textContent = 'No transactions found.'; return; } if (type !== 'all') { allTransactions = allTransactions.filter(function(tx) { if (type === 'deposits') return tx.type === 'deposit' || tx.type === 'deposits'; if (type === 'withdrawals') return tx.type === 'withdraw' || tx.type === 'withdrawal' || tx.type === 'withdrawals'; if (type === 'earnings') return tx.type === 'earnings' || tx.type === 'earning' || tx.type === 'payout' || tx.type === 'referral_earnings' || tx.type === 'ad_earnings' || tx.type === 'tasks_earnings'; if (type === 'investments') return tx.type === 'investment' || tx.type === 'investments'; return tx.type === type; }); } if (allTransactions.length === 0) { historyList.textContent = 'No ' + type + ' transactions found.'; return; } allTransactions.sort(function(a, b) { return new Date(b.date) - new Date(a.date); }); renderHistory(allTransactions); }) .catch(function(error) { historyList.textContent = 'Error loading history.'; }); } function renderHistory(transactions) { var historyList = document.getElementById('historyList'); if (!historyList) return; var html = ''; for (var i = 0; i < transactions.length; i++) { var tx = transactions[i]; var icon = tx.type === 'deposit' ? '๐Ÿ“ฅ' : tx.type === 'withdraw' ? '๐Ÿ“ค' : tx.type === 'investment' ? '๐ŸŒฑ' : tx.type === 'referral_earnings' ? '๐ŸŽ' : tx.type === 'ad_earnings' ? '๐Ÿ“บ' : tx.type === 'tasks_earnings' ? 'โœ…' : '๐Ÿ’ฐ'; var status = tx.status || 'completed'; var displayText = tx.type.charAt(0).toUpperCase() + tx.type.slice(1); if (tx.type === 'referral_earnings') displayText = 'Referral Bonus'; if (tx.type === 'ad_earnings') displayText = 'Ad Earnings'; if (tx.type === 'tasks_earnings') displayText = 'Tasks Earnings'; var amountDisplay = '$' + tx.amount.toFixed(3); if (tx.type === 'investment' && tx.field) amountDisplay = '$' + tx.amount.toFixed(3) + ' (Field ' + tx.field + ')'; var statusBadge = (tx.type === 'withdraw' && tx.status === 'pending') ? ' โณ' : ''; html += '
' + '
' + icon + '
' + '
' + '
' + displayText + ' ๐ŸŸฃ Polygon' + statusBadge + '
' + '
' + tx.date + '
' + '
' + '
' + amountDisplay + '
' + '
'; } historyList.innerHTML = html; } function setupEventListeners() { var withdrawForm = document.getElementById('withdrawForm'); if (withdrawForm) { withdrawForm.addEventListener('submit', function(e) { e.preventDefault(); if (window._isBanned) return; var submitBtn = document.querySelector('.withdraw-btn'); if (submitBtn && submitBtn.disabled) return; showInterstitialIfNeeded(); var userId = tgUser ? tgUser.id : '0'; var currency = window.selectedCurrency || 'usdt'; var amountInput = document.getElementById('withdrawAmount'); var addressInput = document.getElementById('withdrawAddress'); var bep20Input = document.getElementById('bep20Address'); var gramInput = document.getElementById('gramAddress'); var amount = 0; if (window.withdrawAmount !== undefined && window.withdrawAmount > 0) amount = window.withdrawAmount; else if (amountInput && amountInput.value) amount = parseFloat(amountInput.value); else { var fullBalanceEl = document.getElementById('fullBalanceDisplay'); if (fullBalanceEl) amount = parseFloat(fullBalanceEl.textContent.replace('$', '')); } var address = ''; if (currency === 'usdt') { address = addressInput ? addressInput.value.trim() : ''; if (!address || !address.startsWith('0x') || address.length !== 42) { safePopup({title:'โŒ Error', message:'Please enter a valid Polygon wallet address.', buttons:[{type:'ok'}]}); return; } if (address.toLowerCase() === PROJECT_WALLET.toLowerCase()) { safePopup({title:'โŒ Invalid Wallet', message:'Cannot withdraw to project wallet.', buttons:[{type:'ok'}]}); return; } } else if (currency === 'bep20') { address = bep20Input ? bep20Input.value.trim() : ''; if (!address || !address.startsWith('0x') || address.length !== 42) { safePopup({title:'โŒ Error', message:'Please enter a valid BNB Chain (BEP20) wallet address.', buttons:[{type:'ok'}]}); return; } if (address.toLowerCase() === PROJECT_WALLET.toLowerCase()) { safePopup({title:'โŒ Invalid Wallet', message:'Cannot withdraw to project wallet.', buttons:[{type:'ok'}]}); return; } } else { address = gramInput ? gramInput.value.trim() : ''; if (!isValidTonAddress(address)) { safePopup({title:'โŒ Error', message:'Please enter a valid TON wallet address.', buttons:[{type:'ok'}]}); return; } } if (!amount || amount < 1) { safePopup({title:'โŒ Error', message:'Please enter at least $1 USDT.', buttons:[{type:'ok'}]}); return; } if (submitBtn) { submitBtn.disabled = true; submitBtn.textContent = 'โณ Processing...'; } fetch(API_BASE + '/api/withdraw', { method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({ telegram_id: userId, amount: parseFloat(amount), address: address, currency: currency }) }) .then(function(response) { return response.json(); }) .then(function(data) { if (data.success) { safePopup({title:'โœ… Success!', message:data.message || 'Withdrawal submitted!', buttons:[{type:'ok'}]}); if (amountInput) amountInput.value = ''; if (addressInput) addressInput.value = ''; if (bep20Input) bep20Input.value = ''; if (gramInput) gramInput.value = ''; } else { if (data.cooldown_remaining) safePopup({title:'โณ Cooldown Active', message:data.message, buttons:[{type:'ok'}]}); else safePopup({title:'โŒ Error', message:data.message || 'Withdrawal failed.', buttons:[{type:'ok'}]}); } }) .catch(function(error) { safePopup({title:'โŒ Error', message:'Network error.', buttons:[{type:'ok'}]}); }) .finally(function() { setTimeout(function() { if (submitBtn) { submitBtn.disabled = false; submitBtn.textContent = 'Withdraw Full Balance'; } }, 3000); }); }); } } async function canWatchAd() { return true; } async function watchRewardedAd() { if (window._isBanned) return false; if (!window.showRewardedAd) { safePopup({ title: 'โŒ Ad Not Available', message: 'No ads available right now.', buttons: [{type: 'ok'}] }); return false; } try { const result = await window.showRewardedAd(); if (result.done && !result.error && result.state === 'destroy') { const captcha = generateMathCaptcha(); const userAnswer = prompt(`๐Ÿงฎ Verify You're Human\n\n${captcha.question}\n\nEnter your answer:`); if (userAnswer === null) return false; const parsed = parseInt(userAnswer); if (isNaN(parsed) || parsed !== captcha.answer) { safePopup({ title: 'โŒ Wrong Answer', message: 'Incorrect. Please try again.', buttons: [{type: 'ok'}] }); return false; } const userId = tgUser ? tgUser.id : '0'; const fingerprint = getDeviceFingerprint(); try { const response = await fetch(API_BASE + '/api/credit_ad_reward', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ telegram_id: userId, captcha_answer: captcha.answer, captcha_question: captcha.question, device_fingerprint: fingerprint }) }); const data = await response.json(); if (data.success) { loadAdStats(); loadUserData(); safePopup({ title: 'โœ… Ad Watched!', message: 'Thanks for supporting the community giveaway! ๐ŸŽ\n\nYour ad helps fund the weekly prize pool. Winners announced every Friday.', buttons: [{type: 'ok'}] }); setTimeout(() => { loadTasks(); loadReferralProgress(); }, 2000); return true; } else if (data.need_captcha) { safePopup({ title: '๐Ÿงฎ Verification Required', message: data.message || 'Please solve the math question.', buttons: [{type: 'ok'}] }); return false; } else { safePopup({ title: 'โŒ Error', message: data.message || 'Failed to process ad.', buttons: [{type: 'ok'}] }); return false; } } catch (error) { safePopup({ title: 'โŒ Error', message: 'Network error.', buttons: [{type: 'ok'}] }); return false; } } else { safePopup({ title: 'โŒ Ad Not Available', message: 'No ads available right now.', buttons: [{type: 'ok'}] }); return false; } } catch (error) { safePopup({ title: 'โŒ Error', message: 'Network error.', buttons: [{type: 'ok'}] }); return false; } } async function loadAdStats() { if (window._isBanned) return; const userId = tgUser ? tgUser.id : '0'; try { const response = await fetch(API_BASE + '/api/user?telegram_id=' + userId + '&t=' + Date.now()); const userData = await response.json(); if (!userData.success) return; const totalAds = userData.total_ads_watched || 0; const adsTodayEl = document.getElementById('adsToday'); if (adsTodayEl) adsTodayEl.textContent = String(totalAds); const watchBtn = document.getElementById('watchAdBtn'); if (watchBtn) { watchBtn.disabled = false; watchBtn.textContent = 'โ–ถ๏ธ Watch Ad โ€” Support Giveaways'; } updateGiveawayProgress(userData); } catch (error) {} } async function upgradeReferralTier(tier) { if (window._isBanned) return; showInterstitialIfNeeded(); const userId = tgUser ? tgUser.id : '0'; if (!userId || userId === '0') { safePopup({ title: 'โŒ Error', message: 'User not authenticated.', buttons: [{type: 'ok'}] }); return; } safePopupWithCallback({ title: '๐Ÿ“Š Upgrade Referral Tier', message: 'Upgrade to ' + tier.toUpperCase() + ' tier?\n\nPERMANENT upgrade. No refunds.', buttons: [{id:'cancel',type:'cancel'},{id:'confirm',type:'ok',text:'โœ… Upgrade'}] }, async function(buttonId) { if (buttonId === 'confirm') { try { const response = await fetch(API_BASE + '/api/upgrade_tier', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ telegram_id: userId, tier: tier }) }); const data = await response.json(); if (data.success) { safePopup({ title: 'โœ… Upgrade Successful!', message: data.message + '\n\nNew balance: $' + data.new_balance.toFixed(2), buttons: [{type: 'ok'}] }); setTimeout(function() { loadUserData(); }, 1000); } else { safePopup({ title: 'โŒ Error', message: data.message || 'Upgrade failed.', buttons: [{type: 'ok'}] }); } } catch (error) { safePopup({ title: 'โŒ Error', message: 'Network error.', buttons: [{type: 'ok'}] }); } } }); } async function claimWelcomeBonus() { if (window._isBanned) return; const userId = tgUser ? tgUser.id : '0'; safePopupWithCallback({ title: '๐ŸŽ Welcome Bonus', message: 'Claim 0.1 USDT as a welcome bonus!\n\nNo requirements โ€” everyone can claim! ๐ŸŽ‰', buttons: [{id: 'cancel', type: 'cancel'}, {id: 'claim', type: 'ok', text: '๐ŸŽ Claim'}] }, async function(buttonId) { if (buttonId === 'claim') { try { const response = await fetch(`${API_BASE}/api/claim_welcome_bonus`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ telegram_id: userId }) }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); if (errorData.message && errorData.message.toLowerCase().includes('already claimed')) { safePopup({ title: 'โœ… Already Claimed', message: 'You have already claimed your welcome bonus!', buttons: [{type: 'ok'}] }); loadUserData(); loadTasks(); loadReferralProgress(); return; } safePopup({ title: 'โŒ Error', message: errorData.message || 'Something went wrong.', buttons: [{type: 'ok'}] }); return; } const data = await response.json(); if (data.success === false && data.message && data.message.toLowerCase().includes('already claimed')) { safePopup({ title: 'โœ… Already Claimed', message: 'You have already claimed your welcome bonus!', buttons: [{type: 'ok'}] }); loadUserData(); loadTasks(); loadReferralProgress(); return; } if (data.success) { safePopup({ title: '๐ŸŽ‰ Bonus Claimed!', message: data.message + '\n\nNew balance: $' + data.new_balance.toFixed(2), buttons: [{type: 'ok'}] }); loadUserData(); loadTasks(); loadReferralProgress(); } else { safePopup({ title: 'โŒ Error', message: data.message || 'Failed to claim bonus.', buttons: [{type: 'ok'}] }); } } catch (error) { console.error('Error claiming bonus:', error); try { await loadUserData(); const userData = await fetch(`${API_BASE}/api/user?telegram_id=${userId}`).then(r => r.json()); if (userData.success && userData.has_received_welcome_bonus) { safePopup({ title: 'โœ… Bonus Claimed!', message: 'Your welcome bonus has been credited! ๐Ÿ’ฐ', buttons: [{type: 'ok'}] }); loadUserData(); loadTasks(); loadReferralProgress(); return; } } catch (e) {} safePopup({ title: 'โŒ Error', message: 'Network error.', buttons: [{type: 'ok'}] }); } } }); } async function disableInterstitialAds() { if (window._isBanned) return; const userId = tgUser ? tgUser.id : '0'; safePopupWithCallback({ title: '๐Ÿ”‡ Disable Ads', message: 'Pay $4 USDT to reduce pop-up ads on button clicks.\n\nYou will still be able to watch rewarded ads.', buttons: [{id: 'cancel', type: 'cancel'}, {id: 'confirm', type: 'ok', text: 'โœ… Pay $4'}] }, async function(buttonId) { if (buttonId === 'confirm') { try { const response = await fetch(`${API_BASE}/api/disable_interstitial_ads`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ telegram_id: userId }) }); const data = await response.json(); if (data.success) { safePopup({ title: 'โœ… Ads Reduced!', message: data.message, buttons: [{type: 'ok'}] }); const disableBtn = document.getElementById('disableAdsBtn'); if (disableBtn) { disableBtn.textContent = 'โœ… Ads Disabled'; disableBtn.disabled = true; disableBtn.style.opacity = '0.5'; } interstitialAdsDisabled = true; loadUserData(); } else { safePopup({ title: 'โŒ Error', message: data.message || 'Failed to disable ads.', buttons: [{type: 'ok'}] }); } } catch (error) { safePopup({ title: 'โŒ Error', message: 'Network error.', buttons: [{type: 'ok'}] }); } } }); } // ============================================ // TASKS โ€” all tasks visible (including claimed) // ============================================ async function loadTasks() { if (window._isBanned) return; const userId = tgUser ? tgUser.id : '0'; try { const response = await fetch(`${API_BASE}/api/tasks/${userId}?t=${Date.now()}`); const data = await response.json(); if (!data.success) return; const tasksEl = document.getElementById('tasksList'); if (!tasksEl) return; if (data.newly_completed && data.newly_completed.length > 0) { const names = data.newly_completed.map(id => { const t = data.tasks.find(x => x.task_id === id); return t ? t.title : ''; }).filter(Boolean); if (names.length > 0) { safePopup({ title: '๐ŸŽ‰ Tasks Completed!', message: 'You completed:\nโ€ข ' + names.join('\nโ€ข ') + '\n\nGo to Tasks to claim!', buttons: [{type: 'ok'}] }); } } const allTasks = data.tasks.slice(); const userStats = data.user_stats || {}; function renderTask(task, hide) { const isCompleted = task.completed; const isClaimed = task.claimed; const conditionValue = getTaskConditionValue(task.task_id); const currentValue = getTaskCurrentValue(task.task_id, userStats); let progressText = ''; let progressPercent = 0; if (task.category !== 'community') { if (!isCompleted && conditionValue !== null && currentValue !== null) { if (task.category === 'milestones') { progressText = `${Number(Math.min(currentValue, conditionValue)).toFixed(3)}/${conditionValue}`; } else { progressText = `${Math.round(Number(currentValue))}/${conditionValue}`; } progressPercent = Math.min((Number(currentValue) / conditionValue) * 100, 100); } else if (isCompleted) { const max = conditionValue || 1; progressText = `${max}/${max}`; progressPercent = 100; } } const statusBadge = isClaimed ? 'โœ… Claimed' : (isCompleted ? 'Claim Now!' : (progressText ? `โณ ${progressText}` : '')); const statusColor = isClaimed ? '#00ff87' : (isCompleted ? '#00ff87' : '#495670'); const rewardDisplay = task.reward < 0.01 ? '0.00' : Number(task.reward).toFixed(2); const hideStyle = hide ? 'style="display:none;"' : ''; let actionButton = ''; if (isClaimed) { actionButton = ''; } else if (task.category === 'community') { actionButton = ``; } else if (isCompleted) { actionButton = ``; } return `
${task.icon || '๐Ÿ“Œ'}
${task.title}
${task.description}
๐Ÿ’ฐ ${rewardDisplay} USDT
${!isCompleted && !isClaimed && progressText ? `
` : ''}
${statusBadge}
${actionButton}
`; } let html = ''; const cats = { 'investments': { icon: '๐ŸŒฑ', label: 'Investments' }, 'community': { icon: '๐Ÿ“ข', label: 'Community' }, 'milestones': { icon: '๐Ÿ†', label: 'Milestones' } }; ['investments','community','milestones'].forEach(cat => { const items = allTasks.filter(t => t.category === cat).sort((a,b)=>a.task_id-b.task_id); if (items.length === 0) return; html += `
${cats[cat].icon} ${cats[cat].label}
`; if (cat === 'milestones') { let shown = 0, hidden = 0; items.forEach(t => { const shouldHide = !t.completed && !t.claimed && shown >= 3; if (shouldHide) hidden++; else shown++; html += renderTask(t, shouldHide); }); if (hidden > 0) { html += ``; } } else { items.forEach(t => { html += renderTask(t, false); }); } }); if (allTasks.length === 0) { html = `
๐ŸŽ‰
No tasks available
`; } tasksEl.innerHTML = html; const progressEl = document.getElementById('taskProgress'); if (progressEl) { const total = data.stats.total_tasks || 0; const done = data.stats.completed_tasks || 0; progressEl.textContent = `${done}/${total} tasks completed`; progressEl.style.color = done === total ? '#00ff87' : '#ccd6f0'; } } catch (error) { console.error('loadTasks error:', error); } } function openCommunityLink(taskId) { if (window._isBanned) return; const communityLinks = { 27: 'https://t.me/PlantUSDTchannel', 28: 'https://t.me/PlantUSDT', 29: 'https://t.me/PlantUSDTtransactions' }; const link = communityLinks[taskId]; if (!link) return; showInterstitialIfNeeded(); safePopupWithCallback({ title: '๐Ÿ“ข Join Community', message: 'Join our ' + (taskId === 27 ? 'channel' : taskId === 28 ? 'group' : 'transactions channel') + '?\n\nAfter joining, come back and click Claim to receive 0.02 USDT.', buttons: [{id:'cancel',type:'cancel'},{id:'join',type:'ok',text:'๐Ÿ”— Join Now'}] }, function(buttonId) { if (buttonId === 'join') { if (typeof tg !== 'undefined' && tg.openTelegramLink) { tg.openTelegramLink(link); } else { window.open(link, '_blank'); } setTimeout(function() { safePopupWithCallback({ title: 'โœ… Joined?', message: 'Did you join? Click Yes to claim your 0.02 USDT reward.', buttons: [{id:'no',type:'cancel',text:'Not yet'},{id:'yes',type:'ok',text:'โœ… Yes, Claim'}] }, function(buttonId2) { if (buttonId2 === 'yes') { claimTaskReward(taskId); } }); }, 3000); } }); } function showMoreTasks(category) { if (window._isBanned) return; const taskItems = document.querySelectorAll(`.task-item[data-category="${category}"]`); const button = document.querySelector(`button[onclick*="showMoreTasks('${category}')"]`); if (button) button.style.display = 'none'; taskItems.forEach(item => { if (item.style.display === 'none' || !item.style.display) { item.style.display = 'block'; item.style.animation = 'fadeIn 0.3s ease'; } }); } function getTaskConditionValue(taskId) { const taskConditions = {1:1,2:10,3:50,4:100,5:200,6:500,7:1000,37:1,38:10,39:25,40:50,41:100,42:250,43:500,44:1000}; return taskConditions[taskId] || null; } function getTaskCurrentValue(taskId, userStats) { const taskCurrentValues = { 1: userStats.has_invested ? 1 : 0, 2: Number(userStats.total_invested) || 0, 3: Number(userStats.total_invested) || 0, 4: Number(userStats.total_invested) || 0, 5: Number(userStats.total_invested) || 0, 6: Number(userStats.total_invested) || 0, 7: Number(userStats.total_invested) || 0, 37: Number(userStats.total_earnings) || 0, 38: Number(userStats.total_earnings) || 0, 39: Number(userStats.total_earnings) || 0, 40: Number(userStats.total_earnings) || 0, 41: Number(userStats.total_earnings) || 0, 42: Number(userStats.total_earnings) || 0, 43: Number(userStats.total_earnings) || 0, 44: Number(userStats.total_earnings) || 0 }; const value = taskCurrentValues[taskId]; return typeof value === 'number' ? value : 0; } async function claimTaskReward(taskId) { if (window._isBanned) return; const userId = tgUser ? tgUser.id : '0'; if (window.claimingInProgress) return; safePopupWithCallback({ title: '๐Ÿ’ฐ Claim Reward', message: 'Claim your reward for completing this task?', buttons: [{id:'cancel',type:'cancel'},{id:'confirm',type:'ok',text:'๐Ÿ’ฐ Claim'}] }, async function(buttonId) { if (buttonId === 'confirm') { window.claimingInProgress = true; try { const response = await fetch(`${API_BASE}/api/claim_task_reward`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ telegram_id: userId, task_id: taskId }) }); const data = await response.json(); if (data.success === false && data.message === "Task not found") { safePopup({ title: 'โœ… Already Claimed!', message: 'This task was already claimed.', buttons: [{type: 'ok'}] }); loadTasks(); loadUserData(); window.claimingInProgress = false; return; } if (data.success) { const reward = parseFloat(data.message.match(/\d+\.?\d*/)?.[0] || '0'); const rewardDisplay = reward < 0.01 ? '0.00' : reward.toFixed(2); safePopup({ title: '๐ŸŽ‰ Reward Claimed!', message: 'Claimed $' + rewardDisplay + ' USDT!\n\nNew balance: $' + data.new_balance.toFixed(2), buttons: [{type: 'ok'}] }); loadTasks(); loadUserData(); } else { safePopup({ title: 'โŒ Error', message: data.message || 'Failed to claim reward.', buttons: [{type: 'ok'}] }); } } catch (error) { safePopup({ title: 'โ„น๏ธ Check Your Balance', message: 'Please refresh to see if your reward was credited.', buttons: [{type: 'ok'}] }); loadTasks(); loadUserData(); } finally { window.claimingInProgress = false; } } }); } let referralListExpanded = false; async function loadReferralProgress() { if (window._isBanned) return; const userId = tgUser ? tgUser.id : '0'; try { const response = await fetch(`${API_BASE}/api/get_referral_progress/${userId}`); const data = await response.json(); const container = document.getElementById('referralProgressTable'); const showMoreBtn = document.getElementById('showMoreReferralsBtn'); if (!container) return; if (!data.success) { container.innerHTML = 'No eligible referrals yet.'; return; } const referrals = data.referrals || []; if (referrals.length === 0) { container.innerHTML = 'No eligible referrals yet.'; return; } const showCount = referralListExpanded ? referrals.length : 5; const visible = referrals.slice(0, showCount); const hasMore = referrals.length > 5; let html = ''; visible.forEach(ref => { const walletStatus = ref.wallet_connected ? 'โœ…' : 'โŒ'; const adsStatus = ref.ads_watched >= 3 ? 'โœ… 3/3' : `${ref.ads_watched}/3`; const rewardStatus = ref.reward_claimed ? 'โœ… Claimed' : 'โณ Pending'; const statusColor = ref.reward_claimed ? '#00ff87' : '#ffd93d'; html += `${ref.username}${walletStatus}${adsStatus}${rewardStatus}`; }); container.innerHTML = html; if (showMoreBtn) { if (hasMore) { showMoreBtn.style.display = 'block'; showMoreBtn.textContent = referralListExpanded ? '๐Ÿ”ผ Show less' : `๐Ÿ“‹ Show all ${referrals.length} โ†’`; } else { showMoreBtn.style.display = 'none'; } } } catch (error) { const container = document.getElementById('referralProgressTable'); if (container) container.innerHTML = 'Error loading referral progress.'; } } function toggleReferralList() { referralListExpanded = !referralListExpanded; loadReferralProgress(); } window.navigateTo = navigateTo; window.goBack = goBack; window.refreshData = refreshData; window.copyAddress = copyAddress; window.copyReferral = copyReferral; window.claimReferralRewards = claimReferralRewards; window.checkDeposit = checkDeposit; window.checkDepositWithAmount = checkDepositWithAmount; window.investField = investField; window.investFieldWithLock = investFieldWithLock; window.filterHistory = filterHistory; window.saveWallet = saveWallet; window.disconnectWallet = disconnectWallet; window.setWallet = setWallet; window.watchRewardedAd = watchRewardedAd; window.canWatchAd = canWatchAd; window.loadAdStats = loadAdStats; window.claimInvestment = claimInvestment; window.showInterstitialIfNeeded = showInterstitialIfNeeded; window.upgradeReferralTier = upgradeReferralTier; window.claimWelcomeBonus = claimWelcomeBonus; window.disableInterstitialAds = disableInterstitialAds; window.loadTasks = loadTasks; window.claimTaskReward = claimTaskReward; window.showMoreTasks = showMoreTasks; window.openCommunityLink = openCommunityLink; window.loadReferralProgress = loadReferralProgress; window.toggleReferralList = toggleReferralList; window.selectCurrency = selectCurrency; window.isValidTonAddress = isValidTonAddress; window.showBanScreen = showBanScreen; window.updateGiveawayProgress = updateGiveawayProgress; window.startGiveawayTimer = startGiveawayTimer; window.tickGiveawayTimer = tickGiveawayTimer; window.switchTab = switchTab; console.log('โœ… PlantUSDT app loaded successfully (v92)'); console.log('๐Ÿ“‰ Investment returns: 1% / 8% / 35% (old investments unaffected)'); console.log('๐Ÿ’ธ Withdrawal fees: 8% / 10% / 12%'); console.log('๐Ÿ›ก๏ธ Fingerprint fixed: no more false flags on OS updates'); console.log('๐ŸŸก BEP20 withdrawals live โ€” 3 currency options (Polygon / BEP20 / GRAM)'); console.log('๐Ÿ  Always starts on Home tab (no restore of last tab)'); console.log('๐Ÿ”‡ switchTab silent on non-tabbed pages'); console.log('๐Ÿ›ก๏ธ Safety fallback active โ€” if app.js fails, all sections show'); console.log('๐Ÿ“ฑ Bottom nav active: 5 tabs (Home / Tasks / Giveaway / Referrals / Profile)'); console.log('๐Ÿ“ข Welcome bonus: 0.1 USDT โ€” button removed after claiming'); console.log('๐ŸŽ Referral reward: $0.005 pending until claimed'); console.log('๐Ÿ’ฐ Available Earnings button: shows unclaimed referral rewards'); console.log('๐Ÿ”ฅ Active Referrals tracked silently for ambassador promotion'); console.log('๐Ÿ“บ Ads fund weekly community giveaways โ€” no per-ad reward'); console.log('โ™พ๏ธ Ads have no limits โ€” watch as many as you like'); console.log('๐Ÿ“Š Ads stat shows Total Ads Watched (from API total_ads_watched)'); console.log('๐ŸŽ Giveaway progress bar: X / 150 ads this cycle'); console.log('๐Ÿ† Gold bar + QUALIFIED badge when 150+ ads watched'); console.log('โณ Live countdown timer shows time until next Friday 00:00 UTC'); console.log('๐Ÿ“… Timer auto-updates every second via setInterval'); console.log('๐Ÿ“ข Community tasks: Join Channel, Group, Transactions (0.02 each)'); console.log('๐Ÿ“ข Tasks: all tasks visible including claimed (with โœ… tick)'); console.log('๐Ÿšซ Ban system active โ€” banned users see suspension notice'); console.log('๐Ÿ“Š Task rewards display 2 decimals'); console.log('๐Ÿ”’ Duplicate wallet protection active'); console.log('๐ŸŽฏ Math captcha accepts 0 as valid answer'); console.log('๐Ÿ“‹ Referral table shows only eligible referrals (wallet + 3 ads)'); console.log('โœ… Claimed tasks now stay visible with โœ… tick (not hidden)'); console.log('๐Ÿ“ˆ total_ads_watched added to /api/user response'); console.log('๐ŸŽ ads_watched_this_cycle added for giveaway progress'); console.log('๐Ÿ”™ goBack() fallback added โ€” falls back to index.html if no history');