UNPKG

rubic-sdk

Version:
275 lines • 13.5 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.LifiCrossChainProvider = void 0; const bignumber_js_1 = __importDefault(require("bignumber.js")); const errors_1 = require("../../../../../common/errors"); const tokens_1 = require("../../../../../common/tokens"); const native_tokens_1 = require("../../../../../common/tokens/constants/native-tokens"); const blockchain_name_1 = require("../../../../../core/blockchain/models/blockchain-name"); const blockchains_info_1 = require("../../../../../core/blockchain/utils/blockchains-info/blockchains-info"); const web3_pure_1 = require("../../../../../core/blockchain/web3-pure/web3-pure"); const injector_1 = require("../../../../../core/injector/injector"); const get_from_without_fee_1 = require("../../../../common/utils/get-from-without-fee"); const get_solana_fee_1 = require("../../../../common/utils/get-solana-fee"); const cross_chain_trade_type_1 = require("../../models/cross-chain-trade-type"); const cross_chain_provider_1 = require("../common/cross-chain-provider"); const bridge_type_1 = require("../common/models/bridge-type"); const proxy_cross_chain_evm_trade_1 = require("../common/proxy-cross-chain-evm-facade/proxy-cross-chain-evm-trade"); const lifi_cross_chain_supported_blockchain_1 = require("./constants/lifi-cross-chain-supported-blockchain"); const lifi_bridge_types_1 = require("./models/lifi-bridge-types"); const lifi_providers_1 = require("../../../../on-chain/calculation-manager/providers/aggregators/lifi/constants/lifi-providers"); const on_chain_trade_type_1 = require("../../../../on-chain/calculation-manager/providers/common/models/on-chain-trade-type"); const lifi_utils_service_1 = require("../../../../common/providers/lifi/lifi-utils-service"); const lifi_cross_chain_factory_1 = require("./lifi-cross-chain-factory"); const lifi_api_service_1 = require("./services/lifi-api-service"); class LifiCrossChainProvider extends cross_chain_provider_1.CrossChainProvider { constructor() { super(...arguments); this.type = cross_chain_trade_type_1.CROSS_CHAIN_TRADE_TYPE.LIFI; } isSupportedBlockchain(blockchain) { return lifi_cross_chain_supported_blockchain_1.lifiCrossChainSupportedBlockchains.some(supportedBlockchain => supportedBlockchain === blockchain); } async calculate(from, toToken, options) { const fromBlockchain = from.blockchain; const toBlockchain = toToken.blockchain; const useProxy = options?.useProxy?.[this.type] ?? true; const { disabledBridges, disabledDexes } = this.mapDisabledProviders(options.lifiDisabledBridgeTypes || []); const routeOptions = { slippage: options.slippageTolerance, order: 'RECOMMENDED', allowSwitchChain: false, bridges: { deny: disabledBridges }, exchanges: { deny: disabledDexes }, integrator: 'rubic' }; const fromTokenAddress = lifi_utils_service_1.LifiUtilsService.getLifiTokenAddress(from.blockchain, from.isNative, from.address); const toTokenAddress = lifi_utils_service_1.LifiUtilsService.getLifiTokenAddress(toToken.blockchain, toToken.isNative, toToken.address); const fromChainId = lifi_utils_service_1.LifiUtilsService.getLifiChainId(fromBlockchain); const toChainId = lifi_utils_service_1.LifiUtilsService.getLifiChainId(toBlockchain); const feeInfo = await this.getFeeInfo(fromBlockchain, options.providerAddress, from, useProxy); const rubicPercentFeeForSolana = (0, get_solana_fee_1.getSolanaFee)(from) * 100; const feePercent = from.blockchain === blockchain_name_1.BLOCKCHAIN_NAME.SOLANA ? rubicPercentFeeForSolana : feeInfo.rubicProxy?.platformFee?.percent; const fromWithoutFee = (0, get_from_without_fee_1.getFromWithoutFee)(from, feePercent); const fromAddress = this.getWalletAddress(fromBlockchain); const toAddress = lifi_utils_service_1.LifiUtilsService.getLifiReceiverAddress(fromBlockchain, toBlockchain, fromAddress, options?.receiverAddress); const routesRequest = { fromChainId, fromAmount: fromWithoutFee.stringWeiAmount, fromTokenAddress, toChainId, toTokenAddress, options: routeOptions, ...(fromAddress && { fromAddress }), ...(toAddress && { toAddress }) }; const result = await lifi_api_service_1.LifiApiService.getRoutes(routesRequest); const { routes } = result; const bestRoute = routes.find(route => route.steps.length === 1 && !route.containsSwitchChain); if (!bestRoute) { throw new errors_1.RubicSdkError('No available routes'); } const providerFee = bestRoute.steps[0].estimate.feeCosts?.find((el) => el?.included === false); const nativeToken = await tokens_1.PriceToken.createFromToken(native_tokens_1.nativeTokensList[from.blockchain]); if (providerFee && providerFee.amount !== '0') { feeInfo.provider = { cryptoFee: { amount: web3_pure_1.Web3Pure.fromWei(new bignumber_js_1.default(providerFee.amount), providerFee.token.decimals), token: nativeToken } }; } from = new tokens_1.PriceTokenAmount({ ...from.asStructWithAmount, price: new bignumber_js_1.default(bestRoute.fromAmountUSD).dividedBy(from.tokenAmount) }); const to = new tokens_1.PriceTokenAmount({ ...toToken.asStruct, weiAmount: new bignumber_js_1.default(bestRoute.toAmount) }); const priceImpact = from.calculatePriceImpactPercent(to); const { onChainType, bridgeType } = this.parseTradeTypes(bestRoute.steps); const trade = lifi_cross_chain_factory_1.LifiCrossChainFactory.createTrade(fromBlockchain, { from, to, route: bestRoute, gasData: await this.getLifiGasData(from, bestRoute.steps[0]), toTokenAmountMin: web3_pure_1.Web3Pure.fromWei(bestRoute.toAmountMin, to.decimals), feeInfo, priceImpact, onChainSubtype: onChainType, bridgeType: bridgeType || bridge_type_1.BRIDGE_TYPE.LIFI, slippage: options.slippageTolerance }, options.providerAddress, await this.getRoutePath(from, to, bestRoute), useProxy); try { const minAmountUSD = this.getMinAmountUSD(); this.checkMinError(from, minAmountUSD); } catch (err) { return { trade, error: err, tradeType: this.type }; } return { trade, tradeType: this.type }; } checkMinError(from, minAmountUsd) { const fromUsdAmount = from.price.multipliedBy(from.tokenAmount); if (fromUsdAmount.lt(minAmountUsd)) { if (from.price.gt(0)) { const minTokenAmount = minAmountUsd .multipliedBy(from.tokenAmount) .dividedBy(fromUsdAmount); throw new errors_1.MinAmountError(minTokenAmount, from.symbol); } throw new errors_1.MinAmountError(minAmountUsd, 'USDC'); } } async getFeeInfo(fromBlockchain, providerAddress, percentFeeToken, useProxy) { return proxy_cross_chain_evm_trade_1.ProxyCrossChainEvmTrade.getFeeInfo(fromBlockchain, providerAddress, percentFeeToken, useProxy); } parseTradeTypes(bestRouteSteps) { if (!bestRouteSteps[0]) { return { onChainType: { from: undefined, to: undefined }, bridgeType: undefined }; } const steps = bestRouteSteps[0].includedSteps; if (!steps[0]) { return { onChainType: { from: undefined, to: undefined }, bridgeType: undefined }; } const sourceDex = steps[0].action.fromChainId === steps[0].action.toChainId ? steps?.[0].toolDetails.name.toLowerCase() : undefined; const targetDex = steps ?.slice(1) ?.find(provider => provider.action.fromChainId === provider.action.toChainId) ?.toolDetails.name.toLowerCase(); let subType = bestRouteSteps ?.find(provider => provider.action.fromChainId !== provider.action.toChainId) ?.tool.toLowerCase(); subType = subType === 'amarok' ? bridge_type_1.BRIDGE_TYPE.AMAROK : subType; const onChainType = { from: sourceDex ? lifi_providers_1.LIFI_API_ON_CHAIN_PROVIDERS[sourceDex] : undefined, to: targetDex ? lifi_providers_1.LIFI_API_ON_CHAIN_PROVIDERS[targetDex] : undefined }; const bridgeType = bridge_type_1.bridges.find(bridge => bridge.toLowerCase() === subType); return { onChainType, bridgeType }; } mapDisabledProviders(disabledProviders) { const disabledBridges = []; const disabledDexes = []; for (let i = 0; i < disabledProviders.length; i++) { const provider = disabledProviders[i]; const isBridge = Object.values(lifi_bridge_types_1.LIFI_API_CROSS_CHAIN_PROVIDERS).includes(provider); if (isBridge) { disabledBridges.push(provider); continue; } const isDex = Object.keys(lifi_providers_1.LIFI_API_ON_CHAIN_PROVIDERS).includes(provider); if (isDex) { disabledDexes.push(provider); } } return { disabledBridges, disabledDexes }; } async getRoutePath(from, to, route) { const lifiSteps = route.steps[0].includedSteps; const crossChainStep = lifiSteps.find(el => el.type === 'cross'); const isFromNativeSolanaToken = from.isNative && from.blockchain === blockchain_name_1.BLOCKCHAIN_NAME.SOLANA; const isToNativeSolanaToken = to.isNative && to.blockchain === blockchain_name_1.BLOCKCHAIN_NAME.SOLANA; const fromTransit = isFromNativeSolanaToken ? from.address : crossChainStep.action.fromToken.address; const toTransit = isToNativeSolanaToken ? to.address : crossChainStep.action.toToken.address; const fromTokenAmount = await tokens_1.TokenAmount.createToken({ address: fromTransit, blockchain: from.blockchain, weiAmount: new bignumber_js_1.default(crossChainStep.action.fromAmount) }); const toTokenAmount = await tokens_1.TokenAmount.createToken({ address: toTransit, blockchain: to.blockchain, weiAmount: new bignumber_js_1.default(crossChainStep.estimate.toAmount) }); // @TODO Add dex true provider and path const routePath = []; if (lifiSteps?.[0]?.type === 'swap') { routePath.push({ type: 'on-chain', path: [from, fromTokenAmount], provider: on_chain_trade_type_1.ON_CHAIN_TRADE_TYPE.LIFI }); } routePath.push({ type: 'cross-chain', path: [fromTokenAmount, toTokenAmount], provider: cross_chain_trade_type_1.CROSS_CHAIN_TRADE_TYPE.LIFI }); if (lifiSteps?.[2]?.type === 'swap') { routePath.push({ type: 'on-chain', path: [toTokenAmount, to], provider: on_chain_trade_type_1.ON_CHAIN_TRADE_TYPE.LIFI }); } return routePath; } async getLifiGasData(from, step) { if (!blockchains_info_1.BlockchainsInfo.isEvmBlockchainName(from.blockchain)) { return Promise.resolve(null); } const gasCosts = step.estimate.gasCosts; if (!gasCosts || !gasCosts.length) { return Promise.resolve(null); } let gasLimit = new bignumber_js_1.default(0); for (const el of gasCosts) { gasLimit = gasLimit.plus(el.limit); } try { const gasPriceInfo = await injector_1.Injector.gasPriceApi.getGasPrice(from.blockchain); return { gasLimit: new bignumber_js_1.default(gasLimit), ...(gasPriceInfo.gasPrice && { gasPrice: new bignumber_js_1.default(gasPriceInfo.gasPrice) }), ...(gasPriceInfo.baseFee && { baseFee: new bignumber_js_1.default(gasPriceInfo.baseFee) }), ...(gasPriceInfo.maxFeePerGas && { maxFeePerGas: new bignumber_js_1.default(gasPriceInfo.maxFeePerGas) }), ...(gasPriceInfo.maxPriorityFeePerGas && { maxPriorityFeePerGas: new bignumber_js_1.default(gasPriceInfo.maxPriorityFeePerGas) }) }; } catch { return null; } } getMinAmountUSD() { return new bignumber_js_1.default(1); } } exports.LifiCrossChainProvider = LifiCrossChainProvider; //# sourceMappingURL=lifi-cross-chain-provider.js.map