UNPKG

@node-dlc/messaging

Version:
393 lines 16.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.OracleInfoV0 = exports.OracleInfo = exports.MultiOracleInfo = exports.SingleOracleInfo = exports.OracleParams = void 0; const bufio_1 = require("@node-dlc/bufio"); const MessageType_1 = require("../MessageType"); const getTlv_1 = require("../serialize/getTlv"); const OracleAnnouncement_1 = require("./OracleAnnouncement"); /** * OracleParams describe allowed differences between oracles in * numerical outcome contracts, as per rust-dlc specification. */ class OracleParams { constructor() { this.type = OracleParams.type; } /** * Creates an OracleParams from JSON data * @param json JSON object representing oracle params */ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any static fromJSON(json) { const instance = new OracleParams(); instance.maxErrorExp = json.maxErrorExp || json.max_error_exp || 0; instance.minFailExp = json.minFailExp || json.min_fail_exp || 0; instance.maximizeCoverage = json.maximizeCoverage || json.maximize_coverage || false; return instance; } /** * Deserializes oracle_params_v0 message */ static deserialize(buf) { const instance = new OracleParams(); const reader = new bufio_1.BufferReader(buf); reader.readBigSize(); // read type instance.length = reader.readBigSize(); instance.maxErrorExp = reader.readUInt16BE(); instance.minFailExp = reader.readUInt16BE(); instance.maximizeCoverage = reader.readUInt8() === 1; return instance; } /** * Deserializes oracle params body without TLV wrapper (for optional deserialization) */ static deserializeBody(buf) { const instance = new OracleParams(); const reader = new bufio_1.BufferReader(buf); // No type/length to read - just the body content instance.maxErrorExp = reader.readUInt16BE(); instance.minFailExp = reader.readUInt16BE(); instance.maximizeCoverage = reader.readUInt8() === 1; return instance; } validate() { if (this.maxErrorExp < 0) { throw new Error('maxErrorExp must be greater than or equal to 0'); } if (this.minFailExp < 0) { throw new Error('minFailExp must be greater than or equal to 0'); } if (this.maxErrorExp >= this.minFailExp) { throw new Error('maxErrorExp must be less than minFailExp'); } } toJSON() { return { maxErrorExp: this.maxErrorExp, minFailExp: this.minFailExp, maximizeCoverage: this.maximizeCoverage, }; } serialize() { const writer = new bufio_1.BufferWriter(); writer.writeBigSize(this.type); const dataWriter = new bufio_1.BufferWriter(); dataWriter.writeUInt16BE(this.maxErrorExp); dataWriter.writeUInt16BE(this.minFailExp); dataWriter.writeUInt8(this.maximizeCoverage ? 1 : 0); writer.writeBigSize(dataWriter.size); writer.writeBytes(dataWriter.toBuffer()); return writer.toBuffer(); } /** * Serializes the oracle params body without TLV wrapper (for optional serialization) */ serializeBody() { const writer = new bufio_1.BufferWriter(); writer.writeUInt16BE(this.maxErrorExp); writer.writeUInt16BE(this.minFailExp); writer.writeUInt8(this.maximizeCoverage ? 1 : 0); return writer.toBuffer(); } } exports.OracleParams = OracleParams; OracleParams.type = MessageType_1.MessageType.OracleParamsV0; /** * SingleOracleInfo contains information about a single oracle. */ class SingleOracleInfo { constructor() { this.type = SingleOracleInfo.type; } /** * Creates a SingleOracleInfo from JSON data * @param json JSON object representing single oracle info */ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any static fromJSON(json) { const instance = new SingleOracleInfo(); const announcementData = json.announcement || json.oracleAnnouncement; if (!announcementData) { throw new Error('announcement or oracleAnnouncement is required for single oracle info'); } // Parse announcement using proper fromJSON method instance.announcement = OracleAnnouncement_1.OracleAnnouncement.fromJSON(announcementData); return instance; } /** * Deserializes single oracle info */ static deserialize(buf) { const instance = new SingleOracleInfo(); const reader = new bufio_1.BufferReader(buf); // Read the type and length that serialize() writes reader.readBigSize(); // read type instance.length = reader.readBigSize(); // read length // Read the announcement data instance.announcement = OracleAnnouncement_1.OracleAnnouncement.deserialize(reader.readBytes(Number(instance.length))); return instance; } /** * Returns the closest maturity date amongst all events */ getClosestMaturityDate() { return this.announcement.oracleEvent.eventMaturityEpoch; } validate() { this.announcement.validate(); } toJSON() { // Return enum variant format for Rust compatibility return { single: { oracleAnnouncement: this.announcement.toJSON(), }, }; } serialize() { const writer = new bufio_1.BufferWriter(); writer.writeBigSize(this.type); const dataWriter = new bufio_1.BufferWriter(); dataWriter.writeBytes(this.announcement.serialize()); writer.writeBigSize(dataWriter.size); writer.writeBytes(dataWriter.toBuffer()); return writer.toBuffer(); } /** * Serializes the body without TLV wrapper (for embedding in ContractInfo) * This matches rust-dlc behavior where OracleInfo.write() doesn't add type_id */ serializeBody() { return this.announcement.serialize(); } /** * Deserializes the body without TLV wrapper (for embedding in ContractInfo) * This matches rust-dlc behavior where OracleInfo is read without type_id */ static deserializeBody(buf) { const instance = new SingleOracleInfo(); // No type/length to read - just the announcement data directly instance.announcement = OracleAnnouncement_1.OracleAnnouncement.deserialize(buf); return instance; } } exports.SingleOracleInfo = SingleOracleInfo; SingleOracleInfo.type = MessageType_1.MessageType.SingleOracleInfo; /** * MultiOracleInfo contains information about multiple oracles used in multi-oracle based contracts. */ class MultiOracleInfo { constructor() { this.type = MultiOracleInfo.type; /** The set of oracle announcements. */ this.announcements = []; } /** * Creates a MultiOracleInfo from JSON data * @param json JSON object representing multi oracle info */ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any static fromJSON(json) { const instance = new MultiOracleInfo(); instance.threshold = json.threshold || 1; // Parse oracle announcements using proper fromJSON method const announcements = json.oracleAnnouncements || json.oracle_announcements || []; // eslint-disable-next-line @typescript-eslint/no-explicit-any instance.announcements = announcements.map((announcementJson) => OracleAnnouncement_1.OracleAnnouncement.fromJSON(announcementJson)); // Parse oracle params if present (null means explicitly absent) const oracleParamsData = json.oracleParams || json.oracle_params; if (oracleParamsData !== null && oracleParamsData !== undefined) { // Create OracleParams from JSON data using the fromJSON method instance.oracleParams = OracleParams.fromJSON(oracleParamsData); } else { // Explicitly null/undefined - will serialize as 00 (not present) instance.oracleParams = undefined; } return instance; } /** * Deserializes multi oracle info */ static deserialize(buf) { const instance = new MultiOracleInfo(); const reader = new bufio_1.BufferReader(buf); // Read the type and length that serialize() writes reader.readBigSize(); // read type instance.length = reader.readBigSize(); // read length // In rust-dlc format, MultiOracleInfo body is: threshold + announcements + optional oracle params instance.threshold = reader.readUInt16BE(); const numAnnouncements = Number(reader.readBigSize()); // Changed from readUInt16BE to readBigSize to match rust-dlc vec_cb for (let i = 0; i < numAnnouncements; i++) { instance.announcements.push(OracleAnnouncement_1.OracleAnnouncement.deserialize((0, getTlv_1.getTlv)(reader))); } // Optional oracle params using Optional sub-type format const oracleParamsData = reader.readOptional(); if (oracleParamsData) { instance.oracleParams = OracleParams.deserializeBody(oracleParamsData); } return instance; } validate() { if (this.threshold <= 0) { throw new Error('threshold must be greater than 0'); } if (this.threshold > this.announcements.length) { throw new Error('threshold cannot be greater than number of announcements'); } if (this.announcements.length === 0) { throw new Error('must have at least one announcement'); } // Validate all announcements this.announcements.forEach((announcement) => announcement.validate()); // Validate oracle params if present if (this.oracleParams) { this.oracleParams.validate(); } } /** * Returns the closest maturity date amongst all events */ getClosestMaturityDate() { return Math.min(...this.announcements.map((a) => a.oracleEvent.eventMaturityEpoch)); } toJSON() { // Return enum variant format for Rust compatibility return { multi: { threshold: this.threshold, oracleAnnouncements: this.announcements.map((a) => a.toJSON()), oracleParams: this.oracleParams?.toJSON(), }, }; } serialize() { const writer = new bufio_1.BufferWriter(); // writer.writeBigSize(this.type); const dataWriter = new bufio_1.BufferWriter(); dataWriter.writeUInt16BE(this.threshold); dataWriter.writeBigSize(this.announcements.length); // Changed from writeUInt16BE to writeBigSize to match rust-dlc vec_cb for (const announcement of this.announcements) { dataWriter.writeBytes(announcement.serialize()); } // Use Optional serialization for oracle params (body content only, not TLV wrapped) const oracleParamsData = this.oracleParams ? this.oracleParams.serializeBody() : null; dataWriter.writeOptional(oracleParamsData); // writer.writeBigSize(dataWriter.size); writer.writeBytes(dataWriter.toBuffer()); return writer.toBuffer(); } /** * Serializes the body without TLV wrapper (for embedding in ContractInfo) * This matches rust-dlc behavior where OracleInfo.write() doesn't add type_id */ serializeBody() { const writer = new bufio_1.BufferWriter(); writer.writeUInt16BE(this.threshold); writer.writeBigSize(this.announcements.length); // Changed from writeUInt16BE to writeBigSize to match rust-dlc vec_cb for (const announcement of this.announcements) { writer.writeBytes(announcement.serialize()); } // Use Optional serialization for oracle params (body content only, not TLV wrapped) const oracleParamsData = this.oracleParams ? this.oracleParams.serializeBody() : null; writer.writeOptional(oracleParamsData); return writer.toBuffer(); } /** * Deserializes the body without TLV wrapper (for embedding in ContractInfo) * This matches rust-dlc behavior where OracleInfo is read without type_id */ static deserializeBody(buf) { const instance = new MultiOracleInfo(); const reader = new bufio_1.BufferReader(buf); // No type/length to read - directly read the multi-oracle body instance.threshold = reader.readUInt16BE(); const numAnnouncements = Number(reader.readBigSize()); // BigSize for announcements count for (let i = 0; i < numAnnouncements; i++) { instance.announcements.push(OracleAnnouncement_1.OracleAnnouncement.deserialize((0, getTlv_1.getTlv)(reader))); } // Optional oracle params using Optional sub-type format const oracleParamsData = reader.readOptional(); if (oracleParamsData) { instance.oracleParams = OracleParams.deserializeBody(oracleParamsData); } return instance; } } exports.MultiOracleInfo = MultiOracleInfo; MultiOracleInfo.type = MessageType_1.MessageType.MultiOracleInfo; /** * OracleInfo contains information about the oracles to be used in * executing a DLC. Updated to support both single and multi-oracle * patterns as per rust-dlc specification. */ class OracleInfo { static deserialize(buf) { const reader = new bufio_1.BufferReader(buf); const type = Number(reader.readBigSize()); switch (type) { case MessageType_1.MessageType.SingleOracleInfo: return SingleOracleInfo.deserialize(buf); case MessageType_1.MessageType.MultiOracleInfo: return MultiOracleInfo.deserialize(buf); default: throw new Error(`Unknown oracle info type: ${type}`); } } /** * Creates an OracleInfo from JSON data (e.g., from test vectors) * @param json JSON object representing oracle info */ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any static fromJSON(json) { if (!json) { throw new Error('oracleInfo is required'); } // Handle direct single oracle (legacy format) if (json.announcement) { return SingleOracleInfo.fromJSON(json); } // Handle wrapped single oracle else if (json.single) { return SingleOracleInfo.fromJSON(json.single); } // Handle multi oracle else if (json.multi) { return MultiOracleInfo.fromJSON(json.multi); } else { throw new Error('oracleInfo must have either announcement, single, or multi'); } } /** * Returns the closest maturity date amongst all events */ getClosestMaturityDate() { if (this instanceof SingleOracleInfo) { return this.announcement.oracleEvent.eventMaturityEpoch; } else if (this instanceof MultiOracleInfo) { return this.getClosestMaturityDate(); } throw new Error('Unknown oracle info type'); } } exports.OracleInfo = OracleInfo; // For backward compatibility, keep the V0 class as alias to SingleOracleInfo class OracleInfoV0 extends SingleOracleInfo { /** * Creates an OracleInfoV0 from JSON data (alias for SingleOracleInfo.fromJSON) * @param json JSON object representing oracle info */ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any static fromJSON(json) { return SingleOracleInfo.fromJSON(json); } } exports.OracleInfoV0 = OracleInfoV0; //# sourceMappingURL=OracleInfo.js.map