@pythnetwork/price-service-sdk
Version:
Pyth price service SDK
166 lines (165 loc) • 6.18 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.parseAccumulatorUpdateData = exports.sliceAccumulatorUpdateData = exports.parseTwapMessage = exports.parsePriceFeedMessage = exports.isAccumulatorUpdateData = void 0;
const bn_js_1 = __importDefault(require("bn.js"));
const ACCUMULATOR_MAGIC = "504e4155";
const MAJOR_VERSION = 1;
const MINOR_VERSION = 0;
const KECCAK160_HASH_SIZE = 20;
const PRICE_FEED_MESSAGE_VARIANT = 0;
const TWAP_MESSAGE_VARIANT = 1;
function isAccumulatorUpdateData(updateBytes) {
return (updateBytes.toString("hex").slice(0, 8) === ACCUMULATOR_MAGIC &&
updateBytes[4] === MAJOR_VERSION &&
updateBytes[5] === MINOR_VERSION);
}
exports.isAccumulatorUpdateData = isAccumulatorUpdateData;
function parsePriceFeedMessage(message) {
let cursor = 0;
const variant = message.readUInt8(cursor);
if (variant !== PRICE_FEED_MESSAGE_VARIANT) {
throw new Error("Not a price feed message");
}
cursor += 1;
const feedId = message.subarray(cursor, cursor + 32);
cursor += 32;
const price = new bn_js_1.default(message.subarray(cursor, cursor + 8), "be");
cursor += 8;
const confidence = new bn_js_1.default(message.subarray(cursor, cursor + 8), "be");
cursor += 8;
const exponent = message.readInt32BE(cursor);
cursor += 4;
const publishTime = new bn_js_1.default(message.subarray(cursor, cursor + 8), "be");
cursor += 8;
const prevPublishTime = new bn_js_1.default(message.subarray(cursor, cursor + 8), "be");
cursor += 8;
const emaPrice = new bn_js_1.default(message.subarray(cursor, cursor + 8), "be");
cursor += 8;
const emaConf = new bn_js_1.default(message.subarray(cursor, cursor + 8), "be");
cursor += 8;
return {
feedId,
price,
confidence,
exponent,
publishTime,
prevPublishTime,
emaPrice,
emaConf,
};
}
exports.parsePriceFeedMessage = parsePriceFeedMessage;
function parseTwapMessage(message) {
let cursor = 0;
const variant = message.readUInt8(cursor);
if (variant !== TWAP_MESSAGE_VARIANT) {
throw new Error("Not a twap message");
}
cursor += 1;
const feedId = message.subarray(cursor, cursor + 32);
cursor += 32;
const cumulativePrice = new bn_js_1.default(message.subarray(cursor, cursor + 16), "be");
cursor += 16;
const cumulativeConf = new bn_js_1.default(message.subarray(cursor, cursor + 16), "be");
cursor += 16;
const numDownSlots = new bn_js_1.default(message.subarray(cursor, cursor + 8), "be");
cursor += 8;
const exponent = message.readInt32BE(cursor);
cursor += 4;
const publishTime = new bn_js_1.default(message.subarray(cursor, cursor + 8), "be");
cursor += 8;
const prevPublishTime = new bn_js_1.default(message.subarray(cursor, cursor + 8), "be");
cursor += 8;
const publishSlot = new bn_js_1.default(message.subarray(cursor, cursor + 8), "be");
cursor += 8;
return {
feedId,
cumulativePrice,
cumulativeConf,
numDownSlots,
exponent,
publishTime,
prevPublishTime,
publishSlot,
};
}
exports.parseTwapMessage = parseTwapMessage;
/**
* An AccumulatorUpdateData contains a VAA and a list of updates. This function returns a new serialized AccumulatorUpdateData with only the updates in the range [start, end).
*/
function sliceAccumulatorUpdateData(data, start, end) {
if (!isAccumulatorUpdateData(data)) {
throw new Error("Invalid accumulator message");
}
let cursor = 6;
const trailingPayloadSize = data.readUint8(cursor);
cursor += 1 + trailingPayloadSize;
// const proofType = data.readUint8(cursor);
cursor += 1;
const vaaSize = data.readUint16BE(cursor);
cursor += 2;
cursor += vaaSize;
const endOfVaa = cursor;
const updates = [];
const numUpdates = data.readUInt8(cursor);
cursor += 1;
for (let i = 0; i < numUpdates; i++) {
const updateStart = cursor;
const messageSize = data.readUint16BE(cursor);
cursor += 2;
cursor += messageSize;
const numProofs = data.readUInt8(cursor);
cursor += 1;
cursor += KECCAK160_HASH_SIZE * numProofs;
updates.push(data.subarray(updateStart, cursor));
}
if (cursor !== data.length) {
throw new Error("Didn't reach the end of the message");
}
const sliceUpdates = updates.slice(start, end);
return Buffer.concat([
data.subarray(0, endOfVaa),
Buffer.from([sliceUpdates.length]),
...updates.slice(start, end),
]);
}
exports.sliceAccumulatorUpdateData = sliceAccumulatorUpdateData;
function parseAccumulatorUpdateData(data) {
if (!isAccumulatorUpdateData(data)) {
throw new Error("Invalid accumulator message");
}
let cursor = 6;
const trailingPayloadSize = data.readUint8(cursor);
cursor += 1 + trailingPayloadSize;
// const proofType = data.readUint8(cursor);
cursor += 1;
const vaaSize = data.readUint16BE(cursor);
cursor += 2;
const vaa = data.subarray(cursor, cursor + vaaSize);
cursor += vaaSize;
const numUpdates = data.readUInt8(cursor);
const updates = [];
cursor += 1;
for (let i = 0; i < numUpdates; i++) {
const messageSize = data.readUint16BE(cursor);
cursor += 2;
const message = data.subarray(cursor, cursor + messageSize);
cursor += messageSize;
const numProofs = data.readUInt8(cursor);
cursor += 1;
const proof = [];
for (let j = 0; j < numProofs; j++) {
proof.push(Array.from(data.subarray(cursor, cursor + KECCAK160_HASH_SIZE)));
cursor += KECCAK160_HASH_SIZE;
}
updates.push({ message, proof });
}
if (cursor !== data.length) {
throw new Error("Didn't reach the end of the message");
}
return { vaa, updates };
}
exports.parseAccumulatorUpdateData = parseAccumulatorUpdateData;