rubic-sdk
Version:
Simplify dApp creation
248 lines • 12.1 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.ChangenowCrossChainProvider = 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_1 = require("../../../../../common/utils/blockchain");
const blockchain_name_1 = require("../../../../../core/blockchain/models/blockchain-name");
const blockchains_info_1 = require("../../../../../core/blockchain/utils/blockchains-info/blockchains-info");
const evm_web3_pure_1 = require("../../../../../core/blockchain/web3-pure/typed-web3-pure/evm-web3-pure/evm-web3-pure");
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 changenow_cross_chain_trade_1 = require("./changenow-cross-chain-trade");
const changenow_api_blockchain_1 = require("./constants/changenow-api-blockchain");
const changenow_proxy_supported_blockchains_1 = require("./constants/changenow-proxy-supported-blockchains");
const native_addresses_1 = require("./constants/native-addresses");
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 typed_trade_providers_1 = require("../../../../on-chain/calculation-manager/constants/trade-providers/typed-trade-providers");
const changenow_cross_chain_api_service_1 = require("./services/changenow-cross-chain-api-service");
class ChangenowCrossChainProvider extends cross_chain_provider_1.CrossChainProvider {
constructor() {
super(...arguments);
this.type = cross_chain_trade_type_1.CROSS_CHAIN_TRADE_TYPE.CHANGENOW;
}
isSupportedBlockchain(blockchain) {
return Object.keys(changenow_api_blockchain_1.changenowApiBlockchain).includes(blockchain);
}
isSupportedProxyBlockchain(blockchain) {
return changenow_proxy_supported_blockchains_1.changenowProxySupportedBlockchains.some(supportedBlockchain => supportedBlockchain === blockchain);
}
// eslint-disable-next-line complexity
async calculate(from, toToken, options) {
const fromBlockchain = from.blockchain;
const toBlockchain = toToken.blockchain;
const useProxy = this.isSupportedProxyBlockchain(fromBlockchain) &&
(options?.useProxy?.[this.type] || false);
if (!this.areSupportedBlockchains(fromBlockchain, toBlockchain) ||
(!options.changenowFullyEnabled && !blockchains_info_1.BlockchainsInfo.isEvmBlockchainName(fromBlockchain))) {
return {
trade: null,
error: new errors_1.NotSupportedTokensError(),
tradeType: this.type
};
}
const { fromCurrency, toCurrency, transitCurrency, nativeCurrency } = await this.getChangenowCurrencies(from, toToken);
if (!toCurrency || (!fromCurrency && !transitCurrency && !nativeCurrency)) {
return {
trade: null,
error: new errors_1.NotSupportedTokensError(),
tradeType: this.type
};
}
const feeInfo = await this.getFeeInfo(fromBlockchain, options.providerAddress, from, useProxy);
const fromWithoutFee = (0, get_from_without_fee_1.getFromWithoutFee)(from, feeInfo.rubicProxy?.platformFee?.percent);
let onChainTrade = null;
let transitFromToken = fromWithoutFee;
if (!fromCurrency) {
if (!useProxy) {
return {
trade: null,
error: new errors_1.NotSupportedTokensError(),
tradeType: this.type
};
}
onChainTrade = await this.getOnChainTrade(fromWithoutFee, [], options.slippageTolerance, transitCurrency
? transitCurrency.tokenContract
: native_tokens_1.nativeTokensList[fromBlockchain].address);
if (!onChainTrade) {
return {
trade: null,
error: new errors_1.NotSupportedTokensError(),
tradeType: this.type
};
}
transitFromToken = onChainTrade.to;
}
const transit = onChainTrade ? transitCurrency || nativeCurrency : fromCurrency;
try {
const { toAmount, quoteError } = await this.fetchQuoteData(transit, toCurrency, fromWithoutFee);
const to = new tokens_1.PriceTokenAmount({
...toToken.asStruct,
tokenAmount: toAmount
});
const changenowTrade = {
from: from,
to,
toTokenAmountMin: toAmount,
fromCurrency: transit,
toCurrency,
feeInfo,
gasData: await this.getGasData(from),
onChainTrade
};
const trade = new changenow_cross_chain_trade_1.ChangenowCrossChainTrade(changenowTrade, options.providerAddress, await this.getRoutePath(from, to), useProxy);
if (quoteError) {
return {
trade,
error: quoteError,
tradeType: this.type
};
}
const error = await this.checkMinMaxAmounts(transitFromToken, transit, toCurrency);
if (error) {
return {
trade,
error,
tradeType: this.type
};
}
return { trade, tradeType: this.type };
}
catch {
const error = await this.checkMinMaxAmounts(transitFromToken, transit, toCurrency);
if (error) {
return {
trade: null,
error,
tradeType: this.type
};
}
return {
trade: null,
error: new errors_1.NotSupportedTokensError(),
tradeType: this.type
};
}
}
async getChangenowCurrencies(from, to) {
const currencies = await changenow_cross_chain_api_service_1.ChangeNowCrossChainApiService.getCurrencies();
const nativeToken = native_tokens_1.nativeTokensList[from.blockchain];
return {
fromCurrency: this.getCurrency(currencies, from),
toCurrency: this.getCurrency(currencies, to),
nativeCurrency: this.getCurrency(currencies, nativeToken),
transitCurrency: this.getTransitCurrency(currencies, from.blockchain)
};
}
async checkMinMaxAmounts(from, fromCurrency, toCurrency) {
const { minAmount, maxAmount } = await this.getMinMaxRange(fromCurrency, toCurrency);
if (minAmount.gt(from.tokenAmount)) {
return new errors_1.MinAmountError(minAmount, from.symbol);
}
if (maxAmount?.lt(from.tokenAmount)) {
return new errors_1.MaxAmountError(maxAmount, from.symbol);
}
return null;
}
isNativeAddress(token, currency) {
return native_addresses_1.nativeTokensData.some(nativeTokenData => token.blockchain === nativeTokenData.blockchain &&
(0, blockchain_1.compareAddresses)(nativeTokenData.address, token.address) &&
currency.network === changenow_api_blockchain_1.changenowApiBlockchain[nativeTokenData.blockchain] &&
currency.ticker === nativeTokenData.ticker);
}
async fetchQuoteData(fromCurrency, toCurrency, fromWithoutFee) {
try {
const res = await changenow_cross_chain_api_service_1.ChangeNowCrossChainApiService.getQuoteTx({
fromCurrency: fromCurrency.ticker,
toCurrency: toCurrency.ticker,
fromAmount: fromWithoutFee.tokenAmount.toFixed(),
fromNetwork: fromCurrency.network,
toNetwork: toCurrency.network
});
return {
toAmount: new bignumber_js_1.default(res.toAmount)
};
}
catch (err) {
const error = err?.error;
if (error?.message?.includes('Out of min amount')) {
const minAmount = new bignumber_js_1.default(error?.payload?.range?.minAmount);
return {
toAmount: new bignumber_js_1.default(0),
quoteError: new errors_1.MinAmountError(minAmount, fromWithoutFee.symbol)
};
}
throw new errors_1.RubicSdkError(error?.message);
}
}
async getMinMaxRange(fromCurrency, toCurrency) {
const response = await changenow_cross_chain_api_service_1.ChangeNowCrossChainApiService.getMinMaxRange({
fromCurrency: fromCurrency.ticker,
toCurrency: toCurrency.ticker,
fromNetwork: fromCurrency.network,
toNetwork: toCurrency.network
});
return {
minAmount: new bignumber_js_1.default(response.minAmount),
maxAmount: response.maxAmount ? new bignumber_js_1.default(response.maxAmount) : null
};
}
async getFeeInfo(fromBlockchain, providerAddress, percentFeeToken, useProxy) {
return proxy_cross_chain_evm_trade_1.ProxyCrossChainEvmTrade.getFeeInfo(fromBlockchain, providerAddress, percentFeeToken, useProxy);
}
async getOnChainTrade(from, _availableDexes, slippageTolerance, transitTokenAddress) {
const fromBlockchain = from.blockchain;
const dexes = Object.values(typed_trade_providers_1.typedTradeProviders[fromBlockchain]).filter(dex => dex.supportReceiverAddress);
const to = await tokens_1.PriceToken.createToken({
address: transitTokenAddress,
blockchain: fromBlockchain
});
const onChainTrades = (await Promise.allSettled(dexes.map(dex => dex.calculate(from, to, {
slippageTolerance,
gasCalculation: 'disabled',
useProxy: false
}))))
.filter(value => value.status === 'fulfilled')
.map(value => value.value)
.sort((a, b) => b.to.tokenAmount.comparedTo(a.to.tokenAmount));
if (!onChainTrades.length) {
return null;
}
return onChainTrades[0];
}
getCurrency(currencies, token) {
if (!token) {
return undefined;
}
const apiBlockchain = token.blockchain === blockchain_name_1.BLOCKCHAIN_NAME.AVALANCHE &&
evm_web3_pure_1.EvmWeb3Pure.isNativeAddress(token.address)
? 'cchain'
: changenow_api_blockchain_1.changenowApiBlockchain[token.blockchain];
return currencies.find(currency => currency.network === apiBlockchain &&
((currency.tokenContract === null &&
(token.isNative || this.isNativeAddress(token, currency))) ||
(currency.tokenContract &&
(0, blockchain_1.compareAddresses)(token.address, currency.tokenContract))));
}
getTransitCurrency(currencies, blockchain) {
const apiBlockchain = changenow_api_blockchain_1.changenowApiBlockchain[blockchain];
return currencies.find(currency => currency.network === apiBlockchain && currency.tokenContract !== null);
}
async getRoutePath(from, to) {
return [
{
type: 'cross-chain',
provider: cross_chain_trade_type_1.CROSS_CHAIN_TRADE_TYPE.CHANGENOW,
path: [from, to]
}
];
}
}
exports.ChangenowCrossChainProvider = ChangenowCrossChainProvider;
//# sourceMappingURL=changenow-cross-chain-provider.js.map