diff --git a/packages/maskbook/src/_locales/en/messages.json b/packages/maskbook/src/_locales/en/messages.json index eaa1139af66a..436ecfe2a556 100644 --- a/packages/maskbook/src/_locales/en/messages.json +++ b/packages/maskbook/src/_locales/en/messages.json @@ -363,7 +363,6 @@ "plugin_wallet_switch_network": "Swtich to {{network}}", "plugin_wallet_switch_network_under_going": "Switching to {{network}}…", "plugin_wallet_not_availabe_on": "Not available on {{network}}.", - "plugin_wallet_swtich_to": "Please switch to {{network}} on {{provider}}.", "plugin_wallet_settings_portfolio_data_source_primary": "Portfolio Data Source", "plugin_wallet_settings_portfolio_data_source_secondary": "Select the source of portfolio data.", "plugin_wallet_settings_collectible_data_source_primary": "Collectible Data Source", diff --git a/packages/maskbook/src/_locales/ja/messages.json b/packages/maskbook/src/_locales/ja/messages.json index 026d73a2377c..037aca2c4972 100644 --- a/packages/maskbook/src/_locales/ja/messages.json +++ b/packages/maskbook/src/_locales/ja/messages.json @@ -363,7 +363,6 @@ "plugin_wallet_switch_network": "", "plugin_wallet_switch_network_under_going": "", "plugin_wallet_not_availabe_on": "", - "plugin_wallet_swtich_to": "", "plugin_wallet_settings_portfolio_data_source_primary": "ポートフォリオデータのソーズ", "plugin_wallet_settings_portfolio_data_source_secondary": "ポートフォリオデータのソースを選択", "plugin_wallet_settings_collectible_data_source_primary": "コレクションデータのソース", diff --git a/packages/maskbook/src/_locales/ko/messages.json b/packages/maskbook/src/_locales/ko/messages.json index 9e00914af028..c0aa18c2c06b 100644 --- a/packages/maskbook/src/_locales/ko/messages.json +++ b/packages/maskbook/src/_locales/ko/messages.json @@ -363,7 +363,6 @@ "plugin_wallet_switch_network": "", "plugin_wallet_switch_network_under_going": "", "plugin_wallet_not_availabe_on": "", - "plugin_wallet_swtich_to": "", "plugin_wallet_settings_portfolio_data_source_primary": "포트폴리오 데이터 소스", "plugin_wallet_settings_portfolio_data_source_secondary": "포트폴리오 데이터 소스 선택", "plugin_wallet_settings_collectible_data_source_primary": "수집품 데이터 소스", diff --git a/packages/maskbook/src/_locales/zh/messages.json b/packages/maskbook/src/_locales/zh/messages.json index 606b310be5c4..788d00752c80 100644 --- a/packages/maskbook/src/_locales/zh/messages.json +++ b/packages/maskbook/src/_locales/zh/messages.json @@ -363,7 +363,6 @@ "plugin_wallet_switch_network": "", "plugin_wallet_switch_network_under_going": "", "plugin_wallet_not_availabe_on": "", - "plugin_wallet_swtich_to": "", "plugin_wallet_settings_portfolio_data_source_primary": "投資組合資料來源", "plugin_wallet_settings_portfolio_data_source_secondary": "選擇投資組合資料來源。", "plugin_wallet_settings_collectible_data_source_primary": "收藏品資料來源", diff --git a/packages/maskbook/src/extension/background-script/EthereumServices/tokenList.ts b/packages/maskbook/src/extension/background-script/EthereumServices/tokenList.ts index e7c1a18a48d1..6c2d79c0b19f 100644 --- a/packages/maskbook/src/extension/background-script/EthereumServices/tokenList.ts +++ b/packages/maskbook/src/extension/background-script/EthereumServices/tokenList.ts @@ -4,8 +4,9 @@ import { ERC20TokenDetailed, EthereumTokenType, formatEthereumAddress, - getChainDetailed, + isChainIdValid, } from '@masknet/web3-shared' +import { Flags } from '../../../utils' interface TokenList { keywords: string[] @@ -45,13 +46,7 @@ export async function fetchERC20TokensFromTokenList( chainId = ChainId.Mainnet, ): Promise { return (await fetchTokenList(url)).tokens - .filter( - (x) => - x.chainId === chainId && - (process.env.NODE_ENV === 'production' && process.env.build === 'stable' - ? getChainDetailed(chainId)?.network === 'mainnet' - : true), - ) + .filter((x) => x.chainId === chainId && isChainIdValid(chainId, Flags.wallet_allow_testnet)) .map((x) => ({ type: EthereumTokenType.ERC20, ...x, diff --git a/packages/maskbook/src/plugins/ITO/SNSAdaptor/PostInspector.tsx b/packages/maskbook/src/plugins/ITO/SNSAdaptor/PostInspector.tsx index 1e8e06c31e8e..59b0e9149442 100644 --- a/packages/maskbook/src/plugins/ITO/SNSAdaptor/PostInspector.tsx +++ b/packages/maskbook/src/plugins/ITO/SNSAdaptor/PostInspector.tsx @@ -51,7 +51,7 @@ export function PostInspector(props: PostInspectorProps) { (t) => ({ address: t.address, - type: isSameAddress(t.address, NATIVE_TOKEN_ADDRESS) + type: isSameAddress(t.address, NATIVE_TOKEN_ADDRESS ?? '') ? EthereumTokenType.Native : EthereumTokenType.ERC20, } as Pick), diff --git a/packages/maskbook/src/plugins/RedPacket/SNSAdaptor/RedPacket.tsx b/packages/maskbook/src/plugins/RedPacket/SNSAdaptor/RedPacket.tsx index 1f29ec4cfd55..ccd284a7f290 100644 --- a/packages/maskbook/src/plugins/RedPacket/SNSAdaptor/RedPacket.tsx +++ b/packages/maskbook/src/plugins/RedPacket/SNSAdaptor/RedPacket.tsx @@ -229,8 +229,7 @@ export function RedPacket(props: RedPacketProps) { // the red packet can fetch without account if (!availability || !token) return ( - + +
diff --git a/packages/maskbook/src/plugins/RedPacket/SNSAdaptor/hooks/useAvailabilityComputed.ts b/packages/maskbook/src/plugins/RedPacket/SNSAdaptor/hooks/useAvailabilityComputed.ts index 179ff4d445d9..a17663569527 100644 --- a/packages/maskbook/src/plugins/RedPacket/SNSAdaptor/hooks/useAvailabilityComputed.ts +++ b/packages/maskbook/src/plugins/RedPacket/SNSAdaptor/hooks/useAvailabilityComputed.ts @@ -30,7 +30,7 @@ export function useAvailabilityComputed(account: string, payload: RedPacketJSONP const isClaimed = availability.claimed_amount ? availability.claimed_amount !== '0' : availability.ifclaimed const isRefunded = isEmpty && Number.parseInt(availability.claimed, 10) < Number.parseInt(availability.total, 10) const isCreator = isSameAddress(payload?.sender.address ?? '', account) - const parsedChainId = payload.network ? getChainIdFromName(payload.network) : ChainId.Mainnet + const parsedChainId = getChainIdFromName(payload.network ?? '') ?? ChainId.Mainnet return { ...asyncResult, computed: { diff --git a/packages/maskbook/src/plugins/RedPacket/SNSAdaptor/index.tsx b/packages/maskbook/src/plugins/RedPacket/SNSAdaptor/index.tsx index a330432e696b..da59526f3377 100644 --- a/packages/maskbook/src/plugins/RedPacket/SNSAdaptor/index.tsx +++ b/packages/maskbook/src/plugins/RedPacket/SNSAdaptor/index.tsx @@ -1,5 +1,5 @@ import type { Plugin } from '@masknet/plugin-infra' -import { EthereumTokenType, formatBalance, getChainDetailed, getChainIdFromName } from '@masknet/web3-shared' +import { ChainId, EthereumTokenType, formatBalance, getChainDetailed, getChainIdFromName } from '@masknet/web3-shared' import MaskbookPluginWrapper from '../../MaskbookPluginWrapper' import { base } from '../base' import { RedPacketMetaKey } from '../constants' @@ -25,7 +25,7 @@ const sns: Plugin.SNSAdaptor.Definition = { [ RedPacketMetaKey, (payload: RedPacketJSONPayload) => { - const chainId = getChainIdFromName(payload.network ?? 'ETH') + const chainId = getChainIdFromName(payload.network ?? '') ?? ChainId.Mainnet const chainDetailed = getChainDetailed(chainId) const tokenDetailed = payload.token_type === EthereumTokenType.Native ? chainDetailed?.nativeCurrency : payload.token diff --git a/packages/maskbook/src/plugins/Wallet/services/assets.ts b/packages/maskbook/src/plugins/Wallet/services/assets.ts index 04665d423f72..344e87487e11 100644 --- a/packages/maskbook/src/plugins/Wallet/services/assets.ts +++ b/packages/maskbook/src/plugins/Wallet/services/assets.ts @@ -8,9 +8,9 @@ import { CurrencyType, EthereumTokenType, formatEthereumAddress, - getChainDetailed, getChainIdFromName, getTokenConstants, + isChainIdMainnet, NetworkType, pow10, } from '@masknet/web3-shared' @@ -101,32 +101,30 @@ export async function getAssetsList( } function formatAssetsFromDebank(data: BalanceRecord[]) { - return data.map((x): Asset => { - const chainId = getChainIdFromName(x.id) - return { - chain: x.chain, - token: - chainId && getChainDetailed(chainId)?.network === 'mainnet' - ? createNativeToken(getChainIdFromName(x.id) ?? ChainId.Mainnet) - : createERC20Token( - getChainIdFromName(x.chain) ?? ChainId.Mainnet, - formatEthereumAddress(x.id), - x.decimals, - x.name, - x.symbol, - ), - balance: new BigNumber(x.balance).toFixed(), - price: { - [CurrencyType.USD]: new BigNumber(x.price).toFixed(), - }, - value: { - [CurrencyType.USD]: new BigNumber(x.price) - .multipliedBy(new BigNumber(x.balance).dividedBy(pow10(x.decimals))) - .toFixed(), - }, - logoURL: x.logo_url, - } - }) + return data + .filter((x) => getChainIdFromName(x.chain)) + .map((y): Asset => { + const chainId = getChainIdFromName(y.chain) ?? ChainId.Mainnet + // the asset id is the token address or the name of the chain + const chainIdFormId = getChainIdFromName(y.id) + return { + chain: y.chain, + token: + chainIdFormId && isChainIdMainnet(chainIdFormId) + ? createNativeToken(chainId) + : createERC20Token(chainId, formatEthereumAddress(y.id), y.decimals, y.name, y.symbol), + balance: new BigNumber(y.balance).toFixed(), + price: { + [CurrencyType.USD]: new BigNumber(y.price).toFixed(), + }, + value: { + [CurrencyType.USD]: new BigNumber(y.price) + .multipliedBy(new BigNumber(y.balance).dividedBy(pow10(y.decimals))) + .toFixed(), + }, + logoURL: y.logo_url, + } + }) } const filterAssetType = ['compound', 'trash', 'uniswap', 'uniswap-v2', 'nft'] diff --git a/packages/maskbook/src/web3/UI/EthereumChainBoundary.tsx b/packages/maskbook/src/web3/UI/EthereumChainBoundary.tsx index eac923fb1b30..19d00bcb5e3c 100644 --- a/packages/maskbook/src/web3/UI/EthereumChainBoundary.tsx +++ b/packages/maskbook/src/web3/UI/EthereumChainBoundary.tsx @@ -7,11 +7,9 @@ import { getNetworkTypeFromChainId, NetworkType, ProviderType, - resolveProviderName, useAccount, - useAllowTestnet, - useChainDetailed, useChainId, + useChainIdValid, } from '@masknet/web3-shared' import { useValueRef, delay } from '@masknet/shared' import { ActionButtonPromise } from '../../extension/options-page/DashboardComponents/ActionButton' @@ -29,8 +27,7 @@ export function EthereumChainBoundary(props: EthereumChainBoundaryProps) { const { t } = useI18N() const account = useAccount() const chainId = useChainId() - const chainDetailed = useChainDetailed() - const allowTestnet = useAllowTestnet() + const chainIdValid = useChainIdValid() const providerType = useValueRef(currentProviderSettings) const expectedChainId = props.chainId @@ -38,11 +35,8 @@ export function EthereumChainBoundary(props: EthereumChainBoundaryProps) { const acutalChainId = chainId const actualNetwork = getChainName(acutalChainId) - // if false then the user should switch network manually - const isSwitchable = true - - // if testnets were not allowed it will not guide the user to switch the network - const isAllowed = allowTestnet || chainDetailed?.network === 'mainnet' + // if false then it will not guide the user to switch the network + const isAllowed = chainIdValid && !!account const onSwitch = useCallback(async () => { // a short time loading makes the user fells better @@ -67,8 +61,9 @@ export function EthereumChainBoundary(props: EthereumChainBoundaryProps) { if (!networkType) return if (networkType === NetworkType.Ethereum) await Services.Ethereum.switchEthereumChain(expectedChainId) else await Services.Ethereum.addEthereumChain(chainDetailedCAIP, account) - }, [account, isAllowed, isSwitchable, providerType, expectedChainId]) + }, [account, isAllowed, providerType, expectedChainId]) + // matched if (acutalChainId === expectedChainId) return <>{props.children} if (!isAllowed) @@ -92,16 +87,8 @@ export function EthereumChainBoundary(props: EthereumChainBoundaryProps) { network: actualNetwork, })} - {isSwitchable ? null : ( - - {t('plugin_wallet_swtich_to', { - network: expectedNetwork, - provider: resolveProviderName(providerType), - })} - - )} - {isSwitchable ? ( + {isAllowed ? ( ) - if (!chainIdValid) + if (!chainIdValid && !offChain) return ( diff --git a/packages/shared/src/UI/components/TokenIcon/index.tsx b/packages/shared/src/UI/components/TokenIcon/index.tsx index b8be8c538f1b..03f72929ab85 100644 --- a/packages/shared/src/UI/components/TokenIcon/index.tsx +++ b/packages/shared/src/UI/components/TokenIcon/index.tsx @@ -19,7 +19,7 @@ import { useStylesExtends } from '../../UIHelper/custom-ui-helper' function resolveTokenIconURLs(address: string, baseURIs: string[], chainId: ChainId, logoURI?: string) { const checkSummedAddress = formatEthereumAddress(address) - if (isSameAddress(getTokenConstants().NATIVE_TOKEN_ADDRESS, checkSummedAddress)) { + if (isSameAddress(getTokenConstants().NATIVE_TOKEN_ADDRESS ?? '', checkSummedAddress)) { return baseURIs.map((x) => `${x}/info/logo.png`) } @@ -57,7 +57,7 @@ export function TokenIcon(props: TokenIconProps) { const chainDetailed = useChainDetailed() const tokenBlockie = useBlockie(address) const { TOKEN_ASSET_BASE_URI } = useTokenAssetBaseURLConstants(chainId) - const tokenURIs = resolveTokenIconURLs(address, TOKEN_ASSET_BASE_URI, chainId ?? chainId_, logoURI) + const tokenURIs = resolveTokenIconURLs(address, TOKEN_ASSET_BASE_URI ?? [], chainId ?? chainId_, logoURI) const { value: logoURL, loading } = useImageFailOver(chainDetailed ? tokenURIs : [], '') return ( diff --git a/packages/web3-shared/src/assets/chains.json b/packages/web3-shared/src/assets/chains.json index 1e3556315be1..6f288dbc64f8 100644 --- a/packages/web3-shared/src/assets/chains.json +++ b/packages/web3-shared/src/assets/chains.json @@ -258,7 +258,7 @@ }, { "name": "Optimistic Ethereum", - "chain": "ETH", + "chain": "OPT", "network": "mainnet", "rpc": ["https://mainnet.optimism.io/"], "faucets": [], @@ -367,7 +367,7 @@ }, { "name": "ELA-ETH-Sidechain Mainnet", - "chain": "ETH", + "chain": "ELA-ETH", "network": "mainnet", "rpc": ["https://mainrpc.elaeth.io"], "faucets": [], @@ -379,7 +379,7 @@ }, { "name": "ELA-ETH-Sidechain Testnet", - "chain": "ETH", + "chain": "ELA-ETH", "network": "testnet", "rpc": ["https://rpc.elaeth.io"], "faucets": ["https://faucet.elaeth.io/"], @@ -391,7 +391,7 @@ }, { "name": "ELA-DID-Sidechain Mainnet", - "chain": "ETH", + "chain": "ELA-ETH", "network": "mainnet", "rpc": [], "faucets": [], @@ -403,7 +403,7 @@ }, { "name": "ELA-DID-Sidechain Testnet", - "chain": "ETH", + "chain": "ELA-ETH", "network": "testnet", "rpc": [], "faucets": [], @@ -729,7 +729,7 @@ }, { "name": "Optimistic Ethereum Testnet Kovan", - "chain": "ETH", + "chain": "OPT", "network": "kovan", "rpc": ["https://kovan.optimism.io/"], "faucets": [], @@ -1028,7 +1028,7 @@ }, { "name": "HOO Smart Chain Testnet", - "chain": "ETH", + "chain": "HOO", "network": "testnet", "rpc": ["https://http-testnet.hoosmartchain.com"], "faucets": ["https://faucet-testnet.hscscan.com/"], @@ -1142,7 +1142,7 @@ }, { "name": "Optimistic Ethereum Testnet Goerli", - "chain": "ETH", + "chain": "OPT", "network": "goerli", "rpc": ["https://goerli.optimism.io/"], "faucets": [], @@ -1936,7 +1936,7 @@ }, { "name": "Firenze test network", - "chain": "ETH", + "chain": "FIR", "network": "testnet", "rpc": ["https://ethnode.primusmoney.com/firenze"], "faucets": [], diff --git a/packages/web3-shared/src/context/index.tsx b/packages/web3-shared/src/context/index.tsx index ec3d4742abcf..6d7035ee3e5e 100644 --- a/packages/web3-shared/src/context/index.tsx +++ b/packages/web3-shared/src/context/index.tsx @@ -2,7 +2,7 @@ import { useContext, createContext } from 'react' import { createContainer } from 'unstated-next' import { useSubscription } from 'use-subscription' import type { Web3ProviderType } from './type' -import { getChainDetailed } from '../utils' +import { getChainDetailed, isChainIdValid } from '../utils' export type { Web3ProviderType } from './type' @@ -46,7 +46,7 @@ export function useWeb3State() { erc20Tokens, erc20TokensCount, portfolioProvider, - chainIdValid: !account || !!(allowTestnet && chainDetailed) || chainDetailed?.network === 'mainnet', + chainIdValid: !account || isChainIdValid(chainId, allowTestnet), } } diff --git a/packages/web3-shared/src/hooks/useChainIdValid.ts b/packages/web3-shared/src/hooks/useChainIdValid.ts new file mode 100644 index 000000000000..b8af156e93a3 --- /dev/null +++ b/packages/web3-shared/src/hooks/useChainIdValid.ts @@ -0,0 +1,5 @@ +import { useWeb3StateContext } from '../context' + +export function useChainIdValid() { + return useWeb3StateContext().chainIdValid +} diff --git a/packages/web3-shared/src/utils/address.ts b/packages/web3-shared/src/utils/address.ts new file mode 100644 index 000000000000..a52929746019 --- /dev/null +++ b/packages/web3-shared/src/utils/address.ts @@ -0,0 +1,22 @@ +import { getTokenConstants } from '../constants' + +export function isSameAddress(addrA: string, addrB: string) { + return addrA.toLowerCase() === addrB.toLowerCase() +} + +export function currySameAddress(base: string) { + return (target: string | { address: string }) => { + if (typeof target === 'string') { + return isSameAddress(base, target) + } else if (typeof target === 'object' && typeof target.address === 'string') { + return isSameAddress(base, target.address) + } + throw new Error('Unsupported `target` address format') + } +} + +export const isDAI = currySameAddress(getTokenConstants().DAI_ADDRESS) + +export const isOKB = currySameAddress(getTokenConstants().OKB_ADDRESS) + +export const isNative = currySameAddress(getTokenConstants().NATIVE_TOKEN_ADDRESS) diff --git a/packages/web3-shared/src/utils/chainDetailed.ts b/packages/web3-shared/src/utils/chainDetailed.ts new file mode 100644 index 000000000000..1a047850b8c3 --- /dev/null +++ b/packages/web3-shared/src/utils/chainDetailed.ts @@ -0,0 +1,93 @@ +import { safeUnreachable } from '@dimensiondev/kit' +import CHAINS from '../assets/chains.json' +import { getRPCConstants } from '../constants' +import { ChainId, NetworkType } from '../types' + +export function isChainIdValid(chainId: ChainId, allowTestnet = false) { + const chainDetailed = getChainDetailed(chainId) + return !!getNetworkTypeFromChainId(chainId) && (chainDetailed?.network === 'mainnet' || allowTestnet) +} + +export function isChainIdMainnet(chainId: ChainId) { + const chainDetailed = getChainDetailed(chainId) + return chainDetailed?.network === 'mainnet' +} + +export function getChainDetailed(chainId = ChainId.Mainnet) { + return CHAINS.find((x) => x.chainId === chainId) +} + +// Learn more: https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-2.md +export function getChainDetailedCAIP(chainId = ChainId.Mainnet) { + const chainDetailed = getChainDetailed(chainId) + const { RPC } = getRPCConstants(chainId) + if (!chainDetailed) return + return { + chainId: `0x${chainDetailed.chainId.toString(16)}`, + chainName: chainDetailed.name, + nativeCurrency: chainDetailed.nativeCurrency, + rpcUrls: RPC, + blockExplorerUrls: [ + chainDetailed.explorers && chainDetailed.explorers.length > 0 && chainDetailed.explorers[0].url + ? chainDetailed.explorers[0].url + : chainDetailed.infoURL, + ], + } +} + +export function getChainRPC(chainId: ChainId, seed: number) { + const { RPC, RPC_WEIGHTS } = getRPCConstants(chainId) + if (!RPC || !RPC_WEIGHTS) throw new Error('Unknown chain id.') + return RPC[RPC_WEIGHTS[seed]] +} + +export function getChainName(chainId: ChainId) { + const chainDetailed = getChainDetailed(chainId) + return chainDetailed?.name ?? 'Unknown Network' +} + +export function getChainFullName(chainId: ChainId) { + const chainDetailed = getChainDetailed(chainId) + return chainDetailed?.fullName ?? 'Unknown Network' +} + +export function getChainIdFromName(name: string) { + if (!name) return + const chainDetailed = CHAINS.find((x) => + [x.chain, x.network, x.name, x.shortName, x.fullName ?? ''] + .filter(Boolean) + .map((y) => y.toLowerCase()) + .includes(name.toLowerCase()), + ) + return chainDetailed && getNetworkTypeFromChainId(chainDetailed.chainId) + ? (chainDetailed.chainId as ChainId) + : undefined +} + +export function getChainIdFromNetworkType(networkType: NetworkType) { + switch (networkType) { + case NetworkType.Ethereum: + return ChainId.Mainnet + case NetworkType.Binance: + return ChainId.BSC + case NetworkType.Polygon: + return ChainId.Matic + default: + safeUnreachable(networkType) + return ChainId.Mainnet + } +} + +export function getNetworkTypeFromChainId(chainId: ChainId) { + const chainDetailed = getChainDetailed(chainId) + switch (chainDetailed?.chain) { + case 'ETH': + return NetworkType.Ethereum + case 'BSC': + return NetworkType.Binance + case 'Matic': + return NetworkType.Polygon + default: + return + } +} diff --git a/packages/web3-shared/src/utils/index.ts b/packages/web3-shared/src/utils/index.ts index 03b8aa7ac219..e642bfdf99e1 100644 --- a/packages/web3-shared/src/utils/index.ts +++ b/packages/web3-shared/src/utils/index.ts @@ -1,3 +1,5 @@ +export * from './address' export * from './token' export * from './formatter' export * from './number' +export * from './chainDetailed' diff --git a/packages/web3-shared/src/utils/token.ts b/packages/web3-shared/src/utils/token.ts index 365a85919a31..702035579051 100644 --- a/packages/web3-shared/src/utils/token.ts +++ b/packages/web3-shared/src/utils/token.ts @@ -1,9 +1,8 @@ -import { getEnumAsArray, safeUnreachable } from '@dimensiondev/kit' -import BigNumber from 'bignumber.js' import type Web3 from 'web3' import { AbiOutput, hexToBytes, toAscii } from 'web3-utils' -import CHAINS from '../assets/chains.json' -import { getRPCConstants, getTokenConstants } from '../constants' +import BigNumber from 'bignumber.js' +import { getEnumAsArray } from '@dimensiondev/kit' +import { getTokenConstants } from '../constants' import { Asset, ChainId, @@ -13,113 +12,9 @@ import { ERC721TokenAssetDetailed, EthereumTokenType, NativeTokenDetailed, - NetworkType, } from '../types' +import { getChainDetailed } from './chainDetailed' -export function isSameAddress(addrA: string, addrB: string) { - return addrA.toLowerCase() === addrB.toLowerCase() -} - -export function currySameAddress(base: string) { - return (target: string | { address: string }) => { - if (typeof target === 'string') { - return isSameAddress(base, target) - } else if (typeof target === 'object' && typeof target.address === 'string') { - return isSameAddress(base, target.address) - } - throw new Error('Unsupported `target` address format') - } -} - -export const isDAI = currySameAddress(getTokenConstants().DAI_ADDRESS) - -export const isOKB = currySameAddress(getTokenConstants().OKB_ADDRESS) - -export const isNative = currySameAddress(getTokenConstants().NATIVE_TOKEN_ADDRESS) - -export function addGasMargin(value: BigNumber.Value, scale = 3000) { - return new BigNumber(value).multipliedBy(new BigNumber(10000).plus(scale)).dividedToIntegerBy(10000) -} - -//#region chain detailed -export function getChainDetailed(chainId = ChainId.Mainnet) { - return CHAINS.find((x) => x.chainId === chainId) -} - -// Learn more: https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-2.md -export function getChainDetailedCAIP(chainId = ChainId.Mainnet) { - const chainDetailed = getChainDetailed(chainId) - const { RPC } = getRPCConstants(chainId) - if (!chainDetailed) return - return { - chainId: `0x${chainDetailed.chainId.toString(16)}`, - chainName: chainDetailed.name, - nativeCurrency: chainDetailed.nativeCurrency, - rpcUrls: RPC, - blockExplorerUrls: [ - chainDetailed.explorers && chainDetailed.explorers.length > 0 && chainDetailed.explorers[0].url - ? chainDetailed.explorers[0].url - : chainDetailed.infoURL, - ], - } -} - -export function getChainRPC(chainId: ChainId, seed: number) { - const { RPC, RPC_WEIGHTS } = getRPCConstants(chainId) - if (!RPC || !RPC_WEIGHTS) throw new Error('Unknown chain id.') - return RPC[RPC_WEIGHTS[seed]] -} - -export function getChainName(chainId: ChainId) { - const chainDetailed = getChainDetailed(chainId) - return chainDetailed?.name ?? 'Unknown Network' -} - -export function getChainFullName(chainId: ChainId) { - const chainDetailed = getChainDetailed(chainId) - return chainDetailed?.fullName ?? 'Unknown Network' -} - -export function getChainIdFromName(name: string) { - const chainDetailed = CHAINS.find((x) => - [x.chain, x.network, x.name, x.shortName, x.fullName ?? ''] - .filter(Boolean) - .map((y) => y.toLowerCase()) - .includes(name.toLowerCase()), - ) - return chainDetailed?.chainId as ChainId | undefined -} - -export function getChainIdFromNetworkType(networkType: NetworkType) { - switch (networkType) { - case NetworkType.Ethereum: - return ChainId.Mainnet - case NetworkType.Binance: - return ChainId.BSC - case NetworkType.Polygon: - return ChainId.Matic - default: - safeUnreachable(networkType) - return ChainId.Mainnet - } -} - -export function getNetworkTypeFromChainId(chainId: ChainId) { - const chainDetailed = getChainDetailed(chainId) - switch (chainDetailed?.chain) { - case 'ETH': - return NetworkType.Ethereum - case 'BSC': - return NetworkType.Binance - case 'Matic': - return NetworkType.Polygon - default: - return - } -} -//#endregion - -//#region tokens export function createNativeToken(chainId: ChainId): NativeTokenDetailed { const chainDetailed = getChainDetailed(chainId) if (!chainDetailed) throw new Error('Unknown chain id.') @@ -213,6 +108,10 @@ export function createERC20Tokens( } //#endregion +export function addGasMargin(value: BigNumber.Value, scale = 3000) { + return new BigNumber(value).multipliedBy(new BigNumber(10000).plus(scale)).dividedToIntegerBy(10000) +} + export function decodeOutputString(web3: Web3, abis: AbiOutput[], output: string) { if (abis.length === 1) return web3.eth.abi.decodeParameter(abis[0], output) if (abis.length > 1) return web3.eth.abi.decodeParameters(abis, output)