fix: comprehensive wallet detection - generic window.solana fallback, multi-provider array, wallet standard, 150ms async delay, dedup
This commit is contained in:
parent
f1a4437bf9
commit
35286a0a39
1 changed files with 149 additions and 124 deletions
201
js/soldomains.js
201
js/soldomains.js
|
|
@ -230,96 +230,116 @@ async function doReverse() {
|
|||
// ─── 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();
|
||||
const found = [];
|
||||
const seen = new Set();
|
||||
|
||||
for (const w of WALLETS) {
|
||||
function add(name, icon, provider, url) {
|
||||
if (!provider || seen.has(provider)) return;
|
||||
seen.add(provider);
|
||||
found.push({ name, icon, provider, url });
|
||||
}
|
||||
|
||||
// ── Specific well-known injection points ──
|
||||
|
||||
// Phantom
|
||||
try {
|
||||
const provider = w.detect();
|
||||
if (provider && !matchedProviders.has(provider)) {
|
||||
available.push({ ...w, provider });
|
||||
matchedProviders.add(provider);
|
||||
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) {}
|
||||
|
||||
// ── Generic window.solana (Jupiter, MetaMask Snap, and others inject here) ──
|
||||
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, '#');
|
||||
}
|
||||
} catch(e) {}
|
||||
|
||||
// ── Jupiter specific paths ──
|
||||
try {
|
||||
const j = window.jupiter?.solana;
|
||||
if (j && !seen.has(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) ──
|
||||
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) {}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
// All known wallets for install links
|
||||
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');
|
||||
|
|
@ -353,12 +373,14 @@ function createWalletModal() {
|
|||
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 = '';
|
||||
|
||||
// Show detected wallets as clickable buttons
|
||||
if (available.length > 0) {
|
||||
html += '<div class="sol-wallet-divider">DETECTED</div>';
|
||||
html += available.map(w => `
|
||||
|
|
@ -370,8 +392,7 @@ function openModal() {
|
|||
`).join('');
|
||||
}
|
||||
|
||||
// Show not-installed wallets as links (exclude detected ones)
|
||||
const notInstalled = WALLETS.filter(w => !detectedNames.has(w.name));
|
||||
const notInstalled = KNOWN_WALLETS.filter(w => !detectedNames.has(w.name));
|
||||
if (notInstalled.length > 0) {
|
||||
html += '<div class="sol-wallet-divider">NOT INSTALLED</div>';
|
||||
html += notInstalled.map(w => `
|
||||
|
|
@ -384,12 +405,15 @@ function openModal() {
|
|||
}
|
||||
|
||||
if (available.length === 0) {
|
||||
html = '<div class="sol-empty" style="padding:1rem;">NO SOLANA WALLETS DETECTED<br><br>Install a Solana wallet extension to connect.</div>';
|
||||
html = `<div class="sol-empty" style="padding:1rem;">
|
||||
NO SOLANA WALLETS DETECTED<br><br>
|
||||
Install a Solana wallet extension to connect.<br>
|
||||
<span style="color:#14F195;font-size:0.6rem;">If you just installed one, refresh the page.</span>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
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();
|
||||
|
|
@ -401,6 +425,7 @@ function openModal() {
|
|||
});
|
||||
|
||||
modal.classList.remove('hidden');
|
||||
}, 150);
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue