@node-dlc/messaging
Version:
DLC Messaging Protocol
142 lines (116 loc) • 4.21 kB
text/typescript
import { BufferReader, BufferWriter } from '@node-dlc/bufio';
import { MessageType } from '../MessageType';
import { getTlv } from '../serialize/getTlv';
import { IDlcMessage } from './DlcMessage';
import {
DigitDecompositionEventDescriptorV0,
EventDescriptor,
IDigitDecompositionEventDescriptorV0JSON,
IEnumEventDescriptorV0JSON,
} from './EventDescriptor';
/**
* For users to be able to create DLCs based on a given event, they also
* need to obtain information about the oracle and the time at which it
* plans on releasing a signature over the event outcome. OracleEvent
* mesages contain such information, which includes:
* - the nonce(s) that will be used to sign the event outcome(s)
* - the earliest time (UTC) at which it plans on releasing a signature
* over the event outcome, in epoch seconds
* - the event descriptor
* - the event ID which can be a name or categorization associated with
* the event by the oracle
*/
export class OracleEventV0 implements IDlcMessage {
public static type = MessageType.OracleEventV0;
/**
* Deserializes an oracle_event message
* @param buf
*/
public static deserialize(buf: Buffer): OracleEventV0 {
const instance = new OracleEventV0();
const reader = new BufferReader(buf);
reader.readBigSize(); // read type
instance.length = reader.readBigSize();
const nonceCount = reader.readUInt16BE();
for (let i = 0; i < nonceCount; i++) {
instance.oracleNonces.push(reader.readBytes(32));
}
instance.eventMaturityEpoch = reader.readUInt32BE();
instance.eventDescriptor = EventDescriptor.deserialize(getTlv(reader));
const eventIdLength = reader.readBigSize();
const eventIdBuf = reader.readBytes(Number(eventIdLength));
instance.eventId = eventIdBuf.toString();
return instance;
}
/**
* The type for oracle_event message. oracle_event = 55330
*/
public type = OracleEventV0.type;
public length: bigint;
public oracleNonces: Buffer[] = [];
public eventMaturityEpoch: number;
public eventDescriptor: EventDescriptor;
public eventId: string;
/**
* Validates correctness of all fields in the message
* https://github.com/discreetlogcontracts/dlcspecs/blob/master/Oracle.md
* @throws Will throw an error if validation fails
*/
public validate(): void {
if (this.eventMaturityEpoch < 0) {
throw new Error('eventMaturityEpoch must be greater than or equal to 0');
}
if (
this.eventDescriptor.type === DigitDecompositionEventDescriptorV0.type
) {
const eventDescriptor = this
.eventDescriptor as DigitDecompositionEventDescriptorV0;
eventDescriptor.validate();
if (eventDescriptor.nbDigits !== this.oracleNonces.length) {
throw Error(
'OracleEvent oracleNonces length must match DigitDecompositionEventDescriptor nbDigits',
);
}
}
}
/**
* Converts oracle_event to JSON
*/
public toJSON(): IOracleEventV0JSON {
return {
type: this.type,
oracleNonces: this.oracleNonces.map((oracle) => oracle.toString('hex')),
eventMaturityEpoch: this.eventMaturityEpoch,
eventDescriptor: this.eventDescriptor.toJSON(),
eventId: this.eventId,
};
}
/**
* Serializes the oracle_event message into a Buffer
*/
public serialize(): Buffer {
const writer = new BufferWriter();
writer.writeBigSize(this.type);
const dataWriter = new BufferWriter();
dataWriter.writeUInt16BE(this.oracleNonces.length);
for (const nonce of this.oracleNonces) {
dataWriter.writeBytes(nonce);
}
dataWriter.writeUInt32BE(this.eventMaturityEpoch);
dataWriter.writeBytes(this.eventDescriptor.serialize());
dataWriter.writeBigSize(this.eventId.length);
dataWriter.writeBytes(Buffer.from(this.eventId));
writer.writeBigSize(dataWriter.size);
writer.writeBytes(dataWriter.toBuffer());
return writer.toBuffer();
}
}
export interface IOracleEventV0JSON {
type: number;
oracleNonces: string[];
eventMaturityEpoch: number;
eventDescriptor:
| IEnumEventDescriptorV0JSON
| IDigitDecompositionEventDescriptorV0JSON;
eventId: string;
}