@ckb-ccc/core 1.22.0 → 1.23.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.
Files changed (52) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/dist/advanced.d.mts +1 -1
  3. package/dist/advanced.mjs +1 -1
  4. package/dist/{advancedBarrel-Daj_LJkz.d.mts → advancedBarrel-BBbQZ2OW.d.mts} +480 -379
  5. package/dist/advancedBarrel-BBbQZ2OW.d.mts.map +1 -0
  6. package/dist/advancedBarrel.d.mts +1 -1
  7. package/dist/advancedBarrel.mjs +1 -1
  8. package/dist/barrel-Dz1WLXRX.mjs +7 -0
  9. package/dist/barrel-Dz1WLXRX.mjs.map +1 -0
  10. package/dist/barrel.d.mts +2 -2
  11. package/dist/barrel.mjs +1 -1
  12. package/dist/index.d.mts +2 -2
  13. package/dist/index.mjs +1 -1
  14. package/dist/transformers-BHt442Nd.mjs +2 -0
  15. package/dist/transformers-BHt442Nd.mjs.map +1 -0
  16. package/dist.commonjs/advanced.d.ts +1 -1
  17. package/dist.commonjs/advanced.js +1 -1
  18. package/dist.commonjs/{advancedBarrel-CJL3rfuW.d.ts → advancedBarrel-BS4zFcFI.d.ts} +480 -379
  19. package/dist.commonjs/advancedBarrel-BS4zFcFI.d.ts.map +1 -0
  20. package/dist.commonjs/advancedBarrel.d.ts +1 -1
  21. package/dist.commonjs/advancedBarrel.js +1 -1
  22. package/dist.commonjs/{barrel-DZkApbAR.js → barrel-CZYID7jh.js} +10 -10
  23. package/dist.commonjs/barrel-CZYID7jh.js.map +1 -0
  24. package/dist.commonjs/barrel.d.ts +2 -2
  25. package/dist.commonjs/barrel.js +1 -1
  26. package/dist.commonjs/index.d.ts +2 -2
  27. package/dist.commonjs/index.js +1 -1
  28. package/dist.commonjs/transformers-CYUULrnt.js +2 -0
  29. package/dist.commonjs/transformers-CYUULrnt.js.map +1 -0
  30. package/package.json +1 -1
  31. package/src/address/index.ts +32 -4
  32. package/src/ckb/transaction.ts +79 -31
  33. package/src/client/cache/memory.advanced.ts +18 -3
  34. package/src/client/client.ts +41 -2
  35. package/src/client/clientPublicMainnet.ts +9 -2
  36. package/src/client/clientPublicTestnet.ts +9 -2
  37. package/src/client/jsonRpc/client.ts +8 -8
  38. package/src/codec/codec.ts +51 -27
  39. package/src/codec/entity.ts +26 -16
  40. package/src/fixedPoint/index.ts +17 -8
  41. package/src/jsonRpc/transports/webSocket.ts +3 -1
  42. package/src/molecule/codec.ts +437 -202
  43. package/src/utils/index.ts +3 -1
  44. package/dist/advancedBarrel-Daj_LJkz.d.mts.map +0 -1
  45. package/dist/barrel-CFOWSjcM.mjs +0 -7
  46. package/dist/barrel-CFOWSjcM.mjs.map +0 -1
  47. package/dist/transformers-DAMi6ZOq.mjs +0 -2
  48. package/dist/transformers-DAMi6ZOq.mjs.map +0 -1
  49. package/dist.commonjs/advancedBarrel-CJL3rfuW.d.ts.map +0 -1
  50. package/dist.commonjs/barrel-DZkApbAR.js.map +0 -1
  51. package/dist.commonjs/transformers-C6jbFO7W.js +0 -2
  52. package/dist.commonjs/transformers-C6jbFO7W.js.map +0 -1
@@ -2,20 +2,17 @@
2
2
 
3
3
  import { Bytes, bytesFrom, BytesLike } from "../bytes/index.js";
4
4
 
5
- export type CodecLike<Encodable, Decoded = Encodable> = {
5
+ export type CodecLike<Encodable, Decoded = Encodable, Context = any> = {
6
6
  readonly encode: (encodable: Encodable) => Bytes;
7
- readonly decode: (
8
- decodable: BytesLike,
9
- config?: { isExtraFieldIgnored?: boolean },
10
- ) => Decoded;
7
+ readonly decode: (decodable: BytesLike, context?: Context) => Decoded;
11
8
  readonly byteLength?: number;
12
9
  };
13
- export class Codec<Encodable, Decoded = Encodable> {
10
+ export class Codec<Encodable, Decoded = Encodable, Context = any> {
14
11
  constructor(
15
12
  public readonly encode: (encodable: Encodable) => Bytes,
16
13
  public readonly decode: (
17
14
  decodable: BytesLike,
18
- config?: { isExtraFieldIgnored?: boolean }, // This is equivalent to "compatible" in the Rust implementation of Molecule.
15
+ context?: Context,
19
16
  ) => Decoded,
20
17
  public readonly byteLength?: number, // if provided, treat codec as fixed length
21
18
  ) {}
@@ -28,23 +25,23 @@ export class Codec<Encodable, Decoded = Encodable> {
28
25
  }
29
26
  }
30
27
 
31
- decodeOr<T>(
32
- decodable: BytesLike,
33
- fallback: T,
34
- config?: { isExtraFieldIgnored?: boolean }, // This is equivalent to "compatible" in the Rust implementation of Molecule.
35
- ) {
28
+ decodeOr<T>(decodable: BytesLike, fallback: T, context?: Context) {
36
29
  try {
37
- return this.decode(decodable, config);
30
+ return this.decode(decodable, context);
38
31
  } catch (_) {
39
32
  return fallback;
40
33
  }
41
34
  }
42
35
 
43
- static from<Encodable, Decoded = Encodable>({
36
+ static from<Encodable, Decoded = Encodable, Context = any>({
44
37
  encode,
45
38
  decode,
46
39
  byteLength,
47
- }: CodecLike<Encodable, Decoded>): Codec<Encodable, Decoded> {
40
+ }: CodecLike<Encodable, Decoded, Context>): Codec<
41
+ Encodable,
42
+ Decoded,
43
+ Context
44
+ > {
48
45
  return new Codec(
49
46
  (encodable: Encodable) => {
50
47
  const encoded = encode(encodable);
@@ -55,7 +52,7 @@ export class Codec<Encodable, Decoded = Encodable> {
55
52
  }
56
53
  return encoded;
57
54
  },
58
- (decodable, config) => {
55
+ (decodable, context) => {
59
56
  const decodableBytes = bytesFrom(decodable);
60
57
  if (
61
58
  byteLength !== undefined &&
@@ -65,7 +62,7 @@ export class Codec<Encodable, Decoded = Encodable> {
65
62
  `Codec.decode: expected byte length ${byteLength}, got ${decodableBytes.byteLength}`,
66
63
  );
67
64
  }
68
- return decode(decodable, config);
65
+ return decode(decodable, context);
69
66
  },
70
67
  byteLength,
71
68
  );
@@ -77,32 +74,59 @@ export class Codec<Encodable, Decoded = Encodable> {
77
74
  }: {
78
75
  inMap?: (encodable: NewEncodable) => Encodable;
79
76
  outMap?: (decoded: Decoded) => NewDecoded;
80
- }): Codec<NewEncodable, NewDecoded> {
77
+ }): Codec<NewEncodable, NewDecoded, Context> {
81
78
  return new Codec(
82
79
  (encodable) =>
83
80
  this.encode((inMap ? inMap(encodable) : encodable) as Encodable),
84
- (buffer, config) =>
81
+ (buffer, context) =>
85
82
  (outMap
86
- ? outMap(this.decode(buffer, config))
87
- : this.decode(buffer, config)) as NewDecoded,
83
+ ? outMap(this.decode(buffer, context))
84
+ : this.decode(buffer, context)) as NewDecoded,
88
85
  this.byteLength,
89
86
  );
90
87
  }
91
88
 
92
89
  mapIn<NewEncodable>(
93
90
  map: (encodable: NewEncodable) => Encodable,
94
- ): Codec<NewEncodable, Decoded> {
91
+ ): Codec<NewEncodable, Decoded, Context> {
95
92
  return this.map({ inMap: map });
96
93
  }
97
94
 
98
95
  mapOut<NewDecoded>(
99
96
  map: (decoded: Decoded) => NewDecoded,
100
- ): Codec<Encodable, NewDecoded> {
97
+ ): Codec<Encodable, NewDecoded, Context> {
101
98
  return this.map({ outMap: map });
102
99
  }
103
100
  }
104
101
 
105
- export type EncodableType<T extends CodecLike<any, any>> =
106
- T extends CodecLike<infer Encodable, unknown> ? Encodable : never;
107
- export type DecodedType<T extends CodecLike<any, any>> =
108
- T extends CodecLike<any, infer Decoded> ? Decoded : never;
102
+ export type EncodableType<T extends CodecLike<any, any, any>> =
103
+ T extends CodecLike<infer Encodable, unknown, any> ? Encodable : never;
104
+ export type DecodedType<T extends CodecLike<any, any, any>> =
105
+ T extends CodecLike<any, infer Decoded, any> ? Decoded : never;
106
+
107
+ type IsAny<T> = 0 extends 1 & T ? true : false;
108
+
109
+ /**
110
+ * The context a codec specifically requires when composed with other codecs.
111
+ * Legacy `any` is normalized to `unknown`, while `Extract` preserves that the
112
+ * normalized type is assignable to the codec's original context.
113
+ */
114
+ export type ContextType<T extends CodecLike<any, any, any>> = T extends {
115
+ readonly decode: (decodable: BytesLike, context?: infer Context) => unknown;
116
+ }
117
+ ? Extract<IsAny<Context> extends true ? unknown : Context, Context>
118
+ : unknown;
119
+
120
+ /**
121
+ * The combined context required by every codec in a record.
122
+ *
123
+ * Map each child context to a function parameter before forming the union so a
124
+ * legacy `any` (normalized to `unknown` by {@link ContextType}) cannot absorb
125
+ * the other contexts. Inferring from the resulting contravariant parameter
126
+ * position converts the function union into an intersection of its contexts.
127
+ */
128
+ export type ChildContext<T extends Record<string, CodecLike<any, any, any>>> = {
129
+ [K in keyof T]: (context: ContextType<T[K]>) => void;
130
+ }[keyof T] extends (context: infer Context) => void
131
+ ? Context
132
+ : unknown;
@@ -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 type { CodecLike, DecodedType } from "./codec.js";
6
+ import type { CodecLike, ContextType, 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.
@@ -15,7 +15,12 @@ export abstract class Entity {
15
15
  * This should be used with the {@link codec} decorator.
16
16
  * @public
17
17
  */
18
- static Base<SubTypeLike, SubType = SubTypeLike>() {
18
+ static Base<
19
+ SubTypeLike,
20
+ SubType = SubTypeLike,
21
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
22
+ Context = any,
23
+ >() {
19
24
  abstract class Impl extends Entity {
20
25
  /**
21
26
  * The bytes length of the entity, if it is fixed, otherwise undefined
@@ -41,10 +46,11 @@ export abstract class Entity {
41
46
  * @public
42
47
  * @static
43
48
  * @param _ - The bytes to decode
49
+ * @param _context - Optional context passed to the codec
44
50
  * @returns The decoded entity
45
51
  * @throws Will throw an error if the entity is not serializable
46
52
  */
47
- static decode(_: BytesLike): SubType {
53
+ static decode(_: BytesLike, _context?: Context): SubType {
48
54
  throw new Error(
49
55
  "decode not implemented, use @ccc.codec to decorate your type",
50
56
  );
@@ -55,10 +61,11 @@ export abstract class Entity {
55
61
  * @public
56
62
  * @static
57
63
  * @param _ - The bytes to create the entity from
64
+ * @param _context - Optional context passed to the codec
58
65
  * @returns The created entity
59
66
  * @throws Will throw an error if the entity is not serializable
60
67
  */
61
- static fromBytes(_bytes: BytesLike): SubType {
68
+ static fromBytes(_bytes: BytesLike, _context?: Context): SubType {
62
69
  throw new Error(
63
70
  "fromBytes not implemented, use @ccc.codec to decorate your type",
64
71
  );
@@ -181,14 +188,18 @@ export abstract class Entity {
181
188
  */
182
189
  static BaseUnion<
183
190
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
184
- CodecType extends CodecLike<any, UnionDecoded<any, any>>,
191
+ CodecType extends CodecLike<any, UnionDecoded<any, any>, any>,
185
192
  SubTypeLike,
186
193
  SubType = SubTypeLike,
187
194
  >() {
188
195
  type Handlers<Result> = UnionMatchHandlers<CodecType, Result>;
189
196
  type Decoded = DecodedType<CodecType>;
190
197
 
191
- abstract class Impl extends Entity.Base<SubTypeLike, SubType>() {
198
+ abstract class Impl extends Entity.Base<
199
+ SubTypeLike,
200
+ SubType,
201
+ ContextType<CodecType>
202
+ >() {
192
203
  /**
193
204
  * The inner decoded object representing the union value.
194
205
  * @public
@@ -263,12 +274,11 @@ export function codec<
263
274
  Encodable,
264
275
  TypeLike extends Encodable,
265
276
  Decoded extends TypeLike,
277
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
278
+ Context = any,
266
279
  >(codec: {
267
280
  encode: (encodable: Encodable) => Bytes;
268
- decode: (
269
- decodable: Bytes,
270
- config?: { isExtraFieldIgnored?: boolean },
271
- ) => Decoded;
281
+ decode: (decodable: Bytes, context?: Context) => Decoded;
272
282
  byteLength?: number;
273
283
  }) {
274
284
  return function <
@@ -277,8 +287,8 @@ export function codec<
277
287
  from(decoded: TypeLike): Type;
278
288
  byteLength?: number;
279
289
  encode(encodable: TypeLike): Bytes;
280
- decode(bytesLike: BytesLike): Type;
281
- fromBytes(bytes: BytesLike): Type;
290
+ decode(bytesLike: BytesLike, context?: Context): Type;
291
+ fromBytes(bytes: BytesLike, context?: Context): Type;
282
292
  },
283
293
  >(Constructor: ConstructorType, ..._: unknown[]) {
284
294
  Constructor.byteLength = codec.byteLength;
@@ -288,13 +298,13 @@ export function codec<
288
298
  };
289
299
  }
290
300
  if (Constructor.decode === undefined) {
291
- Constructor.decode = function (bytesLike: BytesLike) {
292
- return Constructor.from(codec.decode(bytesFrom(bytesLike)));
301
+ Constructor.decode = function (bytesLike: BytesLike, context?: Context) {
302
+ return Constructor.from(codec.decode(bytesFrom(bytesLike), context));
293
303
  };
294
304
  }
295
305
  if (Constructor.fromBytes === undefined) {
296
- Constructor.fromBytes = function (bytes: BytesLike) {
297
- return Constructor.from(codec.decode(bytesFrom(bytes)));
306
+ Constructor.fromBytes = function (bytes: BytesLike, context?: Context) {
307
+ return Constructor.from(codec.decode(bytesFrom(bytes), context));
298
308
  };
299
309
  }
300
310
 
@@ -30,7 +30,11 @@ export type FixedPointLike = bigint | string | number;
30
30
  */
31
31
 
32
32
  export function fixedPointToString(val: FixedPointLike, decimals = 8): string {
33
- const str = fixedPointFrom(val).toString();
33
+ const fp = fixedPointFrom(val, decimals);
34
+ if (fp < 0n) {
35
+ return `-${fixedPointToString(-fp, decimals)}`;
36
+ }
37
+ const str = fp.toString();
34
38
  if (decimals === 0) {
35
39
  return str;
36
40
  }
@@ -65,15 +69,20 @@ export function fixedPointFrom(val: FixedPointLike, decimals = 8): FixedPoint {
65
69
  return val;
66
70
  }
67
71
 
68
- const [l, r] = (
69
- typeof val === "number" ? val.toFixed(decimals) : val.toString()
70
- ).split(".");
71
- const lVal = BigInt(l.padEnd(l.length + decimals, "0"));
72
- if (r === undefined) {
73
- return lVal;
72
+ let str = typeof val === "number" ? val.toFixed(decimals) : val.toString();
73
+ const isNegative = str.startsWith("-");
74
+ if (isNegative || str.startsWith("+")) {
75
+ str = str.slice(1);
76
+ }
77
+
78
+ const [l, r] = str.split(".");
79
+ const lVal = l === "" ? 0n : BigInt(l.padEnd(l.length + decimals, "0"));
80
+ if (r === undefined || decimals === 0) {
81
+ return isNegative ? -lVal : lVal;
74
82
  }
75
83
 
76
- return lVal + BigInt(r.slice(0, decimals).padEnd(decimals, "0"));
84
+ const unsignedVal = lVal + BigInt(r.slice(0, decimals).padEnd(decimals, "0"));
85
+ return isNegative ? -unsignedVal : unsignedVal;
77
86
  }
78
87
 
79
88
  /**
@@ -209,7 +209,9 @@ export class JsonRpcTransportWebSocket implements JsonRpcTransport {
209
209
  this.disposed = true;
210
210
  const socket = this.socket;
211
211
 
212
- if (!socket || socket.readyState === socket.CLOSED) return;
212
+ if (!socket || socket.readyState === socket.CLOSED) {
213
+ return;
214
+ }
213
215
 
214
216
  await new Promise<void>((resolve) => {
215
217
  socket.addEventListener("close", () => resolve(), { once: true });