diff --git a/packages/messaging/__tests__/messages/DlcAcceptV0.spec.ts b/packages/messaging/__tests__/messages/DlcAcceptV0.spec.ts index 93e4894..2418c2d 100644 --- a/packages/messaging/__tests__/messages/DlcAcceptV0.spec.ts +++ b/packages/messaging/__tests__/messages/DlcAcceptV0.spec.ts @@ -2,7 +2,11 @@ import { BitcoinNetworks } from 'bitcoin-networks'; import { expect } from 'chai'; import { CetAdaptorSignaturesV0 } from '../../lib/messages/CetAdaptorSignaturesV0'; -import { DlcAccept, DlcAcceptV0 } from '../../lib/messages/DlcAccept'; +import { + DlcAccept, + DlcAcceptContainer, + DlcAcceptV0, +} from '../../lib/messages/DlcAccept'; import { FundingInputV0 } from '../../lib/messages/FundingInput'; import { NegotiationFields } from '../../lib/messages/NegotiationFields'; import { MessageType } from '../../lib/MessageType'; @@ -114,7 +118,7 @@ describe('DlcAccept', () => { describe('deserialize', () => { it('should throw if incorrect type', () => { - instance.type = 0x123; + instance.type = 0x123 as MessageType; expect(function () { DlcAccept.deserialize(instance.serialize()); }).to.throw(Error); @@ -287,4 +291,22 @@ describe('DlcAccept', () => { }); }); }); + + describe('DlcAcceptContainer', () => { + it('should serialize and deserialize', () => { + const dlcAccept = DlcAcceptV0.deserialize(dlcAcceptHex); + // swap payout and change spk to differentiate between dlcaccepts + const dlcAccept2 = DlcAcceptV0.deserialize(dlcAcceptHex); + dlcAccept2.payoutSPK = dlcAccept.changeSPK; + dlcAccept2.changeSPK = dlcAccept.payoutSPK; + + const container = new DlcAcceptContainer(); + container.addAccept(dlcAccept); + container.addAccept(dlcAccept2); + + const instance = DlcAcceptContainer.deserialize(container.serialize()); + + expect(container.serialize()).to.deep.equal(instance.serialize()); + }); + }); }); diff --git a/packages/messaging/__tests__/messages/DlcOfferV0.spec.ts b/packages/messaging/__tests__/messages/DlcOfferV0.spec.ts index b9b0369..e357621 100644 --- a/packages/messaging/__tests__/messages/DlcOfferV0.spec.ts +++ b/packages/messaging/__tests__/messages/DlcOfferV0.spec.ts @@ -5,6 +5,7 @@ import { OrderPositionInfoV0 } from '../../lib'; import { ContractInfo } from '../../lib/messages/ContractInfo'; import { DlcOffer, + DlcOfferContainer, DlcOfferV0, LOCKTIME_THRESHOLD, } from '../../lib/messages/DlcOffer'; @@ -139,7 +140,7 @@ describe('DlcOffer', () => { describe('deserialize', () => { it('should throw if incorrect type', () => { - instance.type = 0x123; + instance.type = 0x123 as MessageType; expect(function () { DlcOffer.deserialize(instance.serialize()); }).to.throw(Error); @@ -411,4 +412,22 @@ describe('DlcOffer', () => { }); }); }); + + describe('DlcOfferContainer', () => { + it('should serialize and deserialize', () => { + const dlcOffer = DlcOfferV0.deserialize(dlcOfferHex); + // swap payout and change spk to differentiate between dlcoffers + const dlcOffer2 = DlcOfferV0.deserialize(dlcOfferHex); + dlcOffer2.payoutSPK = dlcOffer.changeSPK; + dlcOffer2.changeSPK = dlcOffer.payoutSPK; + + const container = new DlcOfferContainer(); + container.addOffer(dlcOffer); + container.addOffer(dlcOffer2); + + const instance = DlcOfferContainer.deserialize(container.serialize()); + + expect(container.serialize()).to.deep.equal(instance.serialize()); + }); + }); }); diff --git a/packages/messaging/__tests__/messages/DlcSignV0.spec.ts b/packages/messaging/__tests__/messages/DlcSignV0.spec.ts index 84e99e5..db158d7 100644 --- a/packages/messaging/__tests__/messages/DlcSignV0.spec.ts +++ b/packages/messaging/__tests__/messages/DlcSignV0.spec.ts @@ -1,7 +1,12 @@ import { expect } from 'chai'; +import { MessageType } from '../../lib'; import { CetAdaptorSignaturesV0 } from '../../lib/messages/CetAdaptorSignaturesV0'; -import { DlcSign, DlcSignV0 } from '../../lib/messages/DlcSign'; +import { + DlcSign, + DlcSignContainer, + DlcSignV0, +} from '../../lib/messages/DlcSign'; import { FundingSignaturesV0 } from '../../lib/messages/FundingSignaturesV0'; describe('DlcSign', () => { @@ -14,6 +19,11 @@ describe('DlcSign', () => { 'hex', ); + const contractId2 = Buffer.from( + '4946fe172de3778fa660b9858d0624044f4494667757f50388abe6fe523376e8', + 'hex', + ); + const cetAdaptorSignaturesV0 = Buffer.from( 'fda716' + // type cet_adaptor_signatures_v0 'fd01e7' + // length @@ -44,7 +54,7 @@ describe('DlcSign', () => { 'hex', ); - const dlcAcceptHex = Buffer.concat([ + const dlcSignHex = Buffer.concat([ type, contractId, cetAdaptorSignaturesV0, @@ -67,7 +77,7 @@ describe('DlcSign', () => { describe('deserialize', () => { it('should throw if incorrect type', () => { - instance.type = 0x123; + instance.type = 0x123 as MessageType; expect(function () { DlcSign.deserialize(instance.serialize()); }).to.throw(Error); @@ -84,14 +94,14 @@ describe('DlcSign', () => { describe('serialize', () => { it('serializes', () => { expect(instance.serialize().toString('hex')).to.equal( - dlcAcceptHex.toString('hex'), + dlcSignHex.toString('hex'), ); }); }); describe('deserialize', () => { it('deserializes', () => { - const instance = DlcSignV0.deserialize(dlcAcceptHex); + const instance = DlcSignV0.deserialize(dlcSignHex); expect(instance.contractId).to.deep.equal(contractId); expect(instance.cetSignatures.serialize().toString('hex')).to.equal( cetAdaptorSignaturesV0.toString('hex'), @@ -111,4 +121,21 @@ describe('DlcSign', () => { }); }); }); + + describe('DlcSignContainer', () => { + it('should serialize and deserialize', () => { + const dlcSign = DlcSignV0.deserialize(dlcSignHex); + // swap payout and change spk to differentiate between dlcaccepts + const dlcSign2 = DlcSignV0.deserialize(dlcSignHex); + dlcSign2.contractId = contractId2; + + const container = new DlcSignContainer(); + container.addSign(dlcSign); + container.addSign(dlcSign2); + + const instance = DlcSignContainer.deserialize(container.serialize()); + + expect(container.serialize()).to.deep.equal(instance.serialize()); + }); + }); }); diff --git a/packages/messaging/__tests__/messages/OrderAccept.spec.ts b/packages/messaging/__tests__/messages/OrderAccept.spec.ts index b147181..e82808b 100644 --- a/packages/messaging/__tests__/messages/OrderAccept.spec.ts +++ b/packages/messaging/__tests__/messages/OrderAccept.spec.ts @@ -1,6 +1,9 @@ import { expect } from 'chai'; -import { OrderAcceptV0 } from '../../lib/messages/OrderAccept'; +import { + OrderAcceptContainer, + OrderAcceptV0, +} from '../../lib/messages/OrderAccept'; import { OrderNegotiationFieldsV0 } from '../../lib/messages/OrderNegotiationFields'; describe('OrderAccept', () => { @@ -9,6 +12,11 @@ describe('OrderAccept', () => { 'hex', ); + const tempOrderId2 = Buffer.from( + '0ef55fca0e3d0a95609ddce833d2f8ba6c2ee37bbe8583bc2068256c51a32914', + 'hex', + ); + describe('serialize', () => { it('serializes', () => { const instance = new OrderAcceptV0(); @@ -43,4 +51,27 @@ describe('OrderAccept', () => { ); }); }); + + describe('OrderAcceptContainer', () => { + it('should serialize and deserialize', () => { + const orderAccept = new OrderAcceptV0(); + + orderAccept.tempOrderId = tempOrderId; + orderAccept.negotiationFields = OrderNegotiationFieldsV0.deserialize( + Buffer.from('fdff3600', 'hex'), + ); + + // swap payout and change spk to differentiate between dlcoffers + const orderAccept2 = OrderAcceptV0.deserialize(orderAccept.serialize()); + orderAccept2.tempOrderId = tempOrderId2; + + const container = new OrderAcceptContainer(); + container.addAccept(orderAccept); + container.addAccept(orderAccept2); + + const instance = OrderAcceptContainer.deserialize(container.serialize()); + + expect(container.serialize()).to.deep.equal(instance.serialize()); + }); + }); }); diff --git a/packages/messaging/__tests__/messages/OrderOffer.spec.ts b/packages/messaging/__tests__/messages/OrderOffer.spec.ts index bb7930a..627c10b 100644 --- a/packages/messaging/__tests__/messages/OrderOffer.spec.ts +++ b/packages/messaging/__tests__/messages/OrderOffer.spec.ts @@ -3,6 +3,7 @@ import { expect } from 'chai'; import { LOCKTIME_THRESHOLD, MessageType, + OrderOfferContainer, OrderPositionInfoV0, } from '../../lib'; import { ContractInfo } from '../../lib/messages/ContractInfo'; @@ -526,4 +527,21 @@ describe('OrderOffer', () => { }).to.throw(Error); }); }); + + describe('OrderOfferContainer', () => { + it('should serialize and deserialize', () => { + const orderOffer = OrderOfferV0.deserialize(buf); + // swap payout and change spk to differentiate between dlcoffers + const orderOffer2 = OrderOfferV0.deserialize(buf); + orderOffer2.refundLocktime = 300; + + const container = new OrderOfferContainer(); + container.addOffer(orderOffer); + container.addOffer(orderOffer2); + + const instance = OrderOfferContainer.deserialize(container.serialize()); + + expect(container.serialize()).to.deep.equal(instance.serialize()); + }); + }); }); diff --git a/packages/messaging/lib/messages/DlcAccept.ts b/packages/messaging/lib/messages/DlcAccept.ts index 91f95cd..1344f55 100644 --- a/packages/messaging/lib/messages/DlcAccept.ts +++ b/packages/messaging/lib/messages/DlcAccept.ts @@ -330,3 +330,59 @@ export interface IDlcAcceptV0Addresses { changeAddress: string; payoutAddress: string; } + +export class DlcAcceptContainer { + private accepts: DlcAccept[] = []; + + /** + * Adds a DlcAccept to the container. + * @param accept The DlcAccept to add. + */ + public addAccept(accept: DlcAccept): void { + this.accepts.push(accept); + } + + /** + * Returns all DlcAccepts in the container. + * @returns An array of DlcAccept instances. + */ + public getAccepts(): DlcAccept[] { + return this.accepts; + } + + /** + * Serializes all DlcAccepts in the container to a Buffer. + * @returns A Buffer containing the serialized DlcAccepts. + */ + public serialize(): Buffer { + const writer = new BufferWriter(); + // Write the number of accepts in the container first. + writer.writeUInt16BE(this.accepts.length); + // Serialize each accept and write it. + this.accepts.forEach((accept) => { + const serializedAccept = accept.serialize(); + // Optionally, write the length of the serialized accept for easier deserialization. + writer.writeUInt16BE(serializedAccept.length); + writer.writeBytes(serializedAccept); + }); + return writer.toBuffer(); + } + + /** + * Deserializes a Buffer into a DlcAcceptContainer with DlcAccepts. + * @param buf The Buffer to deserialize. + * @returns A DlcAcceptContainer instance. + */ + public static deserialize(buf: Buffer, parseCets = true): DlcAcceptContainer { + const reader = new BufferReader(buf); + const container = new DlcAcceptContainer(); + const acceptsCount = reader.readUInt16BE(); + for (let i = 0; i < acceptsCount; i++) { + const acceptLength = reader.readUInt16BE(); + const acceptBuf = reader.readBytes(acceptLength); + const accept = DlcAccept.deserialize(acceptBuf, parseCets); // Adjust based on actual implementation. + container.addAccept(accept); + } + return container; + } +} diff --git a/packages/messaging/lib/messages/DlcOffer.ts b/packages/messaging/lib/messages/DlcOffer.ts index 9a487fa..dd65de7 100644 --- a/packages/messaging/lib/messages/DlcOffer.ts +++ b/packages/messaging/lib/messages/DlcOffer.ts @@ -397,3 +397,60 @@ export interface IDlcOfferV0Addresses { changeAddress: string; payoutAddress: string; } + +export class DlcOfferContainer { + private offers: DlcOffer[] = []; + + /** + * Adds a DlcOffer to the container. + * @param offer The DlcOffer to add. + */ + public addOffer(offer: DlcOffer): void { + this.offers.push(offer); + } + + /** + * Returns all DlcOffers in the container. + * @returns An array of DlcOffer instances. + */ + public getOffers(): DlcOffer[] { + return this.offers; + } + + /** + * Serializes all DlcOffers in the container to a Buffer. + * @returns A Buffer containing the serialized DlcOffers. + */ + public serialize(): Buffer { + const writer = new BufferWriter(); + // Write the number of offers in the container first. + writer.writeUInt16BE(this.offers.length); + // Serialize each offer and write it. + this.offers.forEach((offer) => { + const serializedOffer = offer.serialize(); + // Optionally, write the length of the serialized offer for easier deserialization. + writer.writeUInt16BE(serializedOffer.length); + writer.writeBytes(serializedOffer); + }); + return writer.toBuffer(); + } + + /** + * Deserializes a Buffer into a DlcOfferContainer with DlcOffers. + * @param buf The Buffer to deserialize. + * @returns A DlcOfferContainer instance. + */ + public static deserialize(buf: Buffer): DlcOfferContainer { + const reader = new BufferReader(buf); + const container = new DlcOfferContainer(); + const offersCount = reader.readUInt16BE(); + for (let i = 0; i < offersCount; i++) { + // Optionally, read the length of the serialized offer if it was written during serialization. + const offerLength = reader.readUInt16BE(); + const offerBuf = reader.readBytes(offerLength); + const offer = DlcOffer.deserialize(offerBuf); // This needs to be adjusted based on actual implementation. + container.addOffer(offer); + } + return container; + } +} diff --git a/packages/messaging/lib/messages/DlcSign.ts b/packages/messaging/lib/messages/DlcSign.ts index facb028..172b956 100644 --- a/packages/messaging/lib/messages/DlcSign.ts +++ b/packages/messaging/lib/messages/DlcSign.ts @@ -108,3 +108,60 @@ export interface IDlcSignV0JSON { refundSignature: string; fundingSignatures: IFundingSignaturesV0JSON; } + +export class DlcSignContainer { + private signs: DlcSign[] = []; + + /** + * Adds a DlcSign to the container. + * @param sign The DlcSign to add. + */ + public addSign(sign: DlcSign): void { + this.signs.push(sign); + } + + /** + * Returns all DlcSigns in the container. + * @returns An array of DlcSign instances. + */ + public getSigns(): DlcSign[] { + return this.signs; + } + + /** + * Serializes all DlcSigns in the container to a Buffer. + * @returns A Buffer containing the serialized DlcSigns. + */ + public serialize(): Buffer { + const writer = new BufferWriter(); + // Write the number of signs in the container first. + writer.writeUInt16BE(this.signs.length); + // Serialize each sign and write it. + this.signs.forEach((sign) => { + const serializedSign = sign.serialize(); + // Optionally, write the length of the serialized sign for easier deserialization. + writer.writeUInt16BE(serializedSign.length); + writer.writeBytes(serializedSign); + }); + return writer.toBuffer(); + } + + /** + * Deserializes a Buffer into a DlcSignContainer with DlcSigns. + * @param buf The Buffer to deserialize. + * @returns A DlcSignContainer instance. + */ + public static deserialize(buf: Buffer): DlcSignContainer { + const reader = new BufferReader(buf); + const container = new DlcSignContainer(); + const signsCount = reader.readUInt16BE(); + for (let i = 0; i < signsCount; i++) { + // Optionally, read the length of the serialized sign if it was written during serialization. + const signLength = reader.readUInt16BE(); + const signBuf = reader.readBytes(signLength); + const sign = DlcSign.deserialize(signBuf); // Adjust based on actual implementation. + container.addSign(sign); + } + return container; + } +} diff --git a/packages/messaging/lib/messages/OrderAccept.ts b/packages/messaging/lib/messages/OrderAccept.ts index 61950ec..8a84292 100644 --- a/packages/messaging/lib/messages/OrderAccept.ts +++ b/packages/messaging/lib/messages/OrderAccept.ts @@ -95,3 +95,58 @@ export interface IOrderAcceptV0JSON { | IOrderNegotiationFieldsV0JSON | IOrderNegotiationFieldsV1JSON; } + +export class OrderAcceptContainer { + private accepts: OrderAccept[] = []; + + /** + * Adds an OrderAccept to the container. + * @param accept The OrderAccept to add. + */ + public addAccept(accept: OrderAccept): void { + this.accepts.push(accept); + } + + /** + * Returns all OrderAccepts in the container. + * @returns An array of OrderAccept instances. + */ + public getAccepts(): OrderAccept[] { + return this.accepts; + } + + /** + * Serializes all OrderAccepts in the container to a Buffer. + * @returns A Buffer containing the serialized OrderAccepts. + */ + public serialize(): Buffer { + const writer = new BufferWriter(); + // Write the number of accepts in the container first. + writer.writeUInt16BE(this.accepts.length); + // Serialize each accept and write it. + this.accepts.forEach((accept) => { + const serializedAccept = accept.serialize(); + writer.writeUInt16BE(serializedAccept.length); + writer.writeBytes(serializedAccept); + }); + return writer.toBuffer(); + } + + /** + * Deserializes a Buffer into an OrderAcceptContainer with OrderAccepts. + * @param buf The Buffer to deserialize. + * @returns An OrderAcceptContainer instance. + */ + public static deserialize(buf: Buffer): OrderAcceptContainer { + const reader = new BufferReader(buf); + const container = new OrderAcceptContainer(); + const acceptsCount = reader.readUInt16BE(); + for (let i = 0; i < acceptsCount; i++) { + const acceptLength = reader.readUInt16BE(); + const acceptBuf = reader.readBytes(acceptLength); + const accept = OrderAccept.deserialize(acceptBuf); // Adjust based on actual implementation. + container.addAccept(accept); + } + return container; + } +} diff --git a/packages/messaging/lib/messages/OrderOffer.ts b/packages/messaging/lib/messages/OrderOffer.ts index 52d85e3..4d16e4f 100644 --- a/packages/messaging/lib/messages/OrderOffer.ts +++ b/packages/messaging/lib/messages/OrderOffer.ts @@ -251,3 +251,60 @@ export interface IOrderOfferJSON { | IBatchFundingGroupJSON )[]; } + +export class OrderOfferContainer { + private offers: OrderOffer[] = []; + + /** + * Adds an OrderOffer to the container. + * @param offer The OrderOffer to add. + */ + public addOffer(offer: OrderOffer): void { + this.offers.push(offer); + } + + /** + * Returns all OrderOffers in the container. + * @returns An array of OrderOffer instances. + */ + public getOffers(): OrderOffer[] { + return this.offers; + } + + /** + * Serializes all OrderOffers in the container to a Buffer. + * @returns A Buffer containing the serialized OrderOffers. + */ + public serialize(): Buffer { + const writer = new BufferWriter(); + // Write the number of offers in the container first. + writer.writeUInt16BE(this.offers.length); + // Serialize each offer and write it. + this.offers.forEach((offer) => { + const serializedOffer = offer.serialize(); + // Optionally, write the length of the serialized offer for easier deserialization. + writer.writeUInt16BE(serializedOffer.length); + writer.writeBytes(serializedOffer); + }); + return writer.toBuffer(); + } + + /** + * Deserializes a Buffer into an OrderOfferContainer with OrderOffers. + * @param buf The Buffer to deserialize. + * @returns An OrderOfferContainer instance. + */ + public static deserialize(buf: Buffer): OrderOfferContainer { + const reader = new BufferReader(buf); + const container = new OrderOfferContainer(); + const offersCount = reader.readUInt16BE(); + for (let i = 0; i < offersCount; i++) { + // Optionally, read the length of the serialized offer if it was written during serialization. + const offerLength = reader.readUInt16BE(); + const offerBuf = reader.readBytes(offerLength); + const offer = OrderOffer.deserialize(offerBuf); // Adjust based on actual implementation. + container.addOffer(offer); + } + return container; + } +}