Skip to content

Commit

Permalink
use explorer estimation, eliminate rare bug when gate estimate was us…
Browse files Browse the repository at this point in the history
…ed over slow explorer estimate
  • Loading branch information
shrpne committed Nov 2, 2021
1 parent e92bc58 commit 8a04411
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 94 deletions.
24 changes: 23 additions & 1 deletion api/explorer.js
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ export function getProviderPoolList(address, params) {
* @param {number|string} [amountOptions.buyAmount]
* @param {number|string} [amountOptions.sellAmount]
* @param {AxiosRequestConfig} [axiosOptions]
* @return {Promise<{coins: Array<Coin>, amountIn: number|string, amountOut:number|string}>}
* @return {Promise<{coins: Array<Coin>, amountIn: number|string, amountOut:number|string, swapType:ESTIMATE_SWAP_TYPE}>}
*/
export function getSwapRoute(coin0, coin1, {buyAmount, sellAmount}, axiosOptions) {
const amount = convertToPip(buyAmount || sellAmount);
Expand All @@ -412,6 +412,28 @@ export function getSwapRoute(coin0, coin1, {buyAmount, sellAmount}, axiosOptions
.then((response) => response.data);
}

/**
* @param {string} coin0
* @param {string} coin1
* @param {Object} amountOptions
* @param {number|string} [amountOptions.buyAmount]
* @param {number|string} [amountOptions.sellAmount]
* @param {AxiosRequestConfig} [axiosOptions]
* @return {Promise<{coins: Array<Coin>, amountIn: number|string, amountOut:number|string, swapType:ESTIMATE_SWAP_TYPE}>}
*/
export function getSwapEstimate(coin0, coin1, {buyAmount, sellAmount}, axiosOptions) {
const amount = convertToPip(buyAmount || sellAmount);
let type;
if (sellAmount) {
type = 'input';
}
if (buyAmount) {
type = 'output';
}
return explorer.get(`pools/coins/${coin0}/${coin1}/estimate?type=${type}&amount=${amount}`, axiosOptions)
.then((response) => response.data);
}

/**
* @typedef {Object} StakeListInfo
* @property {Array<StakeItem>} data
Expand Down
125 changes: 32 additions & 93 deletions api/gate.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {ReplaceCoinSymbol, ReplaceCoinSymbolByPath, GetCoinId} from 'minter-js-s
import GetCoinInfo from 'minter-js-sdk/src/api/get-coin-info.js';
import GetCommissionPrice from 'minter-js-sdk/src/api/get-commission-price.js';
import {GATE_API_URL, CHAIN_ID} from '~/assets/variables.js';
import {getSwapRoute} from '@/api/explorer.js';
import {getSwapEstimate as explorerGetSwapEstimate} from '@/api/explorer.js';

const minterApi = new MinterApi({
apiType: 'gate',
Expand All @@ -40,54 +40,23 @@ export function estimateCoinSell(params, axiosOptions) {
return Promise.reject(new Error('Value to sell not specified'));
}
if (params.findRoute && params.swapFrom !== ESTIMATE_SWAP_TYPE.BANCOR) {
let estimateError;
const estimatePromise = _estimateCoinSell(params, axiosOptions)
.catch((error) => {
estimateError = error;
});
const routePromise = getSwapRoute(params.coinToSell, params.coinToBuy, {sellAmount: params.valueToSell}, {...axiosOptions, cache: estimateCache})
// ignore route errors
.catch((error) => {
console.log('getSwapRoute error ignored', error);
});
return Promise.all([estimatePromise, routePromise])
.then(([estimateData, routeData]) => {
if (estimateError && !routeData) {
throw estimateError;
}
const isRouteOnly = routeData && estimateError;
const isRouteBetter = estimateData && routeData && new Big(estimateData.will_get).lt(routeData.amountOut) && routeData.coins.length > 2;

if (isRouteOnly || isRouteBetter) {
// swap by route is better
const idRoute = routeData.coins.map((coin) => coin.id);
// remove first and last items, keep only intermediate items
idRoute.pop();
idRoute.shift();
return Promise.all([
return explorerGetSwapEstimate(params.coinToSell, params.coinToBuy, {sellAmount: params.valueToSell}, {...axiosOptions, cache: estimateCache})
.then((explorerEstimation) => {
return Promise.all([
_estimateCoinSell({
...params,
route: idRoute,
swapFrom: ESTIMATE_SWAP_TYPE.POOL,
// remove first and last items, keep only intermediate items
route: explorerEstimation.coins?.map((coin) => coin.id).slice(1, -1),
swapFrom: explorerEstimation.swapType,
}, axiosOptions),
Promise.resolve(routeData.coins),
])
.then(([estimateRouteData, route]) => {
estimateRouteData = {
...estimateRouteData,
route,
};
const isEstimateRouteBetter = estimateData && estimateRouteData && new Big(estimateData.will_get).lt(estimateRouteData.will_get);

if (isRouteOnly || isEstimateRouteBetter) {
return estimateRouteData;
} else {
// direct estimation may be better
return estimateData;
}
});
}
return estimateData;
Promise.resolve(explorerEstimation.coins),
]);
})
.then(([estimateRouteData, route]) => {
return {
...estimateRouteData,
route,
};
});
} else {
return _estimateCoinSell(params, axiosOptions);
Expand All @@ -99,53 +68,23 @@ export function estimateCoinBuy(params, axiosOptions) {
return Promise.reject(new Error('Value to buy not specified'));
}
if (params.findRoute && params.swapFrom !== ESTIMATE_SWAP_TYPE.BANCOR) {
let estimateError;
const estimatePromise = _estimateCoinBuy(params, axiosOptions)
.catch((error) => {
estimateError = error;
});
const routePromise = getSwapRoute(params.coinToSell, params.coinToBuy, {buyAmount: params.valueToBuy}, {...axiosOptions, cache: estimateCache})
// ignore route errors
.catch((error) => {
console.log('getSwapRoute error ignored', error);
});
return Promise.all([estimatePromise, routePromise])
.then(([estimateData, routeData]) => {
if (estimateError && !routeData) {
throw estimateError;
}
const isRouteOnly = routeData && estimateError;
const isRouteBetter = estimateData && routeData && new Big(estimateData.will_pay).gt(routeData.amountIn) && routeData.coins.length > 2;

if (isRouteOnly || isRouteBetter) {
const idRoute = routeData.coins.map((coin) => coin.id);
// remove first and last items, keep only intermediate items
idRoute.pop();
idRoute.shift();
return Promise.all([
_estimateCoinBuy({
...params,
route: idRoute,
swapFrom: ESTIMATE_SWAP_TYPE.POOL,
}, axiosOptions),
Promise.resolve(routeData.coins),
])
.then(([estimateRouteData, route]) => {
estimateRouteData = {
...estimateRouteData,
route,
};
const isEstimateRouteBetter = estimateData && estimateRouteData && new Big(estimateData.will_pay).gt(estimateRouteData.will_pay);

if (isRouteOnly || isEstimateRouteBetter) {
return estimateRouteData;
} else {
// direct estimation may be better
return estimateData;
}
});
}
return estimateData;
return explorerGetSwapEstimate(params.coinToSell, params.coinToBuy, {buyAmount: params.valueToBuy}, {...axiosOptions, cache: estimateCache})
.then((explorerEstimation) => {
return Promise.all([
_estimateCoinBuy({
...params,
// remove first and last items, keep only intermediate items
route: explorerEstimation.coins?.map((coin) => coin.id).slice(1, -1),
swapFrom: explorerEstimation.swapType,
}, axiosOptions),
Promise.resolve(explorerEstimation.coins),
]);
})
.then(([estimateRouteData, route]) => {
return {
...estimateRouteData,
route,
};
});
} else {
return _estimateCoinBuy(params, axiosOptions);
Expand Down

0 comments on commit 8a04411

Please sign in to comment.