@btc-vision/transaction 1.7.19 → 1.7.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/LICENSE +190 -21
  2. package/README.md +1 -1
  3. package/browser/_version.d.ts +1 -1
  4. package/browser/generators/builders/HashCommitmentGenerator.d.ts +49 -0
  5. package/browser/index.js +1 -1
  6. package/browser/keypair/Address.d.ts +3 -1
  7. package/browser/opnet.d.ts +6 -1
  8. package/browser/signer/AddressRotation.d.ts +12 -0
  9. package/browser/transaction/TransactionFactory.d.ts +14 -0
  10. package/browser/transaction/builders/ConsolidatedInteractionTransaction.d.ts +44 -0
  11. package/browser/transaction/enums/TransactionType.d.ts +3 -1
  12. package/browser/transaction/interfaces/IConsolidatedTransactionParameters.d.ts +31 -0
  13. package/browser/transaction/interfaces/ITransactionParameters.d.ts +2 -0
  14. package/browser/transaction/offline/OfflineTransactionManager.d.ts +69 -0
  15. package/browser/transaction/offline/TransactionReconstructor.d.ts +28 -0
  16. package/browser/transaction/offline/TransactionSerializer.d.ts +50 -0
  17. package/browser/transaction/offline/TransactionStateCapture.d.ts +52 -0
  18. package/browser/transaction/offline/index.d.ts +5 -0
  19. package/browser/transaction/offline/interfaces/ISerializableState.d.ts +62 -0
  20. package/browser/transaction/offline/interfaces/ITypeSpecificData.d.ts +62 -0
  21. package/browser/transaction/offline/interfaces/index.d.ts +2 -0
  22. package/browser/transaction/shared/TweakedTransaction.d.ts +12 -1
  23. package/browser/utxo/interfaces/IUTXO.d.ts +2 -0
  24. package/build/_version.d.ts +1 -1
  25. package/build/_version.js +1 -1
  26. package/build/generators/builders/HashCommitmentGenerator.d.ts +49 -0
  27. package/build/generators/builders/HashCommitmentGenerator.js +229 -0
  28. package/build/keypair/Address.d.ts +3 -1
  29. package/build/keypair/Address.js +87 -54
  30. package/build/opnet.d.ts +6 -1
  31. package/build/opnet.js +6 -1
  32. package/build/signer/AddressRotation.d.ts +12 -0
  33. package/build/signer/AddressRotation.js +16 -0
  34. package/build/transaction/TransactionFactory.d.ts +14 -0
  35. package/build/transaction/TransactionFactory.js +36 -0
  36. package/build/transaction/builders/ConsolidatedInteractionTransaction.d.ts +44 -0
  37. package/build/transaction/builders/ConsolidatedInteractionTransaction.js +259 -0
  38. package/build/transaction/builders/TransactionBuilder.js +2 -0
  39. package/build/transaction/enums/TransactionType.d.ts +3 -1
  40. package/build/transaction/enums/TransactionType.js +2 -0
  41. package/build/transaction/interfaces/IConsolidatedTransactionParameters.d.ts +31 -0
  42. package/build/transaction/interfaces/IConsolidatedTransactionParameters.js +1 -0
  43. package/build/transaction/interfaces/ITransactionParameters.d.ts +2 -0
  44. package/build/transaction/offline/OfflineTransactionManager.d.ts +69 -0
  45. package/build/transaction/offline/OfflineTransactionManager.js +255 -0
  46. package/build/transaction/offline/TransactionReconstructor.d.ts +28 -0
  47. package/build/transaction/offline/TransactionReconstructor.js +243 -0
  48. package/build/transaction/offline/TransactionSerializer.d.ts +50 -0
  49. package/build/transaction/offline/TransactionSerializer.js +700 -0
  50. package/build/transaction/offline/TransactionStateCapture.d.ts +52 -0
  51. package/build/transaction/offline/TransactionStateCapture.js +275 -0
  52. package/build/transaction/offline/index.d.ts +5 -0
  53. package/build/transaction/offline/index.js +5 -0
  54. package/build/transaction/offline/interfaces/ISerializableState.d.ts +62 -0
  55. package/build/transaction/offline/interfaces/ISerializableState.js +2 -0
  56. package/build/transaction/offline/interfaces/ITypeSpecificData.d.ts +62 -0
  57. package/build/transaction/offline/interfaces/ITypeSpecificData.js +19 -0
  58. package/build/transaction/offline/interfaces/index.d.ts +2 -0
  59. package/build/transaction/offline/interfaces/index.js +2 -0
  60. package/build/transaction/shared/TweakedTransaction.d.ts +12 -1
  61. package/build/transaction/shared/TweakedTransaction.js +75 -8
  62. package/build/utxo/interfaces/IUTXO.d.ts +2 -0
  63. package/documentation/README.md +5 -0
  64. package/documentation/offline-transaction-signing.md +650 -0
  65. package/documentation/transaction-building.md +603 -0
  66. package/package.json +2 -2
  67. package/src/_version.ts +1 -1
  68. package/src/generators/builders/HashCommitmentGenerator.ts +495 -0
  69. package/src/keypair/Address.ts +123 -70
  70. package/src/opnet.ts +8 -1
  71. package/src/signer/AddressRotation.ts +72 -0
  72. package/src/transaction/TransactionFactory.ts +90 -0
  73. package/src/transaction/builders/CancelTransaction.ts +4 -2
  74. package/src/transaction/builders/ConsolidatedInteractionTransaction.ts +568 -0
  75. package/src/transaction/builders/CustomScriptTransaction.ts +4 -2
  76. package/src/transaction/builders/MultiSignTransaction.ts +4 -2
  77. package/src/transaction/builders/TransactionBuilder.ts +8 -2
  78. package/src/transaction/enums/TransactionType.ts +2 -0
  79. package/src/transaction/interfaces/IConsolidatedTransactionParameters.ts +78 -0
  80. package/src/transaction/interfaces/ITransactionParameters.ts +8 -0
  81. package/src/transaction/offline/OfflineTransactionManager.ts +630 -0
  82. package/src/transaction/offline/TransactionReconstructor.ts +402 -0
  83. package/src/transaction/offline/TransactionSerializer.ts +920 -0
  84. package/src/transaction/offline/TransactionStateCapture.ts +469 -0
  85. package/src/transaction/offline/index.ts +8 -0
  86. package/src/transaction/offline/interfaces/ISerializableState.ts +141 -0
  87. package/src/transaction/offline/interfaces/ITypeSpecificData.ts +172 -0
  88. package/src/transaction/offline/interfaces/index.ts +2 -0
  89. package/src/transaction/shared/TweakedTransaction.ts +156 -9
  90. package/src/utxo/interfaces/IUTXO.ts +8 -0
  91. package/test/address-rotation.test.ts +553 -0
  92. package/test/offline-transaction.test.ts +2065 -0
@@ -0,0 +1,700 @@
1
+ import { createHash } from 'crypto';
2
+ import { BinaryWriter } from '../../buffer/BinaryWriter.js';
3
+ import { BinaryReader } from '../../buffer/BinaryReader.js';
4
+ import { SERIALIZATION_FORMAT_VERSION, SERIALIZATION_MAGIC_BYTE, } from './interfaces/ISerializableState.js';
5
+ import { TransactionType } from '../enums/TransactionType.js';
6
+ export class TransactionSerializer {
7
+ static serialize(state) {
8
+ const writer = new BinaryWriter();
9
+ this.writeHeader(writer, state.header);
10
+ this.writeBaseParams(writer, state.baseParams);
11
+ this.writeUTXOArray(writer, state.utxos);
12
+ this.writeUTXOArray(writer, state.optionalInputs);
13
+ this.writeOutputArray(writer, state.optionalOutputs);
14
+ writer.writeBoolean(state.addressRotationEnabled);
15
+ this.writeSignerMappings(writer, state.signerMappings);
16
+ this.writeTypeSpecificData(writer, state.typeSpecificData);
17
+ this.writePrecomputedData(writer, state.precomputedData);
18
+ const dataBuffer = Buffer.from(writer.getBuffer());
19
+ const checksum = this.calculateChecksum(dataBuffer);
20
+ return Buffer.concat([dataBuffer, checksum]);
21
+ }
22
+ static deserialize(data) {
23
+ if (data.length < 32) {
24
+ throw new Error('Invalid serialized data: too short');
25
+ }
26
+ const checksum = data.subarray(-32);
27
+ const payload = data.subarray(0, -32);
28
+ const expectedChecksum = this.calculateChecksum(payload);
29
+ if (!checksum.equals(expectedChecksum)) {
30
+ throw new Error('Invalid checksum - data may be corrupted');
31
+ }
32
+ const reader = new BinaryReader(payload);
33
+ const header = this.readHeader(reader);
34
+ if (header.formatVersion > SERIALIZATION_FORMAT_VERSION) {
35
+ throw new Error(`Unsupported format version: ${header.formatVersion}`);
36
+ }
37
+ const baseParams = this.readBaseParams(reader);
38
+ const utxos = this.readUTXOArray(reader);
39
+ const optionalInputs = this.readUTXOArray(reader);
40
+ const optionalOutputs = this.readOutputArray(reader);
41
+ const addressRotationEnabled = reader.readBoolean();
42
+ const signerMappings = this.readSignerMappings(reader);
43
+ const typeSpecificData = this.readTypeSpecificData(reader, header.transactionType);
44
+ const precomputedData = this.readPrecomputedData(reader);
45
+ return {
46
+ header,
47
+ baseParams,
48
+ utxos,
49
+ optionalInputs,
50
+ optionalOutputs,
51
+ addressRotationEnabled,
52
+ signerMappings,
53
+ typeSpecificData,
54
+ precomputedData,
55
+ };
56
+ }
57
+ static toBase64(state) {
58
+ return this.serialize(state).toString('base64');
59
+ }
60
+ static fromBase64(base64) {
61
+ return this.deserialize(Buffer.from(base64, 'base64'));
62
+ }
63
+ static toHex(state) {
64
+ return this.serialize(state).toString('hex');
65
+ }
66
+ static fromHex(hex) {
67
+ return this.deserialize(Buffer.from(hex, 'hex'));
68
+ }
69
+ static writeHeader(writer, header) {
70
+ writer.writeU8(SERIALIZATION_MAGIC_BYTE);
71
+ writer.writeU8(header.formatVersion);
72
+ writer.writeU8(header.consensusVersion);
73
+ writer.writeU8(header.transactionType);
74
+ writer.writeU32(header.chainId);
75
+ writer.writeU64(BigInt(header.timestamp));
76
+ }
77
+ static readHeader(reader) {
78
+ const magic = reader.readU8();
79
+ if (magic !== SERIALIZATION_MAGIC_BYTE) {
80
+ throw new Error(`Invalid magic byte: expected 0x${SERIALIZATION_MAGIC_BYTE.toString(16)}, got 0x${magic.toString(16)}`);
81
+ }
82
+ return {
83
+ formatVersion: reader.readU8(),
84
+ consensusVersion: reader.readU8(),
85
+ transactionType: reader.readU8(),
86
+ chainId: reader.readU32(),
87
+ timestamp: Number(reader.readU64()),
88
+ };
89
+ }
90
+ static writeBaseParams(writer, params) {
91
+ writer.writeStringWithLength(params.from);
92
+ writer.writeBoolean(params.to !== undefined);
93
+ if (params.to !== undefined) {
94
+ writer.writeStringWithLength(params.to);
95
+ }
96
+ writer.writeU32(Math.floor(params.feeRate * 1000));
97
+ writer.writeU64(BigInt(params.priorityFee));
98
+ writer.writeU64(BigInt(params.gasSatFee));
99
+ writer.writeU8(this.networkNameToU8(params.networkName));
100
+ writer.writeU8(params.txVersion);
101
+ writer.writeBoolean(params.note !== undefined);
102
+ if (params.note !== undefined) {
103
+ writer.writeBytesWithLength(Buffer.from(params.note, 'hex'));
104
+ }
105
+ writer.writeBoolean(params.anchor);
106
+ writer.writeBoolean(params.debugFees ?? false);
107
+ }
108
+ static readBaseParams(reader) {
109
+ const from = reader.readStringWithLength();
110
+ const hasTo = reader.readBoolean();
111
+ const to = hasTo ? reader.readStringWithLength() : undefined;
112
+ const feeRate = reader.readU32() / 1000;
113
+ const priorityFee = reader.readU64().toString();
114
+ const gasSatFee = reader.readU64().toString();
115
+ const networkName = this.u8ToNetworkName(reader.readU8());
116
+ const txVersion = reader.readU8();
117
+ const hasNote = reader.readBoolean();
118
+ const note = hasNote
119
+ ? Buffer.from(reader.readBytesWithLength()).toString('hex')
120
+ : undefined;
121
+ const anchor = reader.readBoolean();
122
+ const debugFees = reader.readBoolean();
123
+ return {
124
+ from,
125
+ to,
126
+ feeRate,
127
+ priorityFee,
128
+ gasSatFee,
129
+ networkName,
130
+ txVersion,
131
+ note,
132
+ anchor,
133
+ debugFees,
134
+ };
135
+ }
136
+ static writeUTXOArray(writer, utxos) {
137
+ writer.writeU16(utxos.length);
138
+ for (const utxo of utxos) {
139
+ this.writeUTXO(writer, utxo);
140
+ }
141
+ }
142
+ static writeUTXO(writer, utxo) {
143
+ writer.writeBytes(Buffer.from(utxo.transactionId, 'hex'));
144
+ writer.writeU32(utxo.outputIndex);
145
+ writer.writeU64(BigInt(utxo.value));
146
+ writer.writeBytesWithLength(Buffer.from(utxo.scriptPubKeyHex, 'hex'));
147
+ writer.writeBoolean(utxo.scriptPubKeyAddress !== undefined);
148
+ if (utxo.scriptPubKeyAddress !== undefined) {
149
+ writer.writeStringWithLength(utxo.scriptPubKeyAddress);
150
+ }
151
+ writer.writeBoolean(utxo.redeemScript !== undefined);
152
+ if (utxo.redeemScript !== undefined) {
153
+ writer.writeBytesWithLength(Buffer.from(utxo.redeemScript, 'hex'));
154
+ }
155
+ writer.writeBoolean(utxo.witnessScript !== undefined);
156
+ if (utxo.witnessScript !== undefined) {
157
+ writer.writeBytesWithLength(Buffer.from(utxo.witnessScript, 'hex'));
158
+ }
159
+ writer.writeBoolean(utxo.nonWitnessUtxo !== undefined);
160
+ if (utxo.nonWitnessUtxo !== undefined) {
161
+ writer.writeBytesWithLength(Buffer.from(utxo.nonWitnessUtxo, 'hex'));
162
+ }
163
+ }
164
+ static readUTXOArray(reader) {
165
+ const count = reader.readU16();
166
+ const utxos = [];
167
+ for (let i = 0; i < count; i++) {
168
+ utxos.push(this.readUTXO(reader));
169
+ }
170
+ return utxos;
171
+ }
172
+ static readUTXO(reader) {
173
+ const transactionId = Buffer.from(reader.readBytes(32)).toString('hex');
174
+ const outputIndex = reader.readU32();
175
+ const value = reader.readU64().toString();
176
+ const scriptPubKeyHex = Buffer.from(reader.readBytesWithLength()).toString('hex');
177
+ const hasAddress = reader.readBoolean();
178
+ const scriptPubKeyAddress = hasAddress ? reader.readStringWithLength() : undefined;
179
+ const hasRedeemScript = reader.readBoolean();
180
+ const redeemScript = hasRedeemScript
181
+ ? Buffer.from(reader.readBytesWithLength()).toString('hex')
182
+ : undefined;
183
+ const hasWitnessScript = reader.readBoolean();
184
+ const witnessScript = hasWitnessScript
185
+ ? Buffer.from(reader.readBytesWithLength()).toString('hex')
186
+ : undefined;
187
+ const hasNonWitnessUtxo = reader.readBoolean();
188
+ const nonWitnessUtxo = hasNonWitnessUtxo
189
+ ? Buffer.from(reader.readBytesWithLength()).toString('hex')
190
+ : undefined;
191
+ return {
192
+ transactionId,
193
+ outputIndex,
194
+ value,
195
+ scriptPubKeyHex,
196
+ scriptPubKeyAddress,
197
+ redeemScript,
198
+ witnessScript,
199
+ nonWitnessUtxo,
200
+ };
201
+ }
202
+ static writeOutputArray(writer, outputs) {
203
+ writer.writeU16(outputs.length);
204
+ for (const output of outputs) {
205
+ this.writeOutput(writer, output);
206
+ }
207
+ }
208
+ static writeOutput(writer, output) {
209
+ writer.writeU64(BigInt(output.value));
210
+ writer.writeBoolean(output.address !== undefined);
211
+ if (output.address !== undefined) {
212
+ writer.writeStringWithLength(output.address);
213
+ }
214
+ writer.writeBoolean(output.script !== undefined);
215
+ if (output.script !== undefined) {
216
+ writer.writeBytesWithLength(Buffer.from(output.script, 'hex'));
217
+ }
218
+ writer.writeBoolean(output.tapInternalKey !== undefined);
219
+ if (output.tapInternalKey !== undefined) {
220
+ writer.writeBytesWithLength(Buffer.from(output.tapInternalKey, 'hex'));
221
+ }
222
+ }
223
+ static readOutputArray(reader) {
224
+ const count = reader.readU16();
225
+ const outputs = [];
226
+ for (let i = 0; i < count; i++) {
227
+ outputs.push(this.readOutput(reader));
228
+ }
229
+ return outputs;
230
+ }
231
+ static readOutput(reader) {
232
+ const value = Number(reader.readU64());
233
+ const hasAddress = reader.readBoolean();
234
+ const address = hasAddress ? reader.readStringWithLength() : undefined;
235
+ const hasScript = reader.readBoolean();
236
+ const script = hasScript
237
+ ? Buffer.from(reader.readBytesWithLength()).toString('hex')
238
+ : undefined;
239
+ const hasTapInternalKey = reader.readBoolean();
240
+ const tapInternalKey = hasTapInternalKey
241
+ ? Buffer.from(reader.readBytesWithLength()).toString('hex')
242
+ : undefined;
243
+ return { value, address, script, tapInternalKey };
244
+ }
245
+ static writeSignerMappings(writer, mappings) {
246
+ writer.writeU16(mappings.length);
247
+ for (const mapping of mappings) {
248
+ writer.writeStringWithLength(mapping.address);
249
+ writer.writeU16(mapping.inputIndices.length);
250
+ for (const idx of mapping.inputIndices) {
251
+ writer.writeU16(idx);
252
+ }
253
+ }
254
+ }
255
+ static readSignerMappings(reader) {
256
+ const count = reader.readU16();
257
+ const mappings = [];
258
+ for (let i = 0; i < count; i++) {
259
+ const address = reader.readStringWithLength();
260
+ const indicesCount = reader.readU16();
261
+ const inputIndices = [];
262
+ for (let j = 0; j < indicesCount; j++) {
263
+ inputIndices.push(reader.readU16());
264
+ }
265
+ mappings.push({ address, inputIndices });
266
+ }
267
+ return mappings;
268
+ }
269
+ static writeTypeSpecificData(writer, data) {
270
+ switch (data.type) {
271
+ case TransactionType.FUNDING:
272
+ this.writeFundingData(writer, data);
273
+ break;
274
+ case TransactionType.DEPLOYMENT:
275
+ this.writeDeploymentData(writer, data);
276
+ break;
277
+ case TransactionType.INTERACTION:
278
+ this.writeInteractionData(writer, data);
279
+ break;
280
+ case TransactionType.MULTI_SIG:
281
+ this.writeMultiSigData(writer, data);
282
+ break;
283
+ case TransactionType.CUSTOM_CODE:
284
+ this.writeCustomScriptData(writer, data);
285
+ break;
286
+ case TransactionType.CANCEL:
287
+ this.writeCancelData(writer, data);
288
+ break;
289
+ default:
290
+ throw new Error(`Unsupported transaction type: ${data.type}`);
291
+ }
292
+ }
293
+ static readTypeSpecificData(reader, type) {
294
+ switch (type) {
295
+ case TransactionType.FUNDING:
296
+ return this.readFundingData(reader);
297
+ case TransactionType.DEPLOYMENT:
298
+ return this.readDeploymentData(reader);
299
+ case TransactionType.INTERACTION:
300
+ return this.readInteractionData(reader);
301
+ case TransactionType.MULTI_SIG:
302
+ return this.readMultiSigData(reader);
303
+ case TransactionType.CUSTOM_CODE:
304
+ return this.readCustomScriptData(reader);
305
+ case TransactionType.CANCEL:
306
+ return this.readCancelData(reader);
307
+ default:
308
+ throw new Error(`Unsupported transaction type: ${type}`);
309
+ }
310
+ }
311
+ static writeFundingData(writer, data) {
312
+ writer.writeU64(BigInt(data.amount));
313
+ writer.writeU16(data.splitInputsInto);
314
+ }
315
+ static readFundingData(reader) {
316
+ return {
317
+ type: TransactionType.FUNDING,
318
+ amount: reader.readU64().toString(),
319
+ splitInputsInto: reader.readU16(),
320
+ };
321
+ }
322
+ static writeDeploymentData(writer, data) {
323
+ writer.writeBytesWithLength(Buffer.from(data.bytecode, 'hex'));
324
+ writer.writeBoolean(data.calldata !== undefined);
325
+ if (data.calldata !== undefined) {
326
+ writer.writeBytesWithLength(Buffer.from(data.calldata, 'hex'));
327
+ }
328
+ this.writeChallenge(writer, data.challenge);
329
+ writer.writeBoolean(data.revealMLDSAPublicKey ?? false);
330
+ writer.writeBoolean(data.linkMLDSAPublicKeyToAddress ?? false);
331
+ writer.writeBoolean(data.hashedPublicKey !== undefined);
332
+ if (data.hashedPublicKey !== undefined) {
333
+ writer.writeBytesWithLength(Buffer.from(data.hashedPublicKey, 'hex'));
334
+ }
335
+ }
336
+ static readDeploymentData(reader) {
337
+ const bytecode = Buffer.from(reader.readBytesWithLength()).toString('hex');
338
+ const hasCalldata = reader.readBoolean();
339
+ const calldata = hasCalldata
340
+ ? Buffer.from(reader.readBytesWithLength()).toString('hex')
341
+ : undefined;
342
+ const challenge = this.readChallenge(reader);
343
+ const revealMLDSAPublicKey = reader.readBoolean();
344
+ const linkMLDSAPublicKeyToAddress = reader.readBoolean();
345
+ const hasHashedPublicKey = reader.readBoolean();
346
+ const hashedPublicKey = hasHashedPublicKey
347
+ ? Buffer.from(reader.readBytesWithLength()).toString('hex')
348
+ : undefined;
349
+ return {
350
+ type: TransactionType.DEPLOYMENT,
351
+ bytecode,
352
+ calldata,
353
+ challenge,
354
+ revealMLDSAPublicKey,
355
+ linkMLDSAPublicKeyToAddress,
356
+ hashedPublicKey,
357
+ };
358
+ }
359
+ static writeInteractionData(writer, data) {
360
+ writer.writeBytesWithLength(Buffer.from(data.calldata, 'hex'));
361
+ writer.writeBoolean(data.contract !== undefined);
362
+ if (data.contract !== undefined) {
363
+ writer.writeStringWithLength(data.contract);
364
+ }
365
+ this.writeChallenge(writer, data.challenge);
366
+ writer.writeBoolean(data.loadedStorage !== undefined);
367
+ if (data.loadedStorage !== undefined) {
368
+ this.writeLoadedStorage(writer, data.loadedStorage);
369
+ }
370
+ writer.writeBoolean(data.isCancellation ?? false);
371
+ writer.writeBoolean(data.disableAutoRefund ?? false);
372
+ writer.writeBoolean(data.revealMLDSAPublicKey ?? false);
373
+ writer.writeBoolean(data.linkMLDSAPublicKeyToAddress ?? false);
374
+ writer.writeBoolean(data.hashedPublicKey !== undefined);
375
+ if (data.hashedPublicKey !== undefined) {
376
+ writer.writeBytesWithLength(Buffer.from(data.hashedPublicKey, 'hex'));
377
+ }
378
+ }
379
+ static readInteractionData(reader) {
380
+ const calldata = Buffer.from(reader.readBytesWithLength()).toString('hex');
381
+ const hasContract = reader.readBoolean();
382
+ const contract = hasContract ? reader.readStringWithLength() : undefined;
383
+ const challenge = this.readChallenge(reader);
384
+ const hasLoadedStorage = reader.readBoolean();
385
+ const loadedStorage = hasLoadedStorage ? this.readLoadedStorage(reader) : undefined;
386
+ const isCancellation = reader.readBoolean();
387
+ const disableAutoRefund = reader.readBoolean();
388
+ const revealMLDSAPublicKey = reader.readBoolean();
389
+ const linkMLDSAPublicKeyToAddress = reader.readBoolean();
390
+ const hasHashedPublicKey = reader.readBoolean();
391
+ const hashedPublicKey = hasHashedPublicKey
392
+ ? Buffer.from(reader.readBytesWithLength()).toString('hex')
393
+ : undefined;
394
+ return {
395
+ type: TransactionType.INTERACTION,
396
+ calldata,
397
+ contract,
398
+ challenge,
399
+ loadedStorage,
400
+ isCancellation,
401
+ disableAutoRefund,
402
+ revealMLDSAPublicKey,
403
+ linkMLDSAPublicKeyToAddress,
404
+ hashedPublicKey,
405
+ };
406
+ }
407
+ static writeMultiSigData(writer, data) {
408
+ writer.writeU16(data.pubkeys.length);
409
+ for (const pubkey of data.pubkeys) {
410
+ writer.writeBytesWithLength(Buffer.from(pubkey, 'hex'));
411
+ }
412
+ writer.writeU8(data.minimumSignatures);
413
+ writer.writeStringWithLength(data.receiver);
414
+ writer.writeU64(BigInt(data.requestedAmount));
415
+ writer.writeStringWithLength(data.refundVault);
416
+ writer.writeU16(data.originalInputCount);
417
+ writer.writeBoolean(data.existingPsbtBase64 !== undefined);
418
+ if (data.existingPsbtBase64 !== undefined) {
419
+ writer.writeStringWithLength(data.existingPsbtBase64);
420
+ }
421
+ }
422
+ static readMultiSigData(reader) {
423
+ const pubkeysCount = reader.readU16();
424
+ const pubkeys = [];
425
+ for (let i = 0; i < pubkeysCount; i++) {
426
+ pubkeys.push(Buffer.from(reader.readBytesWithLength()).toString('hex'));
427
+ }
428
+ const minimumSignatures = reader.readU8();
429
+ const receiver = reader.readStringWithLength();
430
+ const requestedAmount = reader.readU64().toString();
431
+ const refundVault = reader.readStringWithLength();
432
+ const originalInputCount = reader.readU16();
433
+ const hasExistingPsbt = reader.readBoolean();
434
+ const existingPsbtBase64 = hasExistingPsbt ? reader.readStringWithLength() : undefined;
435
+ return {
436
+ type: TransactionType.MULTI_SIG,
437
+ pubkeys,
438
+ minimumSignatures,
439
+ receiver,
440
+ requestedAmount,
441
+ refundVault,
442
+ originalInputCount,
443
+ existingPsbtBase64,
444
+ };
445
+ }
446
+ static writeCustomScriptData(writer, data) {
447
+ writer.writeU16(data.scriptElements.length);
448
+ for (const element of data.scriptElements) {
449
+ this.writeScriptElement(writer, element);
450
+ }
451
+ writer.writeU16(data.witnesses.length);
452
+ for (const witness of data.witnesses) {
453
+ writer.writeBytesWithLength(Buffer.from(witness, 'hex'));
454
+ }
455
+ writer.writeBoolean(data.annex !== undefined);
456
+ if (data.annex !== undefined) {
457
+ writer.writeBytesWithLength(Buffer.from(data.annex, 'hex'));
458
+ }
459
+ }
460
+ static writeScriptElement(writer, element) {
461
+ writer.writeU8(element.elementType === 'buffer' ? 0 : 1);
462
+ if (element.elementType === 'buffer') {
463
+ writer.writeBytesWithLength(Buffer.from(element.value, 'hex'));
464
+ }
465
+ else {
466
+ writer.writeU32(element.value);
467
+ }
468
+ }
469
+ static readCustomScriptData(reader) {
470
+ const elementsCount = reader.readU16();
471
+ const scriptElements = [];
472
+ for (let i = 0; i < elementsCount; i++) {
473
+ scriptElements.push(this.readScriptElement(reader));
474
+ }
475
+ const witnessesCount = reader.readU16();
476
+ const witnesses = [];
477
+ for (let i = 0; i < witnessesCount; i++) {
478
+ witnesses.push(Buffer.from(reader.readBytesWithLength()).toString('hex'));
479
+ }
480
+ const hasAnnex = reader.readBoolean();
481
+ const annex = hasAnnex
482
+ ? Buffer.from(reader.readBytesWithLength()).toString('hex')
483
+ : undefined;
484
+ return {
485
+ type: TransactionType.CUSTOM_CODE,
486
+ scriptElements,
487
+ witnesses,
488
+ annex,
489
+ };
490
+ }
491
+ static readScriptElement(reader) {
492
+ const typeFlag = reader.readU8();
493
+ if (typeFlag === 0) {
494
+ return {
495
+ elementType: 'buffer',
496
+ value: Buffer.from(reader.readBytesWithLength()).toString('hex'),
497
+ };
498
+ }
499
+ else {
500
+ return {
501
+ elementType: 'opcode',
502
+ value: reader.readU32(),
503
+ };
504
+ }
505
+ }
506
+ static writeCancelData(writer, data) {
507
+ writer.writeBytesWithLength(Buffer.from(data.compiledTargetScript, 'hex'));
508
+ }
509
+ static readCancelData(reader) {
510
+ return {
511
+ type: TransactionType.CANCEL,
512
+ compiledTargetScript: Buffer.from(reader.readBytesWithLength()).toString('hex'),
513
+ };
514
+ }
515
+ static writeChallenge(writer, challenge) {
516
+ writer.writeU64(BigInt(challenge.epochNumber));
517
+ writer.writeStringWithLength(challenge.mldsaPublicKey);
518
+ writer.writeStringWithLength(challenge.legacyPublicKey);
519
+ writer.writeBytesWithLength(Buffer.from(challenge.solution.replace('0x', ''), 'hex'));
520
+ writer.writeBytesWithLength(Buffer.from(challenge.salt.replace('0x', ''), 'hex'));
521
+ writer.writeBytesWithLength(Buffer.from(challenge.graffiti.replace('0x', ''), 'hex'));
522
+ writer.writeU8(challenge.difficulty);
523
+ this.writeChallengeVerification(writer, challenge.verification);
524
+ writer.writeBoolean(challenge.submission !== undefined);
525
+ if (challenge.submission !== undefined) {
526
+ writer.writeStringWithLength(challenge.submission.mldsaPublicKey);
527
+ writer.writeStringWithLength(challenge.submission.legacyPublicKey);
528
+ writer.writeBytesWithLength(Buffer.from(challenge.submission.solution.replace('0x', ''), 'hex'));
529
+ writer.writeBoolean(challenge.submission.graffiti !== undefined);
530
+ if (challenge.submission.graffiti !== undefined) {
531
+ writer.writeBytesWithLength(Buffer.from(challenge.submission.graffiti.replace('0x', ''), 'hex'));
532
+ }
533
+ writer.writeBytesWithLength(Buffer.from(challenge.submission.signature.replace('0x', ''), 'hex'));
534
+ }
535
+ }
536
+ static writeChallengeVerification(writer, verification) {
537
+ writer.writeBytesWithLength(Buffer.from(verification.epochHash.replace('0x', ''), 'hex'));
538
+ writer.writeBytesWithLength(Buffer.from(verification.epochRoot.replace('0x', ''), 'hex'));
539
+ writer.writeBytesWithLength(Buffer.from(verification.targetHash.replace('0x', ''), 'hex'));
540
+ writer.writeBytesWithLength(Buffer.from(verification.targetChecksum.replace('0x', ''), 'hex'));
541
+ writer.writeU64(BigInt(verification.startBlock));
542
+ writer.writeU64(BigInt(verification.endBlock));
543
+ writer.writeU16(verification.proofs.length);
544
+ for (const proof of verification.proofs) {
545
+ writer.writeBytesWithLength(Buffer.from(proof.replace('0x', ''), 'hex'));
546
+ }
547
+ }
548
+ static readChallenge(reader) {
549
+ const epochNumber = reader.readU64().toString();
550
+ const mldsaPublicKey = reader.readStringWithLength();
551
+ const legacyPublicKey = reader.readStringWithLength();
552
+ const solution = '0x' + Buffer.from(reader.readBytesWithLength()).toString('hex');
553
+ const salt = '0x' + Buffer.from(reader.readBytesWithLength()).toString('hex');
554
+ const graffiti = '0x' + Buffer.from(reader.readBytesWithLength()).toString('hex');
555
+ const difficulty = reader.readU8();
556
+ const verification = this.readChallengeVerification(reader);
557
+ const hasSubmission = reader.readBoolean();
558
+ let submission;
559
+ if (hasSubmission) {
560
+ const subMldsaPublicKey = reader.readStringWithLength();
561
+ const subLegacyPublicKey = reader.readStringWithLength();
562
+ const subSolution = '0x' + Buffer.from(reader.readBytesWithLength()).toString('hex');
563
+ const hasGraffiti = reader.readBoolean();
564
+ const subGraffiti = hasGraffiti
565
+ ? '0x' + Buffer.from(reader.readBytesWithLength()).toString('hex')
566
+ : undefined;
567
+ const subSignature = '0x' + Buffer.from(reader.readBytesWithLength()).toString('hex');
568
+ submission = {
569
+ mldsaPublicKey: subMldsaPublicKey,
570
+ legacyPublicKey: subLegacyPublicKey,
571
+ solution: subSolution,
572
+ graffiti: subGraffiti,
573
+ signature: subSignature,
574
+ };
575
+ }
576
+ return {
577
+ epochNumber,
578
+ mldsaPublicKey,
579
+ legacyPublicKey,
580
+ solution,
581
+ salt,
582
+ graffiti,
583
+ difficulty,
584
+ verification,
585
+ submission,
586
+ };
587
+ }
588
+ static readChallengeVerification(reader) {
589
+ const epochHash = '0x' + Buffer.from(reader.readBytesWithLength()).toString('hex');
590
+ const epochRoot = '0x' + Buffer.from(reader.readBytesWithLength()).toString('hex');
591
+ const targetHash = '0x' + Buffer.from(reader.readBytesWithLength()).toString('hex');
592
+ const targetChecksum = '0x' + Buffer.from(reader.readBytesWithLength()).toString('hex');
593
+ const startBlock = reader.readU64().toString();
594
+ const endBlock = reader.readU64().toString();
595
+ const proofsCount = reader.readU16();
596
+ const proofs = [];
597
+ for (let i = 0; i < proofsCount; i++) {
598
+ proofs.push('0x' + Buffer.from(reader.readBytesWithLength()).toString('hex'));
599
+ }
600
+ return {
601
+ epochHash,
602
+ epochRoot,
603
+ targetHash,
604
+ targetChecksum,
605
+ startBlock,
606
+ endBlock,
607
+ proofs,
608
+ };
609
+ }
610
+ static writeLoadedStorage(writer, storage) {
611
+ const keys = Object.keys(storage);
612
+ writer.writeU16(keys.length);
613
+ for (const key of keys) {
614
+ writer.writeStringWithLength(key);
615
+ writer.writeStringArray(storage[key]);
616
+ }
617
+ }
618
+ static readLoadedStorage(reader) {
619
+ const count = reader.readU16();
620
+ const storage = {};
621
+ for (let i = 0; i < count; i++) {
622
+ const key = reader.readStringWithLength();
623
+ storage[key] = reader.readStringArray();
624
+ }
625
+ return storage;
626
+ }
627
+ static writePrecomputedData(writer, data) {
628
+ writer.writeBoolean(data.compiledTargetScript !== undefined);
629
+ if (data.compiledTargetScript !== undefined) {
630
+ writer.writeBytesWithLength(Buffer.from(data.compiledTargetScript, 'hex'));
631
+ }
632
+ writer.writeBoolean(data.randomBytes !== undefined);
633
+ if (data.randomBytes !== undefined) {
634
+ writer.writeBytesWithLength(Buffer.from(data.randomBytes, 'hex'));
635
+ }
636
+ writer.writeBoolean(data.estimatedFees !== undefined);
637
+ if (data.estimatedFees !== undefined) {
638
+ writer.writeU64(BigInt(data.estimatedFees));
639
+ }
640
+ writer.writeBoolean(data.contractSeed !== undefined);
641
+ if (data.contractSeed !== undefined) {
642
+ writer.writeStringWithLength(data.contractSeed);
643
+ }
644
+ writer.writeBoolean(data.contractAddress !== undefined);
645
+ if (data.contractAddress !== undefined) {
646
+ writer.writeStringWithLength(data.contractAddress);
647
+ }
648
+ }
649
+ static readPrecomputedData(reader) {
650
+ const hasCompiledTargetScript = reader.readBoolean();
651
+ const compiledTargetScript = hasCompiledTargetScript
652
+ ? Buffer.from(reader.readBytesWithLength()).toString('hex')
653
+ : undefined;
654
+ const hasRandomBytes = reader.readBoolean();
655
+ const randomBytes = hasRandomBytes
656
+ ? Buffer.from(reader.readBytesWithLength()).toString('hex')
657
+ : undefined;
658
+ const hasEstimatedFees = reader.readBoolean();
659
+ const estimatedFees = hasEstimatedFees ? reader.readU64().toString() : undefined;
660
+ const hasContractSeed = reader.readBoolean();
661
+ const contractSeed = hasContractSeed ? reader.readStringWithLength() : undefined;
662
+ const hasContractAddress = reader.readBoolean();
663
+ const contractAddress = hasContractAddress ? reader.readStringWithLength() : undefined;
664
+ return {
665
+ compiledTargetScript,
666
+ randomBytes,
667
+ estimatedFees,
668
+ contractSeed,
669
+ contractAddress,
670
+ };
671
+ }
672
+ static calculateChecksum(data) {
673
+ const hash1 = createHash('sha256').update(data).digest();
674
+ return createHash('sha256').update(hash1).digest();
675
+ }
676
+ static networkNameToU8(name) {
677
+ switch (name) {
678
+ case 'mainnet':
679
+ return 0;
680
+ case 'testnet':
681
+ return 1;
682
+ case 'regtest':
683
+ return 2;
684
+ default:
685
+ throw new Error(`Unknown network: ${name}`);
686
+ }
687
+ }
688
+ static u8ToNetworkName(value) {
689
+ switch (value) {
690
+ case 0:
691
+ return 'mainnet';
692
+ case 1:
693
+ return 'testnet';
694
+ case 2:
695
+ return 'regtest';
696
+ default:
697
+ throw new Error(`Unknown network value: ${value}`);
698
+ }
699
+ }
700
+ }