@sky-mavis/smart-order-router
Version:
Ronin Swap Smart Order Router
157 lines • 15.8 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.V3SubgraphProvider = exports.printV2SubgraphPool = exports.printV3SubgraphPool = void 0;
const katana_core_1 = require("@sky-mavis/katana-core");
const async_retry_1 = __importDefault(require("async-retry"));
const await_timeout_1 = __importDefault(require("await-timeout"));
const graphql_request_1 = require("graphql-request");
const lodash_1 = __importDefault(require("lodash"));
const util_1 = require("../../util");
const SUBGRAPH_DOMAIN_MAINNET_BASE = 'https://thegraph-v2.roninchain.com';
const printV3SubgraphPool = (s) => `${s.token0.id}/${s.token1.id}/${s.feeTier}`;
exports.printV3SubgraphPool = printV3SubgraphPool;
const printV2SubgraphPool = (s) => `${s.token0.id}/${s.token1.id}`;
exports.printV2SubgraphPool = printV2SubgraphPool;
const SUBGRAPH_URL_BY_CHAIN = {
[katana_core_1.ChainId.mainnet]: `${SUBGRAPH_DOMAIN_MAINNET_BASE}/subgraphs/name/axieinfinity/katana-v3`,
[katana_core_1.ChainId.testnet]: 'https://saigon-thegraph.roninchain.com/subgraphs/name/axieinfinity/katana-v3',
};
const PAGE_SIZE = 1000; // 1k is max possible query size from subgraph.
class V3SubgraphProvider {
constructor(chainId, retries = 2, timeout = 30000, rollback = true, trackedEthThreshold = 0.01, untrackedUsdThreshold = Number.MAX_VALUE, subgraphUrlOverride) {
var _a;
this.chainId = chainId;
this.retries = retries;
this.timeout = timeout;
this.rollback = rollback;
this.trackedEthThreshold = trackedEthThreshold;
this.untrackedUsdThreshold = untrackedUsdThreshold;
this.subgraphUrlOverride = subgraphUrlOverride;
const subgraphUrl = (_a = this.subgraphUrlOverride) !== null && _a !== void 0 ? _a : SUBGRAPH_URL_BY_CHAIN[this.chainId];
if (!subgraphUrl) {
throw new Error(`No subgraph url for chain id: ${this.chainId}`);
}
this.client = new graphql_request_1.GraphQLClient(subgraphUrl);
}
async getPools(_tokenIn, _tokenOut, providerConfig) {
const beforeAll = Date.now();
let blockNumber = (providerConfig === null || providerConfig === void 0 ? void 0 : providerConfig.blockNumber) ? await providerConfig.blockNumber : undefined;
const query = (0, graphql_request_1.gql) `
query getPools($pageSize: Int!, $id: String) {
pools(
first: $pageSize
${blockNumber ? `block: { number: ${blockNumber} }` : ``}
where: { id_gt: $id }
) {
id
token0 {
symbol
id
}
token1 {
symbol
id
}
feeTier
liquidity
totalValueLockedUSD
totalValueLockedETH
totalValueLockedUSDUntracked
}
}
`;
let pools = [];
util_1.log.info(`Getting V3 pools from the subgraph with page size ${PAGE_SIZE}${(providerConfig === null || providerConfig === void 0 ? void 0 : providerConfig.blockNumber) ? ` as of block ${providerConfig === null || providerConfig === void 0 ? void 0 : providerConfig.blockNumber}` : ''}.`);
let retries = 0;
await (0, async_retry_1.default)(async () => {
const timeout = new await_timeout_1.default();
const getPools = async () => {
let lastId = '';
let pools = [];
let poolsPage = [];
// metrics variables
let totalPages = 0;
do {
totalPages += 1;
const poolsResult = await this.client.request(query, {
pageSize: PAGE_SIZE,
id: lastId,
});
poolsPage = poolsResult.pools;
pools = pools.concat(poolsPage);
lastId = pools[pools.length - 1].id;
util_1.metric.putMetric(`V3SubgraphProvider.chain_${this.chainId}.getPools.paginate.pageSize`, poolsPage.length);
} while (poolsPage.length > 0);
util_1.metric.putMetric(`V3SubgraphProvider.chain_${this.chainId}.getPools.paginate`, totalPages);
util_1.metric.putMetric(`V3SubgraphProvider.chain_${this.chainId}.getPools.pools.length`, pools.length);
return pools;
};
/* eslint-disable no-useless-catch */
try {
const getPoolsPromise = getPools();
const timerPromise = timeout.set(this.timeout).then(() => {
throw new Error(`Timed out getting pools from subgraph: ${this.timeout}`);
});
pools = await Promise.race([getPoolsPromise, timerPromise]);
return;
}
catch (err) {
throw err;
}
finally {
timeout.clear();
}
/* eslint-enable no-useless-catch */
}, {
retries: this.retries,
onRetry: (err, retry) => {
retries += 1;
if (this.rollback && blockNumber && lodash_1.default.includes(err.message, 'indexed up to')) {
util_1.metric.putMetric(`V3SubgraphProvider.chain_${this.chainId}.getPools.indexError`, 1);
blockNumber = blockNumber - 10;
util_1.log.info(`Detected subgraph indexing error. Rolled back block number to: ${blockNumber}`);
}
util_1.metric.putMetric(`V3SubgraphProvider.chain_${this.chainId}.getPools.timeout`, 1);
pools = [];
util_1.log.info({ err }, `Failed to get pools from subgraph. Retry attempt: ${retry}`);
},
});
util_1.metric.putMetric(`V3SubgraphProvider.chain_${this.chainId}.getPools.retries`, retries);
const untrackedPools = pools.filter(pool => parseInt(pool.liquidity) > 0 ||
parseFloat(pool.totalValueLockedETH) > this.trackedEthThreshold ||
parseFloat(pool.totalValueLockedUSDUntracked) > this.untrackedUsdThreshold);
util_1.metric.putMetric(`V3SubgraphProvider.chain_${this.chainId}.getPools.untracked.length`, untrackedPools.length);
util_1.metric.putMetric(`V3SubgraphProvider.chain_${this.chainId}.getPools.untracked.percent`, (untrackedPools.length / pools.length) * 100);
const beforeFilter = Date.now();
const poolsSanitized = pools
.filter(pool => parseInt(pool.liquidity) > 0 || parseFloat(pool.totalValueLockedETH) > this.trackedEthThreshold)
.map(pool => {
const { totalValueLockedETH, totalValueLockedUSD } = pool;
return {
id: pool.id.toLowerCase(),
feeTier: pool.feeTier,
token0: {
id: pool.token0.id.toLowerCase(),
},
token1: {
id: pool.token1.id.toLowerCase(),
},
liquidity: pool.liquidity,
tvlETH: parseFloat(totalValueLockedETH),
tvlUSD: parseFloat(totalValueLockedUSD),
};
});
util_1.metric.putMetric(`V3SubgraphProvider.chain_${this.chainId}.getPools.filter.latency`, Date.now() - beforeFilter);
util_1.metric.putMetric(`V3SubgraphProvider.chain_${this.chainId}.getPools.filter.length`, poolsSanitized.length);
util_1.metric.putMetric(`V3SubgraphProvider.chain_${this.chainId}.getPools.filter.percent`, (poolsSanitized.length / pools.length) * 100);
util_1.metric.putMetric(`V3SubgraphProvider.chain_${this.chainId}.getPools`, 1);
util_1.metric.putMetric(`V3SubgraphProvider.chain_${this.chainId}.getPools.latency`, Date.now() - beforeAll);
util_1.log.info(`Got ${pools.length} V3 pools from the subgraph. ${poolsSanitized.length} after filtering`);
return poolsSanitized;
}
}
exports.V3SubgraphProvider = V3SubgraphProvider;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3ViZ3JhcGgtcHJvdmlkZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvcHJvdmlkZXJzL3YzL3N1YmdyYXBoLXByb3ZpZGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLHdEQUFpRDtBQUVqRCw4REFBZ0M7QUFDaEMsa0VBQW9DO0FBQ3BDLHFEQUFxRDtBQUNyRCxvREFBdUI7QUFFdkIscUNBQXlDO0FBSXpDLE1BQU0sNEJBQTRCLEdBQUcsb0NBQW9DLENBQUM7QUFnQ25FLE1BQU0sbUJBQW1CLEdBQUcsQ0FBQyxDQUFpQixFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxNQUFNLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQyxNQUFNLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztBQUExRixRQUFBLG1CQUFtQix1QkFBdUU7QUFFaEcsTUFBTSxtQkFBbUIsR0FBRyxDQUFDLENBQWlCLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFDLE1BQU0sQ0FBQyxFQUFFLEVBQUUsQ0FBQztBQUE3RSxRQUFBLG1CQUFtQix1QkFBMEQ7QUFFMUYsTUFBTSxxQkFBcUIsR0FBc0M7SUFDL0QsQ0FBQyxxQkFBTyxDQUFDLE9BQU8sQ0FBQyxFQUFFLEdBQUcsNEJBQTRCLHdDQUF3QztJQUMxRixDQUFDLHFCQUFPLENBQUMsT0FBTyxDQUFDLEVBQUUsOEVBQThFO0NBQ2xHLENBQUM7QUFFRixNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsQ0FBQywrQ0FBK0M7QUFZdkUsTUFBYSxrQkFBa0I7SUFHN0IsWUFDVSxPQUFnQixFQUNoQixVQUFVLENBQUMsRUFDWCxVQUFVLEtBQUssRUFDZixXQUFXLElBQUksRUFDZixzQkFBc0IsSUFBSSxFQUMxQix3QkFBd0IsTUFBTSxDQUFDLFNBQVMsRUFDeEMsbUJBQTRCOztRQU41QixZQUFP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