UNPKG

rubic-sdk

Version:
287 lines • 14.2 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.SymbiosisCrossChainProvider = void 0; const bignumber_js_1 = __importDefault(require("bignumber.js")); const errors_1 = require("../../../../../common/errors"); const no_linked_account_erros_1 = require("../../../../../common/errors/swap/no-linked-account-erros"); const tokens_1 = require("../../../../../common/tokens"); const blockchain_1 = require("../../../../../common/utils/blockchain"); const blockchain_name_1 = require("../../../../../core/blockchain/models/blockchain-name"); const chain_type_1 = require("../../../../../core/blockchain/models/chain-type"); const blockchains_info_1 = require("../../../../../core/blockchain/utils/blockchains-info/blockchains-info"); const blockchain_id_1 = require("../../../../../core/blockchain/utils/blockchains-info/constants/blockchain-id"); const web3_pure_1 = require("../../../../../core/blockchain/web3-pure/web3-pure"); const fake_wallet_address_1 = require("../../../../common/constants/fake-wallet-address"); const symbiosis_api_service_1 = require("../../../../common/providers/symbiosis/services/symbiosis-api-service"); const get_from_without_fee_1 = require("../../../../common/utils/get-from-without-fee"); const cross_chain_trade_type_1 = require("../../models/cross-chain-trade-type"); const cross_chain_provider_1 = require("../common/cross-chain-provider"); const proxy_cross_chain_evm_trade_1 = require("../common/proxy-cross-chain-evm-facade/proxy-cross-chain-evm-trade"); const symbiosis_cross_chain_factory_1 = require("./symbiosis-cross-chain-factory"); const symbiosis_utils_1 = require("./symbiosis-utils"); const on_chain_trade_type_1 = require("../../../../on-chain/calculation-manager/providers/common/models/on-chain-trade-type"); const symbiosis_cross_chain_supported_blockchains_1 = require("./models/symbiosis-cross-chain-supported-blockchains"); class SymbiosisCrossChainProvider extends cross_chain_provider_1.CrossChainProvider { constructor() { super(...arguments); this.type = cross_chain_trade_type_1.CROSS_CHAIN_TRADE_TYPE.SYMBIOSIS; } isSupportedBlockchain(blockchain) { return symbiosis_cross_chain_supported_blockchains_1.symbiosisCrossChainSupportedBlockchains.some(supportedBlockchain => supportedBlockchain === blockchain); } areSupportedBlockchains(fromBlockchain, toBlockchain) { return super.areSupportedBlockchains(fromBlockchain, toBlockchain); } // eslint-disable-next-line complexity async calculate(from, toToken, options) { const fromBlockchain = from.blockchain; const toBlockchain = toToken.blockchain; // @TODO remove after gas fix for metis const useProxy = from.blockchain === blockchain_name_1.BLOCKCHAIN_NAME.METIS ? false : options?.useProxy?.[this.type] ?? true; let disabledTrade = {}; try { const fromAddress = options.fromAddress || this.getWalletAddress(fromBlockchain) || this.getFakeAddress(fromBlockchain); const feeInfo = await this.getFeeInfo(fromBlockchain, options.providerAddress, from, useProxy); const fromWithoutFee = (0, get_from_without_fee_1.getFromWithoutFee)(from, feeInfo.rubicProxy?.platformFee?.percent); const tokenIn = { chainId: symbiosis_utils_1.SymbiosisUtils.getChainId(from), address: this.getTokenAddress(from), decimals: from.decimals, isNative: from.isNative, symbol: from.symbol }; const tokenOut = { chainId: symbiosis_utils_1.SymbiosisUtils.getChainId(toToken), address: this.getTokenAddress(toToken), decimals: toToken.decimals, isNative: toToken.isNative, symbol: toToken.symbol }; const symbiosisTokenAmountIn = { ...tokenIn, amount: fromWithoutFee.stringWeiAmount }; const deadline = Math.floor(Date.now() / 1000) + 60 * options.deadline; const slippageTolerance = options.slippageTolerance * 10000; const swapParams = { tokenAmountIn: symbiosisTokenAmountIn, tokenOut, from: fromAddress, to: this.getSwapParamsToAddress(options.receiverAddress, fromAddress, toBlockchain), revertableAddress: fromAddress, slippage: slippageTolerance, deadline }; const mockTo = new tokens_1.PriceTokenAmount({ ...toToken.asStruct, tokenAmount: web3_pure_1.Web3Pure.fromWei(0, toToken.decimals) }); disabledTrade = this.getEmptyTrade(from, mockTo, swapParams, feeInfo); try { await this.checkTokenLimits(tokenIn, from); } catch (err) { if (err instanceof errors_1.MinAmountError || err instanceof errors_1.MaxAmountError) { return { error: err, trade: disabledTrade, tradeType: this.type }; } } const { rewards, tokenAmountOut, inTradeType, outTradeType, tx, approveTo, route } = await symbiosis_api_service_1.SymbiosisApiService.getCrossChainSwapTx(swapParams); const to = new tokens_1.PriceTokenAmount({ ...toToken.asStruct, tokenAmount: web3_pure_1.Web3Pure.fromWei(tokenAmountOut.amount, tokenAmountOut.decimals) }); return { trade: symbiosis_cross_chain_factory_1.SymbiosisCrossChainFactory.createTrade(fromBlockchain, { from, to, gasData: await this.getGasData(from), priceImpact: from.calculatePriceImpactPercent(to), slippage: options.slippageTolerance, swapParams, feeInfo, transitAmount: from.tokenAmount, tradeType: { in: inTradeType, out: outTradeType }, contractAddresses: { providerRouter: 'to' in tx ? tx.to : '', providerGateway: approveTo }, ...(rewards?.length && { promotions: this.getPromotions(rewards) }) }, options.providerAddress, await this.getRoutePath(from, to, route), useProxy), tradeType: this.type }; } catch (err) { let rubicSdkError = cross_chain_provider_1.CrossChainProvider.parseError(err); const symbiosisErr = err; const symbiosisSdkError = this.handleMinAmountError(symbiosisErr); if (err?.error?.message.includes('estimateGas: execution reverted: TransferHelper::safeTransfer: transfer failed')) { rubicSdkError = new no_linked_account_erros_1.NoLinkedAccountError(); } return { trade: symbiosisSdkError ? disabledTrade : null, error: symbiosisSdkError || rubicSdkError, tradeType: this.type }; } } getPromotions(rewards) { return rewards.map(promo => `${promo.symbol}_${web3_pure_1.Web3Pure.fromWei(promo.amount, promo.decimals).toFixed()}`); } async getFeeInfo(fromBlockchain, providerAddress, percentFeeToken, useProxy) { return proxy_cross_chain_evm_trade_1.ProxyCrossChainEvmTrade.getFeeInfo(fromBlockchain, providerAddress, percentFeeToken, useProxy); } async getRoutePath(fromToken, toToken, route) { const fromChainId = blockchain_id_1.blockchainId[fromToken.blockchain]; const toChainId = blockchain_id_1.blockchainId[toToken.blockchain]; const transitFrom = [...route].reverse().find(el => el.chainId === fromChainId); const transitTo = route.find(el => el.chainId === toChainId); const fromTokenAmount = transitFrom ? await tokens_1.TokenAmount.createToken({ blockchain: fromToken.blockchain, address: transitFrom.address, weiAmount: new bignumber_js_1.default(0) }) : fromToken; const toTokenAmount = transitTo ? await tokens_1.TokenAmount.createToken({ blockchain: toToken.blockchain, address: transitTo.address, weiAmount: new bignumber_js_1.default(0) }) : toToken; const routePath = []; if (transitFrom) { routePath.push({ type: 'on-chain', provider: on_chain_trade_type_1.ON_CHAIN_TRADE_TYPE.SYMBIOSIS_SWAP, path: [fromToken, fromTokenAmount] }); } routePath.push({ type: 'cross-chain', provider: cross_chain_trade_type_1.CROSS_CHAIN_TRADE_TYPE.SYMBIOSIS, path: [fromTokenAmount, toTokenAmount] }); if (transitTo) { routePath.push({ type: 'on-chain', provider: on_chain_trade_type_1.ON_CHAIN_TRADE_TYPE.SYMBIOSIS_SWAP, path: [toTokenAmount, toToken] }); } return routePath; } getSwapParamsToAddress(receiverAddress, fromAddress, toBlockchain) { if (toBlockchain === blockchain_name_1.BLOCKCHAIN_NAME.BITCOIN && !receiverAddress) { return 'bc1qvyf8ufqpeyfe6vshfxdrr970rkqfphgz28ulhr'; } // @TODO add rubic-mock address if (toBlockchain === blockchain_name_1.BLOCKCHAIN_NAME.TON && !receiverAddress) { return 'UQATSC4TXAqjgLswuSEDVTIGmPG_kNnUTDhrTiIILVmymoQA'; } const toType = blockchains_info_1.BlockchainsInfo.getChainType(toBlockchain); if (toType === chain_type_1.CHAIN_TYPE.EVM && !receiverAddress) { return fake_wallet_address_1.FAKE_WALLET_ADDRESS; } return receiverAddress || fromAddress; } handleMinAmountError(err) { const msg = err.error?.message || ''; if (msg.includes('too low')) { const [, minAmount] = msg.toLowerCase().split('min: '); const minAmountBN = new bignumber_js_1.default(parseFloat(minAmount)); const isFeeInUSDC = minAmountBN.gt(0.5); const symbol = isFeeInUSDC ? 'USDC' : 'WETH'; return new errors_1.MinAmountError(minAmountBN, symbol); } return null; } getEmptyTrade(from, to, swapParams, feeInfo) { return symbiosis_cross_chain_factory_1.SymbiosisCrossChainFactory.createTrade(from.blockchain, { from, to: to, gasData: null, priceImpact: null, slippage: 0, swapParams, feeInfo, transitAmount: from.tokenAmount, tradeType: { in: undefined, out: undefined }, contractAddresses: { providerRouter: '', providerGateway: '' } }, '', [ { type: 'cross-chain', provider: cross_chain_trade_type_1.CROSS_CHAIN_TRADE_TYPE.SYMBIOSIS, path: [from, to] } ], true); } getTokenAddress(token) { if (token.isNative) { if (token.blockchain === blockchain_name_1.BLOCKCHAIN_NAME.METIS) { return '0xdeaddeaddeaddeaddeaddeaddeaddeaddead0000'; } // Native BTC to sBTC if (token.blockchain === blockchain_name_1.BLOCKCHAIN_NAME.BITCOIN) { return '0xc102C66D4a1e1865Ee962084626Cf4c27D5BFc74'; } // Native TON to sTON if (token.isNative && token.blockchain === blockchain_name_1.BLOCKCHAIN_NAME.TON) { return '0xA4f1b5C2fC9b97d4238B3dE3487ccaE2c36dE07C'; } } // TON USDT to sUSDT if (token.blockchain === blockchain_name_1.BLOCKCHAIN_NAME.TON && (0, blockchain_1.compareAddresses)(token.address, 'EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs')) { return '0x9328Eb759596C38a25f59028B146Fecdc3621Dfe'; } return token.address; } async checkTokenLimits(tokenIn, from) { const tokenLimits = await symbiosis_api_service_1.SymbiosisApiService.getTokenLimits(); const token = tokenLimits.find(token => (0, blockchain_1.compareAddresses)(token.address, tokenIn.address) && token.chainId === tokenIn.chainId); if (token) { const minAmountBN = web3_pure_1.Web3Pure.fromWei(token.min, from.decimals); const maxAmountBN = web3_pure_1.Web3Pure.fromWei(token.max, from.decimals); if (from.tokenAmount.lt(minAmountBN)) { throw new errors_1.MinAmountError(minAmountBN, from.symbol); } if (from.tokenAmount.gt(maxAmountBN)) { throw new errors_1.MaxAmountError(maxAmountBN, from.symbol); } } } getFakeAddress(fromBlockchain) { const chainType = blockchains_info_1.BlockchainsInfo.getChainType(fromBlockchain); if (chainType === chain_type_1.CHAIN_TYPE.EVM) { return fake_wallet_address_1.FAKE_WALLET_ADDRESS; } if (chainType === chain_type_1.CHAIN_TYPE.TON) { return 'UQATSC4TXAqjgLswuSEDVTIGmPG_kNnUTDhrTiIILVmymoQA'; } if (chainType === chain_type_1.CHAIN_TYPE.TRON) { return fake_wallet_address_1.FAKE_TRON_WALLET_ADDRESS; } if (chainType === chain_type_1.CHAIN_TYPE.BITCOIN) { return fake_wallet_address_1.FAKE_BITCOIN_ADDRESS; } throw new Error('Blockchain not supported'); } } exports.SymbiosisCrossChainProvider = SymbiosisCrossChainProvider; //# sourceMappingURL=symbiosis-cross-chain-provider.js.map