@ckb-ccc/core 2.0.0-next.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.
Files changed (89) hide show
  1. package/CHANGELOG.md +133 -1
  2. package/README.md +3 -3
  3. package/dist/advanced.d.mts +2 -2
  4. package/dist/advanced.mjs +1 -1
  5. package/{dist.commonjs/advancedBarrel-DNdhwiU0.d.ts → dist/advancedBarrel-DfFMFhdl.d.mts} +2790 -2237
  6. package/dist/advancedBarrel-DfFMFhdl.d.mts.map +1 -0
  7. package/dist/advancedBarrel.d.mts +2 -2
  8. package/dist/advancedBarrel.mjs +1 -1
  9. package/dist/advancedBarrel.mjs.map +1 -1
  10. package/dist/barrel-ONYEMVg5.mjs +7 -0
  11. package/dist/barrel-ONYEMVg5.mjs.map +1 -0
  12. package/dist/barrel.d.mts +2 -2
  13. package/dist/barrel.mjs +1 -1
  14. package/dist/index.d.mts +2 -2
  15. package/dist/index.mjs +1 -1
  16. package/dist/transformers-CduZ1Js5.mjs +2 -0
  17. package/dist/transformers-CduZ1Js5.mjs.map +1 -0
  18. package/dist.commonjs/advanced.d.ts +2 -2
  19. package/dist.commonjs/advanced.js +1 -1
  20. package/{dist/advancedBarrel-BHwnMJqR.d.mts → dist.commonjs/advancedBarrel-Dl0mM9JO.d.ts} +2791 -2236
  21. package/dist.commonjs/advancedBarrel-Dl0mM9JO.d.ts.map +1 -0
  22. package/dist.commonjs/advancedBarrel.d.ts +2 -2
  23. package/dist.commonjs/advancedBarrel.js +1 -1
  24. package/dist.commonjs/advancedBarrel.js.map +1 -1
  25. package/dist.commonjs/barrel-HfgYMxP_.js +23 -0
  26. package/dist.commonjs/barrel-HfgYMxP_.js.map +1 -0
  27. package/dist.commonjs/barrel.d.ts +2 -2
  28. package/dist.commonjs/barrel.js +1 -1
  29. package/dist.commonjs/index.d.ts +2 -2
  30. package/dist.commonjs/index.js +1 -1
  31. package/dist.commonjs/{rolldown-runtime-DWNI8pZO.js → rolldown-runtime-Chgba0Kb.js} +1 -1
  32. package/dist.commonjs/transformers-BUlLwiyt.js +2 -0
  33. package/dist.commonjs/transformers-BUlLwiyt.js.map +1 -0
  34. package/package.json +8 -7
  35. package/src/advancedBarrel.ts +1 -0
  36. package/src/bytes/advanced.ts +1 -6
  37. package/src/bytes/index.ts +37 -10
  38. package/src/ckb/transaction.ts +7 -5
  39. package/src/client/client.ts +83 -21
  40. package/src/client/clientPublicMainnet.advanced.ts +9 -0
  41. package/src/client/clientPublicMainnet.ts +75 -36
  42. package/src/client/clientPublicTestnet.advanced.ts +9 -0
  43. package/src/client/clientPublicTestnet.ts +75 -36
  44. package/src/client/jsonRpc/client.ts +77 -30
  45. package/src/client/jsonRpc/transformers.ts +4 -4
  46. package/src/jsonRpc/index.ts +1 -0
  47. package/src/jsonRpc/requestor.ts +106 -29
  48. package/src/jsonRpc/transports/advanced.ts +0 -4
  49. package/src/jsonRpc/transports/factory.ts +12 -5
  50. package/src/jsonRpc/transports/fallback.ts +14 -6
  51. package/src/jsonRpc/transports/http.ts +19 -12
  52. package/src/jsonRpc/transports/index.ts +4 -0
  53. package/src/jsonRpc/transports/transport.ts +42 -6
  54. package/src/jsonRpc/transports/webSocket.ts +145 -40
  55. package/src/keystore/index.ts +3 -3
  56. package/src/molecule/codec.ts +20 -17
  57. package/src/signer/advanced.ts +1 -0
  58. package/src/signer/btc/psbt.ts +4 -2
  59. package/src/signer/btc/verify.ts +2 -2
  60. package/src/signer/ckb/secp256k1Signing.ts +3 -3
  61. package/src/signer/doge/signerDoge.ts +1 -1
  62. package/src/signer/doge/signerDogePrivateKey.ts +1 -1
  63. package/src/signer/index.ts +1 -0
  64. package/src/signer/jsonRpc/handler.ts +478 -0
  65. package/src/signer/jsonRpc/index.ts +2 -0
  66. package/src/signer/jsonRpc/network.ts +15 -0
  67. package/src/signer/jsonRpc/signer.ts +378 -0
  68. package/src/signer/jsonRpc/transformers.ts +71 -0
  69. package/src/signer/signer/index.ts +5 -13
  70. package/src/utils/abortSignal.ts +56 -0
  71. package/src/utils/constructor.ts +11 -0
  72. package/src/utils/index.ts +172 -5
  73. package/src/utils/owner/aggregated.ts +56 -0
  74. package/src/utils/owner/index.ts +4 -0
  75. package/src/utils/owner/owner.ts +141 -0
  76. package/src/utils/owner/refCount.ts +78 -0
  77. package/src/utils/owner/unique.ts +30 -0
  78. package/src/utils/proxy.ts +165 -0
  79. package/tsdown.config.mts +1 -0
  80. package/dist/address.advanced-LxntWbev.mjs +0 -2
  81. package/dist/address.advanced-LxntWbev.mjs.map +0 -1
  82. package/dist/advancedBarrel-BHwnMJqR.d.mts.map +0 -1
  83. package/dist/barrel-C-BaV9Pe.mjs +0 -7
  84. package/dist/barrel-C-BaV9Pe.mjs.map +0 -1
  85. package/dist.commonjs/address.advanced-BqcYOpZn.js +0 -2
  86. package/dist.commonjs/address.advanced-BqcYOpZn.js.map +0 -1
  87. package/dist.commonjs/advancedBarrel-DNdhwiU0.d.ts.map +0 -1
  88. package/dist.commonjs/barrel-BBOmj4RJ.js +0 -21
  89. package/dist.commonjs/barrel-BBOmj4RJ.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ckb-ccc/core",
3
- "version": "2.0.0-next.0",
3
+ "version": "2.0.0-next.1",
4
4
  "description": "Core of CCC - CKBer's Codebase",
5
5
  "author": "Hanssen0 <hanssen0@hanssen0.com>",
6
6
  "license": "MIT",
@@ -40,7 +40,7 @@
40
40
  "eslint-plugin-prettier": "^5.5.6",
41
41
  "prettier": "^3.8.4",
42
42
  "prettier-plugin-organize-imports": "^4.3.0",
43
- "tsdown": "0.22.12",
43
+ "tsdown": "0.23.0",
44
44
  "@typescript/native": "npm:typescript@^7.0.2",
45
45
  "typescript": "npm:@typescript/typescript6@^6.0.2",
46
46
  "typescript-eslint": "^8.61.1",
@@ -56,22 +56,23 @@
56
56
  "@noble/hashes": "^2.2.0",
57
57
  "bech32": "^2.0.0",
58
58
  "bs58check": "^4.0.0",
59
- "buffer": "^6.0.3",
60
59
  "ethers": "^6.17.0",
61
60
  "isomorphic-ws": "^5.0.0",
61
+ "uint8array-extras": "^1.5.0",
62
62
  "ws": "^8.21.0"
63
63
  },
64
64
  "types": "./dist.commonjs/index.d.ts",
65
65
  "inlinedDependencies": {
66
- "@noble/ciphers": "2.2.0",
67
- "@noble/curves": "2.2.0",
66
+ "@noble/ciphers": "2.4.0",
67
+ "@noble/curves": "2.4.0",
68
68
  "@noble/hashes": [
69
69
  "1.8.0",
70
- "2.2.0"
70
+ "2.4.0"
71
71
  ],
72
72
  "base-x": "5.0.1",
73
73
  "bs58": "6.0.0",
74
- "bs58check": "4.0.0"
74
+ "bs58check": "4.0.0",
75
+ "uint8array-extras": "1.5.0"
75
76
  },
76
77
  "scripts": {
77
78
  "test": "vitest",
@@ -4,3 +4,4 @@ export * from "./ckb/advanced.js";
4
4
  export * from "./client/advanced.js";
5
5
  export * from "./hasher/advanced.js";
6
6
  export * from "./jsonRpc/advanced.js";
7
+ export * from "./signer/advanced.js";
@@ -4,11 +4,6 @@
4
4
  */
5
5
  export type BytesFromEncoding =
6
6
  | "utf8" // UTF-8 encoding
7
- | "utf16le" // UTF-16 Little Endian encoding
8
- | "latin1" // Latin-1 (ISO-8859-1) encoding
9
7
  | "base64" // Base64 encoding
10
8
  | "base64url" // Base64 URL encoding
11
- | "hex" // Hexadecimal encoding
12
- | "ascii" // ASCII encoding
13
- | "binary" // Binary encoding
14
- | "ucs2"; // UCS-2 (alias of UTF-16LE) encoding
9
+ | "hex"; // Hexadecimal encoding
@@ -1,5 +1,12 @@
1
- import { Buffer } from "buffer/index.js";
2
- import { BytesFromEncoding } from "./advanced.js";
1
+ import {
2
+ base64ToUint8Array,
3
+ hexToUint8Array,
4
+ stringToUint8Array,
5
+ uint8ArrayToBase64,
6
+ uint8ArrayToHex,
7
+ uint8ArrayToString,
8
+ } from "uint8array-extras";
9
+ import type { BytesFromEncoding } from "./advanced.js";
3
10
 
4
11
  /**
5
12
  * @public
@@ -91,7 +98,18 @@ export function bytesConcat(...args: BytesLike[]): Bytes {
91
98
  */
92
99
 
93
100
  export function bytesTo(val: BytesLike, encoding: BytesFromEncoding): string {
94
- return Buffer.from(bytesFrom(val)).toString(encoding);
101
+ const bytes = bytesFrom(val);
102
+
103
+ switch (encoding) {
104
+ case "utf8":
105
+ return uint8ArrayToString(bytes);
106
+ case "base64":
107
+ return uint8ArrayToBase64(bytes);
108
+ case "base64url":
109
+ return uint8ArrayToBase64(bytes, { urlSafe: true });
110
+ case "hex":
111
+ return uint8ArrayToHex(bytes);
112
+ }
95
113
  }
96
114
 
97
115
  /**
@@ -133,17 +151,13 @@ export function bytesFrom(
133
151
  }
134
152
 
135
153
  if (typeof bytes === "string") {
136
- if (encoding !== undefined) {
137
- return Buffer.from(bytes, encoding);
154
+ if (encoding !== undefined && encoding !== "hex") {
155
+ return bytesFromString(bytes, encoding);
138
156
  }
139
157
 
140
158
  const str = bytes.startsWith("0x") ? bytes.slice(2) : bytes;
141
159
  const paddedStr = str.length % 2 === 0 ? str : `0${str}`;
142
- const data = Buffer.from(paddedStr, "hex");
143
- if (data.length * 2 !== paddedStr.length) {
144
- throw new Error(`Invalid bytes ${bytes}`);
145
- }
146
- return data;
160
+ return hexToUint8Array(paddedStr);
147
161
  }
148
162
 
149
163
  const bytesArr = Array.from(bytes);
@@ -153,6 +167,19 @@ export function bytesFrom(
153
167
  return new Uint8Array(bytes);
154
168
  }
155
169
 
170
+ function bytesFromString(
171
+ value: string,
172
+ encoding: Exclude<BytesFromEncoding, "hex">,
173
+ ): Bytes {
174
+ switch (encoding) {
175
+ case "utf8":
176
+ return stringToUint8Array(value);
177
+ case "base64":
178
+ case "base64url":
179
+ return base64ToUint8Array(value);
180
+ }
181
+ }
182
+
156
183
  /**
157
184
  * Compares two byte-like values for equality.
158
185
  * @public
@@ -1,11 +1,11 @@
1
1
  import { Bytes, BytesLike, bytesFrom } from "../bytes/index.js";
2
+ import type { Client } from "../client/client.js";
2
3
  import type { ClientCollectableSearchKeyFilterLike } from "../client/clientTypes.advanced.js";
3
4
  import {
4
5
  ClientBlockHeader,
5
6
  type CellDepInfoLike,
6
- type Client,
7
7
  type ClientBlockHeaderLike,
8
- } from "../client/index.js";
8
+ } from "../client/clientTypes.js";
9
9
  import { KnownScript } from "../client/knownScript.js";
10
10
  import {
11
11
  Codec,
@@ -1063,7 +1063,7 @@ export class WitnessArgs extends Entity.Base<WitnessArgsLike, WitnessArgs>() {
1063
1063
  * @public
1064
1064
  */
1065
1065
  export function udtBalanceFrom(dataLike: BytesLike): Num {
1066
- const data = bytesFrom(dataLike).slice(0, 16);
1066
+ const data = bytesFrom(dataLike).subarray(0, 16);
1067
1067
  return data.length === 0 ? Zero : numFromBytes(data);
1068
1068
  }
1069
1069
 
@@ -2269,6 +2269,7 @@ export class Transaction extends Entity.Base<TransactionLike, Transaction>() {
2269
2269
  type: ScriptLike,
2270
2270
  balanceTweak?: NumLike,
2271
2271
  ): Promise<number> {
2272
+ const scriptSize = Script.from(type).occupiedSize;
2272
2273
  const expectedBalance =
2273
2274
  this.getOutputsUdtBalance(type) + numFrom(balanceTweak ?? 0);
2274
2275
  if (expectedBalance === Zero) {
@@ -2299,6 +2300,7 @@ export class Transaction extends Entity.Base<TransactionLike, Transaction>() {
2299
2300
  from,
2300
2301
  {
2301
2302
  script: type,
2303
+ scriptLenRange: [scriptSize, scriptSize + 1],
2302
2304
  outputDataLenRange: [16, numFrom("0xffffffff")],
2303
2305
  },
2304
2306
  (acc, { outputData }, _i, collected) => {
@@ -2792,9 +2794,9 @@ export function calcDaoClaimEpoch(
2792
2794
  if (
2793
2795
  partialCycle !== Zero ||
2794
2796
  // deposit.numerator withdraw.numerator
2795
- // --------------------- <= ----------------------
2797
+ // --------------------- < -----------------------
2796
2798
  // deposit.denominator withdraw.denominator
2797
- deposit.numerator * withdraw.denominator <=
2799
+ deposit.numerator * withdraw.denominator <
2798
2800
  withdraw.numerator * deposit.denominator
2799
2801
  ) {
2800
2802
  // Need to wait for the next cycle
@@ -34,19 +34,33 @@ import {
34
34
  ErrorClientWaitTransactionTimeout,
35
35
  OutputsValidator,
36
36
  ScriptInfo,
37
+ type ScriptInfoLike,
37
38
  } from "./clientTypes.js";
38
39
  import { KnownScript } from "./knownScript.js";
39
40
 
41
+ export type ClientConfig = {
42
+ cache?: ClientCache;
43
+ scripts?: Partial<Record<KnownScript, ScriptInfoLike>>;
44
+ };
45
+
40
46
  /**
41
47
  * @public
42
48
  */
43
49
  export abstract class Client {
44
50
  public cache: ClientCache;
51
+ private readonly scripts: Partial<Record<KnownScript, ScriptInfoLike>>;
45
52
 
46
- constructor(config?: { cache?: ClientCache }) {
53
+ constructor(config?: ClientConfig) {
47
54
  this.cache = config?.cache ?? new ClientCacheMemory();
55
+ this.scripts = config?.scripts ?? {};
48
56
  }
49
57
 
58
+ /**
59
+ * The legacy primary URL associated with this Client.
60
+ *
61
+ * @deprecated A Client may use multiple endpoints or a Transport without a
62
+ * URL, so this value does not reliably identify its connection.
63
+ */
50
64
  abstract get url(): string;
51
65
  abstract get addressPrefix(): string;
52
66
 
@@ -61,7 +75,9 @@ export abstract class Client {
61
75
  * ```typescript
62
76
  * import { ccc } from "@ckb-ccc/core";
63
77
  *
64
- * const client = new ccc.ClientPublicTestnet();
78
+ * const clientOwner = ccc.ClientPublicTestnet.open();
79
+ * const client = clientOwner.value;
80
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
65
81
  *
66
82
  * // Get xUDT script deployment info
67
83
  * const xudtInfo = await client.getKnownScript(ccc.KnownScript.XUdt);
@@ -75,7 +91,15 @@ export abstract class Client {
75
91
  * );
76
92
  * ```
77
93
  */
78
- abstract getKnownScript(script: KnownScript): Promise<ScriptInfo>;
94
+ async getKnownScript(script: KnownScript): Promise<ScriptInfo> {
95
+ const found = this.scripts[script];
96
+ if (!found) {
97
+ throw new Error(
98
+ `No script information was found for ${script} on ${this.addressPrefix}`,
99
+ );
100
+ }
101
+ return ScriptInfo.from(found);
102
+ }
79
103
 
80
104
  abstract getFeeRateStatistics(
81
105
  blockRange?: NumLike,
@@ -92,7 +116,9 @@ export abstract class Client {
92
116
  * ```typescript
93
117
  * import { ccc } from "@ckb-ccc/core";
94
118
  *
95
- * const client = new ccc.ClientPublicTestnet();
119
+ * const clientOwner = ccc.ClientPublicTestnet.open();
120
+ * const client = clientOwner.value;
121
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
96
122
  * const feeRate = await client.getFeeRate();
97
123
  * console.log(`Current fee rate: ${feeRate} Shannons/KB`);
98
124
  * ```
@@ -123,7 +149,9 @@ export abstract class Client {
123
149
  * ```typescript
124
150
  * import { ccc } from "@ckb-ccc/core";
125
151
  *
126
- * const client = new ccc.ClientPublicTestnet();
152
+ * const clientOwner = ccc.ClientPublicTestnet.open();
153
+ * const client = clientOwner.value;
154
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
127
155
  * const tipBlockNumber = await client.getTip();
128
156
  * console.log(`Current block height: ${tipBlockNumber}`);
129
157
  * ```
@@ -140,7 +168,9 @@ export abstract class Client {
140
168
  * ```typescript
141
169
  * import { ccc } from "@ckb-ccc/core";
142
170
  *
143
- * const client = new ccc.ClientPublicTestnet();
171
+ * const clientOwner = ccc.ClientPublicTestnet.open();
172
+ * const client = clientOwner.value;
173
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
144
174
  * const header = await client.getTipHeader();
145
175
  * console.log(`Block #${header.number}, hash: ${header.hash}`);
146
176
  * ```
@@ -260,7 +290,9 @@ export abstract class Client {
260
290
  * ```typescript
261
291
  * import { ccc } from "@ckb-ccc/core";
262
292
  *
263
- * const client = new ccc.ClientPublicTestnet();
293
+ * const clientOwner = ccc.ClientPublicTestnet.open();
294
+ * const client = clientOwner.value;
295
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
264
296
  * const cell = await client.getCell({
265
297
  * txHash: "0xTX_HASH...",
266
298
  * index: 0,
@@ -339,7 +371,9 @@ export abstract class Client {
339
371
  * ```typescript
340
372
  * import { ccc } from "@ckb-ccc/core";
341
373
  *
342
- * const client = new ccc.ClientPublicTestnet();
374
+ * const clientOwner = ccc.ClientPublicTestnet.open();
375
+ * const client = clientOwner.value;
376
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
343
377
  * const cell = await client.getCellLive(
344
378
  * { txHash: "0xTX_HASH...", index: 0 },
345
379
  * true, // include data
@@ -388,7 +422,9 @@ export abstract class Client {
388
422
  * ```typescript
389
423
  * import { ccc } from "@ckb-ccc/core";
390
424
  *
391
- * const client = new ccc.ClientPublicTestnet();
425
+ * const clientOwner = ccc.ClientPublicTestnet.open();
426
+ * const client = clientOwner.value;
427
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
392
428
  * const { script: lock } = await ccc.Address.fromString("ckt1q...", client);
393
429
  *
394
430
  * // Get first page of cells
@@ -414,7 +450,9 @@ export abstract class Client {
414
450
  after?: string,
415
451
  ): Promise<ClientFindCellsResponse> {
416
452
  const res = await this.findCellsPagedNoCache(key, order, limit, after);
417
- await this.cache.recordCells(res.cells);
453
+ if (key.withData !== false) {
454
+ await this.cache.recordCells(res.cells);
455
+ }
418
456
  return res;
419
457
  }
420
458
 
@@ -453,7 +491,9 @@ export abstract class Client {
453
491
  * ```typescript
454
492
  * import { ccc } from "@ckb-ccc/core";
455
493
  *
456
- * const client = new ccc.ClientPublicTestnet();
494
+ * const clientOwner = ccc.ClientPublicTestnet.open();
495
+ * const client = clientOwner.value;
496
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
457
497
  * const { script: lock } = await ccc.Address.fromString("ckt1q...", client);
458
498
  *
459
499
  * // Find all cells owned by a lock script
@@ -507,7 +547,9 @@ export abstract class Client {
507
547
  * ```typescript
508
548
  * import { ccc } from "@ckb-ccc/core";
509
549
  *
510
- * const client = new ccc.ClientPublicTestnet();
550
+ * const clientOwner = ccc.ClientPublicTestnet.open();
551
+ * const client = clientOwner.value;
552
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
511
553
  * const { script: lock } = await ccc.Address.fromString("ckt1q...", client);
512
554
  *
513
555
  * // Find all cells belonging to this address
@@ -559,7 +601,9 @@ export abstract class Client {
559
601
  * ```typescript
560
602
  * import { ccc } from "@ckb-ccc/core";
561
603
  *
562
- * const client = new ccc.ClientPublicTestnet();
604
+ * const clientOwner = ccc.ClientPublicTestnet.open();
605
+ * const client = clientOwner.value;
606
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
563
607
  * // Find all xUDT cells of a specific token
564
608
  * const xudtType = await ccc.Script.fromKnownScript(
565
609
  * client, ccc.KnownScript.XUdt, "0xOWNER_LOCK_HASH...",
@@ -603,7 +647,11 @@ export abstract class Client {
603
647
 
604
648
  /**
605
649
  * Resolve cell dependency info into concrete CellDep objects.
606
- * If a CellDepInfo specifies a type script, the actual deployed cell is located on-chain.
650
+ *
651
+ * If a CellDepInfo specifies a type script, the live cell carrying it is looked up
652
+ * on-chain and, when found, its outpoint is used instead of the configured one. When
653
+ * the lookup finds nothing, the configured outpoint is used as written. A CellDepInfo
654
+ * without a type script is always used as written.
607
655
  *
608
656
  * @param cellDepsInfoLike - One or more CellDepInfo or arrays of CellDepInfo.
609
657
  * @returns Resolved CellDep array ready to be added to a transaction.
@@ -612,7 +660,9 @@ export abstract class Client {
612
660
  * ```typescript
613
661
  * import { ccc } from "@ckb-ccc/core";
614
662
  *
615
- * const client = new ccc.ClientPublicTestnet();
663
+ * const clientOwner = ccc.ClientPublicTestnet.open();
664
+ * const client = clientOwner.value;
665
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
616
666
  * const xudtInfo = await client.getKnownScript(ccc.KnownScript.XUdt);
617
667
  * const cellDeps = await client.getCellDeps(xudtInfo.cellDeps);
618
668
  * // cellDeps can be added to a transaction:
@@ -729,7 +779,9 @@ export abstract class Client {
729
779
  * ```typescript
730
780
  * import { ccc } from "@ckb-ccc/core";
731
781
  *
732
- * const client = new ccc.ClientPublicTestnet();
782
+ * const clientOwner = ccc.ClientPublicTestnet.open();
783
+ * const client = clientOwner.value;
784
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
733
785
  * const { script: lock } = await ccc.Address.fromString("ckt1q...", client);
734
786
  *
735
787
  * // List all transactions related to an address (grouped)
@@ -842,7 +894,9 @@ export abstract class Client {
842
894
  * ```typescript
843
895
  * import { ccc } from "@ckb-ccc/core";
844
896
  *
845
- * const client = new ccc.ClientPublicTestnet();
897
+ * const clientOwner = ccc.ClientPublicTestnet.open();
898
+ * const client = clientOwner.value;
899
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
846
900
  * const { script: lock } = await ccc.Address.fromString(
847
901
  * "ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq...",
848
902
  * client,
@@ -874,7 +928,9 @@ export abstract class Client {
874
928
  * ```typescript
875
929
  * import { ccc } from "@ckb-ccc/core";
876
930
  *
877
- * const client = new ccc.ClientPublicTestnet();
931
+ * const clientOwner = ccc.ClientPublicTestnet.open();
932
+ * const client = clientOwner.value;
933
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
878
934
  * const signer = new ccc.SignerCkbPrivateKey(client, "0x...");
879
935
  * await signer.connect();
880
936
  *
@@ -905,7 +961,9 @@ export abstract class Client {
905
961
  * ```typescript
906
962
  * import { ccc } from "@ckb-ccc/core";
907
963
  *
908
- * const client = new ccc.ClientPublicTestnet();
964
+ * const clientOwner = ccc.ClientPublicTestnet.open();
965
+ * const client = clientOwner.value;
966
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
909
967
  * const signer = new ccc.SignerCkbPrivateKey(client, "0x...");
910
968
  * await signer.connect();
911
969
  *
@@ -949,7 +1007,9 @@ export abstract class Client {
949
1007
  * ```typescript
950
1008
  * import { ccc } from "@ckb-ccc/core";
951
1009
  *
952
- * const client = new ccc.ClientPublicTestnet();
1010
+ * const clientOwner = ccc.ClientPublicTestnet.open();
1011
+ * const client = clientOwner.value;
1012
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
953
1013
  * const txResponse = await client.getTransaction("0xTX_HASH...");
954
1014
  * if (txResponse) {
955
1015
  * console.log(`Status: ${txResponse.status}`);
@@ -1022,7 +1082,9 @@ export abstract class Client {
1022
1082
  * ```typescript
1023
1083
  * import { ccc } from "@ckb-ccc/core";
1024
1084
  *
1025
- * const client = new ccc.ClientPublicTestnet();
1085
+ * const clientOwner = ccc.ClientPublicTestnet.open();
1086
+ * const client = clientOwner.value;
1087
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
1026
1088
  * // Wait for transaction to be committed (0 confirmations)
1027
1089
  * const tx = await client.waitTransaction("0xTX_HASH...");
1028
1090
  * console.log(`Confirmed in block: ${tx?.blockNumber}`);
@@ -1,6 +1,15 @@
1
1
  import { ScriptInfoLike } from "./clientTypes.js";
2
2
  import { KnownScript } from "./knownScript.js";
3
3
 
4
+ /**
5
+ * The known scripts, with a cell dep outpoint recorded for each.
6
+ *
7
+ * An outpoint here is a starting point. A dep with a `type` is resolved on-chain by
8
+ * {@link Client.getCellDeps} before use, so its outpoint keeps working after the code
9
+ * cell moves and may look spent when checked directly. Only a dep without a `type`
10
+ * needs updating when its cell moves. See #531.
11
+ */
12
+
4
13
  export const MAINNET_SCRIPTS: Record<KnownScript, ScriptInfoLike | undefined> =
5
14
  Object.freeze({
6
15
  [KnownScript.NervosDao]: {
@@ -1,55 +1,94 @@
1
1
  import WebSocket from "isomorphic-ws";
2
+ import { RequestorJsonRpc } from "../jsonRpc/requestor.js";
3
+ import type { ClientConfig } from "./client.js";
2
4
  import { MAINNET_SCRIPTS } from "./clientPublicMainnet.advanced.js";
3
- import { ScriptInfo, ScriptInfoLike } from "./clientTypes.js";
4
- import { ClientJsonRpc, ClientJsonRpcConfig } from "./jsonRpc/index.js";
5
- import { KnownScript } from "./knownScript.js";
5
+ import { ClientJsonRpc, type ClientJsonRpcConfig } from "./jsonRpc/client.js";
6
6
 
7
7
  /**
8
8
  * @public
9
9
  */
10
10
  export class ClientPublicMainnet extends ClientJsonRpc {
11
+ private static defaultUrls(): readonly [string, ...string[]] {
12
+ return typeof WebSocket !== "undefined"
13
+ ? [
14
+ "wss://mainnet.ckb.dev/ws",
15
+ "https://mainnet.ckb.dev/",
16
+ "https://mainnet.ckbapp.dev/",
17
+ ]
18
+ : ["https://mainnet.ckb.dev/", "https://mainnet.ckbapp.dev/"];
19
+ }
20
+
21
+ private static resolveConfig(
22
+ config?: ClientJsonRpcConfig & {
23
+ /** @deprecated URL belongs to Transport construction. */
24
+ url?: string;
25
+ },
26
+ ): ClientJsonRpcConfig & { url: string; fallbacks: string[] } {
27
+ const defaultUrls = this.defaultUrls();
28
+ return {
29
+ ...config,
30
+ url: config?.url ?? defaultUrls[0],
31
+ fallbacks: config?.fallbacks ?? [...defaultUrls],
32
+ scripts: config?.scripts ?? MAINNET_SCRIPTS,
33
+ };
34
+ }
35
+
36
+ /**
37
+ * @deprecated Use {@link ClientPublicMainnet.new} with a borrowed Transport or
38
+ * {@link ClientPublicMainnet.open} when creating Transports.
39
+ */
11
40
  constructor(
12
- private readonly config?: ClientJsonRpcConfig & {
41
+ config?: ClientJsonRpcConfig & {
42
+ /** @deprecated URL belongs to Transport construction. */
13
43
  url?: string;
14
- scripts?: Record<KnownScript, ScriptInfoLike | undefined>;
15
44
  },
16
45
  ) {
17
- const hasWebSocket = typeof WebSocket !== "undefined";
18
- super(
19
- config?.url ??
20
- (hasWebSocket
21
- ? "wss://mainnet.ckb.dev/ws"
22
- : "https://mainnet.ckb.dev/"),
23
- {
24
- ...config,
25
- fallbacks:
26
- config?.fallbacks ??
27
- (hasWebSocket
28
- ? [
29
- "wss://mainnet.ckb.dev/ws",
30
- "https://mainnet.ckb.dev/",
31
- "https://mainnet.ckbapp.dev/",
32
- ]
33
- : ["https://mainnet.ckb.dev/", "https://mainnet.ckbapp.dev/"]),
34
- },
35
- );
46
+ const resolved = ClientPublicMainnet.resolveConfig(config);
47
+ super(resolved.url, resolved);
36
48
  }
37
49
 
38
- get scripts(): Record<KnownScript, ScriptInfoLike | undefined> {
39
- return this.config?.scripts ?? MAINNET_SCRIPTS;
50
+ /** Creates a Client that borrows an existing Transport. */
51
+ static new(
52
+ config: Omit<Parameters<typeof RequestorJsonRpc.new>[0], "onError"> &
53
+ ClientConfig,
54
+ ): ClientPublicMainnet {
55
+ const { cache, scripts, ...requestorConfig } = config;
56
+ const requestor = this.newRequestor(requestorConfig);
57
+ return new ClientPublicMainnet({ cache, scripts, requestor });
40
58
  }
41
59
 
42
- get addressPrefix(): string {
43
- return "ckb";
60
+ /** Opens a Client with explicit ownership of its default dependencies. */
61
+ static open(
62
+ config?: Omit<
63
+ Parameters<typeof RequestorJsonRpc.open>[0],
64
+ "onError" | "urls"
65
+ > &
66
+ ClientConfig & {
67
+ urls?: Parameters<typeof RequestorJsonRpc.open>[0]["urls"];
68
+ },
69
+ ) {
70
+ const {
71
+ cache,
72
+ scripts,
73
+ urls = this.defaultUrls(),
74
+ ...requestorConfig
75
+ } = config ?? {};
76
+ return this.openRequestor({
77
+ ...requestorConfig,
78
+ urls,
79
+ }).map(
80
+ (requestor) =>
81
+ new ClientPublicMainnet({
82
+ cache,
83
+ scripts,
84
+ requestor,
85
+ url: urls[0],
86
+ fallbacks: [...urls.slice(1)],
87
+ }),
88
+ );
44
89
  }
45
90
 
46
- async getKnownScript(script: KnownScript): Promise<ScriptInfo> {
47
- const found = this.scripts[script];
48
- if (!found) {
49
- throw new Error(
50
- `No script information was found for ${script} on ${this.addressPrefix}`,
51
- );
52
- }
53
- return ScriptInfo.from(found);
91
+ get addressPrefix(): string {
92
+ return "ckb";
54
93
  }
55
94
  }
@@ -1,6 +1,15 @@
1
1
  import { ScriptInfoLike } from "./clientTypes.js";
2
2
  import { KnownScript } from "./knownScript.js";
3
3
 
4
+ /**
5
+ * The known scripts, with a cell dep outpoint recorded for each.
6
+ *
7
+ * An outpoint here is a starting point. A dep with a `type` is resolved on-chain by
8
+ * {@link Client.getCellDeps} before use, so its outpoint keeps working after the code
9
+ * cell moves and may look spent when checked directly. Only a dep without a `type`
10
+ * needs updating when its cell moves. See #531.
11
+ */
12
+
4
13
  export const TESTNET_SCRIPTS: Record<KnownScript, ScriptInfoLike> =
5
14
  Object.freeze({
6
15
  [KnownScript.NervosDao]: {