From 68d68b1ebfeb0b364021b109aabda76665f30e4e Mon Sep 17 00:00:00 2001 From: martbost Date: Wed, 9 Sep 2026 06:41:09 -0500 Subject: [PATCH] Wallet: recover from a dead WalletConnect session instead of failing the buy Probe the session after connect and retry once after a "disconnected" send error by wiping the stale session and re-opening the picker (Trust kills the session after its own security stop). Co-Authored-By: Claude Fable 5.1 --- public/assets/wallet.js | 30 +++++++++++++++++++++++++++++- public/index.html | 2 +- public/my.html | 2 +- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/public/assets/wallet.js b/public/assets/wallet.js index 48ada81..d51e9c0 100644 --- a/public/assets/wallet.js +++ b/public/assets/wallet.js @@ -85,6 +85,24 @@ window.IAPWallet = (function () { function eth() { if (!provider) throw new Error('Connect your wallet first.'); return provider; } + // A WalletConnect session can die underneath AppKit's cached "connected" + // state: the wallet app rejects or kills it (Trust does this after its own + // security stop), the phone sleeps, the relay drops. AppKit still reports an + // address, so the next request fails with a "disconnected" style error. + // Detect that, wipe the stale session, and re-open the picker for a fresh one. + const DEAD_RE = /disconnect|not connected|no matching key|session (topic|expired|deleted|not found)|call connect|please call connect|missing or invalid|relay/i; + const isDead = e => DEAD_RE.test(String((e && e.message) || e || '')); + async function freshConnect(c) { + try { IAP.status('Your wallet session dropped. Reconnect in the picker…'); } catch (e) {} + await disconnect(); + try { await modal.open(); } catch (e) {} + const addr = await waitForConnection(180000); + try { if (modal && modal.close) await modal.close(); } catch (e) {} + provider = await resolveProvider(); + await ensureChain(c).catch(() => {}); + return addr; + } + async function connect() { const c = await IAP.getConfig(); await initAppKit(c); @@ -97,6 +115,9 @@ window.IAPWallet = (function () { if (!addr) { try { await modal.open(); } catch (e) {} addr = await waitForConnection(180000); } try { if (modal && modal.close) await modal.close(); } catch (e) {} // dismiss the picker once we're connected provider = await resolveProvider(); + // probe the session: a dead WalletConnect session answers with a disconnect error + try { await provider.request({ method: 'eth_chainId' }); } + catch (e) { if (isDead(e)) return freshConnect(c); } await ensureChain(c).catch(() => {}); // AppKit already connects on the right network; switch is best-effort return addr; } @@ -159,7 +180,14 @@ window.IAPWallet = (function () { tx.maxFeePerGas = g.maxFeePerGas; } } catch (e) {} - return eth().request({ method: 'eth_sendTransaction', params: [tx] }); + try { + return await eth().request({ method: 'eth_sendTransaction', params: [tx] }); + } catch (e) { + if (!isDead(e)) throw e; + // session died between connect and send: reconnect once and resend + tx.from = await freshConnect(c); + return eth().request({ method: 'eth_sendTransaction', params: [tx] }); + } } async function waitTx(hash) { diff --git a/public/index.html b/public/index.html index d1499f7..5b0caf6 100644 --- a/public/index.html +++ b/public/index.html @@ -439,7 +439,7 @@ - + diff --git a/public/my.html b/public/my.html index 45b7d2e..d249a36 100644 --- a/public/my.html +++ b/public/my.html @@ -735,7 +735,7 @@ - +