UNPKG

@broxus/js-bridge-essentials

Version:

Bridge JavaScript Essentials library

1,016 lines (1,015 loc) 89.7 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.BridgeAssetsService = void 0; const js_core_1 = require("@broxus/js-core"); const js_utils_1 = require("@broxus/js-utils"); const web3_js_1 = require("@solana/web3.js"); const buffer_1 = require("buffer"); const mobx_1 = require("mobx"); const constants_1 = require("../constants"); const models_1 = require("../models"); const types_1 = require("../types"); const utils_1 = require("../utils"); // eslint-disable-next-line import/no-relative-packages const bridge_1 = __importStar(require("../../wasm/bridge")); class BridgeAssetsService extends js_core_1.AbstractStore { params; constructor(params) { super(); this.params = params; this.setData(() => ({ assets: new Map(), currencies: [], externals: [], rawTokens: [], tokens: [], })); this.setState(() => ({ isAssetsFetched: false, isBuilt: false, isFetching: false, isTokensFetched: false, })); (0, mobx_1.makeObservable)(this); this.init().catch(js_utils_1.error); } async init() { const { assetsUrlMap, currenciesListUrl, tokensListsUrls } = this.params; const tonNetworks = (0, utils_1.onlyTonNetworks)(this.params.networks ?? []); const tonChains = tonNetworks.map(network => network.chainId.toString()); try { this.setState({ isBuilt: false, isFetching: true }); const promises = Object.entries({ ...assetsUrlMap }).map(async ([chainId, uri]) => [ chainId, await fetch(uri, { method: 'GET' }).then(value => value.json()), ]); await Promise.all(promises).then(res => { this.setData('assets', res.reduce((acc, [chainId, result]) => acc.set(chainId, result.multitoken), new Map())); }); this.setState('isAssetsFetched', Object.values(this.assets).flat().length > 0); } catch (e) { (0, js_utils_1.error)('Bridge assets fetching failed with an error', e); this.setState('isFetching', false); return; } if (currenciesListUrl) { try { const currenciesManifest = await fetch(currenciesListUrl, { method: 'GET' }).then(value => value.json()); this.setData('currencies', currenciesManifest.tokens.map(currency => { const tags = new Set((currency.tags ?? []).concat('currency')).values().toArray(); const isTonNetwork = currency.chainId ? Number(currency.chainId) === types_1.TonChains.Mainnet : false; if (isTonNetwork && ((0, js_core_1.isTvmAddress)(currency.address) || (0, utils_1.isTonAddress)(currency.address))) { return { ...currency, address: (0, utils_1.resolveTonAddress)(currency.address).toRawString(), chainId: Number(currency.chainId ?? types_1.TonChains.Mainnet), tags, }; } return { ...currency, tags }; })); } catch (e) { (0, js_utils_1.debug)('Currencies manifests fetching failed with an error', e); } } try { const entries = Object.entries({ ...tokensListsUrls }); const tokensManifests = await Promise.allSettled(entries.map(async ([vendor, lists]) => { const result = await Promise.allSettled(lists.map(async (url) => { const res = await fetch(url, { method: 'GET' }); return res.json(); })).then(res => res.map(r => (r.status === 'fulfilled' ? r.value : undefined))); return result.filter(Boolean).map(manifest => ({ ...manifest, tokens: manifest?.tokens.map(token => ({ ...token, tags: new Set((token.tags ?? []).concat(vendor)).values().toArray(), })), })); })).then(res => res.map(r => (r.status === 'fulfilled' ? r.value : undefined))); const flatten = Object.values(tokensManifests).flat(); const tokens = flatten.reduce((acc, value) => acc.concat(...value?.tokens ?? []), []); this.setData({ rawTokens: tokens.map(token => { const isTonNetwork = token.chainId ? tonChains.includes(token.chainId.toString()) : false; if (isTonNetwork && ((0, js_core_1.isTvmAddress)(token?.address) || (0, utils_1.isTonAddress)(token.address))) { return { ...token, address: (0, utils_1.resolveTonAddress)(token.address).toRawString(), chainId: Number(token.chainId ?? types_1.TonChains.Mainnet), }; } return token; }), }); } catch (e) { (0, js_utils_1.debug)('Tokens manifests fetching failed with an error', e); } finally { this.setState({ isFetching: false, isTokensFetched: true }); } await this.build(); } async build() { const exists = new Set(); const nativeCurrencies = this.tokens.slice(); const natives = []; const evmNetworks = (0, utils_1.onlyEvmNetworks)(this.params.networks ?? []); const evmConnections = new Map(); const tvmNetworks = (0, utils_1.onlyTvmNetworks)(this.params.networks ?? []); const tvmConnections = new Map(); const tonNetworks = (0, utils_1.onlyTonNetworks)(this.params.networks ?? []); const tonChains = tonNetworks.map(network => network.chainId.toString()); this._data.currencies.forEach(currency => { const isTonNetwork = currency.chainId ? tonChains.includes(currency.chainId.toString()) : false; try { if ((0, utils_1.isEvmAddress)(currency.address)) { if (currency.chainId == null) { (0, js_utils_1.debug)('Chain ID is not defined for EVM token', currency.address); return; } const chainId = currency.chainId.toString(); const connection = evmConnections.get(chainId) ?? (0, utils_1.getEvmConnection)(evmNetworks, chainId); if (!connection) { return; } evmConnections.set(chainId, connection); const key = `evm_${chainId}_${currency.address.toLowerCase()}`; if (!exists.has(key)) { natives.push(new models_1.EvmToken(connection, { address: currency.address, chainId: Number(currency.chainId), decimals: currency.decimals, key, logoURI: currency.logoURI, name: currency.name, symbol: currency.symbol, tags: new Set((currency.tags ?? []).concat('currency')), wrappedLogoURI: currency.wrappedTokenLogoURI, wrappedName: currency.wrappedTokenName, wrappedSymbol: currency.wrappedTokenSymbol, })); exists.add(key); } } else if (isTonNetwork && ((0, js_core_1.isTvmAddress)(currency.address) || (0, utils_1.isTonAddress)(currency.address))) { if (currency.chainId == null) { (0, js_utils_1.debug)('Chain ID is not defined for EVM token', currency.address); return; } const chainId = currency.chainId.toString(); const connection = tvmConnections.get(chainId) ?? (0, js_core_1.getTvmConnection)(tonNetworks, chainId); if (!connection) { return; } tvmConnections.set(chainId, connection); const root = (0, utils_1.resolveTonAddress)(currency.address).toRawString().toLowerCase(); const key = `ton_${chainId}_${root}`; if (!exists.has(key)) { natives.push(new models_1.TonToken(connection, { address: currency.address, chainId: Number(currency.chainId), decimals: currency.decimals, key, logoURI: currency.logoURI, name: currency.name, symbol: currency.symbol, tags: new Set((currency.tags ?? []).concat('currency')), wrappedLogoURI: currency.wrappedTokenLogoURI, wrappedName: currency.wrappedTokenName, wrappedSymbol: currency.wrappedTokenSymbol, })); exists.add(key); } } else if ((0, js_core_1.isTvmAddress)(currency.address)) { if (currency.chainId == null) { (0, js_utils_1.debug)('Chain ID is not defined for TVM token', currency.address); return; } const chainId = currency.chainId.toString(); const connection = tvmConnections.get(chainId) ?? (0, js_core_1.getTvmConnection)(tvmNetworks, chainId); if (!connection) { return; } tvmConnections.set(chainId, connection); const key = `tvm_${chainId}_${currency.address.toLowerCase()}`; if (!exists.has(key)) { natives.push(new js_core_1.TvmToken(connection, { address: (0, js_core_1.resolveTvmAddress)(currency.address), chainId: Number(currency.chainId), decimals: currency.decimals, key, logoURI: currency.logoURI, name: currency.name, symbol: currency.symbol, tags: new Set((currency.tags ?? []).concat('currency')), wrappedLogoURI: currency.wrappedTokenLogoURI, wrappedName: currency.wrappedTokenName, wrappedSymbol: currency.wrappedTokenSymbol, })); exists.add(key); } } else if ((0, utils_1.isSolanaAddress)(currency.address)) { const connection = this.params.getSolConnection?.(); const key = `solana_${currency.chainId}_${currency.address}`; if (connection && !exists.has(key)) { natives.push(new models_1.SolanaToken(connection, { address: new web3_js_1.PublicKey(currency.address), chainId: Number(currency.chainId), decimals: currency.decimals, key, logoURI: currency.logoURI, name: currency.name, symbol: currency.symbol, tags: new Set((currency.tags ?? []).concat('currency')), wrappedLogoURI: currency.wrappedTokenLogoURI, wrappedName: currency.wrappedTokenName, wrappedSymbol: currency.wrappedTokenSymbol, })); } } } catch { } }); this.setData('tokens', natives.concat(nativeCurrencies)); const tokens = this.tokens.slice(); this._data.rawTokens.forEach(token => { const isTonNetwork = token.chainId ? tonChains.includes(token.chainId.toString()) : false; try { if ((0, utils_1.isEvmAddress)(token.address)) { if (token.chainId == null) { (0, js_utils_1.debug)('Chain ID is not defined for EVM token', token.address); return; } const chainId = token.chainId.toString(); const connection = evmConnections.get(chainId) ?? (0, utils_1.getEvmConnection)(evmNetworks, chainId); if (!connection) { return; } evmConnections.set(chainId, connection); const key = `evm_${chainId}_${token.address.toLowerCase()}`; if (!exists.has(key)) { tokens.push(new models_1.EvmToken(connection, { address: token.address, chainId: Number(token.chainId), decimals: token.decimals, key, logoURI: token.logoURI, name: token.name, symbol: token.symbol, tags: new Set(token.tags), })); exists.add(key); } else if (this.has(key)) { const existing = this.getByKey(key); if (existing instanceof models_1.EvmToken) { const tags = existing.get('tags')?.values().toArray() ?? []; existing.setData({ tags: new Set(tags.concat(...(token.tags ?? []))), }); } } else { const existing = tokens.find(i => i.get('key') === key); if (existing instanceof models_1.EvmToken) { const tags = existing.get('tags')?.values().toArray() ?? []; existing.setData({ tags: new Set(tags.concat(...(token.tags ?? []))), }); } } } else if (isTonNetwork && ((0, js_core_1.isTvmAddress)(token.address) || (0, utils_1.isTonAddress)(token.address))) { if (token.chainId == null) { (0, js_utils_1.debug)('Chain ID is not defined for TVM token', token.address); return; } const chainId = token.chainId.toString(); const connection = tvmConnections.get(chainId) ?? (0, js_core_1.getTvmConnection)(tonNetworks, chainId); if (!connection) { return; } const root = (0, utils_1.resolveTonAddress)(token.address).toRawString().toLowerCase(); const key = `ton_${chainId}_${root}`; if (!exists.has(key)) { tokens.push(new models_1.TonToken(connection, { address: token.address, chainId: Number(token.chainId), decimals: token.decimals, key, logoURI: token.logoURI, name: token.name, symbol: token.symbol, tags: new Set(token.tags), })); exists.add(key); } else if (this.has(key)) { const existing = this.getByKey(key); if (existing instanceof models_1.TonToken) { const tags = existing.get('tags')?.values().toArray() ?? []; existing.setData({ tags: new Set(tags.concat(...(token.tags ?? []))), }); } } else { const existing = tokens.find(i => i.get('key') === key); if (existing instanceof models_1.TonToken) { const tags = existing.get('tags')?.values().toArray() ?? []; existing.setData({ tags: new Set(tags.concat(...(token.tags ?? []))), }); } } } else if ((0, js_core_1.isTvmAddress)(token.address)) { if (token.chainId == null) { (0, js_utils_1.debug)('Chain ID is not defined for TVM token', token.address); return; } const chainId = token.chainId.toString(); const connection = tvmConnections.get(chainId) ?? (0, js_core_1.getTvmConnection)(tvmNetworks, chainId); if (!connection) { return; } const key = `tvm_${chainId}_${token.address.toLowerCase()}`; if (!exists.has(key)) { tokens.push(new js_core_1.TvmToken(connection, { address: token.address, chainId: Number(token.chainId), decimals: token.decimals, key, logoURI: token.logoURI, name: token.name, symbol: token.symbol, tags: new Set(token.tags), })); exists.add(key); } else if (this.has(key)) { const existing = this.getByKey(key); if (existing instanceof js_core_1.TvmToken) { const tags = existing.get('tags')?.values().toArray() ?? []; existing.setData({ tags: new Set(tags.concat(...(token.tags ?? []))), }); } } else { const existing = tokens.find(i => i.get('key') === key); if (existing instanceof js_core_1.TvmToken) { const tags = existing.get('tags')?.values().toArray() ?? []; existing.setData({ tags: new Set(tags.concat(...(token.tags ?? []))), }); } } } else if ((0, utils_1.isSolanaAddress)(token.address)) { const connection = this.params.getSolConnection?.(); if (!connection) { return; } const key = `solana_${token.chainId}_${token.address}`; if (!exists.has(key)) { tokens.push(new models_1.SolanaToken(connection, { address: new web3_js_1.PublicKey(token.address), chainId: Number(token.chainId), decimals: token.decimals, key, logoURI: token.logoURI, name: token.name, symbol: token.symbol, tags: new Set(token.tags), })); } else if (this.has(key)) { const existing = this.getByKey(key); if (existing instanceof models_1.SolanaToken) { const tags = existing.get('tags')?.values().toArray() ?? []; existing.setData({ tags: new Set(tags.concat(...(token.tags ?? []))), }); } } else { const existing = tokens.find(i => i.get('key') === key); if (existing instanceof models_1.SolanaToken) { const tags = existing.get('tags')?.values().toArray() ?? []; existing.setData({ tags: new Set(tags.concat(...(token.tags ?? []))), }); } } } } catch { } }); this.setData('tokens', tokens); this.setState('isBuilt', true); } get assets() { return this._data.assets; } get tokens() { return this._data.tokens; } get isFetching() { return this._state.isFetching; } get(networkType, chainId, root, lowercase = true) { return this._byKey[`${networkType}_${chainId}_${lowercase ? root.toLowerCase() : root}`]; } getByRoot(root) { return this._byRoot[root]; } getByKey(root) { return this._byKey[root]; } /** * Check if token was stored to the cache. * @param {string} key * @returns {boolean} */ has(key) { return this._byKey[key] !== undefined; } /** * Add a new token to the tokens list. * @param {BridgeAsset} token */ add(token) { if (this.has(token.get('key'))) { this.setData('tokens', this.tokens.map(item => { if (item.get('key').toLowerCase() === token.get('key')?.toLowerCase()) { const isTvmTokens = item instanceof js_core_1.TvmToken && token instanceof js_core_1.TvmToken; if ((0, js_core_1.isTvmAddress)(token.root) && isTvmTokens) { return item.setData({ ...token.toJSON(), tags: new Set([ ...(item.get('tags')?.values().toArray() ?? []), ...(token.get('tags')?.values().toArray() ?? []), ]), }); } const isEvmTokens = item instanceof models_1.EvmToken && token instanceof models_1.EvmToken; if ((0, utils_1.isEvmAddress)(token.root) && isEvmTokens) { return item.setData({ ...token.toJSON(), tags: new Set([ ...(item.get('tags')?.values().toArray() ?? []), ...(token.get('tags')?.values().toArray() ?? []), ]), }); } } return item; })); } else { const tokens = this.tokens.slice(); // @ts-ignore token.setData('root', token.root); tokens.push(token); this.setData('tokens', tokens); } } /** * Remove token from the tokens list * @param {BridgeAsset} token */ remove(token) { if (this.has(token.get('key'))) { this.setData('tokens', this.tokens.filter(item => item.get('key').toLowerCase() !== token.get('key')?.toLowerCase())); } } /** * Returns the minimum required pipeline configuration for TVM - Evm transfers. * @param {string} root - TVM token root * @param {string} sourceId - source TVM network chain id * @param {string} targetId - target EVM network chain id * @returns {Promise<SolTvmPipelineConfig | undefined>} */ async resolveTvmEvmPipeline(root, sourceId, targetId) { const sourceNetwork = (0, utils_1.findNetwork)(this.params.networks ?? [], sourceId, 'tvm'); if (!sourceNetwork) { throw new Error('Cannot resolve source network config'); } const targetNetwork = (0, utils_1.findNetwork)(this.params.networks ?? [], targetId, 'evm'); if (!targetNetwork) { throw new Error('Cannot resolve target network config'); } const tvmConnection = (0, js_core_1.getTvmConnection)([], sourceId, sourceNetwork); const evmConnection = (0, utils_1.getEvmConnection)([], targetId, targetNetwork); let alien = false, merge, config = { isMerged: false, tvmTokenAddress: (0, js_core_1.resolveTvmAddress)(root), }; try { const meta = await models_1.TokenRootAlienEvm.Utils.meta(tvmConnection, root); config = { ...config, baseChainId: meta.baseChainId, evmTokenAddress: meta.evmTokenAddress, isNative: meta.baseChainId !== targetId, }; alien = meta.baseChainId === targetId; } catch (e) { (0, js_utils_1.debug)('Fetch token meta failed with an error', e); } if (!alien) { const asset = this.assets.get(sourceId)?.evm_tvm; if (!asset) { throw new Error('Evm => Tvm asset not found. Check the Bridge assets manifest.'); } try { merge = await models_1.AlienProxyV8.Utils.getEvmTokenMergeDetails(tvmConnection, asset.proxy, root, targetId); alien = merge !== undefined; } catch (e) { (0, js_utils_1.debug)('Fetch merge details failed with an error', e); } if (!merge) { try { merge = await models_1.AlienProxyV9.Utils.getEvmTokenMergeDetails(tvmConnection, asset.proxy, root, targetId); alien = merge !== undefined; } catch (e) { (0, js_utils_1.debug)('Fetch merge details failed with an error', e); } } } if (alien) { const asset = this.assets.get(sourceId)?.evm_tvm; if (!asset) { throw new Error('Evm => Tvm asset not found. Check the Bridge assets manifest.'); } const assetVault = asset.vaults.find(item => item.chainId === targetId); if (!assetVault) { throw new Error('Evm => Tvm vault not found. Check the Bridge assets manifest.'); } config = { ...config, ...merge, evmConfigurationAddress: (0, js_core_1.resolveTvmAddress)(assetVault.ethereumConfiguration), isNative: false, proxyAddress: (0, js_core_1.resolveTvmAddress)(asset.proxy), tokenBase: 'evm', vaultAddress: assetVault.vault, }; if (merge?.evmTokenAddress) { config.evmTokenAddress = merge.evmTokenAddress; } if (merge?.canonicalAddress) { config.tvmTokenAddress = merge.canonicalAddress; } } else { const asset = this.assets.get(sourceId)?.tvm_evm; if (!asset) { throw new Error('Tvm => Evm asset not found. Check the Bridge assets manifest.'); } const assetVault = asset.vaults.find(item => item.chainId === targetId); if (!assetVault) { throw new Error('Tvm => Evm vault not found. Check the Bridge assets manifest.'); } config = { ...config, evmConfigurationAddress: (0, js_core_1.resolveTvmAddress)(assetVault.ethereumConfiguration), isNative: true, proxyAddress: (0, js_core_1.resolveTvmAddress)(asset.proxy), tokenBase: 'tvm', vaultAddress: assetVault.vault, }; try { const evmTokenAddress = await models_1.EvmMultiVault.Utils.getNativeToken(evmConnection, config.vaultAddress.toString(), root); config.evmTokenAddress = evmTokenAddress.toLowerCase(); } catch (e) { (0, js_utils_1.debug)('EvmMultiVault.getNativeToken failed with an error', e); } } if (config.evmTokenAddress) { const meta = await models_1.EvmMultiVault.Utils.tokens(evmConnection, config.vaultAddress.toString(), config.evmTokenAddress); if (!(0, js_core_1.isAddressesEquals)(meta.custom, constants_1.EvmZeroAddress)) { config.evmTokenAddress = meta.custom; } config.depositFee = meta.depositFee; config.isBlacklisted = meta.blacklisted; config.withdrawFee = meta.withdrawFee; if (!(0, js_utils_1.isGoodNumber)(meta.activation) && evmConnection) { try { if (config.isNative) { const fees = await models_1.EvmMultiVault.Utils.getNativeFees(evmConnection, config.vaultAddress.toString()); config.depositFee = fees.depositFee; config.withdrawFee = fees.withdrawFee; } else { const fees = await models_1.EvmMultiVault.Utils.getAlienFees(evmConnection, config.vaultAddress.toString()); config.depositFee = fees.depositFee; config.withdrawFee = fees.withdrawFee; } } catch (e) { } } try { config.tvmConfigurationAddress = config.isNative ? await models_1.NativeProxyV6.Utils.getTvmEvmConfiguration(tvmConnection, config.proxyAddress) : await models_1.AlienProxyV8.Utils.getTvmEvmConfiguration(tvmConnection, config.proxyAddress); } catch (e) { config.tvmConfigurationAddress = config.isNative ? await models_1.NativeProxyV7.Utils.getTvmEvmConfiguration(tvmConnection, config.proxyAddress) : await models_1.AlienProxyV9.Utils.getTvmEvmConfiguration(tvmConnection, config.proxyAddress); } } if (!config.evmTokenAddress) { throw new Error('EVM token address is not defined'); } const evmWrappedCurrency = targetNetwork.currency.wrappedCurrencyAddress; const tvmWrappedCurrency = sourceNetwork.currency.wrappedCurrencyAddress; config = { ...config, isNativeEvmCurrency: (0, js_core_1.isAddressesEquals)(config.evmTokenAddress, evmWrappedCurrency), isNativeTvmCurrency: (0, js_core_1.isAddressesEquals)(config.tvmTokenAddress, tvmWrappedCurrency), }; return new models_1.TvmEvmPipelineConfig(config); } /** * Returns the minimum required pipeline configuration for Solana - TVM transfers. * @param {string} root - EVM token root * @param {string} sourceId - source EVM network chain id * @param {string} targetId - target TVM network chain id * @param {BridgeAsset} fallbackAsset * @returns {Promise<SolTvmPipelineConfig | undefined>} */ async resolveEvmTvmPipeline(root, sourceId, targetId, fallbackAsset) { const sourceNetwork = (0, utils_1.findNetwork)(this.params.networks ?? [], sourceId, 'evm'); if (!sourceNetwork) { throw new Error('Cannot resolve source network config'); } const targetNetwork = (0, utils_1.findNetwork)(this.params.networks ?? [], targetId, 'tvm'); if (!targetNetwork) { throw new Error('Cannot resolve target network config'); } const evmConnection = (0, utils_1.getEvmConnection)([], sourceId, sourceNetwork); const tvmConnection = (0, js_core_1.getTvmConnection)([], targetId, targetNetwork); if (!evmConnection) { throw new Error('Connection cannot be defined'); } const asset = this.assets.get(targetId)?.evm_tvm; if (!asset) { throw new Error('Evm => Tvm asset not found. Check the Bridge assets manifest.'); } const assetVault = asset?.vaults.find(item => item.chainId === sourceId); if (!assetVault) { throw new Error('Evm => Tvm vault not found. Check the Bridge assets manifest.'); } let config = { evmTokenAddress: root, isMerged: false, proxyAddress: (0, js_core_1.resolveTvmAddress)(asset.proxy), }; config = { ...config, evmConfigurationAddress: (0, js_core_1.resolveTvmAddress)(assetVault.ethereumConfiguration), vaultAddress: assetVault.vault, }; let meta = await models_1.EvmMultiVault.Utils.tokens(evmConnection, assetVault.vault, root); if (meta.isNative) { const oppositeAsset = this.assets.get(targetId)?.tvm_evm; if (!oppositeAsset) { throw new Error('Tvm => Evm asset not found. Check the Bridge assets manifest.'); } const oppositeVault = oppositeAsset?.vaults.find(item => item.chainId === sourceId); if (!oppositeVault) { throw new Error('Tvm => Evm vault not found. Check the Bridge assets manifest.'); } config = { ...config, evmConfigurationAddress: (0, js_core_1.resolveTvmAddress)(oppositeVault.ethereumConfiguration), isNative: true, proxyAddress: (0, js_core_1.resolveTvmAddress)(oppositeAsset.proxy), tokenBase: 'tvm', vaultAddress: oppositeVault.vault, }; const tvmTokenAddress = await models_1.EvmMultiVault.Utils.natives(evmConnection, oppositeVault.vault, root); if (tvmTokenAddress) { config.tvmTokenAddress = (0, js_core_1.resolveTvmAddress)(tvmTokenAddress); } } else { config = { ...config, isNative: false, tokenBase: 'evm' }; let token = this.get('evm', sourceId, root); if (token?.symbol && this.isNativeCurrency(root)) { const tvmTokenAddress = this._data.currencies.find(i => i.chainId?.toString() === targetId?.toString() && i.symbol === token?.symbol && (0, js_core_1.isTvmAddress)(i.address))?.address; if (tvmTokenAddress) { config.tvmTokenAddress = (0, js_core_1.resolveTvmAddress)(tvmTokenAddress); } } if (!config.tvmTokenAddress) { token = await this.resolveEvmAsset(root, sourceId, fallbackAsset); if (token?.decimals !== undefined && token.name && token.symbol) { config.tvmTokenAddress = await models_1.AlienProxyV8.Utils.deriveEvmAlienTokenRoot(tvmConnection, config.proxyAddress, { chainId: sourceId, decimals: token.decimals.toString(), name: token.name, symbol: token.symbol, token: root, }); } if (config.tvmTokenAddress) { try { const merge = await models_1.AlienProxyV8.Utils.getEvmTokenMergeDetails(tvmConnection, config.proxyAddress, config.tvmTokenAddress, sourceId); config = { ...config, ...merge }; if (merge?.evmTokenAddress) { config.evmTokenAddress = merge.evmTokenAddress; } if (merge?.canonicalAddress) { config.tvmTokenAddress = merge.canonicalAddress; } } catch (e) { (0, js_utils_1.error)('Cannot define merge details for Alien token', e); } } } } meta = await models_1.EvmMultiVault.Utils.tokens(evmConnection, config.vaultAddress.toString(), root); config.depositFee = meta.depositFee; config.isBlacklisted = meta.blacklisted; config.withdrawFee = meta.withdrawFee; if (!(0, js_utils_1.isGoodNumber)(meta.activation)) { try { if (config.isNative) { const fees = await models_1.EvmMultiVault.Utils.getNativeFees(evmConnection, config.vaultAddress.toString()); config.depositFee = fees.depositFee; config.withdrawFee = fees.withdrawFee; } else { const fees = await models_1.EvmMultiVault.Utils.getAlienFees(evmConnection, config.vaultAddress.toString()); config.depositFee = fees.depositFee; config.withdrawFee = fees.withdrawFee; } } catch (e) { } } try { config.tvmConfigurationAddress = config.isNative ? await models_1.NativeProxyV6.Utils.getTvmEvmConfiguration(tvmConnection, config.proxyAddress) : await models_1.AlienProxyV8.Utils.getTvmEvmConfiguration(tvmConnection, config.proxyAddress); } catch (e) { config.tvmConfigurationAddress = config.isNative ? await models_1.NativeProxyV7.Utils.getTvmEvmConfiguration(tvmConnection, config.proxyAddress) : await models_1.AlienProxyV9.Utils.getTvmEvmConfiguration(tvmConnection, config.proxyAddress); } const evmWrappedCurrency = sourceNetwork.currency.wrappedCurrencyAddress; const tvmWrappedCurrency = targetNetwork.currency.wrappedCurrencyAddress; config = { ...config, isNativeEvmCurrency: (0, js_core_1.isAddressesEquals)(config.evmTokenAddress, evmWrappedCurrency), isNativeTvmCurrency: (0, js_core_1.isAddressesEquals)(config.tvmTokenAddress, tvmWrappedCurrency), }; return new models_1.EvmTvmPipelineConfig(config); } /** * Returns the minimum required pipeline configuration for TVM - Solana transfers. * @param {string} root - TVM token root * @param {string} sourceId - source Solana network chain id * @param {string} targetId - target TVM network chain id * @returns {Promise<SolTvmPipelineConfig | undefined>} */ async resolveTvmSolPipeline(root, sourceId, targetId) { const connection = this.params.getSolConnection?.(); if (!connection) { throw new Error('Solana connection is not provided'); } const sourceNetwork = (0, utils_1.findNetwork)(this.params.networks ?? [], sourceId, 'tvm'); if (!sourceNetwork) { throw new Error('Cannot resolve source network config'); } const targetNetwork = (0, utils_1.findNetwork)(this.params.networks ?? [], targetId, 'solana'); if (!targetNetwork) { throw new Error('Cannot resolve target network config'); } const tvmConnection = (0, js_core_1.getTvmConnection)([], sourceId, sourceNetwork); let alien = false, merge, config = { isMerged: false, tvmTokenAddress: (0, js_core_1.resolveTvmAddress)(root), }; // First, we should check alien token root meta. // If request is not falling - token is alien TVM and based in Solana // Otherwise token is steel native for TVM try { const meta = await models_1.TokenRootAlienSolana.Utils.meta(tvmConnection, root); config = { ...config, isNative: false, solTokenAddress: (0, utils_1.resolveSolanaAddress)(meta.solTokenAddress), tokenBase: 'solana', }; alien = true; } catch (e) { (0, js_utils_1.debug)('Fetch token meta failed with an error', e); } if (!alien) { const asset = this.assets.get(sourceId)?.solana_tvm; if (!asset) { throw new Error('Solana => Tvm asset not found. Check the Bridge assets manifest.'); } try { merge = await models_1.AlienProxyV8.Utils.getSolTokenMergeDetails(tvmConnection, asset.proxy, root); alien = merge !== undefined; } catch (e) { (0, js_utils_1.debug)('Fetch merge details failed with an error', e); } if (!merge) { try { merge = await models_1.AlienProxyV9.Utils.getSolTokenMergeDetails(tvmConnection, asset.proxy, root); alien = merge !== undefined; } catch (e) { (0, js_utils_1.debug)('Fetch merge details failed with an error', e); } } } if (alien) { const asset = this.assets.get(sourceId)?.solana_tvm; if (!asset) { throw new Error('Solana => Tvm asset not found. Check the Bridge assets manifest.'); } config = { ...config, ...merge, isNative: false, proxyAddress: (0, js_core_1.resolveTvmAddress)(asset.proxy), solConfigurationAddress: (0, js_core_1.resolveTvmAddress)(asset.solanaConfiguration), tokenBase: 'solana', tvmConfigurationAddress: (0, js_core_1.resolveTvmAddress)(asset.tvmConfiguration), }; if (merge?.solTokenAddress) { config.solTokenAddress = merge.solTokenAddress; } if (merge?.canonicalAddress) { config.tvmTokenAddress = merge.canonicalAddress; } } else { const asset = this.assets.get(sourceId)?.tvm_solana; if (!asset) { throw new Error('Tvm => Solana asset not found. Check the Bridge assets manifest.'); } config = { ...config, isNative: true, proxyAddress: (0, js_core_1.resolveTvmAddress)(asset.proxy), solConfigurationAddress: (0, js_core_1.resolveTvmAddress)(asset.solanaConfiguration), tokenBase: 'tvm', tvmConfigurationAddress: (0, js_core_1.resolveTvmAddress)(asset.tvmConfiguration), vaultAddress: (0, utils_1.resolveSolanaAddress)(asset.vault), }; } try { await (0, bridge_1.default)(); let tokenSettingsAddress; if (config.isNative) { if (config.tvmTokenAddress === undefined) { (0, js_utils_1.error)('TVM token root is not defined'); return undefined; } tokenSettingsAddress = (0, bridge_1.getTokenSettingsAddress)(config.tvmTokenAddress.toString(), false); } else { if (config.solTokenAddress === undefined) { (0, js_utils_1.error)('Solana token mint root is not defined'); return undefined; } tokenSettingsAddress = (0, bridge_1.getTokenSettingsAddress)(config.solTokenAddress.toBase58(), true); } tokenSettingsAddress = new web3_js_1.PublicKey(tokenSettingsAddress); const tokenSettings = await connection.getAccountInfo(tokenSettingsAddress); if (tokenSettings?.data) { const settings = (0, bridge_1.unpackTokenSettings)(tokenSettings.data); config = { ...config, depositFee: settings.fee_deposit_info.multiplier.toString(), solTokenSettingsAddress: tokenSettingsAddress, withdrawFee: settings.fee_withdrawal_info.multiplier.toString(), }; if ('Solana' in settings.kind) { config.vaultAddress = (0, utils_1.resolveSolanaAddress)(settings.kind.Solana.vault); } else if ('Ever' in settings.kind) { config.solTokenAddress = (0, utils_1.resolveSolanaAddress)(settings.kind.Ever.mint); } } else { const solTokenAddress = await (0, bridge_1.getMintAddress)(root); config.solTokenAddress = new web3_js_1.PublicKey(solTokenAddress); } } catch (e) { (0, js_utils_1.error)(e); } const solWrappedCurrency = targetNetwork.currency.wrappedCurrencyAddress; const tvmWrappedCurrency = sourceNetwork.currency.wrappedCurrencyAddress; config = { ...config, isNativeSolCurrency: solWrappedCurrency?.equals(config.solTokenAddress) ?? false, isNativeTvmCurrency: (0, js_core_1.isAddressesEquals)(config.tvmTokenAddress, tvmWrappedCurrency), }; return new models_1.TvmSolPipelineConfig(config); } /** * Returns the minimum required pipeline configuration for Solana - TVM transfers. * @param {string} root - Solana mint address * @param {string} sourceId - source Solana network chain id * @param {string} targetId - target TVM network chain id * @returns {Promise<SolTvmPipelineConfig | undefined>} */ async resolveSolTvmPipeline(root, sourceId, targetId) { const connection = this.params.getSolConnection?.(); if (!connection) { throw new Error('Solana connection is not provided'); } const sourceNetwork = (0, utils_1.findNetwork)(this.params.networks ?? [], sourceId, 'solana'); if (!sourceNetwork) { throw new Error('Cannot resolve source network config'); } const targetNetwork = (0, utils_1.findNetwork)(this.params.networks ?? [], targetId, 'tvm'); if (!targetNetwork) { throw new Error('Cannot resolve target network config'); } const tvmConnection = (0, js_core_1.getTvmConnection)([], targetId, targetNetwork); let config = { isMerged: false, }; const isSol = !(0, js_core_1.isTvmAddress)(root); if (isSol) { config.solTokenAddress = (0, utils_1.resolveSolanaAddress)(root); } else { config.tvmTokenAddress = (0, js_core_1.resolveTvmAddress)(root); } try { await (0, bridge_1.default)(); let tokenSettingsAddress = (0, bridge_1.getTokenSettingsAddress)(root, isSol); tokenSettingsAddress = new web3_js_1.PublicKey(tokenSettingsAddress); const tokenSettings = await connection.getAccountInfo(tokenSettingsAddress); if (tokenSettings?.data == null) { (0, js_utils_1.error)('Token settings is not provided');