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