Skip to content

Commit 940e33f

Browse files
fix(token-lists): drop tokens whose chainId is absent from viem/chains
@uniswap/default-token-list still ships tokens for Ropsten (chainId 3) and Rinkeby (chainId 4), both removed from viem/chains. combineTokenLists caught the buildNativeToken throw but logged it via console.error before ignoring it, producing noise on every cold load. Extend the existing safeParse filter to also drop tokens whose chainId is not present in viem/chains, mirroring the existing non-EVM drop. This removes the throw at source and keeps tokensByChainId free of unreachable buckets. Closes #465
1 parent bec0209 commit 940e33f

2 files changed

Lines changed: 30 additions & 3 deletions

File tree

src/hooks/useTokenLists.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,29 @@ describe('useTokenLists', () => {
222222
expect(nativeToken?.symbol).toBe('ETH')
223223
})
224224

225+
it('filters out tokens whose chainId is not present in viem/chains and does not log', () => {
226+
// biome-ignore lint/suspicious/noExplicitAny: mocking internal combine param
227+
vi.mocked(tanstackQuery.useSuspenseQueries).mockImplementation(({ combine }: any) => {
228+
const ropstenToken: Token = {
229+
address: '0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6',
230+
chainId: 3,
231+
decimals: 18,
232+
name: 'Wrapped Ether (Ropsten)',
233+
symbol: 'WETH',
234+
}
235+
return combine([mockSuspenseQueryResult([mockToken1, ropstenToken])])
236+
})
237+
238+
const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
239+
const { result } = renderHook(() => useTokenLists(), { wrapper })
240+
241+
expect(result.current.tokens.some((t) => t.chainId === 3)).toBe(false)
242+
expect(result.current.tokensByChainId[3]).toBeUndefined()
243+
expect(errorSpy).not.toHaveBeenCalled()
244+
245+
errorSpy.mockRestore()
246+
})
247+
225248
it('filters out tokens that fail schema validation', () => {
226249
// biome-ignore lint/suspicious/noExplicitAny: mocking internal combine param
227250
vi.mocked(tanstackQuery.useSuspenseQueries).mockImplementation(({ combine }: any) => {

src/hooks/useTokenLists.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,14 @@ function combineTokenLists(results: Array<UseSuspenseQueryResult<TokenList>>): T
110110
.flatMap((result) => result.data.tokens)
111111
// tokenSchema enforces EVM address format (0x + 40 hex chars), so non-EVM entries
112112
// (e.g. Solana tokens from @uniswap/default-token-list v18+) are silently dropped here.
113+
// Tokens whose chainId is not present in viem/chains (e.g. deprecated testnets like
114+
// Ropsten/Rinkeby still shipped by @uniswap/default-token-list) are also dropped so
115+
// buildNativeToken never throws and tokensByChainId stays free of unreachable buckets.
113116
// Supporting non-EVM chains would require changes to the address schema, chain config,
114117
// wallet integration, and contract lookup -- out of scope for this EVM-focused starter kit.
115118
.filter((token) => {
116-
const result = tokenSchema.safeParse(token)
117-
118-
return result.success
119+
if (!tokenSchema.safeParse(token).success) return false
120+
return supportedChainIds.has(token.chainId)
119121
})
120122
.map((token) => [tokenKey(token), token]),
121123
).values(),
@@ -201,6 +203,8 @@ export async function fetchTokenList(url: string): Promise<TokenList> {
201203
}
202204
}
203205

206+
const supportedChainIds = new Set<number>(Object.values(chains).map((c) => c.id))
207+
204208
/**
205209
* Builds a native token object based on the chain ID.
206210
*

0 commit comments

Comments
 (0)