From 9cacd2dc2685cc7e03cb861e33e9e7107f62adfe Mon Sep 17 00:00:00 2001 From: Christophe Deveaux Date: Tue, 17 Dec 2024 18:08:37 +0100 Subject: [PATCH] feat: dynamically load token lists for Orbit chains (#2135) --- .../src/components/TransferPanel/TokenRow.tsx | 6 +- .../components/TransferPanel/TokenSearch.tsx | 4 +- .../TransferPanel/TransferPanelMain/hooks.ts | 2 +- .../src/hooks/arbTokenBridge.types.ts | 6 +- .../src/hooks/useArbTokenBridge.ts | 4 +- .../src/util/TokenListUtils.ts | 102 ++++++++---------- 6 files changed, 54 insertions(+), 70 deletions(-) diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenRow.tsx b/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenRow.tsx index 65fcb9dafe..6d95a50d2a 100644 --- a/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenRow.tsx +++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenRow.tsx @@ -34,9 +34,9 @@ import { TokenLogoFallback } from './TokenInfo' import { useBalanceOnSourceChain } from '../../hooks/useBalanceOnSourceChain' import { useSourceChainNativeCurrencyDecimals } from '../../hooks/useSourceChainNativeCurrencyDecimals' -function tokenListIdsToNames(ids: number[]): string { +function tokenListIdsToNames(ids: string[]): string { return ids - .map((tokenListId: number) => listIdsToNames[tokenListId]) + .map((tokenListId: string) => listIdsToNames[tokenListId]) .join(', ') } @@ -90,7 +90,7 @@ function TokenListInfo({ token }: { token: ERC20BridgeToken | null }) { return 'Native USDC on Arbitrum Sepolia' } - const listIds: Set = token.listIds + const listIds: Set = token.listIds const listIdsSize = listIds.size if (listIdsSize === 0) { return 'Added by User' diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenSearch.tsx b/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenSearch.tsx index 93af1c6977..8d90a95caa 100644 --- a/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenSearch.tsx +++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenSearch.tsx @@ -47,7 +47,7 @@ import { useSetInputAmount } from '../../hooks/TransferPanel/useSetInputAmount' export const ARB_ONE_NATIVE_USDC_TOKEN = { ...ArbOneNativeUSDC, - listIds: new Set(), + listIds: new Set(), type: TokenType.ERC20, // the address field is for L1 address but native USDC does not have an L1 address // the L2 address is used instead to avoid errors @@ -57,7 +57,7 @@ export const ARB_ONE_NATIVE_USDC_TOKEN = { export const ARB_SEPOLIA_NATIVE_USDC_TOKEN = { ...ArbOneNativeUSDC, - listIds: new Set(), + listIds: new Set(), type: TokenType.ERC20, address: CommonAddress.ArbitrumSepolia.USDC, l2Address: CommonAddress.ArbitrumSepolia.USDC diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanelMain/hooks.ts b/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanelMain/hooks.ts index 4d748b11ca..9cb4413a42 100644 --- a/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanelMain/hooks.ts +++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanelMain/hooks.ts @@ -16,7 +16,7 @@ const commonUSDC = { type: TokenType.ERC20, symbol: 'USDC', decimals: 6, - listIds: new Set() + listIds: new Set() } export function useUpdateUSDCTokenData() { diff --git a/packages/arb-token-bridge-ui/src/hooks/arbTokenBridge.types.ts b/packages/arb-token-bridge-ui/src/hooks/arbTokenBridge.types.ts index 8c2d259e1a..2b62dd9bc8 100644 --- a/packages/arb-token-bridge-ui/src/hooks/arbTokenBridge.types.ts +++ b/packages/arb-token-bridge-ui/src/hooks/arbTokenBridge.types.ts @@ -90,7 +90,7 @@ export interface BridgeToken { address: string l2Address?: string logoURI?: string - listIds: Set // no listID indicates added by user + listIds: Set // no listID indicates added by user isL2Native?: boolean } @@ -140,8 +140,8 @@ export interface ArbTokenBridgeEth { export interface ArbTokenBridgeToken { add: (erc20L1orL2Address: string) => Promise addL2NativeToken: (erc20L2Address: string) => void - addTokensFromList: (tokenList: TokenList, listID: number) => void - removeTokensFromList: (listID: number) => void + addTokensFromList: (tokenList: TokenList, listID: string) => void + removeTokensFromList: (listID: string) => void updateTokenData: (l1Address: string) => Promise triggerOutbox: (params: { event: L2ToL1EventResultPlus diff --git a/packages/arb-token-bridge-ui/src/hooks/useArbTokenBridge.ts b/packages/arb-token-bridge-ui/src/hooks/useArbTokenBridge.ts index 6d96383d1d..39e39f2b83 100644 --- a/packages/arb-token-bridge-ui/src/hooks/useArbTokenBridge.ts +++ b/packages/arb-token-bridge-ui/src/hooks/useArbTokenBridge.ts @@ -136,7 +136,7 @@ export const useArbTokenBridge = ( const l1NetworkID = useMemo(() => String(l1.network.id), [l1.network.id]) - const removeTokensFromList = (listID: number) => { + const removeTokensFromList = (listID: string) => { setBridgeTokens(prevBridgeTokens => { const newBridgeTokens = { ...prevBridgeTokens } for (const address in bridgeTokens) { @@ -153,7 +153,7 @@ export const useArbTokenBridge = ( }) } - const addTokensFromList = async (arbTokenList: TokenList, listId: number) => { + const addTokensFromList = async (arbTokenList: TokenList, listId: string) => { const l1ChainID = l1.network.id const l2ChainID = l2.network.id diff --git a/packages/arb-token-bridge-ui/src/util/TokenListUtils.ts b/packages/arb-token-bridge-ui/src/util/TokenListUtils.ts index 1622484a9d..4f9f629475 100644 --- a/packages/arb-token-bridge-ui/src/util/TokenListUtils.ts +++ b/packages/arb-token-bridge-ui/src/util/TokenListUtils.ts @@ -9,11 +9,14 @@ import CoinGeckoLogo from '@/images/lists/coinGecko.svg' import ArbitrumLogo from '@/images/lists/ArbitrumLogo.png' import { ArbTokenBridge } from '../hooks/arbTokenBridge.types' import { ChainId } from './networks' +import orbitChainsData from './orbitChainsData.json' -export const SPECIAL_ARBITRUM_TOKEN_TOKEN_LIST_ID = 0 +export const SPECIAL_ARBITRUM_TOKEN_TOKEN_LIST_ID = + 'SPECIAL_ARBITRUM_TOKEN_TOKEN_LIST_ID' export interface BridgeTokenList { - id: number + // string is required here to avoid duplicates when mapping orbit chains to tokenlists + id: string originChainID: number url: string name: string @@ -34,7 +37,7 @@ export const BRIDGE_TOKEN_LISTS: BridgeTokenList[] = [ isArbitrumTokenTokenList: true }, { - id: 1, + id: '1', originChainID: ChainId.ArbitrumOne, url: 'https://tokenlist.arbitrum.io/ArbTokenLists/arbed_arb_whitelist_era.json', name: 'Arbitrum Whitelist Era', @@ -42,7 +45,7 @@ export const BRIDGE_TOKEN_LISTS: BridgeTokenList[] = [ logoURI: ArbitrumLogo }, { - id: 2, + id: '2', originChainID: ChainId.ArbitrumOne, url: 'https://tokenlist.arbitrum.io/ArbTokenLists/arbed_uniswap_labs_default.json', name: 'Arbed Uniswap List', @@ -50,7 +53,7 @@ export const BRIDGE_TOKEN_LISTS: BridgeTokenList[] = [ logoURI: UniswapLogo }, { - id: 4, + id: '4', originChainID: ChainId.ArbitrumOne, url: 'https://tokenlist.arbitrum.io/ArbTokenLists/arbed_coingecko.json', name: 'Arbed CoinGecko List', @@ -58,7 +61,7 @@ export const BRIDGE_TOKEN_LISTS: BridgeTokenList[] = [ logoURI: CoinGeckoLogo }, { - id: 5, + id: '5', originChainID: ChainId.ArbitrumOne, url: 'https://tokenlist.arbitrum.io/ArbTokenLists/arbed_coinmarketcap.json', name: 'Arbed CMC List', @@ -66,7 +69,7 @@ export const BRIDGE_TOKEN_LISTS: BridgeTokenList[] = [ logoURI: CMCLogo }, { - id: 6, + id: '6', originChainID: ChainId.ArbitrumNova, url: 'https://tokenlist.arbitrum.io/ArbTokenLists/42170_arbed_uniswap_labs_default.json', name: 'Arbed Uniswap List', @@ -78,7 +81,7 @@ export const BRIDGE_TOKEN_LISTS: BridgeTokenList[] = [ // TODO: remove list for chain ID 412346 after fix: // https://github.com/OffchainLabs/arb-token-bridge/issues/564 { - id: 9, + id: '9', // Local node originChainID: ChainId.ArbitrumLocal, url: 'https://tokenlist.arbitrum.io/ArbTokenLists/421613_arbed_coinmarketcap.json', @@ -87,7 +90,7 @@ export const BRIDGE_TOKEN_LISTS: BridgeTokenList[] = [ logoURI: CMCLogo }, { - id: 10, + id: '10', originChainID: ChainId.ArbitrumSepolia, url: 'https://tokenlist.arbitrum.io/ArbTokenLists/421614_arbed_uniswap_labs.json', name: 'Arbed Uniswap List', @@ -96,7 +99,7 @@ export const BRIDGE_TOKEN_LISTS: BridgeTokenList[] = [ }, // CoinGecko { - id: 11, + id: '11', originChainID: ChainId.ArbitrumNova, url: 'https://tokenlist.arbitrum.io/ArbTokenLists/42170_arbed_coingecko.json', name: 'Arbed CoinGecko List', @@ -104,25 +107,15 @@ export const BRIDGE_TOKEN_LISTS: BridgeTokenList[] = [ logoURI: CoinGeckoLogo }, { - id: 13, + id: '13', originChainID: ChainId.ArbitrumSepolia, url: 'https://tokenlist.arbitrum.io/ArbTokenLists/421614_arbed_coingecko.json', name: 'Arbed CoinGecko List', isDefault: true, logoURI: CoinGeckoLogo }, - // Orbit { - id: 14, - // Xai - originChainID: 660279, - url: 'https://tokenlist.arbitrum.io/ArbTokenLists/660279_arbed_uniswap_labs.json', - name: 'Arbed Uniswap List', - isDefault: true, - logoURI: UniswapLogo - }, - { - id: 660279, + id: '660279', // Xai originChainID: 660279, url: 'tokenLists/660279_default.json', @@ -130,42 +123,33 @@ export const BRIDGE_TOKEN_LISTS: BridgeTokenList[] = [ isDefault: true, logoURI: '/images/XaiLogo.svg' }, - { - id: 15, - // Rari - originChainID: 1380012617, - url: 'https://tokenlist.arbitrum.io/ArbTokenLists/1380012617_arbed_uniswap_labs.json', - name: 'Arbed Uniswap List', - isDefault: true, - logoURI: UniswapLogo - }, - { - id: 16, - // Muster - originChainID: 4078, - url: 'https://tokenlist.arbitrum.io/ArbTokenLists/4078_arbed_uniswap_labs.json', - name: 'Arbed Uniswap List', - isDefault: true, - logoURI: UniswapLogo - }, - { - id: 17, - // Proof of Play Apex - originChainID: 70700, - url: 'https://tokenlist.arbitrum.io/ArbTokenLists/70700_arbed_uniswap_labs.json', - name: 'Arbed Uniswap List', - isDefault: true, - logoURI: UniswapLogo - }, - { - id: 19, - // SX Network - originChainID: 4162, - url: 'https://tokenlist.arbitrum.io/ArbTokenLists/4162_arbed_uniswap_labs.json', - name: 'Arbed Uniswap List', - isDefault: true, - logoURI: UniswapLogo - } + // For all orbit chains, + ...orbitChainsData.mainnet + .concat(orbitChainsData.testnet) + .reduce((acc, chain) => { + // Only include arbified native token list for L3 settling to ArbOne + if (chain.parentChainId === ChainId.ArbitrumOne) { + acc.push({ + id: `${chain.chainId}_native`, + originChainID: chain.chainId, + url: `https://tokenlist.arbitrum.io/ArbTokenLists/${chain.chainId}_arbed_native_list.json`, + name: `${chain.name} Default List`, + isDefault: true, + logoURI: ArbitrumLogo + }) + } + + acc.push({ + id: `${chain.chainId}_uniswap`, + originChainID: chain.chainId, + url: `https://tokenlist.arbitrum.io/ArbTokenLists/${chain.chainId}_arbed_uniswap_labs.json`, + name: `${chain.name} Arbed Uniswap List`, + isDefault: true, + logoURI: UniswapLogo + }) + + return acc + }, [] as BridgeTokenList[]) ] export const listIdsToNames: { [key: string]: string } = {} @@ -176,7 +160,7 @@ BRIDGE_TOKEN_LISTS.forEach(bridgeTokenList => { export interface TokenListWithId extends TokenList { l2ChainId: string - bridgeTokenListId: number + bridgeTokenListId: string isValid?: boolean }