@fleet-sdk/serializer 0.8.2 → 0.8.5

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.
package/dist/index.js CHANGED
@@ -4,20 +4,20 @@ var common = require('@fleet-sdk/common');
4
4
  var crypto = require('@fleet-sdk/crypto');
5
5
 
6
6
  // src/coders/sigmaByteReader.ts
7
- function hexToBigInt(hex6) {
8
- const value = BigInt(hex6.length % 2 ? `0x0${hex6}` : `0x${hex6}`);
9
- const highByte = Number.parseInt(hex6.slice(0, 2), 16);
7
+ function hexToBigInt(hex8) {
8
+ const value = BigInt(hex8.length % 2 ? `0x0${hex8}` : `0x${hex8}`);
9
+ const highByte = Number.parseInt(hex8.slice(0, 2), 16);
10
10
  if (128 & highByte) return -negateAndMask(value);
11
11
  return value;
12
12
  }
13
13
  function bigIntToHex(value) {
14
14
  const positive = value >= common._0n;
15
- let hex6 = (positive ? value : negateAndMask(value)).toString(16);
16
- if (hex6.length % 2) hex6 = `0${hex6}`;
17
- if (positive && 128 & Number.parseInt(hex6.slice(0, 2), 16)) {
18
- return `00${hex6}`;
15
+ let hex8 = (positive ? value : negateAndMask(value)).toString(16);
16
+ if (hex8.length % 2) hex8 = `0${hex8}`;
17
+ if (positive && 128 & Number.parseInt(hex8.slice(0, 2), 16)) {
18
+ return `00${hex8}`;
19
19
  }
20
- return hex6;
20
+ return hex8;
21
21
  }
22
22
  function negateAndMask(value) {
23
23
  let val = value;
@@ -150,12 +150,26 @@ var SigmaByteReader = class {
150
150
  #bytes;
151
151
  #cursor;
152
152
  get isEmpty() {
153
- return common.isEmpty(this.#bytes);
153
+ return this.#bytes.length === this.#cursor;
154
+ }
155
+ get bytes() {
156
+ return this.#bytes;
157
+ }
158
+ get cursor() {
159
+ return this.#cursor;
154
160
  }
155
161
  constructor(bytes) {
156
162
  this.#bytes = crypto.ensureBytes(bytes);
157
163
  this.#cursor = 0;
158
164
  }
165
+ readArray(readFn) {
166
+ const length = this.readUInt();
167
+ const items = new Array(length);
168
+ for (let i = 0; i < length; i++) {
169
+ items[i] = readFn(this, i);
170
+ }
171
+ return items;
172
+ }
159
173
  readBool() {
160
174
  return this.readByte() === 1;
161
175
  }
@@ -179,9 +193,12 @@ var SigmaByteReader = class {
179
193
  readBytes(length) {
180
194
  return this.#bytes.subarray(this.#cursor, this.#cursor += length);
181
195
  }
182
- readVlq() {
196
+ readUInt() {
183
197
  return readVLQ(this);
184
198
  }
199
+ readBigUInt() {
200
+ return readBigVLQ(this);
201
+ }
185
202
  readI8() {
186
203
  const byte = this.readByte();
187
204
  return byte > MAX_I8 ? byte - (MAX_U8 + 1) : byte;
@@ -199,6 +216,19 @@ var SigmaByteReader = class {
199
216
  const len = readVLQ(this);
200
217
  return hexToBigInt(crypto.hex.encode(this.readBytes(len)));
201
218
  }
219
+ /**
220
+ * Returns bytes without advancing the cursor.
221
+ */
222
+ peek(count, offset = 0) {
223
+ const begin = this.#cursor + offset;
224
+ return this.#bytes.subarray(begin, begin + count);
225
+ }
226
+ /**
227
+ * Checks if the current position in the byte array starts with the given bytes.
228
+ */
229
+ match(bytes, offset = 0) {
230
+ return common.startsWith(this.#bytes, bytes, this.#cursor + offset);
231
+ }
202
232
  };
203
233
  var SigmaByteWriter = class {
204
234
  #bytes;
@@ -214,37 +244,37 @@ var SigmaByteWriter = class {
214
244
  this.write(value === true ? 1 : 0);
215
245
  return this;
216
246
  }
217
- writeVLQ(value) {
247
+ writeUInt(value) {
218
248
  return writeVLQ(this, value);
219
249
  }
220
- writeBigVLQ(value) {
250
+ writeBigUInt(value) {
221
251
  return writeBigVLQ(this, value);
222
252
  }
223
253
  writeI16(value) {
224
254
  if (value < MIN_I16 || value > MAX_I16) {
225
255
  throw new RangeError(`Value ${value} is out of range for a 16-bit integer`);
226
256
  }
227
- this.writeBigVLQ(zigZag32.encode(value));
257
+ this.writeBigUInt(zigZag32.encode(value));
228
258
  return this;
229
259
  }
230
260
  writeI32(value) {
231
261
  if (value < MIN_I32 || value > MAX_I32) {
232
262
  throw new RangeError(`Value ${value} is out of range for a 32-bit integer`);
233
263
  }
234
- return this.writeBigVLQ(zigZag32.encode(value));
264
+ return this.writeBigUInt(zigZag32.encode(value));
235
265
  }
236
266
  writeI64(value) {
237
267
  if (value < MIN_I64 || value > MAX_I64) {
238
268
  throw new RangeError(`Value ${value} is out of range for a 64-bit integer`);
239
269
  }
240
- return this.writeBigVLQ(zigZag64.encode(value));
270
+ return this.writeBigUInt(zigZag64.encode(value));
241
271
  }
242
272
  writeI256(value) {
243
273
  if (value < MIN_I256 || value > MAX_I256) {
244
274
  throw new RangeError(`Value ${value} is out of range for a 256-bit integer`);
245
275
  }
246
- const hex6 = bigIntToHex(value);
247
- return this.writeVLQ(hex6.length / 2).writeHex(hex6);
276
+ const hex8 = bigIntToHex(value);
277
+ return this.writeUInt(hex8.length / 2).writeHex(hex8);
248
278
  }
249
279
  write(byte) {
250
280
  this.#bytes[this.#cursor++] = byte;
@@ -278,6 +308,23 @@ var SigmaByteWriter = class {
278
308
  const hash = hashFn(this.toBytes());
279
309
  return this.writeBytes(length ? hash.subarray(0, length) : hash);
280
310
  }
311
+ /**
312
+ * Writes a length-delimited array of items to the byte stream using a provided
313
+ * serializer function.
314
+ *
315
+ * @typeParam T - The type of items in the array.
316
+ * @param items - The array of items to serialize and write.
317
+ * @param serializer - A function that serializes each item and writes it using the provided SigmaByteWriter.
318
+ * @returns The current instance of SigmaByteWriter for method chaining.
319
+ */
320
+ writeArray(items, serializer) {
321
+ this.writeUInt(items.length);
322
+ if (items.length === 0) return this;
323
+ for (const item of items) {
324
+ serializer(item, this);
325
+ }
326
+ return this;
327
+ }
281
328
  encode(coder) {
282
329
  return coder.encode(this.toBytes());
283
330
  }
@@ -399,6 +446,14 @@ var SUnitType = class extends SMonomorphicType {
399
446
  return "SUnit";
400
447
  }
401
448
  };
449
+ var SBoxType = class extends SMonomorphicType {
450
+ get code() {
451
+ return 99;
452
+ }
453
+ toString() {
454
+ return "SBox";
455
+ }
456
+ };
402
457
 
403
458
  // src/types/descriptors.ts
404
459
  var constructorCode = Object.freeze({
@@ -441,6 +496,7 @@ var descriptors = {
441
496
  groupElement: new SGroupElementType(),
442
497
  sigmaProp: new SSigmaPropType(),
443
498
  unit: new SUnitType(),
499
+ box: new SBoxType(),
444
500
  coll: collDescriptor,
445
501
  tuple: tupleDescriptor
446
502
  };
@@ -537,7 +593,8 @@ var SSigmaProp = monoProxy(
537
593
  SSigmaPropType,
538
594
  descriptors.sigmaProp
539
595
  );
540
- var SUnit = monoProxy(SUnitType, undefined, true);
596
+ var SUnit = monoProxy(SUnitType, void 0, true);
597
+ var SBox = monoProxy(SBoxType, void 0, true);
541
598
  var SColl = genericProxy(SCollType, (target, _, args) => {
542
599
  const [type, elements] = args;
543
600
  const elementsType = type();
@@ -554,6 +611,143 @@ var SPair = genericProxy(STupleType, (target, _, args) => {
554
611
  }
555
612
  throw new Error("Invalid tuple declaration.");
556
613
  });
614
+ var MAX_UINT16_VALUE = 65535;
615
+ var FEE_CONTRACT_BYTES = crypto.hex.decode(common.FEE_CONTRACT);
616
+ var P2PK_CONTRACT_PREFIX = crypto.hex.decode("0008cd");
617
+ var COMPRESSED_PK_LENGTH = 33;
618
+ var P2PK_CONTRACT_LENGTH = P2PK_CONTRACT_PREFIX.length + COMPRESSED_PK_LENGTH;
619
+ function serializeBox(box, writer = new SigmaByteWriter(4096), distinctTokenIds) {
620
+ writer.writeBigUInt(common.ensureBigInt(box.value)).writeHex(box.ergoTree).writeUInt(box.creationHeight);
621
+ writeTokens(writer, box.assets, distinctTokenIds);
622
+ writeRegisters(writer, box.additionalRegisters);
623
+ if (common.isDefined(distinctTokenIds)) return writer;
624
+ if (!isBox(box)) throw new Error("Invalid box type.");
625
+ return writer.writeHex(box.transactionId).writeUInt(box.index);
626
+ }
627
+ function isBox(box) {
628
+ const castedBox = box;
629
+ return common.isDefined(castedBox.transactionId) && common.isDefined(castedBox.index);
630
+ }
631
+ function writeTokens(writer, tokens, tokenIds) {
632
+ if (tokenIds) {
633
+ writer.writeArray(
634
+ tokens,
635
+ (token, w) => w.writeUInt(tokenIds.indexOf(token.tokenId)).writeBigUInt(common.ensureBigInt(token.amount))
636
+ );
637
+ } else {
638
+ writer.writeArray(
639
+ tokens,
640
+ (token, w) => w.writeHex(token.tokenId).writeBigUInt(common.ensureBigInt(token.amount))
641
+ );
642
+ }
643
+ }
644
+ function writeRegisters(writer, registers) {
645
+ const keys = Object.keys(registers).sort();
646
+ const values = [];
647
+ for (const key of keys) {
648
+ const value = registers[key];
649
+ if (!value) continue;
650
+ values.push(value);
651
+ }
652
+ writer.writeArray(values, (value, w) => w.writeHex(value));
653
+ }
654
+ function estimateBoxSize(box, withValue) {
655
+ if (common.isUndefined(box.creationHeight)) {
656
+ throw new Error("Box size estimation error: creation height is undefined.");
657
+ }
658
+ let size = 0;
659
+ size += estimateVLQSize(common.isDefined(withValue) ? withValue : box.value);
660
+ size += common.byteSizeOf(box.ergoTree);
661
+ size += estimateVLQSize(box.creationHeight);
662
+ size += estimateVLQSize(box.assets.length);
663
+ for (const asset of box.assets) {
664
+ size += common.byteSizeOf(asset.tokenId) + estimateVLQSize(asset.amount);
665
+ }
666
+ let registersLength = 0;
667
+ for (const key in box.additionalRegisters) {
668
+ const register = box.additionalRegisters[key];
669
+ if (register) {
670
+ size += common.byteSizeOf(register);
671
+ registersLength++;
672
+ }
673
+ }
674
+ size += estimateVLQSize(registersLength);
675
+ size += 32;
676
+ size += estimateVLQSize(isBox(box) ? box.index : MAX_UINT16_VALUE);
677
+ return size;
678
+ }
679
+ function deserializeEmbeddedBox(reader, distinctTokenIds, transactionId, index) {
680
+ let begin = reader.cursor;
681
+ const value = reader.readBigUInt();
682
+ const ergoTree = crypto.hex.encode(readErgoTree(reader));
683
+ const creationHeight = reader.readUInt();
684
+ const boxIdWriter = new SigmaByteWriter(4096).writeBytes(reader.bytes.subarray(begin, reader.cursor));
685
+ const assets = readTokens(reader, distinctTokenIds);
686
+ boxIdWriter.writeUInt(assets.length);
687
+ for (const asset of assets) {
688
+ boxIdWriter.writeHex(asset.tokenId).writeBigUInt(asset.amount);
689
+ }
690
+ begin = reader.cursor;
691
+ const additionalRegisters = readRegisters(reader);
692
+ boxIdWriter.writeBytes(reader.bytes.subarray(begin, reader.cursor)).writeHex(transactionId).writeUInt(index);
693
+ return {
694
+ boxId: crypto.hex.encode(crypto.blake2b256(boxIdWriter.toBytes())),
695
+ value,
696
+ ergoTree,
697
+ creationHeight,
698
+ assets,
699
+ additionalRegisters,
700
+ transactionId,
701
+ index
702
+ };
703
+ }
704
+ function deserializeBox(input) {
705
+ const reader = input instanceof SigmaByteReader ? input : new SigmaByteReader(input);
706
+ const begin = reader.cursor;
707
+ const box = {
708
+ boxId: "",
709
+ // placeholder, will be calculated later
710
+ value: reader.readBigUInt(),
711
+ ergoTree: crypto.hex.encode(readErgoTree(reader)),
712
+ creationHeight: reader.readUInt(),
713
+ assets: readTokens(reader),
714
+ additionalRegisters: readRegisters(reader),
715
+ transactionId: crypto.hex.encode(reader.readBytes(32)),
716
+ index: reader.readUInt()
717
+ };
718
+ box.boxId = crypto.hex.encode(crypto.blake2b256(reader.bytes.subarray(begin, reader.cursor)));
719
+ return box;
720
+ }
721
+ function readErgoTree(reader) {
722
+ if (reader.match(FEE_CONTRACT_BYTES)) {
723
+ return reader.readBytes(FEE_CONTRACT_BYTES.length);
724
+ }
725
+ if (reader.match(P2PK_CONTRACT_PREFIX) && crypto.validateEcPoint(reader.peek(COMPRESSED_PK_LENGTH, P2PK_CONTRACT_PREFIX.length))) {
726
+ return reader.readBytes(P2PK_CONTRACT_LENGTH);
727
+ }
728
+ const header = reader.readByte();
729
+ const hasSize = (header & common.ergoTreeHeaderFlags.sizeInclusion) !== 0;
730
+ if (!hasSize) {
731
+ throw new Error("ErgoTree parsing without the size flag is not supported.");
732
+ }
733
+ const size = reader.readUInt();
734
+ return new SigmaByteWriter(1 + 4 + size).write(header).writeUInt(size).writeBytes(reader.readBytes(size)).toBytes();
735
+ }
736
+ function readTokens(reader, tokenIds) {
737
+ return reader.readArray((r) => ({
738
+ tokenId: tokenIds ? tokenIds[r.readUInt()] : crypto.hex.encode(r.readBytes(32)),
739
+ amount: r.readBigUInt()
740
+ }));
741
+ }
742
+ function readRegisters(reader) {
743
+ const registers = {};
744
+ const count = reader.readUInt();
745
+ for (let i = 0; i < count; i++) {
746
+ const value = SConstant.from(reader).toHex();
747
+ registers[`R${(i + 4).toString()}`] = value;
748
+ }
749
+ return registers;
750
+ }
557
751
 
558
752
  // src/serializers/dataSerializer.ts
559
753
  var GROUP_ELEMENT_LENGTH = 33;
@@ -595,7 +789,7 @@ var dataSerializer = {
595
789
  } else {
596
790
  common.assert(Array.isArray(data), `SColl expected an array, got ${typeof data}.`);
597
791
  }
598
- writer.writeVLQ(data.length);
792
+ writer.writeUInt(data.length);
599
793
  switch (type.elementsType.code) {
600
794
  case descriptors.bool.code: {
601
795
  return writer.writeBits(data);
@@ -623,6 +817,7 @@ var dataSerializer = {
623
817
  return writer;
624
818
  }
625
819
  if (type.code === descriptors.unit.code) return writer;
820
+ if (type.code === descriptors.box.code) return serializeBox(data, writer);
626
821
  throw Error(
627
822
  `Serialization error: '0x${type.code.toString(16)}' type not implemented.`
628
823
  );
@@ -654,7 +849,7 @@ var dataSerializer = {
654
849
  } else {
655
850
  switch (type.code) {
656
851
  case descriptors.coll.code: {
657
- const length = reader.readVlq();
852
+ const length = reader.readUInt();
658
853
  const embeddedType = type.elementsType;
659
854
  switch (embeddedType.code) {
660
855
  case descriptors.bool.code:
@@ -676,7 +871,9 @@ var dataSerializer = {
676
871
  );
677
872
  }
678
873
  case descriptors.unit.code:
679
- return undefined;
874
+ return void 0;
875
+ case descriptors.box.code:
876
+ return deserializeBox(reader);
680
877
  }
681
878
  }
682
879
  throw new Error(`Parsing error: '0x${type.code.toString(16)}' type not implemented.`);
@@ -688,6 +885,8 @@ var typeSerializer = {
688
885
  writer.write(type.code);
689
886
  } else if (type.code === descriptors.unit.code) {
690
887
  writer.write(type.code);
888
+ } else if (type.code === descriptors.box.code) {
889
+ writer.write(type.code);
691
890
  } else if (isColl(type)) {
692
891
  if (type.elementsType.embeddable) {
693
892
  writer.write(descriptors.coll.simpleCollTypeCode + type.elementsType.code);
@@ -740,7 +939,7 @@ var typeSerializer = {
740
939
  "Invalid type: tuples must have between 2 and 255 items."
741
940
  );
742
941
  writer.write(descriptors.tuple.genericTupleTypeCode);
743
- writer.writeVLQ(len);
942
+ writer.writeUInt(len);
744
943
  }
745
944
  }
746
945
  for (let i = 0; i < type.elementsType.length; i++) {
@@ -788,16 +987,17 @@ var typeSerializer = {
788
987
  }
789
988
  switch (byte) {
790
989
  case descriptors.tuple.genericTupleTypeCode: {
791
- const len = r.readVlq();
990
+ const len = r.readUInt();
792
991
  const wrapped = new Array(len);
793
992
  for (let i = 0; i < len; i++) {
794
993
  wrapped[i] = this.deserialize(r);
795
994
  }
796
995
  return new STupleType(wrapped);
797
996
  }
798
- case descriptors.unit.code: {
997
+ case descriptors.unit.code:
799
998
  return descriptors.unit;
800
- }
999
+ case descriptors.box.code:
1000
+ return descriptors.box;
801
1001
  }
802
1002
  throw new Error("Not implemented.");
803
1003
  }
@@ -813,8 +1013,8 @@ var SConstant = class _SConstant {
813
1013
  this.#data = type.coerce(data);
814
1014
  }
815
1015
  static from(bytes) {
816
- common.assert(bytes.length > 0, "Empty constant bytes.");
817
- const reader = new SigmaByteReader(bytes);
1016
+ const reader = bytes instanceof SigmaByteReader ? bytes : new SigmaByteReader(bytes);
1017
+ if (reader.isEmpty) throw new Error("Empty constant bytes.");
818
1018
  const type = typeSerializer.deserialize(reader);
819
1019
  const data = dataSerializer.deserialize(type, reader);
820
1020
  return new _SConstant(type, data);
@@ -836,7 +1036,7 @@ var SConstant = class _SConstant {
836
1036
  }
837
1037
  };
838
1038
  function decode(value) {
839
- if (value === undefined) return;
1039
+ if (value === void 0) return;
840
1040
  try {
841
1041
  return SConstant.from(value);
842
1042
  } catch {
@@ -860,118 +1060,99 @@ function parse(constant, mode = "strict") {
860
1060
  return;
861
1061
  }
862
1062
  }
863
- var MAX_UINT16_VALUE = 65535;
864
- function serializeBox(box, writer = new SigmaByteWriter(4096), distinctTokenIds) {
865
- writer.writeBigVLQ(common.ensureBigInt(box.value));
866
- writer.writeHex(box.ergoTree);
867
- writer.writeVLQ(box.creationHeight);
868
- writeTokens(writer, box.assets, distinctTokenIds);
869
- writeRegisters(writer, box.additionalRegisters);
870
- if (common.isDefined(distinctTokenIds)) return writer;
871
- if (!isBox(box)) throw new Error("Invalid box type.");
872
- return writer.writeHex(box.transactionId).writeVLQ(box.index);
873
- }
874
- function isBox(box) {
875
- const castedBox = box;
876
- return common.isDefined(castedBox.transactionId) && common.isDefined(castedBox.index);
1063
+ function serializeTransaction(transaction) {
1064
+ const tokenIds = getDistinctTokenIds(transaction.outputs);
1065
+ return new SigmaByteWriter(1e5).writeArray(transaction.inputs, (input, w) => writeInput(w, input)).writeArray(transaction.dataInputs, (dataInput, w) => w.writeHex(dataInput.boxId)).writeArray(tokenIds, (tokenId, w) => w.writeHex(tokenId)).writeArray(transaction.outputs, (output, w) => serializeBox(output, w, tokenIds));
877
1066
  }
878
- function writeTokens(writer, tokens, tokenIds) {
879
- if (common.isEmpty(tokens)) {
880
- writer.write(0);
1067
+ function writeInput(writer, input) {
1068
+ if (isSignedInput(input)) {
1069
+ writeSignedInput(writer, input);
881
1070
  return;
882
1071
  }
883
- writer.writeVLQ(tokens.length);
884
- if (common.some(tokenIds)) {
885
- tokens.map(
886
- (token) => writer.writeVLQ(tokenIds.indexOf(token.tokenId)).writeBigVLQ(common.ensureBigInt(token.amount))
887
- );
888
- } else {
889
- tokens.map(
890
- (token) => writer.writeHex(token.tokenId).writeBigVLQ(common.ensureBigInt(token.amount))
891
- );
892
- }
1072
+ writeUnsignedInput(writer, input);
893
1073
  }
894
- function writeRegisters(writer, registers) {
895
- const keys = Object.keys(registers).sort();
896
- let length = 0;
897
- for (const key of keys) {
898
- if (registers[key]) length++;
899
- }
900
- writer.writeVLQ(length);
901
- if (length === 0) return;
902
- for (const key of keys) {
903
- const register = registers[key];
904
- if (common.isDefined(register)) writer.writeHex(register);
905
- }
1074
+ function writeSignedInput(writer, input) {
1075
+ writer.writeHex(input.boxId);
1076
+ writeProof(writer, input.spendingProof?.proofBytes);
1077
+ writeExtension(writer, input.spendingProof?.extension);
906
1078
  }
907
- function estimateBoxSize(box, withValue) {
908
- if (common.isUndefined(box.creationHeight)) {
909
- throw new Error("Box size estimation error: creation height is undefined.");
910
- }
911
- let size = 0;
912
- size += estimateVLQSize(common.isDefined(withValue) ? withValue : box.value);
913
- size += common.byteSizeOf(box.ergoTree);
914
- size += estimateVLQSize(box.creationHeight);
915
- size += estimateVLQSize(box.assets.length);
916
- for (const asset of box.assets) {
917
- size += common.byteSizeOf(asset.tokenId) + estimateVLQSize(asset.amount);
918
- }
919
- let registersLength = 0;
920
- for (const key in box.additionalRegisters) {
921
- const register = box.additionalRegisters[key];
922
- if (register) {
923
- size += common.byteSizeOf(register);
924
- registersLength++;
925
- }
926
- }
927
- size += estimateVLQSize(registersLength);
928
- size += 32;
929
- size += estimateVLQSize(isBox(box) ? box.index : MAX_UINT16_VALUE);
930
- return size;
1079
+ function writeUnsignedInput(writer, input) {
1080
+ writer.writeHex(input.boxId);
1081
+ writeProof(writer, null);
1082
+ writeExtension(
1083
+ writer,
1084
+ isSignedInput(input) ? input.spendingProof?.extension : input.extension
1085
+ );
931
1086
  }
932
- function serializeTransaction(transaction) {
933
- const writer = new SigmaByteWriter(1e5);
934
- writer.writeVLQ(transaction.inputs.length);
935
- transaction.inputs.map((input) => writeInput(writer, input));
936
- writer.writeVLQ(transaction.dataInputs.length);
937
- transaction.dataInputs.map((dataInput) => writer.writeHex(dataInput.boxId));
938
- const distinctTokenIds = getDistinctTokenIds(transaction.outputs);
939
- writer.writeVLQ(distinctTokenIds.length);
940
- distinctTokenIds.map((tokenId) => writer.writeHex(tokenId));
941
- writer.writeVLQ(transaction.outputs.length);
942
- transaction.outputs.map((output) => serializeBox(output, writer, distinctTokenIds));
943
- return writer;
1087
+ function isSignedInput(input) {
1088
+ return input.spendingProof !== void 0;
944
1089
  }
945
- function writeInput(writer, input) {
946
- writer.writeHex(input.boxId);
947
- writer.write(0);
948
- writeExtension(writer, input.extension);
1090
+ function writeProof(writer, proof) {
1091
+ if (!proof) {
1092
+ writer.write(0);
1093
+ return;
1094
+ }
1095
+ const bytes = crypto.hex.decode(proof);
1096
+ writer.writeUInt(bytes.length).writeBytes(bytes);
949
1097
  }
950
1098
  function writeExtension(writer, extension) {
951
- const keys = Object.keys(extension);
952
- let length = 0;
953
- for (const key of keys) {
954
- if (common.isDefined(extension[key])) length++;
1099
+ if (!extension) {
1100
+ writer.write(0);
1101
+ return;
955
1102
  }
956
- writer.writeVLQ(length);
957
- if (length === 0) return;
1103
+ const keys = Object.keys(extension);
1104
+ const values = [];
958
1105
  for (const key of keys) {
959
- const val = extension[key];
960
- if (common.isDefined(val)) {
961
- writer.writeVLQ(Number(key)).writeHex(val);
962
- }
963
- }
1106
+ const value = extension[key];
1107
+ if (!value) continue;
1108
+ values.push([key, value]);
1109
+ }
1110
+ writer.writeArray(
1111
+ values,
1112
+ ([key, value], w) => w.writeUInt(Number(key)).writeHex(value)
1113
+ );
964
1114
  }
965
1115
  function getDistinctTokenIds(outputs) {
966
1116
  const tokenIds = /* @__PURE__ */ new Set();
967
1117
  outputs.flatMap((output) => output.assets.map((asset) => tokenIds.add(asset.tokenId)));
968
1118
  return Array.from(tokenIds);
969
1119
  }
1120
+ function deserializeTransaction(input) {
1121
+ const reader = new SigmaByteReader(input);
1122
+ const inputs = reader.readArray(readInput);
1123
+ const id = computeId(reader, inputs);
1124
+ const dataInputs = reader.readArray((r) => ({ boxId: crypto.hex.encode(r.readBytes(32)) }));
1125
+ const tokenIds = reader.readArray((r) => crypto.hex.encode(r.readBytes(32)));
1126
+ const outputs = reader.readArray((r, i) => deserializeEmbeddedBox(r, tokenIds, id, i));
1127
+ return {
1128
+ id,
1129
+ inputs,
1130
+ dataInputs,
1131
+ outputs
1132
+ };
1133
+ }
1134
+ function readInput(reader) {
1135
+ const boxId = crypto.hex.encode(reader.readBytes(32));
1136
+ const proofLength = reader.readUInt();
1137
+ const proofBytes = proofLength > 0 ? crypto.hex.encode(reader.readBytes(proofLength)) : null;
1138
+ const extensionLength = reader.readUInt();
1139
+ const extension = {};
1140
+ for (let i = 0; i < extensionLength; i++) {
1141
+ extension[reader.readUInt()] = SConstant.from(reader).toHex();
1142
+ }
1143
+ return proofBytes ? { boxId, spendingProof: { proofBytes, extension } } : { boxId, extension };
1144
+ }
1145
+ function computeId(reader, inputs) {
1146
+ const bytes = new SigmaByteWriter(reader.bytes.length).writeArray(inputs, (input, writer) => writeUnsignedInput(writer, input)).writeBytes(reader.bytes.subarray(reader.cursor)).toBytes();
1147
+ return crypto.hex.encode(crypto.blake2b256(bytes));
1148
+ }
970
1149
 
971
1150
  exports.SBigInt = SBigInt;
972
1151
  exports.SBigIntType = SBigIntType;
973
1152
  exports.SBool = SBool;
974
1153
  exports.SBoolType = SBoolType;
1154
+ exports.SBox = SBox;
1155
+ exports.SBoxType = SBoxType;
975
1156
  exports.SByte = SByte;
976
1157
  exports.SByteType = SByteType;
977
1158
  exports.SColl = SColl;
@@ -999,6 +1180,9 @@ exports.SigmaByteReader = SigmaByteReader;
999
1180
  exports.SigmaByteWriter = SigmaByteWriter;
1000
1181
  exports.dataSerializer = dataSerializer;
1001
1182
  exports.decode = decode;
1183
+ exports.deserializeBox = deserializeBox;
1184
+ exports.deserializeEmbeddedBox = deserializeEmbeddedBox;
1185
+ exports.deserializeTransaction = deserializeTransaction;
1002
1186
  exports.estimateBoxSize = estimateBoxSize;
1003
1187
  exports.estimateVLQSize = estimateVLQSize;
1004
1188
  exports.isColl = isColl;