Wallet: fix Trust Wallet chain-add + personal_sign ("invalid method parameters")

- wallet_addEthereumChain omits blockExplorerUrls when the config explorer is
  empty (rehearsal has none) — an empty-string URL made Trust Wallet reject the
  add with "invalid method parameters", blocking new users from adding the chain.
- personal_sign now hex-encodes the SIWE message (Trust Wallet requires hex;
  MetaMask took raw). Signed bytes are identical so server recovery is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
martbost
2026-09-07 06:58:12 -05:00
parent 41d3293486
commit 85a6ac5bb0
3 changed files with 13 additions and 5 deletions
+11 -3
View File
@@ -17,9 +17,13 @@ window.IAPWallet = (function () {
await eth().request({ method: 'wallet_switchEthereumChain', params: [{ chainId: want }] });
} catch (e) {
if (e.code !== 4902) throw e;
await eth().request({ method: 'wallet_addEthereumChain', params: [{
const addParams = {
chainId: want, chainName: c.chainName, nativeCurrency: { name: 'POL', symbol: 'POL', decimals: 18 },
rpcUrls: [c.rpc], blockExplorerUrls: [c.explorer] }] });
rpcUrls: [c.rpc] };
// only include a block explorer when it's a real URL — an empty string here
// makes wallets (Trust Wallet especially) reject with "invalid method parameters"
if (c.explorer && /^https?:\/\//i.test(c.explorer)) addParams.blockExplorerUrls = [c.explorer];
await eth().request({ method: 'wallet_addEthereumChain', params: [addParams] });
}
}
async function connect() {
@@ -34,7 +38,11 @@ window.IAPWallet = (function () {
const ch = await (await fetch('/api/auth/challenge', { method: 'POST',
headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ address: addr }) })).json();
if (ch.error) throw new Error(ch.error);
const sig = await eth().request({ method: 'personal_sign', params: [ch.message, addr] });
// hex-encode the message: MetaMask accepts a raw string, but Trust Wallet and
// others require hex for personal_sign (else "invalid method parameters").
// The signed bytes are identical, so server-side recovery is unchanged.
const hexMsg = '0x' + Array.from(new TextEncoder().encode(ch.message)).map(b => b.toString(16).padStart(2, '0')).join('');
const sig = await eth().request({ method: 'personal_sign', params: [hexMsg, addr] });
const r = await (await fetch('/api/auth/verify', { method: 'POST',
headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ address: addr, signature: sig }) })).json();
if (r.error) throw new Error(r.error);
+1 -1
View File
@@ -438,7 +438,7 @@
</section>
<script src="/assets/common.js?v=20260906m"></script>
<script src="/assets/wallet.js?v=20260906m"></script>
<script src="/assets/wallet.js?v=20260907f"></script>
<script src="/assets/home.js?v=20260906m"></script>
<script src="/assets/chat.js?v=20260906m"></script>
</body>
+1 -1
View File
@@ -634,7 +634,7 @@
</div>
</div>
<script src="/assets/common.js?v=20260907e"></script>
<script src="/assets/wallet.js?v=20260907e"></script>
<script src="/assets/wallet.js?v=20260907f"></script>
<script src="/assets/my.js?v=20260907e"></script>
<script src="/assets/chat.js?v=20260907e"></script>
</body>