rubic-sdk
Version:
Simplify dApp creation
275 lines • 13.5 kB
JavaScript
"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