Skip to content

fix(swap): flag symbol-squatter tokens impersonating native coins#354

Merged
BitHighlander merged 1 commit into
developfrom
fix/swap-symbol-squatter
Jul 15, 2026
Merged

fix(swap): flag symbol-squatter tokens impersonating native coins#354
BitHighlander merged 1 commit into
developfrom
fix/swap-symbol-squatter

Conversation

@BitHighlander

Copy link
Copy Markdown
Collaborator

A token that self-declares a major chain's ticker/name — e.g. an Ethereum ERC-20 whose symbol is SOLANA (real case: eip155:1/erc20:0x3d8063…, name BarbieCrashBandicootRFK88) — rendered in the swap asset cards with the native coin's logo + symbol. The UI trusts the token's self-declared symbol and the server-supplied icon, so a squatter inherits real-asset branding and it becomes unclear which asset you're actually swapping.

Fix

The CAIP namespace is the source of truth: the genuine native asset is always a /slip44: CAIP, never a token.

  • shared/symbolSquatter.tsisSymbolSquatter(caip, symbol): true when a non-native CAIP (parseCaip().isToken) wears a major chain identity and is not the catalogued/known asset for that CAIP. The catalog check means legit L1s that live as ERC-20s (e.g. MATIC) are not flagged. Fails open while the asset catalog is still loading.
  • shared/assetLookup.tsisAssetMapReady() + isKnownAsset() helpers.
  • SwapDialog AssetSelector (both PAY and RECEIVE cards) — on a squatter: drop the borrowed server icon (falls back to CAIP/letter bubble, so it can no longer show the native logo), red ring, and a clear "not the native coin — verify the contract" warning.
  • GreenCountUp — wrap prefix/suffix in whiteSpace:pre; inline-flex was collapsing the leading space and gluing the amount to the symbol (…291.85SOLANA).

Tests / verification

  • shared/symbolSquatter.test.ts covers the detection (scam ERC-20 → flagged; native slip44 → not; catalogued MATIC ERC-20 → not; loading → fails open). Passes.
  • Typecheck: no new errors (differential 0).
  • Visual smoke on-device pending (make vault).

Notes: detection uses a curated set of commonly-squatted major-chain identities (marked ponytail: for extension). Applied to the main swap asset cards; extending the same flag to the picker rows is a natural follow-up.

…ding

A token that self-declares a major chain's ticker/name (e.g. an Ethereum
ERC-20 whose symbol is "SOLANA") was rendered in the swap asset cards with
the native coin's logo + symbol, because the UI trusts the token's
self-declared symbol and the server-supplied icon. That lets scam/squatter
tokens impersonate real assets and confuses which asset a user is swapping.

- shared/symbolSquatter.ts: detect a non-native CAIP (parseCaip.isToken) that
  wears a major chain identity AND is not the catalogued/known asset for that
  CAIP (so legit L1-as-ERC20s like MATIC are not flagged). Fails open while the
  asset catalog is still loading.
- shared/assetLookup.ts: isAssetMapReady() + isKnownAsset() catalog helpers.
- SwapDialog AssetSelector: on a squatter, drop the borrowed server icon (falls
  back to CAIP/letter), red ring, and a clear 'not the native coin' warning.
- GreenCountUp: wrap prefix/suffix in whiteSpace:pre — inline-flex was
  collapsing the leading space, gluing amount to symbol ('...291.85SOLANA').

Detection covered by shared/symbolSquatter.test.ts.
@BitHighlander BitHighlander merged commit ff015d0 into develop Jul 15, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant