Skip to content

EVM NFTs: query Ethereum, Polygon and Base for every EVM address - #18

Merged
Tarrant64 merged 1 commit into
mainfrom
fix/evm-nft-fanout
Sep 29, 2026
Merged

Tarrant64 merged 1 commit into
mainfrom
fix/evm-nft-fanout

Conversation

@Tarrant64

Copy link
Copy Markdown
Owner

Why split from #17

An independent review of #17 (fix/evm-multichain-fanout) blocked it: the
balance/token fan-out half is wrong (native coin double-counted on every
/portfolio/summary consumer; spam ERC-20 tokens priced by their raw
on-chain symbol with no allowlist or ignore-list check — a live probe found
one spam "USDC" on Base worth more than all the legitimate fan-out value
combined). The same review judged the NFT fan-out half correct and
recommended shipping it alone while the balance half is reworked.

Full review: http://192.168.50.240/data/2026-09-28/ABCT-PR17-REVIEW-2026-09-28.html

What's included

Wallets are stored one-row-per-(address, blockchain), and a bare 0x
address is always filed as ethereum (detect_blockchain only assigns
polygon/base from an explicit polygon:0x.../base:0x... prefix).
/nfts/polygon and /nfts/base only ever asked Alchemy about addresses
whose own row already said that chain, so a real Polygon/Base holder
registered as ethereum was invisible to those pages.

What's excluded

services/evm_balance_fanout.py and the routers/portfolio.py balance-total
wiring are entirely excluded from this PR — that's the half the review
blocked. It is not touched in any file here; git diff origin/main --stat
below lists only NFT files. The 6 balance-fan-out unit tests from #17's
test_evm_fanout.py are also excluded (they exercise
services/evm_balance_fanout.py, which does not exist on this branch).

 CHANGELOG.md                          |  1 +
 backend/routers/nfts.py               | 37 +++++++++++----------
 backend/services/alchemy_nft_utils.py | 62 +++++++++++++++++++++++++++++++++++
 backend/services/base.py              | 34 ++++++++++++++++---
 backend/services/ethereum_nft.py      | 56 ++++++++++++++++++++++++++-----
 backend/services/polygon.py           | 34 ++++++++++++++++---
 6 files changed, 190 insertions(+), 34 deletions(-)

Tests

  • tests/unit/test_evm_fanout.py: 8/8 pass.
  • Full suite (timeout 1200 pytest tests -q, same venv the EVM: query Ethereum, Polygon and Base for every EVM address #17 review used —
    /home/ccata/Claude/ABCT-worktrees/_venv-review-17): 540 passed, 9 failed.
    The same 9 failures are present on main (8× sqlite3.OperationalError: no such table: token_metadata_cache, 1× missing PIL/Pillow dependency) —
    no new failures introduced.
  • tests/unit/test_wallet_leak_check.py (including
    test_real_repo_tree_is_clean): 26/26 pass.

Totals unchanged by this PR — no balance, token-count, or portfolio-total
code is touched. NFT counts on the Polygon/Base pages will increase (the bug
this PR fixes), and NFT value only reaches the portfolio total if the user
has "include NFTs in total" turned on (off by default).

🤖 Generated with Claude Code

Split out of PR #17 (fix/evm-multichain-fanout) after independent review
found its balance/token fan-out half wrong (native coin double-counted,
spam ERC-20s priced by raw on-chain symbol) while judging the NFT half
correct: http://192.168.50.240/data/2026-09-28/ABCT-PR17-REVIEW-2026-09-28.html

Wallets are stored one-row-per-(address, blockchain), and a bare 0x
address is always filed as 'ethereum' (utils/address.detect_blockchain
only assigns polygon/base from an explicit prefixed address). /nfts/polygon
and /nfts/base only ever asked Alchemy about addresses whose own row
already said that chain, so a real Polygon/Base holder registered as
'ethereum' was invisible. Every EVM-family wallet (ethereum/polygon/base/
bsc/arbitrum/avalanche) is now a candidate address for Ethereum, Polygon
and Base NFT fetches, deduplicated by address, with the existing spam
filter, persistent cache and wipe-guard-on-provider-failure behaviour
(#11/#16) plus the #16 wallet-set-fingerprint cache invalidation extended
to Ethereum/Polygon/Base.

Excludes services/evm_balance_fanout.py and the routers/portfolio.py
balance-total wiring entirely -- that half is being reworked separately.
Totals are unaffected by this PR.

8 unit tests in tests/unit/test_evm_fanout.py (mocked HTTP/DB, fake
addresses, no live calls or real keys).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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