Skip to content

Commit 0550838

Browse files
authored
Globally Replace WSOL with SOL (#3786)
* fix: update SOL/WSOL display logic and block native-wrapped same-chain swaps * chore: clean up section header logic * chore: minor name and function cleanup * chore: prevent native and wrapped token swaps on same chain
1 parent 59ec738 commit 0550838

10 files changed

Lines changed: 102 additions & 67 deletions

File tree

src/config/mainnet/tokens.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ export const MAINNET_TOKENS: TokenConfig[] = [
235235
tokenId: { chain: 'Solana', address: 'native' },
236236
},
237237
{
238-
symbol: 'WSOL',
238+
symbol: 'SOL',
239239
decimals: 9,
240240
tokenId: {
241241
chain: 'Solana',

src/hooks/useFetchSupportedRoutes.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ const useFetchSupportedRoutes = ({
5858

5959
try {
6060
supported = await route.isRouteSupported(
61-
name,
6261
sourceToken,
6362
destToken,
6463
fromChain,

src/hooks/useTokenListWithSearch.ts

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ import type { Token } from 'config/tokens';
1212
import config from 'config';
1313
import { useTokens } from 'contexts/TokensContext';
1414
import { getTokenSymbol } from 'utils';
15-
import type { Balances } from 'utils/wallet/types';
15+
import {
16+
getWrappedNativeToken,
17+
shouldFilterSameChainToken,
18+
} from 'utils/wrappedNativeTokens';
1619
import { unionBy } from 'es-toolkit';
1720

1821
interface UseTokenListWithSearchParams {
@@ -22,8 +25,6 @@ interface UseTokenListWithSearchParams {
2225
isSource: boolean;
2326
isSameChainSwap: boolean;
2427
sourceToken?: Token;
25-
balances: Balances;
26-
walletAddress: string;
2728
tokenPastingEnabled?: boolean;
2829
}
2930

@@ -46,8 +47,6 @@ export const useTokenListWithSearch = ({
4647
isSource,
4748
isSameChainSwap,
4849
sourceToken,
49-
balances,
50-
walletAddress,
5150
tokenPastingEnabled = true,
5251
}: UseTokenListWithSearchParams): UseTokenListWithSearchReturn => {
5352
const [searchedTokens, setSearchedTokens] = useState<Token[]>([]);
@@ -60,6 +59,15 @@ export const useTokenListWithSearch = ({
6059
setSearchedTokens((prev) => [...prev, token]);
6160
}, []);
6261

62+
// Get wrapped native address for same-chain swaps (only for destination selection)
63+
const wrappedNativeAddr = useMemo(() => {
64+
if (!isSameChainSwap || !chain || isSource) {
65+
return undefined;
66+
}
67+
const wrapped = getWrappedNativeToken(config.network, chain);
68+
return wrapped?.toLowerCase();
69+
}, [isSameChainSwap, chain, isSource]);
70+
6371
useEffect(() => {
6472
if (!chain || !tokenPastingEnabled || !deferredSearch) {
6573
setSearchedTokens([]);
@@ -139,10 +147,10 @@ export const useTokenListWithSearch = ({
139147
});
140148
}
141149

142-
// For destination token list in same-chain swaps, filter out the source token
143-
if (!isSource && isSameChainSwap && sourceToken) {
150+
// For destination token list in same-chain swaps, filter out invalid options
151+
if (sourceToken && isSameChainSwap && !isSource) {
144152
tokens = tokens.filter(
145-
(t) => t.addressString !== sourceToken.addressString,
153+
(t) => !shouldFilterSameChainToken(sourceToken, wrappedNativeAddr, t),
146154
);
147155
}
148156

@@ -152,9 +160,10 @@ export const useTokenListWithSearch = ({
152160
searchedTokens,
153161
deferredSearch,
154162
searchLower,
155-
isSource,
156-
isSameChainSwap,
157163
sourceToken,
164+
isSameChainSwap,
165+
isSource,
166+
wrappedNativeAddr,
158167
]);
159168

160169
const tokenPrices = useMemo(

src/routes/operator.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,9 @@ export default class RouteOperator {
146146
): Promise<TokenId[]> {
147147
const supported: Set<string> = new Set();
148148

149-
await this.forEach(async (name, route) => {
149+
await this.forEach(async (_, route) => {
150150
try {
151151
const destTokenIds = await route.supportedDestTokens(
152-
name,
153152
sourceToken,
154153
sourceChain,
155154
destChain,

src/routes/sdkv2/route.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ import config, { getWormholeContextV2 } from 'config';
2121
import { sleep } from 'utils';
2222
import { isFrankensteinToken } from 'utils';
2323
import { isNttToken } from 'utils/ntt';
24+
import {
25+
getWrappedNativeToken,
26+
shouldFilterSameChainToken,
27+
} from 'utils/wrappedNativeTokens';
2428

2529
type Amount = sdkAmount.Amount;
2630

@@ -61,7 +65,6 @@ export class SDKv2Route {
6165
}
6266

6367
async isRouteSupported(
64-
name: string,
6568
sourceToken: Token,
6669
destToken: Token,
6770
fromChain: Chain,
@@ -88,7 +91,6 @@ export class SDKv2Route {
8891

8992
try {
9093
const supportedDestinationTokens = await this.supportedDestTokens(
91-
name,
9294
sourceToken,
9395
fromChain,
9496
toChain,
@@ -108,7 +110,6 @@ export class SDKv2Route {
108110
}
109111

110112
async supportedDestTokens(
111-
routeName: string,
112113
sourceToken: Token | undefined,
113114
fromChain?: Chain | undefined,
114115
toChain?: Chain | undefined,
@@ -148,14 +149,19 @@ export class SDKv2Route {
148149
routeSupportedTokenFetcher,
149150
);
150151

152+
// Get wrapped native address for same-chain swaps
153+
const wrappedNativeAddr = isSameChain
154+
? getWrappedNativeToken(config.network, toContext.chain)?.toLowerCase()
155+
: undefined;
156+
151157
const filteredTokens = destTokens.filter((t) => {
152158
const token = config.tokens.get(t);
153159
if (token && isFrankensteinToken(token, toContext.chain)) {
154160
return false;
155161
}
156162

157-
if (isSameChain && token?.address === sourceToken.address) {
158-
return false;
163+
if (isSameChain) {
164+
return !shouldFilterSameChainToken(sourceToken, wrappedNativeAddr, t);
159165
}
160166

161167
return true;

src/utils/sdkv2.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
TBTCBridge,
2222
chainToPlatform,
2323
} from '@wormhole-foundation/sdk';
24+
import { getWrappedNativeToken } from './wrappedNativeTokens';
2425
import type { NttRoute } from '@wormhole-foundation/sdk-route-ntt';
2526
import type { CCTPv2ExecutorRoute } from '@wormhole-labs/cctp-executor-route';
2627
import { Connection } from '@solana/web3.js';
@@ -559,10 +560,10 @@ const getTokenBridgeToken = async (
559560
address: token.address,
560561
});
561562

562-
const wrappedNative = await tb.getWrappedNative();
563+
const wrappedNative = getWrappedNativeToken(config.network, chain);
563564

564565
const tokenId =
565-
wrappedNative.toString() === tokenAddress.toString()
566+
wrappedNative && wrappedNative === tokenAddress.toString()
566567
? nativeTokenId(chain)
567568
: Wormhole.tokenId(chain, tokenAddress.toString());
568569

src/utils/wrappedNativeTokens.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import type { Chain, Network, TokenAddress } from '@wormhole-foundation/sdk';
2+
import { chainToPlatform, isNative } from '@wormhole-foundation/sdk';
3+
import { WETH_CONTRACTS } from '@wormhole-foundation/sdk-evm';
4+
5+
const WSOL_ADDRESS = 'So11111111111111111111111111111111111111112';
6+
7+
export function getWrappedNativeToken(
8+
network: Network,
9+
chain: Chain,
10+
): string | undefined {
11+
const platform = chainToPlatform(chain);
12+
13+
if (platform === 'Evm') {
14+
return WETH_CONTRACTS[network]?.[chain];
15+
}
16+
17+
if (platform === 'Solana') {
18+
return WSOL_ADDRESS;
19+
}
20+
21+
return undefined;
22+
}
23+
24+
/**
25+
* Determines if a token should be filtered out in same-chain swaps
26+
* based on native/wrapped token pair restrictions
27+
*/
28+
export function shouldFilterSameChainToken(
29+
sourceToken: { address: TokenAddress<Chain> } | null,
30+
wrappedNativeAddr: string | undefined,
31+
currentToken: { address: TokenAddress<Chain> },
32+
): boolean {
33+
if (!sourceToken) {
34+
return false;
35+
}
36+
37+
const sourceAddr = sourceToken.address.toString();
38+
const currentAddr = currentToken.address.toString();
39+
40+
if (currentAddr === sourceAddr) {
41+
return true;
42+
}
43+
44+
// Block native-wrapped token pairs if we have wrapped native address
45+
if (wrappedNativeAddr) {
46+
const srcIsNative = isNative(sourceToken.address);
47+
const srcIsWrapped = sourceAddr.toLowerCase() === wrappedNativeAddr;
48+
49+
const destIsWrapped = currentAddr.toLowerCase() === wrappedNativeAddr;
50+
const destIsNative = isNative(currentToken.address);
51+
52+
if ((srcIsNative && destIsWrapped) || (srcIsWrapped && destIsNative)) {
53+
return true;
54+
}
55+
}
56+
57+
return false;
58+
}

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,6 @@ const TokenList = (props: Props) => {
4242
isSource: props.isSource,
4343
isSameChainSwap: props.isSameChainSwap,
4444
sourceToken: props.sourceToken,
45-
balances: props.balances,
46-
walletAddress: props.wallet.address,
4745
tokenPastingEnabled: tokenPastingIsEnabled,
4846
});
4947

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

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,6 @@ const TokenList = (props: Props) => {
4242
isSource: props.isSource,
4343
isSameChainSwap: props.isSameChainSwap,
4444
sourceToken: props.sourceToken,
45-
balances: props.balances,
46-
walletAddress: props.wallet.address,
4745
tokenPastingEnabled: tokenPastingIsEnabled,
4846
});
4947

@@ -78,15 +76,6 @@ const TokenList = (props: Props) => {
7876
tokenListContainer: {
7977
padding: '16px 0 0 0 !important',
8078
},
81-
title: {
82-
fontSize: 14,
83-
marginBottom: '8px',
84-
},
85-
tokenLoaderRow: {
86-
display: 'flex',
87-
justifyContent: 'space-between',
88-
padding: '8px 16px',
89-
},
9079
tokenList: {
9180
maxHeight: '360px',
9281
[theme.breakpoints.down('sm')]: {
@@ -147,15 +136,17 @@ const TokenList = (props: Props) => {
147136
const isRestSection =
148137
isGroupingEnabled && isWalletConnected && index >= ownedCount;
149138

139+
const headerLabel = (() => {
140+
if (!isGroupingEnabled) return null;
141+
if (index === 0 && ownedCount > 0) return 'Your tokens';
142+
if (index === ownedCount) return 'All tokens';
143+
return null;
144+
})();
145+
150146
return (
151147
<Fragment key={token.key}>
152-
<TokenSectionHeader
153-
index={index}
154-
ownedCount={ownedCount}
155-
isGroupingEnabled={isGroupingEnabled}
156-
/>
148+
{headerLabel && <TokenSectionHeader label={headerLabel} />}
157149
<TokenItem
158-
key={token.key}
159150
token={token}
160151
chain={props.selectedChainConfig.sdkName}
161152
onClick={() => props.onSelectToken(token)}

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

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,9 @@ import { Box, useTheme } from '@mui/material';
22
import { Typography } from '@mui/material';
33
import React from 'react';
44

5-
const TokenSectionHeader = ({
6-
index,
7-
ownedCount,
8-
isGroupingEnabled,
9-
}: {
10-
index: number;
11-
ownedCount: number;
12-
isGroupingEnabled: boolean;
13-
}) => {
5+
const TokenSectionHeader = ({ label }: { label: string }) => {
146
const theme = useTheme();
157

16-
if (!isGroupingEnabled) {
17-
return null;
18-
}
19-
20-
let label: string | null = null;
21-
22-
if (index === 0 && ownedCount > 0) {
23-
label = 'Your tokens';
24-
}
25-
26-
if (index === ownedCount) {
27-
label = 'All tokens';
28-
}
29-
30-
if (!label) {
31-
return null;
32-
}
33-
348
return (
359
<Box
3610
sx={{

0 commit comments

Comments
 (0)