@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/CHANGELOG.md +11 -0
- package/dist/index.d.mts +54 -16
- package/dist/index.d.ts +54 -16
- package/dist/index.js +285 -122
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +283 -125
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
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(
|
8
|
-
const value = BigInt(
|
9
|
-
const highByte = Number.parseInt(
|
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
|
16
|
-
if (
|
17
|
-
if (positive && 128 & Number.parseInt(
|
18
|
-
return `00${
|
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
|
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
|
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
|
-
|
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
|
-
|
247
|
+
writeUInt(value) {
|
218
248
|
return writeVLQ(this, value);
|
219
249
|
}
|
220
|
-
|
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.
|
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.
|
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.
|
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
|
247
|
-
return this.
|
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
|
};
|
@@ -538,6 +594,7 @@ var SSigmaProp = monoProxy(
|
|
538
594
|
descriptors.sigmaProp
|
539
595
|
);
|
540
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.
|
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.
|
852
|
+
const length = reader.readUInt();
|
658
853
|
const embeddedType = type.elementsType;
|
659
854
|
switch (embeddedType.code) {
|
660
855
|
case descriptors.bool.code:
|
@@ -677,6 +872,8 @@ var dataSerializer = {
|
|
677
872
|
}
|
678
873
|
case descriptors.unit.code:
|
679
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.
|
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.
|
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
|
-
|
817
|
-
|
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);
|
@@ -860,97 +1060,29 @@ 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);
|
877
|
-
}
|
878
|
-
function writeTokens(writer, tokens, tokenIds) {
|
879
|
-
if (common.isEmpty(tokens)) {
|
880
|
-
writer.write(0);
|
881
|
-
return;
|
882
|
-
}
|
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
|
-
}
|
893
|
-
}
|
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
|
-
}
|
906
|
-
}
|
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;
|
931
|
-
}
|
932
1063
|
function serializeTransaction(transaction) {
|
933
|
-
const
|
934
|
-
|
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;
|
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));
|
944
1066
|
}
|
945
1067
|
function writeInput(writer, input) {
|
946
|
-
writer.writeHex(input.boxId);
|
947
1068
|
if (isSignedInput(input)) {
|
948
|
-
|
949
|
-
writeExtension(writer, input.spendingProof?.extension);
|
1069
|
+
writeSignedInput(writer, input);
|
950
1070
|
return;
|
951
1071
|
}
|
1072
|
+
writeUnsignedInput(writer, input);
|
1073
|
+
}
|
1074
|
+
function writeSignedInput(writer, input) {
|
1075
|
+
writer.writeHex(input.boxId);
|
1076
|
+
writeProof(writer, input.spendingProof?.proofBytes);
|
1077
|
+
writeExtension(writer, input.spendingProof?.extension);
|
1078
|
+
}
|
1079
|
+
function writeUnsignedInput(writer, input) {
|
1080
|
+
writer.writeHex(input.boxId);
|
952
1081
|
writeProof(writer, null);
|
953
|
-
writeExtension(
|
1082
|
+
writeExtension(
|
1083
|
+
writer,
|
1084
|
+
isSignedInput(input) ? input.spendingProof?.extension : input.extension
|
1085
|
+
);
|
954
1086
|
}
|
955
1087
|
function isSignedInput(input) {
|
956
1088
|
return input.spendingProof !== void 0;
|
@@ -961,8 +1093,7 @@ function writeProof(writer, proof) {
|
|
961
1093
|
return;
|
962
1094
|
}
|
963
1095
|
const bytes = crypto.hex.decode(proof);
|
964
|
-
writer.
|
965
|
-
writer.writeBytes(bytes);
|
1096
|
+
writer.writeUInt(bytes.length).writeBytes(bytes);
|
966
1097
|
}
|
967
1098
|
function writeExtension(writer, extension) {
|
968
1099
|
if (!extension) {
|
@@ -970,29 +1101,58 @@ function writeExtension(writer, extension) {
|
|
970
1101
|
return;
|
971
1102
|
}
|
972
1103
|
const keys = Object.keys(extension);
|
973
|
-
|
974
|
-
for (const key of keys) {
|
975
|
-
if (common.isDefined(extension[key])) length++;
|
976
|
-
}
|
977
|
-
writer.writeVLQ(length);
|
978
|
-
if (length === 0) return;
|
1104
|
+
const values = [];
|
979
1105
|
for (const key of keys) {
|
980
|
-
const
|
981
|
-
if (
|
982
|
-
|
983
|
-
|
984
|
-
|
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
|
+
);
|
985
1114
|
}
|
986
1115
|
function getDistinctTokenIds(outputs) {
|
987
1116
|
const tokenIds = /* @__PURE__ */ new Set();
|
988
1117
|
outputs.flatMap((output) => output.assets.map((asset) => tokenIds.add(asset.tokenId)));
|
989
1118
|
return Array.from(tokenIds);
|
990
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
|
+
}
|
991
1149
|
|
992
1150
|
exports.SBigInt = SBigInt;
|
993
1151
|
exports.SBigIntType = SBigIntType;
|
994
1152
|
exports.SBool = SBool;
|
995
1153
|
exports.SBoolType = SBoolType;
|
1154
|
+
exports.SBox = SBox;
|
1155
|
+
exports.SBoxType = SBoxType;
|
996
1156
|
exports.SByte = SByte;
|
997
1157
|
exports.SByteType = SByteType;
|
998
1158
|
exports.SColl = SColl;
|
@@ -1020,6 +1180,9 @@ exports.SigmaByteReader = SigmaByteReader;
|
|
1020
1180
|
exports.SigmaByteWriter = SigmaByteWriter;
|
1021
1181
|
exports.dataSerializer = dataSerializer;
|
1022
1182
|
exports.decode = decode;
|
1183
|
+
exports.deserializeBox = deserializeBox;
|
1184
|
+
exports.deserializeEmbeddedBox = deserializeEmbeddedBox;
|
1185
|
+
exports.deserializeTransaction = deserializeTransaction;
|
1023
1186
|
exports.estimateBoxSize = estimateBoxSize;
|
1024
1187
|
exports.estimateVLQSize = estimateVLQSize;
|
1025
1188
|
exports.isColl = isColl;
|