@ckb-ccc/core 1.22.0 → 2.0.0-next.1
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 +61 -1
- package/dist/advanced.d.mts +1 -1
- package/dist/advanced.mjs +1 -1
- package/{dist.commonjs/advancedBarrel-CJL3rfuW.d.ts → dist/advancedBarrel-DfFMFhdl.d.mts} +934 -567
- package/dist/advancedBarrel-DfFMFhdl.d.mts.map +1 -0
- package/dist/advancedBarrel.d.mts +1 -1
- package/dist/advancedBarrel.mjs +1 -1
- package/dist/barrel-ONYEMVg5.mjs +7 -0
- package/dist/barrel-ONYEMVg5.mjs.map +1 -0
- package/dist/barrel.d.mts +2 -2
- package/dist/barrel.mjs +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +1 -1
- package/dist/transformers-CduZ1Js5.mjs +2 -0
- package/dist/transformers-CduZ1Js5.mjs.map +1 -0
- package/dist.commonjs/advanced.d.ts +1 -1
- package/dist.commonjs/advanced.js +1 -1
- package/{dist/advancedBarrel-Daj_LJkz.d.mts → dist.commonjs/advancedBarrel-Dl0mM9JO.d.ts} +935 -566
- package/dist.commonjs/advancedBarrel-Dl0mM9JO.d.ts.map +1 -0
- package/dist.commonjs/advancedBarrel.d.ts +1 -1
- package/dist.commonjs/advancedBarrel.js +1 -1
- package/dist.commonjs/{barrel-DZkApbAR.js → barrel-HfgYMxP_.js} +10 -10
- package/dist.commonjs/barrel-HfgYMxP_.js.map +1 -0
- package/dist.commonjs/barrel.d.ts +2 -2
- package/dist.commonjs/barrel.js +1 -1
- package/dist.commonjs/index.d.ts +2 -2
- package/dist.commonjs/index.js +1 -1
- package/dist.commonjs/transformers-BUlLwiyt.js +2 -0
- package/dist.commonjs/transformers-BUlLwiyt.js.map +1 -0
- package/package.json +1 -1
- package/src/ckb/epoch.ts +44 -26
- package/src/ckb/script.ts +23 -46
- package/src/ckb/transaction.ts +192 -195
- package/src/client/client.ts +2 -2
- package/src/client/jsonRpc/client.ts +3 -7
- package/src/codec/codec.ts +65 -40
- package/src/codec/entity.ts +95 -67
- package/src/codec/predefined.ts +11 -0
- package/src/molecule/codec.ts +116 -8
- package/src/molecule/predefined.ts +1 -0
- package/src/signer/ckb/signerMultisigCkbReadonly.ts +36 -24
- package/src/signer/ckb/verifyJoyId.ts +39 -11
- package/src/signer/index.ts +17 -0
- package/src/signer/signer/index.ts +11 -0
- package/src/signer/signerFromSignature.ts +65 -0
- package/src/utils/index.ts +108 -26
- package/dist/advancedBarrel-Daj_LJkz.d.mts.map +0 -1
- package/dist/barrel-CFOWSjcM.mjs +0 -7
- package/dist/barrel-CFOWSjcM.mjs.map +0 -1
- package/dist/transformers-DAMi6ZOq.mjs +0 -2
- package/dist/transformers-DAMi6ZOq.mjs.map +0 -1
- package/dist.commonjs/advancedBarrel-CJL3rfuW.d.ts.map +0 -1
- package/dist.commonjs/barrel-DZkApbAR.js.map +0 -1
- package/dist.commonjs/transformers-C6jbFO7W.js +0 -2
- package/dist.commonjs/transformers-C6jbFO7W.js.map +0 -1
package/src/codec/codec.ts
CHANGED
|
@@ -3,12 +3,13 @@
|
|
|
3
3
|
import { Bytes, bytesFrom, BytesLike } from "../bytes/index.js";
|
|
4
4
|
|
|
5
5
|
export type CodecLike<Encodable, Decoded = Encodable> = {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
decodable:
|
|
6
|
+
encode: (encodable: Encodable) => BytesLike;
|
|
7
|
+
decode: (
|
|
8
|
+
decodable: Bytes,
|
|
9
9
|
config?: { isExtraFieldIgnored?: boolean },
|
|
10
10
|
) => Decoded;
|
|
11
|
-
|
|
11
|
+
from?: ((encoded: Encodable) => Decoded) | null;
|
|
12
|
+
byteLength?: number;
|
|
12
13
|
};
|
|
13
14
|
export class Codec<Encodable, Decoded = Encodable> {
|
|
14
15
|
constructor(
|
|
@@ -17,6 +18,7 @@ export class Codec<Encodable, Decoded = Encodable> {
|
|
|
17
18
|
decodable: BytesLike,
|
|
18
19
|
config?: { isExtraFieldIgnored?: boolean }, // This is equivalent to "compatible" in the Rust implementation of Molecule.
|
|
19
20
|
) => Decoded,
|
|
21
|
+
public readonly from: (encodable: Encodable) => Decoded,
|
|
20
22
|
public readonly byteLength?: number, // if provided, treat codec as fixed length
|
|
21
23
|
) {}
|
|
22
24
|
|
|
@@ -40,53 +42,76 @@ export class Codec<Encodable, Decoded = Encodable> {
|
|
|
40
42
|
}
|
|
41
43
|
}
|
|
42
44
|
|
|
43
|
-
static from<Encodable, Decoded = Encodable>(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
static from<Encodable, Decoded = Encodable>(
|
|
46
|
+
codecLike: CodecLike<Encodable, Decoded>,
|
|
47
|
+
): Codec<Encodable, Decoded> {
|
|
48
|
+
const newEncode = function (encodable: Encodable) {
|
|
49
|
+
const encoded = bytesFrom(codecLike.encode(encodable));
|
|
50
|
+
if (
|
|
51
|
+
codecLike.byteLength !== undefined &&
|
|
52
|
+
encoded.byteLength !== codecLike.byteLength
|
|
53
|
+
) {
|
|
54
|
+
throw new Error(
|
|
55
|
+
`Codec.encode: expected byte length ${codecLike.byteLength}, got ${encoded.byteLength}`,
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
return encoded;
|
|
59
|
+
};
|
|
60
|
+
const newDecode = function (
|
|
61
|
+
decodable: BytesLike,
|
|
62
|
+
config?: { isExtraFieldIgnored?: boolean },
|
|
63
|
+
) {
|
|
64
|
+
const decodableBytes = bytesFrom(decodable);
|
|
65
|
+
if (
|
|
66
|
+
codecLike.byteLength !== undefined &&
|
|
67
|
+
decodableBytes.byteLength !== codecLike.byteLength
|
|
68
|
+
) {
|
|
69
|
+
throw new Error(
|
|
70
|
+
`Codec.decode: expected byte length ${codecLike.byteLength}, got ${decodableBytes.byteLength}`,
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
return codecLike.decode(decodableBytes, config);
|
|
74
|
+
};
|
|
48
75
|
return new Codec(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
return encoded;
|
|
57
|
-
},
|
|
58
|
-
(decodable, config) => {
|
|
59
|
-
const decodableBytes = bytesFrom(decodable);
|
|
60
|
-
if (
|
|
61
|
-
byteLength !== undefined &&
|
|
62
|
-
decodableBytes.byteLength !== byteLength
|
|
63
|
-
) {
|
|
64
|
-
throw new Error(
|
|
65
|
-
`Codec.decode: expected byte length ${byteLength}, got ${decodableBytes.byteLength}`,
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
return decode(decodable, config);
|
|
69
|
-
},
|
|
70
|
-
byteLength,
|
|
76
|
+
newEncode,
|
|
77
|
+
newDecode,
|
|
78
|
+
codecLike.from?.bind(codecLike) ??
|
|
79
|
+
function (encodable: Encodable) {
|
|
80
|
+
return newDecode(newEncode(encodable));
|
|
81
|
+
},
|
|
82
|
+
codecLike.byteLength,
|
|
71
83
|
);
|
|
72
84
|
}
|
|
73
85
|
|
|
74
86
|
map<NewEncodable = Encodable, NewDecoded = Decoded>({
|
|
75
87
|
inMap,
|
|
76
88
|
outMap,
|
|
89
|
+
from,
|
|
77
90
|
}: {
|
|
78
91
|
inMap?: (encodable: NewEncodable) => Encodable;
|
|
79
92
|
outMap?: (decoded: Decoded) => NewDecoded;
|
|
93
|
+
from?: (encodable: NewEncodable) => NewDecoded;
|
|
80
94
|
}): Codec<NewEncodable, NewDecoded> {
|
|
81
|
-
|
|
82
|
-
(encodable) =>
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
95
|
+
const encode = inMap
|
|
96
|
+
? (encodable: NewEncodable) => this.encode(inMap(encodable))
|
|
97
|
+
: (this.encode as unknown as (encodable: NewEncodable) => Bytes);
|
|
98
|
+
const decode = outMap
|
|
99
|
+
? (buffer: BytesLike, config?: { isExtraFieldIgnored?: boolean }) =>
|
|
100
|
+
outMap(this.decode(buffer, config))
|
|
101
|
+
: (this.decode as unknown as (
|
|
102
|
+
buffer: BytesLike,
|
|
103
|
+
config?: { isExtraFieldIgnored?: boolean },
|
|
104
|
+
) => NewDecoded);
|
|
105
|
+
const newFrom =
|
|
106
|
+
from ??
|
|
107
|
+
((encodable: NewEncodable): NewDecoded => {
|
|
108
|
+
const toEncode = (inMap ? inMap(encodable) : encodable) as Encodable;
|
|
109
|
+
return (
|
|
110
|
+
outMap ? outMap(this.from(toEncode)) : this.from(toEncode)
|
|
111
|
+
) as NewDecoded;
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
return new Codec(encode, decode, newFrom, this.byteLength);
|
|
90
115
|
}
|
|
91
116
|
|
|
92
117
|
mapIn<NewEncodable>(
|
package/src/codec/entity.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { hashCkb } from "../hasher/index.js";
|
|
|
3
3
|
import { Hex, hexFrom } from "../hex/index.js";
|
|
4
4
|
import type { UnionDecoded, UnionMatchHandlers } from "../molecule/codec.js";
|
|
5
5
|
import { Constructor } from "../utils/index.js";
|
|
6
|
-
import
|
|
6
|
+
import { Codec, CodecLike, DecodedType } from "./codec.js";
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* The base class of CCC to create a serializable instance. This should be used with the {@link codec} decorator.
|
|
@@ -16,6 +16,13 @@ export abstract class Entity {
|
|
|
16
16
|
* @public
|
|
17
17
|
*/
|
|
18
18
|
static Base<SubTypeLike, SubType = SubTypeLike>() {
|
|
19
|
+
// Static methods in this class are written in function syntax not method syntax
|
|
20
|
+
// to enable strictFunctionTypes to catch more errors.
|
|
21
|
+
// This protects when the class is extended and the static methods are overridden with incompatible types.
|
|
22
|
+
// See https://www.typescriptlang.org/tsconfig/#strictFunctionTypes
|
|
23
|
+
// >> During development of this feature, we discovered a large number of inherently unsafe class hierarchies,
|
|
24
|
+
// >> including some in the DOM. Because of this, the setting only applies to functions written in function syntax,
|
|
25
|
+
// >> not to those in method syntax
|
|
19
26
|
abstract class Impl extends Entity {
|
|
20
27
|
/**
|
|
21
28
|
* The bytes length of the entity, if it is fixed, otherwise undefined
|
|
@@ -31,38 +38,34 @@ export abstract class Entity {
|
|
|
31
38
|
* @returns The encoded bytes
|
|
32
39
|
* @throws Will throw an error if the entity is not serializable
|
|
33
40
|
*/
|
|
34
|
-
static encode(_: SubTypeLike)
|
|
35
|
-
throw new Error(
|
|
36
|
-
"encode not implemented, use @ccc.codec to decorate your type",
|
|
37
|
-
);
|
|
38
|
-
}
|
|
41
|
+
static encode: (_: SubTypeLike) => Bytes;
|
|
39
42
|
/**
|
|
40
43
|
* Decode the entity from bytes
|
|
41
44
|
* @public
|
|
42
45
|
* @static
|
|
43
46
|
* @param _ - The bytes to decode
|
|
47
|
+
* @param _config - The configuration for decoding, including whether to ignore extra fields
|
|
44
48
|
* @returns The decoded entity
|
|
45
49
|
* @throws Will throw an error if the entity is not serializable
|
|
46
50
|
*/
|
|
47
|
-
static decode
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
51
|
+
static decode: (
|
|
52
|
+
_: BytesLike,
|
|
53
|
+
_config?: { isExtraFieldIgnored?: boolean },
|
|
54
|
+
) => SubType;
|
|
52
55
|
|
|
53
56
|
/**
|
|
54
57
|
* Create an entity from bytes
|
|
55
58
|
* @public
|
|
56
59
|
* @static
|
|
57
60
|
* @param _ - The bytes to create the entity from
|
|
61
|
+
* @param _config - The configuration for decoding, including whether to ignore extra fields
|
|
58
62
|
* @returns The created entity
|
|
59
63
|
* @throws Will throw an error if the entity is not serializable
|
|
60
64
|
*/
|
|
61
|
-
static fromBytes
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
65
|
+
static fromBytes: (
|
|
66
|
+
_bytes: BytesLike,
|
|
67
|
+
_config?: { isExtraFieldIgnored?: boolean },
|
|
68
|
+
) => SubType;
|
|
66
69
|
|
|
67
70
|
/**
|
|
68
71
|
* Create an entity from a serializable object
|
|
@@ -72,9 +75,7 @@ export abstract class Entity {
|
|
|
72
75
|
* @returns The created entity
|
|
73
76
|
* @throws Will throw an error if the entity is not serializable
|
|
74
77
|
*/
|
|
75
|
-
static from(_: SubTypeLike)
|
|
76
|
-
throw new Error("from not implemented");
|
|
77
|
-
}
|
|
78
|
+
static from: (_: SubTypeLike) => SubType;
|
|
78
79
|
|
|
79
80
|
/**
|
|
80
81
|
* Convert the entity to bytes
|
|
@@ -110,11 +111,9 @@ export abstract class Entity {
|
|
|
110
111
|
|
|
111
112
|
return bytesEq(
|
|
112
113
|
this.toBytes(),
|
|
113
|
-
/* eslint-disable @typescript-eslint/no-unsafe-call, @typescript-eslint/no-explicit-any */
|
|
114
114
|
(
|
|
115
|
-
(
|
|
115
|
+
(this.constructor as typeof Impl).from(other) as unknown as Impl
|
|
116
116
|
).toBytes(),
|
|
117
|
-
/* eslint-enable @typescript-eslint/no-unsafe-call, @typescript-eslint/no-explicit-any */
|
|
118
117
|
);
|
|
119
118
|
}
|
|
120
119
|
|
|
@@ -137,12 +136,6 @@ export abstract class Entity {
|
|
|
137
136
|
}
|
|
138
137
|
}
|
|
139
138
|
|
|
140
|
-
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment */
|
|
141
|
-
Impl.encode = undefined as any;
|
|
142
|
-
Impl.decode = undefined as any;
|
|
143
|
-
Impl.fromBytes = undefined as any;
|
|
144
|
-
/* eslint-enable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment */
|
|
145
|
-
|
|
146
139
|
return Impl;
|
|
147
140
|
}
|
|
148
141
|
|
|
@@ -247,57 +240,92 @@ export abstract class Entity {
|
|
|
247
240
|
* A class decorator to add methods implementation on the {@link Entity.Base} class
|
|
248
241
|
* @example
|
|
249
242
|
* ```typescript
|
|
250
|
-
*
|
|
251
|
-
* mol.
|
|
252
|
-
*
|
|
253
|
-
*
|
|
254
|
-
*
|
|
255
|
-
*
|
|
256
|
-
* )
|
|
243
|
+
* const ScriptCodec = mol.table({
|
|
244
|
+
* codeHash: mol.Byte32,
|
|
245
|
+
* hashType: HashTypeCodec,
|
|
246
|
+
* args: mol.Bytes,
|
|
247
|
+
* });
|
|
248
|
+
* export type ScriptLike = EncodableType<typeof ScriptCodec>;
|
|
249
|
+
* @codec(ScriptCodec)
|
|
257
250
|
* export class Script extends Entity.Base<ScriptLike, Script>() {
|
|
258
|
-
*
|
|
251
|
+
* public codeHash: Hex;
|
|
252
|
+
* public hashType: HashType;
|
|
253
|
+
* public args: Hex;
|
|
254
|
+
*
|
|
255
|
+
* constructor({ codeHash, hashType, args }: DecodedType<typeof ScriptCodec>) {
|
|
256
|
+
* super();
|
|
257
|
+
*
|
|
258
|
+
* this.codeHash = codeHash;
|
|
259
|
+
* this.hashType = hashType;
|
|
260
|
+
* this.args = args;
|
|
261
|
+
* }
|
|
259
262
|
* }
|
|
260
263
|
* ```
|
|
261
264
|
*/
|
|
262
|
-
export function codec<
|
|
263
|
-
Encodable,
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
encode: (encodable: Encodable) => Bytes;
|
|
268
|
-
decode: (
|
|
269
|
-
decodable: Bytes,
|
|
270
|
-
config?: { isExtraFieldIgnored?: boolean },
|
|
271
|
-
) => Decoded;
|
|
272
|
-
byteLength?: number;
|
|
273
|
-
}) {
|
|
265
|
+
export function codec<Encodable, Decoded>(
|
|
266
|
+
codecLike: CodecLike<Encodable, Decoded>,
|
|
267
|
+
) {
|
|
268
|
+
const codec = Codec.from(codecLike);
|
|
269
|
+
|
|
274
270
|
return function <
|
|
271
|
+
TypeLike extends Encodable,
|
|
275
272
|
Type extends TypeLike,
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
273
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
274
|
+
ConstructorType extends Constructor<Type, [Decoded, ...any[]]>,
|
|
275
|
+
>(
|
|
276
|
+
Constructor: ConstructorType &
|
|
277
|
+
Omit<CodecLike<TypeLike, Type>, "from"> & {
|
|
278
|
+
// Since Base.from only accepts TypeLike,
|
|
279
|
+
// passing this check actually tells us that Decoded extends TypeLike
|
|
280
|
+
from: (encodable: TypeLike | Decoded) => Type;
|
|
281
|
+
fromBytes: (bytes: BytesLike) => Type;
|
|
282
|
+
},
|
|
283
|
+
..._: unknown[]
|
|
284
|
+
): void {
|
|
285
|
+
const Base = Object.getPrototypeOf(Constructor) as Omit<
|
|
286
|
+
CodecLike<TypeLike, Type>,
|
|
287
|
+
"from"
|
|
288
|
+
> & {
|
|
289
|
+
// See above, we already know that Decoded extends TypeLike, so we can safely cast the type here.
|
|
290
|
+
from: (encodable: TypeLike) => Type;
|
|
291
|
+
fromBytes: (bytes: BytesLike) => Type;
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
Base.byteLength = codec.byteLength;
|
|
295
|
+
if (Base.encode === undefined) {
|
|
296
|
+
Base.encode = function (this: typeof Constructor, encodable: TypeLike) {
|
|
297
|
+
// Theoretically, the type allows us to codec.encode(encodable) directly.
|
|
298
|
+
// However, Constructor.from usually does more than just casting the type,
|
|
299
|
+
// so we need to call it to ensure the correct data is passed to codec.encode.
|
|
300
|
+
return codec.encode(this.from(encodable));
|
|
288
301
|
};
|
|
289
302
|
}
|
|
290
|
-
if (
|
|
291
|
-
|
|
292
|
-
|
|
303
|
+
if (Base.decode === undefined) {
|
|
304
|
+
Base.decode = function (
|
|
305
|
+
this: typeof Constructor,
|
|
306
|
+
bytesLike: BytesLike,
|
|
307
|
+
config?: { isExtraFieldIgnored?: boolean },
|
|
308
|
+
) {
|
|
309
|
+
return this.from(codec.decode(bytesFrom(bytesLike), config));
|
|
293
310
|
};
|
|
294
311
|
}
|
|
295
|
-
if (
|
|
296
|
-
|
|
297
|
-
|
|
312
|
+
if (Base.fromBytes === undefined) {
|
|
313
|
+
Base.fromBytes = function (
|
|
314
|
+
this: typeof Constructor,
|
|
315
|
+
bytes: BytesLike,
|
|
316
|
+
config?: { isExtraFieldIgnored?: boolean },
|
|
317
|
+
) {
|
|
318
|
+
return this.from(codec.decode(bytesFrom(bytes), config));
|
|
298
319
|
};
|
|
299
320
|
}
|
|
321
|
+
if (Base.from === undefined) {
|
|
322
|
+
Base.from = function (encodable: TypeLike) {
|
|
323
|
+
if (encodable instanceof Constructor) {
|
|
324
|
+
return encodable;
|
|
325
|
+
}
|
|
300
326
|
|
|
301
|
-
|
|
327
|
+
return new Constructor(codec.from(encodable));
|
|
328
|
+
};
|
|
329
|
+
}
|
|
302
330
|
};
|
|
303
331
|
}
|
package/src/codec/predefined.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
Num,
|
|
5
5
|
numBeFromBytes,
|
|
6
6
|
numBeToBytes,
|
|
7
|
+
numFrom,
|
|
7
8
|
numFromBytes,
|
|
8
9
|
NumLike,
|
|
9
10
|
numToBytes,
|
|
@@ -35,6 +36,7 @@ export function codecUint(
|
|
|
35
36
|
return numBeFromBytes(buffer);
|
|
36
37
|
}
|
|
37
38
|
},
|
|
39
|
+
from: numFrom,
|
|
38
40
|
});
|
|
39
41
|
}
|
|
40
42
|
|
|
@@ -69,17 +71,20 @@ export function codecPadding(
|
|
|
69
71
|
return new Uint8Array(byteLength);
|
|
70
72
|
},
|
|
71
73
|
decode: () => {},
|
|
74
|
+
from: () => {},
|
|
72
75
|
});
|
|
73
76
|
}
|
|
74
77
|
|
|
75
78
|
export const CodecRaw: Codec<BytesLike, Bytes> = Codec.from({
|
|
76
79
|
encode: (value) => bytesFrom(value),
|
|
77
80
|
decode: (buffer) => bytesFrom(buffer),
|
|
81
|
+
from: bytesFrom,
|
|
78
82
|
});
|
|
79
83
|
|
|
80
84
|
export const CodecBytes: Codec<HexLike, Hex> = Codec.from({
|
|
81
85
|
encode: (value) => bytesFrom(value),
|
|
82
86
|
decode: (buffer) => hexFrom(buffer),
|
|
87
|
+
from: hexFrom,
|
|
83
88
|
});
|
|
84
89
|
|
|
85
90
|
export const CodecUint8 = codecUintNumber(1, true);
|
|
@@ -112,34 +117,40 @@ export const CodecBool: Codec<boolean> = Codec.from({
|
|
|
112
117
|
byteLength: 1,
|
|
113
118
|
encode: (value) => bytesFrom(value ? [1] : [0]),
|
|
114
119
|
decode: (buffer) => bytesFrom(buffer)[0] !== 0,
|
|
120
|
+
from: Boolean,
|
|
115
121
|
});
|
|
116
122
|
|
|
117
123
|
export const CodecByte: Codec<HexLike, Hex> = Codec.from({
|
|
118
124
|
byteLength: 1,
|
|
119
125
|
encode: (value) => bytesFrom(value),
|
|
120
126
|
decode: (buffer) => hexFrom(buffer),
|
|
127
|
+
from: hexFrom,
|
|
121
128
|
});
|
|
122
129
|
|
|
123
130
|
export const CodecByte4: Codec<HexLike, Hex> = Codec.from({
|
|
124
131
|
byteLength: 4,
|
|
125
132
|
encode: (value) => bytesFrom(value),
|
|
126
133
|
decode: (buffer) => hexFrom(buffer),
|
|
134
|
+
from: hexFrom,
|
|
127
135
|
});
|
|
128
136
|
|
|
129
137
|
export const CodecByte8: Codec<HexLike, Hex> = Codec.from({
|
|
130
138
|
byteLength: 8,
|
|
131
139
|
encode: (value) => bytesFrom(value),
|
|
132
140
|
decode: (buffer) => hexFrom(buffer),
|
|
141
|
+
from: hexFrom,
|
|
133
142
|
});
|
|
134
143
|
|
|
135
144
|
export const CodecByte16: Codec<HexLike, Hex> = Codec.from({
|
|
136
145
|
byteLength: 16,
|
|
137
146
|
encode: (value) => bytesFrom(value),
|
|
138
147
|
decode: (buffer) => hexFrom(buffer),
|
|
148
|
+
from: hexFrom,
|
|
139
149
|
});
|
|
140
150
|
|
|
141
151
|
export const CodecByte32: Codec<HexLike, Hex> = Codec.from({
|
|
142
152
|
byteLength: 32,
|
|
143
153
|
encode: (value) => bytesFrom(value),
|
|
144
154
|
decode: (buffer) => hexFrom(buffer),
|
|
155
|
+
from: hexFrom,
|
|
145
156
|
});
|
package/src/molecule/codec.ts
CHANGED
|
@@ -58,8 +58,9 @@ function getMessage(e: unknown): string {
|
|
|
58
58
|
* @param itemCodec fixed-size vector item codec
|
|
59
59
|
*/
|
|
60
60
|
export function fixedItemVec<Encodable, Decoded>(
|
|
61
|
-
|
|
61
|
+
itemCodecLike: CodecLike<Encodable, Decoded>,
|
|
62
62
|
): Codec<Array<Encodable>, Array<Decoded>> {
|
|
63
|
+
const itemCodec = Codec.from(itemCodecLike);
|
|
63
64
|
const itemByteLength = itemCodec.byteLength;
|
|
64
65
|
if (itemByteLength === undefined) {
|
|
65
66
|
throw new Error("fixedItemVec: itemCodec requires a byte length");
|
|
@@ -108,6 +109,13 @@ export function fixedItemVec<Encodable, Decoded>(
|
|
|
108
109
|
throw new Error(`fixedItemVec - ${getMessage(e)}`, { cause: e });
|
|
109
110
|
}
|
|
110
111
|
},
|
|
112
|
+
from(userDefinedItems) {
|
|
113
|
+
try {
|
|
114
|
+
return userDefinedItems.map((item) => itemCodec.from(item));
|
|
115
|
+
} catch (e: unknown) {
|
|
116
|
+
throw new Error(`fixedItemVec - ${getMessage(e)}`, { cause: e });
|
|
117
|
+
}
|
|
118
|
+
},
|
|
111
119
|
});
|
|
112
120
|
}
|
|
113
121
|
|
|
@@ -116,8 +124,10 @@ export function fixedItemVec<Encodable, Decoded>(
|
|
|
116
124
|
* @param itemCodec the vector item codec. It can be fixed-size or dynamic-size.
|
|
117
125
|
*/
|
|
118
126
|
export function dynItemVec<Encodable, Decoded>(
|
|
119
|
-
|
|
127
|
+
itemCodecLike: CodecLike<Encodable, Decoded>,
|
|
120
128
|
): Codec<Array<Encodable>, Array<Decoded>> {
|
|
129
|
+
const itemCodec = Codec.from(itemCodecLike);
|
|
130
|
+
|
|
121
131
|
return Codec.from({
|
|
122
132
|
encode(userDefinedItems) {
|
|
123
133
|
try {
|
|
@@ -175,6 +185,13 @@ export function dynItemVec<Encodable, Decoded>(
|
|
|
175
185
|
throw new Error(`dynItemVec - ${getMessage(e)}`, { cause: e });
|
|
176
186
|
}
|
|
177
187
|
},
|
|
188
|
+
from(userDefinedItems) {
|
|
189
|
+
try {
|
|
190
|
+
return userDefinedItems.map((item) => itemCodec.from(item));
|
|
191
|
+
} catch (e: unknown) {
|
|
192
|
+
throw new Error(`dynItemVec - ${getMessage(e)}`, { cause: e });
|
|
193
|
+
}
|
|
194
|
+
},
|
|
178
195
|
});
|
|
179
196
|
}
|
|
180
197
|
|
|
@@ -199,8 +216,10 @@ export function vector<Encodable, Decoded>(
|
|
|
199
216
|
* @param innerCodec
|
|
200
217
|
*/
|
|
201
218
|
export function option<Encodable, Decoded>(
|
|
202
|
-
|
|
219
|
+
innerCodecLike: CodecLike<Encodable, Decoded>,
|
|
203
220
|
): Codec<Encodable | undefined | null, Decoded | undefined> {
|
|
221
|
+
const innerCodec = Codec.from(innerCodecLike);
|
|
222
|
+
|
|
204
223
|
return Codec.from({
|
|
205
224
|
encode(userDefinedOrNull) {
|
|
206
225
|
if (userDefinedOrNull == null) {
|
|
@@ -223,6 +242,16 @@ export function option<Encodable, Decoded>(
|
|
|
223
242
|
throw new Error(`option - ${getMessage(e)}`, { cause: e });
|
|
224
243
|
}
|
|
225
244
|
},
|
|
245
|
+
from(userDefinedOrNull) {
|
|
246
|
+
try {
|
|
247
|
+
if (userDefinedOrNull == null) {
|
|
248
|
+
return undefined;
|
|
249
|
+
}
|
|
250
|
+
return innerCodec.from(userDefinedOrNull);
|
|
251
|
+
} catch (e: unknown) {
|
|
252
|
+
throw new Error(`option - ${getMessage(e)}`, { cause: e });
|
|
253
|
+
}
|
|
254
|
+
},
|
|
226
255
|
});
|
|
227
256
|
}
|
|
228
257
|
|
|
@@ -231,8 +260,10 @@ export function option<Encodable, Decoded>(
|
|
|
231
260
|
* @param codec
|
|
232
261
|
*/
|
|
233
262
|
export function byteVec<Encodable, Decoded>(
|
|
234
|
-
|
|
263
|
+
codecLike: CodecLike<Encodable, Decoded>,
|
|
235
264
|
): Codec<Encodable, Decoded> {
|
|
265
|
+
const codec = Codec.from(codecLike);
|
|
266
|
+
|
|
236
267
|
return Codec.from({
|
|
237
268
|
encode(userDefined) {
|
|
238
269
|
try {
|
|
@@ -262,6 +293,13 @@ export function byteVec<Encodable, Decoded>(
|
|
|
262
293
|
throw new Error(`byteVec - ${getMessage(e)}`, { cause: e });
|
|
263
294
|
}
|
|
264
295
|
},
|
|
296
|
+
from(userDefined) {
|
|
297
|
+
try {
|
|
298
|
+
return codec.from(userDefined);
|
|
299
|
+
} catch (e: unknown) {
|
|
300
|
+
throw new Error(`byteVec - ${getMessage(e)}`, { cause: e });
|
|
301
|
+
}
|
|
302
|
+
},
|
|
265
303
|
});
|
|
266
304
|
}
|
|
267
305
|
|
|
@@ -301,7 +339,13 @@ export function table<
|
|
|
301
339
|
T extends Record<string, CodecLike<any, any>>,
|
|
302
340
|
Encodable extends EncodableRecord<T>,
|
|
303
341
|
Decoded extends DecodedRecord<T>,
|
|
304
|
-
>(
|
|
342
|
+
>(codecLayoutLike: T): Codec<Encodable, Decoded> {
|
|
343
|
+
const codecLayout = Object.fromEntries(
|
|
344
|
+
Object.entries(codecLayoutLike).map(([key, codec]) => [
|
|
345
|
+
key,
|
|
346
|
+
Codec.from(codec),
|
|
347
|
+
]),
|
|
348
|
+
);
|
|
305
349
|
const keys = Object.keys(codecLayout);
|
|
306
350
|
|
|
307
351
|
return Codec.from({
|
|
@@ -380,6 +424,18 @@ export function table<
|
|
|
380
424
|
}
|
|
381
425
|
return object as Decoded;
|
|
382
426
|
},
|
|
427
|
+
from(object) {
|
|
428
|
+
const result: any = {};
|
|
429
|
+
for (const key of keys) {
|
|
430
|
+
try {
|
|
431
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
432
|
+
result[key] = codecLayout[key].from((object as any)[key]);
|
|
433
|
+
} catch (e: unknown) {
|
|
434
|
+
throw new Error(`table.${key} - ${getMessage(e)}`, { cause: e });
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
return result as Decoded;
|
|
438
|
+
},
|
|
383
439
|
});
|
|
384
440
|
}
|
|
385
441
|
|
|
@@ -446,9 +502,15 @@ export type UnionMatchHandlers<
|
|
|
446
502
|
*/
|
|
447
503
|
|
|
448
504
|
export function union<T extends Record<string, CodecLike<any, any>>>(
|
|
449
|
-
|
|
505
|
+
codecLayoutLike: T,
|
|
450
506
|
fields?: Record<keyof T, number | undefined | null>,
|
|
451
507
|
): Codec<UnionEncodable<T> | { inner: UnionEncodable<T> }, UnionDecoded<T>> {
|
|
508
|
+
const codecLayout = Object.fromEntries(
|
|
509
|
+
Object.entries(codecLayoutLike).map(([key, codec]) => [
|
|
510
|
+
key,
|
|
511
|
+
Codec.from(codec),
|
|
512
|
+
]),
|
|
513
|
+
);
|
|
452
514
|
const entries = Object.entries(codecLayout);
|
|
453
515
|
|
|
454
516
|
// Determine if all variants have a fixed and equal byteLength.
|
|
@@ -532,6 +594,25 @@ export function union<T extends Record<string, CodecLike<any, any>>>(
|
|
|
532
594
|
value: codecLayout[field].decode(value.subarray(4), config),
|
|
533
595
|
} as UnionDecoded<T>;
|
|
534
596
|
},
|
|
597
|
+
from(encodable) {
|
|
598
|
+
const { type, value } = extract(encodable);
|
|
599
|
+
const typeStr = type.toString();
|
|
600
|
+
const codec = codecLayout[typeStr];
|
|
601
|
+
if (!codec) {
|
|
602
|
+
throw new Error(
|
|
603
|
+
`union: invalid type, expected ${entries.map((e) => e[0]).toString()}, but got ${typeStr}`,
|
|
604
|
+
);
|
|
605
|
+
}
|
|
606
|
+
try {
|
|
607
|
+
return {
|
|
608
|
+
type,
|
|
609
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
610
|
+
value: codec.from(value),
|
|
611
|
+
} as UnionDecoded<T>;
|
|
612
|
+
} catch (e: unknown) {
|
|
613
|
+
throw new Error(`union.(${typeStr}) - ${getMessage(e)}`, { cause: e });
|
|
614
|
+
}
|
|
615
|
+
},
|
|
535
616
|
});
|
|
536
617
|
}
|
|
537
618
|
|
|
@@ -544,7 +625,13 @@ export function struct<
|
|
|
544
625
|
T extends Record<string, CodecLike<any, any>>,
|
|
545
626
|
Encodable extends EncodableRecord<T>,
|
|
546
627
|
Decoded extends DecodedRecord<T>,
|
|
547
|
-
>(
|
|
628
|
+
>(codecLayoutLike: T): Codec<Encodable, Decoded> {
|
|
629
|
+
const codecLayout = Object.fromEntries(
|
|
630
|
+
Object.entries(codecLayoutLike).map(([key, codec]) => [
|
|
631
|
+
key,
|
|
632
|
+
Codec.from(codec),
|
|
633
|
+
]),
|
|
634
|
+
);
|
|
548
635
|
const codecArray = Object.values(codecLayout);
|
|
549
636
|
const keys = Object.keys(codecLayout);
|
|
550
637
|
|
|
@@ -584,6 +671,18 @@ export function struct<
|
|
|
584
671
|
});
|
|
585
672
|
return object as Decoded;
|
|
586
673
|
},
|
|
674
|
+
from(object) {
|
|
675
|
+
const result: any = {};
|
|
676
|
+
for (const key of keys) {
|
|
677
|
+
try {
|
|
678
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
679
|
+
result[key] = codecLayout[key].from((object as any)[key]);
|
|
680
|
+
} catch (e: unknown) {
|
|
681
|
+
throw new Error(`struct.${key} - ${getMessage(e)}`, { cause: e });
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
return result as Decoded;
|
|
685
|
+
},
|
|
587
686
|
});
|
|
588
687
|
}
|
|
589
688
|
|
|
@@ -594,9 +693,11 @@ export function struct<
|
|
|
594
693
|
* @param itemCount
|
|
595
694
|
*/
|
|
596
695
|
export function array<Encodable, Decoded>(
|
|
597
|
-
|
|
696
|
+
itemCodecLike: CodecLike<Encodable, Decoded>,
|
|
598
697
|
itemCount: number,
|
|
599
698
|
): Codec<Array<Encodable>, Array<Decoded>> {
|
|
699
|
+
const itemCodec = Codec.from(itemCodecLike);
|
|
700
|
+
|
|
600
701
|
if (itemCodec.byteLength === undefined) {
|
|
601
702
|
throw new Error("array: itemCodec requires a byte length");
|
|
602
703
|
}
|
|
@@ -638,5 +739,12 @@ export function array<Encodable, Decoded>(
|
|
|
638
739
|
throw new Error(`array - ${getMessage(e)}`, { cause: e });
|
|
639
740
|
}
|
|
640
741
|
},
|
|
742
|
+
from(userDefinedItems) {
|
|
743
|
+
try {
|
|
744
|
+
return userDefinedItems.map((item) => itemCodec.from(item));
|
|
745
|
+
} catch (e: unknown) {
|
|
746
|
+
throw new Error(`array - ${getMessage(e)}`, { cause: e });
|
|
747
|
+
}
|
|
748
|
+
},
|
|
641
749
|
});
|
|
642
750
|
}
|