@ckbfs/api 1.2.3 → 1.2.5

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.
@@ -1,14 +1,15 @@
1
1
  import { ccc, Transaction, Script, Signer } from "@ckb-ccc/core";
2
- import { calculateChecksum, updateChecksum } from './checksum';
3
- import { CKBFSData, BackLinkType, CKBFSDataType } from './molecule';
4
- import { createChunkedCKBFSWitnesses } from './witness';
5
- import {
6
- getCKBFSScriptConfig,
7
- NetworkType,
8
- ProtocolVersion,
9
- DEFAULT_NETWORK,
10
- DEFAULT_VERSION
11
- } from './constants';
2
+ import { calculateChecksum, updateChecksum } from "./checksum";
3
+ import { CKBFSData, BackLinkType, CKBFSDataType } from "./molecule";
4
+ import { createChunkedCKBFSWitnesses } from "./witness";
5
+ import {
6
+ getCKBFSScriptConfig,
7
+ NetworkType,
8
+ ProtocolVersion,
9
+ ProtocolVersionType,
10
+ DEFAULT_NETWORK,
11
+ DEFAULT_VERSION,
12
+ } from "./constants";
12
13
 
13
14
  /**
14
15
  * Utility functions for CKB transaction creation and handling
@@ -23,7 +24,7 @@ export interface CKBFSCellOptions {
23
24
  capacity?: bigint;
24
25
  lock: Script;
25
26
  network?: NetworkType;
26
- version?: string;
27
+ version?: ProtocolVersionType;
27
28
  useTypeID?: boolean;
28
29
  }
29
30
 
@@ -49,7 +50,7 @@ export interface AppendOptions {
49
50
  contentChunks: Uint8Array[];
50
51
  feeRate?: number;
51
52
  network?: NetworkType;
52
- version?: string;
53
+ version?: ProtocolVersionType;
53
54
  }
54
55
 
55
56
  /**
@@ -57,8 +58,8 @@ export interface AppendOptions {
57
58
  * @param value The string to ensure is hex prefixed
58
59
  * @returns A hex prefixed string
59
60
  */
60
- function ensureHexPrefix(value: string): `0x${string}` {
61
- if (value.startsWith('0x')) {
61
+ export function ensureHexPrefix(value: string): `0x${string}` {
62
+ if (value.startsWith("0x")) {
62
63
  return value as `0x${string}`;
63
64
  }
64
65
  return `0x${value}` as `0x${string}`;
@@ -70,26 +71,26 @@ function ensureHexPrefix(value: string): `0x${string}` {
70
71
  * @returns The created cell output
71
72
  */
72
73
  export function createCKBFSCell(options: CKBFSCellOptions) {
73
- const {
74
- contentType,
75
- filename,
76
- capacity,
77
- lock,
78
- network = DEFAULT_NETWORK,
74
+ const {
75
+ contentType,
76
+ filename,
77
+ capacity,
78
+ lock,
79
+ network = DEFAULT_NETWORK,
79
80
  version = DEFAULT_VERSION,
80
- useTypeID = false
81
+ useTypeID = false,
81
82
  } = options;
82
-
83
+
83
84
  // Get CKBFS script config
84
85
  const config = getCKBFSScriptConfig(network, version, useTypeID);
85
-
86
+
86
87
  // Create pre CKBFS type script
87
88
  const preCkbfsTypeScript = new Script(
88
89
  ensureHexPrefix(config.codeHash),
89
90
  config.hashType as any,
90
- "0x0000000000000000000000000000000000000000000000000000000000000000"
91
+ "0x0000000000000000000000000000000000000000000000000000000000000000",
91
92
  );
92
-
93
+
93
94
  // Return the cell output
94
95
  return {
95
96
  lock,
@@ -105,130 +106,140 @@ export function createCKBFSCell(options: CKBFSCellOptions) {
105
106
  * @returns Promise resolving to the created transaction
106
107
  */
107
108
  export async function createPublishTransaction(
108
- signer: Signer,
109
- options: PublishOptions
109
+ signer: Signer,
110
+ options: PublishOptions,
110
111
  ): Promise<Transaction> {
111
- const {
112
- contentChunks,
113
- contentType,
114
- filename,
115
- lock,
112
+ const {
113
+ contentChunks,
114
+ contentType,
115
+ filename,
116
+ lock,
116
117
  capacity,
117
118
  feeRate,
118
119
  network = DEFAULT_NETWORK,
119
120
  version = DEFAULT_VERSION,
120
- useTypeID = false
121
+ useTypeID = false,
121
122
  } = options;
122
-
123
+
123
124
  // Calculate checksum for the combined content
124
125
  const textEncoder = new TextEncoder();
125
126
  const combinedContent = Buffer.concat(contentChunks);
126
127
  const checksum = await calculateChecksum(combinedContent);
127
-
128
+
128
129
  // Create CKBFS witnesses - each chunk already includes the CKBFS header
129
130
  // Pass 0 as version byte - this is the protocol version byte in the witness header
130
131
  // not to be confused with the Protocol Version (V1 vs V2)
131
132
  const ckbfsWitnesses = createChunkedCKBFSWitnesses(contentChunks);
132
-
133
+
133
134
  // Calculate the actual witness indices where our content is placed
134
135
  // Index 0 is reserved for the secp256k1 witness for signing
135
136
  // So our CKBFS data starts at index 1
136
137
  const contentStartIndex = 1;
137
138
  const witnessIndices = Array.from(
138
- { length: contentChunks.length },
139
- (_, i) => contentStartIndex + i
139
+ { length: contentChunks.length },
140
+ (_, i) => contentStartIndex + i,
140
141
  );
141
-
142
+
142
143
  // Create CKBFS cell output data based on version
143
144
  let outputData: Uint8Array;
144
-
145
+
145
146
  if (version === ProtocolVersion.V1) {
146
147
  // V1 format: Single index field (a single number, not an array)
147
148
  // For V1, use the first index where content is placed
148
- outputData = CKBFSData.pack({
149
- index: contentStartIndex,
150
- checksum,
151
- contentType: contentType,
152
- filename: filename,
153
- backLinks: [],
154
- }, version);
149
+ outputData = CKBFSData.pack(
150
+ {
151
+ index: contentStartIndex,
152
+ checksum,
153
+ contentType: contentType,
154
+ filename: filename,
155
+ backLinks: [],
156
+ },
157
+ version,
158
+ );
155
159
  } else {
156
160
  // V2 format: Multiple indexes (array of numbers)
157
161
  // For V2, use all the indices where content is placed
158
- outputData = CKBFSData.pack({
159
- indexes: witnessIndices,
160
- checksum,
161
- contentType,
162
- filename,
163
- backLinks: [],
164
- }, version);
162
+ outputData = CKBFSData.pack(
163
+ {
164
+ indexes: witnessIndices,
165
+ checksum,
166
+ contentType,
167
+ filename,
168
+ backLinks: [],
169
+ },
170
+ version,
171
+ );
165
172
  }
166
-
173
+
167
174
  // Get CKBFS script config
168
175
  const config = getCKBFSScriptConfig(network, version, useTypeID);
169
-
176
+
170
177
  const preCkbfsTypeScript = new Script(
171
178
  ensureHexPrefix(config.codeHash),
172
179
  config.hashType as any,
173
- "0x0000000000000000000000000000000000000000000000000000000000000000"
180
+ "0x0000000000000000000000000000000000000000000000000000000000000000",
174
181
  );
175
- const ckbfsCellSize = BigInt(outputData.length + preCkbfsTypeScript.occupiedSize + lock.occupiedSize + 8) * 100000000n
182
+ const ckbfsCellSize =
183
+ BigInt(
184
+ outputData.length +
185
+ preCkbfsTypeScript.occupiedSize +
186
+ lock.occupiedSize +
187
+ 8,
188
+ ) * 100000000n;
176
189
  // Create pre transaction without cell deps initially
177
190
  const preTx = Transaction.from({
178
191
  outputs: [
179
- createCKBFSCell({
180
- contentType,
181
- filename,
182
- lock,
183
- network,
192
+ createCKBFSCell({
193
+ contentType,
194
+ filename,
195
+ lock,
196
+ network,
184
197
  version,
185
198
  useTypeID,
186
- capacity: ckbfsCellSize || capacity
187
- })
199
+ capacity: ckbfsCellSize || capacity,
200
+ }),
188
201
  ],
189
202
  witnesses: [
190
203
  [], // Empty secp witness for signing
191
- ...ckbfsWitnesses.map(w => `0x${Buffer.from(w).toString('hex')}`),
204
+ ...ckbfsWitnesses.map((w) => `0x${Buffer.from(w).toString("hex")}`),
192
205
  ],
193
- outputsData: [
194
- outputData,
195
- ]
206
+ outputsData: [outputData],
196
207
  });
197
-
208
+
198
209
  // Add the CKBFS dep group cell dependency
199
210
  preTx.addCellDeps({
200
211
  outPoint: {
201
212
  txHash: ensureHexPrefix(config.depTxHash),
202
213
  index: config.depIndex || 0,
203
214
  },
204
- depType: "depGroup"
215
+ depType: "depGroup",
205
216
  });
206
-
217
+
207
218
  // Get the recommended address to ensure lock script cell deps are included
208
219
  const address = await signer.getRecommendedAddressObj();
209
-
220
+
210
221
  // Complete inputs by capacity
211
222
  await preTx.completeInputsByCapacity(signer);
212
-
223
+
213
224
  // Complete fee change to lock
214
225
  await preTx.completeFeeChangeToLock(signer, lock, feeRate || 2000);
215
-
226
+
216
227
  // Create type ID args
217
228
  const args = ccc.hashTypeId(preTx.inputs[0], 0x0);
218
-
229
+
219
230
  // Create CKBFS type script with type ID
220
231
  const ckbfsTypeScript = new Script(
221
232
  ensureHexPrefix(config.codeHash),
222
233
  config.hashType as any,
223
- args
234
+ args,
224
235
  );
225
-
236
+
226
237
  // Create final transaction with same cell deps as preTx
227
238
  const tx = Transaction.from({
228
239
  cellDeps: preTx.cellDeps,
229
240
  witnesses: [
230
241
  [], // Reset first witness for signing
231
- ...preTx.witnesses.slice(1)
242
+ ...preTx.witnesses.slice(1),
232
243
  ],
233
244
  outputsData: preTx.outputsData,
234
245
  inputs: preTx.inputs,
@@ -238,10 +249,10 @@ export async function createPublishTransaction(
238
249
  type: ckbfsTypeScript,
239
250
  capacity: preTx.outputs[0].capacity,
240
251
  },
241
- ...preTx.outputs.slice(1) // Include rest of outputs (e.g., change)
242
- ]
252
+ ...preTx.outputs.slice(1), // Include rest of outputs (e.g., change)
253
+ ],
243
254
  });
244
-
255
+
245
256
  return tx;
246
257
  }
247
258
 
@@ -252,52 +263,59 @@ export async function createPublishTransaction(
252
263
  * @returns Promise resolving to the created transaction
253
264
  */
254
265
  export async function createAppendTransaction(
255
- signer: Signer,
256
- options: AppendOptions
266
+ signer: Signer,
267
+ options: AppendOptions,
257
268
  ): Promise<Transaction> {
258
- const {
259
- ckbfsCell,
260
- contentChunks,
269
+ const {
270
+ ckbfsCell,
271
+ contentChunks,
261
272
  feeRate,
262
273
  network = DEFAULT_NETWORK,
263
- version = DEFAULT_VERSION
274
+ version = DEFAULT_VERSION,
264
275
  } = options;
265
276
  const { outPoint, data, type, lock, capacity } = ckbfsCell;
266
-
277
+
267
278
  // Get CKBFS script config early to use version info
268
279
  const config = getCKBFSScriptConfig(network, version);
269
-
280
+
270
281
  // Create CKBFS witnesses - each chunk already includes the CKBFS header
271
282
  // Pass 0 as version byte - this is the protocol version byte in the witness header
272
283
  // not to be confused with the Protocol Version (V1 vs V2)
273
284
  const ckbfsWitnesses = createChunkedCKBFSWitnesses(contentChunks);
274
-
285
+
275
286
  // Combine the new content chunks for checksum calculation
276
287
  const combinedContent = Buffer.concat(contentChunks);
277
-
288
+
278
289
  // Update the existing checksum with the new content - this matches Adler32's
279
290
  // cumulative nature as required by Rule 11 in the RFC
280
291
  const contentChecksum = await updateChecksum(data.checksum, combinedContent);
281
- console.log(`Updated checksum from ${data.checksum} to ${contentChecksum} for appended content`);
282
-
292
+ console.log(
293
+ `Updated checksum from ${data.checksum} to ${contentChecksum} for appended content`,
294
+ );
295
+
296
+ // Get the recommended address to ensure lock script cell deps are included
297
+ const address = await signer.getRecommendedAddressObj();
298
+
283
299
  // Calculate the actual witness indices where our content is placed
284
- // Index 0 is reserved for the secp256k1 witness for signing
285
- // So our CKBFS data starts at index 1
286
- const contentStartIndex = 1;
300
+ // CKBFS data starts at index 1 if signer's lock script is the same as ckbfs's lock script
301
+ // else CKBFS data starts at index 0
302
+ const contentStartIndex = address.script.hash() === lock.hash() ? 1 : 0;
287
303
  const witnessIndices = Array.from(
288
- { length: contentChunks.length },
289
- (_, i) => contentStartIndex + i
304
+ { length: contentChunks.length },
305
+ (_, i) => contentStartIndex + i,
290
306
  );
291
-
307
+
292
308
  // Create backlink for the current state based on version
293
309
  let newBackLink: any;
294
-
310
+
295
311
  if (version === ProtocolVersion.V1) {
296
312
  // V1 format: Use index field (single number)
297
313
  newBackLink = {
298
314
  // In V1, field order is index, checksum, txHash
299
315
  // and index is a single number value, not an array
300
- index: data.index || (data.indexes && data.indexes.length > 0 ? data.indexes[0] : 0),
316
+ index:
317
+ data.index ||
318
+ (data.indexes && data.indexes.length > 0 ? data.indexes[0] : 0),
301
319
  checksum: data.checksum,
302
320
  txHash: outPoint.txHash,
303
321
  };
@@ -311,51 +329,61 @@ export async function createAppendTransaction(
311
329
  txHash: outPoint.txHash,
312
330
  };
313
331
  }
314
-
332
+
315
333
  // Update backlinks - add the new one to the existing backlinks array
316
334
  const backLinks = [...(data.backLinks || []), newBackLink];
317
-
335
+
318
336
  // Define output data based on version
319
337
  let outputData: Uint8Array;
320
-
338
+
321
339
  if (version === ProtocolVersion.V1) {
322
340
  // In V1, index is a single number, not an array
323
341
  // The first witness index is used (V1 can only reference one witness)
324
- outputData = CKBFSData.pack({
325
- index: witnessIndices[0], // Use only the first index as a number
326
- checksum: contentChecksum,
327
- contentType: data.contentType,
328
- filename: data.filename,
329
- backLinks,
330
- }, ProtocolVersion.V1); // Explicitly use V1 for packing
342
+ outputData = CKBFSData.pack(
343
+ {
344
+ index: witnessIndices[0], // Use only the first index as a number
345
+ checksum: contentChecksum,
346
+ contentType: data.contentType,
347
+ filename: data.filename,
348
+ backLinks,
349
+ },
350
+ ProtocolVersion.V1,
351
+ ); // Explicitly use V1 for packing
331
352
  } else {
332
353
  // In V2, indexes is an array of witness indices
333
- outputData = CKBFSData.pack({
334
- indexes: witnessIndices,
335
- checksum: contentChecksum,
336
- contentType: data.contentType,
337
- filename: data.filename,
338
- backLinks,
339
- }, ProtocolVersion.V2); // Explicitly use V2 for packing
354
+ outputData = CKBFSData.pack(
355
+ {
356
+ indexes: witnessIndices,
357
+ checksum: contentChecksum,
358
+ contentType: data.contentType,
359
+ filename: data.filename,
360
+ backLinks,
361
+ },
362
+ ProtocolVersion.V2,
363
+ ); // Explicitly use V2 for packing
340
364
  }
341
-
365
+
342
366
  // Pack the original data to get its size - use the appropriate version
343
367
  const originalData = CKBFSData.pack(data, version);
344
368
  const originalDataSize = originalData.length;
345
-
369
+
346
370
  // Get sizes and calculate capacity requirements
347
371
  const newDataSize = outputData.length;
348
-
372
+
349
373
  // Calculate the required capacity for the output cell
350
- // This accounts for:
374
+ // This accounts for:
351
375
  // 1. The output data size
352
376
  // 2. The type script's occupied size
353
377
  // 3. The lock script's occupied size
354
378
  // 4. A constant of 8 bytes (for header overhead)
355
- const ckbfsCellSize = BigInt(outputData.length + type.occupiedSize + lock.occupiedSize + 8) * 100000000n;
356
-
357
- console.log(`Original capacity: ${capacity}, Calculated size: ${ckbfsCellSize}, Data size: ${outputData.length}`);
358
-
379
+ const ckbfsCellSize =
380
+ BigInt(outputData.length + type.occupiedSize + lock.occupiedSize + 8) *
381
+ 100000000n;
382
+
383
+ console.log(
384
+ `Original capacity: ${capacity}, Calculated size: ${ckbfsCellSize}, Data size: ${outputData.length}`,
385
+ );
386
+
359
387
  // Use the maximum value between calculated size and original capacity
360
388
  // to ensure we have enough capacity but don't decrease capacity unnecessarily
361
389
  const outputCapacity = ckbfsCellSize > capacity ? ckbfsCellSize : capacity;
@@ -369,59 +397,57 @@ export async function createAppendTransaction(
369
397
  index: outPoint.index,
370
398
  },
371
399
  since: "0x0",
372
- }
400
+ },
373
401
  ],
374
402
  outputs: [
375
403
  {
376
404
  lock,
377
405
  type,
378
406
  capacity: outputCapacity,
379
- }
407
+ },
380
408
  ],
381
- outputsData: [
382
- outputData,
383
- ]
409
+ outputsData: [outputData],
384
410
  });
385
411
 
386
-
387
412
  // Add the CKBFS dep group cell dependency
388
413
  tx.addCellDeps({
389
414
  outPoint: {
390
415
  txHash: ensureHexPrefix(config.depTxHash),
391
416
  index: config.depIndex || 0,
392
417
  },
393
- depType: "depGroup"
418
+ depType: "depGroup",
394
419
  });
395
-
396
- // Get the recommended address to ensure lock script cell deps are included
397
- const address = await signer.getRecommendedAddressObj();
398
420
 
399
421
  const inputsBefore = tx.inputs.length;
400
422
  // If we need more capacity than the original cell had, add additional inputs
401
423
  if (outputCapacity > capacity) {
402
- console.log(`Need additional capacity: ${outputCapacity - capacity} shannons`);
424
+ console.log(
425
+ `Need additional capacity: ${outputCapacity - capacity} shannons`,
426
+ );
403
427
  // Add more inputs to cover the increased capacity
404
428
  await tx.completeInputsByCapacity(signer);
405
429
  }
406
430
 
407
- const witnesses: any = []
431
+ const witnesses: any = [];
408
432
  // add empty witness for signer if ckbfs's lock is the same as signer's lock
409
- if(address.script.hash() === lock.hash()) {
410
- witnesses.push('0x')
433
+ if (address.script.hash() === lock.hash()) {
434
+ witnesses.push("0x");
411
435
  }
412
436
  // add ckbfs witnesses
413
- witnesses.push(...ckbfsWitnesses.map(w => `0x${Buffer.from(w).toString('hex')}`))
437
+ witnesses.push(
438
+ ...ckbfsWitnesses.map((w) => `0x${Buffer.from(w).toString("hex")}`),
439
+ );
414
440
 
415
441
  // Add empty witnesses for signer's input
416
442
  // This is to ensure that the transaction is valid and can be signed
417
- for(let i = inputsBefore; i < tx.inputs.length; i++) {
418
- witnesses.push('0x')
443
+ for (let i = inputsBefore; i < tx.inputs.length; i++) {
444
+ witnesses.push("0x");
419
445
  }
420
- tx.witnesses = witnesses
446
+ tx.witnesses = witnesses;
421
447
 
422
448
  // Complete fee
423
449
  await tx.completeFeeChangeToLock(signer, address.script, feeRate || 2000);
424
-
450
+
425
451
  return tx;
426
452
  }
427
453
 
@@ -432,8 +458,8 @@ export async function createAppendTransaction(
432
458
  * @returns Promise resolving to the signed transaction
433
459
  */
434
460
  export async function publishCKBFS(
435
- signer: Signer,
436
- options: PublishOptions
461
+ signer: Signer,
462
+ options: PublishOptions,
437
463
  ): Promise<Transaction> {
438
464
  const tx = await createPublishTransaction(signer, options);
439
465
  return signer.signTransaction(tx);
@@ -446,9 +472,9 @@ export async function publishCKBFS(
446
472
  * @returns Promise resolving to the signed transaction
447
473
  */
448
474
  export async function appendCKBFS(
449
- signer: Signer,
450
- options: AppendOptions
475
+ signer: Signer,
476
+ options: AppendOptions,
451
477
  ): Promise<Transaction> {
452
478
  const tx = await createAppendTransaction(signer, options);
453
479
  return signer.signTransaction(tx);
454
- }
480
+ }
@@ -0,0 +1 @@
1
+ Hello CKBFS from direct content!
@@ -0,0 +1 @@
1
+ Hello CKBFS from direct content!
@@ -1,49 +0,0 @@
1
- ---
2
- description:
3
- globs:
4
- alwaysApply: true
5
- ---
6
-
7
- You are an expert in TypeScript, Node.js, Next.js App Router, React, Shadcn UI, Radix UI and Tailwind.
8
-
9
- Code Style and Structure
10
- - Write concise, technical TypeScript code with accurate examples.
11
- - Use functional and declarative programming patterns; avoid classes.
12
- - Prefer iteration and modularization over code duplication.
13
- - Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
14
- - Structure files: exported component, subcomponents, helpers, static content, types.
15
-
16
- Naming Conventions
17
- - Use lowercase with dashes for directories (e.g., components/auth-wizard).
18
- - Favor named exports for components.
19
-
20
- TypeScript Usage
21
- - Use TypeScript for all code; prefer interfaces over types.
22
- - Avoid enums; use maps instead.
23
- - Use functional components with TypeScript interfaces.
24
-
25
- Syntax and Formatting
26
- - Use the "function" keyword for pure functions.
27
- - Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements.
28
- - Use declarative JSX.
29
-
30
- UI and Styling
31
- - Use Shadcn UI, Radix, and Tailwind for components and styling.
32
- - Implement responsive design with Tailwind CSS; use a mobile-first approach.
33
-
34
- Performance Optimization
35
- - Minimize 'use client', 'useEffect', and 'setState'; favor React Server Components (RSC).
36
- - Wrap client components in Suspense with fallback.
37
- - Use dynamic loading for non-critical components.
38
- - Optimize images: use WebP format, include size data, implement lazy loading.
39
-
40
- Key Conventions
41
- - Use 'nuqs' for URL search parameter state management.
42
- - Optimize Web Vitals (LCP, CLS, FID).
43
- - Limit 'use client':
44
- - Favor server components and Next.js SSR.
45
- - Use only for Web API access in small components.
46
- - Avoid for data fetching or state management.
47
-
48
- Follow Next.js docs for Data Fetching, Rendering, and Routing.
49
-
package/ABC.LOGS DELETED
@@ -1 +0,0 @@
1
- MINT,TO:ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqdpallzwnhe64rqnqmev7hf98yrmh4yzucgdw7qwGIVE_NAME,NEW_NAME:NERVAPE_COOKIE