@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.
- package/CHANGELOG.md +54 -0
- package/dist/ckb/script.d.ts +2 -1
- package/dist/ckb/script.d.ts.map +1 -1
- package/dist/ckb/transaction.d.ts +70 -5
- package/dist/ckb/transaction.d.ts.map +1 -1
- package/dist/ckb/transaction.js +186 -53
- package/dist/client/client.d.ts +3 -1
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/client.js +4 -3
- package/dist/client/clientPublicMainnet.advanced.d.ts +2 -1
- package/dist/client/clientPublicMainnet.advanced.d.ts.map +1 -1
- package/dist/client/clientPublicMainnet.advanced.js +1 -1
- package/dist/client/clientPublicMainnet.d.ts +2 -1
- package/dist/client/clientPublicMainnet.d.ts.map +1 -1
- package/dist/client/clientPublicTestnet.advanced.d.ts +2 -1
- package/dist/client/clientPublicTestnet.advanced.d.ts.map +1 -1
- package/dist/client/clientPublicTestnet.advanced.js +1 -1
- package/dist/client/clientPublicTestnet.d.ts +2 -1
- package/dist/client/clientPublicTestnet.d.ts.map +1 -1
- package/dist/client/clientTypes.d.ts +0 -25
- package/dist/client/clientTypes.d.ts.map +1 -1
- package/dist/client/clientTypes.js +0 -27
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -0
- package/dist/client/knownScript.d.ts +26 -0
- package/dist/client/knownScript.d.ts.map +1 -0
- package/dist/client/knownScript.js +27 -0
- package/dist/num/index.d.ts.map +1 -1
- package/dist/num/index.js +17 -1
- package/dist/signer/ckb/signerCkbPublicKey.d.ts.map +1 -1
- package/dist/signer/ckb/signerCkbPublicKey.js +1 -5
- package/dist/signer/nostr/index.d.ts +1 -0
- package/dist/signer/nostr/index.d.ts.map +1 -1
- package/dist/signer/nostr/index.js +1 -0
- package/dist/signer/nostr/signerNostr.d.ts +1 -1
- package/dist/signer/nostr/signerNostr.d.ts.map +1 -1
- package/dist/signer/nostr/signerNostr.js +8 -0
- package/dist/signer/nostr/signerNostrPrivateKey.d.ts +5 -7
- package/dist/signer/nostr/signerNostrPrivateKey.d.ts.map +1 -1
- package/dist/signer/nostr/signerNostrPrivateKey.js +6 -12
- package/dist/signer/nostr/signerNostrPublicKeyReadonly.d.ts +11 -0
- package/dist/signer/nostr/signerNostrPublicKeyReadonly.d.ts.map +1 -0
- package/dist/signer/nostr/signerNostrPublicKeyReadonly.js +22 -0
- package/dist.commonjs/ckb/script.d.ts +2 -1
- package/dist.commonjs/ckb/script.d.ts.map +1 -1
- package/dist.commonjs/ckb/transaction.d.ts +70 -5
- package/dist.commonjs/ckb/transaction.d.ts.map +1 -1
- package/dist.commonjs/ckb/transaction.js +282 -147
- package/dist.commonjs/client/client.d.ts +3 -1
- package/dist.commonjs/client/client.d.ts.map +1 -1
- package/dist.commonjs/client/client.js +4 -3
- package/dist.commonjs/client/clientPublicMainnet.advanced.d.ts +2 -1
- package/dist.commonjs/client/clientPublicMainnet.advanced.d.ts.map +1 -1
- package/dist.commonjs/client/clientPublicMainnet.advanced.js +21 -21
- package/dist.commonjs/client/clientPublicMainnet.d.ts +2 -1
- package/dist.commonjs/client/clientPublicMainnet.d.ts.map +1 -1
- package/dist.commonjs/client/clientPublicTestnet.advanced.d.ts +2 -1
- package/dist.commonjs/client/clientPublicTestnet.advanced.d.ts.map +1 -1
- package/dist.commonjs/client/clientPublicTestnet.advanced.js +21 -21
- package/dist.commonjs/client/clientPublicTestnet.d.ts +2 -1
- package/dist.commonjs/client/clientPublicTestnet.d.ts.map +1 -1
- package/dist.commonjs/client/clientTypes.d.ts +0 -25
- package/dist.commonjs/client/clientTypes.d.ts.map +1 -1
- package/dist.commonjs/client/clientTypes.js +1 -28
- package/dist.commonjs/client/index.d.ts +1 -0
- package/dist.commonjs/client/index.d.ts.map +1 -1
- package/dist.commonjs/client/index.js +1 -0
- package/dist.commonjs/client/knownScript.d.ts +26 -0
- package/dist.commonjs/client/knownScript.d.ts.map +1 -0
- package/dist.commonjs/client/knownScript.js +30 -0
- package/dist.commonjs/num/index.d.ts.map +1 -1
- package/dist.commonjs/num/index.js +17 -1
- package/dist.commonjs/signer/ckb/signerCkbPublicKey.d.ts.map +1 -1
- package/dist.commonjs/signer/ckb/signerCkbPublicKey.js +1 -5
- package/dist.commonjs/signer/nostr/index.d.ts +1 -0
- package/dist.commonjs/signer/nostr/index.d.ts.map +1 -1
- package/dist.commonjs/signer/nostr/index.js +1 -0
- package/dist.commonjs/signer/nostr/signerNostr.d.ts +1 -1
- package/dist.commonjs/signer/nostr/signerNostr.d.ts.map +1 -1
- package/dist.commonjs/signer/nostr/signerNostr.js +8 -0
- package/dist.commonjs/signer/nostr/signerNostrPrivateKey.d.ts +5 -7
- package/dist.commonjs/signer/nostr/signerNostrPrivateKey.d.ts.map +1 -1
- package/dist.commonjs/signer/nostr/signerNostrPrivateKey.js +6 -12
- package/dist.commonjs/signer/nostr/signerNostrPublicKeyReadonly.d.ts +11 -0
- package/dist.commonjs/signer/nostr/signerNostrPublicKeyReadonly.d.ts.map +1 -0
- package/dist.commonjs/signer/nostr/signerNostrPublicKeyReadonly.js +26 -0
- package/package.json +2 -2
- package/src/ckb/script.ts +2 -1
- package/src/ckb/transaction.ts +270 -62
- package/src/client/client.ts +5 -4
- package/src/client/clientPublicMainnet.advanced.ts +2 -1
- package/src/client/clientPublicMainnet.ts +2 -1
- package/src/client/clientPublicTestnet.advanced.ts +2 -1
- package/src/client/clientPublicTestnet.ts +2 -1
- package/src/client/clientTypes.ts +0 -28
- package/src/client/index.ts +1 -0
- package/src/client/knownScript.ts +27 -0
- package/src/num/index.ts +21 -1
- package/src/signer/ckb/signerCkbPublicKey.ts +3 -5
- package/src/signer/nostr/index.ts +1 -0
- package/src/signer/nostr/signerNostr.ts +3 -1
- package/src/signer/nostr/signerNostrPrivateKey.ts +7 -14
- package/src/signer/nostr/signerNostrPublicKeyReadonly.ts +29 -0
package/src/ckb/transaction.ts
CHANGED
|
@@ -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
|
|
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.
|
|
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.
|
|
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(
|
|
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
|
|
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 ===
|
|
1075
|
-
script.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
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
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.
|
|
1434
|
-
if (!
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
1604
|
-
1,
|
|
1605
|
-
)) {
|
|
1606
|
-
if (
|
|
1607
|
-
this.inputs.some(({ previousOutput }) =>
|
|
1608
|
-
previousOutput.eq(cell.outPoint),
|
|
1609
|
-
)
|
|
1610
|
-
) {
|
|
1611
|
-
continue;
|
|
1612
|
-
}
|
|
1769
|
+
);
|
|
1613
1770
|
|
|
1614
|
-
|
|
1615
|
-
return
|
|
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
|
|
1789
|
+
async getFee(client: Client): Promise<Num> {
|
|
1633
1790
|
return (await this.getInputsCapacity(client)) - this.getOutputsCapacity();
|
|
1634
1791
|
}
|
|
1635
1792
|
|
|
1636
|
-
async
|
|
1793
|
+
async getFeeRate(client: Client): Promise<Num> {
|
|
1637
1794
|
return (
|
|
1638
|
-
((await this.
|
|
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.
|
|
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.
|
|
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
|
+
}
|
package/src/client/client.ts
CHANGED
|
@@ -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
|
|
600
|
-
if (maxFeeRate > Zero &&
|
|
601
|
-
throw new ErrorClientMaxFeeRateExceeded(maxFeeRate,
|
|
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,7 +1,8 @@
|
|
|
1
1
|
import WebSocket from "isomorphic-ws";
|
|
2
2
|
import { MAINNET_SCRIPTS } from "./clientPublicMainnet.advanced.js";
|
|
3
|
-
import {
|
|
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,7 +1,8 @@
|
|
|
1
1
|
import WebSocket from "isomorphic-ws";
|
|
2
2
|
import { TESTNET_SCRIPTS } from "./clientPublicTestnet.advanced.js";
|
|
3
|
-
import {
|
|
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
|
*/
|
package/src/client/index.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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
|
}
|