@ckbfs/api 2.0.3 → 2.0.4

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;
@@ -0,0 +1,412 @@
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
+ const previousData = {
117
+ previousTxHash: ckbfsCell.outPoint.txHash,
118
+ previousWitnessIndex: ckbfsCell.data?.index || 0,
119
+ previousChecksum: ckbfsCell.data?.checksum || 0
120
+ };
121
+
122
+ let tx = await ckbfs.createAppendContentTransaction(content, ckbfsCell, previousData as any);
123
+ tx.addCellDeps(TraceLockDep)
124
+
125
+ const sizeBefore = tx.outputs[0].lock.occupiedSize
126
+ const traceLogLock = Script.from({
127
+ codeHash: TraceLogCodeHash,
128
+ hashType: "type",
129
+ args: toHash
130
+ })
131
+ tx.outputs[0].lock = traceLogLock
132
+ const sizeAfter = traceLogLock.occupiedSize
133
+
134
+ const diffSize = BigInt(sizeAfter - sizeBefore) * BigInt(100000000)
135
+ tx.outputs[0].capacity = tx.outputs[0].capacity + diffSize
136
+
137
+ const sporeLockArgs = `0x01${ tx.outputs[0].type?.hash().slice(2) }`
138
+ const newSporeLock = Script.from({
139
+ codeHash: ShadowSporeCodeHash,
140
+ args: sporeLockArgs,
141
+ hashType: "data1",
142
+ })
143
+
144
+ tx.outputs = [
145
+ tx.outputs[0]
146
+ ]
147
+
148
+ const signer = ckbfs['signer'] as any
149
+ const sporeTx = await transferSpore({
150
+ signer,
151
+ id: sporeId,
152
+ to: newSporeLock,
153
+ tx: tx,
154
+ })
155
+
156
+ tx.addCellDeps(ShadowDep)
157
+
158
+ const finalTx = sporeTx.tx
159
+ await finalTx.completeFeeBy(signer)
160
+ const txHash = await signer.sendTransaction(finalTx)
161
+ console.log(`File appended successfully! Transaction Hash: ${txHash}`);
162
+ return { txHash, log: content }
163
+ }
164
+
165
+ export async function giveName(name: string, ckbfsId: string) {
166
+ const ckbfsCell = await getCkbfsCellInfo(ckbfsId)
167
+ const content = `GIVE_NAME,NEW_NAME:${name}\n`
168
+
169
+ console.log("ckbfsCell=", ckbfsCell)
170
+
171
+ const previousData = {
172
+ previousTxHash: ckbfsCell.outPoint.txHash,
173
+ previousWitnessIndex: ckbfsCell.data?.index || 0,
174
+ previousChecksum: ckbfsCell.data?.checksum || 0
175
+ };
176
+ const signer = ckbfs['signer']
177
+ const address = await signer.getRecommendedAddress()
178
+ const addressHash = await getAddressScriptHash(address)
179
+ console.log("addressHash=", addressHash)
180
+ let tx = await ckbfs.createAppendContentTransaction(content, ckbfsCell, previousData as any);
181
+ tx.addCellDeps(TestnetTraceLockDep)
182
+ console.log(tx.stringify())
183
+ const txHash = await signer.sendTransaction(tx)
184
+ console.log(`File appended successfully! Transaction Hash: ${txHash}`);
185
+ return { txHash, log: content }
186
+ }
187
+
188
+ // export async function transfer(to: string, ckbfsId: string) {
189
+ // const ckbfsCell = await getCkbfsCellInfo(ckbfsId)
190
+ // const from = await ckbfs.getAddress();
191
+ // const fromHash = await getAddressScriptHash(from)
192
+ // const toHash = await getAddressScriptHash(to)
193
+ // const content = `TRANSFER,FROM:${fromHash},TO:${toHash}\n`
194
+
195
+ // const signer = ckbfs['signer']
196
+ // let tx = await ckbfs.createAppendContentTransaction(content, ckbfsCell);
197
+ // tx.outputs[0].lock.args = toHash as `0x{string}`;
198
+ // tx.addCellDeps(TestnetTraceLockDep)
199
+ // const txHash = await signer.sendTransaction(tx)
200
+ // console.log(`File appended successfully! Transaction Hash: ${txHash}`);
201
+
202
+ // return { txHash, log: content };
203
+ // }
204
+
205
+ // export async function release(from: string, ckbfsId: string) {
206
+ // const ckbfsCell = await await getCkbfsCellInfo(ckbfsId)
207
+ // const fromHash = await getAddressScriptHash(from)
208
+ // const content = `RELEASE,FROM:${fromHash}\n`
209
+ // const signer = ckbfs['signer']
210
+ // let tx = await ckbfs.createAppendContentTransaction(content, ckbfsCell);
211
+
212
+ // tx.addCellDeps(TestnetTraceLockDep)
213
+ // const txHash = await signer.sendTransaction(tx)
214
+ // console.log(`File appended successfully! Transaction Hash: ${txHash}`);
215
+ // return { txHash, log: content };
216
+ // }
217
+
218
+ // export async function retrieveLogsFromChain(ckbfsId: string) {
219
+ // const { outPoint, data } = await getCkbfsCellInfo(ckbfsId)
220
+ // const content = await getFileContentFromChain(client, outPoint, data)
221
+ // const logs = content.toString().trim().split("\n")
222
+ // return logs
223
+ // }
224
+
225
+ export async function getCkbfsCellInfo(ckbfsId: string) {
226
+ const { codeHash, hashType } = getCKBFSScriptConfig(NetworkType.Testnet, ProtocolVersion.V3)
227
+ console.log("codeHash, hashType=", codeHash, hashType, ckbfsId)
228
+ const cell = await client.findSingletonCellByType({
229
+ codeHash,
230
+ hashType,
231
+ args: ckbfsId
232
+ }, true)
233
+
234
+ if (!cell || !cell.cellOutput.type) {
235
+ throw new Error('No CKBFS cell found');
236
+ }
237
+
238
+ const rawData = cell.outputData.startsWith('0x')
239
+ ? Buffer.from(cell.outputData.slice(2), 'hex')
240
+ : Buffer.from(cell.outputData, 'hex');
241
+
242
+ const ckbfsData = CKBFSData.unpack(rawData, ProtocolVersion.V3)
243
+
244
+ return {
245
+ outPoint: { txHash: cell.outPoint.txHash as string, index: Number(cell.outPoint.index) },
246
+ type: cell.cellOutput.type,
247
+ lock: cell.cellOutput.lock,
248
+ capacity: cell.cellOutput.capacity,
249
+ data: ckbfsData,
250
+ };
251
+ }
252
+
253
+
254
+ export function getCkbfsList() {
255
+ const file = path.join(__dirname, `./data/${'testnet'}/ckbfs-list.json`)
256
+ return JSON.parse(fs.readFileSync(file).toString())
257
+ }
258
+
259
+ export async function mintAll() {
260
+ const ckbfsList = getCkbfsList()
261
+ for(const { no } of ckbfsList) {
262
+ const { txHash, ckbfsId } = await mint(no)
263
+ console.log(`minted ckbfs no=${no}, ckbfsId=${ckbfsId}, txHash=${txHash}`);
264
+
265
+ const interval = setInterval(async () => {
266
+ try {
267
+ const tx = await client.getTransaction(txHash)
268
+ if (tx && tx.status === 'committed') {
269
+ clearInterval(interval)
270
+ console.info(`tx confirmed, https://explorer.nervos.org/transaction/${txHash}`);
271
+ }
272
+ } catch (error) {
273
+ console.error(error)
274
+ }
275
+ }, 5 * 1000)
276
+ }
277
+ }
278
+
279
+ async function getCellInfoFromV3Transaction(txHash: string): Promise<{
280
+ outPoint: { txHash: string; index: number };
281
+ type: Script;
282
+ data: CKBFSDataType;
283
+ lock: Script;
284
+ capacity: bigint;
285
+ previousTxHash: string;
286
+ previousWitnessIndex: number;
287
+ previousChecksum: number;
288
+ }> {
289
+ console.log(`Retrieving v3 transaction data for: ${txHash}`);
290
+
291
+ try {
292
+ // Get transaction from RPC
293
+ const txWithStatus = await client.getTransaction(txHash);
294
+ if (!txWithStatus || !txWithStatus.transaction) {
295
+ throw new Error(`Transaction ${txHash} not found`);
296
+ }
297
+
298
+ const tx = Transaction.from(txWithStatus.transaction);
299
+ console.log(`Transaction found with ${tx.outputs.length} outputs`);
300
+
301
+ // Find the CKBFS cell output (first output with type script)
302
+ let ckbfsCellIndex = 0;
303
+ const output = tx.outputs[ckbfsCellIndex];
304
+ if (!output || !output.type) {
305
+ throw new Error('No CKBFS cell found in the transaction');
306
+ }
307
+
308
+ console.log(`Found CKBFS v3 cell at index ${ckbfsCellIndex}`);
309
+ console.log(`Cell type script hash: ${output.type.hash()}`);
310
+
311
+ // Get output data
312
+ const outputData = tx.outputsData[ckbfsCellIndex];
313
+ if (!outputData) {
314
+ throw new Error('Output data not found');
315
+ }
316
+
317
+ // Parse the output data as CKBFS v3 data
318
+ const rawData = outputData.startsWith('0x')
319
+ ? ccc.bytesFrom(outputData.slice(2), 'hex')
320
+ : Buffer.from(outputData, 'hex');
321
+
322
+ // Unpack the raw data using v3 format
323
+ const version = ProtocolVersion.V3;
324
+ console.log(`Using protocol version ${version} for unpacking v3 cell data`);
325
+
326
+ let ckbfsData: CKBFSDataType;
327
+ try {
328
+ ckbfsData = CKBFSData.unpack(rawData, version);
329
+
330
+ console.log('Successfully unpacked CKBFS v3 cell data:');
331
+ console.log(`- Checksum: ${ckbfsData.checksum}`);
332
+ console.log(`- File: ${ckbfsData.filename}`);
333
+ console.log(`- Content Type: ${ckbfsData.contentType}`);
334
+ console.log(`- Index: ${ckbfsData.index}`);
335
+ } catch (error) {
336
+ console.error('Error unpacking CKBFS v3 data:', error);
337
+ throw new Error(`Failed to unpack CKBFS v3 data: ${error}`);
338
+ }
339
+
340
+ // Extract backlink information from v3 witness
341
+ let previousTxHash = '0x' + '00'.repeat(32);
342
+ let previousWitnessIndex = 0;
343
+ let previousChecksum = 0;
344
+
345
+ if (ckbfsData.index !== undefined && ckbfsData.index < tx.witnesses.length) {
346
+ const witnessHex = tx.witnesses[ckbfsData.index];
347
+ const witness = Buffer.from(witnessHex.slice(2), 'hex');
348
+
349
+ if (isCKBFSV3Witness(witness)) {
350
+ try {
351
+ const witnessData = extractCKBFSV3WitnessContent(witness, true);
352
+ previousTxHash = witnessData.previousTxHash || previousTxHash;
353
+ previousWitnessIndex = witnessData.previousWitnessIndex || 0;
354
+ previousChecksum = witnessData.previousChecksum || 0;
355
+
356
+ console.log('Extracted v3 backlink information:');
357
+ console.log(`- Previous TX Hash: ${previousTxHash}`);
358
+ console.log(`- Previous Witness Index: ${previousWitnessIndex}`);
359
+ console.log(`- Previous Checksum: ${previousChecksum}`);
360
+ } catch (error) {
361
+ console.warn('Could not extract backlink info from witness:', error);
362
+ }
363
+ }
364
+ }
365
+
366
+ return {
367
+ outPoint: {
368
+ txHash,
369
+ index: ckbfsCellIndex
370
+ },
371
+ type: output.type,
372
+ lock: output.lock,
373
+ capacity: output.capacity,
374
+ data: ckbfsData,
375
+ previousTxHash,
376
+ previousWitnessIndex,
377
+ previousChecksum
378
+ };
379
+ } catch (error) {
380
+ console.error('Error retrieving v3 transaction data:', error);
381
+ throw new Error(`Failed to retrieve or parse v3 cell data: ${error}`);
382
+ }
383
+ }
384
+
385
+ async function testReresolve(ckbfsId: string) {
386
+ const data = (await resolveCKBFSCell(client, ckbfsId, {network: NetworkType.Testnet}))!
387
+ return data
388
+ }
389
+
390
+ // mintAll()
391
+
392
+ // mint("X30125NMNVAP000201").then(console.log)
393
+
394
+ // claim("ckt1qyq0zr47f0p8sm5d3cvtlpkljs7zvqcw7ngqnfscx0", "0xa3347c13f0419d9013a3f48a2b9ad993c2b6b5806827f3bf37480a58580d669d", "0x0084106b9bea08f512e35b725c4a710ebf09cb65c05601ebde8d911bc6c662bf")
395
+
396
+ // getCkbfsCellInfo("0xdb0b0b637060d2f6c42c4429e712fa043c1937968c03c54a5014b4595f88413a").then((data) => {
397
+ // console.log("ckbfs data=", data)
398
+ // console.log("mintAll done");
399
+ // })
400
+
401
+ //giveName("bbb", "0x0084106b9bea08f512e35b725c4a710ebf09cb65c05601ebde8d911bc6c662bf").then(console.log)
402
+
403
+ // getCkbfsCellInfo("0x52315569e5ff0d6d6392f047fcbea97bae1b32b688c29aca5251a157157278d3").then((data) => {
404
+ // console.log("ckbfs data=", data)
405
+ // })
406
+
407
+
408
+ // getCellInfoFromV3Transaction("0x8dc79a7630145e2a220e2363beca2781c6a4f0f79ef7a01ab73f17dc90571fb7").then(console.log)
409
+
410
+ // getCkbfsCellInfo("0x0084106b9bea08f512e35b725c4a710ebf09cb65c05601ebde8d911bc6c662bf").then(console.log)
411
+
412
+ // testReresolve("0x0084106b9bea08f512e35b725c4a710ebf09cb65c05601ebde8d911bc6c662bf").then(console.log)
@@ -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
- await retrieveFileByURIV3Example();
213
- //await retrieveFileByOutPointV3Example();
245
+ // await retrieveFileByURIV3Example();
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.4",
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