@pythnetwork/price-service-sdk
Version:
Pyth price service SDK
192 lines (191 loc) • 6.17 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: Object.getOwnPropertyDescriptor(all, name).get
});
}
_export(exports, {
get isAccumulatorUpdateData () {
return isAccumulatorUpdateData;
},
get parseAccumulatorUpdateData () {
return parseAccumulatorUpdateData;
},
get parsePriceFeedMessage () {
return parsePriceFeedMessage;
},
get parseTwapMessage () {
return parseTwapMessage;
},
get sliceAccumulatorUpdateData () {
return sliceAccumulatorUpdateData;
}
});
const _bn = /*#__PURE__*/ _interop_require_default(require("bn.js"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
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").startsWith(ACCUMULATOR_MAGIC) && updateBytes[4] === MAJOR_VERSION && updateBytes[5] === MINOR_VERSION;
}
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.default(message.subarray(cursor, cursor + 8), "be");
cursor += 8;
const confidence = new _bn.default(message.subarray(cursor, cursor + 8), "be");
cursor += 8;
const exponent = message.readInt32BE(cursor);
cursor += 4;
const publishTime = new _bn.default(message.subarray(cursor, cursor + 8), "be");
cursor += 8;
const prevPublishTime = new _bn.default(message.subarray(cursor, cursor + 8), "be");
cursor += 8;
const emaPrice = new _bn.default(message.subarray(cursor, cursor + 8), "be");
cursor += 8;
const emaConf = new _bn.default(message.subarray(cursor, cursor + 8), "be");
cursor += 8;
return {
feedId,
price,
confidence,
exponent,
publishTime,
prevPublishTime,
emaPrice,
emaConf
};
}
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.default(message.subarray(cursor, cursor + 16), "be");
cursor += 16;
const cumulativeConf = new _bn.default(message.subarray(cursor, cursor + 16), "be");
cursor += 16;
const numDownSlots = new _bn.default(message.subarray(cursor, cursor + 8), "be");
cursor += 8;
const exponent = message.readInt32BE(cursor);
cursor += 4;
const publishTime = new _bn.default(message.subarray(cursor, cursor + 8), "be");
cursor += 8;
const prevPublishTime = new _bn.default(message.subarray(cursor, cursor + 8), "be");
cursor += 8;
const publishSlot = new _bn.default(message.subarray(cursor, cursor + 8), "be");
cursor += 8;
return {
feedId,
cumulativePrice,
cumulativeConf,
numDownSlots,
exponent,
publishTime,
prevPublishTime,
publishSlot
};
}
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)
]);
}
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([
...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
};
}