/** * Mobile wallet detection and deep-link helpers. * * On mobile browsers (Safari / Chrome) there is no injected `window.ethereum`, * so the `injected()` wagmi connector returns nothing and the user sees * "No wallet provider found". The fix is to detect this state early and offer * deep links that open MetaMask / Trust / Coinbase / OKX and land the user * inside the wallet's in-app browser at the current dApp URL. * * Deep-link patterns used: * MetaMask https://metamask.app.link/dapp/ (universal link → iOS/Android) * Trust https://link.trustwallet.com/open_url?coin_id=60&url= * Coinbase https://go.cb-wallet.com/dapp?url= * OKX https://www.okx.com/download?deeplink=okx%3A%2F%2Fmain%2Fdapp%2Fbrowser%3Furl%3D * * All links open in a new tab (_blank) so if the user doesn't have the app * installed they land on the wallet's download page without breaking nav. */ /** True when the JS runtime has access to browser APIs. */ const isBrowser = typeof window !== 'undefined' /** * Rough mobile UA check — covers iOS (iPhone/iPad) and Android. * Intentionally excludes desktop Chrome/Firefox even if the viewport is narrow. */ export function isMobileDevice(): boolean { if (!isBrowser) return false return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) } /** * Returns true when an injected EIP-1193 provider is present in the window * (i.e. the user is already inside MetaMask's browser, has a browser extension, * or Coinbase Wallet's in-app browser). */ export function hasInjectedWallet(): boolean { if (!isBrowser) return false // window.ethereum is the canonical EIP-1193 injection point. // Some wallets also inject under their own namespace but all reputable ones // also set window.ethereum (or window.web3 as a fallback). return !!(window as unknown as { ethereum?: unknown }).ethereum } /** * True when the user is on mobile AND has no injected wallet — the state * where we should show the mobile wallet picker instead of a bare error. */ export function needsMobileWallet(): boolean { return isMobileDevice() && !hasInjectedWallet() } export interface WalletLink { name: string /** Short subtitle shown under the name */ hint: string /** URL that opens the wallet app and navigates to `dappUrl` */ href: string /** CSS color for the icon background */ color: string /** Short letter(s) displayed when no SVG icon is available */ abbr: string } /** * Build the deep-link set for the given dApp URL. * Pass `window.location.href` (or a canonical URL) as `dappUrl`. */ export function getWalletLinks(dappUrl: string): WalletLink[] { const enc = encodeURIComponent(dappUrl) // MetaMask universal link: strip the protocol and pass host+path // e.g. "https://trumpsignal.com/en" → "trumpsignal.com/en" const hostPath = dappUrl.replace(/^https?:\/\//, '') return [ { name: 'MetaMask', hint: 'Most popular — iOS & Android', href: `https://metamask.app.link/dapp/${hostPath}`, color: '#E8831D', abbr: '🦊', }, { name: 'Trust Wallet', hint: 'Binance-backed, iOS & Android', href: `https://link.trustwallet.com/open_url?coin_id=60&url=${enc}`, color: '#3375BB', abbr: '🛡', }, { name: 'Coinbase Wallet', hint: 'No Coinbase account needed', href: `https://go.cb-wallet.com/dapp?url=${enc}`, color: '#1652F0', abbr: '🔵', }, { name: 'OKX Wallet', hint: 'iOS & Android', href: `https://www.okx.com/download?deeplink=${encodeURIComponent(`okx://main/dapp/browser?url=${enc}`)}`, color: '#000000', abbr: 'OKX', }, ] }