@ckb-ccc/core 0.0.13 → 0.0.14-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 (46) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +16 -3
  3. package/dist/ckb/transaction.d.ts.map +1 -1
  4. package/dist/ckb/transaction.js +12 -8
  5. package/dist/client/client.d.ts +1 -1
  6. package/dist/client/client.d.ts.map +1 -1
  7. package/dist/client/client.js +2 -2
  8. package/dist/client/clientTypes.d.ts +9 -0
  9. package/dist/client/clientTypes.d.ts.map +1 -1
  10. package/dist/client/clientTypes.js +13 -0
  11. package/dist/client/jsonRpc/index.d.ts.map +1 -1
  12. package/dist/client/jsonRpc/index.js +29 -13
  13. package/dist/num/index.d.ts +13 -0
  14. package/dist/num/index.d.ts.map +1 -1
  15. package/dist/num/index.js +23 -1
  16. package/dist/signer/ckb/signerCkbPrivateKey.d.ts.map +1 -1
  17. package/dist/signer/ckb/signerCkbPrivateKey.js +9 -8
  18. package/dist/signer/ckb/signerCkbPublicKey.d.ts +8 -2
  19. package/dist/signer/ckb/signerCkbPublicKey.d.ts.map +1 -1
  20. package/dist/signer/ckb/signerCkbPublicKey.js +65 -7
  21. package/dist.commonjs/ckb/transaction.d.ts.map +1 -1
  22. package/dist.commonjs/ckb/transaction.js +11 -7
  23. package/dist.commonjs/client/client.d.ts +1 -1
  24. package/dist.commonjs/client/client.d.ts.map +1 -1
  25. package/dist.commonjs/client/client.js +2 -2
  26. package/dist.commonjs/client/clientTypes.d.ts +9 -0
  27. package/dist.commonjs/client/clientTypes.d.ts.map +1 -1
  28. package/dist.commonjs/client/clientTypes.js +16 -1
  29. package/dist.commonjs/client/jsonRpc/index.d.ts.map +1 -1
  30. package/dist.commonjs/client/jsonRpc/index.js +28 -12
  31. package/dist.commonjs/num/index.d.ts +13 -0
  32. package/dist.commonjs/num/index.d.ts.map +1 -1
  33. package/dist.commonjs/num/index.js +25 -2
  34. package/dist.commonjs/signer/ckb/signerCkbPrivateKey.d.ts.map +1 -1
  35. package/dist.commonjs/signer/ckb/signerCkbPrivateKey.js +9 -8
  36. package/dist.commonjs/signer/ckb/signerCkbPublicKey.d.ts +8 -2
  37. package/dist.commonjs/signer/ckb/signerCkbPublicKey.d.ts.map +1 -1
  38. package/dist.commonjs/signer/ckb/signerCkbPublicKey.js +64 -6
  39. package/package.json +1 -1
  40. package/src/ckb/transaction.ts +13 -11
  41. package/src/client/client.ts +2 -2
  42. package/src/client/clientTypes.ts +24 -0
  43. package/src/client/jsonRpc/index.ts +43 -28
  44. package/src/num/index.ts +24 -1
  45. package/src/signer/ckb/signerCkbPrivateKey.ts +13 -9
  46. package/src/signer/ckb/signerCkbPublicKey.ts +97 -12
@@ -15,6 +15,8 @@ import {
15
15
  ClientTransactionResponse,
16
16
  ErrorClientBase,
17
17
  ErrorClientBaseLike,
18
+ ErrorClientDuplicatedTransaction,
19
+ ErrorClientRBFRejected,
18
20
  ErrorClientResolveUnknown,
19
21
  ErrorClientVerification,
20
22
  OutputsValidator,
@@ -50,6 +52,41 @@ async function transform(
50
52
  return value;
51
53
  }
52
54
 
55
+ const ERROR_PARSERS: [
56
+ string,
57
+ (error: ErrorClientBaseLike, match: RegExpMatchArray) => ErrorClientBase,
58
+ ][] = [
59
+ [
60
+ "Resolve\\(Unknown\\(OutPoint\\((0x.*)\\)\\)\\)",
61
+ (error, match) =>
62
+ new ErrorClientResolveUnknown(error, OutPoint.fromBytes(match[1])),
63
+ ],
64
+ [
65
+ "Verification\\(Error { kind: Script, inner: TransactionScriptError { source: (Inputs|Outputs)\\[([0-9]*)\\].(Lock|Type), cause: ValidationFailure: see error code (-?[0-9])* on page https://nervosnetwork\\.github\\.io/ckb-script-error-codes/by-(type|data)-hash/(.*)\\.html",
66
+ (error, match) =>
67
+ new ErrorClientVerification(
68
+ error,
69
+ match[3] === "Lock"
70
+ ? "lock"
71
+ : match[1] === "Inputs"
72
+ ? "inputType"
73
+ : "outputType",
74
+ match[2],
75
+ Number(match[4]),
76
+ match[5] === "data" ? "data" : "type",
77
+ match[6],
78
+ ),
79
+ ],
80
+ [
81
+ "Duplicated\\(Byte32\\((0x.*)\\)\\)",
82
+ (error, match) => new ErrorClientDuplicatedTransaction(error, match[1]),
83
+ ],
84
+ [
85
+ 'RBFRejected\\("Tx\'s current fee is ([0-9]*), expect it to >= ([0-9]*) to replace old txs"\\)',
86
+ (error, match) => new ErrorClientRBFRejected(error, match[1], match[2]),
87
+ ],
88
+ ];
89
+
53
90
  /**
54
91
  * An abstract class implementing JSON-RPC client functionality for a specific URL and timeout.
55
92
  * Provides methods for sending transactions and building JSON-RPC payloads.
@@ -353,33 +390,11 @@ export abstract class ClientJsonRpc extends Client {
353
390
  }
354
391
  const err = errAny as ErrorClientBaseLike;
355
392
 
356
- const unknownOutPointMatch = err.data.match(
357
- new RegExp("Resolve\\(Unknown\\(OutPoint\\((0x.*)\\)\\)\\)"),
358
- )?.[1];
359
- if (unknownOutPointMatch) {
360
- throw new ErrorClientResolveUnknown(
361
- err,
362
- OutPoint.fromBytes(unknownOutPointMatch),
363
- );
364
- }
365
- const verificationFailedMatch = err.data.match(
366
- new RegExp(
367
- "Verification\\(Error { kind: Script, inner: TransactionScriptError { source: (Inputs|Outputs)\\[([0-9]*)\\].(Lock|Type), cause: ValidationFailure: see error code (-?[0-9])* on page https://nervosnetwork\\.github\\.io/ckb-script-error-codes/by-(type|data)-hash/(.*)\\.html",
368
- ),
369
- );
370
- if (verificationFailedMatch) {
371
- throw new ErrorClientVerification(
372
- err,
373
- verificationFailedMatch[3] === "Lock"
374
- ? "lock"
375
- : verificationFailedMatch[1] === "Inputs"
376
- ? "inputType"
377
- : "outputType",
378
- verificationFailedMatch[2],
379
- Number(verificationFailedMatch[4]),
380
- verificationFailedMatch[5] === "data" ? "data" : "type",
381
- verificationFailedMatch[6],
382
- );
393
+ for (const [regexp, builder] of ERROR_PARSERS) {
394
+ const match = err.data.match(regexp);
395
+ if (match) {
396
+ throw builder(err, match);
397
+ }
383
398
  }
384
399
 
385
400
  throw new ErrorClientBase(err);
@@ -405,7 +420,7 @@ export abstract class ClientJsonRpc extends Client {
405
420
  throw new Error(`Id mismatched, got ${res.id}, expected ${payload.id}`);
406
421
  }
407
422
  if (res.error) {
408
- throw res.error;
423
+ throw new Error(`Client request error ${JSON.stringify(res.error)}`);
409
424
  }
410
425
  return res.result;
411
426
  }
package/src/num/index.ts CHANGED
@@ -14,6 +14,29 @@ export type Num = bigint;
14
14
  */
15
15
  export type NumLike = string | number | bigint | HexLike;
16
16
 
17
+ /**
18
+ * Get the min among all numbers.
19
+ * @public
20
+ *
21
+ * @param numbers - numbers.
22
+ * @returns The min numbers among them.
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * numMin(1, 2, 3); // Outputs 1n
27
+ * ```
28
+ */
29
+ export function numMin(a: NumLike, ...numbers: NumLike[]): Num {
30
+ let min = numFrom(a);
31
+ numbers.forEach((nLike) => {
32
+ const n = numFrom(nLike);
33
+ if (n < min) {
34
+ min = n;
35
+ }
36
+ });
37
+ return min;
38
+ }
39
+
17
40
  /**
18
41
  * Get the max among all numbers.
19
42
  * @public
@@ -167,7 +190,7 @@ export function numFromBytes(val: BytesLike): Num {
167
190
  * ```
168
191
  */
169
192
  export function numLeFromBytes(val: BytesLike): Num {
170
- return numBeFromBytes(bytesFrom(val).reverse());
193
+ return numBeFromBytes([...bytesFrom(val)].reverse());
171
194
  }
172
195
 
173
196
  /**
@@ -45,17 +45,21 @@ export class SignerCkbPrivateKey extends SignerCkbPublicKey {
45
45
 
46
46
  async signOnlyTransaction(txLike: TransactionLike): Promise<Transaction> {
47
47
  const tx = Transaction.from(txLike);
48
- const { script } = await this.getRecommendedAddressObj();
49
- const info = await tx.getSignHashInfo(script, this.client);
50
- if (!info) {
51
- return tx;
52
- }
53
48
 
54
- const signature = await this._signMessage(info.message);
49
+ for (const { script } of await this.getRelatedScripts(tx)) {
50
+ const info = await tx.getSignHashInfo(script, this.client);
51
+ if (!info) {
52
+ return tx;
53
+ }
54
+
55
+ const signature = await this._signMessage(info.message);
56
+
57
+ const witness =
58
+ tx.getWitnessArgsAt(info.position) ?? WitnessArgs.from({});
59
+ witness.lock = signature;
60
+ tx.setWitnessArgsAt(info.position, witness);
61
+ }
55
62
 
56
- const witness = tx.getWitnessArgsAt(info.position) ?? WitnessArgs.from({});
57
- witness.lock = signature;
58
- tx.setWitnessArgsAt(info.position, witness);
59
63
  return tx;
60
64
  }
61
65
  }
@@ -1,7 +1,7 @@
1
1
  import { Address } from "../../address/index.js";
2
2
  import { bytesFrom } from "../../bytes/index.js";
3
- import { Transaction, TransactionLike } from "../../ckb/index.js";
4
- import { Client, KnownScript } from "../../client/index.js";
3
+ import { Script, Transaction, TransactionLike } from "../../ckb/index.js";
4
+ import { CellDepInfo, Client, KnownScript } from "../../client/index.js";
5
5
  import { hashCkb } from "../../hasher/index.js";
6
6
  import { Hex, HexLike, hexFrom } from "../../hex/index.js";
7
7
  import { Signer, SignerSignType, SignerType } from "../signer/index.js";
@@ -43,24 +43,109 @@ export class SignerCkbPublicKey extends Signer {
43
43
  return this.publicKey;
44
44
  }
45
45
 
46
+ async getAddressObjSecp256k1(): Promise<Address> {
47
+ return Address.fromKnownScript(
48
+ this.client,
49
+ KnownScript.Secp256k1Blake160,
50
+ bytesFrom(hashCkb(this.publicKey)).slice(0, 20),
51
+ );
52
+ }
53
+
54
+ async getRecommendedAddressObj(_preference?: unknown): Promise<Address> {
55
+ return this.getAddressObjSecp256k1();
56
+ }
57
+
46
58
  async getAddressObjs(): Promise<Address[]> {
47
- return [
48
- await Address.fromKnownScript(
59
+ const secp256k1 = await this.getAddressObjSecp256k1();
60
+
61
+ const addresses: Address[] = [];
62
+ let count = 0;
63
+ for await (const cell of this.client.findCells({
64
+ script: await Script.fromKnownScript(
49
65
  this.client,
50
- KnownScript.Secp256k1Blake160,
51
- bytesFrom(hashCkb(this.publicKey)).slice(0, 20),
66
+ KnownScript.AnyoneCanPay,
67
+ secp256k1.script.args,
52
68
  ),
53
- ];
69
+ scriptType: "lock",
70
+ scriptSearchMode: "prefix",
71
+ withData: false,
72
+ })) {
73
+ if (count >= 10) {
74
+ break;
75
+ }
76
+ count += 1;
77
+
78
+ if (addresses.some(({ script }) => script.eq(cell.cellOutput.lock))) {
79
+ continue;
80
+ }
81
+
82
+ addresses.push(
83
+ Address.from({
84
+ prefix: this.client.addressPrefix,
85
+ script: cell.cellOutput.lock,
86
+ }),
87
+ );
88
+ }
89
+
90
+ return [secp256k1, ...addresses];
54
91
  }
55
92
 
56
- async prepareTransaction(txLike: TransactionLike): Promise<Transaction> {
93
+ async getRelatedScripts(
94
+ txLike: TransactionLike,
95
+ ): Promise<{ script: Script; cellDeps: CellDepInfo[] }[]> {
57
96
  const tx = Transaction.from(txLike);
58
- const { script } = await this.getRecommendedAddressObj();
59
- await tx.addCellDepsOfKnownScripts(
97
+
98
+ const secp256k1 = await this.getAddressObjSecp256k1();
99
+ const acp = await Script.fromKnownScript(
60
100
  this.client,
61
- KnownScript.Secp256k1Blake160,
101
+ KnownScript.AnyoneCanPay,
102
+ secp256k1.script.args,
103
+ );
104
+
105
+ const scripts: { script: Script; cellDeps: CellDepInfo[] }[] = [];
106
+ for (const input of tx.inputs) {
107
+ await input.completeExtraInfos(this.client);
108
+ if (!input.cellOutput) {
109
+ throw new Error("Unable to complete input");
110
+ }
111
+
112
+ const { lock } = input.cellOutput;
113
+ if (scripts.some(({ script }) => script.eq(lock))) {
114
+ continue;
115
+ }
116
+
117
+ if (lock.eq(secp256k1.script)) {
118
+ scripts.push({
119
+ script: lock,
120
+ cellDeps: (
121
+ await this.client.getKnownScript(KnownScript.Secp256k1Blake160)
122
+ ).cellDeps,
123
+ });
124
+ } else if (
125
+ lock.codeHash === acp.codeHash &&
126
+ lock.hashType === acp.hashType &&
127
+ lock.args.startsWith(acp.args)
128
+ ) {
129
+ scripts.push({
130
+ script: lock,
131
+ cellDeps: (await this.client.getKnownScript(KnownScript.AnyoneCanPay))
132
+ .cellDeps,
133
+ });
134
+ }
135
+ }
136
+
137
+ return scripts;
138
+ }
139
+
140
+ async prepareTransaction(txLike: TransactionLike): Promise<Transaction> {
141
+ const tx = Transaction.from(txLike);
142
+
143
+ await Promise.all(
144
+ (await this.getRelatedScripts(tx)).map(async ({ script, cellDeps }) => {
145
+ await tx.prepareSighashAllWitness(script, 65, this.client);
146
+ await tx.addCellDepInfos(this.client, cellDeps);
147
+ }),
62
148
  );
63
- await tx.prepareSighashAllWitness(script, 65, this.client);
64
149
  return tx;
65
150
  }
66
151
  }