@ckbfs/api 2.0.0 → 2.0.2

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.
@@ -87,6 +87,15 @@ export declare function preparePublishV3Transaction(options: PublishV3Options):
87
87
  * @returns Promise resolving to the created transaction
88
88
  */
89
89
  export declare function createPublishV3Transaction(signer: Signer, options: PublishV3Options): Promise<Transaction>;
90
+ /**
91
+ * Prepares a transaction for appending content to a CKBFS v3 file without fee and change handling
92
+ * @param options Options for appending content
93
+ * @returns Promise resolving to the prepared transaction and the output index of CKBFS Cell
94
+ */
95
+ export declare function prepareAppendV3Transaction(options: AppendV3Options): Promise<{
96
+ tx: Transaction;
97
+ outputIndex: number;
98
+ }>;
90
99
  /**
91
100
  * Creates a transaction for appending content to a CKBFS v3 file
92
101
  * @param signer The signer to use for the transaction
@@ -94,6 +103,13 @@ export declare function createPublishV3Transaction(signer: Signer, options: Publ
94
103
  * @returns Promise resolving to the created transaction
95
104
  */
96
105
  export declare function createAppendV3Transaction(signer: Signer, options: AppendV3Options): Promise<Transaction>;
106
+ /**
107
+ * Creates a transaction for appending content to a CKBFS v3 file (dry run without fee completion)
108
+ * @param signer The signer to use for the transaction
109
+ * @param options Options for appending content
110
+ * @returns Promise resolving to the created transaction
111
+ */
112
+ export declare function createAppendV3TransactionDry(signer: Signer, options: AppendV3Options): Promise<Transaction>;
97
113
  /**
98
114
  * Creates a transaction for transferring ownership of a CKBFS v3 file
99
115
  * @param signer The signer to use for the transaction
@@ -3,7 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createCKBFSV3Cell = createCKBFSV3Cell;
4
4
  exports.preparePublishV3Transaction = preparePublishV3Transaction;
5
5
  exports.createPublishV3Transaction = createPublishV3Transaction;
6
+ exports.prepareAppendV3Transaction = prepareAppendV3Transaction;
6
7
  exports.createAppendV3Transaction = createAppendV3Transaction;
8
+ exports.createAppendV3TransactionDry = createAppendV3TransactionDry;
7
9
  exports.createTransferV3Transaction = createTransferV3Transaction;
8
10
  exports.publishCKBFSV3 = publishCKBFSV3;
9
11
  exports.appendCKBFSV3 = appendCKBFSV3;
@@ -209,6 +211,125 @@ async function createPublishV3Transaction(signer, options) {
209
211
  }
210
212
  return preTx;
211
213
  }
214
+ /**
215
+ * Prepares a transaction for appending content to a CKBFS v3 file without fee and change handling
216
+ * @param options Options for appending content
217
+ * @returns Promise resolving to the prepared transaction and the output index of CKBFS Cell
218
+ */
219
+ async function prepareAppendV3Transaction(options) {
220
+ const { from, ckbfsCell, contentChunks, network = constants_1.DEFAULT_NETWORK, previousTxHash, previousWitnessIndex, previousChecksum, } = options;
221
+ // Calculate new checksum by updating from previous checksum
222
+ const combinedContent = Buffer.concat(contentChunks);
223
+ const newChecksum = await (0, checksum_1.updateChecksum)(previousChecksum, combinedContent);
224
+ // Calculate the actual witness indices where our content is placed
225
+ const contentStartIndex = from?.witnesses.length || 1;
226
+ // Create CKBFS v3 witnesses with backlink info
227
+ const ckbfsWitnesses = (0, witness_1.createChunkedCKBFSV3Witnesses)(contentChunks, {
228
+ previousTxHash,
229
+ previousWitnessIndex,
230
+ previousChecksum,
231
+ startIndex: contentStartIndex,
232
+ });
233
+ // Create updated CKBFS v3 cell output data
234
+ const outputData = molecule_1.CKBFSData.pack({
235
+ index: contentStartIndex,
236
+ checksum: newChecksum,
237
+ contentType: ckbfsCell.data.contentType,
238
+ filename: ckbfsCell.data.filename,
239
+ }, constants_1.ProtocolVersion.V3);
240
+ // Get CKBFS script config
241
+ const config = (0, constants_1.getCKBFSScriptConfig)(network, constants_1.ProtocolVersion.V3, false);
242
+ // Calculate the required capacity for the output cell
243
+ const ckbfsCellSize = BigInt(outputData.length + ckbfsCell.type.occupiedSize + ckbfsCell.lock.occupiedSize + 8) *
244
+ 100000000n;
245
+ // Use the maximum value between calculated size and original capacity
246
+ const outputCapacity = ckbfsCellSize > ckbfsCell.capacity ? ckbfsCellSize : ckbfsCell.capacity;
247
+ // Create initial transaction with the CKBFS cell input
248
+ let preTx;
249
+ if (from) {
250
+ // If from is not empty, inject/merge the fields
251
+ preTx = core_1.Transaction.from({
252
+ ...from,
253
+ inputs: from.inputs.length === 0
254
+ ? [
255
+ {
256
+ previousOutput: ckbfsCell.outPoint,
257
+ since: "0x0",
258
+ },
259
+ ]
260
+ : [
261
+ ...from.inputs,
262
+ {
263
+ previousOutput: ckbfsCell.outPoint,
264
+ since: "0x0",
265
+ },
266
+ ],
267
+ outputs: from.outputs.length === 0
268
+ ? [
269
+ {
270
+ lock: ckbfsCell.lock,
271
+ type: ckbfsCell.type,
272
+ capacity: outputCapacity,
273
+ },
274
+ ]
275
+ : [
276
+ ...from.outputs,
277
+ {
278
+ lock: ckbfsCell.lock,
279
+ type: ckbfsCell.type,
280
+ capacity: outputCapacity,
281
+ },
282
+ ],
283
+ outputsData: from.outputsData.length === 0
284
+ ? [outputData]
285
+ : [
286
+ ...from.outputsData,
287
+ outputData,
288
+ ],
289
+ witnesses: from.witnesses.length === 0
290
+ ? [
291
+ [], // Empty secp witness for signing if not provided
292
+ ...ckbfsWitnesses.map((w) => `0x${Buffer.from(w).toString("hex")}`),
293
+ ]
294
+ : [
295
+ ...from.witnesses,
296
+ ...ckbfsWitnesses.map((w) => `0x${Buffer.from(w).toString("hex")}`),
297
+ ],
298
+ });
299
+ }
300
+ else {
301
+ preTx = core_1.Transaction.from({
302
+ inputs: [
303
+ {
304
+ previousOutput: ckbfsCell.outPoint,
305
+ since: "0x0",
306
+ },
307
+ ],
308
+ outputs: [
309
+ {
310
+ lock: ckbfsCell.lock,
311
+ type: ckbfsCell.type,
312
+ capacity: outputCapacity,
313
+ },
314
+ ],
315
+ witnesses: [
316
+ [], // Empty secp witness for signing
317
+ ...ckbfsWitnesses.map((w) => `0x${Buffer.from(w).toString("hex")}`),
318
+ ],
319
+ outputsData: [outputData],
320
+ });
321
+ }
322
+ // Add the CKBFS dep group cell dependency
323
+ preTx.addCellDeps({
324
+ outPoint: {
325
+ txHash: (0, shared_1.ensureHexPrefix)(config.depTxHash),
326
+ index: config.depIndex || 0,
327
+ },
328
+ depType: "depGroup",
329
+ });
330
+ const outputIndex = from ? from.outputs.length : 0;
331
+ return { tx: preTx, outputIndex };
332
+ }
212
333
  /**
213
334
  * Creates a transaction for appending content to a CKBFS v3 file
214
335
  * @param signer The signer to use for the transaction
@@ -216,18 +337,61 @@ async function createPublishV3Transaction(signer, options) {
216
337
  * @returns Promise resolving to the created transaction
217
338
  */
218
339
  async function createAppendV3Transaction(signer, options) {
219
- const { ckbfsCell, contentChunks, feeRate, network = constants_1.DEFAULT_NETWORK, previousTxHash, previousWitnessIndex, previousChecksum, } = options;
340
+ const { ckbfsCell, feeRate, } = options;
341
+ const { lock } = ckbfsCell;
342
+ // Use prepareAppendV3Transaction to create the base transaction
343
+ const { tx: preTx, outputIndex } = await prepareAppendV3Transaction(options);
344
+ // Get the recommended address to ensure lock script cell deps are included
345
+ const address = await signer.getRecommendedAddressObj();
346
+ const inputsBefore = preTx.inputs.length;
347
+ // If we need more capacity than the original cell had, add additional inputs
348
+ if (preTx.outputs[outputIndex].capacity > ckbfsCell.capacity) {
349
+ console.log(`Need additional capacity: ${preTx.outputs[outputIndex].capacity - ckbfsCell.capacity} shannons`);
350
+ // Add more inputs to cover the increased capacity
351
+ await preTx.completeInputsByCapacity(signer);
352
+ }
353
+ const witnesses = [];
354
+ // add empty witness for signer if ckbfs's lock is the same as signer's lock
355
+ if (address.script.hash() === lock.hash()) {
356
+ witnesses.push("0x");
357
+ }
358
+ // add ckbfs witnesses (skip the first witness which is for signing)
359
+ witnesses.push(...preTx.witnesses.slice(1));
360
+ // Add empty witnesses for additional signer inputs
361
+ // This is to ensure that the transaction is valid and can be signed
362
+ for (let i = inputsBefore; i < preTx.inputs.length; i++) {
363
+ witnesses.push("0x");
364
+ }
365
+ preTx.witnesses = witnesses;
366
+ // Complete fee
367
+ await preTx.completeFeeChangeToLock(signer, address.script, feeRate || 2000);
368
+ return preTx;
369
+ }
370
+ /**
371
+ * Creates a transaction for appending content to a CKBFS v3 file (dry run without fee completion)
372
+ * @param signer The signer to use for the transaction
373
+ * @param options Options for appending content
374
+ * @returns Promise resolving to the created transaction
375
+ */
376
+ async function createAppendV3TransactionDry(signer, options) {
377
+ const { ckbfsCell, contentChunks, network = constants_1.DEFAULT_NETWORK, previousTxHash, previousWitnessIndex, previousChecksum, } = options;
378
+ const { lock } = ckbfsCell;
220
379
  // Calculate new checksum by updating from previous checksum
221
380
  const combinedContent = Buffer.concat(contentChunks);
222
381
  const newChecksum = await (0, checksum_1.updateChecksum)(previousChecksum, combinedContent);
382
+ // Get the recommended address to ensure lock script cell deps are included
383
+ const address = await signer.getRecommendedAddressObj();
384
+ // Calculate the actual witness indices where our content is placed
385
+ // CKBFS data starts at index 1 if signer's lock script is the same as ckbfs's lock script
386
+ // else CKBFS data starts at index 0
387
+ const contentStartIndex = address.script.hash() === lock.hash() ? 1 : 0;
223
388
  // Create CKBFS v3 witnesses with backlink info
224
389
  const ckbfsWitnesses = (0, witness_1.createChunkedCKBFSV3Witnesses)(contentChunks, {
225
390
  previousTxHash,
226
391
  previousWitnessIndex,
227
392
  previousChecksum,
393
+ startIndex: contentStartIndex,
228
394
  });
229
- // V3 format uses single index (first witness containing content)
230
- const contentStartIndex = 1; // First witness is for signer, content starts at index 1
231
395
  // Create updated CKBFS v3 cell output data
232
396
  const outputData = molecule_1.CKBFSData.pack({
233
397
  index: contentStartIndex,
@@ -240,9 +404,10 @@ async function createAppendV3Transaction(signer, options) {
240
404
  // Calculate the required capacity for the output cell
241
405
  const ckbfsCellSize = BigInt(outputData.length + ckbfsCell.type.occupiedSize + ckbfsCell.lock.occupiedSize + 8) *
242
406
  100000000n;
407
+ console.log(`Original capacity: ${ckbfsCell.capacity}, Calculated size: ${ckbfsCellSize}, Data size: ${outputData.length}`);
243
408
  // Use the maximum value between calculated size and original capacity
244
409
  const outputCapacity = ckbfsCellSize > ckbfsCell.capacity ? ckbfsCellSize : ckbfsCell.capacity;
245
- // Create transaction
410
+ // Create initial transaction with the CKBFS cell input
246
411
  const tx = core_1.Transaction.from({
247
412
  inputs: [
248
413
  {
@@ -257,10 +422,6 @@ async function createAppendV3Transaction(signer, options) {
257
422
  capacity: outputCapacity,
258
423
  },
259
424
  ],
260
- witnesses: [
261
- [], // Empty secp witness for signing
262
- ...ckbfsWitnesses.map((w) => `0x${Buffer.from(w).toString("hex")}`),
263
- ],
264
425
  outputsData: [outputData],
265
426
  });
266
427
  // Add the CKBFS dep group cell dependency
@@ -271,10 +432,20 @@ async function createAppendV3Transaction(signer, options) {
271
432
  },
272
433
  depType: "depGroup",
273
434
  });
274
- // Complete inputs by capacity for fees
275
- await tx.completeInputsByCapacity(signer);
276
- // Complete fee change to lock
277
- await tx.completeFeeChangeToLock(signer, ckbfsCell.lock, feeRate || 2000);
435
+ const inputsBefore = tx.inputs.length;
436
+ const witnesses = [];
437
+ // add empty witness for signer if ckbfs's lock is the same as signer's lock
438
+ if (address.script.hash() === lock.hash()) {
439
+ witnesses.push("0x");
440
+ }
441
+ // add ckbfs witnesses
442
+ witnesses.push(...ckbfsWitnesses.map((w) => `0x${Buffer.from(w).toString("hex")}`));
443
+ // Add empty witnesses for signer's input
444
+ // This is to ensure that the transaction is valid and can be signed
445
+ for (let i = inputsBefore; i < tx.inputs.length; i++) {
446
+ witnesses.push("0x");
447
+ }
448
+ tx.witnesses = witnesses;
278
449
  return tx;
279
450
  }
280
451
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ckbfs/api",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "SDK for CKBFS protocol on CKB",
5
5
  "license": "MIT",
6
6
  "author": "Code Monad<code@lab-11.org>",
package/src/index.ts CHANGED
@@ -34,7 +34,10 @@ import {
34
34
  appendCKBFSV3,
35
35
  transferCKBFSV3,
36
36
  createPublishV3Transaction,
37
+ prepareAppendV3Transaction,
38
+ preparePublishV3Transaction,
37
39
  createAppendV3Transaction,
40
+ createAppendV3TransactionDry,
38
41
  createTransferV3Transaction,
39
42
  } from "./utils/transaction";
40
43
  import {
@@ -341,6 +341,150 @@ export async function createPublishV3Transaction(
341
341
  return preTx;
342
342
  }
343
343
 
344
+ /**
345
+ * Prepares a transaction for appending content to a CKBFS v3 file without fee and change handling
346
+ * @param options Options for appending content
347
+ * @returns Promise resolving to the prepared transaction and the output index of CKBFS Cell
348
+ */
349
+ export async function prepareAppendV3Transaction(
350
+ options: AppendV3Options,
351
+ ): Promise<{tx: Transaction, outputIndex: number}> {
352
+ const {
353
+ from,
354
+ ckbfsCell,
355
+ contentChunks,
356
+ network = DEFAULT_NETWORK,
357
+ previousTxHash,
358
+ previousWitnessIndex,
359
+ previousChecksum,
360
+ } = options;
361
+
362
+ // Calculate new checksum by updating from previous checksum
363
+ const combinedContent = Buffer.concat(contentChunks);
364
+ const newChecksum = await updateChecksum(previousChecksum, combinedContent);
365
+
366
+ // Calculate the actual witness indices where our content is placed
367
+ const contentStartIndex = from?.witnesses.length || 1;
368
+
369
+ // Create CKBFS v3 witnesses with backlink info
370
+ const ckbfsWitnesses = createChunkedCKBFSV3Witnesses(contentChunks, {
371
+ previousTxHash,
372
+ previousWitnessIndex,
373
+ previousChecksum,
374
+ startIndex: contentStartIndex,
375
+ });
376
+
377
+ // Create updated CKBFS v3 cell output data
378
+ const outputData = CKBFSData.pack(
379
+ {
380
+ index: contentStartIndex,
381
+ checksum: newChecksum,
382
+ contentType: ckbfsCell.data.contentType,
383
+ filename: ckbfsCell.data.filename,
384
+ },
385
+ ProtocolVersion.V3,
386
+ );
387
+
388
+ // Get CKBFS script config
389
+ const config = getCKBFSScriptConfig(network, ProtocolVersion.V3, false);
390
+
391
+ // Calculate the required capacity for the output cell
392
+ const ckbfsCellSize =
393
+ BigInt(outputData.length + ckbfsCell.type.occupiedSize + ckbfsCell.lock.occupiedSize + 8) *
394
+ 100000000n;
395
+
396
+ // Use the maximum value between calculated size and original capacity
397
+ const outputCapacity = ckbfsCellSize > ckbfsCell.capacity ? ckbfsCellSize : ckbfsCell.capacity;
398
+
399
+ // Create initial transaction with the CKBFS cell input
400
+ let preTx: Transaction;
401
+ if (from) {
402
+ // If from is not empty, inject/merge the fields
403
+ preTx = Transaction.from({
404
+ ...from,
405
+ inputs: from.inputs.length === 0
406
+ ? [
407
+ {
408
+ previousOutput: ckbfsCell.outPoint,
409
+ since: "0x0",
410
+ },
411
+ ]
412
+ : [
413
+ ...from.inputs,
414
+ {
415
+ previousOutput: ckbfsCell.outPoint,
416
+ since: "0x0",
417
+ },
418
+ ],
419
+ outputs: from.outputs.length === 0
420
+ ? [
421
+ {
422
+ lock: ckbfsCell.lock,
423
+ type: ckbfsCell.type,
424
+ capacity: outputCapacity,
425
+ },
426
+ ]
427
+ : [
428
+ ...from.outputs,
429
+ {
430
+ lock: ckbfsCell.lock,
431
+ type: ckbfsCell.type,
432
+ capacity: outputCapacity,
433
+ },
434
+ ],
435
+ outputsData: from.outputsData.length === 0
436
+ ? [outputData]
437
+ : [
438
+ ...from.outputsData,
439
+ outputData,
440
+ ],
441
+ witnesses: from.witnesses.length === 0
442
+ ? [
443
+ [], // Empty secp witness for signing if not provided
444
+ ...ckbfsWitnesses.map((w) => `0x${Buffer.from(w).toString("hex")}`),
445
+ ]
446
+ : [
447
+ ...from.witnesses,
448
+ ...ckbfsWitnesses.map((w) => `0x${Buffer.from(w).toString("hex")}`),
449
+ ],
450
+ });
451
+ } else {
452
+ preTx = Transaction.from({
453
+ inputs: [
454
+ {
455
+ previousOutput: ckbfsCell.outPoint,
456
+ since: "0x0",
457
+ },
458
+ ],
459
+ outputs: [
460
+ {
461
+ lock: ckbfsCell.lock,
462
+ type: ckbfsCell.type,
463
+ capacity: outputCapacity,
464
+ },
465
+ ],
466
+ witnesses: [
467
+ [], // Empty secp witness for signing
468
+ ...ckbfsWitnesses.map((w) => `0x${Buffer.from(w).toString("hex")}`),
469
+ ],
470
+ outputsData: [outputData],
471
+ });
472
+ }
473
+
474
+ // Add the CKBFS dep group cell dependency
475
+ preTx.addCellDeps({
476
+ outPoint: {
477
+ txHash: ensureHexPrefix(config.depTxHash),
478
+ index: config.depIndex || 0,
479
+ },
480
+ depType: "depGroup",
481
+ });
482
+
483
+ const outputIndex = from ? from.outputs.length : 0;
484
+
485
+ return {tx: preTx, outputIndex};
486
+ }
487
+
344
488
  /**
345
489
  * Creates a transaction for appending content to a CKBFS v3 file
346
490
  * @param signer The signer to use for the transaction
@@ -353,27 +497,86 @@ export async function createAppendV3Transaction(
353
497
  ): Promise<Transaction> {
354
498
  const {
355
499
  ckbfsCell,
356
- contentChunks,
357
500
  feeRate,
501
+ } = options;
502
+ const { lock } = ckbfsCell;
503
+
504
+ // Use prepareAppendV3Transaction to create the base transaction
505
+ const { tx: preTx, outputIndex } = await prepareAppendV3Transaction(options);
506
+
507
+ // Get the recommended address to ensure lock script cell deps are included
508
+ const address = await signer.getRecommendedAddressObj();
509
+
510
+ const inputsBefore = preTx.inputs.length;
511
+ // If we need more capacity than the original cell had, add additional inputs
512
+ if (preTx.outputs[outputIndex].capacity > ckbfsCell.capacity) {
513
+ console.log(
514
+ `Need additional capacity: ${preTx.outputs[outputIndex].capacity - ckbfsCell.capacity} shannons`,
515
+ );
516
+ // Add more inputs to cover the increased capacity
517
+ await preTx.completeInputsByCapacity(signer);
518
+ }
519
+
520
+ const witnesses: any = [];
521
+ // add empty witness for signer if ckbfs's lock is the same as signer's lock
522
+ if (address.script.hash() === lock.hash()) {
523
+ witnesses.push("0x");
524
+ }
525
+ // add ckbfs witnesses (skip the first witness which is for signing)
526
+ witnesses.push(...preTx.witnesses.slice(1));
527
+
528
+ // Add empty witnesses for additional signer inputs
529
+ // This is to ensure that the transaction is valid and can be signed
530
+ for (let i = inputsBefore; i < preTx.inputs.length; i++) {
531
+ witnesses.push("0x");
532
+ }
533
+ preTx.witnesses = witnesses;
534
+
535
+ // Complete fee
536
+ await preTx.completeFeeChangeToLock(signer, address.script, feeRate || 2000);
537
+
538
+ return preTx;
539
+ }
540
+
541
+ /**
542
+ * Creates a transaction for appending content to a CKBFS v3 file (dry run without fee completion)
543
+ * @param signer The signer to use for the transaction
544
+ * @param options Options for appending content
545
+ * @returns Promise resolving to the created transaction
546
+ */
547
+ export async function createAppendV3TransactionDry(
548
+ signer: Signer,
549
+ options: AppendV3Options,
550
+ ): Promise<Transaction> {
551
+ const {
552
+ ckbfsCell,
553
+ contentChunks,
358
554
  network = DEFAULT_NETWORK,
359
555
  previousTxHash,
360
556
  previousWitnessIndex,
361
557
  previousChecksum,
362
558
  } = options;
559
+ const { lock } = ckbfsCell;
363
560
 
364
561
  // Calculate new checksum by updating from previous checksum
365
562
  const combinedContent = Buffer.concat(contentChunks);
366
563
  const newChecksum = await updateChecksum(previousChecksum, combinedContent);
367
564
 
565
+ // Get the recommended address to ensure lock script cell deps are included
566
+ const address = await signer.getRecommendedAddressObj();
567
+
568
+ // Calculate the actual witness indices where our content is placed
569
+ // CKBFS data starts at index 1 if signer's lock script is the same as ckbfs's lock script
570
+ // else CKBFS data starts at index 0
571
+ const contentStartIndex = address.script.hash() === lock.hash() ? 1 : 0;
572
+
368
573
  // Create CKBFS v3 witnesses with backlink info
369
574
  const ckbfsWitnesses = createChunkedCKBFSV3Witnesses(contentChunks, {
370
575
  previousTxHash,
371
576
  previousWitnessIndex,
372
577
  previousChecksum,
578
+ startIndex: contentStartIndex,
373
579
  });
374
-
375
- // V3 format uses single index (first witness containing content)
376
- const contentStartIndex = 1; // First witness is for signer, content starts at index 1
377
580
 
378
581
  // Create updated CKBFS v3 cell output data
379
582
  const outputData = CKBFSData.pack(
@@ -394,10 +597,14 @@ export async function createAppendV3Transaction(
394
597
  BigInt(outputData.length + ckbfsCell.type.occupiedSize + ckbfsCell.lock.occupiedSize + 8) *
395
598
  100000000n;
396
599
 
600
+ console.log(
601
+ `Original capacity: ${ckbfsCell.capacity}, Calculated size: ${ckbfsCellSize}, Data size: ${outputData.length}`,
602
+ );
603
+
397
604
  // Use the maximum value between calculated size and original capacity
398
605
  const outputCapacity = ckbfsCellSize > ckbfsCell.capacity ? ckbfsCellSize : ckbfsCell.capacity;
399
606
 
400
- // Create transaction
607
+ // Create initial transaction with the CKBFS cell input
401
608
  const tx = Transaction.from({
402
609
  inputs: [
403
610
  {
@@ -412,10 +619,6 @@ export async function createAppendV3Transaction(
412
619
  capacity: outputCapacity,
413
620
  },
414
621
  ],
415
- witnesses: [
416
- [], // Empty secp witness for signing
417
- ...ckbfsWitnesses.map((w) => `0x${Buffer.from(w).toString("hex")}`),
418
- ],
419
622
  outputsData: [outputData],
420
623
  });
421
624
 
@@ -428,11 +631,24 @@ export async function createAppendV3Transaction(
428
631
  depType: "depGroup",
429
632
  });
430
633
 
431
- // Complete inputs by capacity for fees
432
- await tx.completeInputsByCapacity(signer);
634
+ const inputsBefore = tx.inputs.length;
433
635
 
434
- // Complete fee change to lock
435
- await tx.completeFeeChangeToLock(signer, ckbfsCell.lock, feeRate || 2000);
636
+ const witnesses: any = [];
637
+ // add empty witness for signer if ckbfs's lock is the same as signer's lock
638
+ if (address.script.hash() === lock.hash()) {
639
+ witnesses.push("0x");
640
+ }
641
+ // add ckbfs witnesses
642
+ witnesses.push(
643
+ ...ckbfsWitnesses.map((w) => `0x${Buffer.from(w).toString("hex")}`),
644
+ );
645
+
646
+ // Add empty witnesses for signer's input
647
+ // This is to ensure that the transaction is valid and can be signed
648
+ for (let i = inputsBefore; i < tx.inputs.length; i++) {
649
+ witnesses.push("0x");
650
+ }
651
+ tx.witnesses = witnesses;
436
652
 
437
653
  return tx;
438
654
  }