diff --git a/src/assets/index.ts b/src/assets/index.ts index 449d7d3f8..443d8b3ee 100644 --- a/src/assets/index.ts +++ b/src/assets/index.ts @@ -1,5 +1,6 @@ import { nativeAssets, testnetNativeAssets } from './native' import { erc20Assets, testnetErc20Assets, chainToTokenAddressMap, chainToTestnetTokenAddressMap } from './erc20' +import { getSendGasLimitERC20 } from './sendGasLimits' const assets = { ...nativeAssets, @@ -11,4 +12,4 @@ const testnetAssets = { ...testnetErc20Assets } -export { assets, testnetAssets, chainToTokenAddressMap, chainToTestnetTokenAddressMap } +export { assets, testnetAssets, chainToTokenAddressMap, chainToTestnetTokenAddressMap, getSendGasLimitERC20 } diff --git a/src/assets/native.ts b/src/assets/native.ts index 0f46a7e42..55214c1c4 100644 --- a/src/assets/native.ts +++ b/src/assets/native.ts @@ -1,12 +1,12 @@ import { TESTNET_NATIVE } from './testnet' -import { AssetMap, ChainId } from '../types' -import { sendGasLimits } from '../assets/sendGasLimits' +import { AssetMap, ChainId, AssetTypes } from '../types' +import { sendGasLimits } from './sendGasLimits' const nativeAssets: AssetMap = { BTC: { name: 'Bitcoin', chain: ChainId.Bitcoin, - type: 'native', + type: AssetTypes.native, code: 'BTC', coinGeckoId: 'bitcoin', color: '#f7931a', @@ -16,7 +16,7 @@ const nativeAssets: AssetMap = { BCH: { name: 'Bitcoin Cash', chain: ChainId.BitcoinCash, - type: 'native', + type: AssetTypes.native, code: 'BCH', coinGeckoId: 'bitcoin-cash', color: '#a1db5e', @@ -26,7 +26,7 @@ const nativeAssets: AssetMap = { ETH: { name: 'Ether', chain: ChainId.Ethereum, - type: 'native', + type: AssetTypes.native, code: 'ETH', coinGeckoId: 'ethereum', color: '#627eea', @@ -36,7 +36,7 @@ const nativeAssets: AssetMap = { RBTC: { name: 'Rootstock BTC', chain: ChainId.Rootstock, - type: 'native', + type: AssetTypes.native, code: 'RBTC', coinGeckoId: 'rootstock', color: '#006e3c', @@ -46,7 +46,7 @@ const nativeAssets: AssetMap = { BNB: { name: 'Binance Coin', chain: ChainId.BinanceSmartChain, - type: 'native', + type: AssetTypes.native, code: 'BNB', coinGeckoId: 'binancecoin', color: '#f9a825', @@ -56,7 +56,7 @@ const nativeAssets: AssetMap = { NEAR: { name: 'Near', chain: ChainId.Near, - type: 'native', + type: AssetTypes.native, code: 'NEAR', coinGeckoId: 'near', color: '#000000', @@ -66,7 +66,7 @@ const nativeAssets: AssetMap = { SOL: { name: 'Solana', chain: ChainId.Solana, - type: 'native', + type: AssetTypes.native, code: 'SOL', coinGeckoId: 'solana', color: '#008080', @@ -76,7 +76,7 @@ const nativeAssets: AssetMap = { MATIC: { name: 'Matic', chain: ChainId.Polygon, - type: 'native', + type: AssetTypes.native, code: 'MATIC', coinGeckoId: 'matic-network', color: '#8247E5', @@ -86,7 +86,7 @@ const nativeAssets: AssetMap = { ARBETH: { name: 'Arbitrum ETH', chain: ChainId.Arbitrum, - type: 'native', + type: AssetTypes.native, code: 'ARBETH', coinGeckoId: 'ethereum', color: '#28A0EF', @@ -97,7 +97,7 @@ const nativeAssets: AssetMap = { FUSE: { name: 'Fuse Network', chain: ChainId.Fuse, - type: 'native', + type: AssetTypes.native, code: 'FUSE', coinGeckoId: 'fuse-network-token', color: '#46e8b6', @@ -107,7 +107,7 @@ const nativeAssets: AssetMap = { LUNA: { name: 'Luna', chain: ChainId.Terra, - type: 'native', + type: AssetTypes.native, code: 'LUNA', coinGeckoId: 'terra-luna', color: '#008080', @@ -117,7 +117,7 @@ const nativeAssets: AssetMap = { UST: { name: 'TerraUSD', chain: ChainId.Terra, - type: 'native', + type: AssetTypes.native, code: 'UST', decimals: 6, color: '#0083ff', @@ -128,7 +128,7 @@ const nativeAssets: AssetMap = { AVAX: { name: 'Avalanche', chain: ChainId.Avalanche, - type: 'native', + type: AssetTypes.native, code: 'AVAX', coinGeckoId: 'avalanche-2', color: '#E84141', diff --git a/src/assets/sendGasLimits.ts b/src/assets/sendGasLimits.ts index 111f98358..842eeb757 100644 --- a/src/assets/sendGasLimits.ts +++ b/src/assets/sendGasLimits.ts @@ -1,11 +1,30 @@ +import { ChainId } from '../types' +import { hasTokens } from '../chains' + const sendGasLimits = { BTC: 290, NATIVE_EVM: 21000, // EVM -> ETH, RBTC, MATIC, BNB, AVAX, FUSE ERC20_EVM: 90000, // EVM -> ETH, RBTC, MATIC, BNB, AVAX, FUSE TERRA: 100000, // applies on both native and ERC2 Terra assets - ARBETH: 620000, + ARBETH: 620000, // for native asset is around ~420k and for ERC20 ~540k NEAR: 10000000000000, SOL: 1000000 } -export { sendGasLimits } +const getSendGasLimitERC20 = (chainId: ChainId): number | null => { + if (!hasTokens(chainId)) { + throw new Error(`Chain '${chainId}' doesn't support tokens!`) + } + + switch (chainId) { + case ChainId.Arbitrum: + return sendGasLimits.ARBETH + case ChainId.Terra: + return sendGasLimits.TERRA + default: + // EVM standard gas limit + return sendGasLimits.ERC20_EVM + } +} + +export { sendGasLimits, getSendGasLimitERC20 } diff --git a/src/chains.ts b/src/chains.ts index f7a533688..e0fcf7c9d 100644 --- a/src/chains.ts +++ b/src/chains.ts @@ -28,6 +28,8 @@ const chains: { [key in ChainId]: Chain } = { safeConfirmations: 1, // 0,1 blocks per minute * 180 minutes (3 hours) -> 18 blocks wait period txFailureTimeout: 10800000, // 3 hours in ms + evmCompatible: false, + hasTokens: false, // TODO: include network types in validation isValidAddress: (address) => !!validateBitcoinAddress(address), formatAddress: (address) => address, @@ -44,6 +46,8 @@ const chains: { [key in ChainId]: Chain } = { safeConfirmations: 1, // ~0,1 blocks per minute * 180 minutes (3 hours) -> 18 blocks wait period txFailureTimeout: 10800000, // 3 hours in ms + evmCompatible: false, + hasTokens: false, // TODO: include network types in validation isValidAddress: (address) => isValidBitcoinCashAddress(address), formatAddress: (address) => formatBitcoinCashAddress(address), @@ -60,6 +64,8 @@ const chains: { [key in ChainId]: Chain } = { safeConfirmations: 3, // ~4 blocks per minute * 30 minutes -> 120 blocks wait period txFailureTimeout: 1800000, // in ms + evmCompatible: true, + hasTokens: true, isValidAddress: (hexAddress: string) => isValidAddress(with0x(hexAddress)), formatAddress: (hexAddress: string) => toChecksumAddress(with0x(hexAddress)), isValidTransactionHash: (hash: string) => isValidHex(hash), @@ -75,6 +81,8 @@ const chains: { [key in ChainId]: Chain } = { safeConfirmations: 5, // ~3 blocks per minute * 30 minutes -> 90 blocks wait period txFailureTimeout: 1800000, // in ms + evmCompatible: true, + hasTokens: true, isValidAddress: (hexAddress: string) => isValidAddress(with0x(hexAddress)), formatAddress: (hexAddress: string, network?: string) => toChecksumAddress(with0x(hexAddress), getRSKChainID(network)), @@ -91,6 +99,8 @@ const chains: { [key in ChainId]: Chain } = { safeConfirmations: 5, // ~20 blocks per minute * 10 minutes -> 200 blocks wait period txFailureTimeout: 600000, // in ms + evmCompatible: true, + hasTokens: true, isValidAddress: (hexAddress: string) => isValidAddress(with0x(hexAddress)), formatAddress: (hexAddress: string) => toChecksumAddress(with0x(hexAddress)), isValidTransactionHash: (hash: string) => isValidHex(hash), @@ -106,6 +116,8 @@ const chains: { [key in ChainId]: Chain } = { safeConfirmations: 10, // ~50 blocks per minute * 5 minutes -> 250 blocks wait period txFailureTimeout: 300000, // in ms + evmCompatible: false, + hasTokens: false, isValidAddress: (address) => isValidNearAddress(address), formatAddress: (address) => address, isValidTransactionHash: (hash: string) => isValidNearTx(hash), @@ -121,6 +133,8 @@ const chains: { [key in ChainId]: Chain } = { safeConfirmations: 31, // ~120 blocks per minute * 5 minutes -> 600 blocks wait period txFailureTimeout: 300000, // in ms + evmCompatible: false, + hasTokens: false, isValidAddress: (address) => isValidSolanaAddress(address), formatAddress: (address) => address, isValidTransactionHash: (hash: string) => isValidSolanaTx(hash), @@ -136,6 +150,8 @@ const chains: { [key in ChainId]: Chain } = { safeConfirmations: 1, // ~10 blocks per minute * 15 minutes -> 150 blocks wait period txFailureTimeout: 900000, // in ms + evmCompatible: false, + hasTokens: true, isValidAddress: (address) => isValidTerraAddress(address), formatAddress: (address) => address, isValidTransactionHash: (hash: string) => isValidTerraTx(hash), @@ -151,6 +167,8 @@ const chains: { [key in ChainId]: Chain } = { safeConfirmations: 5, // ~30 blocks per minute * 10 minutes -> 300 blocks wait period txFailureTimeout: 600000, // in ms + evmCompatible: true, + hasTokens: true, isValidAddress: (hexAddress: string) => isValidAddress(with0x(hexAddress)), formatAddress: (hexAddress: string) => toChecksumAddress(with0x(hexAddress)), isValidTransactionHash: (hash: string) => isValidHex(hash), @@ -166,6 +184,8 @@ const chains: { [key in ChainId]: Chain } = { safeConfirmations: 5, // ~15 blocks per minute * 10 minutes -> 150 blocks wait period txFailureTimeout: 600000, // in ms + evmCompatible: true, + hasTokens: true, isValidAddress: (hexAddress: string) => isValidAddress(with0x(hexAddress)), formatAddress: (hexAddress: string) => toChecksumAddress(with0x(hexAddress)), isValidTransactionHash: (hash: string) => isValidHex(hash), @@ -181,6 +201,8 @@ const chains: { [key in ChainId]: Chain } = { safeConfirmations: 5, // ~12 blocks per minute * 15 minutes -> 180 blocks wait period txFailureTimeout: 900000, // in ms + evmCompatible: true, + hasTokens: true, isValidAddress: (hexAddress: string) => isValidAddress(with0x(hexAddress)), formatAddress: (hexAddress: string) => toChecksumAddress(with0x(hexAddress)), isValidTransactionHash: (hash: string) => isValidHex(hash), @@ -196,6 +218,8 @@ const chains: { [key in ChainId]: Chain } = { safeConfirmations: 5, // ~15 blocks per minute * 10 minutes -> 150 blocks wait period txFailureTimeout: 600000, // in ms + evmCompatible: true, + hasTokens: true, isValidAddress: (hexAddress: string) => isValidAddress(with0x(hexAddress)), formatAddress: (hexAddress: string) => toChecksumAddress(with0x(hexAddress)), isValidTransactionHash: (hash: string) => isValidHex(hash), @@ -204,15 +228,11 @@ const chains: { [key in ChainId]: Chain } = { } function isEthereumChain(chain: ChainId) { - return [ - ChainId.BinanceSmartChain, - ChainId.Ethereum, - ChainId.Rootstock, - ChainId.Polygon, - ChainId.Avalanche, - ChainId.Arbitrum, - ChainId.Fuse - ].includes(chain) + return chains[chain].evmCompatible } -export { chains, isEthereumChain } +function hasTokens(chain: ChainId) { + return chains[chain].hasTokens +} + +export { chains, isEthereumChain, hasTokens } diff --git a/src/index.ts b/src/index.ts index 8f3c20a76..c98c89f43 100755 --- a/src/index.ts +++ b/src/index.ts @@ -1,8 +1,14 @@ import BigNumber from 'bignumber.js' -import { assets, testnetAssets, chainToTokenAddressMap, chainToTestnetTokenAddressMap } from './assets' +import { + assets, + testnetAssets, + chainToTokenAddressMap, + chainToTestnetTokenAddressMap, + getSendGasLimitERC20 +} from './assets' import { chains, isEthereumChain } from './chains' import { dappChains } from './dapps' -import { Asset, ChainId } from './types' +import { Asset, AssetType, AssetTypes, ChainId } from './types' function unitToCurrency(asset: Asset, value: number | BigNumber): BigNumber { const multiplier = new BigNumber(10).pow(asset.decimals) @@ -19,11 +25,14 @@ export { chainToTokenAddressMap, testnetAssets, chainToTestnetTokenAddressMap, + getSendGasLimitERC20, chains, dappChains, isEthereumChain, unitToCurrency, currencyToUnit, Asset, + AssetType, + AssetTypes, ChainId } diff --git a/src/types.ts b/src/types.ts index 6ac86c56a..cfcda73ca 100644 --- a/src/types.ts +++ b/src/types.ts @@ -7,13 +7,20 @@ export interface Chain { } safeConfirmations: number txFailureTimeout: number + evmCompatible: boolean + hasTokens: boolean isValidAddress: (address: string, network?: string) => boolean formatAddress: (address: string, network?: string) => string isValidTransactionHash: (hash: string) => boolean formatTransactionHash: (hash: string) => string } -export type AssetType = 'native' | 'erc20' +export enum AssetTypes { + native = 'native', + erc20 = 'erc20' +} + +export type AssetType = AssetTypes.native | AssetTypes.erc20 export enum ChainId { Bitcoin = 'bitcoin',