@orca-so/whirlpool-sdk
Version:
Whirlpool SDK for the Orca protocol.
89 lines (88 loc) • 4.55 kB
JavaScript
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;
;