Add WalletConnect: connect from any mobile browser (no dApp browser)
Mobile users in a normal browser hit "no wallet found" because EIP-6963 only sees injected/extension wallets. WalletConnect fixes it: the connect picker now offers WalletConnect (auto-selected when no injected wallet is present), which shows a QR on desktop and opens the wallet app directly on mobile — no in-app dApp browser, no second login. Lazy-loads the @walletconnect/ethereum-provider UMD from jsdelivr; the result is a plain EIP-1193 provider so sign/switch/buy are unchanged. CSP widened for the SDK + WC relay. Project id lives in site config (public value); gated so nothing changes until it's set. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+41
-2
@@ -52,12 +52,51 @@ window.IAPWallet = (function () {
|
|||||||
card.appendChild(cancel); back.appendChild(card); document.body.appendChild(back);
|
card.appendChild(cancel); back.appendChild(card); document.body.appendChild(back);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// ── WalletConnect: works in any normal mobile browser (no in-app dApp browser
|
||||||
|
// needed) and on desktop via QR. Lazy-loaded UMD; the returned object is a
|
||||||
|
// plain EIP-1193 provider, so everything downstream is unchanged.
|
||||||
|
let wcSdkPromise = null, wcProvider = null;
|
||||||
|
function loadWcSdk() {
|
||||||
|
const ready = () => (window['@walletconnect/ethereum-provider'] || {}).EthereumProvider;
|
||||||
|
if (ready()) return Promise.resolve(ready());
|
||||||
|
if (wcSdkPromise) return wcSdkPromise;
|
||||||
|
wcSdkPromise = new Promise((resolve, reject) => {
|
||||||
|
const s = document.createElement('script');
|
||||||
|
s.src = 'https://cdn.jsdelivr.net/npm/@walletconnect/ethereum-provider@2.21.1/dist/index.umd.js';
|
||||||
|
s.async = true;
|
||||||
|
s.onload = () => { const EP = ready(); EP ? resolve(EP) : reject(new Error('WalletConnect failed to load.')); };
|
||||||
|
s.onerror = () => reject(new Error('Could not load WalletConnect. Check your connection and try again.'));
|
||||||
|
document.head.appendChild(s);
|
||||||
|
});
|
||||||
|
return wcSdkPromise;
|
||||||
|
}
|
||||||
|
async function makeWalletConnect(c) {
|
||||||
|
const projectId = String(c.walletConnectProjectId || '').trim();
|
||||||
|
if (!projectId) throw new Error('WalletConnect is not configured yet.');
|
||||||
|
const EP = await loadWcSdk();
|
||||||
|
const chainId = Number(c.chainId);
|
||||||
|
if (!wcProvider) {
|
||||||
|
wcProvider = await EP.init({
|
||||||
|
projectId, chains: [chainId], optionalChains: [chainId], showQrModal: true,
|
||||||
|
rpcMap: { [chainId]: c.rpc },
|
||||||
|
metadata: { name: c.siteName || 'InstantAdPay', description: c.tagline || 'Advertise and earn, paid on-chain.',
|
||||||
|
url: location.origin, icons: [location.origin + '/logo-icon.png'] }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!wcProvider.session) await wcProvider.connect(); // QR on desktop, opens the wallet app on mobile
|
||||||
|
return wcProvider;
|
||||||
|
}
|
||||||
async function ensureProvider() {
|
async function ensureProvider() {
|
||||||
if (CHOSEN && CHOSEN.provider) return CHOSEN.provider;
|
if (CHOSEN && CHOSEN.provider) return CHOSEN.provider;
|
||||||
const list = providerList();
|
const list = providerList();
|
||||||
|
let cfg = null;
|
||||||
|
try { cfg = await IAP.getConfig(); } catch (e) {}
|
||||||
|
const wcOn = !!(cfg && String(cfg.walletConnectProjectId || '').trim());
|
||||||
|
if (wcOn) list.push({ info: { name: 'WalletConnect — scan a QR or open your wallet app', __wc: true } });
|
||||||
if (!list.length) throw new Error('No wallet found. Open this page in your wallet app (Trust, MetaMask, SafePal, Phantom, OKX, TokenPocket) or install a wallet extension.');
|
if (!list.length) throw new Error('No wallet found. Open this page in your wallet app (Trust, MetaMask, SafePal, Phantom, OKX, TokenPocket) or install a wallet extension.');
|
||||||
CHOSEN = list.length === 1 ? list[0] : await pickModal(list);
|
const pick = list.length === 1 ? list[0] : await pickModal(list);
|
||||||
if (!CHOSEN) throw new Error('No wallet selected.');
|
if (!pick) throw new Error('No wallet selected.');
|
||||||
|
CHOSEN = (pick.info && pick.info.__wc) ? { info: pick.info, provider: await makeWalletConnect(cfg) } : pick;
|
||||||
return CHOSEN.provider;
|
return CHOSEN.provider;
|
||||||
}
|
}
|
||||||
function eth() {
|
function eth() {
|
||||||
|
|||||||
+1
-1
@@ -439,7 +439,7 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<script src="/assets/common.js?v=20260908c"></script>
|
<script src="/assets/common.js?v=20260908c"></script>
|
||||||
<script src="/assets/wallet.js?v=20260907q"></script>
|
<script src="/assets/wallet.js?v=20260908a"></script>
|
||||||
<script src="/assets/home.js?v=20260906m"></script>
|
<script src="/assets/home.js?v=20260906m"></script>
|
||||||
<script src="/assets/chat.js?v=20260906m"></script>
|
<script src="/assets/chat.js?v=20260906m"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
+1
-1
@@ -690,7 +690,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="/assets/common.js?v=20260908c"></script>
|
<script src="/assets/common.js?v=20260908c"></script>
|
||||||
<script src="/assets/wallet.js?v=20260907q"></script>
|
<script src="/assets/wallet.js?v=20260908a"></script>
|
||||||
<script src="/assets/my.js?v=20260908h"></script>
|
<script src="/assets/my.js?v=20260908h"></script>
|
||||||
<script src="/assets/chat.js?v=20260907l"></script>
|
<script src="/assets/chat.js?v=20260907l"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ const MIME = { '.html': 'text/html; charset=utf-8', '.css': 'text/css', '.js': '
|
|||||||
'.png': 'image/png', '.jpg': 'image/jpeg', '.svg': 'image/svg+xml', '.webp': 'image/webp',
|
'.png': 'image/png', '.jpg': 'image/jpeg', '.svg': 'image/svg+xml', '.webp': 'image/webp',
|
||||||
'.ico': 'image/x-icon', '.json': 'application/json', '.mp4': 'video/mp4', '.woff2': 'font/woff2',
|
'.ico': 'image/x-icon', '.json': 'application/json', '.mp4': 'video/mp4', '.woff2': 'font/woff2',
|
||||||
'.gif': 'image/gif', '.webm': 'video/webm', '.txt': 'text/plain; charset=utf-8', '.xml': 'application/xml; charset=utf-8' };
|
'.gif': 'image/gif', '.webm': 'video/webm', '.txt': 'text/plain; charset=utf-8', '.xml': 'application/xml; charset=utf-8' };
|
||||||
const CSP = "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: https:; media-src 'self' https: blob:; connect-src 'self'; font-src 'self' data: https://fonts.gstatic.com; form-action 'self'; frame-src https: http:";
|
const CSP = "default-src 'self'; script-src 'self' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: https:; media-src 'self' https: blob:; connect-src 'self' https://*.walletconnect.com wss://*.walletconnect.com https://*.walletconnect.org wss://*.walletconnect.org https://*.web3modal.org https://*.reown.com wss://*.reown.com; font-src 'self' data: https://fonts.gstatic.com; form-action 'self'; frame-src https: http:";
|
||||||
function baseHeaders(extra) {
|
function baseHeaders(extra) {
|
||||||
return Object.assign({ 'Content-Security-Policy': CSP, 'X-Content-Type-Options': 'nosniff',
|
return Object.assign({ 'Content-Security-Policy': CSP, 'X-Content-Type-Options': 'nosniff',
|
||||||
'Referrer-Policy': 'strict-origin-when-cross-origin' }, extra || {});
|
'Referrer-Policy': 'strict-origin-when-cross-origin' }, extra || {});
|
||||||
|
|||||||
Reference in New Issue
Block a user