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 ─────────────────────────────────────────────────
|
// ─── WALLET ─────────────────────────────────────────────────
|
||||||
let connectedProvider = null;
|
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() {
|
function getAvailableWallets() {
|
||||||
const available = [];
|
const found = [];
|
||||||
const matchedProviders = new Set();
|
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 {
|
try {
|
||||||
const provider = w.detect();
|
const p = window.phantom?.solana;
|
||||||
if (provider && !matchedProviders.has(provider)) {
|
if (p && p.isPhantom) add('PHANTOM', '👻', p, 'https://phantom.app');
|
||||||
available.push({ ...w, provider });
|
} catch(e) {}
|
||||||
matchedProviders.add(provider);
|
|
||||||
|
// 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) {}
|
} 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
|
// All known wallets for install links
|
||||||
if (available.length === 0 && window.solana) {
|
const KNOWN_WALLETS = [
|
||||||
available.push({
|
{ name: 'PHANTOM', icon: '👻', url: 'https://phantom.app' },
|
||||||
name: 'SOLANA WALLET',
|
{ name: 'JUPITER', icon: '🪐', url: 'https://jup.ag' },
|
||||||
icon: '◈',
|
{ name: 'SOLFLARE', icon: '🔆', url: 'https://solflare.com' },
|
||||||
provider: window.solana,
|
{ name: 'BACKPACK', icon: '🎒', url: 'https://backpack.app' },
|
||||||
url: '#'
|
{ name: 'COINBASE', icon: '🔵', url: 'https://coinbase.com/wallet' },
|
||||||
});
|
{ name: 'TRUST', icon: '🛡️', url: 'https://trustwallet.com' },
|
||||||
}
|
{ name: 'METAMASK', icon: '🦊', url: 'https://metamask.io' },
|
||||||
|
];
|
||||||
return available;
|
|
||||||
}
|
|
||||||
|
|
||||||
function initWallet() {
|
function initWallet() {
|
||||||
const btn = $('#wallet-btn');
|
const btn = $('#wallet-btn');
|
||||||
|
|
@ -353,12 +373,14 @@ function createWalletModal() {
|
||||||
function openModal() {
|
function openModal() {
|
||||||
const modal = $('#wallet-modal');
|
const modal = $('#wallet-modal');
|
||||||
const list = $('#wallet-list');
|
const list = $('#wallet-list');
|
||||||
|
|
||||||
|
// Small delay to let async provider injection complete
|
||||||
|
setTimeout(() => {
|
||||||
const available = getAvailableWallets();
|
const available = getAvailableWallets();
|
||||||
const detectedNames = new Set(available.map(w => w.name));
|
const detectedNames = new Set(available.map(w => w.name));
|
||||||
|
|
||||||
let html = '';
|
let html = '';
|
||||||
|
|
||||||
// Show detected wallets as clickable buttons
|
|
||||||
if (available.length > 0) {
|
if (available.length > 0) {
|
||||||
html += '<div class="sol-wallet-divider">DETECTED</div>';
|
html += '<div class="sol-wallet-divider">DETECTED</div>';
|
||||||
html += available.map(w => `
|
html += available.map(w => `
|
||||||
|
|
@ -370,8 +392,7 @@ function openModal() {
|
||||||
`).join('');
|
`).join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show not-installed wallets as links (exclude detected ones)
|
const notInstalled = KNOWN_WALLETS.filter(w => !detectedNames.has(w.name));
|
||||||
const notInstalled = WALLETS.filter(w => !detectedNames.has(w.name));
|
|
||||||
if (notInstalled.length > 0) {
|
if (notInstalled.length > 0) {
|
||||||
html += '<div class="sol-wallet-divider">NOT INSTALLED</div>';
|
html += '<div class="sol-wallet-divider">NOT INSTALLED</div>';
|
||||||
html += notInstalled.map(w => `
|
html += notInstalled.map(w => `
|
||||||
|
|
@ -384,12 +405,15 @@ function openModal() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (available.length === 0) {
|
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;
|
list.innerHTML = html;
|
||||||
|
|
||||||
// Bind click handlers only for detected wallets (buttons, not links)
|
|
||||||
list.querySelectorAll('.sol-wallet-option.detected').forEach(btn => {
|
list.querySelectorAll('.sol-wallet-option.detected').forEach(btn => {
|
||||||
btn.addEventListener('click', (e) => {
|
btn.addEventListener('click', (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
@ -401,6 +425,7 @@ function openModal() {
|
||||||
});
|
});
|
||||||
|
|
||||||
modal.classList.remove('hidden');
|
modal.classList.remove('hidden');
|
||||||
|
}, 150);
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeModal() {
|
function closeModal() {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue