@ckb-ccc/core 1.6.0 → 1.7.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 (104) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/dist/ckb/script.d.ts +2 -1
  3. package/dist/ckb/script.d.ts.map +1 -1
  4. package/dist/ckb/transaction.d.ts +70 -5
  5. package/dist/ckb/transaction.d.ts.map +1 -1
  6. package/dist/ckb/transaction.js +186 -53
  7. package/dist/client/client.d.ts +3 -1
  8. package/dist/client/client.d.ts.map +1 -1
  9. package/dist/client/client.js +4 -3
  10. package/dist/client/clientPublicMainnet.advanced.d.ts +2 -1
  11. package/dist/client/clientPublicMainnet.advanced.d.ts.map +1 -1
  12. package/dist/client/clientPublicMainnet.advanced.js +1 -1
  13. package/dist/client/clientPublicMainnet.d.ts +2 -1
  14. package/dist/client/clientPublicMainnet.d.ts.map +1 -1
  15. package/dist/client/clientPublicTestnet.advanced.d.ts +2 -1
  16. package/dist/client/clientPublicTestnet.advanced.d.ts.map +1 -1
  17. package/dist/client/clientPublicTestnet.advanced.js +1 -1
  18. package/dist/client/clientPublicTestnet.d.ts +2 -1
  19. package/dist/client/clientPublicTestnet.d.ts.map +1 -1
  20. package/dist/client/clientTypes.d.ts +0 -25
  21. package/dist/client/clientTypes.d.ts.map +1 -1
  22. package/dist/client/clientTypes.js +0 -27
  23. package/dist/client/index.d.ts +1 -0
  24. package/dist/client/index.d.ts.map +1 -1
  25. package/dist/client/index.js +1 -0
  26. package/dist/client/knownScript.d.ts +26 -0
  27. package/dist/client/knownScript.d.ts.map +1 -0
  28. package/dist/client/knownScript.js +27 -0
  29. package/dist/num/index.d.ts.map +1 -1
  30. package/dist/num/index.js +17 -1
  31. package/dist/signer/ckb/signerCkbPublicKey.d.ts.map +1 -1
  32. package/dist/signer/ckb/signerCkbPublicKey.js +1 -5
  33. package/dist/signer/nostr/index.d.ts +1 -0
  34. package/dist/signer/nostr/index.d.ts.map +1 -1
  35. package/dist/signer/nostr/index.js +1 -0
  36. package/dist/signer/nostr/signerNostr.d.ts +1 -1
  37. package/dist/signer/nostr/signerNostr.d.ts.map +1 -1
  38. package/dist/signer/nostr/signerNostr.js +8 -0
  39. package/dist/signer/nostr/signerNostrPrivateKey.d.ts +5 -7
  40. package/dist/signer/nostr/signerNostrPrivateKey.d.ts.map +1 -1
  41. package/dist/signer/nostr/signerNostrPrivateKey.js +6 -12
  42. package/dist/signer/nostr/signerNostrPublicKeyReadonly.d.ts +11 -0
  43. package/dist/signer/nostr/signerNostrPublicKeyReadonly.d.ts.map +1 -0
  44. package/dist/signer/nostr/signerNostrPublicKeyReadonly.js +22 -0
  45. package/dist.commonjs/ckb/script.d.ts +2 -1
  46. package/dist.commonjs/ckb/script.d.ts.map +1 -1
  47. package/dist.commonjs/ckb/transaction.d.ts +70 -5
  48. package/dist.commonjs/ckb/transaction.d.ts.map +1 -1
  49. package/dist.commonjs/ckb/transaction.js +282 -147
  50. package/dist.commonjs/client/client.d.ts +3 -1
  51. package/dist.commonjs/client/client.d.ts.map +1 -1
  52. package/dist.commonjs/client/client.js +4 -3
  53. package/dist.commonjs/client/clientPublicMainnet.advanced.d.ts +2 -1
  54. package/dist.commonjs/client/clientPublicMainnet.advanced.d.ts.map +1 -1
  55. package/dist.commonjs/client/clientPublicMainnet.advanced.js +21 -21
  56. package/dist.commonjs/client/clientPublicMainnet.d.ts +2 -1
  57. package/dist.commonjs/client/clientPublicMainnet.d.ts.map +1 -1
  58. package/dist.commonjs/client/clientPublicTestnet.advanced.d.ts +2 -1
  59. package/dist.commonjs/client/clientPublicTestnet.advanced.d.ts.map +1 -1
  60. package/dist.commonjs/client/clientPublicTestnet.advanced.js +21 -21
  61. package/dist.commonjs/client/clientPublicTestnet.d.ts +2 -1
  62. package/dist.commonjs/client/clientPublicTestnet.d.ts.map +1 -1
  63. package/dist.commonjs/client/clientTypes.d.ts +0 -25
  64. package/dist.commonjs/client/clientTypes.d.ts.map +1 -1
  65. package/dist.commonjs/client/clientTypes.js +1 -28
  66. package/dist.commonjs/client/index.d.ts +1 -0
  67. package/dist.commonjs/client/index.d.ts.map +1 -1
  68. package/dist.commonjs/client/index.js +1 -0
  69. package/dist.commonjs/client/knownScript.d.ts +26 -0
  70. package/dist.commonjs/client/knownScript.d.ts.map +1 -0
  71. package/dist.commonjs/client/knownScript.js +30 -0
  72. package/dist.commonjs/num/index.d.ts.map +1 -1
  73. package/dist.commonjs/num/index.js +17 -1
  74. package/dist.commonjs/signer/ckb/signerCkbPublicKey.d.ts.map +1 -1
  75. package/dist.commonjs/signer/ckb/signerCkbPublicKey.js +1 -5
  76. package/dist.commonjs/signer/nostr/index.d.ts +1 -0
  77. package/dist.commonjs/signer/nostr/index.d.ts.map +1 -1
  78. package/dist.commonjs/signer/nostr/index.js +1 -0
  79. package/dist.commonjs/signer/nostr/signerNostr.d.ts +1 -1
  80. package/dist.commonjs/signer/nostr/signerNostr.d.ts.map +1 -1
  81. package/dist.commonjs/signer/nostr/signerNostr.js +8 -0
  82. package/dist.commonjs/signer/nostr/signerNostrPrivateKey.d.ts +5 -7
  83. package/dist.commonjs/signer/nostr/signerNostrPrivateKey.d.ts.map +1 -1
  84. package/dist.commonjs/signer/nostr/signerNostrPrivateKey.js +6 -12
  85. package/dist.commonjs/signer/nostr/signerNostrPublicKeyReadonly.d.ts +11 -0
  86. package/dist.commonjs/signer/nostr/signerNostrPublicKeyReadonly.d.ts.map +1 -0
  87. package/dist.commonjs/signer/nostr/signerNostrPublicKeyReadonly.js +26 -0
  88. package/package.json +2 -2
  89. package/src/ckb/script.ts +2 -1
  90. package/src/ckb/transaction.ts +270 -62
  91. package/src/client/client.ts +5 -4
  92. package/src/client/clientPublicMainnet.advanced.ts +2 -1
  93. package/src/client/clientPublicMainnet.ts +2 -1
  94. package/src/client/clientPublicTestnet.advanced.ts +2 -1
  95. package/src/client/clientPublicTestnet.ts +2 -1
  96. package/src/client/clientTypes.ts +0 -28
  97. package/src/client/index.ts +1 -0
  98. package/src/client/knownScript.ts +27 -0
  99. package/src/num/index.ts +21 -1
  100. package/src/signer/ckb/signerCkbPublicKey.ts +3 -5
  101. package/src/signer/nostr/index.ts +1 -0
  102. package/src/signer/nostr/signerNostr.ts +3 -1
  103. package/src/signer/nostr/signerNostrPrivateKey.ts +7 -14
  104. package/src/signer/nostr/signerNostrPublicKeyReadonly.ts +29 -0
@@ -1,6 +1,12 @@
1
1
  import { Bytes, BytesLike, bytesFrom } from "../bytes/index.js";
2
2
  import type { ClientCollectableSearchKeyFilterLike } from "../client/clientTypes.advanced.js";
3
- import type { CellDepInfoLike, Client, KnownScript } from "../client/index.js";
3
+ import {
4
+ ClientBlockHeader,
5
+ type CellDepInfoLike,
6
+ type Client,
7
+ type ClientBlockHeaderLike,
8
+ } from "../client/index.js";
9
+ import { KnownScript } from "../client/knownScript.js";
4
10
  import {
5
11
  Zero,
6
12
  fixedPointFrom,
@@ -275,6 +281,127 @@ export class Cell {
275
281
  );
276
282
  }
277
283
 
284
+ get capacityFree() {
285
+ const occupiedSize = fixedPointFrom(
286
+ this.cellOutput.occupiedSize + bytesFrom(this.outputData).length,
287
+ );
288
+ return this.cellOutput.capacity - occupiedSize;
289
+ }
290
+
291
+ /**
292
+ * Occupied bytes of a cell on chain
293
+ * It's CellOutput.occupiedSize + bytesFrom(outputData).byteLength
294
+ */
295
+ get occupiedSize() {
296
+ return this.cellOutput.occupiedSize + bytesFrom(this.outputData).byteLength;
297
+ }
298
+
299
+ /**
300
+ * Gets confirmed Nervos DAO profit of a Cell
301
+ * It returns non-zero value only when the cell is in withdrawal phase 2
302
+ * See https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0023-dao-deposit-withdraw/0023-dao-deposit-withdraw.md
303
+ *
304
+ * @param client - A client for searching DAO related headers
305
+ * @returns Profit
306
+ *
307
+ * @example
308
+ * ```typescript
309
+ * const profit = await cell.getDaoProfit(client);
310
+ * ```
311
+ */
312
+ async getDaoProfit(client: Client): Promise<Num> {
313
+ if (!(await this.isNervosDao(client, "withdrew"))) {
314
+ return Zero;
315
+ }
316
+
317
+ const { depositHeader, withdrawHeader } =
318
+ await this.getNervosDaoInfo(client);
319
+ if (!withdrawHeader || !depositHeader) {
320
+ throw new Error(
321
+ `Unable to get headers of a Nervos DAO cell ${this.outPoint.txHash}:${this.outPoint.index.toString()}`,
322
+ );
323
+ }
324
+
325
+ return calcDaoProfit(this.capacityFree, depositHeader, withdrawHeader);
326
+ }
327
+
328
+ async isNervosDao(
329
+ client: Client,
330
+ phase?: "deposited" | "withdrew",
331
+ ): Promise<boolean> {
332
+ const { type } = this.cellOutput;
333
+
334
+ const daoType = await client.getKnownScript(KnownScript.NervosDao);
335
+ if (
336
+ !type ||
337
+ type.codeHash !== daoType.codeHash ||
338
+ type.hashType !== daoType.hashType
339
+ ) {
340
+ // Non Nervos DAO cell
341
+ return false;
342
+ }
343
+
344
+ const hasWithdrew = numFrom(this.outputData) !== Zero;
345
+ return (
346
+ !phase ||
347
+ (phase === "deposited" && !hasWithdrew) ||
348
+ (phase === "withdrew" && hasWithdrew)
349
+ );
350
+ }
351
+
352
+ async getNervosDaoInfo(client: Client): Promise<
353
+ // Non Nervos DAO cell
354
+ | {
355
+ depositHeader?: undefined;
356
+ withdrawHeader?: undefined;
357
+ }
358
+ // Deposited Nervos DAO cell
359
+ | {
360
+ depositHeader: ClientBlockHeader;
361
+ withdrawHeader?: undefined;
362
+ }
363
+ // Withdrew Nervos DAO cell
364
+ | {
365
+ depositHeader: ClientBlockHeader;
366
+ withdrawHeader: ClientBlockHeader;
367
+ }
368
+ > {
369
+ if (!(await this.isNervosDao(client))) {
370
+ // Non Nervos DAO cell
371
+ return {};
372
+ }
373
+
374
+ if (numFrom(this.outputData) === Zero) {
375
+ // Deposited Nervos DAO cell
376
+ const depositRes = await client.getCellWithHeader(this.outPoint);
377
+ if (!depositRes?.header) {
378
+ throw new Error(
379
+ `Unable to get header of a Nervos DAO deposited cell ${this.outPoint.txHash}:${this.outPoint.index.toString()}`,
380
+ );
381
+ }
382
+
383
+ return {
384
+ depositHeader: depositRes.header,
385
+ };
386
+ }
387
+
388
+ // Withdrew Nervos DAO cell
389
+ const [depositHeader, withdrawRes] = await Promise.all([
390
+ client.getHeaderByNumber(numFromBytes(this.outputData)),
391
+ client.getCellWithHeader(this.outPoint),
392
+ ]);
393
+ if (!withdrawRes?.header || !depositHeader) {
394
+ throw new Error(
395
+ `Unable to get headers of a Nervos DAO withdrew cell ${this.outPoint.txHash}:${this.outPoint.index.toString()}`,
396
+ );
397
+ }
398
+
399
+ return {
400
+ depositHeader,
401
+ withdrawHeader: withdrawRes.header,
402
+ };
403
+ }
404
+
278
405
  /**
279
406
  * Clone a Cell
280
407
  *
@@ -525,14 +652,29 @@ export class CellInput extends mol.Entity.Base<CellInputLike, CellInput>() {
525
652
  );
526
653
  }
527
654
 
655
+ async getCell(client: Client): Promise<Cell> {
656
+ await this.completeExtraInfos(client);
657
+ if (!this.cellOutput || !this.outputData) {
658
+ throw new Error("Unable to complete input");
659
+ }
660
+
661
+ return Cell.from({
662
+ outPoint: this.previousOutput,
663
+ cellOutput: this.cellOutput,
664
+ outputData: this.outputData,
665
+ });
666
+ }
667
+
528
668
  /**
529
- * Complete extra infos in the input. Like the output of the out point.
669
+ * Complete extra infos in the input. Including
670
+ * - Previous cell output
671
+ * - Previous cell data
530
672
  * The instance will be modified.
531
673
  *
532
674
  * @returns true if succeed.
533
675
  * @example
534
676
  * ```typescript
535
- * await cellInput.completeExtraInfos();
677
+ * await cellInput.completeExtraInfos(client);
536
678
  * ```
537
679
  */
538
680
  async completeExtraInfos(client: Client): Promise<void> {
@@ -549,6 +691,15 @@ export class CellInput extends mol.Entity.Base<CellInputLike, CellInput>() {
549
691
  this.outputData = cell.outputData;
550
692
  }
551
693
 
694
+ /**
695
+ * The extra capacity created when consume this input.
696
+ * This is usually NervosDAO interest, see https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0023-dao-deposit-withdraw/0023-dao-deposit-withdraw.md.
697
+ * And it can also be miners' income. (But this is not implemented yet)
698
+ */
699
+ async getExtraCapacity(client: Client): Promise<Num> {
700
+ return (await this.getCell(client)).getDaoProfit(client);
701
+ }
702
+
552
703
  clone(): CellInput {
553
704
  const cloned = super.clone();
554
705
  cloned.cellOutput = this.cellOutput;
@@ -701,11 +852,13 @@ export class WitnessArgs extends mol.Entity.Base<
701
852
  }
702
853
 
703
854
  /**
855
+ * Convert a bytes to a num.
856
+ *
704
857
  * @public
705
858
  */
706
859
  export function udtBalanceFrom(dataLike: BytesLike): Num {
707
860
  const data = bytesFrom(dataLike).slice(0, 16);
708
- return numFromBytes(data);
861
+ return data.length === 0 ? Zero : numFromBytes(data);
709
862
  }
710
863
 
711
864
  export const RawTransaction = mol.table({
@@ -1013,13 +1166,9 @@ export class Transaction extends mol.Entity.Base<
1013
1166
  for (let i = 0; i < this.witnesses.length; i += 1) {
1014
1167
  const input = this.inputs[i];
1015
1168
  if (input) {
1016
- await input.completeExtraInfos(client);
1017
-
1018
- if (!input.cellOutput) {
1019
- throw new Error("Unable to complete input");
1020
- }
1169
+ const { cellOutput } = await input.getCell(client);
1021
1170
 
1022
- if (!script.eq(input.cellOutput.lock)) {
1171
+ if (!script.eq(cellOutput.lock)) {
1023
1172
  continue;
1024
1173
  }
1025
1174
 
@@ -1064,15 +1213,11 @@ export class Transaction extends mol.Entity.Base<
1064
1213
  const script = Script.from({ ...scriptIdLike, args: "0x" });
1065
1214
 
1066
1215
  for (let i = 0; i < this.inputs.length; i += 1) {
1067
- const input = this.inputs[i];
1068
- await input.completeExtraInfos(client);
1069
- if (!input.cellOutput) {
1070
- throw new Error("Unable to complete input");
1071
- }
1216
+ const { cellOutput } = await this.inputs[i].getCell(client);
1072
1217
 
1073
1218
  if (
1074
- script.codeHash === input.cellOutput.lock.codeHash &&
1075
- script.hashType === input.cellOutput.lock.hashType
1219
+ script.codeHash === cellOutput.lock.codeHash &&
1220
+ script.hashType === cellOutput.lock.hashType
1076
1221
  ) {
1077
1222
  return i;
1078
1223
  }
@@ -1098,13 +1243,9 @@ export class Transaction extends mol.Entity.Base<
1098
1243
  const script = Script.from(scriptLike);
1099
1244
 
1100
1245
  for (let i = 0; i < this.inputs.length; i += 1) {
1101
- const input = this.inputs[i];
1102
- await input.completeExtraInfos(client);
1103
- if (!input.cellOutput) {
1104
- throw new Error("Unable to complete input");
1105
- }
1246
+ const { cellOutput } = await this.inputs[i].getCell(client);
1106
1247
 
1107
- if (script.eq(input.cellOutput.lock)) {
1248
+ if (script.eq(cellOutput.lock)) {
1108
1249
  return i;
1109
1250
  }
1110
1251
  }
@@ -1129,13 +1270,9 @@ export class Transaction extends mol.Entity.Base<
1129
1270
  const script = Script.from(scriptLike);
1130
1271
 
1131
1272
  for (let i = this.inputs.length - 1; i >= 0; i -= 1) {
1132
- const input = this.inputs[i];
1133
- await input.completeExtraInfos(client);
1134
- if (!input.cellOutput) {
1135
- throw new Error("Unable to complete input");
1136
- }
1273
+ const { cellOutput } = await this.inputs[i].getCell(client);
1137
1274
 
1138
- if (script.eq(input.cellOutput.lock)) {
1275
+ if (script.eq(cellOutput.lock)) {
1139
1276
  return i;
1140
1277
  }
1141
1278
  }
@@ -1276,6 +1413,10 @@ export class Transaction extends mol.Entity.Base<
1276
1413
  * ```
1277
1414
  */
1278
1415
  addInput(inputLike: CellInputLike): number {
1416
+ if (this.witnesses.length > this.inputs.length) {
1417
+ this.witnesses.splice(this.inputs.length, 0, "0x");
1418
+ }
1419
+
1279
1420
  return this.inputs.push(CellInput.from(inputLike));
1280
1421
  }
1281
1422
 
@@ -1365,6 +1506,21 @@ export class Transaction extends mol.Entity.Base<
1365
1506
  * ```
1366
1507
  */
1367
1508
  setWitnessArgsAt(index: number, witness: WitnessArgs): void {
1509
+ this.setWitnessAt(index, witness.toBytes());
1510
+ }
1511
+
1512
+ /**
1513
+ * Set witness at index
1514
+ *
1515
+ * @param index - The index of the witness.
1516
+ * @param witness - The witness to set.
1517
+ *
1518
+ * @example
1519
+ * ```typescript
1520
+ * await tx.setWitnessAt(0, witness);
1521
+ * ```
1522
+ */
1523
+ setWitnessAt(index: number, witness: HexLike): void {
1368
1524
  if (this.witnesses.length < index) {
1369
1525
  this.witnesses.push(
1370
1526
  ...Array.from(
@@ -1374,7 +1530,7 @@ export class Transaction extends mol.Entity.Base<
1374
1530
  );
1375
1531
  }
1376
1532
 
1377
- this.witnesses[index] = hexFrom(witness.toBytes());
1533
+ this.witnesses[index] = hexFrom(witness);
1378
1534
  }
1379
1535
 
1380
1536
  /**
@@ -1405,20 +1561,31 @@ export class Transaction extends mol.Entity.Base<
1405
1561
  this.setWitnessArgsAt(position, witness);
1406
1562
  }
1407
1563
 
1408
- async getInputsCapacity(client: Client): Promise<Num> {
1564
+ async getInputsCapacityExtra(client: Client): Promise<Num> {
1409
1565
  return reduceAsync(
1410
1566
  this.inputs,
1411
- async (acc, input) => {
1412
- await input.completeExtraInfos(client);
1413
- if (!input.cellOutput) {
1414
- throw new Error("Unable to complete input");
1415
- }
1416
- return acc + input.cellOutput.capacity;
1417
- },
1567
+ async (acc, input) => acc + (await input.getExtraCapacity(client)),
1418
1568
  numFrom(0),
1419
1569
  );
1420
1570
  }
1421
1571
 
1572
+ // This also includes extra amount
1573
+ async getInputsCapacity(client: Client): Promise<Num> {
1574
+ return (
1575
+ (await reduceAsync(
1576
+ this.inputs,
1577
+ async (acc, input) => {
1578
+ const {
1579
+ cellOutput: { capacity },
1580
+ } = await input.getCell(client);
1581
+
1582
+ return acc + capacity;
1583
+ },
1584
+ numFrom(0),
1585
+ )) + (await this.getInputsCapacityExtra(client))
1586
+ );
1587
+ }
1588
+
1422
1589
  getOutputsCapacity(): Num {
1423
1590
  return this.outputs.reduce(
1424
1591
  (acc, { capacity }) => acc + capacity,
@@ -1430,15 +1597,12 @@ export class Transaction extends mol.Entity.Base<
1430
1597
  return reduceAsync(
1431
1598
  this.inputs,
1432
1599
  async (acc, input) => {
1433
- await input.completeExtraInfos(client);
1434
- if (!input.cellOutput || !input.outputData) {
1435
- throw new Error("Unable to complete input");
1436
- }
1437
- if (!input.cellOutput.type?.eq(type)) {
1600
+ const { cellOutput, outputData } = await input.getCell(client);
1601
+ if (!cellOutput.type?.eq(type)) {
1438
1602
  return;
1439
1603
  }
1440
1604
 
1441
- return acc + udtBalanceFrom(input.outputData);
1605
+ return acc + udtBalanceFrom(outputData);
1442
1606
  },
1443
1607
  numFrom(0),
1444
1608
  );
@@ -1594,25 +1758,18 @@ export class Transaction extends mol.Entity.Base<
1594
1758
  from: Signer,
1595
1759
  filter?: ClientCollectableSearchKeyFilterLike,
1596
1760
  ): Promise<number> {
1597
- for await (const cell of from.findCells(
1761
+ const { addedCount, accumulated } = await this.completeInputs(
1762
+ from,
1598
1763
  filter ?? {
1599
1764
  scriptLenRange: [0, 1],
1600
1765
  outputDataLenRange: [0, 1],
1601
1766
  },
1767
+ () => undefined,
1602
1768
  true,
1603
- undefined,
1604
- 1,
1605
- )) {
1606
- if (
1607
- this.inputs.some(({ previousOutput }) =>
1608
- previousOutput.eq(cell.outPoint),
1609
- )
1610
- ) {
1611
- continue;
1612
- }
1769
+ );
1613
1770
 
1614
- this.addInput(cell);
1615
- return 1;
1771
+ if (accumulated === undefined) {
1772
+ return addedCount;
1616
1773
  }
1617
1774
 
1618
1775
  throw new Error(`Insufficient CKB, need at least one new cell`);
@@ -1629,13 +1786,13 @@ export class Transaction extends mol.Entity.Base<
1629
1786
  return this.completeInputsAddOne(from, filter);
1630
1787
  }
1631
1788
 
1632
- async fee(client: Client): Promise<Num> {
1789
+ async getFee(client: Client): Promise<Num> {
1633
1790
  return (await this.getInputsCapacity(client)) - this.getOutputsCapacity();
1634
1791
  }
1635
1792
 
1636
- async feeRate(client: Client): Promise<Num> {
1793
+ async getFeeRate(client: Client): Promise<Num> {
1637
1794
  return (
1638
- ((await this.fee(client)) * numFrom(1000)) /
1795
+ ((await this.getFee(client)) * numFrom(1000)) /
1639
1796
  numFrom(this.toBytes().length + 4)
1640
1797
  );
1641
1798
  }
@@ -1686,7 +1843,7 @@ export class Transaction extends mol.Entity.Base<
1686
1843
  // The initial fee is calculated based on prepared transaction
1687
1844
  leastFee = tx.estimateFee(feeRate);
1688
1845
  }
1689
- const fee = await tx.fee(from.client);
1846
+ const fee = await tx.getFee(from.client);
1690
1847
  // The extra capacity paid the fee without a change
1691
1848
  if (fee === leastFee) {
1692
1849
  this.copy(tx);
@@ -1700,7 +1857,7 @@ export class Transaction extends mol.Entity.Base<
1700
1857
  continue;
1701
1858
  }
1702
1859
 
1703
- if ((await tx.fee(from.client)) !== leastFee) {
1860
+ if ((await tx.getFee(from.client)) !== leastFee) {
1704
1861
  throw new Error(
1705
1862
  "The change function doesn't use all available capacity",
1706
1863
  );
@@ -1779,3 +1936,54 @@ export class Transaction extends mol.Entity.Base<
1779
1936
  );
1780
1937
  }
1781
1938
  }
1939
+
1940
+ /**
1941
+ * Calculate Nervos DAO profit between two blocks
1942
+ */
1943
+ export function calcDaoProfit(
1944
+ profitableCapacity: NumLike,
1945
+ depositHeaderLike: ClientBlockHeaderLike,
1946
+ withdrawHeaderLike: ClientBlockHeaderLike,
1947
+ ): Num {
1948
+ const depositHeader = ClientBlockHeader.from(depositHeaderLike);
1949
+ const withdrawHeader = ClientBlockHeader.from(withdrawHeaderLike);
1950
+
1951
+ const profitableSize = numFrom(profitableCapacity);
1952
+
1953
+ return (
1954
+ (profitableSize * withdrawHeader.dao.ar) / depositHeader.dao.ar -
1955
+ profitableSize
1956
+ );
1957
+ }
1958
+
1959
+ /**
1960
+ * Calculate claimable epoch for Nervos DAO withdrawal
1961
+ * See https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0023-dao-deposit-withdraw/0023-dao-deposit-withdraw.md
1962
+ */
1963
+ export function calcDaoClaimEpoch(
1964
+ depositHeader: ClientBlockHeaderLike,
1965
+ withdrawHeader: ClientBlockHeaderLike,
1966
+ ): Epoch {
1967
+ const depositEpoch = ClientBlockHeader.from(depositHeader).epoch;
1968
+ const withdrawEpoch = ClientBlockHeader.from(withdrawHeader).epoch;
1969
+ const intDiff = withdrawEpoch[0] - depositEpoch[0];
1970
+ // deposit[1] withdraw[1]
1971
+ // ---------- <= -----------
1972
+ // deposit[2] withdraw[2]
1973
+ if (
1974
+ intDiff % numFrom(180) !== numFrom(0) ||
1975
+ depositEpoch[1] * withdrawEpoch[2] <= depositEpoch[2] * withdrawEpoch[1]
1976
+ ) {
1977
+ return [
1978
+ depositEpoch[0] + (intDiff / numFrom(180) + numFrom(1)) * numFrom(180),
1979
+ depositEpoch[1],
1980
+ depositEpoch[2],
1981
+ ];
1982
+ }
1983
+
1984
+ return [
1985
+ depositEpoch[0] + (intDiff / numFrom(180)) * numFrom(180),
1986
+ depositEpoch[1],
1987
+ depositEpoch[2],
1988
+ ];
1989
+ }
@@ -33,10 +33,10 @@ import {
33
33
  ClientTransactionResponse,
34
34
  ErrorClientMaxFeeRateExceeded,
35
35
  ErrorClientWaitTransactionTimeout,
36
- KnownScript,
37
36
  OutputsValidator,
38
37
  ScriptInfo,
39
38
  } from "./clientTypes.js";
39
+ import { KnownScript } from "./knownScript.js";
40
40
 
41
41
  function hasHeaderConfirmed(header: ClientBlockHeader): boolean {
42
42
  return numFrom(Date.now()) - header.timestamp >= CONFIRMED_BLOCK_TIME;
@@ -295,6 +295,7 @@ export abstract class Client {
295
295
 
296
296
  /**
297
297
  * Find cells by search key designed for collectable cells.
298
+ * The result also includes cached cells, the order param only works for cells fetched from RPC.
298
299
  *
299
300
  * @param keyLike - The search key.
300
301
  * @returns A async generator for yielding cells.
@@ -596,9 +597,9 @@ export abstract class Client {
596
597
  const tx = Transaction.from(transaction);
597
598
 
598
599
  const maxFeeRate = numFrom(options?.maxFeeRate ?? DEFAULT_MAX_FEE_RATE);
599
- const fee = await tx.feeRate(this);
600
- if (maxFeeRate > Zero && fee > maxFeeRate) {
601
- throw new ErrorClientMaxFeeRateExceeded(maxFeeRate, fee);
600
+ const feeRate = await tx.getFeeRate(this);
601
+ if (maxFeeRate > Zero && feeRate > maxFeeRate) {
602
+ throw new ErrorClientMaxFeeRateExceeded(maxFeeRate, feeRate);
602
603
  }
603
604
 
604
605
  const txHash = await this.sendTransactionNoCache(tx, validator);
@@ -1,4 +1,5 @@
1
- import { KnownScript, ScriptInfoLike } from "./clientTypes.js";
1
+ import { ScriptInfoLike } from "./clientTypes.js";
2
+ import { KnownScript } from "./knownScript.js";
2
3
 
3
4
  export const MAINNET_SCRIPTS: Record<KnownScript, ScriptInfoLike | undefined> =
4
5
  Object.freeze({
@@ -1,7 +1,8 @@
1
1
  import WebSocket from "isomorphic-ws";
2
2
  import { MAINNET_SCRIPTS } from "./clientPublicMainnet.advanced.js";
3
- import { KnownScript, ScriptInfo, ScriptInfoLike } from "./clientTypes.js";
3
+ import { ScriptInfo, ScriptInfoLike } from "./clientTypes.js";
4
4
  import { ClientJsonRpc, ClientJsonRpcConfig } from "./jsonRpc/index.js";
5
+ import { KnownScript } from "./knownScript.js";
5
6
 
6
7
  /**
7
8
  * @public
@@ -1,4 +1,5 @@
1
- import { KnownScript, ScriptInfoLike } from "./clientTypes.js";
1
+ import { ScriptInfoLike } from "./clientTypes.js";
2
+ import { KnownScript } from "./knownScript.js";
2
3
 
3
4
  export const TESTNET_SCRIPTS: Record<KnownScript, ScriptInfoLike> =
4
5
  Object.freeze({
@@ -1,7 +1,8 @@
1
1
  import WebSocket from "isomorphic-ws";
2
2
  import { TESTNET_SCRIPTS } from "./clientPublicTestnet.advanced.js";
3
- import { KnownScript, ScriptInfo, ScriptInfoLike } from "./clientTypes.js";
3
+ import { ScriptInfo, ScriptInfoLike } from "./clientTypes.js";
4
4
  import { ClientJsonRpc, ClientJsonRpcConfig } from "./jsonRpc/index.js";
5
+ import { KnownScript } from "./knownScript.js";
5
6
 
6
7
  /**
7
8
  * @public
@@ -24,34 +24,6 @@ import {
24
24
  clientSearchKeyRangeFrom,
25
25
  } from "./clientTypes.advanced.js";
26
26
 
27
- /**
28
- * @public
29
- */
30
- export enum KnownScript {
31
- NervosDao = "NervosDao",
32
- Secp256k1Blake160 = "Secp256k1Blake160",
33
- Secp256k1Multisig = "Secp256k1Multisig",
34
- AnyoneCanPay = "AnyoneCanPay",
35
- TypeId = "TypeId",
36
- XUdt = "XUdt",
37
- JoyId = "JoyId",
38
- COTA = "COTA",
39
- PWLock = "PWLock",
40
- OmniLock = "OmniLock",
41
- NostrLock = "NostrLock",
42
- UniqueType = "UniqueType",
43
-
44
- // ckb-proxy-locks https://github.com/ckb-devrel/ckb-proxy-locks
45
- AlwaysSuccess = "AlwaysSuccess",
46
- InputTypeProxyLock = "InputTypeProxyLock",
47
- OutputTypeProxyLock = "OutputTypeProxyLock",
48
- LockProxyLock = "LockProxyLock",
49
- SingleUseLock = "SingleUseLock",
50
- TypeBurnLock = "TypeBurnLock",
51
- EasyToDiscoverType = "EasyToDiscoverType",
52
- TimeLock = "TimeLock",
53
- }
54
-
55
27
  /**
56
28
  * @public
57
29
  */
@@ -4,3 +4,4 @@ export * from "./clientPublicMainnet.js";
4
4
  export * from "./clientPublicTestnet.js";
5
5
  export * from "./clientTypes.js";
6
6
  export * from "./jsonRpc/index.js";
7
+ export * from "./knownScript.js";
@@ -0,0 +1,27 @@
1
+ /**
2
+ * @public
3
+ */
4
+ export enum KnownScript {
5
+ NervosDao = "NervosDao",
6
+ Secp256k1Blake160 = "Secp256k1Blake160",
7
+ Secp256k1Multisig = "Secp256k1Multisig",
8
+ AnyoneCanPay = "AnyoneCanPay",
9
+ TypeId = "TypeId",
10
+ XUdt = "XUdt",
11
+ JoyId = "JoyId",
12
+ COTA = "COTA",
13
+ PWLock = "PWLock",
14
+ OmniLock = "OmniLock",
15
+ NostrLock = "NostrLock",
16
+ UniqueType = "UniqueType",
17
+
18
+ // ckb-proxy-locks https://github.com/ckb-devrel/ckb-proxy-locks
19
+ AlwaysSuccess = "AlwaysSuccess",
20
+ InputTypeProxyLock = "InputTypeProxyLock",
21
+ OutputTypeProxyLock = "OutputTypeProxyLock",
22
+ LockProxyLock = "LockProxyLock",
23
+ SingleUseLock = "SingleUseLock",
24
+ TypeBurnLock = "TypeBurnLock",
25
+ EasyToDiscoverType = "EasyToDiscoverType",
26
+ TimeLock = "TimeLock",
27
+ }
package/src/num/index.ts CHANGED
@@ -154,11 +154,31 @@ export function numLeToBytes(val: NumLike, bytes?: number): Bytes {
154
154
  * ```
155
155
  */
156
156
  export function numBeToBytes(val: NumLike, bytes?: number): Bytes {
157
- const rawBytes = bytesFrom(numFrom(val).toString(16));
157
+ let num = numFrom(val);
158
+ if (num < numFrom(0)) {
159
+ if (bytes == null) {
160
+ throw Error(
161
+ "negative number can not be serialized without knowing bytes length",
162
+ );
163
+ }
164
+
165
+ // 0x100............00 - abs(num)
166
+ // | . bytes * 8 .|
167
+ // 2's complement for negative number
168
+ num = (numFrom(1) << (numFrom(8) * numFrom(bytes))) + num;
169
+ if (num < 0) {
170
+ throw Error("negative number underflow");
171
+ }
172
+ }
173
+
174
+ const rawBytes = bytesFrom(num.toString(16));
158
175
  if (bytes == null) {
159
176
  return rawBytes;
160
177
  }
161
178
 
179
+ if (rawBytes.length > bytes) {
180
+ throw Error("number overflow");
181
+ }
162
182
  return bytesConcat("00".repeat(bytes - rawBytes.length), rawBytes);
163
183
  }
164
184
 
@@ -104,12 +104,10 @@ export class SignerCkbPublicKey extends Signer {
104
104
 
105
105
  const scripts: { script: Script; cellDeps: CellDepInfo[] }[] = [];
106
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
- }
107
+ const {
108
+ cellOutput: { lock },
109
+ } = await input.getCell(this.client);
111
110
 
112
- const { lock } = input.cellOutput;
113
111
  if (scripts.some(({ script }) => script.eq(lock))) {
114
112
  continue;
115
113
  }
@@ -1,3 +1,4 @@
1
1
  export * from "./signerNostr.js";
2
2
  export * from "./signerNostrPrivateKey.js";
3
+ export * from "./signerNostrPublicKeyReadonly.js";
3
4
  export * from "./verify.js";