@ickb/sdk 1000.0.82 → 9000.0.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 (157) hide show
  1. package/README.md +81 -32
  2. package/dist/constants.d.ts +13 -22
  3. package/dist/constants.d.ts.map +1 -1
  4. package/dist/constants.js +80 -76
  5. package/dist/constants.js.map +1 -1
  6. package/dist/conversion/estimate.d.ts +39 -0
  7. package/dist/conversion/estimate.d.ts.map +1 -0
  8. package/dist/conversion/estimate.js +117 -0
  9. package/dist/conversion/estimate.js.map +1 -0
  10. package/dist/conversion/maturity.d.ts +15 -0
  11. package/dist/conversion/maturity.d.ts.map +1 -0
  12. package/dist/conversion/maturity.js +112 -0
  13. package/dist/conversion/maturity.js.map +1 -0
  14. package/dist/conversion/plans.d.ts +20 -0
  15. package/dist/conversion/plans.d.ts.map +1 -0
  16. package/dist/conversion/plans.js +106 -0
  17. package/dist/conversion/plans.js.map +1 -0
  18. package/dist/conversion/projection.d.ts +22 -0
  19. package/dist/conversion/projection.d.ts.map +1 -0
  20. package/dist/conversion/projection.js +91 -0
  21. package/dist/conversion/projection.js.map +1 -0
  22. package/dist/conversion/types.d.ts +252 -0
  23. package/dist/conversion/types.d.ts.map +1 -0
  24. package/dist/conversion/types.js +2 -0
  25. package/dist/conversion/types.js.map +1 -0
  26. package/dist/conversion/withdrawal_ring.d.ts +36 -0
  27. package/dist/conversion/withdrawal_ring.d.ts.map +1 -0
  28. package/dist/conversion/withdrawal_ring.js +87 -0
  29. package/dist/conversion/withdrawal_ring.js.map +1 -0
  30. package/dist/dao.d.ts +86 -0
  31. package/dist/dao.d.ts.map +1 -0
  32. package/dist/dao.js +113 -0
  33. package/dist/dao.js.map +1 -0
  34. package/dist/index.d.ts +51 -3
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +20 -3
  37. package/dist/index.js.map +1 -1
  38. package/dist/logic.d.ts +85 -0
  39. package/dist/logic.d.ts.map +1 -0
  40. package/dist/logic.js +184 -0
  41. package/dist/logic.js.map +1 -0
  42. package/dist/order/cells.d.ts +207 -0
  43. package/dist/order/cells.d.ts.map +1 -0
  44. package/dist/order/cells.js +427 -0
  45. package/dist/order/cells.js.map +1 -0
  46. package/dist/order/conversion.d.ts +43 -0
  47. package/dist/order/conversion.d.ts.map +1 -0
  48. package/dist/order/conversion.js +123 -0
  49. package/dist/order/conversion.js.map +1 -0
  50. package/dist/order/fee.d.ts +9 -0
  51. package/dist/order/fee.d.ts.map +1 -0
  52. package/dist/order/fee.js +24 -0
  53. package/dist/order/fee.js.map +1 -0
  54. package/dist/order/fill.d.ts +36 -0
  55. package/dist/order/fill.d.ts.map +1 -0
  56. package/dist/order/fill.js +53 -0
  57. package/dist/order/fill.js.map +1 -0
  58. package/dist/order/info.d.ts +62 -0
  59. package/dist/order/info.d.ts.map +1 -0
  60. package/dist/order/info.js +99 -0
  61. package/dist/order/info.js.map +1 -0
  62. package/dist/order/master.d.ts +49 -0
  63. package/dist/order/master.d.ts.map +1 -0
  64. package/dist/order/master.js +27 -0
  65. package/dist/order/master.js.map +1 -0
  66. package/dist/order/matcher.d.ts +43 -0
  67. package/dist/order/matcher.d.ts.map +1 -0
  68. package/dist/order/matcher.js +123 -0
  69. package/dist/order/matcher.js.map +1 -0
  70. package/dist/order/order.d.ts +59 -0
  71. package/dist/order/order.d.ts.map +1 -0
  72. package/dist/order/order.js +239 -0
  73. package/dist/order/order.js.map +1 -0
  74. package/dist/order/order_data.d.ts +51 -0
  75. package/dist/order/order_data.d.ts.map +1 -0
  76. package/dist/order/order_data.js +64 -0
  77. package/dist/order/order_data.js.map +1 -0
  78. package/dist/order/ratio.d.ts +42 -0
  79. package/dist/order/ratio.d.ts.map +1 -0
  80. package/dist/order/ratio.js +82 -0
  81. package/dist/order/ratio.js.map +1 -0
  82. package/dist/order/relative.d.ts +43 -0
  83. package/dist/order/relative.d.ts.map +1 -0
  84. package/dist/order/relative.js +54 -0
  85. package/dist/order/relative.js.map +1 -0
  86. package/dist/owned_owner.d.ts +113 -0
  87. package/dist/owned_owner.d.ts.map +1 -0
  88. package/dist/owned_owner.js +280 -0
  89. package/dist/owned_owner.js.map +1 -0
  90. package/dist/sdk.d.ts +71 -42
  91. package/dist/sdk.d.ts.map +1 -1
  92. package/dist/sdk.js +388 -209
  93. package/dist/sdk.js.map +1 -1
  94. package/dist/send/sign_and_send_transaction.d.ts +46 -0
  95. package/dist/send/sign_and_send_transaction.d.ts.map +1 -0
  96. package/dist/send/sign_and_send_transaction.js +101 -0
  97. package/dist/send/sign_and_send_transaction.js.map +1 -0
  98. package/dist/send/wait_transaction.d.ts +41 -0
  99. package/dist/send/wait_transaction.d.ts.map +1 -0
  100. package/dist/send/wait_transaction.js +204 -0
  101. package/dist/send/wait_transaction.js.map +1 -0
  102. package/dist/udt.d.ts +123 -0
  103. package/dist/udt.d.ts.map +1 -0
  104. package/dist/udt.js +244 -0
  105. package/dist/udt.js.map +1 -0
  106. package/dist/utils/chain.d.ts +38 -0
  107. package/dist/utils/chain.d.ts.map +1 -0
  108. package/dist/utils/chain.js +20 -0
  109. package/dist/utils/chain.js.map +1 -0
  110. package/dist/utils/codec.d.ts +19 -0
  111. package/dist/utils/codec.d.ts.map +1 -0
  112. package/dist/utils/codec.js +66 -0
  113. package/dist/utils/codec.js.map +1 -0
  114. package/dist/utils/transaction_header.d.ts +17 -0
  115. package/dist/utils/transaction_header.d.ts.map +1 -0
  116. package/dist/utils/transaction_header.js +44 -0
  117. package/dist/utils/transaction_header.js.map +1 -0
  118. package/dist/utils/utils.d.ts +126 -0
  119. package/dist/utils/utils.d.ts.map +1 -0
  120. package/dist/utils/utils.js +151 -0
  121. package/dist/utils/utils.js.map +1 -0
  122. package/package.json +19 -26
  123. package/src/constants.ts +84 -181
  124. package/src/conversion/estimate.ts +157 -0
  125. package/src/conversion/maturity.ts +159 -0
  126. package/src/conversion/plans.ts +144 -0
  127. package/src/conversion/projection.ts +128 -0
  128. package/src/conversion/types.ts +287 -0
  129. package/src/conversion/withdrawal_ring.ts +126 -0
  130. package/src/dao.ts +172 -0
  131. package/src/index.ts +89 -3
  132. package/src/logic.ts +295 -0
  133. package/src/order/cells.ts +520 -0
  134. package/src/order/conversion.ts +173 -0
  135. package/src/order/fee.ts +30 -0
  136. package/src/order/fill.ts +83 -0
  137. package/src/order/info.ts +178 -0
  138. package/src/order/master.ts +42 -0
  139. package/src/order/matcher.ts +191 -0
  140. package/src/order/order.ts +302 -0
  141. package/src/order/order_data.ts +128 -0
  142. package/src/order/ratio.ts +144 -0
  143. package/src/order/relative.ts +106 -0
  144. package/src/owned_owner.ts +394 -0
  145. package/src/sdk.ts +555 -440
  146. package/src/send/sign_and_send_transaction.ts +120 -0
  147. package/src/send/wait_transaction.ts +271 -0
  148. package/src/udt.ts +317 -0
  149. package/src/utils/chain.ts +43 -0
  150. package/src/utils/codec.ts +74 -0
  151. package/src/utils/transaction_header.ts +66 -0
  152. package/src/utils/utils.ts +237 -0
  153. package/dist/codec.d.ts +0 -3
  154. package/dist/codec.d.ts.map +0 -1
  155. package/dist/codec.js +0 -58
  156. package/dist/codec.js.map +0 -1
  157. package/src/codec.ts +0 -138
package/src/logic.ts ADDED
@@ -0,0 +1,295 @@
1
+ import { ccc } from "@ckb-ccc/core";
2
+ import {
3
+ assertDaoOutputLimit,
4
+ DaoOutputLimitError,
5
+ depositData,
6
+ depositMaturity,
7
+ isDaoDeposit,
8
+ pushHeaderDep,
9
+ type LockUpPolicy,
10
+ } from "./dao.ts";
11
+ import {
12
+ decodeReceiptData,
13
+ encodeReceiptData,
14
+ IckbUdt,
15
+ ickbValue,
16
+ receiptDataBytes,
17
+ type ReceiptData,
18
+ } from "./udt.ts";
19
+ import { transactionHeaders } from "./utils/transaction_header.ts";
20
+ import {
21
+ findCells,
22
+ type ScriptDeps,
23
+ type TransactionHeader,
24
+ type ValueComponents,
25
+ } from "./utils/utils.ts";
26
+
27
+ const maxDepositQuantity = 63;
28
+ // Receipts must carry enough capacity for phase 2 when the wallet has no other
29
+ // CKB: one iCKB xUDT cell, one plain capacity cell, and the fee reserve.
30
+ const phase2TxFeeReserve = ccc.One;
31
+
32
+ /**
33
+ * A live iCKB deposit: a DAO deposit cell locked by the iCKB Logic script, valued at its
34
+ * deposit header.
35
+ */
36
+ export interface IckbDepositCell extends ValueComponents {
37
+ /** The DAO deposit cell. */
38
+ cell: ccc.Cell;
39
+ /** The deposit header and the tip the readiness was judged against. */
40
+ headers: [TransactionHeader, TransactionHeader];
41
+ /** The DAO interest accrued between the two headers. */
42
+ interests: ccc.Num;
43
+ /**
44
+ * The DAO claim epoch as sampled at the tip, not rolled: each reader judges it against
45
+ * its own {@link LockUpPolicy} with `depositMaturity`.
46
+ */
47
+ claimEpoch: ccc.Epoch;
48
+ }
49
+
50
+ /**
51
+ * Represents a receipt cell containing the receipt for iCKB Deposits.
52
+ */
53
+ export interface ReceiptCell extends ValueComponents {
54
+ /** The cell associated with the receipt. */
55
+ cell: ccc.Cell;
56
+ /** The header of the transaction that made the deposits. */
57
+ header: TransactionHeader;
58
+ }
59
+
60
+ /**
61
+ * Manages logic related to deposits and receipts in the blockchain.
62
+ */
63
+ export class LogicManager implements ScriptDeps {
64
+ /** The iCKB Logic script used as receipt type and DAO deposit lock. */
65
+ public readonly script: ccc.Script;
66
+
67
+ /** Cell dependencies required to execute the iCKB Logic script. */
68
+ public readonly cellDeps: ccc.CellDep[];
69
+
70
+ /** The Nervos DAO script the deposits carry, with its cell deps. */
71
+ public readonly dao: ScriptDeps;
72
+
73
+ /** Creates the manager for one iCKB Logic deployment over one DAO deployment. */
74
+ constructor(script: ccc.Script, cellDeps: ccc.CellDep[], dao: ScriptDeps) {
75
+ this.script = script;
76
+ this.cellDeps = cellDeps;
77
+ this.dao = dao;
78
+ }
79
+
80
+ /** Whether the cell is an iCKB receipt: typed by the logic script with a decodable prefix. */
81
+ public isReceipt(cell: ccc.Cell): boolean {
82
+ return (
83
+ cell.cellOutput.type?.eq(this.script) === true &&
84
+ ccc.bytesFrom(cell.outputData).length >= receiptDataBytes
85
+ );
86
+ }
87
+
88
+ /** Whether the cell is a DAO deposit locked by the logic script. */
89
+ public isDeposit(cell: ccc.Cell): boolean {
90
+ return isDaoDeposit(cell, this.dao.script) && cell.cellOutput.lock.eq(this.script);
91
+ }
92
+
93
+ /**
94
+ * Adds `depositQuantity` DAO deposits of `depositCapacity` locked by the logic script,
95
+ * then the receipt that mints their iCKB in phase 2, locked by `lock`.
96
+ *
97
+ * @remarks Caller must ensure UDT cellDeps are added to the transaction
98
+ * (e.g., via ickbUdt.addCellDeps(tx)).
99
+ */
100
+ public deposit(
101
+ txLike: ccc.TransactionLike,
102
+ depositQuantity: number,
103
+ depositCapacity: ccc.FixedPoint,
104
+ lock: ccc.Script,
105
+ ): ccc.Transaction {
106
+ const tx = ccc.Transaction.from(txLike);
107
+ if (depositQuantity <= 0) {
108
+ return tx;
109
+ }
110
+ if (!Number.isSafeInteger(depositQuantity)) {
111
+ throw new TypeError("iCKB deposit quantity must be a safe integer");
112
+ }
113
+ if (depositQuantity > maxDepositQuantity) {
114
+ // The completion walk steps a plan down on this error.
115
+ throw new DaoOutputLimitError(tx.outputs.length + depositQuantity + 1);
116
+ }
117
+
118
+ const depositCell = ccc.Cell.from({
119
+ previousOutput: { txHash: `0x${"00".repeat(32)}`, index: 0 },
120
+ cellOutput: { capacity: depositCapacity, lock: this.script, type: this.dao.script },
121
+ outputData: depositData(),
122
+ });
123
+ const depositAmount = depositCell.capacityFree;
124
+ if (depositAmount < ccc.fixedPointFrom(1000)) {
125
+ throw new Error(
126
+ "iCKB deposit minimum is 1000 CKB free capacity (1082 CKB total capacity)",
127
+ );
128
+ }
129
+ if (depositAmount > ccc.fixedPointFrom(1000000)) {
130
+ throw new Error(
131
+ "iCKB deposit maximum is 1000000 CKB free capacity (1000082 CKB total capacity)",
132
+ );
133
+ }
134
+
135
+ tx.addCellDeps(this.cellDeps);
136
+ tx.addCellDeps(this.dao.cellDeps);
137
+ for (let i = 0; i < depositQuantity; i += 1) {
138
+ tx.addOutput(depositCell.cellOutput, depositCell.outputData);
139
+ }
140
+ // Receipts track the deposit's free capacity, not the full DAO cell capacity.
141
+ tx.addOutput(
142
+ { capacity: receiptPhase2Capacity(lock), lock, type: this.script },
143
+ encodeReceiptData({ depositQuantity: BigInt(depositQuantity), depositAmount }),
144
+ );
145
+ assertDaoOutputLimit(tx, this.dao.script);
146
+ return tx;
147
+ }
148
+
149
+ /**
150
+ * Adds receipt inputs and their deposit header deps for iCKB deposit completion.
151
+ *
152
+ * @remarks This prepares the phase-2 inputs; the iCKB they mint is completed by
153
+ * `IckbSdk.completeTransaction`.
154
+ */
155
+ public completeDeposit(
156
+ txLike: ccc.TransactionLike,
157
+ receipts: ReceiptCell[],
158
+ ): ccc.Transaction {
159
+ const tx = ccc.Transaction.from(txLike);
160
+ if (receipts.length === 0) {
161
+ return tx;
162
+ }
163
+ for (const receipt of receipts) {
164
+ const outPoint = receipt.cell.outPoint.toHex();
165
+ if (!this.isReceipt(receipt.cell)) {
166
+ throw new Error(
167
+ `Receipt ${outPoint} is not an iCKB receipt for this logic script`,
168
+ );
169
+ }
170
+ if (receipt.header.txHash !== receipt.cell.outPoint.txHash) {
171
+ throw new Error(
172
+ `Receipt ${outPoint} header txHash ${String(receipt.header.txHash)} does not match cell txHash ${receipt.cell.outPoint.txHash}`,
173
+ );
174
+ }
175
+ }
176
+ tx.addCellDeps(this.cellDeps);
177
+ for (const receipt of receipts) {
178
+ pushHeaderDep(tx, receipt.header.header.hash);
179
+ tx.addInput(receipt.cell);
180
+ }
181
+ return tx;
182
+ }
183
+
184
+ /**
185
+ * The receipts among `cells`, valued at their deposit headers, each header read once.
186
+ */
187
+ public async receiptsFrom(
188
+ client: ccc.Client,
189
+ cells: readonly ccc.Cell[],
190
+ ): Promise<ReceiptCell[]> {
191
+ const receipts = cells.filter((cell) => this.isReceipt(cell));
192
+ const headers = await transactionHeaders(
193
+ client,
194
+ receipts.map((cell) => cell.outPoint.txHash),
195
+ );
196
+ return receipts.map((cell) => {
197
+ const { txHash } = cell.outPoint;
198
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- every receipt's hash was read above.
199
+ return receiptCell(cell, { header: headers.get(txHash)!, txHash });
200
+ });
201
+ }
202
+
203
+ /**
204
+ * Every live iCKB deposit, valued at its deposit header, with its claim epoch at the tip;
205
+ * each deposit transaction's header is read once.
206
+ */
207
+ public async findDeposits(
208
+ client: ccc.Client,
209
+ tip: ccc.ClientBlockHeader,
210
+ ): Promise<IckbDepositCell[]> {
211
+ const cells = (
212
+ await findCells(client, {
213
+ script: this.script,
214
+ scriptType: "lock",
215
+ filter: {
216
+ script: this.dao.script,
217
+ outputData: depositData(),
218
+ outputDataSearchMode: "exact",
219
+ },
220
+ scriptSearchMode: "exact",
221
+ withData: true,
222
+ })
223
+ ).filter((cell) => this.isDeposit(cell));
224
+ const headers = await transactionHeaders(
225
+ client,
226
+ cells.map((cell) => cell.outPoint.txHash),
227
+ );
228
+ return cells.map((cell) => {
229
+ const { txHash } = cell.outPoint;
230
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- every deposit's hash was read above.
231
+ return ickbDepositCell(cell, { header: headers.get(txHash)!, txHash }, tip);
232
+ });
233
+ }
234
+ }
235
+
236
+ /** Values a DAO deposit cell at its deposit header and samples its claim epoch at the tip. */
237
+ export function ickbDepositCell(
238
+ cell: ccc.Cell,
239
+ depositHeader: TransactionHeader,
240
+ tip: ccc.ClientBlockHeader,
241
+ ): IckbDepositCell {
242
+ const interests = ccc.calcDaoProfit(cell.capacityFree, depositHeader.header, tip);
243
+ return {
244
+ cell,
245
+ headers: [depositHeader, { header: tip }],
246
+ interests,
247
+ claimEpoch: ccc.calcDaoClaimEpoch(depositHeader.header, tip),
248
+ ckbValue: cell.cellOutput.capacity + interests,
249
+ udtValue: ickbValue(cell.capacityFree, depositHeader.header),
250
+ };
251
+ }
252
+
253
+ /** The deposits a withdrawal request made now may claim at their sampled dates under the policy. */
254
+ export function readyDeposits(
255
+ deposits: readonly IckbDepositCell[],
256
+ tip: ccc.ClientBlockHeader,
257
+ policy: LockUpPolicy,
258
+ ): IckbDepositCell[] {
259
+ return deposits.filter(
260
+ (deposit) => depositMaturity(deposit.claimEpoch, tip, policy).isReady,
261
+ );
262
+ }
263
+
264
+ /** Decodes a receipt cell and values it at its deposit header. */
265
+ export function receiptCell(cell: ccc.Cell, header: TransactionHeader): ReceiptCell {
266
+ let receipt: ReceiptData;
267
+ try {
268
+ receipt = decodeReceiptData(cell.outputData);
269
+ } catch (error) {
270
+ throw new Error(
271
+ `Invalid iCKB receipt payload at ${cell.outPoint.toHex()}: ${cell.outputData}`,
272
+ { cause: error },
273
+ );
274
+ }
275
+ return {
276
+ cell,
277
+ header,
278
+ ckbValue: cell.cellOutput.capacity,
279
+ udtValue: ickbValue(receipt.depositAmount, header.header) * receipt.depositQuantity,
280
+ };
281
+ }
282
+
283
+ /**
284
+ * Returns the CKB needed for the two phase-2 outputs created by one receipt.
285
+ *
286
+ * @remarks The value is sized with the actual user lock because lock args affect
287
+ * occupied capacity. It includes one plain output, one xUDT output, and the
288
+ * phase-2 fee reserve.
289
+ */
290
+ export function receiptPhase2Capacity(lock: ccc.Script): ccc.FixedPoint {
291
+ // Capacity is measured with the actual user lock. Lock args are wallet-specific
292
+ // and can make both phase-2 outputs larger than protocol-only examples.
293
+ const plainCellCapacity = BigInt(8 + lock.occupiedSize) * ccc.One;
294
+ return plainCellCapacity + IckbUdt.minimumXudtCellCapacity(lock) + phase2TxFeeReserve;
295
+ }