@ckb-ccc/core 0.0.4 → 0.0.5-alpha.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 (99) hide show
  1. package/README.md +6 -0
  2. package/dist/ckb/transaction.d.ts +85 -2
  3. package/dist/ckb/transaction.d.ts.map +1 -1
  4. package/dist/ckb/transaction.js +152 -7
  5. package/dist/client/client.d.ts +11 -3
  6. package/dist/client/client.d.ts.map +1 -1
  7. package/dist/client/client.js +44 -2
  8. package/dist/client/clientPublicMainnet.advanced.d.ts.map +1 -1
  9. package/dist/client/clientPublicMainnet.advanced.js +4 -0
  10. package/dist/client/clientPublicTestnet.advanced.d.ts.map +1 -1
  11. package/dist/client/clientPublicTestnet.advanced.js +4 -0
  12. package/dist/client/clientTypes.d.ts +48 -1
  13. package/dist/client/clientTypes.d.ts.map +1 -1
  14. package/dist/client/clientTypes.js +27 -1
  15. package/dist/client/jsonRpc/index.d.ts +19 -1
  16. package/dist/client/jsonRpc/index.d.ts.map +1 -1
  17. package/dist/client/jsonRpc/index.js +25 -1
  18. package/dist/client/jsonRpc/transformers.d.ts +17 -3
  19. package/dist/client/jsonRpc/transformers.d.ts.map +1 -1
  20. package/dist/client/jsonRpc/transformers.js +37 -3
  21. package/dist/client/jsonRpc/types.d.ts +15 -0
  22. package/dist/client/jsonRpc/types.d.ts.map +1 -1
  23. package/dist/fixedPoint/index.d.ts.map +1 -1
  24. package/dist/fixedPoint/index.js +4 -1
  25. package/dist/fixedPoint/index.test.d.ts +2 -0
  26. package/dist/fixedPoint/index.test.d.ts.map +1 -0
  27. package/dist/fixedPoint/index.test.js +43 -0
  28. package/dist/signer/btc/signerBtc.d.ts.map +1 -1
  29. package/dist/signer/btc/signerBtc.js +2 -3
  30. package/dist/signer/evm/signerEvm.d.ts.map +1 -1
  31. package/dist/signer/evm/signerEvm.js +2 -3
  32. package/dist/signer/index.d.ts +0 -1
  33. package/dist/signer/index.d.ts.map +1 -1
  34. package/dist/signer/index.js +0 -1
  35. package/dist/signer/signer.d.ts +17 -2
  36. package/dist/signer/signer.d.ts.map +1 -1
  37. package/dist/signer/signer.js +17 -1
  38. package/dist.commonjs/ckb/transaction.d.ts +85 -2
  39. package/dist.commonjs/ckb/transaction.d.ts.map +1 -1
  40. package/dist.commonjs/ckb/transaction.js +150 -5
  41. package/dist.commonjs/client/client.d.ts +11 -3
  42. package/dist.commonjs/client/client.d.ts.map +1 -1
  43. package/dist.commonjs/client/client.js +43 -1
  44. package/dist.commonjs/client/clientPublicMainnet.advanced.d.ts.map +1 -1
  45. package/dist.commonjs/client/clientPublicMainnet.advanced.js +4 -0
  46. package/dist.commonjs/client/clientPublicTestnet.advanced.d.ts.map +1 -1
  47. package/dist.commonjs/client/clientPublicTestnet.advanced.js +4 -0
  48. package/dist.commonjs/client/clientTypes.d.ts +48 -1
  49. package/dist.commonjs/client/clientTypes.d.ts.map +1 -1
  50. package/dist.commonjs/client/clientTypes.js +29 -0
  51. package/dist.commonjs/client/jsonRpc/index.d.ts +19 -1
  52. package/dist.commonjs/client/jsonRpc/index.d.ts.map +1 -1
  53. package/dist.commonjs/client/jsonRpc/index.js +25 -1
  54. package/dist.commonjs/client/jsonRpc/transformers.d.ts +17 -3
  55. package/dist.commonjs/client/jsonRpc/transformers.d.ts.map +1 -1
  56. package/dist.commonjs/client/jsonRpc/transformers.js +35 -1
  57. package/dist.commonjs/client/jsonRpc/types.d.ts +15 -0
  58. package/dist.commonjs/client/jsonRpc/types.d.ts.map +1 -1
  59. package/dist.commonjs/fixedPoint/index.d.ts.map +1 -1
  60. package/dist.commonjs/fixedPoint/index.js +4 -1
  61. package/dist.commonjs/fixedPoint/index.test.d.ts +2 -0
  62. package/dist.commonjs/fixedPoint/index.test.d.ts.map +1 -0
  63. package/dist.commonjs/fixedPoint/index.test.js +45 -0
  64. package/dist.commonjs/signer/btc/signerBtc.d.ts.map +1 -1
  65. package/dist.commonjs/signer/btc/signerBtc.js +2 -3
  66. package/dist.commonjs/signer/evm/signerEvm.d.ts.map +1 -1
  67. package/dist.commonjs/signer/evm/signerEvm.js +2 -3
  68. package/dist.commonjs/signer/index.d.ts +0 -1
  69. package/dist.commonjs/signer/index.d.ts.map +1 -1
  70. package/dist.commonjs/signer/index.js +0 -1
  71. package/dist.commonjs/signer/signer.d.ts +17 -2
  72. package/dist.commonjs/signer/signer.d.ts.map +1 -1
  73. package/dist.commonjs/signer/signer.js +17 -1
  74. package/dist.commonjs/tsconfig.commonjs.tsbuildinfo +1 -1
  75. package/jest.config.js +5 -0
  76. package/package.json +6 -2
  77. package/src/ckb/transaction.ts +198 -3
  78. package/src/client/client.ts +87 -3
  79. package/src/client/clientPublicMainnet.advanced.ts +5 -0
  80. package/src/client/clientPublicTestnet.advanced.ts +5 -0
  81. package/src/client/clientTypes.ts +70 -1
  82. package/src/client/jsonRpc/index.ts +54 -2
  83. package/src/client/jsonRpc/transformers.ts +73 -4
  84. package/src/client/jsonRpc/types.ts +16 -0
  85. package/src/fixedPoint/index.test.ts +55 -0
  86. package/src/fixedPoint/index.ts +7 -1
  87. package/src/signer/btc/signerBtc.ts +6 -3
  88. package/src/signer/evm/signerEvm.ts +2 -3
  89. package/src/signer/index.ts +0 -1
  90. package/src/signer/signer.ts +21 -0
  91. package/dist/signer/helpers.d.ts +0 -40
  92. package/dist/signer/helpers.d.ts.map +0 -1
  93. package/dist/signer/helpers.js +0 -91
  94. package/dist.commonjs/signer/helpers.d.ts +0 -40
  95. package/dist.commonjs/signer/helpers.d.ts.map +0 -1
  96. package/dist.commonjs/signer/helpers.js +0 -96
  97. package/src/signer/helpers.ts +0 -124
  98. package/tsconfig.base.json +0 -21
  99. package/tsconfig.commonjs.json +0 -8
@@ -3,7 +3,14 @@ import { Bytes, BytesLike, bytesFrom } from "../bytes";
3
3
  import { Client } from "../client";
4
4
  import { Hasher, ckbHash } from "../hasher";
5
5
  import { Hex, HexLike, hexFrom } from "../hex";
6
- import { Num, NumLike, numFrom, numFromBytes, numToBytes } from "../num";
6
+ import {
7
+ Num,
8
+ NumLike,
9
+ numFrom,
10
+ numFromBytes,
11
+ numToBytes,
12
+ numToHex,
13
+ } from "../num";
7
14
  import { apply } from "../utils";
8
15
  import * as mol from "./molecule.advanced";
9
16
  import { Script, ScriptLike } from "./script";
@@ -272,20 +279,26 @@ export class CellOutput {
272
279
  }
273
280
 
274
281
  export type CellLike = {
282
+ outPoint: OutPointLike;
275
283
  cellOutput: CellOutputLike;
276
284
  outputData: HexLike;
285
+ blockNumber: NumLike;
277
286
  };
278
287
  export class Cell {
279
288
  /**
280
289
  * Creates an instance of Cell.
281
290
  *
291
+ * @param outPoint - The output point of the cell.
282
292
  * @param cellOutput - The cell output of the cell.
283
293
  * @param outputData - The output data of the cell.
294
+ * @param blockNumber - The block number of the cell.
284
295
  */
285
296
 
286
297
  constructor(
298
+ public outPoint: OutPoint,
287
299
  public cellOutput: CellOutput,
288
300
  public outputData: Hex,
301
+ public blockNumber: Num,
289
302
  ) {}
290
303
 
291
304
  /**
@@ -300,7 +313,12 @@ export class Cell {
300
313
  return cell;
301
314
  }
302
315
 
303
- return new Cell(CellOutput.from(cell.cellOutput), hexFrom(cell.outputData));
316
+ return new Cell(
317
+ OutPoint.from(cell.outPoint),
318
+ CellOutput.from(cell.cellOutput),
319
+ hexFrom(cell.outputData),
320
+ numFrom(cell.blockNumber),
321
+ );
304
322
  }
305
323
  }
306
324
 
@@ -309,6 +327,7 @@ export type CellInputLike = {
309
327
  since: NumLike;
310
328
  cellOutput?: CellOutputLike;
311
329
  outputData?: HexLike;
330
+ blockNumber?: NumLike;
312
331
  };
313
332
  export class CellInput {
314
333
  /**
@@ -318,6 +337,7 @@ export class CellInput {
318
337
  * @param since - The since value of the cell input.
319
338
  * @param cellOutput - The optional cell output associated with the cell input.
320
339
  * @param outputData - The optional output data associated with the cell input.
340
+ * @param blockNumber - The optional block number associated with the cell input.
321
341
  */
322
342
 
323
343
  constructor(
@@ -325,6 +345,7 @@ export class CellInput {
325
345
  public since: Num,
326
346
  public cellOutput?: CellOutput,
327
347
  public outputData?: Hex,
348
+ public blockNumber?: Num,
328
349
  ) {}
329
350
 
330
351
  /**
@@ -352,6 +373,7 @@ export class CellInput {
352
373
  numFrom(cellInput.since),
353
374
  apply(CellOutput.from, cellInput.cellOutput),
354
375
  apply(hexFrom, cellInput.outputData),
376
+ apply(numFrom, cellInput.blockNumber),
355
377
  );
356
378
  }
357
379
 
@@ -369,7 +391,7 @@ export class CellInput {
369
391
  */
370
392
 
371
393
  async completeExtraInfos(client: Client): Promise<CellInput> {
372
- if (this.cellOutput && this.outputData) {
394
+ if (this.cellOutput && this.outputData && this.blockNumber) {
373
395
  return this;
374
396
  }
375
397
 
@@ -377,6 +399,7 @@ export class CellInput {
377
399
  if (cell) {
378
400
  this.cellOutput = cell.cellOutput;
379
401
  this.outputData = cell.outputData;
402
+ this.blockNumber = cell.blockNumber;
380
403
  }
381
404
  return this;
382
405
  }
@@ -751,6 +774,15 @@ export class Transaction {
751
774
  });
752
775
  }
753
776
 
777
+ stringify(): string {
778
+ return JSON.stringify(this, (_, value) => {
779
+ if (typeof value === "bigint") {
780
+ return numToHex(value);
781
+ }
782
+ return value;
783
+ });
784
+ }
785
+
754
786
  /**
755
787
  * Converts the raw transaction data to bytes.
756
788
  *
@@ -807,4 +839,167 @@ export class Transaction {
807
839
  hasher.update(numToBytes(raw.length, 8));
808
840
  hasher.update(raw);
809
841
  }
842
+
843
+ /**
844
+ * Computes the signing hash information for a given script.
845
+ *
846
+ * @param scriptLike - The script associated with the transaction, represented as a ScriptLike object.
847
+ * @param client - The client for complete extra infos in the transaction.
848
+ * @returns A promise that resolves to an object containing the signing message and the witness position,
849
+ * or undefined if no matching input is found.
850
+ *
851
+ * @example
852
+ * ```typescript
853
+ * const signHashInfo = await tx.getSignHashInfo(scriptLike, client);
854
+ * if (signHashInfo) {
855
+ * console.log(signHashInfo.message); // Outputs the signing message
856
+ * console.log(signHashInfo.position); // Outputs the witness position
857
+ * }
858
+ * ```
859
+ */
860
+ async getSignHashInfo(
861
+ scriptLike: ScriptLike,
862
+ client: Client,
863
+ ): Promise<{ message: Hex; position: number } | undefined> {
864
+ const script = Script.from(scriptLike);
865
+ let position = -1;
866
+ const hasher = new Hasher();
867
+ hasher.update(this.hash());
868
+
869
+ for (let i = 0; i < this.witnesses.length; i += 1) {
870
+ if (this.inputs[i]) {
871
+ const input = await this.inputs[i].completeExtraInfos(client);
872
+
873
+ if (!input.cellOutput) {
874
+ throw Error("Unable to resolve inputs info");
875
+ }
876
+
877
+ if (!script.eq(input.cellOutput.lock)) {
878
+ continue;
879
+ }
880
+
881
+ if (position === -1) {
882
+ position = i;
883
+ }
884
+ }
885
+
886
+ if (position === -1) {
887
+ return undefined;
888
+ }
889
+
890
+ Transaction.hashWitnessToHasher(this.witnesses[i], hasher);
891
+ }
892
+
893
+ if (position === -1) {
894
+ return undefined;
895
+ }
896
+
897
+ return {
898
+ message: hasher.digest(),
899
+ position,
900
+ };
901
+ }
902
+
903
+ /**
904
+ * Find the first occurrence of a input with the specified lock
905
+ *
906
+ * @param scriptLike - The script associated with the transaction, represented as a ScriptLike object.
907
+ * @param client - The client for complete extra infos in the transaction.
908
+ * @returns A promise that resolves to the prepared transaction
909
+ *
910
+ * @example
911
+ * ```typescript
912
+ * const index = await tx.findInputIndexByLock(scriptLike, client);
913
+ * ```
914
+ */
915
+ async findInputIndexByLock(
916
+ scriptLike: ScriptLike,
917
+ client: Client,
918
+ ): Promise<number | undefined> {
919
+ const script = Script.from(scriptLike);
920
+
921
+ for (let i = 0; i < this.inputs.length; i += 1) {
922
+ const input = await this.inputs[i].completeExtraInfos(client);
923
+
924
+ if (!input.cellOutput) {
925
+ throw Error("Unable to resolve inputs info");
926
+ }
927
+
928
+ if (script.eq(input.cellOutput.lock)) {
929
+ return i;
930
+ }
931
+ }
932
+ }
933
+
934
+ /**
935
+ * Get witness at index as WitnessArgs
936
+ *
937
+ * @param index - The index of the witness.
938
+ * @returns The witness parsed as WitnessArgs.
939
+ *
940
+ * @example
941
+ * ```typescript
942
+ * const witnessArgs = await tx.getWitnessArgsAt(0);
943
+ * ```
944
+ */
945
+ getWitnessArgsAt(index: number): WitnessArgs | undefined {
946
+ const rawWitness = this.witnesses[index];
947
+ return (rawWitness ?? "0x") !== "0x"
948
+ ? WitnessArgs.fromBytes(rawWitness)
949
+ : undefined;
950
+ }
951
+
952
+ /**
953
+ * Set witness at index by WitnessArgs
954
+ *
955
+ * @param index - The index of the witness.
956
+ * @param witness - The WitnessArgs to set.
957
+ * @returns The transaction itself.
958
+ *
959
+ * @example
960
+ * ```typescript
961
+ * await tx.setWitnessArgsAt(0, witnessArgs);
962
+ * ```
963
+ */
964
+ setWitnessArgsAt(index: number, witness: WitnessArgs): Transaction {
965
+ if (this.witnesses.length < index) {
966
+ this.witnesses.push(
967
+ ...Array.from(
968
+ new Array(index - this.witnesses.length),
969
+ (): Hex => "0x",
970
+ ),
971
+ );
972
+ }
973
+
974
+ this.witnesses[index] = hexFrom(witness.toBytes());
975
+ return this;
976
+ }
977
+
978
+ /**
979
+ * Prepare dummy witness for sighash all method
980
+ *
981
+ * @param scriptLike - The script associated with the transaction, represented as a ScriptLike object.
982
+ * @param lockLen - The length of dummy lock bytes.
983
+ * @param client - The client for complete extra infos in the transaction.
984
+ * @returns A promise that resolves to the prepared transaction
985
+ *
986
+ * @example
987
+ * ```typescript
988
+ * await tx.prepareSighashAllWitness(scriptLike, 85, client);
989
+ * ```
990
+ */
991
+ async prepareSighashAllWitness(
992
+ scriptLike: ScriptLike,
993
+ lockLen: number,
994
+ client: Client,
995
+ ): Promise<Transaction> {
996
+ const position = await this.findInputIndexByLock(scriptLike, client);
997
+ if (position === undefined) {
998
+ return this;
999
+ }
1000
+
1001
+ const witness = this.getWitnessArgsAt(position) ?? WitnessArgs.from({});
1002
+ witness.lock = hexFrom(Array.from(new Array(lockLen), () => 0));
1003
+ return this.setWitnessArgsAt(position, witness);
1004
+ }
810
1005
  }
@@ -1,13 +1,26 @@
1
- import { Cell, OutPointLike, Script, TransactionLike } from "../ckb";
1
+ import {
2
+ Cell,
3
+ OutPointLike,
4
+ Script,
5
+ ScriptLike,
6
+ TransactionLike,
7
+ } from "../ckb";
8
+ import { Zero } from "../fixedPoint";
2
9
  import { Hex, HexLike } from "../hex";
3
- import { numFrom } from "../num";
4
- import { ClientTransactionResponse, OutputsValidator } from "./clientTypes";
10
+ import { Num, NumLike, numFrom } from "../num";
11
+ import {
12
+ ClientFindCellsResponse,
13
+ ClientIndexerSearchKeyLike,
14
+ ClientTransactionResponse,
15
+ OutputsValidator,
16
+ } from "./clientTypes";
5
17
 
6
18
  export enum KnownScript {
7
19
  Secp256k1Blake160,
8
20
  Secp256k1Multisig,
9
21
  AnyoneCanPay,
10
22
  JoyId,
23
+ COTA,
11
24
  OmniLock,
12
25
  }
13
26
 
@@ -39,8 +52,79 @@ export abstract class Client {
39
52
  }
40
53
 
41
54
  return Cell.from({
55
+ outPoint,
42
56
  cellOutput: transaction.transaction.outputs[index],
43
57
  outputData: transaction.transaction.outputsData[index] ?? "0x",
58
+ blockNumber: transaction.blockNumber,
44
59
  });
45
60
  }
61
+
62
+ abstract findCellsPaged(
63
+ key: ClientIndexerSearchKeyLike,
64
+ order?: "asc" | "desc",
65
+ limit?: NumLike,
66
+ after?: string,
67
+ ): Promise<ClientFindCellsResponse>;
68
+
69
+ async *findCells(
70
+ key: ClientIndexerSearchKeyLike,
71
+ order?: "asc" | "desc",
72
+ limit = 10,
73
+ ): AsyncGenerator<Cell> {
74
+ let last: string | undefined = undefined;
75
+
76
+ while (true) {
77
+ const { cells, lastCursor } = await this.findCellsPaged(
78
+ key,
79
+ order,
80
+ limit,
81
+ last,
82
+ );
83
+ for (const cell of cells) {
84
+ yield cell;
85
+ }
86
+ if (cells.length === 0 || cells.length < limit) {
87
+ return;
88
+ }
89
+ last = lastCursor;
90
+ }
91
+ }
92
+
93
+ findCellsByLockAndType(
94
+ lock: ScriptLike,
95
+ type: ScriptLike,
96
+ withData = true,
97
+ ): AsyncGenerator<Cell> {
98
+ return this.findCells({
99
+ script: lock,
100
+ scriptType: "lock",
101
+ scriptSearchMode: "exact",
102
+ filter: {
103
+ script: type,
104
+ },
105
+ withData,
106
+ });
107
+ }
108
+
109
+ abstract getCellsCapacity(key: ClientIndexerSearchKeyLike): Promise<Num>;
110
+
111
+ async getBalanceSingle(lock: ScriptLike): Promise<Num> {
112
+ return this.getCellsCapacity({
113
+ script: lock,
114
+ scriptType: "lock",
115
+ scriptSearchMode: "exact",
116
+ filter: {
117
+ scriptLenRange: [0, 1],
118
+ outputDataLenRange: [0, 1],
119
+ },
120
+ });
121
+ }
122
+
123
+ async getBalance(locks: ScriptLike[]): Promise<Num> {
124
+ return locks.reduce(
125
+ (res: Promise<Num>, lock) =>
126
+ this.getBalanceSingle(lock).then((a) => res.then((b) => a + b)),
127
+ Promise.resolve(Zero),
128
+ );
129
+ }
46
130
  }
@@ -25,6 +25,11 @@ export const MAINNET_SCRIPTS: Record<
25
25
  "0xd00c84f0ec8fd441c38bc3f87a371f547190f2fcff88e642bc5bf54b9e318323",
26
26
  hashType: "type",
27
27
  },
28
+ [KnownScript.COTA]: {
29
+ codeHash:
30
+ "0x1122a4fb54697cf2e6e3a96c9d80fd398a936559b90954c6e88eb7ba0cf652df",
31
+ hashType: "type",
32
+ },
28
33
  [KnownScript.OmniLock]: {
29
34
  codeHash:
30
35
  "0x9b819793a64463aed77c615d6cb226eea5487ccfc0783043a587254cda2b6f26",
@@ -25,6 +25,11 @@ export const TESTNET_SCRIPTS: Record<
25
25
  "0xd23761b364210735c19c60561d213fb3beae2fd6172743719eff6920e020baac",
26
26
  hashType: "type",
27
27
  },
28
+ [KnownScript.COTA]: {
29
+ codeHash:
30
+ "0x89cd8003a0eaf8e65e0c31525b7d1d5c1becefd2ea75bb4cff87810ae37764d8",
31
+ hashType: "type",
32
+ },
28
33
  [KnownScript.OmniLock]: {
29
34
  codeHash:
30
35
  "0xf329effd1c475a2978453c8600e1eaf0bc2087ee093c3ee64cc96ec6847752cb",
@@ -1,4 +1,7 @@
1
- import { Transaction } from "../ckb";
1
+ import { Cell, Script, ScriptLike, Transaction } from "../ckb";
2
+ import { Hex, HexLike, hexFrom } from "../hex";
3
+ import { Num, NumLike, numFrom } from "../num";
4
+ import { apply } from "../utils";
2
5
 
3
6
  export type OutputsValidator = "passthrough" | "well_known_scripts_only";
4
7
 
@@ -11,4 +14,70 @@ export type TransactionStatus =
11
14
  export type ClientTransactionResponse = {
12
15
  transaction: Transaction;
13
16
  status: TransactionStatus;
17
+ blockNumber: Num;
18
+ };
19
+
20
+ export type ClientIndexerSearchKeyLike = {
21
+ script: ScriptLike;
22
+ scriptType: "lock" | "type";
23
+ scriptSearchMode?: "prefix" | "exact" | "partial";
24
+ filter?: {
25
+ script?: ScriptLike;
26
+ scriptLenRange?: [NumLike, NumLike];
27
+ outputData?: HexLike;
28
+ outputDataSearchMode?: "prefix" | "exact" | "partial";
29
+ outputDataLenRange?: [NumLike, NumLike];
30
+ outputCapacityRange?: [NumLike, NumLike];
31
+ blockRange?: [NumLike, NumLike];
32
+ };
33
+ withData?: boolean;
34
+ };
35
+
36
+ function rangeFrom([a, b]: [NumLike, NumLike]): [Num, Num] {
37
+ return [numFrom(a), numFrom(b)];
38
+ }
39
+ export class ClientIndexerSearchKey {
40
+ constructor(
41
+ public script: Script,
42
+ public scriptType: "lock" | "type",
43
+ public scriptSearchMode: "prefix" | "exact" | "partial" | undefined,
44
+ public filter:
45
+ | {
46
+ script?: Script;
47
+ scriptLenRange?: [Num, Num];
48
+ outputData?: Hex;
49
+ outputDataSearchMode?: "prefix" | "exact" | "partial";
50
+ outputDataLenRange?: [Num, Num];
51
+ outputCapacityRange?: [Num, Num];
52
+ blockRange?: [Num, Num];
53
+ }
54
+ | undefined,
55
+ public withData: boolean | undefined,
56
+ ) {}
57
+
58
+ static from(keyLike: ClientIndexerSearchKeyLike): ClientIndexerSearchKey {
59
+ return new ClientIndexerSearchKey(
60
+ Script.from(keyLike.script),
61
+ keyLike.scriptType,
62
+ keyLike.scriptSearchMode,
63
+ apply(
64
+ (filter: NonNullable<ClientIndexerSearchKeyLike["filter"]>) => ({
65
+ script: apply(Script.from, filter.script),
66
+ scriptLenRange: apply(rangeFrom, filter.scriptLenRange),
67
+ outputData: apply(hexFrom, filter.outputData),
68
+ outputDataSearchMode: filter.outputDataSearchMode,
69
+ outputDataLenRange: apply(rangeFrom, filter.outputDataLenRange),
70
+ outputCapacityRange: apply(rangeFrom, filter.outputCapacityRange),
71
+ blockRange: apply(rangeFrom, filter.blockRange),
72
+ }),
73
+ keyLike.filter,
74
+ ),
75
+ keyLike.withData,
76
+ );
77
+ }
78
+ }
79
+
80
+ export type ClientFindCellsResponse = {
81
+ lastCursor: string;
82
+ cells: Cell[];
14
83
  };
@@ -1,8 +1,14 @@
1
1
  import fetch from "cross-fetch";
2
2
  import { TransactionLike } from "../../ckb";
3
3
  import { Hex, HexLike, hexFrom } from "../../hex";
4
+ import { Num, NumLike, numFrom, numToHex } from "../../num";
4
5
  import { Client } from "../client";
5
- import { ClientTransactionResponse, OutputsValidator } from "../clientTypes";
6
+ import {
7
+ ClientFindCellsResponse,
8
+ ClientIndexerSearchKeyLike,
9
+ ClientTransactionResponse,
10
+ OutputsValidator,
11
+ } from "../clientTypes";
6
12
  import { JsonRpcPayload, JsonRpcTransformers } from "./advanced";
7
13
 
8
14
  /**
@@ -89,6 +95,44 @@ export abstract class ClientJsonRpc extends Client {
89
95
  JsonRpcTransformers.transactionResponseTo,
90
96
  ) as (txHash: HexLike) => Promise<ClientTransactionResponse>;
91
97
 
98
+ /**
99
+ * find cells from node.
100
+ *
101
+ * @param key - The search key of cells.
102
+ * @param order - The order of cells.
103
+ * @param limit - The max return size of cells.
104
+ * @param after - Pagination parameter.
105
+ * @returns The found cells.
106
+ */
107
+
108
+ findCellsPaged = this.buildSender(
109
+ "get_cells",
110
+ [
111
+ JsonRpcTransformers.indexerSearchKeyFrom,
112
+ (order) => order ?? "asc",
113
+ (limit) => numToHex(limit ?? 10),
114
+ ],
115
+ JsonRpcTransformers.findCellsResponseTo,
116
+ ) as (
117
+ key: ClientIndexerSearchKeyLike,
118
+ order?: "asc" | "desc",
119
+ limit?: NumLike,
120
+ after?: string,
121
+ ) => Promise<ClientFindCellsResponse>;
122
+
123
+ /**
124
+ * get cells capacity from node.
125
+ *
126
+ * @param key - The search key of cells.
127
+ * @returns The sum of cells capacity.
128
+ */
129
+
130
+ getCellsCapacity = this.buildSender(
131
+ "get_cells_capacity",
132
+ [JsonRpcTransformers.indexerSearchKeyFrom],
133
+ ({ capacity }) => numFrom(capacity),
134
+ ) as (key: ClientIndexerSearchKeyLike) => Promise<Num>;
135
+
92
136
  /**
93
137
  * Builds a sender function for a JSON-RPC method.
94
138
  *
@@ -106,7 +150,15 @@ export abstract class ClientJsonRpc extends Client {
106
150
  return async (...req: unknown[]) => {
107
151
  const payload = ClientJsonRpc.buildPayload(
108
152
  rpcMethod,
109
- await Promise.all(req.map((v, i) => transform(v, inTransformers[i]))),
153
+ await Promise.all(
154
+ req
155
+ .concat(
156
+ Array.from(
157
+ new Array(Math.max(inTransformers.length - req.length, 0)),
158
+ ),
159
+ )
160
+ .map((v, i) => transform(v, inTransformers[i])),
161
+ ),
110
162
  );
111
163
 
112
164
  return transform(await this.send(payload), outTransformer);
@@ -1,4 +1,5 @@
1
1
  import {
2
+ Cell,
2
3
  CellDep,
3
4
  CellDepLike,
4
5
  CellInput,
@@ -18,15 +19,23 @@ import {
18
19
  depTypeFrom,
19
20
  hashTypeFrom,
20
21
  } from "../../ckb";
21
- import { numToHex } from "../../num";
22
+ import { Hex } from "../../hex";
23
+ import { NumLike, numFrom, numToHex } from "../../num";
22
24
  import { apply } from "../../utils";
23
- import { ClientTransactionResponse, TransactionStatus } from "../clientTypes";
25
+ import {
26
+ ClientFindCellsResponse,
27
+ ClientIndexerSearchKey,
28
+ ClientIndexerSearchKeyLike,
29
+ ClientTransactionResponse,
30
+ TransactionStatus,
31
+ } from "../clientTypes";
24
32
  import {
25
33
  JsonRpcCellDep,
26
34
  JsonRpcCellInput,
27
35
  JsonRpcCellOutput,
28
36
  JsonRpcDepType,
29
37
  JsonRpcHashType,
38
+ JsonRpcIndexerSearchKey,
30
39
  JsonRpcOutPoint,
31
40
  JsonRpcScript,
32
41
  JsonRpcTransaction,
@@ -147,15 +156,75 @@ export class JsonRpcTransformers {
147
156
  });
148
157
  }
149
158
  static transactionResponseTo({
150
- tx_status: { status },
159
+ tx_status: { status, block_number },
151
160
  transaction,
152
161
  }: {
153
- tx_status: { status: TransactionStatus };
162
+ tx_status: { status: TransactionStatus; block_number: Hex };
154
163
  transaction: JsonRpcTransaction;
155
164
  }): ClientTransactionResponse {
156
165
  return {
157
166
  transaction: JsonRpcTransformers.transactionTo(transaction),
158
167
  status,
168
+ blockNumber: numFrom(block_number),
169
+ };
170
+ }
171
+ static rangeFrom([a, b]: [NumLike, NumLike]): [Hex, Hex] {
172
+ return [numToHex(a), numToHex(b)];
173
+ }
174
+ static indexerSearchKeyFrom(
175
+ keyLike: ClientIndexerSearchKeyLike,
176
+ ): JsonRpcIndexerSearchKey {
177
+ const key = ClientIndexerSearchKey.from(keyLike);
178
+ return {
179
+ script: JsonRpcTransformers.scriptFrom(key.script),
180
+ script_type: key.scriptType,
181
+ script_search_mode: key.scriptSearchMode,
182
+ filter: apply(
183
+ (filter: NonNullable<ClientIndexerSearchKey["filter"]>) => ({
184
+ script: apply(JsonRpcTransformers.scriptFrom, filter.script),
185
+ script_len_range: apply(
186
+ JsonRpcTransformers.rangeFrom,
187
+ filter.scriptLenRange,
188
+ ),
189
+ output_data: filter.outputData,
190
+ output_data_filter_mode: filter.outputDataSearchMode,
191
+ output_data_len_range: apply(
192
+ JsonRpcTransformers.rangeFrom,
193
+ filter.outputDataLenRange,
194
+ ),
195
+ output_capacity_range: apply(
196
+ JsonRpcTransformers.rangeFrom,
197
+ filter.outputCapacityRange,
198
+ ),
199
+ block_range: apply(JsonRpcTransformers.rangeFrom, filter.blockRange),
200
+ }),
201
+ key.filter,
202
+ ),
203
+ with_data: key.withData,
204
+ };
205
+ }
206
+ static findCellsResponseTo({
207
+ last_cursor,
208
+ objects,
209
+ }: {
210
+ last_cursor: string;
211
+ objects: {
212
+ block_number: Hex;
213
+ out_point: JsonRpcOutPoint;
214
+ output: JsonRpcCellOutput;
215
+ output_data: Hex;
216
+ }[];
217
+ }): ClientFindCellsResponse {
218
+ return {
219
+ lastCursor: last_cursor,
220
+ cells: objects.map((cell) =>
221
+ Cell.from({
222
+ blockNumber: cell.block_number,
223
+ outPoint: JsonRpcTransformers.outPointTo(cell.out_point),
224
+ cellOutput: JsonRpcTransformers.cellOutputTo(cell.output),
225
+ outputData: cell.output_data,
226
+ }),
227
+ ),
159
228
  };
160
229
  }
161
230
  }
@@ -46,3 +46,19 @@ export type JsonRpcTransaction = {
46
46
  outputs_data: Hex[];
47
47
  witnesses: Hex[];
48
48
  };
49
+
50
+ export type JsonRpcIndexerSearchKey = {
51
+ script: JsonRpcScript;
52
+ script_type: "lock" | "type";
53
+ script_search_mode?: "prefix" | "exact" | "partial";
54
+ filter?: {
55
+ script?: JsonRpcScript;
56
+ script_len_range?: [Hex, Hex];
57
+ output_data?: Hex;
58
+ output_data_filter_mode?: "prefix" | "exact" | "partial";
59
+ output_data_len_range?: [Hex, Hex];
60
+ output_capacity_range?: [Hex, Hex];
61
+ block_range?: [Hex, Hex];
62
+ };
63
+ with_data?: boolean;
64
+ };