diff --git a/js/soldomains.js b/js/soldomains.js index 5ad2f63..db5f7a2 100644 --- a/js/soldomains.js +++ b/js/soldomains.js @@ -230,17 +230,83 @@ async function doReverse() { // ─── 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) { - if (!provider || seen.has(provider)) return; - seen.add(provider); - found.push({ name, icon, provider, url }); + function add(name, icon, provider, url, isWalletStandard) { + if (!provider || seen.has(name)) return; + seen.add(name); + found.push({ name, icon, provider, url, isWalletStandard: !!isWalletStandard }); } - // ── Specific well-known injection points ── + // ── 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 { @@ -271,58 +337,35 @@ function getAvailableWallets() { if (t) add('TRUST', '🛡️', t, 'https://trustwallet.com'); } catch(e) {} - // ── Generic window.solana (Jupiter, MetaMask Snap, and others inject here) ── + // ── 3. Generic window.solana ── try { const ws = window.solana; - if (ws && !seen.has(ws)) { - // Try to identify what it is - if (ws.isJupiter) add('JUPITER', '🪐', ws, 'https://jup.ag'); - else if (ws.isMetaMask) add('METAMASK', '🦊', ws, 'https://metamask.io'); - else if (ws.isPhantom) { /* already caught above */ } - else if (ws.isSolflare) { /* already caught above */ } - else if (ws.isBackpack) { /* already caught above */ } - else add('SOLANA WALLET', '◈', ws, '#'); + 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) {} - // ── Jupiter specific paths ── + // ── 4. Jupiter specific ── try { const j = window.jupiter?.solana; - if (j && !seen.has(j)) add('JUPITER', '🪐', j, 'https://jup.ag'); + if (j) add('JUPITER', '🪐', j, 'https://jup.ag'); } catch(e) {} - // ── MetaMask ethereum.solana path ── - try { - if (window.ethereum?.isMetaMask && window.ethereum?.solana && !seen.has(window.ethereum.solana)) { - add('METAMASK', '🦊', window.ethereum.solana, 'https://metamask.io'); - } - } catch(e) {} - - // ── Multi-provider array (some wallets use this) ── + // ── 5. Multi-provider array ── try { const providers = window.solana?.providers; if (Array.isArray(providers)) { for (const p of providers) { - if (seen.has(p)) continue; 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'); - else add('WALLET', '◈', p, '#'); - } - } - } catch(e) {} - - // ── Wallet Standard discovery (modern wallets) ── - try { - const walletStandard = window.navigator?.wallets; - if (walletStandard && typeof walletStandard[Symbol.iterator] === 'function') { - for (const w of walletStandard) { - if (w.features?.['standard:connect'] && !seen.has(w)) { - const name = (w.name || 'WALLET').toUpperCase(); - add(name, w.icon || '◈', w, w.url || '#'); - } } } } catch(e) {} @@ -330,7 +373,6 @@ function getAvailableWallets() { return found; } -// All known wallets for install links const KNOWN_WALLETS = [ { name: 'PHANTOM', icon: '👻', url: 'https://phantom.app' }, { name: 'JUPITER', icon: '🪐', url: 'https://jup.ag' }, @@ -444,10 +486,26 @@ async function toggleWallet() { async function connectWallet(wallet) { try { closeModal(); - const resp = await wallet.provider.connect(); - walletAddress = resp.publicKey.toString(); - connectedProvider = wallet; - updateWalletUI(); + + 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');