@fleet-sdk/serializer 0.8.3 → 0.9.0
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 +18 -0
- package/dist/index.d.mts +68 -16
- package/dist/index.d.ts +68 -16
- package/dist/index.js +352 -170
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +350 -173
- 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;
|
@@ -34,6 +34,22 @@ function negateAndMask(value) {
|
|
34
34
|
const mask = (1n << BigInt(len)) - 1n;
|
35
35
|
return (~val & mask) + 1n;
|
36
36
|
}
|
37
|
+
|
38
|
+
// src/coders/numRanges.ts
|
39
|
+
var MAX_U8 = 255;
|
40
|
+
var MAX_I8 = 127;
|
41
|
+
var MIN_I16 = -32768;
|
42
|
+
var MAX_I16 = 32767;
|
43
|
+
var MIN_I32 = -2147483648;
|
44
|
+
var MAX_I32 = 2147483647;
|
45
|
+
var MIN_I64 = -BigInt("0x8000000000000000");
|
46
|
+
var MAX_I64 = BigInt("0x7fffffffffffffff");
|
47
|
+
var MIN_I256 = -BigInt(
|
48
|
+
"0x8000000000000000000000000000000000000000000000000000000000000000"
|
49
|
+
);
|
50
|
+
var MAX_I256 = BigInt(
|
51
|
+
"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
52
|
+
);
|
37
53
|
function writeVLQ(writer, value) {
|
38
54
|
if (value === 0) return writer.write(0);
|
39
55
|
if (value < 0) {
|
@@ -80,7 +96,7 @@ function readBigVLQ(reader) {
|
|
80
96
|
if (reader.isEmpty) return common._0n;
|
81
97
|
let value = common._0n;
|
82
98
|
let shift = common._0n;
|
83
|
-
let lower7bits
|
99
|
+
let lower7bits;
|
84
100
|
do {
|
85
101
|
lower7bits = BigInt(reader.readByte());
|
86
102
|
value |= (lower7bits & common._127n) << shift;
|
@@ -129,33 +145,31 @@ var zigZag64 = {
|
|
129
145
|
}
|
130
146
|
};
|
131
147
|
|
132
|
-
// src/coders/numRanges.ts
|
133
|
-
var MAX_U8 = 255;
|
134
|
-
var MAX_I8 = 127;
|
135
|
-
var MIN_I16 = -32768;
|
136
|
-
var MAX_I16 = 32767;
|
137
|
-
var MIN_I32 = -2147483648;
|
138
|
-
var MAX_I32 = 2147483647;
|
139
|
-
var MIN_I64 = -BigInt("0x8000000000000000");
|
140
|
-
var MAX_I64 = BigInt("0x7fffffffffffffff");
|
141
|
-
var MIN_I256 = -BigInt(
|
142
|
-
"0x8000000000000000000000000000000000000000000000000000000000000000"
|
143
|
-
);
|
144
|
-
var MAX_I256 = BigInt(
|
145
|
-
"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
146
|
-
);
|
147
|
-
|
148
148
|
// src/coders/sigmaByteReader.ts
|
149
149
|
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,22 @@ var SigmaByteReader = class {
|
|
199
216
|
const len = readVLQ(this);
|
200
217
|
return hexToBigInt(crypto.hex.encode(this.readBytes(len)));
|
201
218
|
}
|
219
|
+
readRemainingBytes() {
|
220
|
+
return this.readBytes(this.#bytes.length - this.#cursor);
|
221
|
+
}
|
222
|
+
/**
|
223
|
+
* Returns bytes without advancing the cursor.
|
224
|
+
*/
|
225
|
+
peek(count, offset = 0) {
|
226
|
+
const begin = this.#cursor + offset;
|
227
|
+
return this.#bytes.subarray(begin, begin + count);
|
228
|
+
}
|
229
|
+
/**
|
230
|
+
* Checks if the current position in the byte array starts with the given bytes.
|
231
|
+
*/
|
232
|
+
match(bytes, offset = 0) {
|
233
|
+
return common.startsWith(this.#bytes, bytes, this.#cursor + offset);
|
234
|
+
}
|
202
235
|
};
|
203
236
|
var SigmaByteWriter = class {
|
204
237
|
#bytes;
|
@@ -214,37 +247,37 @@ var SigmaByteWriter = class {
|
|
214
247
|
this.write(value === true ? 1 : 0);
|
215
248
|
return this;
|
216
249
|
}
|
217
|
-
|
250
|
+
writeUInt(value) {
|
218
251
|
return writeVLQ(this, value);
|
219
252
|
}
|
220
|
-
|
253
|
+
writeBigUInt(value) {
|
221
254
|
return writeBigVLQ(this, value);
|
222
255
|
}
|
223
256
|
writeI16(value) {
|
224
257
|
if (value < MIN_I16 || value > MAX_I16) {
|
225
258
|
throw new RangeError(`Value ${value} is out of range for a 16-bit integer`);
|
226
259
|
}
|
227
|
-
this.
|
260
|
+
this.writeBigUInt(zigZag32.encode(value));
|
228
261
|
return this;
|
229
262
|
}
|
230
263
|
writeI32(value) {
|
231
264
|
if (value < MIN_I32 || value > MAX_I32) {
|
232
265
|
throw new RangeError(`Value ${value} is out of range for a 32-bit integer`);
|
233
266
|
}
|
234
|
-
return this.
|
267
|
+
return this.writeBigUInt(zigZag32.encode(value));
|
235
268
|
}
|
236
269
|
writeI64(value) {
|
237
270
|
if (value < MIN_I64 || value > MAX_I64) {
|
238
271
|
throw new RangeError(`Value ${value} is out of range for a 64-bit integer`);
|
239
272
|
}
|
240
|
-
return this.
|
273
|
+
return this.writeBigUInt(zigZag64.encode(value));
|
241
274
|
}
|
242
275
|
writeI256(value) {
|
243
276
|
if (value < MIN_I256 || value > MAX_I256) {
|
244
277
|
throw new RangeError(`Value ${value} is out of range for a 256-bit integer`);
|
245
278
|
}
|
246
|
-
const
|
247
|
-
return this.
|
279
|
+
const hex8 = bigIntToHex(value);
|
280
|
+
return this.writeUInt(hex8.length / 2).writeHex(hex8);
|
248
281
|
}
|
249
282
|
write(byte) {
|
250
283
|
this.#bytes[this.#cursor++] = byte;
|
@@ -278,6 +311,23 @@ var SigmaByteWriter = class {
|
|
278
311
|
const hash = hashFn(this.toBytes());
|
279
312
|
return this.writeBytes(length ? hash.subarray(0, length) : hash);
|
280
313
|
}
|
314
|
+
/**
|
315
|
+
* Writes a length-delimited array of items to the byte stream using a provided
|
316
|
+
* serializer function.
|
317
|
+
*
|
318
|
+
* @typeParam T - The type of items in the array.
|
319
|
+
* @param items - The array of items to serialize and write.
|
320
|
+
* @param serializer - A function that serializes each item and writes it using the provided SigmaByteWriter.
|
321
|
+
* @returns The current instance of SigmaByteWriter for method chaining.
|
322
|
+
*/
|
323
|
+
writeArray(items, serializer) {
|
324
|
+
this.writeUInt(items.length);
|
325
|
+
if (items.length === 0) return this;
|
326
|
+
for (const item of items) {
|
327
|
+
serializer(this, item);
|
328
|
+
}
|
329
|
+
return this;
|
330
|
+
}
|
281
331
|
encode(coder) {
|
282
332
|
return coder.encode(this.toBytes());
|
283
333
|
}
|
@@ -399,6 +449,14 @@ var SUnitType = class extends SMonomorphicType {
|
|
399
449
|
return "SUnit";
|
400
450
|
}
|
401
451
|
};
|
452
|
+
var SBoxType = class extends SMonomorphicType {
|
453
|
+
get code() {
|
454
|
+
return 99;
|
455
|
+
}
|
456
|
+
toString() {
|
457
|
+
return "SBox";
|
458
|
+
}
|
459
|
+
};
|
402
460
|
|
403
461
|
// src/types/descriptors.ts
|
404
462
|
var constructorCode = Object.freeze({
|
@@ -441,6 +499,7 @@ var descriptors = {
|
|
441
499
|
groupElement: new SGroupElementType(),
|
442
500
|
sigmaProp: new SSigmaPropType(),
|
443
501
|
unit: new SUnitType(),
|
502
|
+
box: new SBoxType(),
|
444
503
|
coll: collDescriptor,
|
445
504
|
tuple: tupleDescriptor
|
446
505
|
};
|
@@ -521,14 +580,8 @@ var SByte = monoProxy(SByteType, descriptors.byte);
|
|
521
580
|
var SBool = monoProxy(SBoolType, descriptors.bool);
|
522
581
|
var SShort = monoProxy(SShortType, descriptors.short);
|
523
582
|
var SInt = monoProxy(SIntType, descriptors.int);
|
524
|
-
var SLong = monoProxy(
|
525
|
-
|
526
|
-
descriptors.long
|
527
|
-
);
|
528
|
-
var SBigInt = monoProxy(
|
529
|
-
SBigIntType,
|
530
|
-
descriptors.bigInt
|
531
|
-
);
|
583
|
+
var SLong = monoProxy(SLongType, descriptors.long);
|
584
|
+
var SBigInt = monoProxy(SBigIntType, descriptors.bigInt);
|
532
585
|
var SGroupElement = monoProxy(
|
533
586
|
SGroupElementType,
|
534
587
|
descriptors.groupElement
|
@@ -538,6 +591,7 @@ var SSigmaProp = monoProxy(
|
|
538
591
|
descriptors.sigmaProp
|
539
592
|
);
|
540
593
|
var SUnit = monoProxy(SUnitType, void 0, true);
|
594
|
+
var SBox = monoProxy(SBoxType, void 0, true);
|
541
595
|
var SColl = genericProxy(SCollType, (target, _, args) => {
|
542
596
|
const [type, elements] = args;
|
543
597
|
const elementsType = type();
|
@@ -554,6 +608,143 @@ var SPair = genericProxy(STupleType, (target, _, args) => {
|
|
554
608
|
}
|
555
609
|
throw new Error("Invalid tuple declaration.");
|
556
610
|
});
|
611
|
+
var MAX_UINT16_VALUE = 65535;
|
612
|
+
var FEE_CONTRACT_BYTES = crypto.hex.decode(common.FEE_CONTRACT);
|
613
|
+
var P2PK_CONTRACT_PREFIX = crypto.hex.decode("0008cd");
|
614
|
+
var COMPRESSED_PK_LENGTH = 33;
|
615
|
+
var P2PK_CONTRACT_LENGTH = P2PK_CONTRACT_PREFIX.length + COMPRESSED_PK_LENGTH;
|
616
|
+
function serializeBox(box, writer = new SigmaByteWriter(4096), distinctTokenIds) {
|
617
|
+
writer.writeBigUInt(common.ensureBigInt(box.value)).writeHex(box.ergoTree).writeUInt(box.creationHeight);
|
618
|
+
writeTokens(writer, box.assets, distinctTokenIds);
|
619
|
+
writeRegisters(writer, box.additionalRegisters);
|
620
|
+
if (common.isDefined(distinctTokenIds)) return writer;
|
621
|
+
if (!isBox(box)) throw new Error("Invalid box type.");
|
622
|
+
return writer.writeHex(box.transactionId).writeUInt(box.index);
|
623
|
+
}
|
624
|
+
function isBox(box) {
|
625
|
+
const castedBox = box;
|
626
|
+
return common.isDefined(castedBox.transactionId) && common.isDefined(castedBox.index);
|
627
|
+
}
|
628
|
+
function writeTokens(writer, tokens, tokenIds) {
|
629
|
+
if (tokenIds) {
|
630
|
+
writer.writeArray(
|
631
|
+
tokens,
|
632
|
+
(w, token) => w.writeUInt(tokenIds.indexOf(token.tokenId)).writeBigUInt(common.ensureBigInt(token.amount))
|
633
|
+
);
|
634
|
+
} else {
|
635
|
+
writer.writeArray(
|
636
|
+
tokens,
|
637
|
+
(w, token) => w.writeHex(token.tokenId).writeBigUInt(common.ensureBigInt(token.amount))
|
638
|
+
);
|
639
|
+
}
|
640
|
+
}
|
641
|
+
function writeRegisters(writer, registers) {
|
642
|
+
const keys = Object.keys(registers).sort();
|
643
|
+
const values = [];
|
644
|
+
for (const key of keys) {
|
645
|
+
const value = registers[key];
|
646
|
+
if (!value) continue;
|
647
|
+
values.push(value);
|
648
|
+
}
|
649
|
+
writer.writeArray(values, (w, value) => w.writeHex(value));
|
650
|
+
}
|
651
|
+
function estimateBoxSize(box, withValue) {
|
652
|
+
if (common.isUndefined(box.creationHeight)) {
|
653
|
+
throw new Error("Box size estimation error: creation height is undefined.");
|
654
|
+
}
|
655
|
+
let size = 0;
|
656
|
+
size += estimateVLQSize(common.isDefined(withValue) ? withValue : box.value);
|
657
|
+
size += common.byteSizeOf(box.ergoTree);
|
658
|
+
size += estimateVLQSize(box.creationHeight);
|
659
|
+
size += estimateVLQSize(box.assets.length);
|
660
|
+
for (const asset of box.assets) {
|
661
|
+
size += common.byteSizeOf(asset.tokenId) + estimateVLQSize(asset.amount);
|
662
|
+
}
|
663
|
+
let registersLength = 0;
|
664
|
+
for (const key in box.additionalRegisters) {
|
665
|
+
const register = box.additionalRegisters[key];
|
666
|
+
if (register) {
|
667
|
+
size += common.byteSizeOf(register);
|
668
|
+
registersLength++;
|
669
|
+
}
|
670
|
+
}
|
671
|
+
size += estimateVLQSize(registersLength);
|
672
|
+
size += 32;
|
673
|
+
size += estimateVLQSize(isBox(box) ? box.index : MAX_UINT16_VALUE);
|
674
|
+
return size;
|
675
|
+
}
|
676
|
+
function deserializeEmbeddedBox(reader, distinctTokenIds, transactionId, index) {
|
677
|
+
let begin = reader.cursor;
|
678
|
+
const value = reader.readBigUInt();
|
679
|
+
const ergoTree = crypto.hex.encode(readErgoTree(reader));
|
680
|
+
const creationHeight = reader.readUInt();
|
681
|
+
const boxIdWriter = new SigmaByteWriter(4096).writeBytes(reader.bytes.subarray(begin, reader.cursor));
|
682
|
+
const assets = readTokens(reader, distinctTokenIds);
|
683
|
+
boxIdWriter.writeUInt(assets.length);
|
684
|
+
for (const asset of assets) {
|
685
|
+
boxIdWriter.writeHex(asset.tokenId).writeBigUInt(asset.amount);
|
686
|
+
}
|
687
|
+
begin = reader.cursor;
|
688
|
+
const additionalRegisters = readRegisters(reader);
|
689
|
+
boxIdWriter.writeBytes(reader.bytes.subarray(begin, reader.cursor)).writeHex(transactionId).writeUInt(index);
|
690
|
+
return {
|
691
|
+
boxId: crypto.hex.encode(crypto.blake2b256(boxIdWriter.toBytes())),
|
692
|
+
value,
|
693
|
+
ergoTree,
|
694
|
+
creationHeight,
|
695
|
+
assets,
|
696
|
+
additionalRegisters,
|
697
|
+
transactionId,
|
698
|
+
index
|
699
|
+
};
|
700
|
+
}
|
701
|
+
function deserializeBox(input) {
|
702
|
+
const reader = input instanceof SigmaByteReader ? input : new SigmaByteReader(input);
|
703
|
+
const begin = reader.cursor;
|
704
|
+
const box = {
|
705
|
+
boxId: "",
|
706
|
+
// placeholder, will be calculated later
|
707
|
+
value: reader.readBigUInt(),
|
708
|
+
ergoTree: crypto.hex.encode(readErgoTree(reader)),
|
709
|
+
creationHeight: reader.readUInt(),
|
710
|
+
assets: readTokens(reader),
|
711
|
+
additionalRegisters: readRegisters(reader),
|
712
|
+
transactionId: crypto.hex.encode(reader.readBytes(32)),
|
713
|
+
index: reader.readUInt()
|
714
|
+
};
|
715
|
+
box.boxId = crypto.hex.encode(crypto.blake2b256(reader.bytes.subarray(begin, reader.cursor)));
|
716
|
+
return box;
|
717
|
+
}
|
718
|
+
function readErgoTree(reader) {
|
719
|
+
if (reader.match(FEE_CONTRACT_BYTES)) {
|
720
|
+
return reader.readBytes(FEE_CONTRACT_BYTES.length);
|
721
|
+
}
|
722
|
+
if (reader.match(P2PK_CONTRACT_PREFIX) && crypto.validateEcPoint(reader.peek(COMPRESSED_PK_LENGTH, P2PK_CONTRACT_PREFIX.length))) {
|
723
|
+
return reader.readBytes(P2PK_CONTRACT_LENGTH);
|
724
|
+
}
|
725
|
+
const header = reader.readByte();
|
726
|
+
const hasSize = (header & common.ergoTreeHeaderFlags.sizeInclusion) !== 0;
|
727
|
+
if (!hasSize) {
|
728
|
+
throw new Error("ErgoTree parsing without the size flag is not supported.");
|
729
|
+
}
|
730
|
+
const size = reader.readUInt();
|
731
|
+
return new SigmaByteWriter(1 + 4 + size).write(header).writeUInt(size).writeBytes(reader.readBytes(size)).toBytes();
|
732
|
+
}
|
733
|
+
function readTokens(reader, tokenIds) {
|
734
|
+
return reader.readArray((r) => ({
|
735
|
+
tokenId: tokenIds ? tokenIds[r.readUInt()] : crypto.hex.encode(r.readBytes(32)),
|
736
|
+
amount: r.readBigUInt()
|
737
|
+
}));
|
738
|
+
}
|
739
|
+
function readRegisters(reader) {
|
740
|
+
const registers = {};
|
741
|
+
const count = reader.readUInt();
|
742
|
+
for (let i = 0; i < count; i++) {
|
743
|
+
const value = SConstant.from(reader).toHex();
|
744
|
+
registers[`R${(i + 4).toString()}`] = value;
|
745
|
+
}
|
746
|
+
return registers;
|
747
|
+
}
|
557
748
|
|
558
749
|
// src/serializers/dataSerializer.ts
|
559
750
|
var GROUP_ELEMENT_LENGTH = 33;
|
@@ -595,7 +786,7 @@ var dataSerializer = {
|
|
595
786
|
} else {
|
596
787
|
common.assert(Array.isArray(data), `SColl expected an array, got ${typeof data}.`);
|
597
788
|
}
|
598
|
-
writer.
|
789
|
+
writer.writeUInt(data.length);
|
599
790
|
switch (type.elementsType.code) {
|
600
791
|
case descriptors.bool.code: {
|
601
792
|
return writer.writeBits(data);
|
@@ -623,9 +814,8 @@ var dataSerializer = {
|
|
623
814
|
return writer;
|
624
815
|
}
|
625
816
|
if (type.code === descriptors.unit.code) return writer;
|
626
|
-
|
627
|
-
|
628
|
-
);
|
817
|
+
if (type.code === descriptors.box.code) return serializeBox(data, writer);
|
818
|
+
throw Error(`Serialization error: '0x${type.code.toString(16)}' type not implemented.`);
|
629
819
|
},
|
630
820
|
deserialize(type, reader) {
|
631
821
|
if (type.embeddable) {
|
@@ -654,7 +844,7 @@ var dataSerializer = {
|
|
654
844
|
} else {
|
655
845
|
switch (type.code) {
|
656
846
|
case descriptors.coll.code: {
|
657
|
-
const length = reader.
|
847
|
+
const length = reader.readUInt();
|
658
848
|
const embeddedType = type.elementsType;
|
659
849
|
switch (embeddedType.code) {
|
660
850
|
case descriptors.bool.code:
|
@@ -671,12 +861,12 @@ var dataSerializer = {
|
|
671
861
|
}
|
672
862
|
}
|
673
863
|
case descriptors.tuple.code: {
|
674
|
-
return type.elementsType.map(
|
675
|
-
(t) => this.deserialize(t, reader)
|
676
|
-
);
|
864
|
+
return type.elementsType.map((t) => this.deserialize(t, reader));
|
677
865
|
}
|
678
866
|
case descriptors.unit.code:
|
679
867
|
return void 0;
|
868
|
+
case descriptors.box.code:
|
869
|
+
return deserializeBox(reader);
|
680
870
|
}
|
681
871
|
}
|
682
872
|
throw new Error(`Parsing error: '0x${type.code.toString(16)}' type not implemented.`);
|
@@ -688,15 +878,15 @@ var typeSerializer = {
|
|
688
878
|
writer.write(type.code);
|
689
879
|
} else if (type.code === descriptors.unit.code) {
|
690
880
|
writer.write(type.code);
|
881
|
+
} else if (type.code === descriptors.box.code) {
|
882
|
+
writer.write(type.code);
|
691
883
|
} else if (isColl(type)) {
|
692
884
|
if (type.elementsType.embeddable) {
|
693
885
|
writer.write(descriptors.coll.simpleCollTypeCode + type.elementsType.code);
|
694
886
|
} else if (isColl(type.elementsType)) {
|
695
887
|
const nestedColl = type.elementsType;
|
696
888
|
if (nestedColl.elementsType.embeddable) {
|
697
|
-
writer.write(
|
698
|
-
descriptors.coll.nestedCollTypeCode + nestedColl.elementsType.code
|
699
|
-
);
|
889
|
+
writer.write(descriptors.coll.nestedCollTypeCode + nestedColl.elementsType.code);
|
700
890
|
} else {
|
701
891
|
writer.write(descriptors.coll.simpleCollTypeCode);
|
702
892
|
this.serialize(nestedColl, writer);
|
@@ -735,12 +925,9 @@ var typeSerializer = {
|
|
735
925
|
break;
|
736
926
|
default: {
|
737
927
|
const len = type.elementsType.length;
|
738
|
-
common.assert(
|
739
|
-
len >= 2 && len <= 255,
|
740
|
-
"Invalid type: tuples must have between 2 and 255 items."
|
741
|
-
);
|
928
|
+
common.assert(len >= 2 && len <= 255, "Invalid type: tuples must have between 2 and 255 items.");
|
742
929
|
writer.write(descriptors.tuple.genericTupleTypeCode);
|
743
|
-
writer.
|
930
|
+
writer.writeUInt(len);
|
744
931
|
}
|
745
932
|
}
|
746
933
|
for (let i = 0; i < type.elementsType.length; i++) {
|
@@ -776,28 +963,24 @@ var typeSerializer = {
|
|
776
963
|
return new STupleType(internal);
|
777
964
|
}
|
778
965
|
case constructorCode.symmetricPair: {
|
779
|
-
const internal = embdCode === 0 ? [
|
780
|
-
this.deserialize(r),
|
781
|
-
this.deserialize(r),
|
782
|
-
this.deserialize(r),
|
783
|
-
this.deserialize(r)
|
784
|
-
] : [getPrimitiveType(embdCode), getPrimitiveType(embdCode)];
|
966
|
+
const internal = embdCode === 0 ? [this.deserialize(r), this.deserialize(r), this.deserialize(r), this.deserialize(r)] : [getPrimitiveType(embdCode), getPrimitiveType(embdCode)];
|
785
967
|
return new STupleType(internal);
|
786
968
|
}
|
787
969
|
}
|
788
970
|
}
|
789
971
|
switch (byte) {
|
790
972
|
case descriptors.tuple.genericTupleTypeCode: {
|
791
|
-
const len = r.
|
973
|
+
const len = r.readUInt();
|
792
974
|
const wrapped = new Array(len);
|
793
975
|
for (let i = 0; i < len; i++) {
|
794
976
|
wrapped[i] = this.deserialize(r);
|
795
977
|
}
|
796
978
|
return new STupleType(wrapped);
|
797
979
|
}
|
798
|
-
case descriptors.unit.code:
|
980
|
+
case descriptors.unit.code:
|
799
981
|
return descriptors.unit;
|
800
|
-
|
982
|
+
case descriptors.box.code:
|
983
|
+
return descriptors.box;
|
801
984
|
}
|
802
985
|
throw new Error("Not implemented.");
|
803
986
|
}
|
@@ -808,16 +991,22 @@ var MAX_CONSTANT_LENGTH = 4096;
|
|
808
991
|
var SConstant = class _SConstant {
|
809
992
|
#type;
|
810
993
|
#data;
|
994
|
+
#bytes;
|
811
995
|
constructor(type, data) {
|
812
996
|
this.#type = type;
|
813
997
|
this.#data = type.coerce(data);
|
814
998
|
}
|
815
999
|
static from(bytes) {
|
816
|
-
|
817
|
-
|
1000
|
+
const reader = bytes instanceof SigmaByteReader ? bytes : new SigmaByteReader(bytes);
|
1001
|
+
if (reader.isEmpty) throw new Error("Empty constant bytes.");
|
1002
|
+
const start = reader.cursor;
|
818
1003
|
const type = typeSerializer.deserialize(reader);
|
819
1004
|
const data = dataSerializer.deserialize(type, reader);
|
820
|
-
return new _SConstant(type, data);
|
1005
|
+
return new _SConstant(type, data).#withBytes(reader.bytes.slice(start, reader.cursor));
|
1006
|
+
}
|
1007
|
+
#withBytes(bytes) {
|
1008
|
+
this.#bytes = bytes;
|
1009
|
+
return this;
|
821
1010
|
}
|
822
1011
|
get type() {
|
823
1012
|
return this.#type;
|
@@ -825,16 +1014,52 @@ var SConstant = class _SConstant {
|
|
825
1014
|
get data() {
|
826
1015
|
return this.#data;
|
827
1016
|
}
|
828
|
-
|
829
|
-
|
1017
|
+
/**
|
1018
|
+
* Returns the serialized representation of the current instance as a `Uint8Array`.
|
1019
|
+
* If the bytes have already been computed and cached, returns the cached value.
|
1020
|
+
* Otherwise, serializes the instance and returns the resulting bytes.
|
1021
|
+
*/
|
1022
|
+
get bytes() {
|
1023
|
+
if (this.#bytes) return this.#bytes;
|
1024
|
+
return this.serialize();
|
1025
|
+
}
|
1026
|
+
/**
|
1027
|
+
* Serializes the current object into a `Uint8Array`.
|
1028
|
+
*/
|
1029
|
+
serialize() {
|
1030
|
+
const writer = new SigmaByteWriter(guessConstantBytesSize(this.type, this.data));
|
830
1031
|
typeSerializer.serialize(this.type, writer);
|
831
1032
|
dataSerializer.serialize(this.data, this.type, writer);
|
832
|
-
|
1033
|
+
this.#bytes = writer.toBytes();
|
1034
|
+
return this.#bytes;
|
1035
|
+
}
|
1036
|
+
/**
|
1037
|
+
* @deprecated use `serialize` instead
|
1038
|
+
*/
|
1039
|
+
toBytes() {
|
1040
|
+
return this.serialize();
|
833
1041
|
}
|
834
1042
|
toHex() {
|
835
|
-
return crypto.hex.encode(this.
|
1043
|
+
return crypto.hex.encode(this.serialize());
|
836
1044
|
}
|
837
1045
|
};
|
1046
|
+
function guessConstantBytesSize(type, data) {
|
1047
|
+
const dataSize = 1;
|
1048
|
+
if (type.code === descriptors.short.code) return dataSize + 8;
|
1049
|
+
if (type.code === descriptors.int.code) return dataSize + 16;
|
1050
|
+
if (type.code === descriptors.long.code) return dataSize + 32;
|
1051
|
+
if (type.code === descriptors.bigInt.code) return dataSize + 64;
|
1052
|
+
if (type.code === descriptors.bool.code) return dataSize + 1;
|
1053
|
+
if (type.code === descriptors.byte.code) return dataSize + 1;
|
1054
|
+
if (type.code === descriptors.unit.code) return dataSize + 0;
|
1055
|
+
if (type.code === descriptors.groupElement.code) return dataSize + 33;
|
1056
|
+
if (type.code === descriptors.sigmaProp.code) return dataSize + 35;
|
1057
|
+
if (isColl(type) && !isColl(type.elementsType) && !isTuple(type.elementsType)) {
|
1058
|
+
const len = data.length;
|
1059
|
+
return dataSize + estimateVLQSize(len) + guessConstantBytesSize(type.elementsType) * len;
|
1060
|
+
}
|
1061
|
+
return MAX_CONSTANT_LENGTH;
|
1062
|
+
}
|
838
1063
|
function decode(value) {
|
839
1064
|
if (value === void 0) return;
|
840
1065
|
try {
|
@@ -860,97 +1085,26 @@ function parse(constant, mode = "strict") {
|
|
860
1085
|
return;
|
861
1086
|
}
|
862
1087
|
}
|
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
1088
|
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;
|
1089
|
+
const tokenIds = getDistinctTokenIds(transaction.outputs);
|
1090
|
+
return new SigmaByteWriter(1e5).writeArray(transaction.inputs, (w, input) => writeInput(w, input)).writeArray(transaction.dataInputs, (w, dataInput) => w.writeHex(dataInput.boxId)).writeArray(tokenIds, (w, tokenId) => w.writeHex(tokenId)).writeArray(transaction.outputs, (w, output) => serializeBox(output, w, tokenIds));
|
944
1091
|
}
|
945
1092
|
function writeInput(writer, input) {
|
946
|
-
writer.writeHex(input.boxId);
|
947
1093
|
if (isSignedInput(input)) {
|
948
|
-
|
949
|
-
writeExtension(writer, input.spendingProof?.extension);
|
1094
|
+
writeSignedInput(writer, input);
|
950
1095
|
return;
|
951
1096
|
}
|
1097
|
+
writeUnsignedInput(writer, input);
|
1098
|
+
}
|
1099
|
+
function writeSignedInput(writer, input) {
|
1100
|
+
writer.writeHex(input.boxId);
|
1101
|
+
writeProof(writer, input.spendingProof?.proofBytes);
|
1102
|
+
writeExtension(writer, input.spendingProof?.extension);
|
1103
|
+
}
|
1104
|
+
function writeUnsignedInput(writer, input) {
|
1105
|
+
writer.writeHex(input.boxId);
|
952
1106
|
writeProof(writer, null);
|
953
|
-
writeExtension(writer, input.extension);
|
1107
|
+
writeExtension(writer, isSignedInput(input) ? input.spendingProof?.extension : input.extension);
|
954
1108
|
}
|
955
1109
|
function isSignedInput(input) {
|
956
1110
|
return input.spendingProof !== void 0;
|
@@ -961,8 +1115,7 @@ function writeProof(writer, proof) {
|
|
961
1115
|
return;
|
962
1116
|
}
|
963
1117
|
const bytes = crypto.hex.decode(proof);
|
964
|
-
writer.
|
965
|
-
writer.writeBytes(bytes);
|
1118
|
+
writer.writeUInt(bytes.length).writeBytes(bytes);
|
966
1119
|
}
|
967
1120
|
function writeExtension(writer, extension) {
|
968
1121
|
if (!extension) {
|
@@ -970,29 +1123,55 @@ function writeExtension(writer, extension) {
|
|
970
1123
|
return;
|
971
1124
|
}
|
972
1125
|
const keys = Object.keys(extension);
|
973
|
-
|
1126
|
+
const values = [];
|
974
1127
|
for (const key of keys) {
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
if (length === 0) return;
|
979
|
-
for (const key of keys) {
|
980
|
-
const val = extension[key];
|
981
|
-
if (common.isDefined(val)) {
|
982
|
-
writer.writeVLQ(Number(key)).writeHex(val);
|
983
|
-
}
|
1128
|
+
const value = extension[key];
|
1129
|
+
if (!value) continue;
|
1130
|
+
values.push([key, value]);
|
984
1131
|
}
|
1132
|
+
writer.writeArray(values, (w, [key, value]) => w.writeUInt(Number(key)).writeHex(value));
|
985
1133
|
}
|
986
1134
|
function getDistinctTokenIds(outputs) {
|
987
1135
|
const tokenIds = /* @__PURE__ */ new Set();
|
988
1136
|
outputs.flatMap((output) => output.assets.map((asset) => tokenIds.add(asset.tokenId)));
|
989
1137
|
return Array.from(tokenIds);
|
990
1138
|
}
|
1139
|
+
function deserializeTransaction(input) {
|
1140
|
+
const reader = new SigmaByteReader(input);
|
1141
|
+
const inputs = reader.readArray(readInput);
|
1142
|
+
const id = computeId(reader, inputs);
|
1143
|
+
const dataInputs = reader.readArray((r) => ({ boxId: crypto.hex.encode(r.readBytes(32)) }));
|
1144
|
+
const tokenIds = reader.readArray((r) => crypto.hex.encode(r.readBytes(32)));
|
1145
|
+
const outputs = reader.readArray((r, i) => deserializeEmbeddedBox(r, tokenIds, id, i));
|
1146
|
+
return {
|
1147
|
+
id,
|
1148
|
+
inputs,
|
1149
|
+
dataInputs,
|
1150
|
+
outputs
|
1151
|
+
};
|
1152
|
+
}
|
1153
|
+
function readInput(reader) {
|
1154
|
+
const boxId = crypto.hex.encode(reader.readBytes(32));
|
1155
|
+
const proofLength = reader.readUInt();
|
1156
|
+
const proofBytes = proofLength > 0 ? crypto.hex.encode(reader.readBytes(proofLength)) : null;
|
1157
|
+
const extensionLength = reader.readUInt();
|
1158
|
+
const extension = {};
|
1159
|
+
for (let i = 0; i < extensionLength; i++) {
|
1160
|
+
extension[reader.readUInt()] = SConstant.from(reader).toHex();
|
1161
|
+
}
|
1162
|
+
return proofBytes ? { boxId, spendingProof: { proofBytes, extension } } : { boxId, extension };
|
1163
|
+
}
|
1164
|
+
function computeId(reader, inputs) {
|
1165
|
+
const bytes = new SigmaByteWriter(reader.bytes.length).writeArray(inputs, (w, input) => writeUnsignedInput(w, input)).writeBytes(reader.bytes.subarray(reader.cursor)).toBytes();
|
1166
|
+
return crypto.hex.encode(crypto.blake2b256(bytes));
|
1167
|
+
}
|
991
1168
|
|
992
1169
|
exports.SBigInt = SBigInt;
|
993
1170
|
exports.SBigIntType = SBigIntType;
|
994
1171
|
exports.SBool = SBool;
|
995
1172
|
exports.SBoolType = SBoolType;
|
1173
|
+
exports.SBox = SBox;
|
1174
|
+
exports.SBoxType = SBoxType;
|
996
1175
|
exports.SByte = SByte;
|
997
1176
|
exports.SByteType = SByteType;
|
998
1177
|
exports.SColl = SColl;
|
@@ -1020,6 +1199,9 @@ exports.SigmaByteReader = SigmaByteReader;
|
|
1020
1199
|
exports.SigmaByteWriter = SigmaByteWriter;
|
1021
1200
|
exports.dataSerializer = dataSerializer;
|
1022
1201
|
exports.decode = decode;
|
1202
|
+
exports.deserializeBox = deserializeBox;
|
1203
|
+
exports.deserializeEmbeddedBox = deserializeEmbeddedBox;
|
1204
|
+
exports.deserializeTransaction = deserializeTransaction;
|
1023
1205
|
exports.estimateBoxSize = estimateBoxSize;
|
1024
1206
|
exports.estimateVLQSize = estimateVLQSize;
|
1025
1207
|
exports.isColl = isColl;
|