@xspswap/smart-order-router
Version:
XSwap Protocol V3 Smart Order Router
202 lines • 18.2 kB
JavaScript
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { ChainId, WETH9 } from '@x-swap-protocol/sdk-core';
import { FeeAmount, Pool, UniV3Factory } from '@x-swap-protocol/v3-sdk';
import JSBI from 'jsbi';
import _ from 'lodash';
import { unparseFeeAmount } from '../../util/amounts';
import { log } from '../../util/log';
import { BBB_XDC, CGO_XDC, GAMA_XDC, SRX_XDC, stgUSDT_XDC, USDC_XDC, WXDC_XDC, } from '../token-provider';
const BASES_TO_CHECK_TRADES_AGAINST = {
[ChainId.XDC]: [WETH9[ChainId.XDC], USDC_XDC],
[ChainId.APOTHEM]: [WETH9[ChainId.APOTHEM]],
};
export const ADDITIONAL_BASES = {
[ChainId.XDC]: {
[WETH9[ChainId.XDC].address]: [
[USDC_XDC, FeeAmount.MEDIUM],
[GAMA_XDC, FeeAmount.LOWEST],
[stgUSDT_XDC, FeeAmount.MEDIUM],
[SRX_XDC, FeeAmount.MEDIUM],
[CGO_XDC, FeeAmount.MEDIUM],
[BBB_XDC, FeeAmount.MEDIUM],
[SRX_XDC, FeeAmount.HIGH],
],
[USDC_XDC.address]: [
[CGO_XDC, FeeAmount.MEDIUM],
[WXDC_XDC, FeeAmount.MEDIUM],
[SRX_XDC, FeeAmount.MEDIUM],
[stgUSDT_XDC, FeeAmount.LOW],
],
[GAMA_XDC.address]: [
[WXDC_XDC, FeeAmount.LOWEST],
[USDC_XDC, FeeAmount.LOWEST],
],
[stgUSDT_XDC.address]: [
[WXDC_XDC, FeeAmount.MEDIUM],
[USDC_XDC, FeeAmount.LOW],
],
[CGO_XDC.address]: [
[WXDC_XDC, FeeAmount.MEDIUM],
[USDC_XDC, FeeAmount.MEDIUM],
],
[BBB_XDC.address]: [[WXDC_XDC, FeeAmount.MEDIUM]],
[SRX_XDC.address]: [
[WXDC_XDC, FeeAmount.MEDIUM],
[USDC_XDC, FeeAmount.MEDIUM],
[WXDC_XDC, FeeAmount.HIGH],
],
},
[ChainId.APOTHEM]: {},
};
export const Uni_V3_XDC_ADDITIONAL_BASES = ADDITIONAL_BASES[ChainId.XDC];
let paths = [];
const recFinder = (path, used, lastToken, dest, hops) => {
const hop = path.length;
// if (hop > 0) {
// lastToken = path[hop - 1]![1];
// }
if (hop < hops) {
if (!lastToken) {
return;
}
const additional = Uni_V3_XDC_ADDITIONAL_BASES[lastToken.address];
if (additional) {
for (const ad of additional) {
const adToken = ad;
const newPair = [lastToken, ...adToken];
const newPath = [...path, newPair];
if (adToken[0].address === dest.address) {
paths.push(newPath);
continue;
}
if (!used[adToken[0].address]) {
recFinder(newPath, { ...used, [adToken[0].address]: true }, adToken[0], dest, hops);
}
}
}
}
};
/**
* Provider that uses a hardcoded list of V3 pools to generate a list of subgraph pools.
*
* Since the pools are hardcoded and the data does not come from the Subgraph, the TVL values
* are dummys and should not be depended on.
*
* Useful for instances where other data sources are unavailable. E.g. Subgraph not available.
*
* @export
* @class StaticV3SubgraphProvider
*/
export class StaticV3UniSubgraphProvider {
constructor(chainId, poolProvider) {
this.chainId = chainId;
this.poolProvider = poolProvider;
}
async getPools(tokenIn, tokenOut) {
paths = [];
log.info('In static subgraph provider for V3');
const bases = BASES_TO_CHECK_TRADES_AGAINST[this.chainId];
const basePairs = _.flatMap(bases, (base) => bases.map((otherBase) => [base, otherBase]));
let pairs = [];
if (tokenIn && tokenOut) {
const additionalIn = ADDITIONAL_BASES[this.chainId][tokenIn.address];
const additionalOut = ADDITIONAL_BASES[this.chainId][tokenOut.address];
if (!additionalIn || !additionalOut) {
basePairs.push([tokenIn, tokenOut]);
if (additionalIn) {
basePairs.push(...additionalIn.map((v) => [tokenIn, v[0]]));
}
else {
basePairs.push(...bases.map((base) => [tokenIn, base]));
}
if (additionalOut) {
basePairs.push(...additionalOut.map((v) => [tokenOut, v[0]]));
}
else {
basePairs.push(...bases.map((base) => [tokenOut, base]));
}
pairs = _(basePairs)
.filter((tokens) => Boolean(tokens[0] && tokens[1]))
.filter(([tokenA, tokenB]) => tokenA.address !== tokenB.address && !tokenA.equals(tokenB))
.flatMap(([tokenA, tokenB]) => {
const additionalA = ADDITIONAL_BASES[this.chainId][tokenA.address];
// const additionalB = ADDITIONAL_BASES[this.chainId][tokenB.address];
if (additionalA) {
const additionalPool = additionalA.filter((v) => v[0].address.toLowerCase() === tokenB.address.toLowerCase());
const res = additionalPool.map((v) => {
return [tokenA, v[0], v[1]];
});
return res;
}
return [
[tokenA, tokenB, FeeAmount.LOWEST],
[tokenA, tokenB, FeeAmount.LOW],
[tokenA, tokenB, FeeAmount.MEDIUM],
[tokenA, tokenB, FeeAmount.HIGH],
];
})
.value();
}
else {
recFinder([], { [tokenIn.address]: true }, tokenIn, tokenOut, 5);
// console.log(
// paths.map((path) =>
// path
// .map(
// (p) => `(${p[0].symbol} - ${p[1].symbol} : ${p[2] / 10000}% )`
// )
// .join(' --> ')
// )
// );
const uniquePairs = {};
paths.forEach((path) => {
path.forEach((pool) => {
const id = `${pool[0].address}-${pool[1].address}-${pool[2]}`;
uniquePairs[id] = pool;
});
});
const direct = tokenIn && tokenOut
? [
[tokenIn, tokenOut, FeeAmount.LOWEST],
[tokenIn, tokenOut, FeeAmount.LOW],
[tokenIn, tokenOut, FeeAmount.MEDIUM],
[tokenIn, tokenOut, FeeAmount.HIGH],
]
: [];
pairs = [...Object.values(uniquePairs), ...direct];
}
}
log.info(`V3-UNI Static subgraph provider about to get ${pairs.length} pools on-chain`);
const poolAccessor = await this.poolProvider.getPools(pairs);
const pools = poolAccessor.getAllPools();
const poolAddressSet = new Set();
const subgraphPools = _(pools)
.map((pool) => {
const { token0, token1, fee, liquidity } = pool;
const poolAddress = Pool.getAddress(pool.token0, pool.token1, pool.fee, UniV3Factory);
if (poolAddressSet.has(poolAddress)) {
return undefined;
}
poolAddressSet.add(poolAddress);
const liquidityNumber = JSBI.toNumber(liquidity);
return {
id: poolAddress,
feeTier: unparseFeeAmount(fee),
liquidity: liquidity.toString(),
token0: {
id: token0.address,
},
token1: {
id: token1.address,
},
// As a very rough proxy we just use liquidity for TVL.
tvlETH: liquidityNumber,
tvlUSD: liquidityNumber,
};
})
.compact()
.value();
return subgraphPools;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhdGljLXN1YmdyYXBoLXByb3ZpZGVyLXYzLXVuaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9wcm92aWRlcnMvdjMvc3RhdGljLXN1YmdyYXBoLXByb3ZpZGVyLXYzLXVuaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSw2REFBNkQ7QUFDN0QsT0FBTyxFQUFFLE9BQU8sRUFBUyxLQUFLLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUNsRSxPQUFPLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxZQUFZLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUN4RSxPQUFPLElBQUksTUFBTSxNQUFNLENBQUM7QUFDeEIsT0FBTyxDQUFDLE1BQU0sUUFBUSxDQUFDO0FBRXZCLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ3RELE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNyQyxPQUFPLEVBQ0wsT0FBTyxFQUNQLE9BQU8sRUFDUCxRQUFRLEVBQ1IsT0FBTyxFQUNQLFdBQVcsRUFDWCxRQUFRLEVBQ1IsUUFBUSxHQUNULE1BQU0sbUJBQW1CLENBQUM7QUFTM0IsTUFBTSw2QkFBNkIsR0FBbUI7SUFDcEQsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxFQUFFLFFBQVEsQ0FBQztJQUM3QyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUM7Q0FDNUMsQ0FBQztBQUVGLE1BQU0sQ0FBQyxNQUFNLGdCQUFnQixHQUV6QjtJQUNGLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxFQUFFO1FBQ2IsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxFQUFFO1lBQzVCLENBQUMsUUFBUSxFQUFFLFNBQVMsQ0FBQyxNQUFNLENBQUM7WUFDNUIsQ0FBQyxRQUFRLEVBQUUsU0FBUyxDQUFDLE1BQU0sQ0FBQztZQUM1QixDQUFDLFdBQVcsRUFBRSxTQUFTLENBQUMsTUFBTSxDQUFDO1lBQy9CLENBQUMsT0FBTyxFQUFFLFNBQVMsQ0FBQyxNQUFNLENBQUM7WUFDM0IsQ0FBQyxPQUFPLEVBQUUsU0FBUyxDQUFDLE1BQU0sQ0FBQztZQUMzQixDQUFDLE9BQU8sRUFBRSxTQUFTLENBQUMsTUFBTSxDQUFDO1lBQzNCLENBQUMsT0FBTyxFQUFFLFNBQVMsQ0FBQyxJQUFJLENBQUM7U0FDMUI7UUFDRCxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsRUFBRTtZQUNsQixDQUFDLE9BQU8sRUFBRSxTQUFTLENBQUMsTUFBTSxDQUFDO1lBQzNCLENBQUMsUUFBUSxFQUFFLFNBQVMsQ0FBQyxNQUFNLENBQUM7WUFDNUIsQ0FBQyxPQUFPLEVBQUUsU0FBUyxDQUFDLE1BQU0sQ0FBQztZQUMzQixDQUFDLFdBQVcsRUFBRSxTQUFTLENBQUMsR0FBRyxDQUFDO1NBQzdCO1FBQ0QsQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLEVBQUU7WUFDbEIsQ0FBQyxRQUFRLEVBQUUsU0FBUyxDQUFDLE1BQU0sQ0FBQztZQUM1QixDQUFDLFFBQVEsRUFBRSxTQUFTLENBQUMsTUFBTSxDQUFDO1NBQzdCO1FBQ0QsQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFDLEVBQUU7WUFDckIsQ0FBQyxRQUFRLEVBQUUsU0FBUyxDQUFDLE1BQU0sQ0FBQztZQUM1QixDQUFDLFFBQVEsRUFBRSxTQUFTLENBQUMsR0FBRyxDQUFDO1NBQzFCO1FBQ0QsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUU7WUFDakIsQ0FBQyxRQUFRLEVBQUUsU0FBUyxDQUFDLE1BQU0sQ0FBQztZQUM1QixDQUFDLFFBQVEsRUFBRSxTQUFTLENBQUMsTUFBTSxDQUFDO1NBQzdCO1FBQ0QsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDLFFBQVEsRUFB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