Skip to content

honor tokens-to-return on /address token balances#1441

Open
pragmaxim wants to merge 1 commit intomasterfrom
evm-address-nonzero-token-filter
Open

honor tokens-to-return on /address token balances#1441
pragmaxim wants to merge 1 commit intomasterfrom
evm-address-nonzero-token-filter

Conversation

@pragmaxim
Copy link
Copy Markdown
Contributor

@pragmaxim pragmaxim commented Mar 26, 2026

Problem

Before this PR, Blockbook parsed tokens=nonzero|used|derived for address requests, but the EVM address path did not actually honor that filter.

EVM address token filtering is inconsistent with xpub filtering :

  • getAccountInfo and /api/v2/address parses tokens=nonzero|used|derived but the EVM address path ignored those modes during token assembly.
  • Zero-balance ERC20s and empty ERC721/ERC1155 contracts could remain in address responses even when callers wanted current holdings only.

Solution

Apply token-mode filtering directly in the EVM address token assembly path :

  • Add explicit rules for ERC20, ERC721, and ERC1155 so tokens=nonzero is honored on the EVM address path.
  • Preserve the legacy omission of metadata-only ERC721/ERC1155 contracts for tokens=used and tokens=derived to stay compatible with current websocket consumers.

Behavior after change

ERC20

  • tokens=nonzero: now works properly. Zero-balance ERC20s are excluded when holdings are available.
  • tokens=used / tokens=derived: zero-balance ERC20s are still included, to preserve legacy behavior.
  • Net effect: the real functional fix for ERC20 is that nonzero finally means nonzero.

ERC721 / ERC1155

  • tokens=nonzero: now works properly.
  • ERC721 is included only if it has ids.
  • ERC1155 is included only if it has multiTokenValues with holdings.
  • tokens=used / tokens=derived: empty NFT-style contracts are still omitted, preserving previous address-path behavior.
  • Net effect: nonzero becomes correct, but compatibility is kept for websocket/default consumers by not surfacing metadata-only empty NFT contracts.

One caveat

  • For details=tokens, current holdings are not fetched, so tokens=nonzero behaves like used. That is documented in docs/api.md (line 479).

Practical summary

  • ERC20: stricter and more correct for nonzero.
  • ERC721/ERC1155: stricter for nonzero, but intentionally compatibility-preserving for used / derived.
  • contract= history behavior remains intact even if a token is filtered out of the tokens list.

Test Commands

  • go test -tags unittest ./api -run 'TestHasEthereumTokenHoldingsField|TestHasEthereumTokenNonzeroHoldings|TestShouldIncludeEthereumAddressToken' -count=1
  • go test -tags unittest ./api -run 'TestHasEthereumTokenNonzeroHoldings|TestShouldIncludeEthereumAddressToken' -count=1
  • go test -tags unittest ./server -run 'TestGetAddressQueryParamsParsesDocumentedAddressOptions' -count=1
  • go test -tags unittest ./api -count=1
  • go test -tags unittest ./server -count=1

@pragmaxim pragmaxim force-pushed the evm-address-nonzero-token-filter branch from 2bb4e64 to ed9bed5 Compare March 26, 2026 07:26
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