@ckb-ccc/core 1.11.5 → 1.12.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.
- package/CHANGELOG.md +31 -0
- package/dist/ckb/transaction.d.ts +160 -29
- package/dist/ckb/transaction.d.ts.map +1 -1
- package/dist/ckb/transaction.js +185 -39
- package/dist/client/client.d.ts +7 -0
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/client.js +9 -2
- package/dist/client/jsonRpc/client.d.ts +1 -1
- package/dist/client/jsonRpc/client.d.ts.map +1 -1
- package/dist/client/jsonRpc/client.js +4 -1
- package/dist/client/jsonRpc/transformers.d.ts +1 -1
- package/dist/client/jsonRpc/transformers.d.ts.map +1 -1
- package/dist/client/jsonRpc/transformers.js +2 -1
- package/dist/jsonRpc/requestor.js +1 -1
- package/dist/signer/btc/verify.d.ts +21 -0
- package/dist/signer/btc/verify.d.ts.map +1 -1
- package/dist/signer/btc/verify.js +38 -2
- package/dist/signer/doge/signerDogePrivateKey.d.ts.map +1 -1
- package/dist/signer/doge/signerDogePrivateKey.js +2 -2
- package/dist/signer/doge/verify.d.ts +12 -1
- package/dist/signer/doge/verify.d.ts.map +1 -1
- package/dist/signer/doge/verify.js +15 -5
- package/dist/signer/signer/index.d.ts +14 -5
- package/dist/signer/signer/index.d.ts.map +1 -1
- package/dist/signer/signer/index.js +19 -11
- package/dist.commonjs/ckb/transaction.d.ts +160 -29
- package/dist.commonjs/ckb/transaction.d.ts.map +1 -1
- package/dist.commonjs/ckb/transaction.js +187 -40
- package/dist.commonjs/client/client.d.ts +7 -0
- package/dist.commonjs/client/client.d.ts.map +1 -1
- package/dist.commonjs/client/client.js +9 -2
- package/dist.commonjs/client/jsonRpc/client.d.ts +1 -1
- package/dist.commonjs/client/jsonRpc/client.d.ts.map +1 -1
- package/dist.commonjs/client/jsonRpc/client.js +4 -1
- package/dist.commonjs/client/jsonRpc/transformers.d.ts +1 -1
- package/dist.commonjs/client/jsonRpc/transformers.d.ts.map +1 -1
- package/dist.commonjs/client/jsonRpc/transformers.js +2 -1
- package/dist.commonjs/jsonRpc/requestor.js +1 -1
- package/dist.commonjs/signer/btc/verify.d.ts +21 -0
- package/dist.commonjs/signer/btc/verify.d.ts.map +1 -1
- package/dist.commonjs/signer/btc/verify.js +40 -2
- package/dist.commonjs/signer/doge/signerDogePrivateKey.d.ts.map +1 -1
- package/dist.commonjs/signer/doge/signerDogePrivateKey.js +2 -2
- package/dist.commonjs/signer/doge/verify.d.ts +12 -1
- package/dist.commonjs/signer/doge/verify.d.ts.map +1 -1
- package/dist.commonjs/signer/doge/verify.js +15 -4
- package/dist.commonjs/signer/signer/index.d.ts +14 -5
- package/dist.commonjs/signer/signer/index.d.ts.map +1 -1
- package/dist.commonjs/signer/signer/index.js +21 -13
- package/package.json +3 -4
- package/{prettier.config.mjs → prettier.config.cjs} +2 -4
- package/src/ckb/transaction.ts +259 -81
- package/src/client/client.ts +9 -2
- package/src/client/jsonRpc/client.ts +5 -2
- package/src/client/jsonRpc/transformers.ts +6 -1
- package/src/jsonRpc/requestor.ts +2 -2
- package/src/signer/btc/verify.ts +52 -3
- package/src/signer/doge/signerDogePrivateKey.ts +2 -2
- package/src/signer/doge/verify.ts +23 -7
- package/src/signer/signer/index.ts +20 -10
package/src/ckb/transaction.ts
CHANGED
|
@@ -198,7 +198,7 @@ export class OutPoint extends mol.Entity.Base<OutPointLike, OutPoint>() {
|
|
|
198
198
|
* @public
|
|
199
199
|
*/
|
|
200
200
|
export type CellOutputLike = {
|
|
201
|
-
capacity
|
|
201
|
+
capacity?: NumLike | null;
|
|
202
202
|
lock: ScriptLike;
|
|
203
203
|
type?: ScriptLike | null;
|
|
204
204
|
};
|
|
@@ -238,7 +238,6 @@ export class CellOutput extends mol.Entity.Base<CellOutputLike, CellOutput>() {
|
|
|
238
238
|
* This method supports automatic capacity calculation when capacity is 0 or omitted.
|
|
239
239
|
*
|
|
240
240
|
* @param cellOutput - A CellOutputLike object or an instance of CellOutput.
|
|
241
|
-
* Can also be an object without capacity when outputData is provided.
|
|
242
241
|
* @param outputData - Optional output data used for automatic capacity calculation.
|
|
243
242
|
* When provided and capacity is 0, the capacity will be calculated
|
|
244
243
|
* as occupiedSize + outputData.length.
|
|
@@ -259,16 +258,9 @@ export class CellOutput extends mol.Entity.Base<CellOutputLike, CellOutput>() {
|
|
|
259
258
|
* }, "0x1234"); // Capacity will be calculated automatically
|
|
260
259
|
* ```
|
|
261
260
|
*/
|
|
262
|
-
static from(cellOutput: CellOutputLike, outputData?: HexLike): CellOutput;
|
|
263
261
|
static from(
|
|
264
|
-
cellOutput:
|
|
265
|
-
|
|
266
|
-
outputData: HexLike,
|
|
267
|
-
): CellOutput;
|
|
268
|
-
static from(
|
|
269
|
-
cellOutput: Omit<CellOutputLike, "capacity"> &
|
|
270
|
-
Partial<Pick<CellOutputLike, "capacity">>,
|
|
271
|
-
outputData?: HexLike,
|
|
262
|
+
cellOutput: CellOutputLike,
|
|
263
|
+
outputData?: HexLike | null,
|
|
272
264
|
): CellOutput {
|
|
273
265
|
if (cellOutput instanceof CellOutput) {
|
|
274
266
|
return cellOutput;
|
|
@@ -307,33 +299,189 @@ export const CellOutputVec = mol.vector(CellOutput);
|
|
|
307
299
|
|
|
308
300
|
/**
|
|
309
301
|
* @public
|
|
302
|
+
* Represents a cell-like object that may or may not be on-chain.
|
|
303
|
+
* It can optionally have an `outPoint` (or `previousOutput`).
|
|
304
|
+
* This is used as a flexible input for creating `CellAny` instances.
|
|
305
|
+
* @see CellAny
|
|
310
306
|
*/
|
|
311
|
-
export type
|
|
312
|
-
|
|
|
313
|
-
|
|
314
|
-
}
|
|
315
|
-
| { previousOutput: OutPointLike }
|
|
316
|
-
) & {
|
|
307
|
+
export type CellAnyLike = {
|
|
308
|
+
outPoint?: OutPointLike | null;
|
|
309
|
+
previousOutput?: OutPointLike | null;
|
|
317
310
|
cellOutput: CellOutputLike;
|
|
318
|
-
outputData
|
|
311
|
+
outputData?: HexLike | null;
|
|
319
312
|
};
|
|
320
313
|
/**
|
|
314
|
+
* Represents a CKB cell that can be either on-chain (with an `outPoint`) or off-chain (without an `outPoint`).
|
|
315
|
+
* This class provides a unified interface for handling cells before they are included in a transaction,
|
|
316
|
+
* or for cells that are already part of the blockchain state.
|
|
317
|
+
*
|
|
321
318
|
* @public
|
|
322
319
|
*/
|
|
323
|
-
export class
|
|
320
|
+
export class CellAny {
|
|
321
|
+
public outPoint: OutPoint | undefined;
|
|
322
|
+
|
|
324
323
|
/**
|
|
325
|
-
* Creates an instance of
|
|
324
|
+
* Creates an instance of CellAny.
|
|
326
325
|
*
|
|
327
|
-
* @param outPoint - The output point of the cell.
|
|
328
326
|
* @param cellOutput - The cell output of the cell.
|
|
329
327
|
* @param outputData - The output data of the cell.
|
|
328
|
+
* @param outPoint - The optional output point of the cell. If provided, the cell is considered on-chain.
|
|
330
329
|
*/
|
|
331
330
|
|
|
332
331
|
constructor(
|
|
333
|
-
public outPoint: OutPoint,
|
|
334
332
|
public cellOutput: CellOutput,
|
|
335
333
|
public outputData: Hex,
|
|
336
|
-
|
|
334
|
+
outPoint?: OutPoint,
|
|
335
|
+
) {
|
|
336
|
+
this.outPoint = outPoint;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Creates a `CellAny` instance from a `CellAnyLike` object.
|
|
341
|
+
* This factory method provides a convenient way to create `CellAny` instances
|
|
342
|
+
* from plain objects, automatically handling the optional `outPoint` or `previousOutput`.
|
|
343
|
+
*
|
|
344
|
+
* @param cell - A `CellAnyLike` object.
|
|
345
|
+
* @returns A new `CellAny` instance.
|
|
346
|
+
*
|
|
347
|
+
* @example
|
|
348
|
+
* ```typescript
|
|
349
|
+
* // Create an off-chain cell (e.g., a new output)
|
|
350
|
+
* const offChainCell = CellAny.from({
|
|
351
|
+
* cellOutput: { capacity: 1000n, lock: lockScript },
|
|
352
|
+
* outputData: "0x"
|
|
353
|
+
* });
|
|
354
|
+
*
|
|
355
|
+
* // Create an on-chain cell from an input
|
|
356
|
+
* const onChainCell = CellAny.from({
|
|
357
|
+
* outPoint: { txHash: "0x...", index: 0 },
|
|
358
|
+
* cellOutput: { capacity: 2000n, lock: lockScript },
|
|
359
|
+
* outputData: "0x1234"
|
|
360
|
+
* });
|
|
361
|
+
* ```
|
|
362
|
+
*/
|
|
363
|
+
static from(cell: CellAnyLike): CellAny {
|
|
364
|
+
if (cell instanceof CellAny) {
|
|
365
|
+
return cell;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
return new CellAny(
|
|
369
|
+
CellOutput.from(cell.cellOutput, cell.outputData),
|
|
370
|
+
hexFrom(cell.outputData ?? "0x"),
|
|
371
|
+
apply(OutPoint.from, cell.outPoint ?? cell.previousOutput),
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Calculates the total occupied size of the cell in bytes.
|
|
377
|
+
* This includes the size of the `CellOutput` structure plus the size of the `outputData`.
|
|
378
|
+
*
|
|
379
|
+
* @returns The total occupied size in bytes.
|
|
380
|
+
*/
|
|
381
|
+
get occupiedSize() {
|
|
382
|
+
return this.cellOutput.occupiedSize + bytesFrom(this.outputData).byteLength;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Calculates the free capacity of the cell.
|
|
387
|
+
* Free capacity is the total capacity minus the capacity occupied by the cell's structure and data.
|
|
388
|
+
*
|
|
389
|
+
* @returns The free capacity in shannons as a `Num`.
|
|
390
|
+
*/
|
|
391
|
+
get capacityFree() {
|
|
392
|
+
return this.cellOutput.capacity - fixedPointFrom(this.occupiedSize);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Checks if the cell is a Nervos DAO cell and optionally checks its phase.
|
|
397
|
+
*
|
|
398
|
+
* @param client - A CKB client instance to fetch known script information.
|
|
399
|
+
* @param phase - Optional phase to check: "deposited" or "withdrew".
|
|
400
|
+
* If omitted, it checks if the cell is a DAO cell regardless of phase.
|
|
401
|
+
* @returns A promise that resolves to `true` if the cell is a matching Nervos DAO cell, `false` otherwise.
|
|
402
|
+
*/
|
|
403
|
+
async isNervosDao(
|
|
404
|
+
client: Client,
|
|
405
|
+
phase?: "deposited" | "withdrew",
|
|
406
|
+
): Promise<boolean> {
|
|
407
|
+
const { type } = this.cellOutput;
|
|
408
|
+
|
|
409
|
+
const daoType = await client.getKnownScript(KnownScript.NervosDao);
|
|
410
|
+
if (
|
|
411
|
+
!type ||
|
|
412
|
+
type.codeHash !== daoType.codeHash ||
|
|
413
|
+
type.hashType !== daoType.hashType
|
|
414
|
+
) {
|
|
415
|
+
// Non Nervos DAO cell
|
|
416
|
+
return false;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
const hasWithdrew = numFrom(this.outputData) !== Zero;
|
|
420
|
+
return (
|
|
421
|
+
!phase ||
|
|
422
|
+
(phase === "deposited" && !hasWithdrew) ||
|
|
423
|
+
(phase === "withdrew" && hasWithdrew)
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Clones the `CellAny` instance.
|
|
429
|
+
*
|
|
430
|
+
* @returns A new `CellAny` instance that is a deep copy of the current one.
|
|
431
|
+
*
|
|
432
|
+
* @example
|
|
433
|
+
* ```typescript
|
|
434
|
+
* const clonedCell = cellAny.clone();
|
|
435
|
+
* ```
|
|
436
|
+
*/
|
|
437
|
+
clone(): CellAny {
|
|
438
|
+
return new CellAny(
|
|
439
|
+
this.cellOutput.clone(),
|
|
440
|
+
this.outputData,
|
|
441
|
+
this.outPoint?.clone(),
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Represents a cell-like object that is guaranteed to be on-chain.
|
|
448
|
+
* It must have an `outPoint` (or its alias `previousOutput`).
|
|
449
|
+
* This is used as a type constraint for creating `Cell` instances.
|
|
450
|
+
* @see Cell
|
|
451
|
+
* @public
|
|
452
|
+
*/
|
|
453
|
+
export type CellLike = CellAnyLike &
|
|
454
|
+
(
|
|
455
|
+
| {
|
|
456
|
+
outPoint: OutPointLike;
|
|
457
|
+
previousOutput?: undefined | null;
|
|
458
|
+
}
|
|
459
|
+
| {
|
|
460
|
+
outPoint?: undefined | null;
|
|
461
|
+
previousOutput: OutPointLike;
|
|
462
|
+
}
|
|
463
|
+
);
|
|
464
|
+
/**
|
|
465
|
+
* Represents an on-chain CKB cell, which is a `CellAny` that is guaranteed to have an `outPoint`.
|
|
466
|
+
* This class is typically used for cells that are already part of the blockchain state, such as transaction inputs.
|
|
467
|
+
* @public
|
|
468
|
+
*/
|
|
469
|
+
export class Cell extends CellAny {
|
|
470
|
+
/**
|
|
471
|
+
* Creates an instance of an on-chain Cell.
|
|
472
|
+
*
|
|
473
|
+
* @param outPoint - The output point of the cell.
|
|
474
|
+
* @param cellOutput - The cell output of the cell.
|
|
475
|
+
* @param outputData - The output data of the cell.
|
|
476
|
+
*/
|
|
477
|
+
|
|
478
|
+
constructor(
|
|
479
|
+
public outPoint: OutPoint,
|
|
480
|
+
cellOutput: CellOutput,
|
|
481
|
+
outputData: Hex,
|
|
482
|
+
) {
|
|
483
|
+
super(cellOutput, outputData, outPoint);
|
|
484
|
+
}
|
|
337
485
|
|
|
338
486
|
/**
|
|
339
487
|
* Creates a Cell instance from a CellLike object.
|
|
@@ -376,25 +524,10 @@ export class Cell {
|
|
|
376
524
|
}
|
|
377
525
|
|
|
378
526
|
return new Cell(
|
|
379
|
-
OutPoint.from(
|
|
527
|
+
OutPoint.from(cell.outPoint ?? cell.previousOutput),
|
|
380
528
|
CellOutput.from(cell.cellOutput, cell.outputData),
|
|
381
|
-
hexFrom(cell.outputData),
|
|
382
|
-
);
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
get capacityFree() {
|
|
386
|
-
const occupiedSize = fixedPointFrom(
|
|
387
|
-
this.cellOutput.occupiedSize + bytesFrom(this.outputData).length,
|
|
529
|
+
hexFrom(cell.outputData ?? "0x"),
|
|
388
530
|
);
|
|
389
|
-
return this.cellOutput.capacity - occupiedSize;
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
/**
|
|
393
|
-
* Occupied bytes of a cell on chain
|
|
394
|
-
* It's CellOutput.occupiedSize + bytesFrom(outputData).byteLength
|
|
395
|
-
*/
|
|
396
|
-
get occupiedSize() {
|
|
397
|
-
return this.cellOutput.occupiedSize + bytesFrom(this.outputData).byteLength;
|
|
398
531
|
}
|
|
399
532
|
|
|
400
533
|
/**
|
|
@@ -426,30 +559,22 @@ export class Cell {
|
|
|
426
559
|
return calcDaoProfit(this.capacityFree, depositHeader, withdrawHeader);
|
|
427
560
|
}
|
|
428
561
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
const hasWithdrew = numFrom(this.outputData) !== Zero;
|
|
446
|
-
return (
|
|
447
|
-
!phase ||
|
|
448
|
-
(phase === "deposited" && !hasWithdrew) ||
|
|
449
|
-
(phase === "withdrew" && hasWithdrew)
|
|
450
|
-
);
|
|
451
|
-
}
|
|
452
|
-
|
|
562
|
+
/**
|
|
563
|
+
* Retrieves detailed information about a Nervos DAO cell, including its deposit and withdrawal headers.
|
|
564
|
+
*
|
|
565
|
+
* @param client - A CKB client instance to fetch cell and header data.
|
|
566
|
+
* @returns A promise that resolves to an object containing header information.
|
|
567
|
+
* - If not a DAO cell, returns `{}`.
|
|
568
|
+
* - If a deposited DAO cell, returns `{ depositHeader }`.
|
|
569
|
+
* - If a withdrawn DAO cell, returns `{ depositHeader, withdrawHeader }`.
|
|
570
|
+
*
|
|
571
|
+
* @throws If the cell is a DAO cell but its corresponding headers cannot be fetched.
|
|
572
|
+
*
|
|
573
|
+
* @example
|
|
574
|
+
* ```typescript
|
|
575
|
+
* const daoInfo = await cell.getNervosDaoInfo(client);
|
|
576
|
+
* ```
|
|
577
|
+
*/
|
|
453
578
|
async getNervosDaoInfo(client: Client): Promise<
|
|
454
579
|
// Non Nervos DAO cell
|
|
455
580
|
| {
|
|
@@ -1583,39 +1708,92 @@ export class Transaction extends mol.Entity.Base<
|
|
|
1583
1708
|
* await tx.getOutput(0);
|
|
1584
1709
|
* ```
|
|
1585
1710
|
*/
|
|
1586
|
-
getOutput(index: NumLike):
|
|
1587
|
-
| {
|
|
1588
|
-
cellOutput: CellOutput;
|
|
1589
|
-
outputData: Hex;
|
|
1590
|
-
}
|
|
1591
|
-
| undefined {
|
|
1711
|
+
getOutput(index: NumLike): CellAny | undefined {
|
|
1592
1712
|
const i = Number(numFrom(index));
|
|
1593
1713
|
if (i >= this.outputs.length) {
|
|
1594
1714
|
return;
|
|
1595
1715
|
}
|
|
1596
|
-
return {
|
|
1716
|
+
return CellAny.from({
|
|
1597
1717
|
cellOutput: this.outputs[i],
|
|
1598
1718
|
outputData: this.outputsData[i] ?? "0x",
|
|
1599
|
-
};
|
|
1719
|
+
});
|
|
1600
1720
|
}
|
|
1721
|
+
|
|
1601
1722
|
/**
|
|
1602
|
-
*
|
|
1723
|
+
* Provides an iterable over the transaction's output cells.
|
|
1724
|
+
*
|
|
1725
|
+
* This getter is a convenient way to iterate through all the output cells (`CellAny`)
|
|
1726
|
+
* of the transaction, combining the `outputs` and `outputsData` arrays.
|
|
1727
|
+
* It can be used with `for...of` loops or other iterable-consuming patterns.
|
|
1603
1728
|
*
|
|
1604
|
-
* @
|
|
1605
|
-
* @
|
|
1729
|
+
* @public
|
|
1730
|
+
* @category Getter
|
|
1731
|
+
* @returns An `Iterable<CellAny>` that yields each output cell of the transaction.
|
|
1606
1732
|
*
|
|
1607
1733
|
* @example
|
|
1608
1734
|
* ```typescript
|
|
1609
|
-
*
|
|
1735
|
+
* for (const cell of tx.outputCells) {
|
|
1736
|
+
* console.log(`Output cell capacity: ${cell.cellOutput.capacity}`);
|
|
1737
|
+
* }
|
|
1610
1738
|
* ```
|
|
1611
1739
|
*/
|
|
1740
|
+
get outputCells(): Iterable<CellAny> {
|
|
1741
|
+
const { outputs, outputsData } = this;
|
|
1742
|
+
|
|
1743
|
+
function* generator(): Generator<CellAny> {
|
|
1744
|
+
for (let i = 0; i < outputs.length; i++) {
|
|
1745
|
+
yield CellAny.from({
|
|
1746
|
+
cellOutput: outputs[i],
|
|
1747
|
+
outputData: outputsData[i] ?? "0x",
|
|
1748
|
+
});
|
|
1749
|
+
}
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1752
|
+
return generator();
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1755
|
+
/**
|
|
1756
|
+
* Adds an output to the transaction.
|
|
1757
|
+
*
|
|
1758
|
+
* This method supports two overloads for adding an output:
|
|
1759
|
+
* 1. By providing a `CellAnyLike` object, which encapsulates both `cellOutput` and `outputData`.
|
|
1760
|
+
* 2. By providing a `CellOutputLike` object and an optional `outputData`.
|
|
1761
|
+
*
|
|
1762
|
+
* @param cellOrOutputLike - A cell-like object containing both cell output and data, or just the cell output object.
|
|
1763
|
+
* @param outputDataLike - Optional data for the cell output. Defaults to "0x" if not provided in the first argument.
|
|
1764
|
+
* @returns The new number of outputs in the transaction.
|
|
1765
|
+
*
|
|
1766
|
+
* @example
|
|
1767
|
+
* ```typescript
|
|
1768
|
+
* // 1. Add an output using a CellAnyLike object
|
|
1769
|
+
* const newLength1 = tx.addOutput({
|
|
1770
|
+
* cellOutput: { lock: recipientLock }, // capacity is calculated automatically
|
|
1771
|
+
* outputData: "0x1234",
|
|
1772
|
+
* });
|
|
1773
|
+
*
|
|
1774
|
+
* // 2. Add an output using CellOutputLike and data separately
|
|
1775
|
+
* const newLength2 = tx.addOutput({ lock: recipientLock }, "0xabcd");
|
|
1776
|
+
* ```
|
|
1777
|
+
*/
|
|
1778
|
+
addOutput(cellLike: CellAnyLike): number;
|
|
1779
|
+
addOutput(
|
|
1780
|
+
outputLike: CellOutputLike,
|
|
1781
|
+
outputDataLike?: HexLike | null,
|
|
1782
|
+
): number;
|
|
1612
1783
|
addOutput(
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
outputData: HexLike = "0x",
|
|
1784
|
+
cellOrOutputLike: CellAnyLike | CellOutputLike,
|
|
1785
|
+
outputDataLike?: HexLike | null,
|
|
1616
1786
|
): number {
|
|
1617
|
-
const
|
|
1618
|
-
|
|
1787
|
+
const cell =
|
|
1788
|
+
"cellOutput" in cellOrOutputLike
|
|
1789
|
+
? CellAny.from(cellOrOutputLike)
|
|
1790
|
+
: CellAny.from({
|
|
1791
|
+
cellOutput: cellOrOutputLike,
|
|
1792
|
+
outputData: outputDataLike,
|
|
1793
|
+
});
|
|
1794
|
+
|
|
1795
|
+
const len = this.outputs.push(cell.cellOutput);
|
|
1796
|
+
this.setOutputDataAt(len - 1, cell.outputData);
|
|
1619
1797
|
|
|
1620
1798
|
return len;
|
|
1621
1799
|
}
|
package/src/client/client.ts
CHANGED
|
@@ -177,6 +177,13 @@ export abstract class Client {
|
|
|
177
177
|
txHash: HexLike,
|
|
178
178
|
): Promise<ClientTransactionResponse | undefined>;
|
|
179
179
|
|
|
180
|
+
/**
|
|
181
|
+
* Get a cell by its out point.
|
|
182
|
+
* The cell will be cached if it is found.
|
|
183
|
+
*
|
|
184
|
+
* @param outPointLike - The out point of the cell to get.
|
|
185
|
+
* @returns The cell if it exists, otherwise undefined.
|
|
186
|
+
*/
|
|
180
187
|
async getCell(outPointLike: OutPointLike): Promise<Cell | undefined> {
|
|
181
188
|
const outPoint = OutPoint.from(outPointLike);
|
|
182
189
|
const cached = await this.cache.getCell(outPoint);
|
|
@@ -195,8 +202,8 @@ export abstract class Client {
|
|
|
195
202
|
}
|
|
196
203
|
|
|
197
204
|
const cell = Cell.from({
|
|
198
|
-
outPoint,
|
|
199
205
|
...output,
|
|
206
|
+
outPoint,
|
|
200
207
|
});
|
|
201
208
|
await this.cache.recordCells(cell);
|
|
202
209
|
return cell;
|
|
@@ -219,8 +226,8 @@ export abstract class Client {
|
|
|
219
226
|
}
|
|
220
227
|
|
|
221
228
|
const cell = Cell.from({
|
|
222
|
-
outPoint,
|
|
223
229
|
...output,
|
|
230
|
+
outPoint,
|
|
224
231
|
});
|
|
225
232
|
await this.cache.recordCells(cell);
|
|
226
233
|
return { cell, header };
|
|
@@ -251,11 +251,14 @@ export abstract class ClientJsonRpc extends Client {
|
|
|
251
251
|
|
|
252
252
|
sendTransactionNoCache = this.buildSender(
|
|
253
253
|
"send_transaction",
|
|
254
|
-
[
|
|
254
|
+
[
|
|
255
|
+
JsonRpcTransformers.transactionFrom,
|
|
256
|
+
(validator?: OutputsValidator | null) => validator ?? undefined,
|
|
257
|
+
],
|
|
255
258
|
hexFrom,
|
|
256
259
|
) as (
|
|
257
260
|
transaction: TransactionLike,
|
|
258
|
-
validator?: OutputsValidator |
|
|
261
|
+
validator?: OutputsValidator | null,
|
|
259
262
|
) => Promise<Hex>;
|
|
260
263
|
|
|
261
264
|
/**
|
|
@@ -124,7 +124,12 @@ export class JsonRpcTransformers {
|
|
|
124
124
|
since: cellInput.since,
|
|
125
125
|
});
|
|
126
126
|
}
|
|
127
|
-
static cellOutputFrom(
|
|
127
|
+
static cellOutputFrom(
|
|
128
|
+
cellOutputLike: CellOutputLike,
|
|
129
|
+
outputData?: HexLike | null,
|
|
130
|
+
): JsonRpcCellOutput {
|
|
131
|
+
const cellOutput = CellOutput.from(cellOutputLike, outputData);
|
|
132
|
+
|
|
128
133
|
return {
|
|
129
134
|
capacity: numToHex(cellOutput.capacity),
|
|
130
135
|
lock: JsonRpcTransformers.scriptFrom(cellOutput.lock),
|
package/src/jsonRpc/requestor.ts
CHANGED
|
@@ -141,8 +141,8 @@ export class RequestorJsonRpc {
|
|
|
141
141
|
if (res.id !== payload.id) {
|
|
142
142
|
throw new Error(`Id mismatched, got ${res.id}, expected ${payload.id}`);
|
|
143
143
|
}
|
|
144
|
-
if (res.error) {
|
|
145
|
-
throw res.error;
|
|
144
|
+
if (res.error != null) {
|
|
145
|
+
throw res.error as unknown;
|
|
146
146
|
}
|
|
147
147
|
return res.result;
|
|
148
148
|
}
|
package/src/signer/btc/verify.ts
CHANGED
|
@@ -1,10 +1,59 @@
|
|
|
1
1
|
import { secp256k1 } from "@noble/curves/secp256k1";
|
|
2
2
|
import { ripemd160 } from "@noble/hashes/legacy.js";
|
|
3
3
|
import { sha256 } from "@noble/hashes/sha2.js";
|
|
4
|
-
import { magicHash } from "bitcoinjs-message";
|
|
5
4
|
import bs58check from "bs58check";
|
|
6
|
-
import { Bytes,
|
|
5
|
+
import { Bytes, bytesConcat, bytesFrom, BytesLike } from "../../bytes/index.js";
|
|
7
6
|
import { Hex, hexFrom } from "../../hex/index.js";
|
|
7
|
+
import { numFrom, numLeToBytes, NumLike } from "../../num/index.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Encodes a number into a variable-length byte array according to the Bitcoin protocol.
|
|
11
|
+
* This format is used for encoding lengths of data, such as script lengths.
|
|
12
|
+
*
|
|
13
|
+
* @param len - The number to encode. Can be a NumLike.
|
|
14
|
+
* @returns The encoded length as a Bytes.
|
|
15
|
+
* @public
|
|
16
|
+
*/
|
|
17
|
+
export function btcVarLengthBytesFrom(len: NumLike): Bytes {
|
|
18
|
+
const num = numFrom(len);
|
|
19
|
+
|
|
20
|
+
return num < 0xfd
|
|
21
|
+
? numLeToBytes(num, 1)
|
|
22
|
+
: num <= 0xffff
|
|
23
|
+
? bytesConcat([0xfd], numLeToBytes(num, 2))
|
|
24
|
+
: num <= 0xffffffff
|
|
25
|
+
? bytesConcat([0xfe], numLeToBytes(num, 4))
|
|
26
|
+
: bytesConcat([0xff], numLeToBytes(num, 8));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Computes the message hash for Bitcoin ECDSA signatures.
|
|
31
|
+
* This function follows the Bitcoin message signing standard, which involves
|
|
32
|
+
* prefixing the message with a magic string and its length, then double SHA256 hashing the result.
|
|
33
|
+
*
|
|
34
|
+
* @param message - The message to be hashed. Can be a string or BytesLike.
|
|
35
|
+
* @param messagePrefix - Optional. A custom prefix to use instead of the default "\u0018Bitcoin Signed Message:\n".
|
|
36
|
+
* @returns The Bitcoin hash of the prefixed message as Bytes.
|
|
37
|
+
* @public
|
|
38
|
+
*/
|
|
39
|
+
export function messageHashBtcEcdsa(
|
|
40
|
+
message: string | BytesLike,
|
|
41
|
+
messagePrefix?: string | BytesLike,
|
|
42
|
+
): Bytes {
|
|
43
|
+
const prefix = messagePrefix ?? "\u0018Bitcoin Signed Message:\n";
|
|
44
|
+
const rawPrefix: Bytes =
|
|
45
|
+
typeof prefix === "string" ? bytesFrom(prefix, "utf8") : bytesFrom(prefix);
|
|
46
|
+
const rawMsg: Bytes =
|
|
47
|
+
typeof message === "string"
|
|
48
|
+
? bytesFrom(message, "utf8")
|
|
49
|
+
: bytesFrom(message);
|
|
50
|
+
|
|
51
|
+
return sha256(
|
|
52
|
+
sha256(
|
|
53
|
+
bytesConcat(rawPrefix, btcVarLengthBytesFrom(rawMsg.length), rawMsg),
|
|
54
|
+
),
|
|
55
|
+
);
|
|
56
|
+
}
|
|
8
57
|
|
|
9
58
|
/**
|
|
10
59
|
* @public
|
|
@@ -47,7 +96,7 @@ export function verifyMessageBtcEcdsa(
|
|
|
47
96
|
|
|
48
97
|
return secp256k1.verify(
|
|
49
98
|
bytesFrom(rawSign),
|
|
50
|
-
|
|
99
|
+
messageHashBtcEcdsa(challenge),
|
|
51
100
|
bytesFrom(publicKey),
|
|
52
101
|
);
|
|
53
102
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { secp256k1 } from "@noble/curves/secp256k1";
|
|
2
|
-
import { magicHash } from "bitcoinjs-message";
|
|
3
2
|
import {
|
|
4
3
|
Bytes,
|
|
5
4
|
bytesConcat,
|
|
@@ -11,6 +10,7 @@ import { Client } from "../../client/index.js";
|
|
|
11
10
|
import { Hex, hexFrom } from "../../hex/index.js";
|
|
12
11
|
import { btcP2pkhAddressFromPublicKey } from "../btc/verify.js";
|
|
13
12
|
import { SignerDoge } from "./signerDoge.js";
|
|
13
|
+
import { messageHashDogeEcdsa } from "./verify.js";
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* A class extending SignerDoge that provides access to a Doge address.
|
|
@@ -85,7 +85,7 @@ export class SignerDogePrivateKey extends SignerDoge {
|
|
|
85
85
|
const challenge = typeof msg === "string" ? msg : hexFrom(msg).slice(2);
|
|
86
86
|
|
|
87
87
|
const signature = secp256k1.sign(
|
|
88
|
-
|
|
88
|
+
messageHashDogeEcdsa(challenge),
|
|
89
89
|
this.privateKey,
|
|
90
90
|
);
|
|
91
91
|
|
|
@@ -1,12 +1,32 @@
|
|
|
1
1
|
import { secp256k1 } from "@noble/curves/secp256k1";
|
|
2
|
-
import {
|
|
3
|
-
import { bytesFrom, BytesLike } from "../../bytes/index.js";
|
|
2
|
+
import { Bytes, bytesFrom, BytesLike } from "../../bytes/index.js";
|
|
4
3
|
import { hexFrom } from "../../hex/index.js";
|
|
5
4
|
import {
|
|
6
5
|
btcEcdsaPublicKeyHash,
|
|
7
6
|
btcPublicKeyFromP2pkhAddress,
|
|
7
|
+
messageHashBtcEcdsa,
|
|
8
8
|
} from "../btc/verify.js";
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Computes the message hash for Dogecoin ECDSA signatures.
|
|
12
|
+
* This function follows the Dogecoin message signing standard, which involves
|
|
13
|
+
* prefixing the message with a magic string and its length, then double SHA256 hashing the result.
|
|
14
|
+
*
|
|
15
|
+
* @param message - The message to be hashed. Can be a string or BytesLike.
|
|
16
|
+
* @param messagePrefix - Optional. A custom prefix to use instead of the default "\x19Dogecoin Signed Message:\n".
|
|
17
|
+
* @returns The Dogecoin hash of the prefixed message as Bytes.
|
|
18
|
+
* @public
|
|
19
|
+
*/
|
|
20
|
+
export function messageHashDogeEcdsa(
|
|
21
|
+
message: string | BytesLike,
|
|
22
|
+
messagePrefix?: string | BytesLike,
|
|
23
|
+
): Bytes {
|
|
24
|
+
return messageHashBtcEcdsa(
|
|
25
|
+
message,
|
|
26
|
+
messagePrefix ?? "\x19Dogecoin Signed Message:\n",
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
10
30
|
/**
|
|
11
31
|
* @public
|
|
12
32
|
*/
|
|
@@ -29,11 +49,7 @@ export function verifyMessageDogeEcdsa(
|
|
|
29
49
|
btcPublicKeyFromP2pkhAddress(address) ===
|
|
30
50
|
hexFrom(
|
|
31
51
|
btcEcdsaPublicKeyHash(
|
|
32
|
-
sig
|
|
33
|
-
.recoverPublicKey(
|
|
34
|
-
magicHash(challenge, "\x19Dogecoin Signed Message:\n"),
|
|
35
|
-
)
|
|
36
|
-
.toHex(),
|
|
52
|
+
sig.recoverPublicKey(messageHashDogeEcdsa(challenge)).toHex(),
|
|
37
53
|
),
|
|
38
54
|
)
|
|
39
55
|
);
|
|
@@ -96,11 +96,12 @@ export abstract class Signer {
|
|
|
96
96
|
): NetworkPreference | undefined {
|
|
97
97
|
if (
|
|
98
98
|
currentNetwork !== undefined &&
|
|
99
|
-
preferences.some(
|
|
100
|
-
signerType
|
|
99
|
+
preferences.some(
|
|
100
|
+
({ signerType, addressPrefix, network }) =>
|
|
101
|
+
signerType === this.type &&
|
|
101
102
|
addressPrefix === this.client.addressPrefix &&
|
|
102
|
-
network === currentNetwork
|
|
103
|
-
|
|
103
|
+
network === currentNetwork,
|
|
104
|
+
)
|
|
104
105
|
) {
|
|
105
106
|
return;
|
|
106
107
|
}
|
|
@@ -459,14 +460,23 @@ export abstract class Signer {
|
|
|
459
460
|
}
|
|
460
461
|
|
|
461
462
|
/**
|
|
462
|
-
*
|
|
463
|
+
* Prepares a transaction before signing.
|
|
464
|
+
* This method can be overridden by subclasses to perform any necessary steps,
|
|
465
|
+
* such as adding cell dependencies or witnesses, before the transaction is signed.
|
|
466
|
+
* The default implementation converts the {@link TransactionLike} object to a {@link Transaction} object
|
|
467
|
+
* without modification.
|
|
463
468
|
*
|
|
464
|
-
* @
|
|
465
|
-
*
|
|
466
|
-
*
|
|
469
|
+
* @remarks
|
|
470
|
+
* Note that this default implementation does not add any cell dependencies or dummy witnesses.
|
|
471
|
+
* This may lead to an underestimation of transaction size and fees if used with methods
|
|
472
|
+
* like `Transaction.completeFee`. Subclasses for signers that are intended to sign
|
|
473
|
+
* transactions should override this method to perform necessary preparations.
|
|
474
|
+
*
|
|
475
|
+
* @param tx - The transaction to prepare.
|
|
476
|
+
* @returns A promise that resolves to the prepared {@link Transaction} object.
|
|
467
477
|
*/
|
|
468
|
-
prepareTransaction(
|
|
469
|
-
|
|
478
|
+
async prepareTransaction(tx: TransactionLike): Promise<Transaction> {
|
|
479
|
+
return Transaction.from(tx);
|
|
470
480
|
}
|
|
471
481
|
|
|
472
482
|
/**
|