Skip to content

fix: route-label token address rules never match integrator config addresses - #862

Open
gomesalexandre wants to merge 2 commits into
lifinance:mainfrom
gomesalexandre:fix_route_label_address_casing
Open

fix: route-label token address rules never match integrator config addresses#862
gomesalexandre wants to merge 2 commits into
lifinance:mainfrom
gomesalexandre:fix_route_label_address_casing

Conversation

@gomesalexandre

Copy link
Copy Markdown

What it says on the box

routeLabels' fromTokenAddress/toTokenAddress rules never match unless the integrator writes their config address in the exact EIP-55 checksummed case the LI.FI API returns.

The bug

getMatchingLabels.ts compared config addresses against route.fromToken.address/route.toToken.address via case-sensitive Array.includes:

conditions.push(rule.fromTokenAddress.includes(route.fromToken.address))

The LI.FI API always returns mixed-case (checksummed) EVM addresses. A live quote confirms this — fromToken.address / toToken.address come back checksummed on every response I checked. Config addresses are commonly written lowercase, and this repo's own default example config does exactly that:

// packages/widget-playground/src/defaultWidgetConfig.ts:143
address: '0x195e3087ea4d7eec6e9c37e9640162fe32433d5e',

So a rule using that config's own address would silently never match.

Why it went unnoticed

Every other config-address-vs-API-address comparison in this package lowercases both sides first (utils/token.ts, useTokenSearch.ts, useToken.ts, useTokenBalances.ts, utils/tokenList.ts, pinnedTokens). This file was the one exception - and the only one with no test coverage. The sibling fromChainId/toChainId criteria in the same rule are numeric, so they're case-free and kept passing while the address criterion silently failed next to them.

Related prior art with the same root-cause class (address-casing mismatch), different location: #165.

Fix

Compare EVM addresses (0x-prefixed, 40 hex chars) case-insensitively; fall back to exact string comparison for everything else. This widget supports Solana, Bitcoin, Sui, Tron and Stellar alongside EVM chains, and several of those use genuinely case-sensitive identifiers (Solana base58 addresses, Sui coin types) - blanket-lowercasing every token identifier would introduce a new false-positive-match bug on those chains. Codex's adversarial review caught exactly this on the first pass; the fix and the added non-EVM regression test both reflect it.

Scope

routeLabels is opt-in integrator config. Labels are purely display/cosmetic - no effect on route ordering, selection, or amounts. No fund impact. Not reachable through the default widget configuration shipped to end users with no custom config.

receipts

$ npx vitest run src/components/RouteCard/getMatchingLabels.test.ts
 Test Files  1 passed (1)
      Tests  5 passed (5)

$ npx vitest run   # full widget package suite
 Test Files  10 passed (10)
      Tests  89 passed (89)   # was 84, +5 new

$ npx tsc --noEmit -p tsconfig.json
(clean, 0 errors)

$ npx biome check src/components/RouteCard/getMatchingLabels.ts src/components/RouteCard/getMatchingLabels.test.ts
Checked 2 files. No fixes needed.

Red-before/green-after verified genuinely: the new non-EVM regression test fails against a naive blanket-.toLowerCase() fix (the exact gap Codex flagged) and passes only against the correctly EVM-scoped fix in this diff.

Codex (gpt-5.6-sol) ran adversarially against the diff and found one real P2 (the EVM-scoping gap above, applied) plus a test-wording nit (also applied). No other issues.

…dresses

routeLabels' fromTokenAddress/toTokenAddress rules were compared to
route.fromToken.address / route.toToken.address via case-sensitive
Array.includes(). The LI.FI API always returns EIP-55 checksummed
(mixed-case) EVM addresses, so any config address that isn't written
in the exact checksummed form silently never matches - including this
repo's own default example config, which writes at least one address
lowercase.

Every other config-address vs API-address comparison in this package
lowercases both sides before comparing; this was the one exception,
and the only one with no test coverage.

Fix compares EVM addresses (0x-prefixed, 40 hex chars) case-insensitively,
and falls back to exact comparison for everything else - non-EVM chains
(Solana base58, Sui coin types, etc.) use case-sensitive identifiers and
must not be case-folded.

Scope: routeLabels is an opt-in integrator config feature; labels are
purely display/cosmetic with no effect on route selection or amounts.
Not reachable through the default widget configuration.
@changeset-bot

changeset-bot Bot commented Sep 2, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 2f70e59

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 20 packages
Name Type
@lifi/widget Patch
@lifi/widget-checkout Patch
connectkit Patch
deposit-flow Patch
dynamic Patch
nextjs Patch
nextjs15 Patch
nft-checkout Patch
nuxt-app Patch
privy-ethers-example Patch
privy Patch
rainbowkit Patch
react-router Patch
remix Patch
reown Patch
svelte Patch
tanstack-router-example Patch
vite-project Patch
vue Patch
zustand-widget-config Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@gomesalexandre
gomesalexandre marked this pull request as ready for review September 2, 2026 03:56
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