Fix EIP-712 chainId dynamic resolution; improve add-wallet modal
- Replace hardcoded chainId:1 with per-chain EIP-712 domain (base→8453, etc.) - Add hyperliquide (chainId 998) as supported EVM chain - Auto-fill wallet address and chain from eth_requestAccounts + eth_chainId - Auto-pick unused color when adding wallet - Remove chain dropdown and address input; add readonly displays - Rename localStorage key to tracked_wallets
This commit is contained in:
80
wallets.js
80
wallets.js
@ -33,12 +33,13 @@
|
||||
/* Constants */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
const LS_KEY = 'cbbtc_tracked_wallets';
|
||||
const LS_KEY = 'tracked_wallets';
|
||||
|
||||
/* Accepted chain identifiers */
|
||||
const VALID_CHAINS = new Set([
|
||||
'base', 'ethereum', 'bitcoin', 'arbitrum', 'optimism',
|
||||
'polygon', 'solana', 'avalanche', 'bsc', 'fantom', 'btc',
|
||||
'hyperliquide',
|
||||
]);
|
||||
|
||||
/* Regex patterns for address validation per chain */
|
||||
@ -52,6 +53,7 @@ const ADDRESS_PATTERNS = {
|
||||
avalanche: /^(0x)?[0-9a-fA-F]{40}$/i,
|
||||
bsc: /^(0x)?[0-9a-fA-F]{40}$/i,
|
||||
fantom: /^(0x)?[0-9a-fA-F]{40}$/i,
|
||||
hyperliquide: /^(0x)?[0-9a-fA-F]{40}$/i,
|
||||
|
||||
/* Bitcoin — bech32 or legacy pubkey hash */
|
||||
bitcoin: /^(bc1[a-z0-9]{25,39}|1[a-km-zA-HJ-NP-Z1-9]{25,34})$/,
|
||||
@ -113,37 +115,34 @@ export class WalletManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load wallets from localStorage.
|
||||
*
|
||||
* On first run returns an empty array. Restores any stored
|
||||
* entries — even if the browser was closed between sessions.
|
||||
*
|
||||
* Invariant: every wallet read from storage has `isVerified: false`
|
||||
* because a signature cannot survive an empty localStorage round-trip
|
||||
* without an accompanying non-empty `signature` field, and we
|
||||
* deliberately do NOT trust persisted signatures.
|
||||
*
|
||||
* @returns {TrackedWallet[]} loaded wallets
|
||||
*/
|
||||
loadWallets() {
|
||||
try {
|
||||
const raw = localStorage.getItem(LS_KEY);
|
||||
if (!raw) {
|
||||
this._wallets = [];
|
||||
return [];
|
||||
}
|
||||
/**
|
||||
* Load wallets from localStorage.
|
||||
*
|
||||
* On first run returns an empty array. Filters out any
|
||||
* unverified wallets — they never survive a page reload.
|
||||
* Only verified wallets (or non-verification-chain wallets that
|
||||
* are always implicitly verified) are retained.
|
||||
*
|
||||
* @returns {TrackedWallet[]} loaded wallets
|
||||
*/
|
||||
loadWallets() {
|
||||
try {
|
||||
const raw = localStorage.getItem(LS_KEY);
|
||||
if (!raw) {
|
||||
this._wallets = [];
|
||||
return [];
|
||||
}
|
||||
|
||||
const parsed = JSON.parse(raw);
|
||||
const parsed = JSON.parse(raw);
|
||||
|
||||
if (!Array.isArray(parsed)) {
|
||||
this._wallets = [];
|
||||
return [];
|
||||
}
|
||||
if (!Array.isArray(parsed)) {
|
||||
this._wallets = [];
|
||||
return [];
|
||||
}
|
||||
|
||||
/* Restore persisted state, including verification.
|
||||
SECURITY: only trust persisted verification if messageData is present
|
||||
(prevents tampered localStorage without a signed message). */
|
||||
/* Restore only verified wallets. Unverified wallets are discarded
|
||||
immediately — they were added but the user didn't complete the
|
||||
signature flow in time. */
|
||||
this._wallets = parsed
|
||||
.filter((w) => w && typeof w === 'object' && w.address && w.chain)
|
||||
.map((w) => ({
|
||||
@ -153,15 +152,24 @@ export class WalletManager {
|
||||
isVerified: !!(w.isVerified && w.messageData),
|
||||
signature: w.signature ? String(w.signature) : null,
|
||||
messageData: w.messageData ? w.messageData : null,
|
||||
}));
|
||||
}))
|
||||
.filter((w) => {
|
||||
/* Non-verification chains (btc, bitcoin, solana) are always kept */
|
||||
if (['btc', 'bitcoin', 'solana'].includes(w.chain)) return true;
|
||||
/* EVM chains: only keep if verified */
|
||||
return w.isVerified;
|
||||
});
|
||||
|
||||
return this._wallets;
|
||||
/* Persist the trimmed list so discarded unverified wallets don't
|
||||
reappear on subsequent reloads. */
|
||||
this._persist();
|
||||
return this._wallets;
|
||||
|
||||
} catch (_ignored) {
|
||||
this._wallets = [];
|
||||
return [];
|
||||
}
|
||||
}
|
||||
} catch (_ignored) {
|
||||
this._wallets = [];
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* CRUD */
|
||||
|
||||
Reference in New Issue
Block a user