@bithomp/xrpl-api
Version:
A Bithomp JavaScript/TypeScript library for interacting with the XRP Ledger
151 lines (150 loc) • 6.42 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseOracleChanges = parseOracleChanges;
exports.parsePriceDataSeries = parsePriceDataSeries;
const bignumber_js_1 = __importDefault(require("bignumber.js"));
const utils_1 = require("../utils");
const common_1 = require("../../common");
function parseOracleStatus(node) {
if (node.diffType === "CreatedNode") {
return "created";
}
if (node.diffType === "ModifiedNode") {
return "modified";
}
if (node.diffType === "DeletedNode") {
return "deleted";
}
return undefined;
}
function hexPriceToBigNumber(hex) {
if (hex === undefined) {
return undefined;
}
if (typeof hex !== "string") {
throw new Error("Price must be a string.");
}
return new bignumber_js_1.default(`0x${hex}`);
}
function getOriginalAssetPrice(assetPrice, scale) {
if (assetPrice === undefined) {
return undefined;
}
if (assetPrice.isZero()) {
return assetPrice;
}
if (scale === 0 || scale === undefined) {
return assetPrice;
}
return assetPrice.dividedBy(new bignumber_js_1.default(10).pow(scale));
}
function parsePriceDataSeries(series) {
const assetPrice = hexPriceToBigNumber(series.PriceData.AssetPrice);
const scale = series.PriceData.Scale;
const originalAssetPrice = getOriginalAssetPrice(assetPrice, scale);
return (0, common_1.removeUndefined)({
baseAsset: series.PriceData.BaseAsset,
quoteAsset: series.PriceData.QuoteAsset,
assetPrice: assetPrice?.toString(),
scale: series.PriceData.Scale,
originalAssetPrice: originalAssetPrice?.toString(),
});
}
function summarizePriceDataSeriesChanges(node) {
const final = node.diffType === "CreatedNode" ? node.newFields : node.finalFields;
const prev = node.previousFields;
const changes = final.PriceDataSeries.reduce((acc, series) => {
const prevSeries = prev.PriceDataSeries.find((s) => s.PriceData.BaseAsset === series.PriceData.BaseAsset && s.PriceData.QuoteAsset === series.PriceData.QuoteAsset);
const priceFinal = hexPriceToBigNumber(series.PriceData.AssetPrice) || new bignumber_js_1.default(0);
const scaleFinal = series.PriceData.Scale || 0;
const originalPriceFinal = getOriginalAssetPrice(priceFinal, scaleFinal);
if (!prevSeries) {
return acc.concat({
status: "added",
baseAsset: series.PriceData.BaseAsset,
quoteAsset: series.PriceData.QuoteAsset,
assetPrice: priceFinal?.toString(),
scale: scaleFinal,
originalAssetPrice: originalPriceFinal?.toString(),
});
}
const pricePrev = hexPriceToBigNumber(prevSeries.PriceData.AssetPrice) || new bignumber_js_1.default(0);
const scalePrev = prevSeries.PriceData.Scale || 0;
const assetPriceChange = (priceFinal || new bignumber_js_1.default(0)).minus(pricePrev);
const scaleChange = (scaleFinal ?? 0) - scalePrev;
if (!assetPriceChange.isZero() || scaleChange !== 0) {
const originalPricePrev = getOriginalAssetPrice(pricePrev, scalePrev) || new bignumber_js_1.default(0);
const originalPriceChange = (originalPriceFinal || new bignumber_js_1.default(0)).minus(originalPricePrev);
return acc.concat((0, common_1.removeUndefined)({
status: "modified",
baseAsset: series.PriceData.BaseAsset,
quoteAsset: series.PriceData.QuoteAsset,
assetPrice: priceFinal?.toString(),
scale: scaleFinal,
originalAssetPrice: originalPriceFinal?.toString(),
assetPriceChange: assetPriceChange.isZero() ? undefined : assetPriceChange?.toString(),
scaleChange: scaleChange || undefined,
originalPriceChange: originalPriceChange.isZero() ? undefined : originalPriceChange.toString(),
}));
}
return acc;
}, []);
const removed = prev.PriceDataSeries.filter((s) => {
return !final.PriceDataSeries.find((series) => series.PriceData.BaseAsset === s.PriceData.BaseAsset && series.PriceData.QuoteAsset === s.PriceData.QuoteAsset);
});
if (removed.length > 0) {
return changes.concat(removed.map((s) => {
const price = hexPriceToBigNumber(s.PriceData.AssetPrice);
return {
status: "removed",
baseAsset: s.PriceData.BaseAsset,
quoteAsset: s.PriceData.QuoteAsset,
assetPrice: price?.toString(),
scale: s.PriceData.Scale,
originalAssetPrice: getOriginalAssetPrice(price, s.PriceData.Scale),
};
}));
}
if (changes.length === 0) {
return undefined;
}
return changes;
}
function summarizeOracle(node) {
const final = node.diffType === "CreatedNode" ? node.newFields : node.finalFields;
const prev = node.previousFields;
const summary = {
status: parseOracleStatus(node),
oracleID: node.ledgerIndex,
oracleDocumentID: final.OracleDocumentID,
provider: final.Provider,
uri: final.URI,
assetClass: final.AssetClass,
lastUpdateTime: final.LastUpdateTime,
priceDataSeries: final.PriceDataSeries.map(parsePriceDataSeries),
};
if (prev.URI) {
summary.uriChanges = final.URI;
}
if (prev.LastUpdateTime) {
summary.lastUpdateTimeChanges = final.LastUpdateTime - (prev.LastUpdateTime || 0);
}
if (prev.PriceDataSeries) {
summary.priceDataSeriesChanges = summarizePriceDataSeriesChanges(node);
}
return (0, common_1.removeUndefined)(summary);
}
function parseOracleChanges(metadata) {
const affectedNodes = metadata.AffectedNodes.filter((affectedNode) => {
const node = affectedNode.CreatedNode || affectedNode.ModifiedNode || affectedNode.DeletedNode;
return node.LedgerEntryType === "Oracle";
});
if (affectedNodes.length !== 1) {
return undefined;
}
const normalizedNode = (0, utils_1.normalizeNode)(affectedNodes[0]);
return summarizeOracle(normalizedNode);
}