/* eslint-disable no-param-reassign */ import { TokenInterface } from '../type'; import { getChain } from './config'; // https://docs.metamask.io/guide/ethereum-provider.html#chain-ids export const getNetworkName = (networkId: number): string => { switch (networkId) { case 1: return 'Mainnet'; case 5: return 'gor'; case 11155111: return 'sep'; case 10: return 'Optimism'; case 288: return 'BOBA-Mainnet'; case 56: return 'BSC-Mainnet'; case 66: return 'OKChain'; case 86: return 'BSC-Mainnet'; case 128: return 'Heco'; case 137: return 'Polygon'; case 321: return 'kcs'; case 1285: return 'Moonriver'; case 42161: return 'Arbitrum'; case 1313161554: return 'Aurora'; case 43114: return 'Avalanche'; case 84531: return 'basegor'; case 8453: return 'base'; case 1030: return 'cfx'; case 534353: return 'scr-alpha'; case 59144: return 'linea'; case 534351: return 'scr-sepolia'; case 534352: return 'scr'; case 169: return 'manta'; case 5000: return 'mantle'; case 195: return 'tokb'; case 53457: return 'dodochain-testnet'; case 48899: return 'zircuit-testnet'; case 200901: return 'btr'; case 421614: return 'arb-sep'; case 48900: return 'zircuit-mainnet'; case 196: return 'okb'; case 4457845: return 'zero-sepolia'; case 543210: return 'zero-mainnet'; case 177: return 'hashkey'; case 43111: return 'hemi'; default: return 'Unknown'; } }; export const EtherTokenWithChainId: Record< number, TokenInterface & { wrappedTokenSymbol: string; wrappedTokenAddress: string } > = { 1: { symbol: 'ETH', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'Ether', decimals: 18, showDecimals: 4, wrappedTokenSymbol: 'WETH', wrappedTokenAddress: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', chainId: 1, }, 5: { symbol: 'ETH', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'Ether', decimals: 18, showDecimals: 4, wrappedTokenSymbol: 'WETH', wrappedTokenAddress: '0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6', chainId: 5, }, 11155111: { symbol: 'ETH', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'Ether', decimals: 18, showDecimals: 4, wrappedTokenSymbol: 'WETH', wrappedTokenAddress: '0x7B07164ecFaF0F0D85DFC062Bc205a4674c75Aa0', chainId: 11155111, }, 10: { symbol: 'ETH', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'Ether', decimals: 18, showDecimals: 4, wrappedTokenSymbol: 'WETH', wrappedTokenAddress: '0x4200000000000000000000000000000000000006', chainId: 10, }, 288: { symbol: 'ETH', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'ETH', decimals: 18, showDecimals: 6, wrappedTokenSymbol: 'WETH', wrappedTokenAddress: '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000', chainId: 288, }, 56: { symbol: 'BNB', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'BNB', decimals: 18, showDecimals: 4, wrappedTokenSymbol: 'WBNB', wrappedTokenAddress: '0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c', chainId: 56, }, 66: { symbol: 'OKT', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'OKT', decimals: 18, showDecimals: 4, wrappedTokenSymbol: 'WOKT', wrappedTokenAddress: '0x8F8526dbfd6E38E3D8307702cA8469Bae6C56C15', chainId: 66, }, 86: { symbol: 'BNB', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'BNB', decimals: 18, showDecimals: 4, wrappedTokenSymbol: 'WBNB', wrappedTokenAddress: '0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c', chainId: 86, }, 128: { symbol: 'HT', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'HT', decimals: 18, showDecimals: 6, wrappedTokenSymbol: 'WHT', wrappedTokenAddress: '0x5545153ccfca01fbd7dd11c0b23ba694d9509a6f', chainId: 128, }, 137: { symbol: 'POL', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'Polygon Ecosystem Token', decimals: 18, showDecimals: 6, wrappedTokenSymbol: 'WPOL', wrappedTokenAddress: '0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270', chainId: 137, }, 321: { symbol: 'KCS', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'KuCoin Token', decimals: 18, showDecimals: 4, wrappedTokenSymbol: 'WKCS', wrappedTokenAddress: '0x4446fc4eb47f2f6586f9faab68b3498f86c07521', chainId: 321, }, 1285: { symbol: 'MOVR', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'MOVR', decimals: 18, showDecimals: 4, wrappedTokenSymbol: 'WMOVR', wrappedTokenAddress: '0x98878b06940ae243284ca214f92bb71a2b032b8a', chainId: 1285, }, 42161: { symbol: 'ETH', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'Ether', decimals: 18, showDecimals: 4, wrappedTokenSymbol: 'WETH', wrappedTokenAddress: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1', chainId: 42161, }, 1313161554: { symbol: 'ETH', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'Ether', decimals: 18, showDecimals: 4, wrappedTokenSymbol: 'WETH', wrappedTokenAddress: '0xC9BdeEd33CD01541e1eeD10f90519d2C06Fe3feB', chainId: 1313161554, }, 43114: { symbol: 'AVAX', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'Avalanche', decimals: 18, showDecimals: 4, wrappedTokenSymbol: 'WAVAX', wrappedTokenAddress: '0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7', chainId: 43114, }, 8453: { symbol: 'ETH', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'Ether', decimals: 18, showDecimals: 4, wrappedTokenSymbol: 'WETH', wrappedTokenAddress: '0x4200000000000000000000000000000000000006', chainId: 8453, }, 84531: { symbol: 'ETH', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'Goerli Ether', decimals: 18, showDecimals: 4, wrappedTokenSymbol: 'WETH', wrappedTokenAddress: '0x4200000000000000000000000000000000000006', chainId: 84531, }, 1030: { symbol: 'CFX', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'CFX', decimals: 18, showDecimals: 4, wrappedTokenSymbol: 'WCFX', wrappedTokenAddress: '0x14b2d3bc65e74dae1030eafd8ac30c533c976a9b', chainId: 1030, }, 534353: { symbol: 'ETH', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'ETH', decimals: 18, showDecimals: 4, wrappedTokenSymbol: 'WETH', wrappedTokenAddress: '0xa1EA0B2354F5A344110af2b6AD68e75545009a03', chainId: 534353, }, 59144: { symbol: 'ETH', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'ETH', decimals: 18, showDecimals: 4, wrappedTokenSymbol: 'WETH', wrappedTokenAddress: '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f', chainId: 59144, }, 534351: { symbol: 'ETH', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'ETH', decimals: 18, showDecimals: 4, wrappedTokenSymbol: 'WETH', wrappedTokenAddress: '0xa7b9C3a116b20bEDDdBE4d90ff97157f67F0bD97', chainId: 534351, }, 534352: { symbol: 'ETH', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'ETH', decimals: 18, showDecimals: 4, wrappedTokenSymbol: 'WETH', wrappedTokenAddress: '0x5300000000000000000000000000000000000004', chainId: 534352, }, 169: { symbol: 'ETH', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'ETH', decimals: 18, showDecimals: 4, wrappedTokenSymbol: 'WETH', wrappedTokenAddress: '0x0Dc808adcE2099A9F62AA87D9670745AbA741746', chainId: 169, }, 5000: { symbol: 'MNT', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'MNT', decimals: 18, showDecimals: 4, wrappedTokenSymbol: 'WMNT', wrappedTokenAddress: '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8', chainId: 5000, }, 195: { symbol: 'OKB', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'OKB', decimals: 18, showDecimals: 4, wrappedTokenSymbol: 'WOKB', wrappedTokenAddress: '0xa7b9C3a116b20bEDDdBE4d90ff97157f67F0bD97', chainId: 195, }, 53457: { symbol: 'DODO', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'DODO', decimals: 18, showDecimals: 4, wrappedTokenSymbol: 'WBERD', wrappedTokenAddress: '0x3a64Ec3606FF7310E8fAd6FcC008e39705fB496d', chainId: 53457, }, 48899: { symbol: 'ETH', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'ETH', decimals: 18, showDecimals: 4, wrappedTokenSymbol: 'WETH', wrappedTokenAddress: '0xb375cCf52923287eC525351C2C11030FD95b856F', chainId: 48899, }, 200901: { symbol: 'BTC', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'BTC', decimals: 18, showDecimals: 4, wrappedTokenSymbol: 'WETH', wrappedTokenAddress: '0xDF45Fe87c36616a5fFDFe05D54A63f29AfE91d9f', chainId: 200901, }, 421614: { symbol: 'ETH', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'ETH', decimals: 18, showDecimals: 4, wrappedTokenSymbol: 'WETH', wrappedTokenAddress: '0xfd6fFee92D25158b29315C71b0Bb4dE727530FaF', chainId: 421614, }, 48900: { symbol: 'ETH', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'ETH', decimals: 18, showDecimals: 4, wrappedTokenSymbol: 'WETH', wrappedTokenAddress: '0x4200000000000000000000000000000000000006', chainId: 48900, }, 196: { symbol: 'OKB', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'OKB', decimals: 18, showDecimals: 4, wrappedTokenSymbol: 'WOKB', wrappedTokenAddress: '0xe538905cf8410324e03a5a23c1c177a474d59b2b', chainId: 196, }, 4457845: { symbol: 'ETH', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'ETH', decimals: 18, showDecimals: 4, wrappedTokenSymbol: 'WETH', wrappedTokenAddress: '0x29D3bD213dA1aB8b590dbfCA53bC7F2445972611', chainId: 4457845, }, 543210: { symbol: 'ETH', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'ETH', decimals: 18, showDecimals: 4, wrappedTokenSymbol: 'WETH', wrappedTokenAddress: '0xAc98B49576B1C892ba6BFae08fE1BB0d80Cf599c', chainId: 543210, }, 177: { symbol: 'HSK', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'HSK', decimals: 18, showDecimals: 4, wrappedTokenSymbol: 'WHSK', wrappedTokenAddress: '0xB210D2120d57b758EE163cFfb43e73728c471Cf1', chainId: 177, }, 43111: { symbol: 'ETH', address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', name: 'ETH', decimals: 18, showDecimals: 4, wrappedTokenSymbol: 'WETH', wrappedTokenAddress: '0x4200000000000000000000000000000000000006', chainId: 43111, }, }; export const getEtherTokenSymbolMatch = (symbolOrigin: string) => { const symbol = symbolOrigin.toLocaleUpperCase(); let result = [symbol]; Object.values(EtherTokenWithChainId).some((item) => { if (symbol === item.symbol || symbol === item.wrappedTokenSymbol) { result = [item.symbol, item.wrappedTokenSymbol]; return true; } return false; }); return result; }; export const getWrappedTokenSymbol = (symbolOrigin: string) => { const symbol = symbolOrigin.toLocaleUpperCase(); let result = symbol; Object.values(EtherTokenWithChainId).some((item) => { if (symbol === item.symbol) { result = item.wrappedTokenSymbol; return true; } return false; }); return result; }; /** * 获取 平台币对应的 wrapped 代币 * 如果 addressOrigin 为 0x...ee 且不传入 chainId,因为大部分链上平台币地址都为 0x...ee, 则无论在再哪条链调用该方法都会返回 ETH 链的 WETH,buggy * 传入 chainId * @param addressOrigin * @returns */ export const getWrappedTokenAddress = ( addressOrigin: string, chainId: number, ) => { const address = addressOrigin.toLowerCase(); const nativeToken = EtherTokenWithChainId[chainId]; if (nativeToken && nativeToken.address.toLowerCase() === address) { return nativeToken.wrappedTokenAddress; } return addressOrigin; }; export const getEtherTokenSymbolBlurMatch = (symbolOrigin: string) => { const symbol = symbolOrigin.toLocaleUpperCase(); let result = [symbol]; const symbolReg = new RegExp(`^${symbol.toLocaleUpperCase()}`); Object.values(EtherTokenWithChainId).some((item) => { if ( symbolReg.test(item.symbol) || symbolReg.test(item.wrappedTokenSymbol) ) { result = [item.symbol, item.wrappedTokenSymbol]; return true; } return false; }); return result; }; enum SymbolMatchType { NOMATCH = 1, BASE, QUOTE, } export const getBlurMatchSymbol = ({ blurSymbol, relevanceSymbols, baseSymbol, quoteSymbol, }: { blurSymbol: string; // 主网代币关联的代币组 relevanceSymbols: string[]; baseSymbol: string; quoteSymbol?: string; }) => { const symbolReg = new RegExp(`^${blurSymbol.toLocaleUpperCase()}`); const matchSymbolInfo: | { [key in SymbolMatchType]: string } | Record = {}; if (symbolReg.test(baseSymbol.toLocaleUpperCase())) { (matchSymbolInfo as { [key in SymbolMatchType]: string })[ SymbolMatchType.BASE ] = baseSymbol.toLocaleUpperCase(); } if (quoteSymbol && symbolReg.test(quoteSymbol.toLocaleUpperCase())) { (matchSymbolInfo as { [key in SymbolMatchType]: string })[ SymbolMatchType.QUOTE ] = quoteSymbol.toLocaleUpperCase(); } if (relevanceSymbols.includes(baseSymbol.toLocaleUpperCase())) { let matchBase = ''; relevanceSymbols.some((symbol) => { if (symbolReg.test(symbol)) { matchBase = symbol; return true; } return false; }); (matchSymbolInfo as { [key in SymbolMatchType]: string })[ SymbolMatchType.BASE ] = matchBase; } if (quoteSymbol && relevanceSymbols.includes(quoteSymbol)) { let matchBase = ''; relevanceSymbols.some((symbol) => { if (symbolReg.test(symbol)) { matchBase = symbol; return true; } return false; }); (matchSymbolInfo as { [key in SymbolMatchType]: string })[ SymbolMatchType.QUOTE ] = matchBase; } return matchSymbolInfo as { [key in SymbolMatchType]: string }; }; /** * 模糊匹配代币 * 最多输入两个代币,中间非字母非数字隔开 * 这里不止要匹配搜索词,还要匹配主网对应的币种。如 ETH,还要匹配 WETH * @returns false | 如果匹配到关联的主币,则返回关联的代币名称。如 WETH */ export const searchSymbol = ({ search, baseSymbol, quoteSymbol, }: { search: string; baseSymbol: string; quoteSymbol?: string; }) => { const filterSymbolArray = search.split(/[^a-zA-Z0-9]+/); const filterSymbolArrayLen = filterSymbolArray.length; if (filterSymbolArrayLen && filterSymbolArrayLen > 2) { return [baseSymbol, quoteSymbol]; } const aSearch = filterSymbolArray[0]; let bSearch = ''; const aMatchSymbols: string[] = getEtherTokenSymbolBlurMatch(aSearch); let bMatchSymbols: string[] = []; if (filterSymbolArrayLen === 2) { // eslint-disable-next-line prefer-destructuring bSearch = filterSymbolArray[1]; bMatchSymbols = getEtherTokenSymbolBlurMatch(bSearch); } if (aSearch) { const aMatchSymbolInfo = getBlurMatchSymbol({ blurSymbol: aSearch, relevanceSymbols: aMatchSymbols, baseSymbol, quoteSymbol, }); const aMatchSymbolInfoKeys = Object.keys(aMatchSymbolInfo); if (!aMatchSymbolInfoKeys.length) return false; if (bSearch) { const bMatchSymbolInfo = getBlurMatchSymbol({ blurSymbol: bSearch, relevanceSymbols: bMatchSymbols, baseSymbol, quoteSymbol, }); const bMatchSymbolInfoKeys = Object.keys(bMatchSymbolInfo); if (!bMatchSymbolInfoKeys.length) return false; if ( aMatchSymbolInfo[SymbolMatchType.BASE] && bMatchSymbolInfo[SymbolMatchType.QUOTE] ) { baseSymbol = aMatchSymbolInfo[SymbolMatchType.BASE]; quoteSymbol = bMatchSymbolInfo[SymbolMatchType.QUOTE]; } else if ( aMatchSymbolInfo[SymbolMatchType.QUOTE] && bMatchSymbolInfo[SymbolMatchType.BASE] ) { baseSymbol = bMatchSymbolInfo[SymbolMatchType.BASE]; quoteSymbol = aMatchSymbolInfo[SymbolMatchType.QUOTE]; } else { return false; } } else if (aMatchSymbolInfo[SymbolMatchType.BASE]) { baseSymbol = aMatchSymbolInfo[SymbolMatchType.BASE]; } else if (aMatchSymbolInfo[SymbolMatchType.QUOTE]) { quoteSymbol = aMatchSymbolInfo[SymbolMatchType.QUOTE]; } } return [baseSymbol, quoteSymbol]; }; export function getEtherscanPage( chainId: number, id?: string, prefix = 'address', ) { const { scanUrlDomain } = getChain(chainId); return `https://${scanUrlDomain}${id ? `/${prefix}/${id}` : ''}`; } export function formatEtherscanLink( type: 'Account' | 'Transaction', chainId: number, address: string, ) { const { scanUrlDomain } = getChain(chainId); switch (type) { case 'Account': { return `https://${scanUrlDomain}etherscan.io/address/${address}`; } case 'Transaction': { return `https://${scanUrlDomain}etherscan.io/tx/${address}`; } } } /** * open etherscan.io or bscscan.com * @param path url path * @param chainId chain ID */ export async function openEtherscanPage( path: string | undefined, chainId: number, customUrl?: string, ): Promise { const { scanUrlDomain } = getChain(chainId); window.open( `https://${customUrl ?? scanUrlDomain}${path ? `/${path}` : ''}`, '_blank', 'noopener,noreferrer', ); } export const generateLinkTo = ( path: string, chainId: number, query?: string, ) => { const pathSuffix = `network=${getNetworkName(chainId).toLowerCase()}${ query || '' }`; if (path.indexOf('?') > -1) { return `${path}&${pathSuffix}`; } return `${path}?${pathSuffix}`; };