UNPKG

@orca-so/whirlpool-sdk

Version:

Whirlpool SDK for the Orca protocol.

89 lines (88 loc) 4.55 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.getTokenUSDPrices = void 0; const spl_token_1 = require("@solana/spl-token"); const decimal_js_1 = __importDefault(require("decimal.js")); const __1 = require(".."); const address_1 = require("./address"); /** * Use on-chain dex data to derive usd prices for tokens. * * @param pools pools to be used for price discovery * @param baseTokenMint a token mint with known stable usd price (e.g. USDC) * @param baseTokenUSDPrice baseTokenMint's usd price. defaults to 1, assuming `baseTokenMint` is a USD stable coin * @param otherBaseTokenMints optional list of token mints to prioritize as base */ function getTokenUSDPrices(dal, pools, baseTokenMint, baseTokenUSDPrice = new decimal_js_1.default(1), otherBaseTokenMints = [spl_token_1.NATIVE_MINT]) { var _a, _b; return __awaiter(this, void 0, void 0, function* () { // Create a bi-directional graph, where tokens are vertices and pairings are edges const tokenGraph = {}; pools.forEach((pool) => { const tokenMintA = pool.tokenMintA.toBase58(); const tokenMintB = pool.tokenMintB.toBase58(); tokenGraph[tokenMintA] = Object.assign({ [tokenMintB]: pool }, tokenGraph[tokenMintA]); tokenGraph[tokenMintB] = Object.assign({ [tokenMintA]: pool }, tokenGraph[tokenMintB]); }); // Start with tokens paired with `baseTokenMint`, then prioritize tokens paired with SOL, then others. // For example, `baseTokenMint` could be USDC mint address. const base = (0, address_1.toPubKey)(baseTokenMint).toBase58(); const otherBases = (0, address_1.toPubKeys)(otherBaseTokenMints).map((pubKey) => pubKey.toBase58()); const result = { [base]: baseTokenUSDPrice }; const queue = [base, ...otherBases]; const visited = new Set(); // Traverse the graph breath-first while (queue.length > 0) { const vertex = queue.shift(); if (!vertex || visited.has(vertex)) { continue; } else { visited.add(vertex); } const vertexPriceUSD = result[vertex]; if (!vertexPriceUSD) { continue; } for (const [neighbor, pool] of Object.entries(tokenGraph[vertex] || {})) { if (visited.has(neighbor)) { continue; } if (result[neighbor]) { queue.push(neighbor); continue; } const tokenDecimalsA = (_a = (yield dal.getMintInfo(pool.tokenMintA, false))) === null || _a === void 0 ? void 0 : _a.decimals; if (tokenDecimalsA === undefined) { throw new Error(`Token mint not found: ${pool.tokenMintA.toBase58()}`); } const tokenDecimalsB = (_b = (yield dal.getMintInfo(pool.tokenMintB, false))) === null || _b === void 0 ? void 0 : _b.decimals; if (tokenDecimalsB === undefined) { throw new Error(`Token mint not found: ${pool.tokenMintB.toBase58()}`); } const yxPrice = (0, __1.sqrtPriceX64ToPrice)(pool.sqrtPrice, tokenDecimalsA, tokenDecimalsB); if (pool.tokenMintA.toBase58() === neighbor) { result[neighbor] = yxPrice.mul(vertexPriceUSD); } else { result[neighbor] = vertexPriceUSD.div(yxPrice); } queue.push(neighbor); } } return result; }); } exports.getTokenUSDPrices = getTokenUSDPrices;