Skip to content

Commit fe299f8

Browse files
fix: findBySymbol not returning a token on multiple symbols (#3802)
* fix: fix token overrides not being respected When setting tokens from defaultInputs, findBySymbol was used which didn't take token overrides into account * refactor: rename util to be more explicit Renamed getTokenSymbol to getTokenDisplaySymbolByTokenAddress * fix: fix performModificationsIfToChainChanged to respect overrides * fix: support overrides in findBySymbol * fix: fix testnet not renaming WSOL * refactor: refactor tokens constructor, fixed tokenBridgeOriginalTokenId being undefined * fix: fix isTokenBridgeWrappedToken * revert: reverted tokenBridgeOriginalTokenId changes * revert: changes aren't needed * build: fix build * refactor: ensure gas token is returned if more than one symbol is found * revert: revert changes to performModificationsIfToChainChanged * refactor: reduce lines for wrappedToken
1 parent 9644a74 commit fe299f8

14 files changed

Lines changed: 117 additions & 71 deletions

File tree

src/config/testnet/tokens.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ export const TESTNET_TOKENS: TokenConfig[] = [
9696
tokenId: { chain: 'Solana', address: 'native' },
9797
},
9898
{
99-
symbol: 'WSOL',
99+
symbol: 'SOL',
100100
tokenId: {
101101
chain: 'Solana',
102102
address: 'So11111111111111111111111111111111111111112',

src/config/tokens.ts

Lines changed: 63 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,8 @@ import {
99
UniversalAddress,
1010
} from '@wormhole-foundation/sdk';
1111
import type { TokenIcon, TokenConfig, WrappedTokenAddresses } from './types';
12-
import { getWormholeContextV2 } from './index';
12+
import config, { getWormholeContextV2 } from './index';
1313
import { isValidSuiType } from '@wormhole-foundation/sdk-sui';
14-
1514
import { fetchTokenMetadata } from 'utils/coingecko';
1615

1716
const TOKEN_CACHE_VERSION = 1;
@@ -46,6 +45,16 @@ class TokenIdLazy<C extends Chain = Chain> implements TokenId<C> {
4645
return new TokenIdLazy(tuple[0], tuple[1]);
4746
}
4847
}
48+
type TokenConstructorProps = {
49+
chain: Chain;
50+
address: string;
51+
decimals: number;
52+
symbol: string;
53+
name?: string;
54+
icon?: TokenIcon | string;
55+
tokenBridgeOriginalTokenId?: TokenId;
56+
coingeckoId?: string;
57+
};
4958

5059
export class Token extends TokenIdLazy {
5160
decimals: number;
@@ -67,16 +76,16 @@ export class Token extends TokenIdLazy {
6776
// Used when filtering out unknown/unverified tokens
6877
isBuiltin?: boolean;
6978

70-
constructor(
71-
chain: Chain,
72-
address: string,
73-
decimals: number,
74-
symbol: string,
75-
name?: string,
76-
icon?: TokenIcon | string,
77-
tokenBridgeOriginalTokenId?: TokenId,
78-
coingeckoId?: string,
79-
) {
79+
constructor({
80+
chain,
81+
address,
82+
decimals,
83+
symbol,
84+
name,
85+
icon,
86+
tokenBridgeOriginalTokenId,
87+
coingeckoId,
88+
}: TokenConstructorProps) {
8089
super(chain, address);
8190
this.decimals = decimals;
8291
this.symbol = symbol;
@@ -158,18 +167,18 @@ export class Token extends TokenIdLazy {
158167
tokenBridgeOriginalTokenId,
159168
coingeckoWebId,
160169
}: TokenJson) {
161-
return new Token(
162-
chain as Chain,
170+
return new Token({
171+
chain: chain as Chain,
163172
address,
164173
decimals,
165174
symbol,
166175
name,
167-
icon === '' ? undefined : icon,
168-
tokenBridgeOriginalTokenId
176+
icon: icon === '' ? undefined : icon,
177+
tokenBridgeOriginalTokenId: tokenBridgeOriginalTokenId
169178
? tokenIdFromTuple(tokenBridgeOriginalTokenId)
170179
: undefined,
171-
coingeckoWebId,
172-
);
180+
coingeckoId: coingeckoWebId,
181+
});
173182
}
174183
}
175184

@@ -389,19 +398,33 @@ export class TokenCache extends TokenMapping<Token> {
389398
// This should be used sparingly/never... use addresses instead.
390399
// Excludes wrapped tokens
391400
findBySymbol(chain: Chain, symbol: string): Token | undefined {
392-
let matching = this.getAllForChain(chain).filter(
393-
(t) => t.symbol.toLowerCase() === symbol.toLowerCase(),
394-
);
401+
const chainOverrides = config.ui?.tokenNameOverrides?.[chain];
402+
const lowerCaseSymbol = symbol.toLowerCase();
403+
404+
let matching = this.getAllForChain(chain).filter((t) => {
405+
const symbolMatch = lowerCaseSymbol === t.symbol.toLowerCase();
406+
const overrideMatch =
407+
lowerCaseSymbol ===
408+
chainOverrides?.[t.address.toString()]?.toLowerCase();
409+
410+
return symbolMatch || overrideMatch;
411+
});
395412

396413
if (matching.length > 1) {
397414
// Exclude wrapped tokens if there's multiple matches
398-
matching = matching.filter((t) => !t.isTokenBridgeWrappedToken);
415+
matching = matching.filter((t) => {
416+
return !t.isTokenBridgeWrappedToken;
417+
});
399418
}
400419

401420
if (matching.length === 1) {
402421
return matching[0];
403422
} else if (matching.length > 1) {
404-
// This means there's more than one native token (not wrapped) with this symbol
423+
const gasToken = matching.find((t) => t.address === 'native');
424+
// This means there's more than one native token (not wrapped) with this symbol.
425+
// prefer the gas token if there are multiple tokens with the same symbol.
426+
if (gasToken) return gasToken;
427+
405428
console.error(`Ambiguous token symbol: ${symbol}`);
406429
}
407430

@@ -471,16 +494,16 @@ export class TokenCache extends TokenMapping<Token> {
471494
}
472495
}
473496

474-
const t = new Token(
475-
tokenId.chain,
476-
canonicalAddress(tokenId),
497+
const t = new Token({
498+
chain: tokenId.chain,
499+
address: canonicalAddress(tokenId),
477500
decimals,
478501
symbol,
479502
name,
480-
image,
503+
icon: image,
481504
tokenBridgeOriginalTokenId,
482505
coingeckoId,
483-
);
506+
});
484507

485508
this.add(t);
486509

@@ -538,16 +561,15 @@ export function buildTokenCache(
538561
cacheKey: string,
539562
): TokenCache {
540563
const cache = TokenCache.load(cacheKey);
541-
542564
for (const { tokenId, symbol, name, icon, decimals } of tokens) {
543-
const token = new Token(
544-
tokenId.chain,
545-
tokenId.address.toString(),
565+
const token = new Token({
566+
chain: tokenId.chain,
567+
address: tokenId.address.toString(),
546568
decimals,
547569
symbol,
548570
name,
549571
icon,
550-
);
572+
});
551573
token.isBuiltin = true;
552574
cache.add(token);
553575
}
@@ -567,16 +589,15 @@ export function buildTokenCache(
567589
chainToPlatform(otherChain as Chain) === 'Evm' ? 18 : 8;
568590

569591
decimals = Math.min(decimals, originalToken.decimals);
570-
571-
const wrappedToken = new Token(
572-
otherChain as Chain,
573-
wrappedAddr,
592+
const wrappedToken = new Token({
593+
chain: otherChain as Chain,
594+
address: wrappedAddr,
574595
decimals,
575-
originalToken.symbol,
576-
originalToken.name,
577-
originalToken.icon,
578-
originalToken,
579-
);
596+
symbol: originalToken.symbol,
597+
name: originalToken.name,
598+
icon: originalToken.icon,
599+
tokenBridgeOriginalTokenId: originalToken,
600+
});
580601
wrappedToken.isBuiltin = true;
581602

582603
cache.add(wrappedToken);

src/hooks/useTokenListWithSearch.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import type { Chain } from '@wormhole-foundation/sdk';
1111
import type { Token } from 'config/tokens';
1212
import config from 'config';
1313
import { useTokens } from 'contexts/TokensContext';
14-
import { getTokenSymbol } from 'utils';
14+
import { getTokenDisplaySymbolByTokenAddress } from 'utils';
1515
import {
1616
getWrappedNativeToken,
1717
shouldFilterSameChainToken,
@@ -119,7 +119,8 @@ export const useTokenListWithSearch = ({
119119

120120
if (deferredSearch) {
121121
tokens = tokens.filter((token) => {
122-
const overrideName = getTokenSymbol(token)?.toLowerCase();
122+
const overrideName =
123+
getTokenDisplaySymbolByTokenAddress(token)?.toLowerCase();
123124
const symbolMatch = token.symbol?.toLowerCase().includes(searchLower);
124125
const nameMatch = token.name?.toLowerCase().includes(searchLower);
125126
const overrideMatch = overrideName?.includes(searchLower);

src/utils/errors.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ import {
1515
} from 'telemetry/types';
1616
import { InsufficientFundsForGasError } from 'sdklegacy';
1717
import { routes, amount as sdkAmount } from '@wormhole-foundation/sdk';
18-
import { chainDisplayName, getGasToken, getTokenSymbol } from 'utils';
18+
import {
19+
chainDisplayName,
20+
getGasToken,
21+
getTokenDisplaySymbolByTokenAddress,
22+
} from 'utils';
1923

2024
// TODO SDKV2
2125
// attempt to capture errors using regex
@@ -86,7 +90,7 @@ export function interpretTransferError(
8690
const gasChain = transferDetails.fromChain;
8791
try {
8892
const gasToken = getGasToken(gasChain);
89-
const gasSymbol = getTokenSymbol(gasToken);
93+
const gasSymbol = getTokenDisplaySymbolByTokenAddress(gasToken);
9094
const chainName = chainDisplayName(gasChain);
9195
const chainSuffix = chainName ? ` on ${chainName}` : '';
9296
uiErrorMessage = `Insufficient ${gasSymbol} for fees${chainSuffix}. Please add more ${gasSymbol} and try again`;

src/utils/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ export function getGasToken(chain: Chain): Token {
6969
return gasToken;
7070
}
7171

72-
export function getTokenSymbol(token: Token): string {
72+
export function getTokenDisplaySymbolByTokenAddress(token: Token): string {
7373
const chainOverrides = config.ui?.tokenNameOverrides?.[token.chain];
7474

7575
if (!chainOverrides) {

src/views/v2/Bridge/AssetPicker/TokenItem.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ import TokenIcon from 'icons/TokenIcons';
1313
import type { Token } from 'config/tokens';
1414

1515
import type { Chain, amount as sdkAmount } from '@wormhole-foundation/sdk';
16-
import { chainDisplayName, getTokenExplorerUrl, getTokenSymbol } from 'utils';
16+
import {
17+
chainDisplayName,
18+
getTokenExplorerUrl,
19+
getTokenDisplaySymbolByTokenAddress,
20+
} from 'utils';
1721
import ChainIcon from 'icons/ChainIcons';
1822
import Color from 'color';
1923
import TokenBalance from 'components/TokenBalance';
@@ -72,7 +76,7 @@ function TokenItem(props: TokenItemProps) {
7276
const explorerURL = address ? getTokenExplorerUrl(chain, address) : '';
7377
const addressDisplay = `${token.shortAddress}`;
7478

75-
const displaySymbol = getTokenSymbol(token);
79+
const displaySymbol = getTokenDisplaySymbolByTokenAddress(token);
7680

7781
return (
7882
<ListItemButton

src/views/v2/Bridge/AssetPicker/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import TokenList from './TokenList';
2626
import AssetBadge from 'components/AssetBadge';
2727
import type { Token } from 'config/tokens';
2828
import { useTokenList } from 'hooks/useTokenList';
29-
import { getTokenSymbol } from 'utils';
29+
import { getTokenDisplaySymbolByTokenAddress } from 'utils';
3030
import {
3131
handleTelemetryOnChainSelect,
3232
handleTelemetryOnTokenSelect,
@@ -118,7 +118,7 @@ const AssetPicker = (props: Props) => {
118118
}
119119

120120
const tokenDisplay = props.token
121-
? getTokenSymbol(props.token)
121+
? getTokenDisplaySymbolByTokenAddress(props.token)
122122
: 'Select token';
123123

124124
return (

src/views/v3/Bridge/AssetPicker/TokenItem.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ import TokenIcon from 'icons/TokenIcons';
1313
import type { Token } from 'config/tokens';
1414

1515
import type { Chain, amount as sdkAmount } from '@wormhole-foundation/sdk';
16-
import { chainDisplayName, getTokenExplorerUrl, getTokenSymbol } from 'utils';
16+
import {
17+
chainDisplayName,
18+
getTokenExplorerUrl,
19+
getTokenDisplaySymbolByTokenAddress,
20+
} from 'utils';
1721
import ChainIcon from 'icons/ChainIcons';
1822
import Color from 'color';
1923
import TokenBalance from 'components/TokenBalance';
@@ -73,7 +77,7 @@ function TokenItem(props: TokenItemProps) {
7377
const explorerURL = address ? getTokenExplorerUrl(chain, address) : '';
7478
const addressDisplay = `${token.shortAddress}`;
7579

76-
const displaySymbol = getTokenSymbol(token);
80+
const displaySymbol = getTokenDisplaySymbolByTokenAddress(token);
7781

7882
return (
7983
<ListItemButton

src/views/v3/Bridge/AssetPicker/index.tsx

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import { OPACITY } from 'utils/style';
2828
import Color from 'color';
2929
import AssetPickerDrawer from 'views/v3/Bridge/AssetPicker/PickerBottomSheet';
3030
import AssetPickerPopover from 'views/v3/Bridge/AssetPicker/PickerModal';
31-
import { calculateUSDPrice, getTokenSymbol } from 'utils';
31+
import { calculateUSDPrice, getTokenDisplaySymbolByTokenAddress } from 'utils';
3232
import { formatWithCommas } from 'utils/formatNumber';
3333
import {
3434
handleTelemetryOnChainSelect,
@@ -104,7 +104,7 @@ function AssetPicker(props: Props) {
104104
return null;
105105
}
106106
const displayValue = `${sdkAmount.display(tokenBalance)} ${
107-
props.token ? getTokenSymbol(props.token) : ''
107+
props.token ? getTokenDisplaySymbolByTokenAddress(props.token) : ''
108108
}`;
109109
return (
110110
<Typography
@@ -161,7 +161,11 @@ function AssetPicker(props: Props) {
161161
const selection = useMemo(() => {
162162
return (
163163
<Tooltip
164-
title={props.token ? getTokenSymbol(props.token) : 'Select a token'}
164+
title={
165+
props.token
166+
? getTokenDisplaySymbolByTokenAddress(props.token)
167+
: 'Select a token'
168+
}
165169
>
166170
<Typography
167171
component="div"
@@ -170,7 +174,9 @@ function AssetPicker(props: Props) {
170174
maxWidth="64px"
171175
noWrap
172176
>
173-
{props.token ? getTokenSymbol(props.token) : 'Select'}
177+
{props.token
178+
? getTokenDisplaySymbolByTokenAddress(props.token)
179+
: 'Select'}
174180
</Typography>
175181
</Tooltip>
176182
);
@@ -398,7 +404,9 @@ function AssetPicker(props: Props) {
398404
color={theme.palette.text.secondary + OPACITY[50]}
399405
fontSize="12px"
400406
fontWeight={500}
401-
>{`1 ${getTokenSymbol(props.token)} = ${unitPrice}`}</Typography>
407+
>{`1 ${getTokenDisplaySymbolByTokenAddress(
408+
props.token,
409+
)} = ${unitPrice}`}</Typography>
402410
</Box>
403411
);
404412
}, [props.token, getTokenPrice, theme.palette.text.secondary]);

src/views/v3/Bridge/Routes/SingleRoute.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import Typography from '@mui/material/Typography';
1010
import Stack from '@mui/material/Stack';
1111
import type { routes } from '@wormhole-foundation/sdk';
1212
import { amount } from '@wormhole-foundation/sdk';
13-
import { getTokenSymbol } from 'utils';
13+
import { getTokenDisplaySymbolByTokenAddress } from 'utils';
1414

1515
import config from 'config';
1616
import { useGasSlider } from 'hooks/useGasSlider';
@@ -383,7 +383,7 @@ const SingleRoute = (props: Props) => {
383383
component="div"
384384
marginBottom="6px"
385385
>
386-
{receiveAmountTrunc} {getTokenSymbol(destToken)}
386+
{receiveAmountTrunc} {getTokenDisplaySymbolByTokenAddress(destToken)}
387387
</Typography>
388388
);
389389
}, [

0 commit comments

Comments
 (0)