UNPKG

@pythnetwork/price-service-sdk

Version:
162 lines (161 loc) 5.42 kB
import BN from "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; export function isAccumulatorUpdateData(updateBytes) { return updateBytes.toString("hex").startsWith(ACCUMULATOR_MAGIC) && updateBytes[4] === MAJOR_VERSION && updateBytes[5] === MINOR_VERSION; } export 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(message.subarray(cursor, cursor + 8), "be"); cursor += 8; const confidence = new BN(message.subarray(cursor, cursor + 8), "be"); cursor += 8; const exponent = message.readInt32BE(cursor); cursor += 4; const publishTime = new BN(message.subarray(cursor, cursor + 8), "be"); cursor += 8; const prevPublishTime = new BN(message.subarray(cursor, cursor + 8), "be"); cursor += 8; const emaPrice = new BN(message.subarray(cursor, cursor + 8), "be"); cursor += 8; const emaConf = new BN(message.subarray(cursor, cursor + 8), "be"); cursor += 8; return { feedId, price, confidence, exponent, publishTime, prevPublishTime, emaPrice, emaConf }; } export 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(message.subarray(cursor, cursor + 16), "be"); cursor += 16; const cumulativeConf = new BN(message.subarray(cursor, cursor + 16), "be"); cursor += 16; const numDownSlots = new BN(message.subarray(cursor, cursor + 8), "be"); cursor += 8; const exponent = message.readInt32BE(cursor); cursor += 4; const publishTime = new BN(message.subarray(cursor, cursor + 8), "be"); cursor += 8; const prevPublishTime = new BN(message.subarray(cursor, cursor + 8), "be"); cursor += 8; const publishSlot = new BN(message.subarray(cursor, cursor + 8), "be"); cursor += 8; return { feedId, cumulativePrice, cumulativeConf, numDownSlots, exponent, publishTime, prevPublishTime, publishSlot }; } /** * 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). */ export 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) ]); } export 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 }; }