diff --git a/.changeset/fuzzy-cows-hope.md b/.changeset/fuzzy-cows-hope.md new file mode 100644 index 000000000..7f6751946 --- /dev/null +++ b/.changeset/fuzzy-cows-hope.md @@ -0,0 +1,5 @@ +--- +'@solana/wallet-adapter-solflare': patch +--- + +Optimize Solflare MetaMask snap detection diff --git a/packages/wallets/solflare/src/adapter.ts b/packages/wallets/solflare/src/adapter.ts index 5d509c0c0..089773327 100644 --- a/packages/wallets/solflare/src/adapter.ts +++ b/packages/wallets/solflare/src/adapter.ts @@ -1,10 +1,6 @@ import type { WalletAdapterNetwork, WalletName } from '@solana/wallet-adapter-base'; import { BaseMessageSignerWalletAdapter, - isIosAndRedirectable, - isVersionedTransaction, - scopePollingDetectionStrategy, - type SendTransactionOptions, WalletConfigError, WalletConnectionError, WalletDisconnectedError, @@ -18,9 +14,13 @@ import { WalletSendTransactionError, WalletSignMessageError, WalletSignTransactionError, + isIosAndRedirectable, + isVersionedTransaction, + scopePollingDetectionStrategy, + type SendTransactionOptions, } from '@solana/wallet-adapter-base'; import type { Transaction, TransactionVersion, VersionedTransaction } from '@solana/web3.js'; -import { type Connection, PublicKey, type TransactionSignature } from '@solana/web3.js'; +import { PublicKey, type Connection, type TransactionSignature } from '@solana/web3.js'; import type { default as Solflare } from '@solflare-wallet/sdk'; import { detectAndRegisterSolflareMetaMaskWallet } from './metamask/detect.js'; @@ -71,7 +71,7 @@ export class SolflareWalletAdapter extends BaseMessageSignerWalletAdapter { } return false; }); - scopePollingDetectionStrategy(detectAndRegisterSolflareMetaMaskWallet); + detectAndRegisterSolflareMetaMaskWallet(); } } diff --git a/packages/wallets/solflare/src/metamask/detect.ts b/packages/wallets/solflare/src/metamask/detect.ts index 88fb60bf5..0990c1213 100644 --- a/packages/wallets/solflare/src/metamask/detect.ts +++ b/packages/wallets/solflare/src/metamask/detect.ts @@ -1,61 +1,52 @@ -import type { EthereumProvider, WindowWithEthereum } from '@solflare-wallet/metamask-sdk'; import { registerWallet } from '@wallet-standard/wallet'; import { SolflareMetaMaskWallet } from './wallet.js'; -let stopPolling = false; +let registered = false; -/** @internal */ -export function detectAndRegisterSolflareMetaMaskWallet(): boolean { - // If detected, stop polling. - if (stopPolling) return true; - (async function () { - try { - // Try to detect, stop polling if detected, and register the wallet. - if (await isSnapProviderDetected()) { - if (!stopPolling) { - stopPolling = true; - registerWallet(new SolflareMetaMaskWallet()); - } - } - } catch (error) { - // Stop polling on unhandled errors (this should never happen). - stopPolling = true; - } - })(); - // Keep polling. - return false; +function register() { + if (registered) return; + registerWallet(new SolflareMetaMaskWallet()); + registered = true; } -async function isSnapProviderDetected(): Promise { - try { - const provider = (window as WindowWithEthereum).ethereum; - if (!provider) return false; +/** @internal */ +export async function detectAndRegisterSolflareMetaMaskWallet(): Promise { + const id = 'solflare-detect-metamask'; - const providerProviders = provider.providers; - if (providerProviders && Array.isArray(providerProviders)) { - for (const provider of providerProviders) { - if (await isSnapSupported(provider)) return true; - } - } + function postMessage() { + window.postMessage( + { + target: 'metamask-contentscript', + data: { + name: 'metamask-provider', + data: { + id, + jsonrpc: '2.0', + method: 'wallet_getSnaps', + }, + }, + }, + window.location.origin + ); + } + + function onMessage(event: MessageEvent) { + const message = event.data; + if (message?.target === 'metamask-inpage' && message.data?.name === 'metamask-provider') { + if (message.data.data?.id === id) { + window.removeEventListener('message', onMessage); - const providerDetected = provider.detected; - if (providerDetected && Array.isArray(providerDetected)) { - for (const provider of providerDetected) { - if (await isSnapSupported(provider)) return true; + if (!message.data.data.error) { + register(); + } + } else { + postMessage(); } } - - return await isSnapSupported(provider); - } catch (error) { - return false; } -} -async function isSnapSupported(provider: EthereumProvider): Promise { - try { - await provider.request({ method: 'wallet_getSnaps' }); - return true; - } catch (error) { - return false; - } + window.addEventListener('message', onMessage); + window.setTimeout(() => window.removeEventListener('message', onMessage), 5000); + + postMessage(); }