rubic-sdk
Version:
Simplify dApp creation
287 lines • 14.2 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.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