@ckbfs/api 2.0.3 → 2.0.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.
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Script, Signer, Transaction } from "@ckb-ccc/core";
2
2
  import { calculateChecksum, verifyChecksum, updateChecksum, verifyWitnessChecksum, verifyV3WitnessChecksum, verifyV3WitnessChain } from "./utils/checksum";
3
3
  import { createCKBFSCell, createPublishTransaction as utilCreatePublishTransaction, preparePublishTransaction, createAppendTransaction as utilCreateAppendTransaction, prepareAppendTransaction, createAppendTransactionDry, publishCKBFS as utilPublishCKBFS, appendCKBFS as utilAppendCKBFS, CKBFSCellOptions, PublishOptions, AppendOptions, AppendV3Options, TransferV3Options } from "./utils/transaction";
4
- import { readFile, readFileAsText, readFileAsUint8Array, writeFile, getContentType, splitFileIntoChunks, combineChunksToFile, getFileContentFromChain, saveFileFromChain, getFileContentFromChainByTypeId, saveFileFromChainByTypeId, decodeFileFromChainByTypeId, getFileContentFromChainByIdentifier, saveFileFromChainByIdentifier, decodeFileFromChainByIdentifier, parseIdentifier, IdentifierType, decodeWitnessContent, decodeMultipleWitnessContents, extractFileFromWitnesses, decodeFileFromWitnessData, saveFileFromWitnessData, getFileContentFromChainV3, getFileContentFromChainByIdentifierV3, saveFileFromChainByIdentifierV3 } from "./utils/file";
4
+ import { readFile, readFileAsText, readFileAsUint8Array, writeFile, getContentType, splitFileIntoChunks, combineChunksToFile, getFileContentFromChain, saveFileFromChain, getFileContentFromChainByTypeId, saveFileFromChainByTypeId, decodeFileFromChainByTypeId, getFileContentFromChainByIdentifier, saveFileFromChainByIdentifier, decodeFileFromChainByIdentifier, parseIdentifier, IdentifierType, decodeWitnessContent, decodeMultipleWitnessContents, extractFileFromWitnesses, decodeFileFromWitnessData, saveFileFromWitnessData, getFileContentFromChainV3, getFileContentFromChainByIdentifierV3, saveFileFromChainByIdentifierV3, resolveCKBFSCell } from "./utils/file";
5
5
  import { createCKBFSWitness, createTextCKBFSWitness, extractCKBFSWitnessContent, isCKBFSWitness, createChunkedCKBFSWitnesses, createCKBFSV3Witness, createChunkedCKBFSV3Witnesses, extractCKBFSV3WitnessContent, isCKBFSV3Witness, CKBFSV3WitnessOptions } from "./utils/witness";
6
6
  import { CKBFSData, BackLinkV1, BackLinkV2, CKBFSDataType, BackLinkType, CKBFS_HEADER, CKBFS_HEADER_STRING } from "./utils/molecule";
7
7
  import { 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 } from "./utils/constants";
@@ -28,9 +28,6 @@ export type PublishContentOptions = Omit<FileOptions, "capacity" | "contentType"
28
28
  */
29
29
  export type AppendContentOptions = Omit<FileOptions, "contentType" | "filename" | "capacity"> & {
30
30
  capacity?: bigint;
31
- previousTxHash?: string;
32
- previousWitnessIndex?: number;
33
- previousChecksum?: number;
34
31
  };
35
32
  /**
36
33
  * Configuration options for the CKBFS SDK
@@ -197,4 +194,4 @@ export declare class CKBFS {
197
194
  */
198
195
  createPublishV3Transaction(filePath: string, options?: Omit<FileOptions, 'version'>): Promise<Transaction>;
199
196
  }
200
- export { calculateChecksum, verifyChecksum, updateChecksum, verifyWitnessChecksum, verifyV3WitnessChecksum, verifyV3WitnessChain, 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, getFileContentFromChainV3, getFileContentFromChainByIdentifierV3, saveFileFromChainByIdentifierV3, createCKBFSWitness, createTextCKBFSWitness, extractCKBFSWitnessContent, isCKBFSWitness, createChunkedCKBFSWitnesses, createCKBFSV3Witness, createChunkedCKBFSV3Witnesses, extractCKBFSV3WitnessContent, isCKBFSV3Witness, CKBFSV3WitnessOptions, 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, };
197
+ export { calculateChecksum, verifyChecksum, updateChecksum, verifyWitnessChecksum, verifyV3WitnessChecksum, verifyV3WitnessChain, 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, getFileContentFromChainV3, getFileContentFromChainByIdentifierV3, saveFileFromChainByIdentifierV3, createCKBFSWitness, createTextCKBFSWitness, extractCKBFSWitnessContent, isCKBFSWitness, createChunkedCKBFSWitnesses, createCKBFSV3Witness, createChunkedCKBFSV3Witnesses, extractCKBFSV3WitnessContent, isCKBFSV3Witness, resolveCKBFSCell, CKBFSV3WitnessOptions, 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.CKBFSData = exports.isCKBFSV3Witness = exports.extractCKBFSV3WitnessContent = exports.createChunkedCKBFSV3Witnesses = exports.createCKBFSV3Witness = exports.createChunkedCKBFSWitnesses = exports.isCKBFSWitness = exports.extractCKBFSWitnessContent = exports.createTextCKBFSWitness = exports.createCKBFSWitness = exports.saveFileFromChainByIdentifierV3 = exports.getFileContentFromChainByIdentifierV3 = exports.getFileContentFromChainV3 = 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.verifyV3WitnessChain = exports.verifyV3WitnessChecksum = 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 = 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 = void 0;
3
+ exports.resolveCKBFSCell = exports.isCKBFSV3Witness = exports.extractCKBFSV3WitnessContent = exports.createChunkedCKBFSV3Witnesses = exports.createCKBFSV3Witness = exports.createChunkedCKBFSWitnesses = exports.isCKBFSWitness = exports.extractCKBFSWitnessContent = exports.createTextCKBFSWitness = exports.createCKBFSWitness = exports.saveFileFromChainByIdentifierV3 = exports.getFileContentFromChainByIdentifierV3 = exports.getFileContentFromChainV3 = 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.verifyV3WitnessChain = exports.verifyV3WitnessChecksum = 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 = 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 = 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; } });
@@ -47,6 +47,7 @@ Object.defineProperty(exports, "getFileContentFromChainV3", { enumerable: true,
47
47
  file_1.getFileContentFromChainV3; } });
48
48
  Object.defineProperty(exports, "getFileContentFromChainByIdentifierV3", { enumerable: true, get: function () { return file_1.getFileContentFromChainByIdentifierV3; } });
49
49
  Object.defineProperty(exports, "saveFileFromChainByIdentifierV3", { enumerable: true, get: function () { return file_1.saveFileFromChainByIdentifierV3; } });
50
+ Object.defineProperty(exports, "resolveCKBFSCell", { enumerable: true, get: function () { return file_1.resolveCKBFSCell; } });
50
51
  const witness_1 = require("./utils/witness");
51
52
  Object.defineProperty(exports, "createCKBFSWitness", { enumerable: true, get: function () { return witness_1.createCKBFSWitness; } });
52
53
  Object.defineProperty(exports, "createTextCKBFSWitness", { enumerable: true, get: function () { return witness_1.createTextCKBFSWitness; } });
@@ -320,18 +321,18 @@ class CKBFS {
320
321
  const version = options.version || this.version;
321
322
  // Use V3 when backlink parameters are provided or version is V3
322
323
  if (version === constants_1.ProtocolVersion.V3 &&
323
- options.previousTxHash &&
324
- options.previousWitnessIndex !== undefined &&
325
- options.previousChecksum !== undefined) {
324
+ ckbfsCell.outPoint.txHash &&
325
+ ckbfsCell.data.index !== undefined &&
326
+ ckbfsCell.data.checksum !== undefined) {
326
327
  const tx = await (0, transaction_1.appendCKBFSV3)(this.signer, {
327
328
  ckbfsCell,
328
329
  contentChunks,
329
330
  feeRate: options.feeRate,
330
331
  network: options.network || this.network,
331
332
  version: constants_1.ProtocolVersion.V3,
332
- previousTxHash: options.previousTxHash,
333
- previousWitnessIndex: options.previousWitnessIndex,
334
- previousChecksum: options.previousChecksum,
333
+ previousTxHash: ckbfsCell.outPoint.txHash,
334
+ previousWitnessIndex: ckbfsCell.data.index,
335
+ previousChecksum: ckbfsCell.data.checksum,
335
336
  });
336
337
  const txHash = await this.signer.sendTransaction(tx);
337
338
  return (0, transaction_2.ensureHexPrefix)(txHash);
@@ -507,18 +508,18 @@ class CKBFS {
507
508
  const version = options.version || this.version;
508
509
  // Use V3 when backlink parameters are provided or version is V3
509
510
  if (version === constants_1.ProtocolVersion.V3 &&
510
- options.previousTxHash &&
511
- options.previousWitnessIndex !== undefined &&
512
- options.previousChecksum !== undefined) {
511
+ ckbfsCell.outPoint.txHash &&
512
+ ckbfsCell.data.index !== undefined &&
513
+ ckbfsCell.data.checksum !== undefined) {
513
514
  return (0, transaction_1.createAppendV3Transaction)(this.signer, {
514
515
  ckbfsCell,
515
516
  contentChunks,
516
517
  feeRate: options.feeRate,
517
518
  network: options.network || this.network,
518
519
  version: constants_1.ProtocolVersion.V3,
519
- previousTxHash: options.previousTxHash,
520
- previousWitnessIndex: options.previousWitnessIndex,
521
- previousChecksum: options.previousChecksum,
520
+ previousTxHash: ckbfsCell.outPoint.txHash,
521
+ previousWitnessIndex: ckbfsCell.data.index,
522
+ previousChecksum: ckbfsCell.data.checksum,
522
523
  });
523
524
  }
524
525
  else {
@@ -138,6 +138,26 @@ export interface ParsedIdentifier {
138
138
  * @returns Parsed identifier information
139
139
  */
140
140
  export declare function parseIdentifier(identifier: string): ParsedIdentifier;
141
+ /**
142
+ * Resolves a CKBFS cell using any supported identifier format
143
+ * @param client The CKB client to use for blockchain queries
144
+ * @param identifier The identifier (TypeID, CKBFS URI, or outPoint URI)
145
+ * @param options Optional configuration for network, version, and useTypeID
146
+ * @returns Promise resolving to the found cell and transaction info, or null if not found
147
+ */
148
+ export declare function resolveCKBFSCell(client: any, identifier: string, options?: {
149
+ network?: "mainnet" | "testnet";
150
+ version?: string;
151
+ useTypeID?: boolean;
152
+ }): Promise<{
153
+ cell: any;
154
+ transaction: any;
155
+ outPoint: {
156
+ txHash: string;
157
+ index: number;
158
+ };
159
+ parsedId: ParsedIdentifier;
160
+ } | null>;
141
161
  /**
142
162
  * Retrieves complete file content from the blockchain using any supported identifier
143
163
  * @param client The CKB client to use for blockchain queries
@@ -52,6 +52,7 @@ exports.extractFileFromWitnesses = extractFileFromWitnesses;
52
52
  exports.decodeFileFromWitnessData = decodeFileFromWitnessData;
53
53
  exports.saveFileFromWitnessData = saveFileFromWitnessData;
54
54
  exports.parseIdentifier = parseIdentifier;
55
+ exports.resolveCKBFSCell = resolveCKBFSCell;
55
56
  exports.getFileContentFromChainByIdentifier = getFileContentFromChainByIdentifier;
56
57
  exports.getFileContentFromChainByTypeId = getFileContentFromChainByTypeId;
57
58
  exports.saveFileFromChainByIdentifier = saveFileFromChainByIdentifier;
@@ -161,9 +161,9 @@ function extractCKBFSV3WitnessContent(witness, isHeadWitness = true) {
161
161
  // Extract previous position
162
162
  const prevTxHashBytes = witness.slice(6, 38);
163
163
  const previousTxHash = '0x' + Array.from(prevTxHashBytes).map(b => b.toString(16).padStart(2, '0')).join('');
164
- const previousWitnessIndex = new DataView(witness.slice(38, 42).buffer).getUint32(0, true);
165
- const previousChecksum = new DataView(witness.slice(42, 46).buffer).getUint32(0, true);
166
- const nextIndex = new DataView(witness.slice(46, 50).buffer).getUint32(0, true);
164
+ const previousWitnessIndex = new DataView(witness.slice(38, 42).buffer.slice(witness.slice(38, 42).byteOffset, witness.slice(38, 42).byteOffset + 4)).getUint32(0, true);
165
+ const previousChecksum = new DataView(witness.slice(42, 46).buffer.slice(witness.slice(42, 46).byteOffset, witness.slice(42, 46).byteOffset + 4)).getUint32(0, true);
166
+ const nextIndex = new DataView(witness.slice(46, 50).buffer.slice(witness.slice(46, 50).byteOffset, witness.slice(46, 50).byteOffset + 4)).getUint32(0, true);
167
167
  const content = witness.slice(50);
168
168
  return {
169
169
  version,
@@ -0,0 +1,406 @@
1
+ import fs from "fs"
2
+ import path from 'path';
3
+ import {
4
+ CKBFS,
5
+ NetworkType,
6
+ CKBFSDataType,
7
+ ProtocolVersion,
8
+ CKBFSData,
9
+ getFileContentFromChain,
10
+ getCKBFSScriptConfig,
11
+ extractCKBFSV3WitnessContent,
12
+ isCKBFSV3Witness,
13
+ resolveCKBFSCell,
14
+ } from '../src';
15
+ import {
16
+ Script,
17
+ Address,
18
+ ClientPublicTestnet,
19
+ ClientPublicMainnet,
20
+ Transaction,
21
+ ccc
22
+ } from "@ckb-ccc/core";
23
+ import {
24
+ transferSpore
25
+ } from "@ckb-ccc/spore";
26
+ //import { isMainnet, network, CKB_PRIVATE_KEY } from "../config"
27
+
28
+
29
+ const client = new ClientPublicTestnet()
30
+
31
+ export const TestnetTraceLockDep = {
32
+ outPoint: {
33
+ txHash: "0xf6d5b0c8c5221cc9d158fd8556a3772c25a295b9f894eeb86291a25522cf90b0",
34
+ index: 0x0,
35
+ },
36
+ depType: "code",
37
+ }
38
+
39
+ export const MainnetTraceLockDep = {
40
+ outPoint: {
41
+ txHash: "0x...", //TODO: fill mainnet tracelock txhash
42
+ index: 0x0,
43
+ },
44
+ depType: "code",
45
+ }
46
+
47
+ export const TestnetShadowDep = {
48
+ outPoint: {
49
+ txHash: "0x2d8a311a55e42d7d6810610149f6e125f0d292112f8ed4a21177aec05da2b905",
50
+ index: 0x0,
51
+ },
52
+ depType: "code",
53
+ }
54
+
55
+ export const MainnetShadowDep = {
56
+ outPoint: {
57
+ txHash: "0x5b20ec7d7d5c6410ac4924c57d1eac1dd50129b6263be3dc93055397b5724dc2",
58
+ index: 0x0,
59
+ },
60
+ depType: "code",
61
+ }
62
+
63
+
64
+ const TraceLockDep = TestnetTraceLockDep
65
+ const ShadowDep = TestnetShadowDep
66
+
67
+ const TraceLogCodeHash = "0xbd7e56daaa4cc9ecf488a50d2f4db2a55a7c86eb2df2157d24a62be9be5b34ab"
68
+ const ShadowSporeCodeHash = "0x6361d4b20d845953d9c9431bbba08905573005a71e2a2432e7e0e7c685666f24"
69
+ const CKB_PRIVATE_KEY = "0x1733e6f7825f99eb41ca26f8569fa90c2cb8c5ae199bbd38a97562291f784983"
70
+
71
+ const ckbfs = new CKBFS(
72
+ CKB_PRIVATE_KEY,
73
+ NetworkType.Testnet,
74
+ {
75
+ version: ProtocolVersion.V3,
76
+ chunkSize: 30 * 1024, // 30KB chunks
77
+ useTypeID: false // Use code hash instead of type ID
78
+ }
79
+ );
80
+
81
+ async function getAddressScriptHash(addr: string | Address) {
82
+ if (typeof addr === 'string') {
83
+ addr = await Address.fromString(addr, client)
84
+ console.log("addr=", addr)
85
+ }
86
+ return `0x03${addr.script.hash().slice(2)}`
87
+ }
88
+
89
+ export async function mint(physicalArtifactNo: string) {
90
+ // Get address info
91
+ const address = await ckbfs.getAddress();
92
+ const ownerHash = await getAddressScriptHash(address)
93
+
94
+ const content = `MINT,TO:${ownerHash}\n`
95
+
96
+ // You can provide additional options
97
+ const options = {
98
+ contentType: 'text/plain',
99
+ filename: `${physicalArtifactNo}.LOGS`,
100
+ };
101
+ const tx = await ckbfs.createPublishContentTransaction(content, options);
102
+ const signer = ckbfs['signer']
103
+ const txHash = await signer.sendTransaction(tx)
104
+ const ckbfsId = tx.outputs[0].type?.args.toString()
105
+ return { txHash, log: content, ckbfsId };
106
+ }
107
+
108
+ export async function claim(to: string, sporeId: string, ckbfsId: string) {
109
+ const from = await ckbfs.getAddress();
110
+ const ckbfsCell = await getCkbfsCellInfo(ckbfsId);
111
+ const fromHash = await getAddressScriptHash(from)
112
+ const toHash = await getAddressScriptHash(to)
113
+
114
+ const content = `TRANSFER,FROM:${fromHash},TO:${toHash}\n`
115
+
116
+ let tx = await ckbfs.createAppendContentTransaction(content, ckbfsCell);
117
+ tx.addCellDeps(TraceLockDep)
118
+
119
+ const sizeBefore = tx.outputs[0].lock.occupiedSize
120
+ const traceLogLock = Script.from({
121
+ codeHash: TraceLogCodeHash,
122
+ hashType: "type",
123
+ args: toHash
124
+ })
125
+ tx.outputs[0].lock = traceLogLock
126
+ const sizeAfter = traceLogLock.occupiedSize
127
+
128
+ const diffSize = BigInt(sizeAfter - sizeBefore) * BigInt(100000000)
129
+ tx.outputs[0].capacity = tx.outputs[0].capacity + diffSize
130
+
131
+ const sporeLockArgs = `0x01${ tx.outputs[0].type?.hash().slice(2) }`
132
+ const newSporeLock = Script.from({
133
+ codeHash: ShadowSporeCodeHash,
134
+ args: sporeLockArgs,
135
+ hashType: "data1",
136
+ })
137
+
138
+ tx.outputs = [
139
+ tx.outputs[0]
140
+ ]
141
+
142
+ const signer = ckbfs['signer'] as any
143
+ const sporeTx = await transferSpore({
144
+ signer,
145
+ id: sporeId,
146
+ to: newSporeLock,
147
+ tx: tx,
148
+ })
149
+
150
+ tx.addCellDeps(ShadowDep)
151
+
152
+ const finalTx = sporeTx.tx
153
+ await finalTx.completeFeeBy(signer)
154
+ const txHash = await signer.sendTransaction(finalTx)
155
+ console.log(`File appended successfully! Transaction Hash: ${txHash}`);
156
+ return { txHash, log: content }
157
+ }
158
+
159
+ export async function giveName(name: string, ckbfsId: string) {
160
+ const ckbfsCell = await getCkbfsCellInfo(ckbfsId)
161
+ const content = `GIVE_NAME,NEW_NAME:${name}\n`
162
+
163
+ console.log("ckbfsCell=", ckbfsCell)
164
+
165
+ const previousData = {
166
+ previousTxHash: ckbfsCell.outPoint.txHash,
167
+ previousWitnessIndex: ckbfsCell.data?.index || 0,
168
+ previousChecksum: ckbfsCell.data?.checksum || 0
169
+ };
170
+ const signer = ckbfs['signer']
171
+ const address = await signer.getRecommendedAddress()
172
+ const addressHash = await getAddressScriptHash(address)
173
+ console.log("addressHash=", addressHash)
174
+ let tx = await ckbfs.createAppendContentTransaction(content, ckbfsCell, previousData as any);
175
+ tx.addCellDeps(TestnetTraceLockDep)
176
+ console.log(tx.stringify())
177
+ const txHash = await signer.sendTransaction(tx)
178
+ console.log(`File appended successfully! Transaction Hash: ${txHash}`);
179
+ return { txHash, log: content }
180
+ }
181
+
182
+ // export async function transfer(to: string, ckbfsId: string) {
183
+ // const ckbfsCell = await getCkbfsCellInfo(ckbfsId)
184
+ // const from = await ckbfs.getAddress();
185
+ // const fromHash = await getAddressScriptHash(from)
186
+ // const toHash = await getAddressScriptHash(to)
187
+ // const content = `TRANSFER,FROM:${fromHash},TO:${toHash}\n`
188
+
189
+ // const signer = ckbfs['signer']
190
+ // let tx = await ckbfs.createAppendContentTransaction(content, ckbfsCell);
191
+ // tx.outputs[0].lock.args = toHash as `0x{string}`;
192
+ // tx.addCellDeps(TestnetTraceLockDep)
193
+ // const txHash = await signer.sendTransaction(tx)
194
+ // console.log(`File appended successfully! Transaction Hash: ${txHash}`);
195
+
196
+ // return { txHash, log: content };
197
+ // }
198
+
199
+ // export async function release(from: string, ckbfsId: string) {
200
+ // const ckbfsCell = await await getCkbfsCellInfo(ckbfsId)
201
+ // const fromHash = await getAddressScriptHash(from)
202
+ // const content = `RELEASE,FROM:${fromHash}\n`
203
+ // const signer = ckbfs['signer']
204
+ // let tx = await ckbfs.createAppendContentTransaction(content, ckbfsCell);
205
+
206
+ // tx.addCellDeps(TestnetTraceLockDep)
207
+ // const txHash = await signer.sendTransaction(tx)
208
+ // console.log(`File appended successfully! Transaction Hash: ${txHash}`);
209
+ // return { txHash, log: content };
210
+ // }
211
+
212
+ // export async function retrieveLogsFromChain(ckbfsId: string) {
213
+ // const { outPoint, data } = await getCkbfsCellInfo(ckbfsId)
214
+ // const content = await getFileContentFromChain(client, outPoint, data)
215
+ // const logs = content.toString().trim().split("\n")
216
+ // return logs
217
+ // }
218
+
219
+ export async function getCkbfsCellInfo(ckbfsId: string) {
220
+ const { codeHash, hashType } = getCKBFSScriptConfig(NetworkType.Testnet, ProtocolVersion.V3)
221
+ console.log("codeHash, hashType=", codeHash, hashType, ckbfsId)
222
+ const cell = await client.findSingletonCellByType({
223
+ codeHash,
224
+ hashType,
225
+ args: ckbfsId
226
+ }, true)
227
+
228
+ if (!cell || !cell.cellOutput.type) {
229
+ throw new Error('No CKBFS cell found');
230
+ }
231
+
232
+ const rawData = cell.outputData.startsWith('0x')
233
+ ? Buffer.from(cell.outputData.slice(2), 'hex')
234
+ : Buffer.from(cell.outputData, 'hex');
235
+
236
+ const ckbfsData = CKBFSData.unpack(rawData, ProtocolVersion.V3)
237
+
238
+ return {
239
+ outPoint: { txHash: cell.outPoint.txHash as string, index: Number(cell.outPoint.index) },
240
+ type: cell.cellOutput.type,
241
+ lock: cell.cellOutput.lock,
242
+ capacity: cell.cellOutput.capacity,
243
+ data: ckbfsData,
244
+ };
245
+ }
246
+
247
+
248
+ export function getCkbfsList() {
249
+ const file = path.join(__dirname, `./data/${'testnet'}/ckbfs-list.json`)
250
+ return JSON.parse(fs.readFileSync(file).toString())
251
+ }
252
+
253
+ export async function mintAll() {
254
+ const ckbfsList = getCkbfsList()
255
+ for(const { no } of ckbfsList) {
256
+ const { txHash, ckbfsId } = await mint(no)
257
+ console.log(`minted ckbfs no=${no}, ckbfsId=${ckbfsId}, txHash=${txHash}`);
258
+
259
+ const interval = setInterval(async () => {
260
+ try {
261
+ const tx = await client.getTransaction(txHash)
262
+ if (tx && tx.status === 'committed') {
263
+ clearInterval(interval)
264
+ console.info(`tx confirmed, https://explorer.nervos.org/transaction/${txHash}`);
265
+ }
266
+ } catch (error) {
267
+ console.error(error)
268
+ }
269
+ }, 5 * 1000)
270
+ }
271
+ }
272
+
273
+ async function getCellInfoFromV3Transaction(txHash: string): Promise<{
274
+ outPoint: { txHash: string; index: number };
275
+ type: Script;
276
+ data: CKBFSDataType;
277
+ lock: Script;
278
+ capacity: bigint;
279
+ previousTxHash: string;
280
+ previousWitnessIndex: number;
281
+ previousChecksum: number;
282
+ }> {
283
+ console.log(`Retrieving v3 transaction data for: ${txHash}`);
284
+
285
+ try {
286
+ // Get transaction from RPC
287
+ const txWithStatus = await client.getTransaction(txHash);
288
+ if (!txWithStatus || !txWithStatus.transaction) {
289
+ throw new Error(`Transaction ${txHash} not found`);
290
+ }
291
+
292
+ const tx = Transaction.from(txWithStatus.transaction);
293
+ console.log(`Transaction found with ${tx.outputs.length} outputs`);
294
+
295
+ // Find the CKBFS cell output (first output with type script)
296
+ let ckbfsCellIndex = 0;
297
+ const output = tx.outputs[ckbfsCellIndex];
298
+ if (!output || !output.type) {
299
+ throw new Error('No CKBFS cell found in the transaction');
300
+ }
301
+
302
+ console.log(`Found CKBFS v3 cell at index ${ckbfsCellIndex}`);
303
+ console.log(`Cell type script hash: ${output.type.hash()}`);
304
+
305
+ // Get output data
306
+ const outputData = tx.outputsData[ckbfsCellIndex];
307
+ if (!outputData) {
308
+ throw new Error('Output data not found');
309
+ }
310
+
311
+ // Parse the output data as CKBFS v3 data
312
+ const rawData = outputData.startsWith('0x')
313
+ ? ccc.bytesFrom(outputData.slice(2), 'hex')
314
+ : Buffer.from(outputData, 'hex');
315
+
316
+ // Unpack the raw data using v3 format
317
+ const version = ProtocolVersion.V3;
318
+ console.log(`Using protocol version ${version} for unpacking v3 cell data`);
319
+
320
+ let ckbfsData: CKBFSDataType;
321
+ try {
322
+ ckbfsData = CKBFSData.unpack(rawData, version);
323
+
324
+ console.log('Successfully unpacked CKBFS v3 cell data:');
325
+ console.log(`- Checksum: ${ckbfsData.checksum}`);
326
+ console.log(`- File: ${ckbfsData.filename}`);
327
+ console.log(`- Content Type: ${ckbfsData.contentType}`);
328
+ console.log(`- Index: ${ckbfsData.index}`);
329
+ } catch (error) {
330
+ console.error('Error unpacking CKBFS v3 data:', error);
331
+ throw new Error(`Failed to unpack CKBFS v3 data: ${error}`);
332
+ }
333
+
334
+ // Extract backlink information from v3 witness
335
+ let previousTxHash = '0x' + '00'.repeat(32);
336
+ let previousWitnessIndex = 0;
337
+ let previousChecksum = 0;
338
+
339
+ if (ckbfsData.index !== undefined && ckbfsData.index < tx.witnesses.length) {
340
+ const witnessHex = tx.witnesses[ckbfsData.index];
341
+ const witness = Buffer.from(witnessHex.slice(2), 'hex');
342
+
343
+ if (isCKBFSV3Witness(witness)) {
344
+ try {
345
+ const witnessData = extractCKBFSV3WitnessContent(witness, true);
346
+ previousTxHash = witnessData.previousTxHash || previousTxHash;
347
+ previousWitnessIndex = witnessData.previousWitnessIndex || 0;
348
+ previousChecksum = witnessData.previousChecksum || 0;
349
+
350
+ console.log('Extracted v3 backlink information:');
351
+ console.log(`- Previous TX Hash: ${previousTxHash}`);
352
+ console.log(`- Previous Witness Index: ${previousWitnessIndex}`);
353
+ console.log(`- Previous Checksum: ${previousChecksum}`);
354
+ } catch (error) {
355
+ console.warn('Could not extract backlink info from witness:', error);
356
+ }
357
+ }
358
+ }
359
+
360
+ return {
361
+ outPoint: {
362
+ txHash,
363
+ index: ckbfsCellIndex
364
+ },
365
+ type: output.type,
366
+ lock: output.lock,
367
+ capacity: output.capacity,
368
+ data: ckbfsData,
369
+ previousTxHash,
370
+ previousWitnessIndex,
371
+ previousChecksum
372
+ };
373
+ } catch (error) {
374
+ console.error('Error retrieving v3 transaction data:', error);
375
+ throw new Error(`Failed to retrieve or parse v3 cell data: ${error}`);
376
+ }
377
+ }
378
+
379
+ async function testReresolve(ckbfsId: string) {
380
+ const data = (await resolveCKBFSCell(client, ckbfsId, {network: NetworkType.Testnet}))!
381
+ return data
382
+ }
383
+
384
+ // mintAll()
385
+
386
+ // mint("X30125NMNVAP000201").then(console.log)
387
+
388
+ // claim("ckt1qyq0zr47f0p8sm5d3cvtlpkljs7zvqcw7ngqnfscx0", "0xa3347c13f0419d9013a3f48a2b9ad993c2b6b5806827f3bf37480a58580d669d", "0x0084106b9bea08f512e35b725c4a710ebf09cb65c05601ebde8d911bc6c662bf")
389
+
390
+ // getCkbfsCellInfo("0xdb0b0b637060d2f6c42c4429e712fa043c1937968c03c54a5014b4595f88413a").then((data) => {
391
+ // console.log("ckbfs data=", data)
392
+ // console.log("mintAll done");
393
+ // })
394
+
395
+ //giveName("bbb", "0x0084106b9bea08f512e35b725c4a710ebf09cb65c05601ebde8d911bc6c662bf").then(console.log)
396
+
397
+ // getCkbfsCellInfo("0x52315569e5ff0d6d6392f047fcbea97bae1b32b688c29aca5251a157157278d3").then((data) => {
398
+ // console.log("ckbfs data=", data)
399
+ // })
400
+
401
+
402
+ getCellInfoFromV3Transaction("0x54c86dbdc6bdafb4616221d54cfc0ff186a4a772eba509838684f8e1ea271b40").then(console.log)
403
+
404
+ getCkbfsCellInfo("0x2c734e7f72e2e9d1a472f5ba26b229ac319c2ab26fdcd05fd7ce301390875f81").then(console.log)
405
+
406
+ // testReresolve("0x0084106b9bea08f512e35b725c4a710ebf09cb65c05601ebde8d911bc6c662bf").then(console.log)
@@ -110,7 +110,7 @@ async function retrieveAndSaveFileV3Example() {
110
110
  async function retrieveFileByURIV3Example() {
111
111
  try {
112
112
  // Example CKBFS URI (replace with actual URI)
113
- const ckbfsUri = "ckbfs://d52d8536d3498bd68fa1e235f7e090c2d047154e22fcea5cfa54ccb58c236eb3";
113
+ const ckbfsUri = "ckbfs://d49b78d821a12da1fc484ef36f855109fc52b195af29cafda1c134656e940a35";
114
114
 
115
115
  console.log(`Retrieving CKBFS v3 file by URI: ${ckbfsUri}`);
116
116
 
@@ -182,6 +182,39 @@ async function retrieveFileByOutPointV3Example() {
182
182
  }
183
183
  }
184
184
 
185
+ async function testReresolve(ckbfsId: string) {
186
+ const data = (await resolveCKBFSCell(client, ckbfsId, {network: NetworkType.Testnet}))!
187
+ return data
188
+ }
189
+
190
+ export async function getCkbfsCellInfo(ckbfsId: string) {
191
+ const { codeHash, hashType } = getCKBFSScriptConfig(NetworkType.Testnet, ProtocolVersion.V3)
192
+ console.log("codeHash, hashType=", codeHash, hashType, ckbfsId)
193
+ const cell = await client.findSingletonCellByType({
194
+ codeHash,
195
+ hashType,
196
+ args: ckbfsId
197
+ }, true)
198
+
199
+ if (!cell || !cell.cellOutput.type) {
200
+ throw new Error('No CKBFS cell found');
201
+ }
202
+
203
+ const rawData = cell.outputData.startsWith('0x')
204
+ ? Buffer.from(cell.outputData.slice(2), 'hex')
205
+ : Buffer.from(cell.outputData, 'hex');
206
+
207
+ const ckbfsData = CKBFSData.unpack(rawData, ProtocolVersion.V3)
208
+
209
+ return {
210
+ outPoint: { txHash: cell.outPoint.txHash as string, index: Number(cell.outPoint.index) },
211
+ type: cell.cellOutput.type,
212
+ lock: cell.cellOutput.lock,
213
+ capacity: cell.cellOutput.capacity,
214
+ data: ckbfsData,
215
+ };
216
+ }
217
+
185
218
  /**
186
219
  * Main function to run the v3 retrieval examples
187
220
  */
@@ -196,24 +229,26 @@ async function main() {
196
229
  console.log('============================================');
197
230
 
198
231
  try {
199
- console.log('Note: These examples require existing CKBFS v3 files.');
200
- console.log('Please run publish-v3.ts first to create v3 files,');
201
- console.log('then update the identifiers in this example.');
202
- console.log('');
203
- console.log('Supported identifier formats:');
204
- console.log('- TypeID: 0x1234...abcdef');
205
- console.log('- CKBFS URI: ckbfs://1234...abcdef');
206
- console.log('- OutPoint URI: ckbfs://1234...abcdefi0');
207
- console.log('');
232
+ // console.log('Note: These examples require existing CKBFS v3 files.');
233
+ // console.log('Please run publish-v3.ts first to create v3 files,');
234
+ // console.log('then update the identifiers in this example.');
235
+ // console.log('');
236
+ // console.log('Supported identifier formats:');
237
+ // console.log('- TypeID: 0x1234...abcdef');
238
+ // console.log('- CKBFS URI: ckbfs://1234...abcdef');
239
+ // console.log('- OutPoint URI: ckbfs://1234...abcdefi0');
240
+ // console.log('');
208
241
 
209
242
  // Uncomment to test different retrieval methods:
210
243
  //await retrieveFileByTypeIdV3Example();
211
244
  // await retrieveAndSaveFileV3Example();
212
245
  await retrieveFileByURIV3Example();
213
- //await retrieveFileByOutPointV3Example();
246
+ // //await retrieveFileByOutPointV3Example();
247
+
248
+ // await testReresolve("0x0084106b9bea08f512e35b725c4a710ebf09cb65c05601ebde8d911bc6c662bf").then(console.log)
214
249
 
215
- console.log('Retrieval example structure completed successfully!');
216
- console.log('Update the identifiers and uncomment methods to test.');
250
+ // console.log('Retrieval example structure completed successfully!');
251
+ // console.log('Update the identifiers and uncomment methods to test.');
217
252
  process.exit(0);
218
253
  } catch (error) {
219
254
  console.error('CKBFS v3 retrieval examples failed:', error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ckbfs/api",
3
- "version": "2.0.3",
3
+ "version": "2.0.5",
4
4
  "description": "SDK for CKBFS protocol on CKB",
5
5
  "license": "MIT",
6
6
  "author": "Code Monad<code@lab-11.org>",
@@ -29,6 +29,7 @@
29
29
  "sdk"
30
30
  ],
31
31
  "devDependencies": {
32
+ "@ckb-ccc/spore": "^1.5.5",
32
33
  "@types/jest": "^29.5.12",
33
34
  "@types/node": "^22.7.9",
34
35
  "jest": "^29.7.0",
package/src/index.ts CHANGED
@@ -142,10 +142,6 @@ export type AppendContentOptions = Omit<
142
142
  "contentType" | "filename" | "capacity"
143
143
  > & {
144
144
  capacity?: bigint;
145
- // V3 backlink parameters (optional for backward compatibility)
146
- previousTxHash?: string;
147
- previousWitnessIndex?: number;
148
- previousChecksum?: number;
149
145
  };
150
146
 
151
147
  /**
@@ -475,9 +471,9 @@ export class CKBFS {
475
471
 
476
472
  // Use V3 when backlink parameters are provided or version is V3
477
473
  if (version === ProtocolVersion.V3 &&
478
- options.previousTxHash &&
479
- options.previousWitnessIndex !== undefined &&
480
- options.previousChecksum !== undefined) {
474
+ ckbfsCell.outPoint.txHash &&
475
+ ckbfsCell.data.index !== undefined &&
476
+ ckbfsCell.data.checksum !== undefined) {
481
477
 
482
478
  const tx = await appendCKBFSV3(this.signer, {
483
479
  ckbfsCell,
@@ -485,9 +481,9 @@ export class CKBFS {
485
481
  feeRate: options.feeRate,
486
482
  network: options.network || this.network,
487
483
  version: ProtocolVersion.V3,
488
- previousTxHash: options.previousTxHash,
489
- previousWitnessIndex: options.previousWitnessIndex,
490
- previousChecksum: options.previousChecksum,
484
+ previousTxHash: ckbfsCell.outPoint.txHash,
485
+ previousWitnessIndex: ckbfsCell.data.index,
486
+ previousChecksum: ckbfsCell.data.checksum,
491
487
  });
492
488
 
493
489
  const txHash = await this.signer.sendTransaction(tx);
@@ -708,9 +704,9 @@ export class CKBFS {
708
704
 
709
705
  // Use V3 when backlink parameters are provided or version is V3
710
706
  if (version === ProtocolVersion.V3 &&
711
- options.previousTxHash &&
712
- options.previousWitnessIndex !== undefined &&
713
- options.previousChecksum !== undefined) {
707
+ ckbfsCell.outPoint.txHash &&
708
+ ckbfsCell.data.index !== undefined &&
709
+ ckbfsCell.data.checksum !== undefined) {
714
710
 
715
711
  return createAppendV3Transaction(this.signer, {
716
712
  ckbfsCell,
@@ -718,9 +714,9 @@ export class CKBFS {
718
714
  feeRate: options.feeRate,
719
715
  network: options.network || this.network,
720
716
  version: ProtocolVersion.V3,
721
- previousTxHash: options.previousTxHash,
722
- previousWitnessIndex: options.previousWitnessIndex,
723
- previousChecksum: options.previousChecksum,
717
+ previousTxHash: ckbfsCell.outPoint.txHash,
718
+ previousWitnessIndex: ckbfsCell.data.index,
719
+ previousChecksum: ckbfsCell.data.checksum,
724
720
  });
725
721
  } else {
726
722
  // Legacy V1/V2 behavior or when V3 backlink params are missing
@@ -208,10 +208,9 @@ export function extractCKBFSV3WitnessContent(witness: Uint8Array, isHeadWitness:
208
208
  // Extract previous position
209
209
  const prevTxHashBytes = witness.slice(6, 38);
210
210
  const previousTxHash = '0x' + Array.from(prevTxHashBytes).map(b => b.toString(16).padStart(2, '0')).join('');
211
-
212
- const previousWitnessIndex = new DataView(witness.slice(38, 42).buffer).getUint32(0, true);
213
- const previousChecksum = new DataView(witness.slice(42, 46).buffer).getUint32(0, true);
214
- const nextIndex = new DataView(witness.slice(46, 50).buffer).getUint32(0, true);
211
+ const previousWitnessIndex = new DataView(witness.slice(38, 42).buffer.slice(witness.slice(38, 42).byteOffset, witness.slice(38, 42).byteOffset + 4)).getUint32(0, true);
212
+ const previousChecksum = new DataView(witness.slice(42, 46).buffer.slice(witness.slice(42, 46).byteOffset, witness.slice(42, 46).byteOffset + 4)).getUint32(0, true);
213
+ const nextIndex = new DataView(witness.slice(46, 50).buffer.slice(witness.slice(46, 50).byteOffset, witness.slice(46, 50).byteOffset + 4)).getUint32(0, true);
215
214
  const content = witness.slice(50);
216
215
 
217
216
  return {