@ckbfs/api 1.5.0 → 1.5.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/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Script, Signer, Transaction } from "@ckb-ccc/core";
2
2
  import { calculateChecksum, verifyChecksum, updateChecksum, verifyWitnessChecksum } from "./utils/checksum";
3
- import { createCKBFSCell, createPublishTransaction as utilCreatePublishTransaction, createAppendTransaction as utilCreateAppendTransaction, publishCKBFS as utilPublishCKBFS, appendCKBFS as utilAppendCKBFS, CKBFSCellOptions, PublishOptions, AppendOptions } from "./utils/transaction";
3
+ import { createCKBFSCell, createPublishTransaction as utilCreatePublishTransaction, preparePublishTransaction, createAppendTransaction as utilCreateAppendTransaction, prepareAppendTransaction, createAppendTransactionDry, publishCKBFS as utilPublishCKBFS, appendCKBFS as utilAppendCKBFS, CKBFSCellOptions, PublishOptions, AppendOptions } from "./utils/transaction";
4
4
  import { readFile, readFileAsText, readFileAsUint8Array, writeFile, getContentType, splitFileIntoChunks, combineChunksToFile, getFileContentFromChain, saveFileFromChain, getFileContentFromChainByTypeId, saveFileFromChainByTypeId, decodeFileFromChainByTypeId, getFileContentFromChainByIdentifier, saveFileFromChainByIdentifier, decodeFileFromChainByIdentifier, parseIdentifier, IdentifierType, decodeWitnessContent, decodeMultipleWitnessContents, extractFileFromWitnesses, decodeFileFromWitnessData, saveFileFromWitnessData } from "./utils/file";
5
5
  import { createCKBFSWitness, createTextCKBFSWitness, extractCKBFSWitnessContent, isCKBFSWitness, createChunkedCKBFSWitnesses } from "./utils/witness";
6
6
  import { CKBFSData, BackLinkV1, BackLinkV2, CKBFSDataType, BackLinkType, CKBFS_HEADER, CKBFS_HEADER_STRING } from "./utils/molecule";
@@ -132,4 +132,4 @@ export declare class CKBFS {
132
132
  */
133
133
  createAppendContentTransaction(content: string | Uint8Array, ckbfsCell: AppendOptions["ckbfsCell"], options?: AppendContentOptions): Promise<Transaction>;
134
134
  }
135
- export { calculateChecksum, verifyChecksum, updateChecksum, verifyWitnessChecksum, createCKBFSCell, utilCreatePublishTransaction as createPublishTransaction, utilCreateAppendTransaction as createAppendTransaction, utilPublishCKBFS as publishCKBFS, utilAppendCKBFS as appendCKBFS, readFile, readFileAsText, readFileAsUint8Array, writeFile, getContentType, splitFileIntoChunks, combineChunksToFile, getFileContentFromChain, saveFileFromChain, getFileContentFromChainByTypeId, saveFileFromChainByTypeId, decodeFileFromChainByTypeId, getFileContentFromChainByIdentifier, saveFileFromChainByIdentifier, decodeFileFromChainByIdentifier, parseIdentifier, IdentifierType, decodeWitnessContent, decodeMultipleWitnessContents, extractFileFromWitnesses, decodeFileFromWitnessData, saveFileFromWitnessData, createCKBFSWitness, createTextCKBFSWitness, extractCKBFSWitnessContent, isCKBFSWitness, createChunkedCKBFSWitnesses, CKBFSData, BackLinkV1, BackLinkV2, CKBFSDataType, BackLinkType, CKBFSCellOptions, PublishOptions, AppendOptions, CKBFS_HEADER, CKBFS_HEADER_STRING, NetworkType, ProtocolVersion, ProtocolVersionType, DEFAULT_NETWORK, DEFAULT_VERSION, CKBFS_CODE_HASH, CKBFS_TYPE_ID, ADLER32_CODE_HASH, ADLER32_TYPE_ID, DEP_GROUP_TX_HASH, DEPLOY_TX_HASH, getCKBFSScriptConfig, CKBFSScriptConfig, };
135
+ export { calculateChecksum, verifyChecksum, updateChecksum, verifyWitnessChecksum, createCKBFSCell, utilCreatePublishTransaction as createPublishTransaction, preparePublishTransaction, utilCreateAppendTransaction as createAppendTransaction, prepareAppendTransaction, utilPublishCKBFS as publishCKBFS, utilAppendCKBFS as appendCKBFS, createAppendTransactionDry, readFile, readFileAsText, readFileAsUint8Array, writeFile, getContentType, splitFileIntoChunks, combineChunksToFile, getFileContentFromChain, saveFileFromChain, getFileContentFromChainByTypeId, saveFileFromChainByTypeId, decodeFileFromChainByTypeId, getFileContentFromChainByIdentifier, saveFileFromChainByIdentifier, decodeFileFromChainByIdentifier, parseIdentifier, IdentifierType, decodeWitnessContent, decodeMultipleWitnessContents, extractFileFromWitnesses, decodeFileFromWitnessData, saveFileFromWitnessData, createCKBFSWitness, createTextCKBFSWitness, extractCKBFSWitnessContent, isCKBFSWitness, createChunkedCKBFSWitnesses, CKBFSData, BackLinkV1, BackLinkV2, CKBFSDataType, BackLinkType, CKBFSCellOptions, PublishOptions, AppendOptions, CKBFS_HEADER, CKBFS_HEADER_STRING, NetworkType, ProtocolVersion, ProtocolVersionType, DEFAULT_NETWORK, DEFAULT_VERSION, CKBFS_CODE_HASH, CKBFS_TYPE_ID, ADLER32_CODE_HASH, ADLER32_TYPE_ID, DEP_GROUP_TX_HASH, DEPLOY_TX_HASH, getCKBFSScriptConfig, CKBFSScriptConfig, };
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ADLER32_TYPE_ID = exports.ADLER32_CODE_HASH = exports.CKBFS_TYPE_ID = exports.CKBFS_CODE_HASH = exports.DEFAULT_VERSION = exports.DEFAULT_NETWORK = exports.ProtocolVersion = exports.NetworkType = exports.CKBFS_HEADER_STRING = exports.CKBFS_HEADER = exports.BackLinkV2 = exports.BackLinkV1 = exports.CKBFSData = exports.createChunkedCKBFSWitnesses = exports.isCKBFSWitness = exports.extractCKBFSWitnessContent = exports.createTextCKBFSWitness = exports.createCKBFSWitness = exports.saveFileFromWitnessData = exports.decodeFileFromWitnessData = exports.extractFileFromWitnesses = exports.decodeMultipleWitnessContents = exports.decodeWitnessContent = exports.IdentifierType = exports.parseIdentifier = exports.decodeFileFromChainByIdentifier = exports.saveFileFromChainByIdentifier = exports.getFileContentFromChainByIdentifier = exports.decodeFileFromChainByTypeId = exports.saveFileFromChainByTypeId = exports.getFileContentFromChainByTypeId = exports.saveFileFromChain = exports.getFileContentFromChain = exports.combineChunksToFile = exports.splitFileIntoChunks = exports.getContentType = exports.writeFile = exports.readFileAsUint8Array = exports.readFileAsText = exports.readFile = exports.appendCKBFS = exports.publishCKBFS = exports.createAppendTransaction = exports.createPublishTransaction = exports.createCKBFSCell = exports.verifyWitnessChecksum = exports.updateChecksum = exports.verifyChecksum = exports.calculateChecksum = exports.CKBFS = void 0;
4
- exports.getCKBFSScriptConfig = exports.DEPLOY_TX_HASH = exports.DEP_GROUP_TX_HASH = void 0;
3
+ exports.CKBFS_CODE_HASH = exports.DEFAULT_VERSION = exports.DEFAULT_NETWORK = exports.ProtocolVersion = exports.NetworkType = exports.CKBFS_HEADER_STRING = exports.CKBFS_HEADER = exports.BackLinkV2 = exports.BackLinkV1 = exports.CKBFSData = exports.createChunkedCKBFSWitnesses = exports.isCKBFSWitness = exports.extractCKBFSWitnessContent = exports.createTextCKBFSWitness = exports.createCKBFSWitness = exports.saveFileFromWitnessData = exports.decodeFileFromWitnessData = exports.extractFileFromWitnesses = exports.decodeMultipleWitnessContents = exports.decodeWitnessContent = exports.IdentifierType = exports.parseIdentifier = exports.decodeFileFromChainByIdentifier = exports.saveFileFromChainByIdentifier = exports.getFileContentFromChainByIdentifier = exports.decodeFileFromChainByTypeId = exports.saveFileFromChainByTypeId = exports.getFileContentFromChainByTypeId = exports.saveFileFromChain = exports.getFileContentFromChain = exports.combineChunksToFile = exports.splitFileIntoChunks = exports.getContentType = exports.writeFile = exports.readFileAsUint8Array = exports.readFileAsText = exports.readFile = exports.createAppendTransactionDry = exports.appendCKBFS = exports.publishCKBFS = exports.prepareAppendTransaction = exports.createAppendTransaction = exports.preparePublishTransaction = exports.createPublishTransaction = exports.createCKBFSCell = exports.verifyWitnessChecksum = exports.updateChecksum = exports.verifyChecksum = exports.calculateChecksum = exports.CKBFS = void 0;
4
+ exports.getCKBFSScriptConfig = exports.DEPLOY_TX_HASH = exports.DEP_GROUP_TX_HASH = exports.ADLER32_TYPE_ID = exports.ADLER32_CODE_HASH = exports.CKBFS_TYPE_ID = void 0;
5
5
  const core_1 = require("@ckb-ccc/core");
6
6
  const checksum_1 = require("./utils/checksum");
7
7
  Object.defineProperty(exports, "calculateChecksum", { enumerable: true, get: function () { return checksum_1.calculateChecksum; } });
@@ -11,7 +11,10 @@ Object.defineProperty(exports, "verifyWitnessChecksum", { enumerable: true, get:
11
11
  const transaction_1 = require("./utils/transaction");
12
12
  Object.defineProperty(exports, "createCKBFSCell", { enumerable: true, get: function () { return transaction_1.createCKBFSCell; } });
13
13
  Object.defineProperty(exports, "createPublishTransaction", { enumerable: true, get: function () { return transaction_1.createPublishTransaction; } });
14
+ Object.defineProperty(exports, "preparePublishTransaction", { enumerable: true, get: function () { return transaction_1.preparePublishTransaction; } });
14
15
  Object.defineProperty(exports, "createAppendTransaction", { enumerable: true, get: function () { return transaction_1.createAppendTransaction; } });
16
+ Object.defineProperty(exports, "prepareAppendTransaction", { enumerable: true, get: function () { return transaction_1.prepareAppendTransaction; } });
17
+ Object.defineProperty(exports, "createAppendTransactionDry", { enumerable: true, get: function () { return transaction_1.createAppendTransactionDry; } });
15
18
  Object.defineProperty(exports, "publishCKBFS", { enumerable: true, get: function () { return transaction_1.publishCKBFS; } });
16
19
  Object.defineProperty(exports, "appendCKBFS", { enumerable: true, get: function () { return transaction_1.appendCKBFS; } });
17
20
  const file_1 = require("./utils/file");
@@ -42,6 +42,7 @@ export interface AppendOptions {
42
42
  feeRate?: number;
43
43
  network?: NetworkType;
44
44
  version?: ProtocolVersionType;
45
+ from?: Transaction;
45
46
  }
46
47
  /**
47
48
  * Ensures a string is prefixed with '0x'
@@ -77,6 +78,15 @@ export declare function preparePublishTransaction(options: PublishOptions): Prom
77
78
  * @returns Promise resolving to the created transaction
78
79
  */
79
80
  export declare function createPublishTransaction(signer: Signer, options: PublishOptions): Promise<Transaction>;
81
+ /**
82
+ * Prepares a transaction for appending content to a CKBFS file without fee and change handling
83
+ * @param options Options for appending content
84
+ * @returns Promise resolving to the prepared transaction and the output index of CKBFS Cell
85
+ */
86
+ export declare function prepareAppendTransaction(options: AppendOptions): Promise<{
87
+ tx: Transaction;
88
+ outputIndex: number;
89
+ }>;
80
90
  /**
81
91
  * Creates a transaction for appending content to a CKBFS file
82
92
  * @param signer The signer to use for the transaction
@@ -4,6 +4,7 @@ exports.ensureHexPrefix = ensureHexPrefix;
4
4
  exports.createCKBFSCell = createCKBFSCell;
5
5
  exports.preparePublishTransaction = preparePublishTransaction;
6
6
  exports.createPublishTransaction = createPublishTransaction;
7
+ exports.prepareAppendTransaction = prepareAppendTransaction;
7
8
  exports.createAppendTransaction = createAppendTransaction;
8
9
  exports.createAppendTransactionDry = createAppendTransactionDry;
9
10
  exports.publishCKBFS = publishCKBFS;
@@ -224,20 +225,13 @@ async function createPublishTransaction(signer, options) {
224
225
  witnesses: preTx.witnesses,
225
226
  outputsData: preTx.outputsData,
226
227
  inputs: preTx.inputs,
227
- outputs: outputIndex === 0
228
- ? [{
229
- lock,
230
- type: ckbfsTypeScript,
231
- capacity: preTx.outputs[outputIndex].capacity,
232
- }]
233
- : [
234
- ...preTx.outputs.slice(0, outputIndex), // Include outputs before CKBFS cell
235
- {
236
- lock,
237
- type: ckbfsTypeScript,
238
- capacity: preTx.outputs[outputIndex].capacity,
239
- }
240
- ],
228
+ outputs: preTx.outputs.map((output, index) => index === outputIndex
229
+ ? {
230
+ lock,
231
+ type: ckbfsTypeScript,
232
+ capacity: output.capacity,
233
+ }
234
+ : output),
241
235
  });
242
236
  return tx;
243
237
  }
@@ -254,13 +248,12 @@ async function createPublishTransaction(signer, options) {
254
248
  }
255
249
  }
256
250
  /**
257
- * Creates a transaction for appending content to a CKBFS file
258
- * @param signer The signer to use for the transaction
251
+ * Prepares a transaction for appending content to a CKBFS file without fee and change handling
259
252
  * @param options Options for appending content
260
- * @returns Promise resolving to the created transaction
253
+ * @returns Promise resolving to the prepared transaction and the output index of CKBFS Cell
261
254
  */
262
- async function createAppendTransaction(signer, options) {
263
- const { ckbfsCell, contentChunks, feeRate, network = constants_1.DEFAULT_NETWORK, version = constants_1.DEFAULT_VERSION, } = options;
255
+ async function prepareAppendTransaction(options) {
256
+ const { from, ckbfsCell, contentChunks, network = constants_1.DEFAULT_NETWORK, version = constants_1.DEFAULT_VERSION, } = options;
264
257
  const { outPoint, data, type, lock, capacity } = ckbfsCell;
265
258
  // Get CKBFS script config early to use version info
266
259
  const config = (0, constants_1.getCKBFSScriptConfig)(network, version);
@@ -273,13 +266,8 @@ async function createAppendTransaction(signer, options) {
273
266
  // Update the existing checksum with the new content - this matches Adler32's
274
267
  // cumulative nature as required by Rule 11 in the RFC
275
268
  const contentChecksum = await (0, checksum_1.updateChecksum)(data.checksum, combinedContent);
276
- console.log(`Updated checksum from ${data.checksum} to ${contentChecksum} for appended content`);
277
- // Get the recommended address to ensure lock script cell deps are included
278
- const address = await signer.getRecommendedAddressObj();
279
269
  // Calculate the actual witness indices where our content is placed
280
- // CKBFS data starts at index 1 if signer's lock script is the same as ckbfs's lock script
281
- // else CKBFS data starts at index 0
282
- const contentStartIndex = address.script.hash() === lock.hash() ? 1 : 0;
270
+ const contentStartIndex = from?.witnesses.length || 1;
283
271
  const witnessIndices = Array.from({ length: contentChunks.length }, (_, i) => contentStartIndex + i);
284
272
  // Create backlink for the current state based on version
285
273
  let newBackLink;
@@ -329,11 +317,6 @@ async function createAppendTransaction(signer, options) {
329
317
  backLinks,
330
318
  }, constants_1.ProtocolVersion.V2); // Explicitly use V2 for packing
331
319
  }
332
- // Pack the original data to get its size - use the appropriate version
333
- const originalData = molecule_1.CKBFSData.pack(data, version);
334
- const originalDataSize = originalData.length;
335
- // Get sizes and calculate capacity requirements
336
- const newDataSize = outputData.length;
337
320
  // Calculate the required capacity for the output cell
338
321
  // This accounts for:
339
322
  // 1. The output data size
@@ -342,61 +325,140 @@ async function createAppendTransaction(signer, options) {
342
325
  // 4. A constant of 8 bytes (for header overhead)
343
326
  const ckbfsCellSize = BigInt(outputData.length + type.occupiedSize + lock.occupiedSize + 8) *
344
327
  100000000n;
345
- console.log(`Original capacity: ${capacity}, Calculated size: ${ckbfsCellSize}, Data size: ${outputData.length}`);
346
328
  // Use the maximum value between calculated size and original capacity
347
329
  // to ensure we have enough capacity but don't decrease capacity unnecessarily
348
330
  const outputCapacity = ckbfsCellSize > capacity ? ckbfsCellSize : capacity;
349
331
  // Create initial transaction with the CKBFS cell input
350
- const tx = core_1.Transaction.from({
351
- inputs: [
352
- {
353
- previousOutput: {
354
- txHash: outPoint.txHash,
355
- index: outPoint.index,
332
+ let preTx;
333
+ if (from) {
334
+ // If from is not empty, inject/merge the fields
335
+ preTx = core_1.Transaction.from({
336
+ ...from,
337
+ inputs: from.inputs.length === 0
338
+ ? [
339
+ {
340
+ previousOutput: {
341
+ txHash: outPoint.txHash,
342
+ index: outPoint.index,
343
+ },
344
+ since: "0x0",
345
+ },
346
+ ]
347
+ : [
348
+ ...from.inputs,
349
+ {
350
+ previousOutput: {
351
+ txHash: outPoint.txHash,
352
+ index: outPoint.index,
353
+ },
354
+ since: "0x0",
355
+ },
356
+ ],
357
+ outputs: from.outputs.length === 0
358
+ ? [
359
+ {
360
+ lock,
361
+ type,
362
+ capacity: outputCapacity,
363
+ },
364
+ ]
365
+ : [
366
+ ...from.outputs,
367
+ {
368
+ lock,
369
+ type,
370
+ capacity: outputCapacity,
371
+ },
372
+ ],
373
+ outputsData: from.outputsData.length === 0
374
+ ? [outputData]
375
+ : [
376
+ ...from.outputsData,
377
+ outputData,
378
+ ],
379
+ witnesses: from.witnesses.length === 0
380
+ ? [
381
+ [], // Empty secp witness for signing if not provided
382
+ ...ckbfsWitnesses.map((w) => `0x${Buffer.from(w).toString("hex")}`),
383
+ ]
384
+ : [
385
+ ...from.witnesses,
386
+ ...ckbfsWitnesses.map((w) => `0x${Buffer.from(w).toString("hex")}`),
387
+ ],
388
+ });
389
+ }
390
+ else {
391
+ preTx = core_1.Transaction.from({
392
+ inputs: [
393
+ {
394
+ previousOutput: {
395
+ txHash: outPoint.txHash,
396
+ index: outPoint.index,
397
+ },
398
+ since: "0x0",
356
399
  },
357
- since: "0x0",
358
- },
359
- ],
360
- outputs: [
361
- {
362
- lock,
363
- type,
364
- capacity: outputCapacity,
365
- },
366
- ],
367
- outputsData: [outputData],
368
- });
400
+ ],
401
+ outputs: [
402
+ {
403
+ lock,
404
+ type,
405
+ capacity: outputCapacity,
406
+ },
407
+ ],
408
+ outputsData: [outputData],
409
+ witnesses: [
410
+ [], // Empty secp witness for signing
411
+ ...ckbfsWitnesses.map((w) => `0x${Buffer.from(w).toString("hex")}`),
412
+ ],
413
+ });
414
+ }
369
415
  // Add the CKBFS dep group cell dependency
370
- tx.addCellDeps({
416
+ preTx.addCellDeps({
371
417
  outPoint: {
372
418
  txHash: ensureHexPrefix(config.depTxHash),
373
419
  index: config.depIndex || 0,
374
420
  },
375
421
  depType: "depGroup",
376
422
  });
377
- const inputsBefore = tx.inputs.length;
423
+ const outputIndex = from ? from.outputs.length : 0;
424
+ return { tx: preTx, outputIndex };
425
+ }
426
+ /**
427
+ * Creates a transaction for appending content to a CKBFS file
428
+ * @param signer The signer to use for the transaction
429
+ * @param options Options for appending content
430
+ * @returns Promise resolving to the created transaction
431
+ */
432
+ async function createAppendTransaction(signer, options) {
433
+ const { ckbfsCell, feeRate, } = options;
434
+ const { lock } = ckbfsCell;
435
+ // Use prepareAppendTransaction to create the base transaction
436
+ const { tx: preTx, outputIndex } = await prepareAppendTransaction(options);
437
+ // Get the recommended address to ensure lock script cell deps are included
438
+ const address = await signer.getRecommendedAddressObj();
439
+ const inputsBefore = preTx.inputs.length;
378
440
  // If we need more capacity than the original cell had, add additional inputs
379
- if (outputCapacity > capacity) {
380
- console.log(`Need additional capacity: ${outputCapacity - capacity} shannons`);
441
+ if (preTx.outputs[outputIndex].capacity > ckbfsCell.capacity) {
442
+ console.log(`Need additional capacity: ${preTx.outputs[outputIndex].capacity - ckbfsCell.capacity} shannons`);
381
443
  // Add more inputs to cover the increased capacity
382
- await tx.completeInputsByCapacity(signer);
444
+ await preTx.completeInputsByCapacity(signer);
383
445
  }
384
446
  const witnesses = [];
385
447
  // add empty witness for signer if ckbfs's lock is the same as signer's lock
386
448
  if (address.script.hash() === lock.hash()) {
387
449
  witnesses.push("0x");
388
450
  }
389
- // add ckbfs witnesses
390
- witnesses.push(...ckbfsWitnesses.map((w) => `0x${Buffer.from(w).toString("hex")}`));
391
- // Add empty witnesses for signer's input
451
+ // add ckbfs witnesses (skip the first witness which is for signing)
452
+ witnesses.push(...preTx.witnesses.slice(1));
453
+ // Add empty witnesses for additional signer inputs
392
454
  // This is to ensure that the transaction is valid and can be signed
393
- for (let i = inputsBefore; i < tx.inputs.length; i++) {
455
+ for (let i = inputsBefore; i < preTx.inputs.length; i++) {
394
456
  witnesses.push("0x");
395
457
  }
396
- tx.witnesses = witnesses;
458
+ preTx.witnesses = witnesses;
397
459
  // Complete fee
398
- await tx.completeFeeChangeToLock(signer, address.script, feeRate || 2000);
399
- return tx;
460
+ await preTx.completeFeeChangeToLock(signer, address.script, feeRate || 2000);
461
+ return preTx;
400
462
  }
401
463
  /**
402
464
  * Creates a transaction for appending content to a CKBFS file
@@ -474,11 +536,6 @@ async function createAppendTransactionDry(signer, options) {
474
536
  backLinks,
475
537
  }, constants_1.ProtocolVersion.V2); // Explicitly use V2 for packing
476
538
  }
477
- // Pack the original data to get its size - use the appropriate version
478
- const originalData = molecule_1.CKBFSData.pack(data, version);
479
- const originalDataSize = originalData.length;
480
- // Get sizes and calculate capacity requirements
481
- const newDataSize = outputData.length;
482
539
  // Calculate the required capacity for the output cell
483
540
  // This accounts for:
484
541
  // 1. The output data size
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ckbfs/api",
3
- "version": "1.5.0",
3
+ "version": "1.5.1",
4
4
  "description": "SDK for CKBFS protocol on CKB",
5
5
  "license": "MIT",
6
6
  "author": "Code Monad<code@lab-11.org>",