@node-dlc/messaging
Version:
DLC Messaging Protocol
308 lines • 13.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ContractInfoV1 = exports.ContractInfoV0 = exports.DisjointContractInfo = exports.SingleContractInfo = exports.ContractInfo = void 0;
const bufio_1 = require("@node-dlc/bufio");
const MessageType_1 = require("../MessageType");
const ContractDescriptor_1 = require("./ContractDescriptor");
const DlcMessage_1 = require("./DlcMessage");
const OracleInfo_1 = require("./OracleInfo");
class ContractInfo extends DlcMessage_1.DlcMessage {
static deserialize(buf) {
const reader = new bufio_1.BufferReader(buf);
const typeId = Number(reader.readBigSize());
switch (typeId) {
case MessageType_1.ContractInfoType.Single:
return SingleContractInfo.deserialize(buf);
case MessageType_1.ContractInfoType.Disjoint:
return DisjointContractInfo.deserialize(buf);
default:
throw new Error(`Contract info type must be Single (0) or Disjoint (1), got ${typeId}`);
}
}
/**
* Creates a ContractInfo from JSON data (e.g., from test vectors)
* @param json JSON object representing contract info
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
static fromJSON(json) {
if (!json) {
throw new Error('contractInfo is required');
}
// Check if it's a single contract info or disjoint contract info
if (json.singleContractInfo || json.single_contract_info) {
return SingleContractInfo.fromJSON(json.singleContractInfo || json.single_contract_info);
}
else if (json.disjointContractInfo || json.disjoint_contract_info) {
return DisjointContractInfo.fromJSON(json.disjointContractInfo || json.disjoint_contract_info);
}
else {
throw new Error('contractInfo must have either singleContractInfo or disjointContractInfo');
}
}
// Method to get total collateral (for compatibility)
getTotalCollateral() {
return this.totalCollateral;
}
}
exports.ContractInfo = ContractInfo;
/**
* SingleContractInfo contains information about a contract's outcomes,
* their corresponding payouts, and the oracles to be used.
* This corresponds to the previous ContractInfoV0.
*/
class SingleContractInfo extends ContractInfo {
constructor() {
super(...arguments);
/**
* The type for single_contract_info message - using MessageType for IDlcMessage compatibility
*/
this.type = MessageType_1.MessageType.SingleContractInfo;
/**
* The contract info type for new format
*/
this.contractInfoType = MessageType_1.ContractInfoType.Single;
}
/**
* Creates a SingleContractInfo from JSON data
* @param json JSON object representing single contract info
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
static fromJSON(json) {
const instance = new SingleContractInfo();
instance.totalCollateral = BigInt(json.totalCollateral || json.total_collateral || 0);
// Handle nested contractInfo structure (test vectors have double nesting)
const contractInfoData = json.contractInfo || json.contract_info || json;
// Parse contract descriptor using proper fromJSON method
instance.contractDescriptor = ContractDescriptor_1.ContractDescriptor.fromJSON(contractInfoData.contractDescriptor ||
contractInfoData.contract_descriptor);
// Parse oracle info using proper fromJSON method
instance.oracleInfo = OracleInfo_1.OracleInfo.fromJSON(contractInfoData.oracleInfo || contractInfoData.oracle_info);
return instance;
}
/**
* Deserializes a single_contract_info message
* @param buf
*/
static deserialize(buf) {
const instance = new SingleContractInfo();
const reader = new bufio_1.BufferReader(buf);
reader.readBigSize(); // read type (0)
instance.totalCollateral = reader.readUInt64BE();
// Read contract descriptor as sibling type (starts with its own type prefix)
instance.contractDescriptor = ContractDescriptor_1.ContractDescriptor.deserialize(Buffer.from(reader.buffer.subarray(reader.position)));
// Skip past the contract descriptor we just read
const descLength = instance.contractDescriptor.serialize().length;
reader.position += descLength;
// Read oracle info with rust-dlc format - discriminator + body
const oracleType = Number(reader.readBigSize());
if (oracleType === 0) {
// Single oracle
instance.oracleInfo = OracleInfo_1.SingleOracleInfo.deserializeBody(Buffer.from(reader.buffer.subarray(reader.position)));
}
else if (oracleType === 1) {
// Multi oracle
instance.oracleInfo = OracleInfo_1.MultiOracleInfo.deserializeBody(Buffer.from(reader.buffer.subarray(reader.position)));
}
else {
throw new Error(`Unknown oracle info type: ${oracleType}`);
}
return instance;
}
// Compatibility property
get length() {
return BigInt(this.serialize().length);
}
/**
* Validates correctness of all fields in the message
* @throws Will throw an error if validation fails
*/
validate() {
if (this.totalCollateral <= 0) {
throw new Error('totalCollateral must be greater than 0');
}
this.oracleInfo.validate();
// TODO: Add contract descriptor validation once available
// this.contractDescriptor.validate();
}
/**
* Converts single_contract_info to JSON
*/
toJSON() {
// Return enum variant format for Rust compatibility
return {
singleContractInfo: {
totalCollateral: Number(this.totalCollateral),
contractInfo: {
contractDescriptor: this.contractDescriptor.toJSON(),
oracleInfo: this.oracleInfo.toJSON(),
},
},
};
}
/**
* Serializes the single_contract_info message into a Buffer
*/
serialize() {
const writer = new bufio_1.BufferWriter();
writer.writeBigSize(this.contractInfoType);
writer.writeUInt64BE(this.totalCollateral);
writer.writeBytes(this.contractDescriptor.serialize());
// Use serializeBody() to match rust-dlc behavior - don't add extra TLV wrapper
if (this.oracleInfo instanceof OracleInfo_1.SingleOracleInfo) {
writer.writeBigSize(0); // Single oracle discriminator
writer.writeBytes(this.oracleInfo.serializeBody());
}
else {
writer.writeBigSize(1); // Multi oracle discriminator
writer.writeBytes(this.oracleInfo.serializeBody());
}
return writer.toBuffer();
}
}
exports.SingleContractInfo = SingleContractInfo;
SingleContractInfo.contractInfoType = MessageType_1.ContractInfoType.Single;
SingleContractInfo.type = MessageType_1.MessageType.SingleContractInfo;
/**
* DisjointContractInfo contains information about multiple disjoint contract events.
* This corresponds to the previous ContractInfoV1.
*/
class DisjointContractInfo extends ContractInfo {
constructor() {
super(...arguments);
/**
* The type for disjoint_contract_info message - using MessageType for IDlcMessage compatibility
*/
this.type = MessageType_1.MessageType.DisjointContractInfo;
/**
* The contract info type for new format
*/
this.contractInfoType = MessageType_1.ContractInfoType.Disjoint;
this.contractOraclePairs = [];
}
/**
* Creates a DisjointContractInfo from JSON data
* @param json JSON object representing disjoint contract info
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
static fromJSON(json) {
const instance = new DisjointContractInfo();
instance.totalCollateral = BigInt(json.totalCollateral || json.total_collateral || 0);
// Parse contract infos array
const contractInfosData = json.contractInfos || json.contract_infos || [];
instance.contractOraclePairs = contractInfosData.map(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(contractInfoData) => ({
contractDescriptor: ContractDescriptor_1.ContractDescriptor.fromJSON(contractInfoData.contractDescriptor ||
contractInfoData.contract_descriptor),
oracleInfo: OracleInfo_1.OracleInfo.fromJSON(contractInfoData.oracleInfo || contractInfoData.oracle_info),
}));
return instance;
}
/**
* Deserializes a disjoint_contract_info message
* @param buf
*/
static deserialize(buf) {
const instance = new DisjointContractInfo();
const reader = new bufio_1.BufferReader(buf);
reader.readBigSize(); // read type (1)
instance.totalCollateral = reader.readUInt64BE();
const numDisjointEvents = Number(reader.readBigSize());
for (let i = 0; i < numDisjointEvents; i++) {
// Read contract descriptor as sibling type (starts with its own type prefix)
const contractDescriptor = ContractDescriptor_1.ContractDescriptor.deserialize(Buffer.from(reader.buffer.subarray(reader.position)));
// Skip past the contract descriptor we just read
const descLength = contractDescriptor.serialize().length;
reader.position += descLength;
// Read oracle info with rust-dlc format - discriminator + body (same as SingleContractInfo)
const oracleType = Number(reader.readBigSize());
let oracleInfo;
if (oracleType === 0) {
// Single oracle
oracleInfo = OracleInfo_1.SingleOracleInfo.deserializeBody(Buffer.from(reader.buffer.subarray(reader.position)));
}
else if (oracleType === 1) {
// Multi oracle
oracleInfo = OracleInfo_1.MultiOracleInfo.deserializeBody(Buffer.from(reader.buffer.subarray(reader.position)));
}
else {
throw new Error(`Unknown oracle info type: ${oracleType}`);
}
// Skip past the oracle info we just read
const oracleInfoLength = oracleInfo.serializeBody().length;
reader.position += oracleInfoLength;
instance.contractOraclePairs.push({ contractDescriptor, oracleInfo });
}
return instance;
}
// Compatibility property
get length() {
return BigInt(this.serialize().length);
}
/**
* Validates correctness of all fields in the message
* @throws Will throw an error if validation fails
*/
validate() {
if (this.totalCollateral <= 0) {
throw new Error('totalCollateral must be greater than 0');
}
if (this.contractOraclePairs.length === 0) {
throw new Error('contractOraclePairs cannot be empty');
}
this.contractOraclePairs.forEach((pair, index) => {
try {
pair.oracleInfo.validate();
// TODO: Add contract descriptor validation once available
// pair.contractDescriptor.validate();
}
catch (error) {
throw new Error(`Validation failed for contract oracle pair ${index}: ${error.message}`);
}
});
}
/**
* Converts disjoint_contract_info to JSON
*/
toJSON() {
// Return enum variant format for Rust compatibility
return {
disjointContractInfo: {
totalCollateral: Number(this.totalCollateral),
contractInfos: this.contractOraclePairs.map((pair) => ({
contractDescriptor: pair.contractDescriptor.toJSON(),
oracleInfo: pair.oracleInfo.toJSON(),
})),
},
};
}
/**
* Serializes the disjoint_contract_info message into a Buffer
*/
serialize() {
const writer = new bufio_1.BufferWriter();
writer.writeBigSize(this.contractInfoType);
writer.writeUInt64BE(this.totalCollateral);
writer.writeBigSize(this.contractOraclePairs.length);
for (const pair of this.contractOraclePairs) {
writer.writeBytes(pair.contractDescriptor.serialize());
// Write oracle info with discriminator like SingleContractInfo does
if (pair.oracleInfo instanceof OracleInfo_1.SingleOracleInfo) {
writer.writeBigSize(0); // Single oracle discriminator
writer.writeBytes(pair.oracleInfo.serializeBody());
}
else {
writer.writeBigSize(1); // Multi oracle discriminator
writer.writeBytes(pair.oracleInfo.serializeBody());
}
}
return writer.toBuffer();
}
}
exports.DisjointContractInfo = DisjointContractInfo;
DisjointContractInfo.contractInfoType = MessageType_1.ContractInfoType.Disjoint;
DisjointContractInfo.type = MessageType_1.MessageType.DisjointContractInfo;
// Legacy support - keeping old class names as aliases (both value and type exports)
exports.ContractInfoV0 = SingleContractInfo;
exports.ContractInfoV1 = DisjointContractInfo;
//# sourceMappingURL=ContractInfo.js.map