@sky-mavis/smart-order-router
Version:
Ronin Swap Smart Order Router
131 lines • 14.2 kB
JavaScript
import { Protocol } from '@uniswap/router-sdk';
import { TradeType } from '@uniswap/sdk-core';
import _ from 'lodash';
import { TokenValidationResult, } from '../../../providers';
import { log, metric, MetricLoggerUnit, routeToString } from '../../../util';
import { V2RouteWithValidQuote } from '../entities';
import { computeAllV2Routes } from '../functions/compute-all-routes';
import { NATIVE_OVERHEAD } from '../gas-models/v3/gas-costs';
import { BaseQuoter } from './base-quoter';
export class V2Quoter extends BaseQuoter {
constructor(v2SubgraphProvider, v2PoolProvider, v2QuoteProvider, v2GasModelFactory, tokenProvider, chainId, blockedTokenListProvider, tokenValidatorProvider) {
super(tokenProvider, chainId, Protocol.V2, blockedTokenListProvider, tokenValidatorProvider);
this.v2SubgraphProvider = v2SubgraphProvider;
this.v2PoolProvider = v2PoolProvider;
this.v2QuoteProvider = v2QuoteProvider;
this.v2GasModelFactory = v2GasModelFactory;
}
async getRoutes(tokenIn, tokenOut, v2CandidatePools, _tradeType, routingConfig) {
const beforeGetRoutes = Date.now();
// Fetch all the pools that we will consider routing via. There are thousands
// of pools, so we filter them to a set of candidate pools that we expect will
// result in good prices.
const { poolAccessor, candidatePools } = v2CandidatePools;
const poolsRaw = poolAccessor.getAllPools();
// Drop any pools that contain tokens that can not be transferred according to the token validator.
const pools = await this.applyTokenValidatorToPools(poolsRaw, (token, tokenValidation) => {
// If there is no available validation result we assume the token is fine.
if (!tokenValidation) {
return false;
}
// Only filters out *intermediate* pools that involve tokens that we detect
// cant be transferred. This prevents us trying to route through tokens that may
// not be transferrable, but allows users to still swap those tokens if they
// specify.
if (tokenValidation == TokenValidationResult.STF && (token.equals(tokenIn) || token.equals(tokenOut))) {
return false;
}
return tokenValidation == TokenValidationResult.STF;
});
// Given all our candidate pools, compute all the possible ways to route from tokenIn to tokenOut.
const { maxSwapsPerPath } = routingConfig;
const routes = computeAllV2Routes(tokenIn, tokenOut, pools, maxSwapsPerPath);
metric.putMetric('V2GetRoutesLoad', Date.now() - beforeGetRoutes, MetricLoggerUnit.Milliseconds);
return {
routes,
candidatePools,
};
}
async getQuotes(routes, amounts, percents, quoteToken, tradeType, _routingConfig, candidatePools, _gasModel, gasPriceWei) {
const beforeGetQuotes = Date.now();
log.info('Starting to get V2 quotes');
if (gasPriceWei === undefined) {
throw new Error('GasPriceWei for V2Routes is required to getQuotes');
}
// throw if we have no amounts or if there are different tokens in the amounts
if (amounts.length == 0 || !amounts.every(amount => amount.currency.equals(amounts[0].currency))) {
throw new Error('Amounts must have at least one amount and must be same token');
}
// safe to force unwrap here because we throw if there are no amounts
const amountToken = amounts[0].currency;
const gasToken = _routingConfig.gasToken
? (await this.tokenProvider.getTokens([_routingConfig.gasToken])).getTokenByAddress(_routingConfig.gasToken)
: undefined;
if (routes.length == 0) {
return { routesWithValidQuotes: [], candidatePools };
}
// For all our routes, and all the fractional amounts, fetch quotes on-chain.
const quoteFn = tradeType == TradeType.EXACT_INPUT
? this.v2QuoteProvider.getQuotesManyExactIn.bind(this.v2QuoteProvider)
: this.v2QuoteProvider.getQuotesManyExactOut.bind(this.v2QuoteProvider);
const beforeQuotes = Date.now();
log.info(`Getting quotes for V2 for ${routes.length} routes with ${amounts.length} amounts per route.`);
const { routesWithQuotes } = await quoteFn(amounts, routes, _routingConfig);
const v2GasModel = await this.v2GasModelFactory.buildGasModel({
chainId: this.chainId,
gasPriceWei,
poolProvider: this.v2PoolProvider,
token: quoteToken,
providerConfig: {
..._routingConfig,
additionalGasOverhead: NATIVE_OVERHEAD(amountToken, quoteToken),
gasToken,
},
});
metric.putMetric('V2QuotesLoad', Date.now() - beforeQuotes, MetricLoggerUnit.Milliseconds);
metric.putMetric('V2QuotesFetched', _(routesWithQuotes)
.map(([, quotes]) => quotes.length)
.sum(), MetricLoggerUnit.Count);
const routesWithValidQuotes = [];
for (const routeWithQuote of routesWithQuotes) {
const [route, quotes] = routeWithQuote;
for (let i = 0; i < quotes.length; i++) {
const percent = percents[i];
const amountQuote = quotes[i];
const { quote, amount } = amountQuote;
if (!quote) {
log.debug({
route: routeToString(route),
amountQuote,
}, 'Dropping a null V2 quote for route.');
continue;
}
const routeWithValidQuote = new V2RouteWithValidQuote({
route,
rawQuote: quote,
amount,
percent,
gasModel: v2GasModel,
quoteToken,
tradeType,
v2PoolProvider: this.v2PoolProvider,
});
routesWithValidQuotes.push(routeWithValidQuote);
}
}
metric.putMetric('V2GetQuotesLoad', Date.now() - beforeGetQuotes, MetricLoggerUnit.Milliseconds);
return {
routesWithValidQuotes,
candidatePools,
};
}
async refreshRoutesThenGetQuotes(tokenIn, tokenOut, routes, amounts, percents, quoteToken, tradeType, routingConfig, gasPriceWei) {
const tokenPairs = [];
routes.forEach(route => route.pairs.forEach(pair => tokenPairs.push([pair.token0, pair.token1])));
return this.v2PoolProvider.getPools(tokenPairs, routingConfig).then(poolAccesor => {
const routes = computeAllV2Routes(tokenIn, tokenOut, poolAccesor.getAllPools(), routingConfig.maxSwapsPerPath);
return this.getQuotes(routes, amounts, percents, quoteToken, tradeType, routingConfig, undefined, undefined, gasPriceWei);
});
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidjItcXVvdGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL3JvdXRlcnMvYWxwaGEtcm91dGVyL3F1b3RlcnMvdjItcXVvdGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUMvQyxPQUFPLEVBQW1CLFNBQVMsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQy9ELE9BQU8sQ0FBQyxNQUFNLFFBQVEsQ0FBQztBQUV2QixPQUFPLEVBT0wscUJBQXFCLEdBQ3RCLE1BQU0sb0JBQW9CLENBQUM7QUFDNUIsT0FBTyxFQUFrQixHQUFHLEVBQUUsTUFBTSxFQUFFLGdCQUFnQixFQUFFLGFBQWEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUc3RixPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDcEQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFHckUsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQzdELE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFJM0MsTUFBTSxPQUFPLFFBQVMsU0FBUSxVQUFxQztJQU1qRSxZQUNFLGtCQUF1QyxFQUN2QyxjQUErQixFQUMvQixlQUFpQyxFQUNqQyxpQkFBcUMsRUFDckMsYUFBNkIsRUFDN0IsT0FBZ0IsRUFDaEIsd0JBQTZDLEVBQzdDLHNCQUFnRDtRQUVoRCxLQUFLLENBQUMsYUFBYSxFQUFFLE9BQU8sRUFBRSxRQUFRLENBQUMsRUFBRSxFQUFFLHdCQUF3QixFQUFFLHNCQUFzQixDQUFDLENBQUM7UUFDN0YsSUFBSSxDQUFDLGtCQUFrQixHQUFHLGtCQUFrQixDQUFDO1FBQzdDLElBQUksQ0FBQyxjQUFjLEdBQUcsY0FBYyxDQUFDO1FBQ3JDLElBQUksQ0FBQyxlQUFlLEdBQUcsZUFBZSxDQUFDO1FBQ3ZDLElB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