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