@ckb-ccc/core 1.5.0 → 1.6.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 (83) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/ckb/transaction.d.ts +57 -4
  3. package/dist/ckb/transaction.d.ts.map +1 -1
  4. package/dist/ckb/transaction.js +83 -26
  5. package/dist/client/cache/cache.d.ts +67 -11
  6. package/dist/client/cache/cache.d.ts.map +1 -1
  7. package/dist/client/cache/cache.js +94 -9
  8. package/dist/client/cache/memory.advanced.d.ts +2 -2
  9. package/dist/client/cache/memory.advanced.d.ts.map +1 -1
  10. package/dist/client/cache/memory.advanced.js +19 -7
  11. package/dist/client/cache/memory.d.ts +24 -7
  12. package/dist/client/cache/memory.d.ts.map +1 -1
  13. package/dist/client/cache/memory.js +76 -18
  14. package/dist/client/client.d.ts +27 -6
  15. package/dist/client/client.d.ts.map +1 -1
  16. package/dist/client/client.js +113 -22
  17. package/dist/client/clientPublicMainnet.d.ts.map +1 -1
  18. package/dist/client/clientPublicMainnet.js +1 -6
  19. package/dist/client/clientTypes.advanced.d.ts +3 -0
  20. package/dist/client/clientTypes.advanced.d.ts.map +1 -1
  21. package/dist/client/clientTypes.advanced.js +3 -0
  22. package/dist/client/clientTypes.d.ts +110 -13
  23. package/dist/client/clientTypes.d.ts.map +1 -1
  24. package/dist/client/clientTypes.js +118 -4
  25. package/dist/client/jsonRpc/client.d.ts +4 -4
  26. package/dist/client/jsonRpc/client.d.ts.map +1 -1
  27. package/dist/client/jsonRpc/client.js +4 -4
  28. package/dist/client/jsonRpc/transformers.js +3 -3
  29. package/dist/jsonRpc/transports/webSocket.d.ts.map +1 -1
  30. package/dist/jsonRpc/transports/webSocket.js +7 -3
  31. package/dist/molecule/predefined.d.ts +10 -10
  32. package/dist/molecule/predefined.d.ts.map +1 -1
  33. package/dist/utils/index.d.ts +4 -0
  34. package/dist/utils/index.d.ts.map +1 -1
  35. package/dist/utils/index.js +13 -1
  36. package/dist.commonjs/advanced.js +17 -7
  37. package/dist.commonjs/ckb/transaction.d.ts +57 -4
  38. package/dist.commonjs/ckb/transaction.d.ts.map +1 -1
  39. package/dist.commonjs/ckb/transaction.js +83 -26
  40. package/dist.commonjs/client/cache/cache.d.ts +67 -11
  41. package/dist.commonjs/client/cache/cache.d.ts.map +1 -1
  42. package/dist.commonjs/client/cache/cache.js +94 -9
  43. package/dist.commonjs/client/cache/memory.advanced.d.ts +2 -2
  44. package/dist.commonjs/client/cache/memory.advanced.d.ts.map +1 -1
  45. package/dist.commonjs/client/cache/memory.advanced.js +19 -7
  46. package/dist.commonjs/client/cache/memory.d.ts +24 -7
  47. package/dist.commonjs/client/cache/memory.d.ts.map +1 -1
  48. package/dist.commonjs/client/cache/memory.js +75 -17
  49. package/dist.commonjs/client/client.d.ts +27 -6
  50. package/dist.commonjs/client/client.d.ts.map +1 -1
  51. package/dist.commonjs/client/client.js +111 -20
  52. package/dist.commonjs/client/clientPublicMainnet.d.ts.map +1 -1
  53. package/dist.commonjs/client/clientPublicMainnet.js +1 -6
  54. package/dist.commonjs/client/clientTypes.advanced.d.ts +3 -0
  55. package/dist.commonjs/client/clientTypes.advanced.d.ts.map +1 -1
  56. package/dist.commonjs/client/clientTypes.advanced.js +4 -0
  57. package/dist.commonjs/client/clientTypes.d.ts +110 -13
  58. package/dist.commonjs/client/clientTypes.d.ts.map +1 -1
  59. package/dist.commonjs/client/clientTypes.js +123 -4
  60. package/dist.commonjs/client/jsonRpc/client.d.ts +4 -4
  61. package/dist.commonjs/client/jsonRpc/client.d.ts.map +1 -1
  62. package/dist.commonjs/client/jsonRpc/client.js +4 -4
  63. package/dist.commonjs/client/jsonRpc/transformers.js +2 -2
  64. package/dist.commonjs/index.js +17 -7
  65. package/dist.commonjs/jsonRpc/transports/webSocket.d.ts.map +1 -1
  66. package/dist.commonjs/jsonRpc/transports/webSocket.js +7 -3
  67. package/dist.commonjs/molecule/index.js +17 -7
  68. package/dist.commonjs/utils/index.d.ts +4 -0
  69. package/dist.commonjs/utils/index.d.ts.map +1 -1
  70. package/dist.commonjs/utils/index.js +13 -0
  71. package/package.json +1 -1
  72. package/src/ckb/transaction.ts +112 -41
  73. package/src/client/cache/cache.ts +126 -13
  74. package/src/client/cache/memory.advanced.ts +24 -7
  75. package/src/client/cache/memory.ts +130 -30
  76. package/src/client/client.ts +170 -27
  77. package/src/client/clientPublicMainnet.ts +1 -6
  78. package/src/client/clientTypes.advanced.ts +4 -0
  79. package/src/client/clientTypes.ts +224 -33
  80. package/src/client/jsonRpc/client.ts +11 -9
  81. package/src/client/jsonRpc/transformers.ts +2 -2
  82. package/src/jsonRpc/transports/webSocket.ts +17 -13
  83. package/src/utils/index.ts +14 -1
@@ -9,11 +9,16 @@ import {
9
9
  } from "../ckb/index.js";
10
10
  import { Zero } from "../fixedPoint/index.js";
11
11
  import { Hex, HexLike, hexFrom } from "../hex/index.js";
12
- import { Num, NumLike, numFrom, numMax } from "../num/index.js";
12
+ import { Num, NumLike, numFrom, numMax, numMin } from "../num/index.js";
13
13
  import { reduceAsync, sleep } from "../utils/index.js";
14
14
  import { ClientCache } from "./cache/index.js";
15
15
  import { ClientCacheMemory } from "./cache/memory.js";
16
- import { ClientCollectableSearchKeyLike } from "./clientTypes.advanced.js";
16
+ import {
17
+ CONFIRMED_BLOCK_TIME,
18
+ ClientCollectableSearchKeyLike,
19
+ DEFAULT_MAX_FEE_RATE,
20
+ DEFAULT_MIN_FEE_RATE,
21
+ } from "./clientTypes.advanced.js";
17
22
  import {
18
23
  CellDepInfo,
19
24
  CellDepInfoLike,
@@ -26,12 +31,17 @@ import {
26
31
  ClientIndexerSearchKeyLike,
27
32
  ClientIndexerSearchKeyTransactionLike,
28
33
  ClientTransactionResponse,
34
+ ErrorClientMaxFeeRateExceeded,
29
35
  ErrorClientWaitTransactionTimeout,
30
36
  KnownScript,
31
37
  OutputsValidator,
32
38
  ScriptInfo,
33
39
  } from "./clientTypes.js";
34
40
 
41
+ function hasHeaderConfirmed(header: ClientBlockHeader): boolean {
42
+ return numFrom(Date.now()) - header.timestamp >= CONFIRMED_BLOCK_TIME;
43
+ }
44
+
35
45
  /**
36
46
  * @public
37
47
  */
@@ -50,30 +60,113 @@ export abstract class Client {
50
60
  abstract getFeeRateStatistics(
51
61
  blockRange?: NumLike,
52
62
  ): Promise<{ mean: Num; median: Num }>;
53
- async getFeeRate(blockRange?: NumLike): Promise<Num> {
54
- return numMax((await this.getFeeRateStatistics(blockRange)).median, 1000);
63
+ async getFeeRate(
64
+ blockRange?: NumLike,
65
+ options?: { maxFeeRate?: NumLike },
66
+ ): Promise<Num> {
67
+ const feeRate = numMax(
68
+ (await this.getFeeRateStatistics(blockRange)).median,
69
+ DEFAULT_MIN_FEE_RATE,
70
+ );
71
+
72
+ const maxFeeRate = numFrom(options?.maxFeeRate ?? DEFAULT_MAX_FEE_RATE);
73
+ if (maxFeeRate === Zero) {
74
+ return feeRate;
75
+ }
76
+
77
+ return numMin(feeRate, maxFeeRate);
55
78
  }
56
79
 
57
80
  abstract getTip(): Promise<Num>;
58
81
  abstract getTipHeader(verbosity?: number | null): Promise<ClientBlockHeader>;
59
- abstract getBlockByNumber(
82
+ abstract getBlockByNumberNoCache(
60
83
  blockNumber: NumLike,
61
84
  verbosity?: number | null,
62
85
  withCycles?: boolean | null,
63
86
  ): Promise<ClientBlock | undefined>;
64
- abstract getBlockByHash(
87
+ abstract getBlockByHashNoCache(
65
88
  blockHash: HexLike,
66
89
  verbosity?: number | null,
67
90
  withCycles?: boolean | null,
68
91
  ): Promise<ClientBlock | undefined>;
69
- abstract getHeaderByNumber(
92
+ abstract getHeaderByNumberNoCache(
70
93
  blockNumber: NumLike,
71
94
  verbosity?: number | null,
72
95
  ): Promise<ClientBlockHeader | undefined>;
73
- abstract getHeaderByHash(
96
+ abstract getHeaderByHashNoCache(
74
97
  blockHash: HexLike,
75
98
  verbosity?: number | null,
76
99
  ): Promise<ClientBlockHeader | undefined>;
100
+ async getBlockByNumber(
101
+ blockNumber: NumLike,
102
+ verbosity?: number | null,
103
+ withCycles?: boolean | null,
104
+ ): Promise<ClientBlock | undefined> {
105
+ const block = await this.cache.getBlockByNumber(blockNumber);
106
+ if (block) {
107
+ return block;
108
+ }
109
+
110
+ const res = await this.getBlockByNumberNoCache(
111
+ blockNumber,
112
+ verbosity,
113
+ withCycles,
114
+ );
115
+ if (res && hasHeaderConfirmed(res.header)) {
116
+ await this.cache.recordBlocks(res);
117
+ }
118
+ return res;
119
+ }
120
+ async getBlockByHash(
121
+ blockHash: HexLike,
122
+ verbosity?: number | null,
123
+ withCycles?: boolean | null,
124
+ ): Promise<ClientBlock | undefined> {
125
+ const block = await this.cache.getBlockByHash(blockHash);
126
+ if (block) {
127
+ return block;
128
+ }
129
+
130
+ const res = await this.getBlockByHashNoCache(
131
+ blockHash,
132
+ verbosity,
133
+ withCycles,
134
+ );
135
+ if (res && hasHeaderConfirmed(res.header)) {
136
+ await this.cache.recordBlocks(res);
137
+ }
138
+ return res;
139
+ }
140
+ async getHeaderByNumber(
141
+ blockNumber: NumLike,
142
+ verbosity?: number | null,
143
+ ): Promise<ClientBlockHeader | undefined> {
144
+ const header = await this.cache.getHeaderByNumber(blockNumber);
145
+ if (header) {
146
+ return header;
147
+ }
148
+
149
+ const res = await this.getHeaderByNumberNoCache(blockNumber, verbosity);
150
+ if (res && hasHeaderConfirmed(res)) {
151
+ await this.cache.recordHeaders(res);
152
+ }
153
+ return res;
154
+ }
155
+ async getHeaderByHash(
156
+ blockHash: HexLike,
157
+ verbosity?: number | null,
158
+ ): Promise<ClientBlockHeader | undefined> {
159
+ const header = await this.cache.getHeaderByHash(blockHash);
160
+ if (header) {
161
+ return header;
162
+ }
163
+
164
+ const res = await this.getHeaderByHashNoCache(blockHash, verbosity);
165
+ if (res && hasHeaderConfirmed(res)) {
166
+ await this.cache.recordHeaders(res);
167
+ }
168
+ return res;
169
+ }
77
170
 
78
171
  abstract estimateCycles(transaction: TransactionLike): Promise<Num>;
79
172
  abstract sendTransactionDry(
@@ -97,25 +190,47 @@ export abstract class Client {
97
190
  return cached;
98
191
  }
99
192
 
100
- const transaction = await this.getTransactionNoCache(outPoint.txHash);
193
+ const transaction = await this.getTransaction(outPoint.txHash);
101
194
  if (!transaction) {
102
195
  return;
103
196
  }
104
-
105
- const index = Number(numFrom(outPoint.index));
106
- if (index >= transaction.transaction.outputs.length) {
197
+ const output = transaction.transaction.getOutput(outPoint.index);
198
+ if (!output) {
107
199
  return;
108
200
  }
109
201
 
110
202
  const cell = Cell.from({
111
203
  outPoint,
112
- cellOutput: transaction.transaction.outputs[index],
113
- outputData: transaction.transaction.outputsData[index] ?? "0x",
204
+ ...output,
114
205
  });
115
206
  await this.cache.recordCells(cell);
116
207
  return cell;
117
208
  }
118
209
 
210
+ async getCellWithHeader(
211
+ outPointLike: OutPointLike,
212
+ ): Promise<{ cell: Cell; header?: ClientBlockHeader } | undefined> {
213
+ const outPoint = OutPoint.from(outPointLike);
214
+
215
+ const res = await this.getTransactionWithHeader(outPoint.txHash);
216
+ if (!res) {
217
+ return;
218
+ }
219
+ const { transaction, header } = res;
220
+
221
+ const output = transaction.transaction.getOutput(outPoint.index);
222
+ if (!output) {
223
+ return;
224
+ }
225
+
226
+ const cell = Cell.from({
227
+ outPoint,
228
+ ...output,
229
+ });
230
+ await this.cache.recordCells(cell);
231
+ return { cell, header };
232
+ }
233
+
119
234
  abstract getCellLiveNoCache(
120
235
  outPointLike: OutPointLike,
121
236
  withData?: boolean | null,
@@ -476,14 +591,19 @@ export abstract class Client {
476
591
  async sendTransaction(
477
592
  transaction: TransactionLike,
478
593
  validator?: OutputsValidator,
594
+ options?: { maxFeeRate?: NumLike },
479
595
  ): Promise<Hex> {
480
596
  const tx = Transaction.from(transaction);
481
597
 
598
+ 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);
602
+ }
603
+
482
604
  const txHash = await this.sendTransactionNoCache(tx, validator);
483
605
 
484
- await this.cache.recordTransactions(tx);
485
606
  await this.cache.markTransactions(tx);
486
-
487
607
  return txHash;
488
608
  }
489
609
 
@@ -492,25 +612,48 @@ export abstract class Client {
492
612
  ): Promise<ClientTransactionResponse | undefined> {
493
613
  const txHash = hexFrom(txHashLike);
494
614
  const res = await this.getTransactionNoCache(txHash);
495
- if (res?.transaction) {
615
+ if (res) {
616
+ await this.cache.recordTransactionResponses(res);
496
617
  return res;
497
618
  }
498
619
 
499
- const tx = await this.cache.getTransaction(txHash);
500
- if (!tx) {
501
- return;
620
+ return this.cache.getTransactionResponse(txHash);
621
+ }
622
+
623
+ /**
624
+ * This method gets specified transaction with its block header (if existed).
625
+ * This is mainly for caching because we need the header to test if we can safely trust the cached tx status.
626
+ * @param txHashLike
627
+ */
628
+ async getTransactionWithHeader(
629
+ txHashLike: HexLike,
630
+ ): Promise<
631
+ | { transaction: ClientTransactionResponse; header?: ClientBlockHeader }
632
+ | undefined
633
+ > {
634
+ const txHash = hexFrom(txHashLike);
635
+ const tx = await this.cache.getTransactionResponse(txHash);
636
+ if (tx?.blockHash) {
637
+ const header = await this.getHeaderByHash(tx.blockHash);
638
+ if (header && hasHeaderConfirmed(header)) {
639
+ return {
640
+ transaction: tx,
641
+ header,
642
+ };
643
+ }
502
644
  }
503
645
 
646
+ const res = await this.getTransactionNoCache(txHash);
504
647
  if (!res) {
505
- return {
506
- transaction: tx,
507
- status: "sent",
508
- };
648
+ return;
509
649
  }
510
650
 
651
+ await this.cache.recordTransactionResponses(res);
511
652
  return {
512
- ...res,
513
- transaction: tx,
653
+ transaction: res,
654
+ header: res.blockHash
655
+ ? await this.getHeaderByHash(res.blockHash)
656
+ : undefined,
514
657
  };
515
658
  }
516
659
 
@@ -552,7 +695,7 @@ export abstract class Client {
552
695
  }
553
696
 
554
697
  if (Date.now() - startTime + interval >= timeout) {
555
- throw new ErrorClientWaitTransactionTimeout();
698
+ throw new ErrorClientWaitTransactionTimeout(timeout);
556
699
  }
557
700
  await sleep(interval);
558
701
  }
@@ -28,13 +28,8 @@ export class ClientPublicMainnet extends ClientJsonRpc {
28
28
  "wss://mainnet.ckb.dev/ws",
29
29
  "https://mainnet.ckb.dev/",
30
30
  "https://mainnet.ckbapp.dev/",
31
- "https://rpc.ankr.com/nervos_ckb",
32
31
  ]
33
- : [
34
- "https://mainnet.ckb.dev/",
35
- "https://mainnet.ckbapp.dev/",
36
- "https://rpc.ankr.com/nervos_ckb",
37
- ]),
32
+ : ["https://mainnet.ckb.dev/", "https://mainnet.ckbapp.dev/"]),
38
33
  },
39
34
  );
40
35
  }
@@ -2,6 +2,10 @@ 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
+ export const DEFAULT_MAX_FEE_RATE = numFrom(10000000);
7
+ export const DEFAULT_MIN_FEE_RATE = numFrom(1000);
8
+
5
9
  export function clientSearchKeyRangeFrom([a, b]: [NumLike, NumLike]): [
6
10
  Num,
7
11
  Num,
@@ -3,6 +3,7 @@ import {
3
3
  CellDep,
4
4
  CellDepLike,
5
5
  Epoch,
6
+ EpochLike,
6
7
  HashType,
7
8
  HashTypeLike,
8
9
  OutPoint,
@@ -10,6 +11,8 @@ import {
10
11
  Script,
11
12
  ScriptLike,
12
13
  Transaction,
14
+ TransactionLike,
15
+ epochFrom,
13
16
  hashTypeFrom,
14
17
  } from "../ckb/index.js";
15
18
  import { Hex, HexLike, hexFrom } from "../hex/index.js";
@@ -67,6 +70,10 @@ export class CellDepInfo {
67
70
  ) {}
68
71
 
69
72
  static from(cellDepInfoLike: CellDepInfoLike): CellDepInfo {
73
+ if (cellDepInfoLike instanceof CellDepInfo) {
74
+ return cellDepInfoLike;
75
+ }
76
+
70
77
  return new CellDepInfo(
71
78
  CellDep.from(cellDepInfoLike.cellDep),
72
79
  apply(Script.from, cellDepInfoLike.type),
@@ -94,6 +101,10 @@ export class ScriptInfo {
94
101
  ) {}
95
102
 
96
103
  static from(scriptInfoLike: ScriptInfoLike): ScriptInfo {
104
+ if (scriptInfoLike instanceof ScriptInfo) {
105
+ return scriptInfoLike;
106
+ }
107
+
97
108
  return new ScriptInfo(
98
109
  hexFrom(scriptInfoLike.codeHash),
99
110
  hashTypeFrom(scriptInfoLike.hashType),
@@ -120,15 +131,59 @@ export type TransactionStatus =
120
131
  /**
121
132
  * @public
122
133
  */
123
- export type ClientTransactionResponse = {
124
- transaction: Transaction;
134
+ export type ClientTransactionResponseLike = {
135
+ transaction: TransactionLike;
125
136
  status: TransactionStatus;
126
- cycles?: Num;
127
- blockHash?: Hex;
128
- blockNumber?: Num;
129
- txIndex?: Num;
137
+ cycles?: NumLike;
138
+ blockHash?: HexLike;
139
+ blockNumber?: NumLike;
140
+ txIndex?: NumLike;
130
141
  reason?: string;
131
142
  };
143
+ /**
144
+ * @public
145
+ */
146
+ export class ClientTransactionResponse {
147
+ constructor(
148
+ public transaction: Transaction,
149
+ public status: TransactionStatus,
150
+ public cycles?: Num,
151
+ public blockHash?: Hex,
152
+ public blockNumber?: Num,
153
+ public txIndex?: Num,
154
+ public reason?: string,
155
+ ) {}
156
+
157
+ static from(
158
+ responseLike: ClientTransactionResponseLike,
159
+ ): ClientTransactionResponse {
160
+ if (responseLike instanceof ClientTransactionResponse) {
161
+ return responseLike;
162
+ }
163
+
164
+ return new ClientTransactionResponse(
165
+ Transaction.from(responseLike.transaction),
166
+ responseLike.status,
167
+ apply(numFrom, responseLike.cycles),
168
+ apply(hexFrom, responseLike.blockHash),
169
+ apply(numFrom, responseLike.blockNumber),
170
+ apply(numFrom, responseLike.txIndex),
171
+ responseLike.reason,
172
+ );
173
+ }
174
+
175
+ clone() {
176
+ return new ClientTransactionResponse(
177
+ this.transaction.clone(),
178
+ this.status,
179
+ this.cycles,
180
+ this.blockHash,
181
+ this.blockNumber,
182
+ this.txIndex,
183
+ this.reason,
184
+ );
185
+ }
186
+ }
132
187
 
133
188
  /**
134
189
  * @public
@@ -154,6 +209,10 @@ export class ClientIndexerSearchKeyFilter {
154
209
  static from(
155
210
  filterLike: ClientIndexerSearchKeyFilterLike,
156
211
  ): ClientIndexerSearchKeyFilter {
212
+ if (filterLike instanceof ClientIndexerSearchKeyFilter) {
213
+ return filterLike;
214
+ }
215
+
157
216
  return new ClientIndexerSearchKeyFilter(
158
217
  apply(Script.from, filterLike.script),
159
218
  apply(clientSearchKeyRangeFrom, filterLike.scriptLenRange),
@@ -186,6 +245,10 @@ export class ClientIndexerSearchKey {
186
245
  ) {}
187
246
 
188
247
  static from(keyLike: ClientIndexerSearchKeyLike): ClientIndexerSearchKey {
248
+ if (keyLike instanceof ClientIndexerSearchKey) {
249
+ return keyLike;
250
+ }
251
+
189
252
  return new ClientIndexerSearchKey(
190
253
  Script.from(keyLike.script),
191
254
  keyLike.scriptType,
@@ -230,6 +293,10 @@ export class ClientIndexerSearchKeyTransaction {
230
293
  static from(
231
294
  keyLike: ClientIndexerSearchKeyTransactionLike,
232
295
  ): ClientIndexerSearchKeyTransaction {
296
+ if (keyLike instanceof ClientIndexerSearchKeyTransaction) {
297
+ return keyLike;
298
+ }
299
+
233
300
  return new ClientIndexerSearchKeyTransaction(
234
301
  Script.from(keyLike.script),
235
302
  keyLike.scriptType,
@@ -273,58 +340,167 @@ export type ClientFindTransactionsGroupedResponse = {
273
340
  /**
274
341
  * @public
275
342
  */
276
- export type ClientBlockHeader = {
277
- compactTarget: Num;
343
+ export type ClientBlockHeaderLike = {
344
+ compactTarget: NumLike;
278
345
  dao: {
279
346
  /**
280
347
  * C_i: the total issuance up to and including block i.
281
348
  */
282
- c: Num;
349
+ c: NumLike;
283
350
  /**
284
351
  * AR_i: the current accumulated rate at block i.
285
352
  * AR_j / AR_i reflects the CKByte amount if one deposit 1 CKB to Nervos DAO at block i, and withdraw at block j.
286
353
  */
287
- ar: Num;
354
+ ar: NumLike;
288
355
  /**
289
356
  * S_i: the total unissued secondary issuance up to and including block i,
290
357
  * including unclaimed Nervos DAO compensation and treasury funds.
291
358
  */
292
- s: Num;
359
+ s: NumLike;
293
360
  /**
294
361
  * U_i: the total occupied capacities currently in the blockchain up to and including block i.
295
362
  * Occupied capacity is the sum of capacities used to store all cells.
296
363
  */
297
- u: Num;
364
+ u: NumLike;
298
365
  };
299
- epoch: Epoch;
300
- extraHash: Hex;
301
- hash: Hex;
302
- nonce: Num;
303
- number: Num;
304
- parentHash: Hex;
305
- proposalsHash: Hex;
306
- timestamp: Num;
307
- transactionsRoot: Hex;
308
- version: Num;
366
+ epoch: EpochLike;
367
+ extraHash: HexLike;
368
+ hash: HexLike;
369
+ nonce: NumLike;
370
+ number: NumLike;
371
+ parentHash: HexLike;
372
+ proposalsHash: HexLike;
373
+ timestamp: NumLike;
374
+ transactionsRoot: HexLike;
375
+ version: NumLike;
309
376
  };
377
+ /**
378
+ * @public
379
+ */
380
+ export class ClientBlockHeader {
381
+ constructor(
382
+ public compactTarget: Num,
383
+ public dao: {
384
+ /**
385
+ * C_i: the total issuance up to and including block i.
386
+ */
387
+ c: Num;
388
+ /**
389
+ * AR_i: the current accumulated rate at block i.
390
+ * AR_j / AR_i reflects the CKByte amount if one deposit 1 CKB to Nervos DAO at block i, and withdraw at block j.
391
+ */
392
+ ar: Num;
393
+ /**
394
+ * S_i: the total unissued secondary issuance up to and including block i,
395
+ * including unclaimed Nervos DAO compensation and treasury funds.
396
+ */
397
+ s: Num;
398
+ /**
399
+ * U_i: the total occupied capacities currently in the blockchain up to and including block i.
400
+ * Occupied capacity is the sum of capacities used to store all cells.
401
+ */
402
+ u: Num;
403
+ },
404
+ public epoch: Epoch,
405
+ public extraHash: Hex,
406
+ public hash: Hex,
407
+ public nonce: Num,
408
+ public number: Num,
409
+ public parentHash: Hex,
410
+ public proposalsHash: Hex,
411
+ public timestamp: Num,
412
+ public transactionsRoot: Hex,
413
+ public version: Num,
414
+ ) {}
415
+
416
+ static from(headerLike: ClientBlockHeaderLike): ClientBlockHeader {
417
+ if (headerLike instanceof ClientBlockHeader) {
418
+ return headerLike;
419
+ }
420
+
421
+ return new ClientBlockHeader(
422
+ numFrom(headerLike.compactTarget),
423
+ {
424
+ c: numFrom(headerLike.dao.c),
425
+ ar: numFrom(headerLike.dao.ar),
426
+ s: numFrom(headerLike.dao.s),
427
+ u: numFrom(headerLike.dao.u),
428
+ },
429
+ epochFrom(headerLike.epoch),
430
+ hexFrom(headerLike.extraHash),
431
+ hexFrom(headerLike.hash),
432
+ numFrom(headerLike.nonce),
433
+ numFrom(headerLike.number),
434
+ hexFrom(headerLike.parentHash),
435
+ hexFrom(headerLike.proposalsHash),
436
+ numFrom(headerLike.timestamp),
437
+ hexFrom(headerLike.transactionsRoot),
438
+ numFrom(headerLike.version),
439
+ );
440
+ }
441
+ }
310
442
 
311
443
  /**
312
444
  * @public
313
445
  */
314
- export type ClientBlockUncle = {
315
- header: ClientBlockHeader;
316
- proposals: Hex[];
446
+ export type ClientBlockUncleLike = {
447
+ header: ClientBlockHeaderLike;
448
+ proposals: HexLike[];
317
449
  };
450
+ /**
451
+ * @public
452
+ */
453
+ export class ClientBlockUncle {
454
+ constructor(
455
+ public header: ClientBlockHeader,
456
+ public proposals: Hex[],
457
+ ) {}
458
+
459
+ static from(uncleLike: ClientBlockUncleLike): ClientBlockUncle {
460
+ if (uncleLike instanceof ClientBlockUncle) {
461
+ return uncleLike;
462
+ }
463
+
464
+ return new ClientBlockUncle(
465
+ ClientBlockHeader.from(uncleLike.header),
466
+ uncleLike.proposals.map(hexFrom),
467
+ );
468
+ }
469
+ }
318
470
 
319
471
  /**
320
472
  * @public
321
473
  */
322
- export type ClientBlock = {
323
- header: ClientBlockHeader;
324
- proposals: Hex[];
325
- transactions: Transaction[];
326
- uncles: ClientBlockUncle[];
474
+ export type ClientBlockLike = {
475
+ header: ClientBlockHeaderLike;
476
+ proposals: HexLike[];
477
+ transactions: TransactionLike[];
478
+ uncles: ClientBlockUncleLike[];
327
479
  };
480
+ /**
481
+ * @public
482
+ */
483
+ export class ClientBlock {
484
+ constructor(
485
+ public header: ClientBlockHeader,
486
+ public proposals: Hex[],
487
+ public transactions: Transaction[],
488
+ public uncles: ClientBlockUncle[],
489
+ ) {}
490
+
491
+ static from(blockLike: ClientBlockLike): ClientBlock {
492
+ if (blockLike instanceof ClientBlock) {
493
+ return blockLike;
494
+ }
495
+
496
+ return new ClientBlock(
497
+ ClientBlockHeader.from(blockLike.header),
498
+ blockLike.proposals.map(hexFrom),
499
+ blockLike.transactions.map(Transaction.from),
500
+ blockLike.uncles.map(ClientBlockUncle.from),
501
+ );
502
+ }
503
+ }
328
504
 
329
505
  export interface ErrorClientBaseLike {
330
506
  message?: string;
@@ -392,8 +568,23 @@ export class ErrorClientRBFRejected extends ErrorClientBase {
392
568
  }
393
569
  }
394
570
 
395
- export class ErrorClientWaitTransactionTimeout extends Error {
396
- constructor() {
397
- super("Wait transaction timeout");
571
+ export class ErrorClientWaitTransactionTimeout extends ErrorClientBase {
572
+ constructor(timeoutLike: NumLike) {
573
+ const timeout = numFrom(timeoutLike).toString();
574
+ super({
575
+ message: `Wait transaction timeout ${timeout}ms`,
576
+ data: JSON.stringify({ timeout }),
577
+ });
578
+ }
579
+ }
580
+
581
+ export class ErrorClientMaxFeeRateExceeded extends ErrorClientBase {
582
+ constructor(limitLike: NumLike, actualLike: NumLike) {
583
+ const limit = numFrom(limitLike).toString();
584
+ const actual = numFrom(actualLike).toString();
585
+ super({
586
+ message: `Max fee rate exceeded limit ${limit}, actual ${actual}. Developer might forgot to complete transaction fee before sending. See https://docs.ckbccc.com/classes/_ckb_ccc_core.index.ccc.Transaction.html#completeFeeBy.`,
587
+ data: JSON.stringify({ limit, actual }),
588
+ });
398
589
  }
399
590
  }