fix: add a Settings toggle for known-symbol spoof verification (closes #176)
Some checks failed
check / check (push) Has been cancelled

This commit was merged in pull request #226.
This commit is contained in:
2026-08-11 15:38:05 +02:00
parent edea22f7ed
commit 74c137dadf
12 changed files with 234 additions and 28 deletions

View File

@@ -956,6 +956,15 @@
transfers and prevent interaction with suspicious
tokens.
</p>
<label
class="text-xs flex items-center gap-1 cursor-pointer mb-2"
>
<input
type="checkbox"
id="settings-hide-spoofed-symbols"
/>
Hide fake tokens impersonating a known symbol
</label>
<label
class="text-xs flex items-center gap-1 cursor-pointer mb-2"
>

View File

@@ -148,6 +148,7 @@ async function loadTransactions(address) {
state.blockscoutUrl,
);
const result = filterTransactions(rawTxs, {
hideSpoofedSymbols: state.hideSpoofedSymbols,
hideLowHolderTokens: state.hideLowHolderTokens,
hideFraudContracts: state.hideFraudContracts,
hideDustTransactions: state.hideDustTransactions,

View File

@@ -222,6 +222,7 @@ async function loadTransactions(address, tokenId) {
state.blockscoutUrl,
);
const result = filterTransactions(rawTxs, {
hideSpoofedSymbols: state.hideSpoofedSymbols,
hideLowHolderTokens: state.hideLowHolderTokens,
hideFraudContracts: state.hideFraudContracts,
hideDustTransactions: state.hideDustTransactions,

View File

@@ -163,6 +163,7 @@ async function loadHomeTxs(ctx) {
if (allAddresses.length === 0) return;
const filters = {
hideSpoofedSymbols: state.hideSpoofedSymbols,
hideLowHolderTokens: state.hideLowHolderTokens,
hideFraudContracts: state.hideFraudContracts,
hideDustTransactions: state.hideDustTransactions,

View File

@@ -303,6 +303,12 @@ function init(ctx) {
applyTheme(state.theme);
});
$("settings-hide-spoofed-symbols").checked = state.hideSpoofedSymbols;
$("settings-hide-spoofed-symbols").addEventListener("change", async () => {
state.hideSpoofedSymbols = $("settings-hide-spoofed-symbols").checked;
await saveState();
});
$("settings-hide-low-holders").checked = state.hideLowHolderTokens;
$("settings-hide-low-holders").addEventListener("change", async () => {
state.hideLowHolderTokens = $("settings-hide-low-holders").checked;

View File

@@ -21,6 +21,7 @@ const DEFAULT_STATE = {
deniedSites: {},
rememberSiteChoice: true,
showZeroBalanceTokens: true,
hideSpoofedSymbols: true,
hideLowHolderTokens: true,
hideFraudContracts: true,
hideDustTransactions: true,
@@ -61,6 +62,7 @@ async function saveState() {
deniedSites: state.deniedSites,
rememberSiteChoice: state.rememberSiteChoice,
showZeroBalanceTokens: state.showZeroBalanceTokens,
hideSpoofedSymbols: state.hideSpoofedSymbols,
hideLowHolderTokens: state.hideLowHolderTokens,
hideFraudContracts: state.hideFraudContracts,
hideDustTransactions: state.hideDustTransactions,
@@ -112,6 +114,12 @@ async function loadState() {
saved.showZeroBalanceTokens !== undefined
? saved.showZeroBalanceTokens
: true;
// A profile written before this setting existed has no key for it.
// It is a safety filter, so absent must load as on, not as undefined.
state.hideSpoofedSymbols =
saved.hideSpoofedSymbols !== undefined
? saved.hideSpoofedSymbols
: true;
state.hideLowHolderTokens =
saved.hideLowHolderTokens !== undefined
? saved.hideLowHolderTokens

View File

@@ -267,12 +267,19 @@ function filterTransactions(txs, filters = {}) {
const dustThresholdGwei = filters.dustThresholdGwei ?? 100000;
const newFraud = [];
const filtered = [];
// Fail-safe, unlike the three flags below: this one is off only when the
// caller says so explicitly, so a caller that omits the key keeps the
// check rather than silently losing it. The setting also governs the
// blocklist learning below, which exists only to serve this check —
// leaving learning on while the check is off would re-hide the very rows
// the user asked to see, through the fraud-contract rule.
const hideSpoofed = filters.hideSpoofedSymbols !== false;
for (const tx of txs) {
const contract = normalizeAddress(tx.contractAddress);
// Always filter spoofed known symbols and record the fraud contract
if (isSpoofedSymbol(tx)) {
// Filter spoofed known symbols and record the fraud contract
if (hideSpoofed && isSpoofedSymbol(tx)) {
if (contract && !fraudSet.has(contract)) {
fraudSet.add(contract);
newFraud.push(contract);