From f00740fa12a3b91f9415d5308cda7aab3ce78d23 Mon Sep 17 00:00:00 2001 From: Matthew Black Date: Mon, 20 Oct 2025 17:13:01 -0500 Subject: [PATCH 1/2] fix: wrap buffer.subarray() calls with Buffer.from() - fix ContractInfo deserialization for React Native - fix DlcAccept CET adaptor signature parsing - fix DlcOffer nextBytes buffer reading compatibility - fix DlcSign funding signature deserialization - ensure all buffer operations work in React Native --- packages/messaging/lib/messages/ContractInfo.ts | 12 ++++++------ packages/messaging/lib/messages/DlcAccept.ts | 4 ++-- packages/messaging/lib/messages/DlcOffer.ts | 10 ++++++---- packages/messaging/lib/messages/DlcSign.ts | 4 ++-- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/packages/messaging/lib/messages/ContractInfo.ts b/packages/messaging/lib/messages/ContractInfo.ts index 9253c19b..9d79c42e 100644 --- a/packages/messaging/lib/messages/ContractInfo.ts +++ b/packages/messaging/lib/messages/ContractInfo.ts @@ -123,7 +123,7 @@ export class SingleContractInfo extends ContractInfo implements IDlcMessage { // Read contract descriptor as sibling type (starts with its own type prefix) instance.contractDescriptor = ContractDescriptor.deserialize( - reader.buffer.subarray(reader.position), + Buffer.from(reader.buffer.subarray(reader.position)), ); // Skip past the contract descriptor we just read const descLength = instance.contractDescriptor.serialize().length; @@ -134,12 +134,12 @@ export class SingleContractInfo extends ContractInfo implements IDlcMessage { if (oracleType === 0) { // Single oracle instance.oracleInfo = SingleOracleInfo.deserializeBody( - reader.buffer.subarray(reader.position), + Buffer.from(reader.buffer.subarray(reader.position)), ); } else if (oracleType === 1) { // Multi oracle instance.oracleInfo = MultiOracleInfo.deserializeBody( - reader.buffer.subarray(reader.position), + Buffer.from(reader.buffer.subarray(reader.position)), ); } else { throw new Error(`Unknown oracle info type: ${oracleType}`); @@ -277,7 +277,7 @@ export class DisjointContractInfo extends ContractInfo implements IDlcMessage { for (let i = 0; i < numDisjointEvents; i++) { // Read contract descriptor as sibling type (starts with its own type prefix) const contractDescriptor = ContractDescriptor.deserialize( - reader.buffer.subarray(reader.position), + Buffer.from(reader.buffer.subarray(reader.position)), ); // Skip past the contract descriptor we just read const descLength = contractDescriptor.serialize().length; @@ -290,12 +290,12 @@ export class DisjointContractInfo extends ContractInfo implements IDlcMessage { if (oracleType === 0) { // Single oracle oracleInfo = SingleOracleInfo.deserializeBody( - reader.buffer.subarray(reader.position), + Buffer.from(reader.buffer.subarray(reader.position)), ); } else if (oracleType === 1) { // Multi oracle oracleInfo = MultiOracleInfo.deserializeBody( - reader.buffer.subarray(reader.position), + Buffer.from(reader.buffer.subarray(reader.position)), ); } else { throw new Error(`Unknown oracle info type: ${oracleType}`); diff --git a/packages/messaging/lib/messages/DlcAccept.ts b/packages/messaging/lib/messages/DlcAccept.ts index b1fcec4b..b2b9b484 100644 --- a/packages/messaging/lib/messages/DlcAccept.ts +++ b/packages/messaging/lib/messages/DlcAccept.ts @@ -203,7 +203,7 @@ export class DlcAccept implements IDlcMessage { for (let i = 0; i < fundingInputsLen; i++) { // FundingInput body is serialized directly without TLV wrapper in rust-dlc format const fundingInput = FundingInput.deserializeBody( - reader.buffer.subarray(reader.position), + Buffer.from(reader.buffer.subarray(reader.position)), ); instance.fundingInputs.push(fundingInput); @@ -219,7 +219,7 @@ export class DlcAccept implements IDlcMessage { if (parseCets) { // Read CET adaptor signatures directly to match serialize format (no TLV wrapping) instance.cetAdaptorSignatures = CetAdaptorSignatures.deserialize( - reader.buffer.subarray(reader.position), + Buffer.from(reader.buffer.subarray(reader.position)), ); // Skip past the CET adaptor signatures we just read diff --git a/packages/messaging/lib/messages/DlcOffer.ts b/packages/messaging/lib/messages/DlcOffer.ts index 50f851b3..bb4f1867 100644 --- a/packages/messaging/lib/messages/DlcOffer.ts +++ b/packages/messaging/lib/messages/DlcOffer.ts @@ -135,8 +135,10 @@ export class DlcOffer implements IDlcMessage { reader.position, reader.position + 5, ); - const possibleProtocolVersion = nextBytes.readUInt32BE(0); - const possibleContractFlags = nextBytes.readUInt8(4); + const nextBytesBuffer = Buffer.from(nextBytes); + const nextBytesReader = new BufferReader(nextBytesBuffer); + const possibleProtocolVersion = nextBytesReader.readUInt32BE(); + const possibleContractFlags = nextBytesReader.readUInt8(); // Heuristic: protocol_version should be 1, contract_flags should be 0 // If first 4 bytes are reasonable protocol version (1-10) and next byte is 0, assume new format @@ -160,7 +162,7 @@ export class DlcOffer implements IDlcMessage { // ContractInfo is serialized as sibling type in dlcspecs PR #163 format instance.contractInfo = ContractInfo.deserialize( - reader.buffer.subarray(reader.position), + Buffer.from(reader.buffer.subarray(reader.position)), ); // Skip past the ContractInfo we just read const contractInfoLength = instance.contractInfo.serialize().length; @@ -177,7 +179,7 @@ export class DlcOffer implements IDlcMessage { for (let i = 0; i < fundingInputsLen; i++) { // FundingInput body is serialized directly without TLV wrapper in rust-dlc format const fundingInput = FundingInput.deserializeBody( - reader.buffer.subarray(reader.position), + Buffer.from(reader.buffer.subarray(reader.position)), ); instance.fundingInputs.push(fundingInput); diff --git a/packages/messaging/lib/messages/DlcSign.ts b/packages/messaging/lib/messages/DlcSign.ts index 757a590b..6cd3ab7e 100644 --- a/packages/messaging/lib/messages/DlcSign.ts +++ b/packages/messaging/lib/messages/DlcSign.ts @@ -156,7 +156,7 @@ export class DlcSign implements IDlcMessage { // Read CET adaptor signatures directly to match serialize format (no TLV wrapping) instance.cetAdaptorSignatures = CetAdaptorSignatures.deserialize( - reader.buffer.subarray(reader.position), + Buffer.from(reader.buffer.subarray(reader.position)), ); // Skip past the CET adaptor signatures we just read @@ -167,7 +167,7 @@ export class DlcSign implements IDlcMessage { // Read funding signatures directly to match serialize format (no TLV wrapping) instance.fundingSignatures = FundingSignatures.deserialize( - reader.buffer.subarray(reader.position), + Buffer.from(reader.buffer.subarray(reader.position)), ); // Skip past the funding signatures we just read From 698e83beb92f0d25be3482cba3d22b2e24a48c28 Mon Sep 17 00:00:00 2001 From: Matthew Black Date: Mon, 20 Oct 2025 17:19:11 -0500 Subject: [PATCH 2/2] fix: wrap buffer.subarray() calls with Buffer.from() other msgs --- packages/messaging/lib/messages/ContractDescriptor.ts | 4 ++-- packages/messaging/lib/messages/DlcClose.ts | 4 ++-- packages/messaging/lib/messages/OrderOffer.ts | 8 +++++--- packages/messaging/lib/messages/PayoutFunction.ts | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/packages/messaging/lib/messages/ContractDescriptor.ts b/packages/messaging/lib/messages/ContractDescriptor.ts index 5d85fecd..db0dd6f5 100644 --- a/packages/messaging/lib/messages/ContractDescriptor.ts +++ b/packages/messaging/lib/messages/ContractDescriptor.ts @@ -212,7 +212,7 @@ export class NumericalDescriptor // Parse payout function - need to calculate its size to avoid consuming all bytes const payoutFunctionStartPos = reader.position; const tempPayoutFunction = PayoutFunction.deserialize( - reader.buffer.subarray(reader.position), + Buffer.from(reader.buffer.subarray(reader.position)), ); instance.payoutFunction = tempPayoutFunction; @@ -222,7 +222,7 @@ export class NumericalDescriptor // Parse remaining bytes as rounding intervals instance.roundingIntervals = RoundingIntervals.deserialize( - reader.buffer.subarray(reader.position), + Buffer.from(reader.buffer.subarray(reader.position)), ); return instance; diff --git a/packages/messaging/lib/messages/DlcClose.ts b/packages/messaging/lib/messages/DlcClose.ts index eb734faf..12d15164 100644 --- a/packages/messaging/lib/messages/DlcClose.ts +++ b/packages/messaging/lib/messages/DlcClose.ts @@ -128,7 +128,7 @@ export class DlcClose implements IDlcMessage { for (let i = 0; i < fundingInputsLen; i++) { // FundingInput body is serialized directly without TLV wrapper in rust-dlc format const fundingInput = FundingInput.deserializeBody( - reader.buffer.subarray(reader.position), + Buffer.from(reader.buffer.subarray(reader.position)), ); instance.fundingInputs.push(fundingInput); @@ -139,7 +139,7 @@ export class DlcClose implements IDlcMessage { // Handle FundingSignatures - deserialize raw data (no TLV wrapper) like DlcSign instance.fundingSignatures = FundingSignatures.deserialize( - reader.buffer.subarray(reader.position), + Buffer.from(reader.buffer.subarray(reader.position)), ); // Skip past the funding signatures we just read diff --git a/packages/messaging/lib/messages/OrderOffer.ts b/packages/messaging/lib/messages/OrderOffer.ts index e8fc19d5..32fca3a4 100644 --- a/packages/messaging/lib/messages/OrderOffer.ts +++ b/packages/messaging/lib/messages/OrderOffer.ts @@ -92,8 +92,10 @@ export class OrderOffer implements IDlcMessage { reader.position, reader.position + 5, ); - const possibleProtocolVersion = nextBytes.readUInt32BE(0); - const possibleContractFlags = nextBytes.readUInt8(4); + const nextBytesBuffer = Buffer.from(nextBytes); + const nextBytesReader = new BufferReader(nextBytesBuffer); + const possibleProtocolVersion = nextBytesReader.readUInt32BE(); + const possibleContractFlags = nextBytesReader.readUInt8(); // Heuristic: protocol_version should be 1, contract_flags should be 0 const isNewFormat = @@ -116,7 +118,7 @@ export class OrderOffer implements IDlcMessage { // ContractInfo is serialized as sibling type in dlcspecs PR #163 format instance.contractInfo = ContractInfo.deserialize( - reader.buffer.subarray(reader.position), + Buffer.from(reader.buffer.subarray(reader.position)), ); // Skip past the ContractInfo we just read const contractInfoLength = instance.contractInfo.serialize().length; diff --git a/packages/messaging/lib/messages/PayoutFunction.ts b/packages/messaging/lib/messages/PayoutFunction.ts index b1de611c..0842127e 100644 --- a/packages/messaging/lib/messages/PayoutFunction.ts +++ b/packages/messaging/lib/messages/PayoutFunction.ts @@ -112,7 +112,7 @@ export class PayoutFunction implements IDlcMessage { // Read payout curve piece const payoutCurvePieceStartPos = reader.position; const payoutCurvePiece = PayoutCurvePiece.deserialize( - reader.buffer.subarray(reader.position), + Buffer.from(reader.buffer.subarray(reader.position)), ); // Skip past the payout curve piece bytes