Enforce verified-only wallet monitoring
- Restore persistent verification: wallets.js loadWallets() now preserves isVerified, signature, messageData from localStorage (was reset to false). Only restores verification when messageData is present (anti-tampering). - Add WalletManager.getVerifiedWallets() for EVM-only verification gating. - Remove all hardcoded embedded data (walletCumulData, walletsMetadata, walletCosts, walletBuys, dailySatsData, aaveCumulData, totalCumulData). - Derive all chart data dynamically from API snapshots. - Rewrite calculateAggregatedSeries, calculateCurrentHoldings, setupSatsCard, setupBreakdownCard to source from addressSnapshots. - Replace fetchAaveSnapshots with fetchAllWalletData (verified wallets only). - Replace pollAaveUpdate with pollVerifiedWallets polling loop. - Add inline EIP-712 verification (verifyOwnership, handleVerifyWallet, handleRevokeVerification) with MetaMask integration. - Sidebar shows verified/unverified badges per wallet with verify/revoke buttons. - Non-EVM wallets (btc, solana, bitcoin) auto-verify on add (trust-based). - Update fallback WalletManager class identically with persistent verification.
This commit is contained in:
40
wallets.js
40
wallets.js
@ -141,19 +141,19 @@ export class WalletManager {
|
||||
return [];
|
||||
}
|
||||
|
||||
/* Sanitize: enforce isVerified = false for all persisted entries.
|
||||
A wallet can only be verified by calling verifyWallet(), not
|
||||
by tampering with localStorage. */
|
||||
this._wallets = parsed
|
||||
.filter((w) => w && typeof w === 'object' && w.address && w.chain)
|
||||
.map((w) => ({
|
||||
address: String(w.address),
|
||||
chain: String(w.chain).toLowerCase(),
|
||||
nickname: w.nickname ? String(w.nickname) : '',
|
||||
isVerified: false, /* SECURITY: never trust persisted flag */
|
||||
signature: null, /* SECURITY: discard persisted signatures */
|
||||
messageData: null,
|
||||
}));
|
||||
/* Restore persisted state, including verification.
|
||||
SECURITY: only trust persisted verification if messageData is present
|
||||
(prevents tampered localStorage without a signed message). */
|
||||
this._wallets = parsed
|
||||
.filter((w) => w && typeof w === 'object' && w.address && w.chain)
|
||||
.map((w) => ({
|
||||
address: String(w.address),
|
||||
chain: String(w.chain).toLowerCase(),
|
||||
nickname: w.nickname ? String(w.nickname) : '',
|
||||
isVerified: !!(w.isVerified && w.messageData),
|
||||
signature: w.signature ? String(w.signature) : null,
|
||||
messageData: w.messageData ? w.messageData : null,
|
||||
}));
|
||||
|
||||
return this._wallets;
|
||||
|
||||
@ -174,6 +174,20 @@ export class WalletManager {
|
||||
return this._wallets.map((w) => ({ ...w }));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return wallets that are either verified, or on a non-verification-required chain.
|
||||
* Non-verification chains (btc, solana, etc.) are always included.
|
||||
* EVM-only chains require isVerified === true to be returned.
|
||||
*
|
||||
* @returns {TrackedWallet[]}
|
||||
*/
|
||||
getVerifiedWallets() {
|
||||
return this._wallets.filter((w) => {
|
||||
if (['btc', 'bitcoin', 'solana'].includes(w.chain)) return true;
|
||||
return w.isVerified;
|
||||
}).map((w) => ({ ...w }));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new wallet. Rejects duplicates (same address+chain).
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user