Positions: force the wallet's account picker (wallet_requestPermissions) when adding a position or when the Buy-from wallet doesn't match; sign/send with the wallet's active account

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
martbost
2026-09-10 06:11:38 -05:00
parent 70b96bf862
commit 15a881a72b
3 changed files with 39 additions and 13 deletions
+7 -8
View File
@@ -1249,10 +1249,9 @@
const me = await (await fetch('/api/me')).json(); const me = await (await fetch('/api/me')).json();
if (!me.address) throw new Error('Link your main wallet first (Wallet tab), then add positions under it.'); if (!me.address) throw new Error('Link your main wallet first (Wallet tab), then add positions under it.');
if (!me.memberId) throw new Error('Switch on payouts for your main wallet first (Wallet tab). Positions register under your member number.'); if (!me.memberId) throw new Error('Switch on payouts for your main wallet first (Wallet tab). Positions register under your member number.');
if (!confirm('In your wallet app, switch to a DIFFERENT account than ' + short(me.address) + ' first (MetaMask: account menu, Add account. Trust or SafePal: switch wallet). The wallet picker will open again so you can connect that account.\n\nReady?')) return; if (!confirm('Your wallet will ask which account to connect. Tick ONLY the new account (not ' + short(me.address) + '), then sign once.\n\nIf you have not created the extra account yet: MetaMask, account menu, Add account. Trust or SafePal: switch wallet.\n\nReady?')) return;
await IAPWallet.disconnect(); IAP.status('Pick the new account in your wallet, then sign once…');
IAP.status('Connect the new account in the picker, then sign once…'); const r = await IAPWallet.signIn({ asPosition: true, pick: true });
const r = await IAPWallet.signIn({ asPosition: true });
$('qsHint').textContent = 'Added ' + short(r.address) + '. Now choose it under "Buy from" and buy a $20 or larger package.'; $('qsHint').textContent = 'Added ' + short(r.address) + '. Now choose it under "Buy from" and buy a $20 or larger package.';
IAP.status('Position added: ' + short(r.address) + '. Pick it under "Buy from" above and buy a $20+ package to count it.', 'ok'); IAP.status('Position added: ' + short(r.address) + '. Pick it under "Buy from" above and buy a $20+ package to count it.', 'ok');
await loadPositions(); await loadPositions();
@@ -1299,11 +1298,11 @@
} }
const wantAddr = fromPos || (meNow.address ? meNow.address.toLowerCase() : null); const wantAddr = fromPos || (meNow.address ? meNow.address.toLowerCase() : null);
if (wantAddr) { // never buy from a wallet other than the one selected: a stray wallet would register a brand-new member if (wantAddr) { // never buy from a wallet other than the one selected: a stray wallet would register a brand-new member
let cur = (IAPWallet.address() || await IAPWallet.connect() || '').toLowerCase(); await IAPWallet.connect();
let cur = String(await IAPWallet.activeAddress() || '').toLowerCase();
if (cur !== wantAddr) { if (cur !== wantAddr) {
IAP.status('Switch your wallet app to ' + wantAddr.slice(0, 6) + '…' + wantAddr.slice(-4) + ', then pick it in the picker…'); IAP.status('Pick ' + wantAddr.slice(0, 6) + '…' + wantAddr.slice(-4) + ' in your wallet\'s account picker…');
await IAPWallet.disconnect(); cur = String(await IAPWallet.pickAccount() || '').toLowerCase();
cur = String(await IAPWallet.connect() || '').toLowerCase();
} }
if (cur !== wantAddr) throw new Error('Your wallet connected as ' + cur.slice(0, 6) + '…' + cur.slice(-4) + ' but you chose ' + wantAddr.slice(0, 6) + '…' + wantAddr.slice(-4) + '. Switch accounts in your wallet app and try again.'); if (cur !== wantAddr) throw new Error('Your wallet connected as ' + cur.slice(0, 6) + '…' + cur.slice(-4) + ' but you chose ' + wantAddr.slice(0, 6) + '…' + wantAddr.slice(-4) + '. Switch accounts in your wallet app and try again.');
} }
+30 -3
View File
@@ -93,6 +93,33 @@ window.IAPWallet = (function () {
} }
function eth() { if (!provider) throw new Error('Connect your wallet first.'); return provider; } function eth() { if (!provider) throw new Error('Connect your wallet first.'); return provider; }
const isInjected = () => !!(provider && window.ethereum && (provider === window.ethereum || provider.isMetaMask));
// the account the wallet will actually sign with: for an injected wallet (MetaMask
// extension) that is its active account, which can differ from AppKit's cached one
async function activeAddress(fallback) {
if (isInjected()) { try { const a = await provider.request({ method: 'eth_accounts' }); if (a && a[0]) return a[0]; } catch (e) {} }
return fallback || currentAddress();
}
// Force the wallet's own account picker. Injected wallets stay connected to the
// site, so a plain disconnect/reconnect never shows one: asking for permissions
// again makes MetaMask open its account-selection prompt, and whatever the user
// ticks becomes the active account. WalletConnect wallets fall back to a fresh
// session (the picker + the wallet app's own account choice).
async function pickAccount() {
const c = await IAP.getConfig();
await initAppKit(c);
const inj = window.ethereum;
if (inj && inj.request) {
try {
await inj.request({ method: 'wallet_requestPermissions', params: [{ eth_accounts: {} }] });
const accs = await inj.request({ method: 'eth_accounts' });
if (accs && accs[0]) { provider = inj; await ensureChain(c).catch(() => {}); return accs[0]; }
} catch (e) {
if (e && (e.code === 4001 || /reject|denied/i.test(String(e.message || '')))) throw new Error('You closed the account picker. Pick the account you want and try again.');
}
}
return freshConnect(c);
}
// A WalletConnect session can die underneath AppKit's cached "connected" // A WalletConnect session can die underneath AppKit's cached "connected"
// state: the wallet app rejects or kills it (Trust does this after its own // state: the wallet app rejects or kills it (Trust does this after its own
@@ -149,7 +176,7 @@ window.IAPWallet = (function () {
// SIWE: challenge -> personal_sign -> verify (server sets the session cookie) // SIWE: challenge -> personal_sign -> verify (server sets the session cookie)
async function signIn(opts) { async function signIn(opts) {
const addr = await connect(); const addr = (opts && opts.pick) ? await pickAccount() : await activeAddress(await connect());
const ch = await (await fetch('/api/auth/challenge', { method: 'POST', const ch = await (await fetch('/api/auth/challenge', { method: 'POST',
headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ address: addr }) })).json(); headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ address: addr }) })).json();
if (ch.error) throw new Error(ch.error); if (ch.error) throw new Error(ch.error);
@@ -177,7 +204,7 @@ window.IAPWallet = (function () {
if (!isNaN(chainNum(cur)) && chainNum(cur) !== wantNum) if (!isNaN(chainNum(cur)) && chainNum(cur) !== wantNum)
throw new Error('Your wallet is on the wrong network. Switch it to ' + (c.chainName || 'the correct network') + ', then try again.'); throw new Error('Your wallet is on the wrong network. Switch it to ' + (c.chainName || 'the correct network') + ', then try again.');
} }
const tx = { from: addr, to: c.contract, data }; const tx = { from: await activeAddress(addr), to: c.contract, data };
if (valueWei) tx.value = '0x' + BigInt(valueWei).toString(16); if (valueWei) tx.value = '0x' + BigInt(valueWei).toString(16);
// Amoy's Bor nodes enforce a ~25 gwei minimum priority fee that MetaMask's // Amoy's Bor nodes enforce a ~25 gwei minimum priority fee that MetaMask's
// own estimate misses ("gas tip below minimum"). Pull the network's correct // own estimate misses ("gas tip below minimum"). Pull the network's correct
@@ -237,5 +264,5 @@ window.IAPWallet = (function () {
return BigInt(h); return BigInt(h);
} }
function walletName() { try { const w = modal && modal.getWalletInfo && modal.getWalletInfo(); return (w && w.name) || ''; } catch (e) { return ''; } } function walletName() { try { const w = modal && modal.getWalletInfo && modal.getWalletInfo(); return (w && w.name) || ''; } catch (e) { return ''; } }
return { connect, signIn, buy, activate, waitTx, disconnect, balance, address: currentAddress, walletName }; return { connect, signIn, buy, activate, waitTx, disconnect, balance, address: currentAddress, activeAddress, pickAccount, walletName };
})(); })();
+2 -2
View File
@@ -793,9 +793,9 @@
</div> </div>
</div> </div>
<script src="/assets/common.js?v=20260909a"></script> <script src="/assets/common.js?v=20260909a"></script>
<script src="/assets/wallet.js?v=20260909c"></script> <script src="/assets/wallet.js?v=20260910a"></script>
<script src="/assets/promo.js?v=20260909b"></script> <script src="/assets/promo.js?v=20260909b"></script>
<script src="/assets/my.js?v=20260909i"></script> <script src="/assets/my.js?v=20260910a"></script>
<script src="/assets/chat.js?v=20260907l"></script> <script src="/assets/chat.js?v=20260907l"></script>
</body> </body>
</html> </html>