/* .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; // ── Wallet Standard Discovery ── // MetaMask Solana and modern wallets register via the Wallet Standard protocol const walletStandardWallets = []; let walletStandardReady = false; function initWalletStandard() { // Listen for wallets that register AFTER us window.addEventListener('wallet-standard:register-wallet', (event) => { try { const callback = event.detail; if (typeof callback === 'function') { callback({ register: (...wallets) => { for (const w of wallets) { if (!walletStandardWallets.some(existing => existing.name === w.name)) { walletStandardWallets.push(w); } } } }); } } catch(e) { console.warn('WS register error:', e); } }); // Announce that the app is ready — catches wallets that loaded BEFORE us try { const appReadyEvent = new CustomEvent('wallet-standard:app-ready', { detail: { register: (...wallets) => { for (const w of wallets) { if (!walletStandardWallets.some(existing => existing.name === w.name)) { walletStandardWallets.push(w); } } } } }); window.dispatchEvent(appReadyEvent); } catch(e) { console.warn('WS app-ready error:', e); } walletStandardReady = true; } // Initialise Wallet Standard immediately initWalletStandard(); function getAvailableWallets() { const found = []; const seen = new Set(); function add(name, icon, provider, url, isWalletStandard) { if (!provider || seen.has(name)) return; seen.add(name); found.push({ name, icon, provider, url, isWalletStandard: !!isWalletStandard }); } // ── 1. Wallet Standard wallets (MetaMask Solana, etc.) ── for (const w of walletStandardWallets) { try { const hasConnect = w.features?.['standard:connect']; if (!hasConnect) continue; const name = (w.name || 'WALLET').toUpperCase(); // Use wallet's icon (base64 data URI) or fallback emoji let icon = '◈'; if (name.includes('METAMASK')) icon = '🦊'; else if (name.includes('PHANTOM')) icon = '👻'; else if (name.includes('SOLFLARE')) icon = '🔆'; else if (name.includes('BACKPACK')) icon = '🎒'; else if (name.includes('COINBASE')) icon = '🔵'; else if (name.includes('TRUST')) icon = '🛡️'; else if (name.includes('JUPITER')) icon = '🪐'; const url = w.url || '#'; add(name, icon, w, url, true); } catch(e) {} } // ── 2. Legacy injection points ── // Phantom try { const p = window.phantom?.solana; if (p && p.isPhantom) add('PHANTOM', '👻', p, 'https://phantom.app'); } catch(e) {} // Solflare try { const s = window.solflare; if (s && s.isSolflare) add('SOLFLARE', '🔆', s, 'https://solflare.com'); } catch(e) {} // Backpack try { const b = window.backpack; if (b && b.isBackpack) add('BACKPACK', '🎒', b, 'https://backpack.app'); } catch(e) {} // Coinbase try { if (window.coinbaseSolana) add('COINBASE', '🔵', window.coinbaseSolana, 'https://coinbase.com/wallet'); } catch(e) {} // Trust try { const t = window.trustwallet?.solana; if (t) add('TRUST', '🛡️', t, 'https://trustwallet.com'); } catch(e) {} // ── 3. Generic window.solana ── try { const ws = window.solana; if (ws && !seen.has('SOLANA WALLET')) { if (ws.isJupiter && !seen.has('JUPITER')) add('JUPITER', '🪐', ws, 'https://jup.ag'); else if (ws.isMetaMask && !seen.has('METAMASK')) add('METAMASK', '🦊', ws, 'https://metamask.io'); else if (ws.isPhantom && !seen.has('PHANTOM')) { /* skip */ } else if (ws.isSolflare && !seen.has('SOLFLARE')){ /* skip */ } else if (ws.isBackpack && !seen.has('BACKPACK')){ /* skip */ } else if (!seen.has('PHANTOM') && !seen.has('METAMASK')) add('SOLANA WALLET', '◈', ws, '#'); } } catch(e) {} // ── 4. Jupiter specific ── try { const j = window.jupiter?.solana; if (j) add('JUPITER', '🪐', j, 'https://jup.ag'); } catch(e) {} // ── 5. Multi-provider array ── try { const providers = window.solana?.providers; if (Array.isArray(providers)) { for (const p of providers) { if (p.isPhantom) add('PHANTOM', '👻', p, 'https://phantom.app'); else if (p.isJupiter) add('JUPITER', '🪐', p, 'https://jup.ag'); else if (p.isSolflare) add('SOLFLARE', '🔆', p, 'https://solflare.com'); else if (p.isBackpack) add('BACKPACK', '🎒', p, 'https://backpack.app'); else if (p.isMetaMask) add('METAMASK', '🦊', p, 'https://metamask.io'); } } } catch(e) {} return found; } const KNOWN_WALLETS = [ { name: 'PHANTOM', icon: '👻', url: 'https://phantom.app' }, { name: 'JUPITER', icon: '🪐', url: 'https://jup.ag' }, { name: 'SOLFLARE', icon: '🔆', url: 'https://solflare.com' }, { name: 'BACKPACK', icon: '🎒', url: 'https://backpack.app' }, { name: 'COINBASE', icon: '🔵', url: 'https://coinbase.com/wallet' }, { name: 'TRUST', icon: '🛡️', url: 'https://trustwallet.com' }, { name: 'METAMASK', icon: '🦊', url: 'https://metamask.io' }, ]; 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'); // Small delay to let async provider injection complete setTimeout(() => { const available = getAvailableWallets(); const detectedNames = new Set(available.map(w => w.name)); let html = ''; if (available.length > 0) { html += '
DETECTED
'; html += available.map(w => ` `).join(''); } const notInstalled = KNOWN_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.
If you just installed one, refresh the page.
`; } list.innerHTML = html; 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'); }, 150); } 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(); if (wallet.isWalletStandard) { // Wallet Standard connect (MetaMask Solana, etc.) const connectFeature = wallet.provider.features['standard:connect']; const result = await connectFeature.connect(); const accounts = result.accounts || []; if (accounts.length > 0) { walletAddress = accounts[0].address; connectedProvider = wallet; updateWalletUI(); } else { throw new Error('No accounts returned'); } } else { // Legacy provider connect (Phantom, Solflare, etc.) 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}
`; }