@ckb-ccc/core 1.9.1 → 1.11.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 (99) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/dist/ckb/hash.d.ts +18 -0
  3. package/dist/ckb/hash.d.ts.map +1 -0
  4. package/dist/ckb/hash.js +19 -0
  5. package/dist/ckb/index.d.ts +2 -0
  6. package/dist/ckb/index.d.ts.map +1 -1
  7. package/dist/ckb/index.js +2 -0
  8. package/dist/ckb/script.d.ts +12 -0
  9. package/dist/ckb/script.d.ts.map +1 -1
  10. package/dist/ckb/script.js +17 -0
  11. package/dist/ckb/transaction.d.ts +326 -25
  12. package/dist/ckb/transaction.d.ts.map +1 -1
  13. package/dist/ckb/transaction.js +354 -79
  14. package/dist/ckb/transactionErrors.d.ts +15 -0
  15. package/dist/ckb/transactionErrors.d.ts.map +1 -0
  16. package/dist/ckb/transactionErrors.js +21 -0
  17. package/dist/client/cache/cache.d.ts +7 -0
  18. package/dist/client/cache/cache.d.ts.map +1 -1
  19. package/dist/client/cache/cache.js +11 -0
  20. package/dist/client/cache/memory.advanced.d.ts +36 -3
  21. package/dist/client/cache/memory.advanced.d.ts.map +1 -1
  22. package/dist/client/cache/memory.advanced.js +53 -25
  23. package/dist/client/cache/memory.d.ts +10 -1
  24. package/dist/client/cache/memory.d.ts.map +1 -1
  25. package/dist/client/cache/memory.js +13 -2
  26. package/dist/client/client.d.ts.map +1 -1
  27. package/dist/client/client.js +6 -9
  28. package/dist/client/clientTypes.advanced.d.ts +0 -1
  29. package/dist/client/clientTypes.advanced.d.ts.map +1 -1
  30. package/dist/client/clientTypes.advanced.js +0 -1
  31. package/dist/hasher/hasherCkb.d.ts +0 -16
  32. package/dist/hasher/hasherCkb.d.ts.map +1 -1
  33. package/dist/hasher/hasherCkb.js +0 -18
  34. package/dist/molecule/codec.d.ts +30 -10
  35. package/dist/molecule/codec.d.ts.map +1 -1
  36. package/dist/molecule/codec.js +46 -13
  37. package/dist/signer/ckb/signerCkbScriptReadonly.d.ts +18 -6
  38. package/dist/signer/ckb/signerCkbScriptReadonly.d.ts.map +1 -1
  39. package/dist/signer/ckb/signerCkbScriptReadonly.js +18 -6
  40. package/dist/signer/signer/index.d.ts +11 -1
  41. package/dist/signer/signer/index.d.ts.map +1 -1
  42. package/dist/signer/signer/index.js +23 -0
  43. package/dist.commonjs/ckb/hash.d.ts +18 -0
  44. package/dist.commonjs/ckb/hash.d.ts.map +1 -0
  45. package/dist.commonjs/ckb/hash.js +22 -0
  46. package/dist.commonjs/ckb/index.d.ts +2 -0
  47. package/dist.commonjs/ckb/index.d.ts.map +1 -1
  48. package/dist.commonjs/ckb/index.js +2 -0
  49. package/dist.commonjs/ckb/script.d.ts +12 -0
  50. package/dist.commonjs/ckb/script.d.ts.map +1 -1
  51. package/dist.commonjs/ckb/script.js +17 -0
  52. package/dist.commonjs/ckb/transaction.d.ts +326 -25
  53. package/dist.commonjs/ckb/transaction.d.ts.map +1 -1
  54. package/dist.commonjs/ckb/transaction.js +353 -78
  55. package/dist.commonjs/ckb/transactionErrors.d.ts +15 -0
  56. package/dist.commonjs/ckb/transactionErrors.d.ts.map +1 -0
  57. package/dist.commonjs/ckb/transactionErrors.js +26 -0
  58. package/dist.commonjs/client/cache/cache.d.ts +7 -0
  59. package/dist.commonjs/client/cache/cache.d.ts.map +1 -1
  60. package/dist.commonjs/client/cache/cache.js +11 -0
  61. package/dist.commonjs/client/cache/memory.advanced.d.ts +36 -3
  62. package/dist.commonjs/client/cache/memory.advanced.d.ts.map +1 -1
  63. package/dist.commonjs/client/cache/memory.advanced.js +54 -26
  64. package/dist.commonjs/client/cache/memory.d.ts +10 -1
  65. package/dist.commonjs/client/cache/memory.d.ts.map +1 -1
  66. package/dist.commonjs/client/cache/memory.js +12 -1
  67. package/dist.commonjs/client/client.d.ts.map +1 -1
  68. package/dist.commonjs/client/client.js +5 -8
  69. package/dist.commonjs/client/clientTypes.advanced.d.ts +0 -1
  70. package/dist.commonjs/client/clientTypes.advanced.d.ts.map +1 -1
  71. package/dist.commonjs/client/clientTypes.advanced.js +1 -2
  72. package/dist.commonjs/hasher/hasherCkb.d.ts +0 -16
  73. package/dist.commonjs/hasher/hasherCkb.d.ts.map +1 -1
  74. package/dist.commonjs/hasher/hasherCkb.js +2 -21
  75. package/dist.commonjs/molecule/codec.d.ts +30 -10
  76. package/dist.commonjs/molecule/codec.d.ts.map +1 -1
  77. package/dist.commonjs/molecule/codec.js +46 -13
  78. package/dist.commonjs/signer/ckb/signerCkbScriptReadonly.d.ts +18 -6
  79. package/dist.commonjs/signer/ckb/signerCkbScriptReadonly.d.ts.map +1 -1
  80. package/dist.commonjs/signer/ckb/signerCkbScriptReadonly.js +18 -6
  81. package/dist.commonjs/signer/signer/index.d.ts +11 -1
  82. package/dist.commonjs/signer/signer/index.d.ts.map +1 -1
  83. package/dist.commonjs/signer/signer/index.js +23 -0
  84. package/package.json +1 -1
  85. package/prettier.config.mjs +1 -1
  86. package/src/ckb/hash.ts +28 -0
  87. package/src/ckb/index.ts +2 -0
  88. package/src/ckb/script.ts +20 -0
  89. package/src/ckb/transaction.ts +436 -80
  90. package/src/ckb/transactionErrors.ts +36 -0
  91. package/src/client/cache/cache.ts +14 -1
  92. package/src/client/cache/memory.advanced.ts +57 -30
  93. package/src/client/cache/memory.ts +18 -1
  94. package/src/client/client.ts +5 -10
  95. package/src/client/clientTypes.advanced.ts +0 -1
  96. package/src/hasher/hasherCkb.ts +0 -26
  97. package/src/molecule/codec.ts +50 -13
  98. package/src/signer/ckb/signerCkbScriptReadonly.ts +24 -8
  99. package/src/signer/signer/index.ts +34 -0
@@ -0,0 +1,36 @@
1
+ import { fixedPointToString } from "../fixedPoint/index.js";
2
+ import { Num, numFrom, NumLike } from "../num/index.js";
3
+ import { Script, ScriptLike } from "./script.js";
4
+
5
+ export class ErrorTransactionInsufficientCapacity extends Error {
6
+ public readonly amount: Num;
7
+ public readonly isForChange: boolean;
8
+
9
+ constructor(
10
+ amountLike: NumLike,
11
+ reason?: {
12
+ isForChange?: boolean;
13
+ },
14
+ ) {
15
+ const amount = numFrom(amountLike);
16
+ const isForChange = reason?.isForChange ?? false;
17
+ super(
18
+ `Insufficient CKB, need ${fixedPointToString(amount)} extra CKB${isForChange ? " for the change cell" : ""}`,
19
+ );
20
+ this.amount = amount;
21
+ this.isForChange = isForChange;
22
+ }
23
+ }
24
+
25
+ export class ErrorTransactionInsufficientCoin extends Error {
26
+ public readonly amount: Num;
27
+ public readonly type: Script;
28
+
29
+ constructor(amountLike: NumLike, typeLike: ScriptLike) {
30
+ const amount = numFrom(amountLike);
31
+ const type = Script.from(typeLike);
32
+ super(`Insufficient coin, need ${amount} extra coin`);
33
+ this.amount = amount;
34
+ this.type = type;
35
+ }
36
+ }
@@ -6,7 +6,7 @@ import {
6
6
  TransactionLike,
7
7
  } from "../../ckb/index.js";
8
8
  import { HexLike } from "../../hex/index.js";
9
- import { NumLike } from "../../num/index.js";
9
+ import { numFrom, NumLike } from "../../num/index.js";
10
10
  import { ClientCollectableSearchKeyLike } from "../clientTypes.advanced.js";
11
11
  import {
12
12
  ClientBlock,
@@ -16,6 +16,7 @@ import {
16
16
  ClientTransactionResponse,
17
17
  ClientTransactionResponseLike,
18
18
  } from "../clientTypes.js";
19
+ import { DEFAULT_CONFIRMED_BLOCK_TIME } from "./memory.advanced.js";
19
20
 
20
21
  /**
21
22
  * @public
@@ -185,4 +186,16 @@ export abstract class ClientCache {
185
186
  async getBlockByNumber(_number: NumLike): Promise<ClientBlock | undefined> {
186
187
  return;
187
188
  }
189
+
190
+ /**
191
+ * Checks if a block header is considered confirmed.
192
+ * The default implementation compares the header's timestamp against the current time
193
+ * and a configured confirmation time. Override this method for custom confirmation logic.
194
+ * @param header
195
+ */
196
+ hasHeaderConfirmed(header: ClientBlockHeader): boolean {
197
+ return (
198
+ numFrom(Date.now()) - header.timestamp >= DEFAULT_CONFIRMED_BLOCK_TIME
199
+ );
200
+ }
188
201
  }
@@ -8,6 +8,8 @@ import {
8
8
  } from "../clientTypes.advanced.js";
9
9
  import { ClientIndexerSearchKey } from "../clientTypes.js";
10
10
 
11
+ export const DEFAULT_CONFIRMED_BLOCK_TIME = numFrom(1000 * 10 * 50); // 50 blocks * 10s
12
+
11
13
  // [isLive, Cell | OutPoint]
12
14
  export type CellRecord =
13
15
  | [
@@ -142,49 +144,74 @@ export function filterCell(
142
144
  return true;
143
145
  }
144
146
 
147
+ /**
148
+ * A Least Recently Used (LRU) cache implemented using a Map.
149
+ *
150
+ * This class extends the built-in Map to provide an LRU cache with a fixed capacity.
151
+ * When the cache is full, the least recently used entry is automatically evicted.
152
+ *
153
+ * @template K The type of the keys in the cache.
154
+ * @template V The type of the values in the cache.
155
+ */
145
156
  export class MapLru<K, V> extends Map<K, V> {
146
- private readonly lru: K[] = [];
147
-
157
+ /**
158
+ * Constructs a new MapLru instance.
159
+ *
160
+ * @param capacity The maximum number of entries the cache can hold. Must be a positive integer.
161
+ * @throws {Error} If the capacity is not a positive integer.
162
+ */
148
163
  constructor(private readonly capacity: number) {
149
164
  super();
150
- }
151
-
152
- get(key: K) {
153
- const val = super.get(key);
154
- if (val === undefined) {
155
- return;
165
+ if (!Number.isInteger(capacity) || capacity < 1) {
166
+ throw new Error("Capacity must be a positive integer");
156
167
  }
168
+ }
157
169
 
158
- const index = this.lru.indexOf(key);
159
- if (index !== -1) {
160
- this.lru.splice(index, 1);
161
- }
162
- this.lru.push(key);
163
- if (this.lru.length > this.capacity) {
164
- this.delete(this.lru[0]);
165
- this.lru.shift();
170
+ /**
171
+ * Retrieves a value from the cache.
172
+ *
173
+ * If the key is present in the cache, the value is moved to the most-recently-used position.
174
+ *
175
+ * @param key The key of the value to retrieve.
176
+ * @returns The value associated with the key, or undefined if the key is not present.
177
+ */
178
+ override get(key: K): V | undefined {
179
+ // Check if the key exists. If not, return undefined.
180
+ if (!super.has(key)) {
181
+ return undefined;
166
182
  }
167
183
 
168
- return val;
169
- }
170
-
171
- set(key: K, value: V) {
172
- this.get(key);
184
+ const value = super.get(key) as V;
173
185
 
186
+ // Move to most-recently-used position
187
+ super.delete(key);
174
188
  super.set(key, value);
175
- return this;
189
+
190
+ return value;
176
191
  }
177
192
 
178
- delete(key: K): boolean {
179
- if (!super.delete(key)) {
180
- return false;
181
- }
193
+ /**
194
+ * Inserts a new value into the cache, or updates an existing value.
195
+ *
196
+ * If the key is already present in the cache, it is first deleted so that the re-insertion
197
+ * moves it to the most-recently-used position.
198
+ * If the cache is over capacity after the insertion, the least recently used entry is evicted.
199
+ *
200
+ * @param key The key of the value to insert or update.
201
+ * @param value The value to associate with the key.
202
+ * @returns This MapLru instance.
203
+ */
204
+ override set(key: K, value: V): this {
205
+ // Delete and re-insert to move key to the end (most-recently-used)
206
+ super.delete(key);
207
+ super.set(key, value);
182
208
 
183
- const index = this.lru.indexOf(key);
184
- if (index !== -1) {
185
- this.lru.splice(index, 1);
209
+ // Evict oldest if over capacity
210
+ if (super.size > this.capacity) {
211
+ const oldestKey = super.keys().next().value!;
212
+ super.delete(oldestKey);
186
213
  }
187
214
 
188
- return true;
215
+ return this;
189
216
  }
190
217
  }
@@ -11,7 +11,12 @@ import {
11
11
  ClientTransactionResponseLike,
12
12
  } from "../clientTypes.js";
13
13
  import { ClientCache } from "./cache.js";
14
- import { CellRecord, filterCell, MapLru } from "./memory.advanced.js";
14
+ import {
15
+ CellRecord,
16
+ DEFAULT_CONFIRMED_BLOCK_TIME,
17
+ filterCell,
18
+ MapLru,
19
+ } from "./memory.advanced.js";
15
20
 
16
21
  export class ClientCacheMemory extends ClientCache {
17
22
  /**
@@ -37,10 +42,18 @@ export class ClientCacheMemory extends ClientCache {
37
42
  Pick<ClientBlock, "header"> | ClientBlock
38
43
  >;
39
44
 
45
+ /**
46
+ * @param maxCells - Maximum number of cells to store in the cache. Defaults to 512.
47
+ * @param maxTxs - Maximum number of transactions to store in the cache. Defaults to 256.
48
+ * @param maxBlocks - Maximum number of blocks to store in the cache. Defaults to 128.
49
+ * @param confirmedBlockTime - Time in milliseconds after which a block is considered confirmed.
50
+ * Defaults to DEFAULT_CONFIRMED_BLOCK_TIME (50 blocks * 10s).
51
+ */
40
52
  constructor(
41
53
  private readonly maxCells = 512,
42
54
  private readonly maxTxs = 256,
43
55
  private readonly maxBlocks = 128,
56
+ private readonly confirmedBlockTime = DEFAULT_CONFIRMED_BLOCK_TIME,
44
57
  ) {
45
58
  super();
46
59
 
@@ -216,4 +229,8 @@ export class ClientCacheMemory extends ClientCache {
216
229
  }
217
230
  return this.getBlockByHash(hash);
218
231
  }
232
+
233
+ hasHeaderConfirmed(header: ClientBlockHeader): boolean {
234
+ return numFrom(Date.now()) - header.timestamp >= this.confirmedBlockTime;
235
+ }
219
236
  }
@@ -14,7 +14,6 @@ import { reduceAsync, sleep } from "../utils/index.js";
14
14
  import { ClientCache } from "./cache/index.js";
15
15
  import { ClientCacheMemory } from "./cache/memory.js";
16
16
  import {
17
- CONFIRMED_BLOCK_TIME,
18
17
  ClientCollectableSearchKeyLike,
19
18
  DEFAULT_MAX_FEE_RATE,
20
19
  DEFAULT_MIN_FEE_RATE,
@@ -38,10 +37,6 @@ import {
38
37
  } from "./clientTypes.js";
39
38
  import { KnownScript } from "./knownScript.js";
40
39
 
41
- function hasHeaderConfirmed(header: ClientBlockHeader): boolean {
42
- return numFrom(Date.now()) - header.timestamp >= CONFIRMED_BLOCK_TIME;
43
- }
44
-
45
40
  /**
46
41
  * @public
47
42
  */
@@ -112,7 +107,7 @@ export abstract class Client {
112
107
  verbosity,
113
108
  withCycles,
114
109
  );
115
- if (res && hasHeaderConfirmed(res.header)) {
110
+ if (res && this.cache.hasHeaderConfirmed(res.header)) {
116
111
  await this.cache.recordBlocks(res);
117
112
  }
118
113
  return res;
@@ -132,7 +127,7 @@ export abstract class Client {
132
127
  verbosity,
133
128
  withCycles,
134
129
  );
135
- if (res && hasHeaderConfirmed(res.header)) {
130
+ if (res && this.cache.hasHeaderConfirmed(res.header)) {
136
131
  await this.cache.recordBlocks(res);
137
132
  }
138
133
  return res;
@@ -147,7 +142,7 @@ export abstract class Client {
147
142
  }
148
143
 
149
144
  const res = await this.getHeaderByNumberNoCache(blockNumber, verbosity);
150
- if (res && hasHeaderConfirmed(res)) {
145
+ if (res && this.cache.hasHeaderConfirmed(res)) {
151
146
  await this.cache.recordHeaders(res);
152
147
  }
153
148
  return res;
@@ -162,7 +157,7 @@ export abstract class Client {
162
157
  }
163
158
 
164
159
  const res = await this.getHeaderByHashNoCache(blockHash, verbosity);
165
- if (res && hasHeaderConfirmed(res)) {
160
+ if (res && this.cache.hasHeaderConfirmed(res)) {
166
161
  await this.cache.recordHeaders(res);
167
162
  }
168
163
  return res;
@@ -636,7 +631,7 @@ export abstract class Client {
636
631
  const tx = await this.cache.getTransactionResponse(txHash);
637
632
  if (tx?.blockHash) {
638
633
  const header = await this.getHeaderByHash(tx.blockHash);
639
- if (header && hasHeaderConfirmed(header)) {
634
+ if (header && this.cache.hasHeaderConfirmed(header)) {
640
635
  return {
641
636
  transaction: tx,
642
637
  header,
@@ -2,7 +2,6 @@ import { ScriptLike } from "../ckb/index.js";
2
2
  import { HexLike } from "../hex/index.js";
3
3
  import { Num, numFrom, NumLike } from "../num/index.js";
4
4
 
5
- export const CONFIRMED_BLOCK_TIME = numFrom(1000 * 10 * 50); // 50 blocks * 10s
6
5
  export const DEFAULT_MAX_FEE_RATE = numFrom(10000000);
7
6
  export const DEFAULT_MIN_FEE_RATE = numFrom(1000);
8
7
 
@@ -1,8 +1,6 @@
1
1
  import { blake2b } from "@noble/hashes/blake2b";
2
2
  import { BytesLike, bytesFrom } from "../bytes/index.js";
3
- import { CellInput, CellInputLike } from "../ckb/index.js";
4
3
  import { Hex, hexFrom } from "../hex/index.js";
5
- import { NumLike, numLeToBytes } from "../num/index.js";
6
4
  import { CKB_BLAKE2B_PERSONAL } from "./advanced.js";
7
5
  import { Hasher } from "./hasher.js";
8
6
 
@@ -81,27 +79,3 @@ export function hashCkb(...data: BytesLike[]): Hex {
81
79
  data.forEach((d) => hasher.update(d));
82
80
  return hasher.digest();
83
81
  }
84
-
85
- /**
86
- * Computes the Type ID hash of the given data.
87
- * @public
88
- *
89
- * @param cellInputLike - The first cell input of the transaction.
90
- * @param outputIndex - The output index of the Type ID cell.
91
- * @returns The hexadecimal string representation of the hash.
92
- *
93
- * @example
94
- * ```typescript
95
- * const hash = hashTypeId(cellInput, outputIndex); // Outputs something like "0x..."
96
- * ```
97
- */
98
-
99
- export function hashTypeId(
100
- cellInputLike: CellInputLike,
101
- outputIndex: NumLike,
102
- ): Hex {
103
- return hashCkb(
104
- CellInput.from(cellInputLike).toBytes(),
105
- numLeToBytes(outputIndex, 8),
106
- );
107
- }
@@ -459,34 +459,71 @@ type UnionDecoded<
459
459
  : never;
460
460
 
461
461
  /**
462
- * Union is a dynamic-size type.
463
- * Serializing a union has two steps:
464
- * - Serialize an item type id in bytes as a 32 bit unsigned integer in little-endian. The item type id is the index of the inner items, and it's starting at 0.
465
- * - Serialize the inner item.
466
- * @param codecLayout the union item record
467
- * @param fields the custom item type id record
462
+ * Constructs a union codec that can serialize and deserialize values tagged with a type identifier.
463
+ *
464
+ * If all variants have the same fixed size, the resulting union codec is fixed-size (header + payload).
465
+ * Otherwise, it falls back to a dynamic-size codec.
466
+ *
467
+ * Serialization format:
468
+ * 1. 4-byte little-endian unsigned integer for the variant index.
469
+ * 2. Encoded bytes of the selected variant.
470
+ *
471
+ * @typeParam T
472
+ * A record mapping variant names to codecs.
473
+ * @param codecLayout
474
+ * An object whose keys are variant names and values are codecs for each variant.
475
+ * @param fields
476
+ * Optional mapping from variant names to custom numeric IDs. If omitted, the index
477
+ * of each variant in `codecLayout` is used as its ID.
478
+ *
479
+ *
468
480
  * @example
469
- * // without custom id
470
- * union({ cafe: Uint8, bee: Uint8 })
471
- * // with custom id
472
- * union({ cafe: Uint8, bee: Uint8 }, { cafe: 0xcafe, bee: 0xbee })
481
+ * // Dynamic union without custom numeric IDs
482
+ * union({ cafe: Uint8, bee: Uint16 })
483
+ *
484
+ * // Dynamic union with custom numeric IDs
485
+ * union({ cafe: Uint8, bee: Uint16 }, { cafe: 0xcafe, bee: 0xbee })
486
+ *
487
+ * // Fixed-size union without custom numeric IDs
488
+ * const PaddedUint8 = struct({ data : u8, padding : u8 })
489
+ * union({ cafe: PaddedUint8, bee: Uint16 });
490
+ *
491
+ * // Fixed-size union with custom numeric IDs
492
+ * union({ cafe: PaddedUint8, bee: Uint16 }, { cafe: 0xcafe, bee: 0xbee })
473
493
  */
494
+
474
495
  export function union<T extends Record<string, CodecLike<any, any>>>(
475
496
  codecLayout: T,
476
497
  fields?: Record<keyof T, number | undefined | null>,
477
498
  ): Codec<UnionEncodable<T>, UnionDecoded<T>> {
478
- const keys = Object.keys(codecLayout);
499
+ const entries = Object.entries(codecLayout);
500
+
501
+ // Determine if all variants have a fixed and equal byteLength.
502
+ let byteLength: number | undefined;
503
+ if (entries.length > 0) {
504
+ const firstLen = entries[0][1].byteLength;
505
+ if (
506
+ firstLen !== undefined &&
507
+ entries.every(([, { byteLength: len }]) => len === firstLen)
508
+ ) {
509
+ // Add 4 bytes for the type header
510
+ byteLength = firstLen + 4;
511
+ }
512
+ }
479
513
 
480
514
  return Codec.from({
515
+ byteLength,
481
516
  encode({ type, value }) {
482
517
  const typeStr = type.toString();
483
518
  const codec = codecLayout[typeStr];
484
519
  if (!codec) {
485
520
  throw new Error(
486
- `union: invalid type, expected ${keys.toString()}, but got ${typeStr}`,
521
+ `union: invalid type, expected ${entries.map((e) => e[0]).toString()}, but got ${typeStr}`,
487
522
  );
488
523
  }
489
- const fieldId = fields ? (fields[typeStr] ?? -1) : keys.indexOf(typeStr);
524
+ const fieldId = fields
525
+ ? (fields[typeStr] ?? -1)
526
+ : entries.findIndex((e) => e[0] === typeStr);
490
527
  if (fieldId < 0) {
491
528
  throw new Error(`union: invalid field id ${fieldId} of ${typeStr}`);
492
529
  }
@@ -4,31 +4,46 @@ import { Client } from "../../client/index.js";
4
4
  import { Signer, SignerSignType, SignerType } from "../signer/index.js";
5
5
 
6
6
  /**
7
- * A class extending Signer that provides read-only access to a CKB script.
8
- * This class does not support signing operations.
7
+ * A read-only signer for a CKB script. It can be used to get addresses,
8
+ * but not to sign transactions. This is useful when you want to watch an address
9
+ * without having the private key.
10
+ *
9
11
  * @public
10
12
  */
11
13
  export class SignerCkbScriptReadonly extends Signer {
14
+ /**
15
+ * The type of the signer.
16
+ */
12
17
  get type(): SignerType {
13
18
  return SignerType.CKB;
14
19
  }
15
20
 
21
+ /**
22
+ * The sign type of the signer.
23
+ * As this is a read-only signer, the sign type is {@link SignerSignType.Unknown}.
24
+ */
16
25
  get signType(): SignerSignType {
17
26
  return SignerSignType.Unknown;
18
27
  }
19
28
 
20
- private readonly script: Script;
29
+ /**
30
+ * The scripts associated with the signer.
31
+ */
32
+ public readonly scripts: Script[];
21
33
 
22
34
  /**
23
35
  * Creates an instance of SignerCkbScriptReadonly.
24
36
  *
25
37
  * @param client - The client instance used for communication.
26
- * @param script - The script associated with the signer.
38
+ * @param scripts - The scripts associated with the signer. Can be a single script, an array of scripts, or multiple script arguments.
27
39
  */
28
- constructor(client: Client, script: ScriptLike) {
40
+ constructor(client: Client, ...scripts: (ScriptLike | ScriptLike[])[]) {
29
41
  super(client);
30
42
 
31
- this.script = Script.from(script);
43
+ this.scripts = scripts.flat().map(Script.from);
44
+ if (this.scripts.length === 0) {
45
+ throw new Error("SignerCkbScriptReadonly requires at least one script.");
46
+ }
32
47
  }
33
48
 
34
49
  /**
@@ -71,8 +86,9 @@ export class SignerCkbScriptReadonly extends Signer {
71
86
  * const addressObjs = await signer.getAddressObjs(); // Outputs the array of Address objects
72
87
  * ```
73
88
  */
74
-
75
89
  async getAddressObjs(): Promise<Address[]> {
76
- return [Address.fromScript(this.script, this.client)];
90
+ return this.scripts.map((script) =>
91
+ Address.fromScript(script, this.client),
92
+ );
77
93
  }
78
94
  }
@@ -6,6 +6,7 @@ import {
6
6
  Client,
7
7
  ClientFindTransactionsGroupedResponse,
8
8
  ClientFindTransactionsResponse,
9
+ ClientIndexerSearchKeyFilterLike,
9
10
  } from "../../client/index.js";
10
11
  import { Hex } from "../../hex/index.js";
11
12
  import { Num } from "../../num/index.js";
@@ -239,6 +240,39 @@ export abstract class Signer {
239
240
  );
240
241
  }
241
242
 
243
+ /**
244
+ * Find cells of this signer
245
+ *
246
+ * @param filter - The filter for the search key.
247
+ * @param withData - Whether to include cell data in the response.
248
+ * @param order - The order of the returned cells, can be "asc" or "desc".
249
+ * @param limit - The maximum number of cells for every querying chunk.
250
+ * @returns A async generator that yields all matching cells
251
+ */
252
+ async *findCellsOnChain(
253
+ filter: ClientIndexerSearchKeyFilterLike,
254
+ withData?: boolean | null,
255
+ order?: "asc" | "desc",
256
+ limit?: number,
257
+ ): AsyncGenerator<Cell> {
258
+ const scripts = await this.getAddressObjs();
259
+ for (const { script } of scripts) {
260
+ for await (const cell of this.client.findCellsOnChain(
261
+ {
262
+ script,
263
+ scriptType: "lock",
264
+ filter,
265
+ scriptSearchMode: "exact",
266
+ withData,
267
+ },
268
+ order,
269
+ limit,
270
+ )) {
271
+ yield cell;
272
+ }
273
+ }
274
+ }
275
+
242
276
  /**
243
277
  * Find cells of this signer
244
278
  *