/* .SOL DOMAINS — Solana Name Service Lookup & Registration */ const SNS_API = 'https://sns-sdk-proxy.bonfida.workers.dev'; const SNS_REG = 'https://www.sns.id/domain/'; const SOLSCAN = 'https://solscan.io/account/'; const REFERRAL_WALLET = '9NuiHh5wgRPx69BFGP1ZR8kHiBENGoJrXs5GpZzKAyn8'; let walletAddress = null; let currentTab = 'search'; // ─── DOM ──────────────────────────────────────────────────── const $ = s => document.querySelector(s); const $$ = s => document.querySelectorAll(s); document.addEventListener('DOMContentLoaded', () => { initTabs(); initSearch(); initWallet(); }); // ─── TABS ─────────────────────────────────────────────────── function initTabs() { $$('.sol-tab').forEach(tab => { tab.addEventListener('click', () => { const t = tab.dataset.tab; switchTab(t); }); }); } function switchTab(t) { currentTab = t; $$('.sol-tab').forEach(tab => tab.classList.toggle('active', tab.dataset.tab === t)); $$('.sol-panel').forEach(p => p.classList.toggle('hidden', p.id !== `panel-${t}`)); if (t === 'mydomains' && walletAddress) loadMyDomains(); } // ─── SEARCH / LOOKUP ──────────────────────────────────────── function initSearch() { const input = $('#sol-search'); const btn = $('#sol-search-go'); if (!input || !btn) return; btn.addEventListener('click', () => doSearch()); input.addEventListener('keydown', e => { if (e.key === 'Enter') doSearch(); }); const revInput = $('#sol-reverse'); const revBtn = $('#sol-reverse-go'); if (revInput && revBtn) { revBtn.addEventListener('click', () => doReverse()); revInput.addEventListener('keydown', e => { if (e.key === 'Enter') doReverse(); }); } } async function doSearch() { const raw = $('#sol-search').value.trim().toLowerCase(); if (!raw) return; const domain = raw.replace(/\.sol$/i, ''); const results = $('#search-results'); results.innerHTML = loadingHTML('RESOLVING DOMAIN...'); try { const res = await fetch(`${SNS_API}/resolve/${domain}`); const data = await res.json(); if (data.s === 'ok' && data.result) { await showTakenDomain(domain, data.result); } else { showAvailableDomain(domain); } } catch (err) { results.innerHTML = errorHTML(`Network error: ${err.message}`); } } async function showTakenDomain(domain, owner) { const results = $('#search-results'); let favourite = null; try { const favRes = await fetch(`${SNS_API}/favourite-domain/${owner}`); const favData = await favRes.json(); if (favData.s === 'ok') favourite = favData.result || null; } catch(e) {} results.innerHTML = `
${esc(domain)}.sol
REGISTERED
${favourite ? `
OWNER'S FAVOURITE
${esc(favourite)}.sol
` : ''}
`; } function showAvailableDomain(domain) { const results = $('#search-results'); const len = domain.length; let priceEstimate = ''; if (len <= 1) priceEstimate = '~750 USDC'; else if (len === 2) priceEstimate = '~700 USDC'; else if (len === 3) priceEstimate = '~640 USDC'; else if (len === 4) priceEstimate = '~160 USDC'; else priceEstimate = '~20 USDC'; const regUrl = `${SNS_REG}${encodeURIComponent(domain)}?ref=${REFERRAL_WALLET}`; results.innerHTML = `
${esc(domain)}.sol
AVAILABLE
LENGTH
${len} character${len !== 1 ? 's' : ''}
ESTIMATED COST
${priceEstimate.split(' ')[0].replace('~','')} ${priceEstimate.split(' ')[1] || 'USDC'} (estimated)
REGISTRATION
Purchase your .sol domain
REGISTER ${esc(domain.toUpperCase())}.SOL ↗
`; } // ─── REVERSE LOOKUP ───────────────────────────────────────── async function doReverse() { const addr = $('#sol-reverse').value.trim(); if (!addr) return; const results = $('#reverse-results'); results.innerHTML = loadingHTML('SCANNING WALLET...'); try { const res = await fetch(`${SNS_API}/domains/${addr}`); const data = await res.json(); // Normalise response to array — API may return various formats let domains = []; if (Array.isArray(data)) { domains = data; } else if (data && typeof data === 'object') { if (Array.isArray(data.result)) { domains = data.result; } else if (typeof data.result === 'string') { domains = [data.result]; } else if (data.result && typeof data.result === 'object' && !Array.isArray(data.result)) { // Single domain object domains = [data.result]; } } if (!domains || domains.length === 0) { results.innerHTML = `
NO .SOL DOMAINS FOUND FOR THIS WALLET
`; return; } let favourite = null; try { const favRes = await fetch(`${SNS_API}/favourite-domain/${addr}`); const favData = await favRes.json(); if (favData.s === 'ok') favourite = favData.result || null; } catch(e) {} results.innerHTML = `
DOMAINS: ${domains.length}
${favourite ? `
FAVOURITE: ${favourite}.sol
` : ''}
WALLET: ${truncAddr(addr)}
${domains.map(d => { const name = typeof d === 'string' ? d : (d.domain || d.name || String(d)); const isFav = favourite && name === favourite; return `
${esc(name)}.sol
${isFav ? '
★ FAVOURITE
' : ''}
`; }).join('')}
`; } catch(err) { results.innerHTML = errorHTML(`Network error: ${err.message}`); } } // ─── WALLET ───────────────────────────────────────────────── let connectedProvider = null; const WALLETS = [ { name: 'PHANTOM', icon: '👻', detect: () => { const p = window.phantom?.solana; return (p && p.isPhantom) ? p : null; }, url: 'https://phantom.app' }, { name: 'JUPITER', icon: '🪐', detect: () => { if (window.jupiter?.solana) return window.jupiter.solana; if (window.solana?.isJupiter) return window.solana; return null; }, url: 'https://jup.ag' }, { name: 'SOLFLARE', icon: '🔆', detect: () => { const s = window.solflare; return (s && s.isSolflare) ? s : null; }, url: 'https://solflare.com' }, { name: 'BACKPACK', icon: '🎒', detect: () => { const b = window.backpack; return (b && b.isBackpack) ? b : null; }, url: 'https://backpack.app' }, { name: 'COINBASE', icon: '🔵', detect: () => window.coinbaseSolana || null, url: 'https://coinbase.com/wallet' }, { name: 'TRUST', icon: '🛡️', detect: () => window.trustwallet?.solana || null, url: 'https://trustwallet.com' }, { name: 'METAMASK', icon: '🦊', detect: () => { // MetaMask Solana injects at window.solana with isMetaMask if (window.solana?.isMetaMask) return window.solana; // Or check ethereum provider flags if (window.ethereum?.isMetaMask && window.ethereum?.solana) return window.ethereum.solana; return null; }, url: 'https://metamask.io' }, ]; function getAvailableWallets() { const available = []; const matchedProviders = new Set(); for (const w of WALLETS) { try { const provider = w.detect(); if (provider && !matchedProviders.has(provider)) { available.push({ ...w, provider }); matchedProviders.add(provider); } } catch(e) {} } // Generic fallback: window.solana if nothing matched if (available.length === 0 && window.solana) { available.push({ name: 'SOLANA WALLET', icon: '◈', provider: window.solana, url: '#' }); } return available; } function initWallet() { const btn = $('#wallet-btn'); if (!btn) return; btn.addEventListener('click', toggleWallet); createWalletModal(); } function createWalletModal() { const modal = document.createElement('div'); modal.id = 'wallet-modal'; modal.className = 'sol-modal hidden'; modal.innerHTML = `
SELECT WALLET
`; document.body.appendChild(modal); modal.querySelector('.sol-modal-backdrop').addEventListener('click', closeModal); modal.querySelector('#modal-close').addEventListener('click', closeModal); } function openModal() { const modal = $('#wallet-modal'); const list = $('#wallet-list'); const available = getAvailableWallets(); const detectedNames = new Set(available.map(w => w.name)); let html = ''; // Show detected wallets as clickable buttons if (available.length > 0) { html += '
DETECTED
'; html += available.map(w => ` `).join(''); } // Show not-installed wallets as links (exclude detected ones) const notInstalled = WALLETS.filter(w => !detectedNames.has(w.name)); if (notInstalled.length > 0) { html += '
NOT INSTALLED
'; html += notInstalled.map(w => ` ${w.icon} ${w.name} INSTALL ↗ `).join(''); } if (available.length === 0) { html = '
NO SOLANA WALLETS DETECTED

Install a Solana wallet extension to connect.
'; } list.innerHTML = html; // Bind click handlers only for detected wallets (buttons, not links) list.querySelectorAll('.sol-wallet-option.detected').forEach(btn => { btn.addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); const name = btn.dataset.wallet; const wallet = available.find(w => w.name === name); if (wallet) connectWallet(wallet); }); }); modal.classList.remove('hidden'); } function closeModal() { const modal = $('#wallet-modal'); if (modal) modal.classList.add('hidden'); } async function toggleWallet() { if (walletAddress) { disconnectWallet(); return; } openModal(); } async function connectWallet(wallet) { try { closeModal(); const resp = await wallet.provider.connect(); walletAddress = resp.publicKey.toString(); connectedProvider = wallet; updateWalletUI(); } catch(err) { console.error('Wallet connection failed:', err); const status = $('#wallet-status'); if (status) status.innerHTML = `CONNECTION REJECTED`; } } function disconnectWallet() { if (connectedProvider && connectedProvider.provider) { try { connectedProvider.provider.disconnect(); } catch(e) {} } walletAddress = null; connectedProvider = null; updateWalletUI(); } function updateWalletUI() { const status = $('#wallet-status'); const btn = $('#wallet-btn'); if (walletAddress) { const wName = connectedProvider ? connectedProvider.name : 'WALLET'; const wIcon = connectedProvider ? connectedProvider.icon : '◈'; status.className = 'sol-wallet-status connected'; status.innerHTML = `● CONNECTED VIA ${wIcon} ${wName} ${truncAddr(walletAddress)}`; btn.className = 'sol-wallet-btn disconnect'; btn.textContent = 'DISCONNECT'; } else { status.className = 'sol-wallet-status'; status.innerHTML = '○ NOT CONNECTED'; btn.className = 'sol-wallet-btn'; btn.textContent = 'CONNECT WALLET'; const panel = $('#mydomains-content'); if (panel) panel.innerHTML = `
CONNECT WALLET TO VIEW YOUR DOMAINS
`; } } // ─── MY DOMAINS ───────────────────────────────────────────── async function loadMyDomains() { if (!walletAddress) return; const content = $('#mydomains-content'); content.innerHTML = loadingHTML('LOADING YOUR DOMAINS...'); try { const res = await fetch(`${SNS_API}/domains/${walletAddress}`); const data = await res.json(); // Normalise to array let domains = []; if (Array.isArray(data)) { domains = data; } else if (data && typeof data === 'object') { if (Array.isArray(data.result)) { domains = data.result; } else if (typeof data.result === 'string') { domains = [data.result]; } else if (data.result && typeof data.result === 'object') { domains = [data.result]; } } let favourite = null; try { const favRes = await fetch(`${SNS_API}/favourite-domain/${walletAddress}`); const favData = await favRes.json(); if (favData.s === 'ok') favourite = favData.result || null; } catch(e) {} if (!domains || domains.length === 0) { const regUrl = `${SNS_REG}?ref=${REFERRAL_WALLET}`; content.innerHTML = `
NO .SOL DOMAINS FOUND
Register one on SNS.id ↗
`; return; } content.innerHTML = `
YOUR DOMAINS: ${domains.length}
${favourite ? `
FAVOURITE: ${favourite}.sol
` : ''}
${domains.map(d => { const name = typeof d === 'string' ? d : (d.domain || d.name || String(d)); const isFav = favourite && name === favourite; return `
${esc(name)}.sol
${isFav ? '
★ FAVOURITE
' : ''}
`; }).join('')}
`; } catch(err) { content.innerHTML = errorHTML(`Network error: ${err.message}`); } } // ─── HELPERS ──────────────────────────────────────────────── function truncAddr(a) { if (!a || a.length < 12) return a; return a.slice(0, 6) + '...' + a.slice(-4); } function esc(s) { const d = document.createElement('div'); d.textContent = s; return d.innerHTML; } function loadingHTML(msg) { return `
${msg}
`; } function errorHTML(msg) { return `
ERROR // ${msg}
`; }