@ckbfs/api 2.0.8 → 2.0.10

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.
@@ -222,7 +222,7 @@ async function prepareAppendV3Transaction(options) {
222
222
  const combinedContent = Buffer.concat(contentChunks);
223
223
  const newChecksum = await (0, checksum_1.updateChecksum)(previousChecksum, combinedContent);
224
224
  // Calculate the actual witness indices where our content is placed
225
- const contentStartIndex = witnessStartIndex || from?.witnesses.length || 0;
225
+ const contentStartIndex = from?.witnesses.length || witnessStartIndex || 0;
226
226
  // Create CKBFS v3 witnesses with backlink info
227
227
  const ckbfsWitnesses = (0, witness_1.createChunkedCKBFSV3Witnesses)(contentChunks, {
228
228
  previousTxHash,
@@ -350,14 +350,15 @@ async function createAppendV3Transaction(signer, options) {
350
350
  // Add more inputs to cover the increased capacity
351
351
  await preTx.completeInputsByCapacity(signer);
352
352
  }
353
- await preTx.completeInputsByCapacity(signer);
354
353
  const witnesses = [];
354
+ var witnessOffsetIndex = 0;
355
355
  // add empty witness for signer if ckbfs's lock is the same as signer's lock
356
356
  if (address.script.hash() === lock.hash()) {
357
357
  witnesses.push("0x");
358
+ witnessOffsetIndex = 1;
358
359
  }
359
360
  // add ckbfs witnesses (skip the first witness which is for signing)
360
- witnesses.push(...preTx.witnesses.slice(1));
361
+ witnesses.push(...preTx.witnesses.slice(witnessOffsetIndex));
361
362
  // Add empty witnesses for additional signer inputs
362
363
  // This is to ensure that the transaction is valid and can be signed
363
364
  for (let i = inputsBefore; i < preTx.inputs.length; i++) {
@@ -2,10 +2,6 @@ import {
2
2
  getFileContentFromChainByIdentifierV3,
3
3
  saveFileFromChainByIdentifierV3,
4
4
  ProtocolVersion,
5
- CKBFSData,
6
- getCKBFSScriptConfig,
7
- NetworkType,
8
- resolveCKBFSCell,
9
5
  } from '../src/index';
10
6
  import { ClientPublicTestnet } from '@ckb-ccc/core';
11
7
 
@@ -18,7 +14,7 @@ const client = new ClientPublicTestnet(); // Use testnet
18
14
  async function retrieveFileByTypeIdV3Example() {
19
15
  try {
20
16
  // Example TypeID (replace with actual TypeID from a v3 published file)
21
- const typeId = "0x32d5f0b09f85a64143e91847b6167d8e952ea3026db92068cada45f4478dd814";
17
+ const typeId = "0xc387111856be837b1f358d49a9d7e4461dc18244c2b7b59f9012617b1c09d7be";
22
18
 
23
19
  console.log(`Retrieving CKBFS v3 file by TypeID: ${typeId}`);
24
20
 
@@ -110,7 +106,7 @@ async function retrieveAndSaveFileV3Example() {
110
106
  async function retrieveFileByURIV3Example() {
111
107
  try {
112
108
  // Example CKBFS URI (replace with actual URI)
113
- const ckbfsUri = "ckbfs://d49b78d821a12da1fc484ef36f855109fc52b195af29cafda1c134656e940a35";
109
+ const ckbfsUri = "ckbfs://c387111856be837b1f358d49a9d7e4461dc18244c2b7b59f9012617b1c09d7be";
114
110
 
115
111
  console.log(`Retrieving CKBFS v3 file by URI: ${ckbfsUri}`);
116
112
 
@@ -149,7 +145,7 @@ async function retrieveFileByURIV3Example() {
149
145
  async function retrieveFileByOutPointV3Example() {
150
146
  try {
151
147
  // Example OutPoint URI (replace with actual transaction hash and index)
152
- const outPointUri = "ckbfs://1cc22be7489f64bda7cbc3a9227a94640394dc99f98181b1c3b1243d24897972i0";
148
+ const outPointUri = "ckbfs://1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdefi0";
153
149
 
154
150
  console.log(`Retrieving CKBFS v3 file by OutPoint: ${outPointUri}`);
155
151
 
@@ -173,7 +169,6 @@ async function retrieveFileByOutPointV3Example() {
173
169
  console.log(`Content type: ${fileData.contentType}`);
174
170
  console.log(`Size: ${fileData.size} bytes`);
175
171
  console.log(`Checksum: ${fileData.checksum}`);
176
- console.log(`Content: ${fileData.content}`);
177
172
 
178
173
  return fileData;
179
174
  } catch (error) {
@@ -182,39 +177,6 @@ async function retrieveFileByOutPointV3Example() {
182
177
  }
183
178
  }
184
179
 
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
-
218
180
  /**
219
181
  * Main function to run the v3 retrieval examples
220
182
  */
@@ -229,26 +191,24 @@ async function main() {
229
191
  console.log('============================================');
230
192
 
231
193
  try {
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('');
194
+ console.log('Note: These examples require existing CKBFS v3 files.');
195
+ console.log('Please run publish-v3.ts first to create v3 files,');
196
+ console.log('then update the identifiers in this example.');
197
+ console.log('');
198
+ console.log('Supported identifier formats:');
199
+ console.log('- TypeID: 0x1234...abcdef');
200
+ console.log('- CKBFS URI: ckbfs://1234...abcdef');
201
+ console.log('- OutPoint URI: ckbfs://1234...abcdefi0');
202
+ console.log('');
241
203
 
242
204
  // Uncomment to test different retrieval methods:
243
- //await retrieveFileByTypeIdV3Example();
205
+ await retrieveFileByTypeIdV3Example();
244
206
  // await retrieveAndSaveFileV3Example();
245
207
  await retrieveFileByURIV3Example();
246
- // //await retrieveFileByOutPointV3Example();
247
-
248
- // await testReresolve("0x0084106b9bea08f512e35b725c4a710ebf09cb65c05601ebde8d911bc6c662bf").then(console.log)
208
+ // await retrieveFileByOutPointV3Example();
249
209
 
250
- // console.log('Retrieval example structure completed successfully!');
251
- // console.log('Update the identifiers and uncomment methods to test.');
210
+ console.log('Retrieval example structure completed successfully!');
211
+ console.log('Update the identifiers and uncomment methods to test.');
252
212
  process.exit(0);
253
213
  } catch (error) {
254
214
  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.8",
3
+ "version": "2.0.10",
4
4
  "description": "SDK for CKBFS protocol on CKB",
5
5
  "license": "MIT",
6
6
  "author": "Code Monad<code@lab-11.org>",
@@ -366,7 +366,7 @@ export async function prepareAppendV3Transaction(
366
366
  const newChecksum = await updateChecksum(previousChecksum, combinedContent);
367
367
 
368
368
  // Calculate the actual witness indices where our content is placed
369
- const contentStartIndex = witnessStartIndex || from?.witnesses.length || 0;
369
+ const contentStartIndex = from?.witnesses.length || witnessStartIndex || 0;
370
370
 
371
371
  // Create CKBFS v3 witnesses with backlink info
372
372
  const ckbfsWitnesses = createChunkedCKBFSV3Witnesses(contentChunks, {
@@ -519,15 +519,15 @@ export async function createAppendV3Transaction(
519
519
  await preTx.completeInputsByCapacity(signer);
520
520
  }
521
521
 
522
- await preTx.completeInputsByCapacity(signer);
523
-
524
522
  const witnesses: any = [];
523
+ var witnessOffsetIndex = 0;
525
524
  // add empty witness for signer if ckbfs's lock is the same as signer's lock
526
525
  if (address.script.hash() === lock.hash()) {
527
526
  witnesses.push("0x");
527
+ witnessOffsetIndex = 1;
528
528
  }
529
529
  // add ckbfs witnesses (skip the first witness which is for signing)
530
- witnesses.push(...preTx.witnesses.slice(1));
530
+ witnesses.push(...preTx.witnesses.slice(witnessOffsetIndex));
531
531
 
532
532
  // Add empty witnesses for additional signer inputs
533
533
  // This is to ensure that the transaction is valid and can be signed
@@ -781,4 +781,4 @@ export async function transferCKBFSV3(
781
781
  ): Promise<Transaction> {
782
782
  const tx = await createTransferV3Transaction(signer, options);
783
783
  return signer.signTransaction(tx);
784
- }
784
+ }
package/RFC.v3.md DELETED
@@ -1,210 +0,0 @@
1
- # CKBFS Protocol V3
2
-
3
- This is a next generation for CKBFS Protocol, aimed to provide a more affordable storage price -- comparing to similar solutions like IPFS.
4
-
5
- The most important change of V3 is that there's no longer `Backlinks` inside the Cell data. Instead, it was moved into witnesses.
6
-
7
-
8
- ## Protocol Standard
9
-
10
- ### Data Structure
11
-
12
- #### CKBFS v3 Cell
13
-
14
- CKBFS Cell is a cell that stores metadata of the file:
15
-
16
- ```yaml
17
- Data:
18
- content_type: Bytes # String Bytes
19
- filename: Bytes # String Bytes
20
- index: Uint32 # Reference of the first witnesses index.
21
- checksum: Uint32 # Adler32 checksum
22
-
23
- Type:
24
- hash_type: "data1"
25
- code_hash: CKBFS_V3_TYPE_DATA_HASH
26
- args: <TypeID, 32 bytes>,[<hasher_code_hash>, optional]
27
- Lock:
28
- <user_defined>
29
- ```
30
-
31
- The following rules should be met in a CKBFS cell:
32
-
33
- - Rule 1: data structure of a CKBFS cell is molecule encoded. See [Molecule](https://github.com/nervosnetwork/molecule) definitions below.
34
- - Rule 2: checksum must match with specified witnesses. Default checksum algorithm will be Alder32 if not specify `hasher_code_hash` in Type script args.
35
- - Rule 3: if `hasher_code_hash` is specified, then it will use hasher binary from CellDeps that matches `code_hash`, with same input parameter.
36
- - Rule 4: Once created, a CKBFS cell can only be updated/transfered, which means it can not be destroyed.
37
- - Rule 5: **`index` is the first witness index of the stored CKBFS structured contents in splited witnesses.**
38
-
39
-
40
- ### Witnesses
41
-
42
- File contents are stored in witnesses. In a single transaction, witnesses can be splitted into multiple parts and concat together while verification.
43
-
44
- ```yaml
45
- Witnesses:
46
- <"CKBFS"> <0x03> <PREVIOUS_POSITION(TX_HASH, Witness_index)> <PREVIOUS_CHECKSUM(4 bytes) | 0x00000000> <NEXT_INDEX | 0x00000000> [CONTENT_BYTES_PART_1]
47
- <NEXT_INDEX | 0x00000000> <CONTENT_BYTES_PART_2>
48
- <NEXT_INDEX | 0x00000000> <CONTENT_BYTES_PART_3> ...
49
- <0x00000000> <CONTENT_BYTES_PART_N>
50
- ```
51
-
52
- The following rules should be met for witnesses used in CKBFS:
53
- - Rule 6: Witnesses are different in `Head Witness`, `Middle Witnesses`, and `Tail Witness`, their form should follow bellow's rules
54
- - Rule 7: The first 5 bytes of `Head Witness` must be UTF8 coded string bytes of `CKBFS`, which should be: `0x434b424653`
55
- - Rule 8: The 6th byte of `Head Witness` must be the version of CKBFS protocol, which should be: `0x03`.
56
- - Rule 9: Previous position of this CKBFS content stores from 7th bytes to 42th bytes in `Head Witness`. it should be previous transaction hash(H256) and previous Head Witness index(Uint32).
57
- - Rule 10: Previous checksum value must stored in `Head Witness`, position from 43rd to 46th bytes. If there's no previous status, then it should be `0x00000000`.
58
- - Rule 10: File contents bytes are stored from:
59
- - 51st byte from the Head Witness.
60
- - 5th byte from the `Middle Witnesses` and `Tail Witness`
61
-
62
- ----
63
-
64
- ### Operations
65
-
66
- This section describes operations and restrictions in CKBFS v3 implementation.
67
-
68
- #### Publish
69
-
70
- Publish operation creates one or more new CKBFS v3 cell.
71
-
72
- ```yaml
73
- Witnesses:
74
- <...>
75
- <0x434b424653, 0x03, 32bytes 0x00, 0x00000000, 0x00000000, 0x00000002,CKBFS_CONTENT_BYTES_PART_1>
76
- <0x00000003, CKBFS_CONTENT_BYTES_PART_2>
77
- <...>
78
- <0x00000000, CKBFS_CONTENT_BYTES_PART_TAIL>
79
- <...>
80
- Inputs:
81
- <...>
82
- Outputs:
83
- <vec> CKBFS_V3_CELL
84
- Data:
85
- content-type: string
86
- filename: string
87
- indexes: uint32
88
- checksum: uint32
89
- Type:
90
- code_hash: ckbfs v3 type script
91
- args: 32 bytes type_id, (...)
92
- <...>
93
- ```
94
-
95
- Publish operation must satisfy following rule:
96
-
97
- - Rule 11: in a publish operation, checksum in cell data must be equal with `hash(Witnesses[ALL_CONTENT_PARTS])`.
98
- - Rule 12: Previous position value, previous checksum value should be all zero in `Head Witnesses`
99
-
100
-
101
- ---
102
-
103
- #### Append
104
-
105
- Append operation updates exist live CKBFS v3 cell, validates the latest checksum.
106
-
107
- ```yaml
108
- // Append
109
- Witnesses:
110
- <...>
111
- <0x434b424653, 0x03, PREVIOUS_TX_HASH_VALUE, PREVIOUS_INDEX_IN_CKBFS_V3_CELL, PREIVOUS_CHECKSUM, 0x00000002,CKBFS_CONTENT_BYTES_PART_1>
112
- <0x00000003, CKBFS_CONTENT_BYTES_PART_2>
113
- <...>
114
- <0x00000000, CKBFS_CONTENT_BYTES_PART_TAIL>
115
- <...>
116
- Inputs:
117
- <...>
118
- CKBFS_V3_CELL
119
- Data:
120
- content-type: string
121
- filename: string
122
- index: uint32
123
- checksum: uint32 # previous checksum
124
- Type:
125
- code_hash: ckbfs v3 type script
126
- args: 32 bytes type_id, (...)
127
- <...>
128
- Outputs:
129
- <...>
130
- CKBFS_V3_CELL:
131
- Data:
132
- content-type: string
133
- filename: string
134
- index: uint32
135
- checksum: uint32 # updated checksum
136
- Type:
137
- code_hash: ckbfs v3 type script
138
- args: 32 bytes type_id, (...)
139
- ```
140
-
141
- - Rule 13: new checksum of updated CKBFS cell should be equal to: `hasher.recover_from(previous_checksum).update(new_content_bytes)`
142
- - Rule 14: `content-type`, `filename`, and Type args of a CKBFS cell CAN NOT be updated in ANY condition
143
-
144
-
145
- ---
146
-
147
- #### Transfer
148
-
149
- Transfer operation transfers ownership of a CKBFS cell, and ensure it did not lost tracking of backlinks.
150
-
151
- ```yaml
152
- // Transfer
153
- Witnesses:
154
- <...>
155
- <0x434b424653, 0x03, PREVIOUS_TX_HASH_VALUE, PREVIOUS_INDEX_IN_CKBFS_V3_CELL, PREIVOUS_CHECKSUM, 0x00000000>
156
- <...>
157
-
158
- Inputs:
159
- <...>
160
- CKBFS_V3_CELL
161
- Data:
162
- content-type: string
163
- filename: string
164
- index: uint32
165
- checksum: uint32
166
- Type:
167
- code_hash: ckbfs type script
168
- args: 32 bytes type_id, (...)
169
- Lock:
170
- <USER_DEFINED>
171
- <...>
172
- Outputs:
173
- <...>
174
- CKBFS_V3_CELL:
175
- Data:
176
- content-type: string
177
- filename: string
178
- index: uint32
179
- checksum: uint32
180
- Type:
181
- code_hash: ckbfs type script
182
- args: 32 bytes type_id, (...)
183
- Lock:
184
- <USER_DEFINED>
185
- ```
186
-
187
- - Rule 15: The `Head Witness` should not contain any content part bytes
188
- - Rule 16: in a transfer operation, `checksum` CAN NOT be updated
189
-
190
-
191
- ---
192
-
193
- ## Other Notes
194
-
195
- ### Molecule Definitions:
196
-
197
- Here’s molecule definitions of CKBFS data structures
198
-
199
- ```jsx
200
- vector Bytes <byte>;
201
- option BytesOpt (Bytes);
202
- option Uint32Opt (Uint32);
203
-
204
- table CKBFSData {
205
- index: Uint32,
206
- checksum: Uint32,
207
- content_type: Bytes,
208
- filename: Bytes,
209
- }
210
- ```
package/code.png DELETED
Binary file
package/demo-output.txt DELETED
@@ -1 +0,0 @@
1
- Hollo, WKBFS! This is a test file. More content in second chunk. Last churk of the test file.
@@ -1 +0,0 @@
1
- Hello CKBFS from direct content!
@@ -1,409 +0,0 @@
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
- SignerCkbPrivateKey,
23
- fixedPointFrom,
24
- Signer
25
- } from "@ckb-ccc/core";
26
- import {
27
- transferSpore
28
- } from "@ckb-ccc/spore";
29
- //import { isMainnet, network, CKB_PRIVATE_KEY } from "../config"
30
-
31
-
32
- const client = new ClientPublicTestnet()
33
-
34
- export const TestnetTraceLockDep = {
35
- outPoint: {
36
- txHash: "0x7a3e492188438ca4b260fed0f7a00d18ec9e4671a8c3b54fc2b3b49447ab2e2f",
37
- index: 0x0,
38
- },
39
- depType: "code",
40
- }
41
-
42
- export const MainnetTraceLockDep = {
43
- outPoint: {
44
- txHash: "0x...", //TODO: fill mainnet tracelock txhash
45
- index: 0x0,
46
- },
47
- depType: "code",
48
- }
49
-
50
- export const TestnetShadowDep = {
51
- outPoint: {
52
- txHash: "0x2d8a311a55e42d7d6810610149f6e125f0d292112f8ed4a21177aec05da2b905",
53
- index: 0x0,
54
- },
55
- depType: "code",
56
- }
57
-
58
- export const MainnetShadowDep = {
59
- outPoint: {
60
- txHash: "0x5b20ec7d7d5c6410ac4924c57d1eac1dd50129b6263be3dc93055397b5724dc2",
61
- index: 0x0,
62
- },
63
- depType: "code",
64
- }
65
-
66
-
67
- const TraceLockDep = TestnetTraceLockDep
68
- const ShadowDep = TestnetShadowDep
69
-
70
- const TraceLogCodeHash = "0xbd7e56daaa4cc9ecf488a50d2f4db2a55a7c86eb2df2157d24a62be9be5b34ab"
71
- const ShadowSporeCodeHash = "0x6361d4b20d845953d9c9431bbba08905573005a71e2a2432e7e0e7c685666f24"
72
- const CKB_PRIVATE_KEY = "0x620ab1e4273b937032380e9f851c3119427ba965805bebcdce60a4494fd3074d"
73
-
74
- const ckbfs = new CKBFS(
75
- CKB_PRIVATE_KEY,
76
- NetworkType.Testnet,
77
- {
78
- version: ProtocolVersion.V3,
79
- chunkSize: 30 * 1024, // 30KB chunks
80
- useTypeID: false // Use code hash instead of type ID
81
- }
82
- );
83
-
84
- async function getAddressScriptHash(addr: string | Address) {
85
- if (typeof addr === 'string') {
86
- addr = await Address.fromString(addr, client)
87
- console.log("addr=", addr)
88
- }
89
- return `0x03${addr.script.hash().slice(2)}`
90
- }
91
-
92
- export async function mint(physicalArtifactNo: string) {
93
- // Get address info
94
- const address = await ckbfs.getAddress();
95
- const ownerHash = await getAddressScriptHash(address)
96
-
97
- const content = `MINT,TO:${ownerHash}\n`
98
-
99
- // You can provide additional options
100
- const options = {
101
- contentType: 'text/plain',
102
- filename: `${physicalArtifactNo}.LOGS`,
103
- };
104
- const tx = await ckbfs.createPublishContentTransaction(content, options);
105
- const signer = ckbfs['signer']
106
- const txHash = await signer.sendTransaction(tx)
107
- const ckbfsId = tx.outputs[0].type?.args.toString()
108
- return { txHash, log: content, ckbfsId };
109
- }
110
-
111
- export async function claim(to: string, sporeId: string, ckbfsId: string) {
112
- const from = await ckbfs.getAddress();
113
- const ckbfsCell = await getCkbfsCellInfo(ckbfsId);
114
- const fromHash = await getAddressScriptHash(from)
115
- const toHash = await getAddressScriptHash(to)
116
-
117
- const content = `TRANSFER,FROM:${fromHash},TO:${toHash}\n`
118
-
119
- let tx = await ckbfs.createAppendContentTransaction(content, ckbfsCell);
120
- tx.addCellDeps(TraceLockDep)
121
-
122
- const sizeBefore = tx.outputs[0].lock.occupiedSize
123
- const traceLogLock = Script.from({
124
- codeHash: TraceLogCodeHash,
125
- hashType: "type",
126
- args: toHash
127
- })
128
- tx.outputs[0].lock = traceLogLock
129
- const sizeAfter = traceLogLock.occupiedSize
130
-
131
- const diffSize = BigInt(sizeAfter - sizeBefore) * BigInt(100000000)
132
- tx.outputs[0].capacity = tx.outputs[0].capacity + diffSize
133
-
134
- const sporeLockArgs = `0x01${ tx.outputs[0].type?.hash().slice(2) }`
135
- const newSporeLock = Script.from({
136
- codeHash: ShadowSporeCodeHash,
137
- args: sporeLockArgs,
138
- hashType: "data1",
139
- })
140
-
141
- tx.outputs = [
142
- tx.outputs[0]
143
- ]
144
-
145
- const signer = ckbfs['signer'] as any
146
- const sporeTx = await transferSpore({
147
- signer,
148
- id: sporeId,
149
- to: newSporeLock,
150
- tx: tx,
151
- })
152
-
153
- tx.addCellDeps(ShadowDep)
154
-
155
- const finalTx = sporeTx.tx
156
- await finalTx.completeFeeBy(signer)
157
- const txHash = await signer.sendTransaction(finalTx)
158
- console.log(`File appended successfully! Transaction Hash: ${txHash}`);
159
- return { txHash, log: content }
160
- }
161
-
162
- export async function giveName(name: string, ckbfsId: string) {
163
- const ckbfsCell = await getCkbfsCellInfo(ckbfsId)
164
- const content = `GIVE_NAME,NEW_NAME:${name}\n`
165
-
166
- console.log("ckbfsCell=", ckbfsCell)
167
-
168
- const signer = ckbfs['signer']
169
- const address = await signer.getRecommendedAddress()
170
- console.log("address=", address)
171
- const addressHash = await getAddressScriptHash(address)
172
- console.log("addressHash=", addressHash)
173
- let tx = await ckbfs.createAppendContentTransaction(content, ckbfsCell, {
174
- witnessStartIndex: 1,
175
- });
176
- tx.addCellDeps(TestnetTraceLockDep)
177
- // console.log("tx=", JSON.stringify(JSON.parse(tx.stringify()), null, 2))
178
- const txHash = await signer.sendTransaction(tx)
179
- console.log(`File appended successfully! Transaction Hash: ${txHash}`);
180
- return { txHash, log: content }
181
- }
182
-
183
- // export async function transfer(to: string, ckbfsId: string) {
184
- // const ckbfsCell = await getCkbfsCellInfo(ckbfsId)
185
- // const from = await ckbfs.getAddress();
186
- // const fromHash = await getAddressScriptHash(from)
187
- // const toHash = await getAddressScriptHash(to)
188
- // const content = `TRANSFER,FROM:${fromHash},TO:${toHash}\n`
189
-
190
- // const signer = ckbfs['signer']
191
- // let tx = await ckbfs.createAppendContentTransaction(content, ckbfsCell);
192
- // tx.outputs[0].lock.args = toHash as `0x{string}`;
193
- // tx.addCellDeps(TestnetTraceLockDep)
194
- // const txHash = await signer.sendTransaction(tx)
195
- // console.log(`File appended successfully! Transaction Hash: ${txHash}`);
196
-
197
- // return { txHash, log: content };
198
- // }
199
-
200
- // export async function release(from: string, ckbfsId: string) {
201
- // const ckbfsCell = await await getCkbfsCellInfo(ckbfsId)
202
- // const fromHash = await getAddressScriptHash(from)
203
- // const content = `RELEASE,FROM:${fromHash}\n`
204
- // const signer = ckbfs['signer']
205
- // let tx = await ckbfs.createAppendContentTransaction(content, ckbfsCell);
206
-
207
- // tx.addCellDeps(TestnetTraceLockDep)
208
- // const txHash = await signer.sendTransaction(tx)
209
- // console.log(`File appended successfully! Transaction Hash: ${txHash}`);
210
- // return { txHash, log: content };
211
- // }
212
-
213
- // export async function retrieveLogsFromChain(ckbfsId: string) {
214
- // const { outPoint, data } = await getCkbfsCellInfo(ckbfsId)
215
- // const content = await getFileContentFromChain(client, outPoint, data)
216
- // const logs = content.toString().trim().split("\n")
217
- // return logs
218
- // }
219
-
220
- export async function getCkbfsCellInfo(ckbfsId: string) {
221
- const { codeHash, hashType } = getCKBFSScriptConfig(NetworkType.Testnet, ProtocolVersion.V3)
222
- console.log("codeHash, hashType=", codeHash, hashType, ckbfsId)
223
- const cell = await client.findSingletonCellByType({
224
- codeHash,
225
- hashType,
226
- args: ckbfsId
227
- }, true)
228
-
229
- if (!cell || !cell.cellOutput.type) {
230
- throw new Error('No CKBFS cell found');
231
- }
232
-
233
- const rawData = cell.outputData.startsWith('0x')
234
- ? Buffer.from(cell.outputData.slice(2), 'hex')
235
- : Buffer.from(cell.outputData, 'hex');
236
-
237
- const ckbfsData = CKBFSData.unpack(rawData, ProtocolVersion.V3)
238
-
239
- return {
240
- outPoint: { txHash: cell.outPoint.txHash as string, index: Number(cell.outPoint.index) },
241
- type: cell.cellOutput.type,
242
- lock: cell.cellOutput.lock,
243
- capacity: cell.cellOutput.capacity,
244
- data: ckbfsData,
245
- };
246
- }
247
-
248
-
249
- export function getCkbfsList() {
250
- const file = path.join(__dirname, `./data/${'testnet'}/ckbfs-list.json`)
251
- return JSON.parse(fs.readFileSync(file).toString())
252
- }
253
-
254
- export async function mintAll() {
255
- const ckbfsList = getCkbfsList()
256
- for(const { no } of ckbfsList) {
257
- const { txHash, ckbfsId } = await mint(no)
258
- console.log(`minted ckbfs no=${no}, ckbfsId=${ckbfsId}, txHash=${txHash}`);
259
-
260
- const interval = setInterval(async () => {
261
- try {
262
- const tx = await client.getTransaction(txHash)
263
- if (tx && tx.status === 'committed') {
264
- clearInterval(interval)
265
- console.info(`tx confirmed, https://explorer.nervos.org/transaction/${txHash}`);
266
- }
267
- } catch (error) {
268
- console.error(error)
269
- }
270
- }, 5 * 1000)
271
- }
272
- }
273
-
274
- async function getCellInfoFromV3Transaction(txHash: string): Promise<{
275
- outPoint: { txHash: string; index: number };
276
- type: Script;
277
- data: CKBFSDataType;
278
- lock: Script;
279
- capacity: bigint;
280
- previousTxHash: string;
281
- previousWitnessIndex: number;
282
- previousChecksum: number;
283
- }> {
284
- console.log(`Retrieving v3 transaction data for: ${txHash}`);
285
-
286
- try {
287
- // Get transaction from RPC
288
- const txWithStatus = await client.getTransaction(txHash);
289
- if (!txWithStatus || !txWithStatus.transaction) {
290
- throw new Error(`Transaction ${txHash} not found`);
291
- }
292
-
293
- const tx = Transaction.from(txWithStatus.transaction);
294
- console.log(`Transaction found with ${tx.outputs.length} outputs`);
295
-
296
- // Find the CKBFS cell output (first output with type script)
297
- let ckbfsCellIndex = 0;
298
- const output = tx.outputs[ckbfsCellIndex];
299
- if (!output || !output.type) {
300
- throw new Error('No CKBFS cell found in the transaction');
301
- }
302
-
303
- console.log(`Found CKBFS v3 cell at index ${ckbfsCellIndex}`);
304
- console.log(`Cell type script hash: ${output.type.hash()}`);
305
-
306
- // Get output data
307
- const outputData = tx.outputsData[ckbfsCellIndex];
308
- if (!outputData) {
309
- throw new Error('Output data not found');
310
- }
311
-
312
- // Parse the output data as CKBFS v3 data
313
- const rawData = outputData.startsWith('0x')
314
- ? ccc.bytesFrom(outputData.slice(2), 'hex')
315
- : Buffer.from(outputData, 'hex');
316
-
317
- // Unpack the raw data using v3 format
318
- const version = ProtocolVersion.V3;
319
- console.log(`Using protocol version ${version} for unpacking v3 cell data`);
320
-
321
- let ckbfsData: CKBFSDataType;
322
- try {
323
- ckbfsData = CKBFSData.unpack(rawData, version);
324
-
325
- console.log('Successfully unpacked CKBFS v3 cell data:');
326
- console.log(`- Checksum: ${ckbfsData.checksum}`);
327
- console.log(`- File: ${ckbfsData.filename}`);
328
- console.log(`- Content Type: ${ckbfsData.contentType}`);
329
- console.log(`- Index: ${ckbfsData.index}`);
330
- } catch (error) {
331
- console.error('Error unpacking CKBFS v3 data:', error);
332
- throw new Error(`Failed to unpack CKBFS v3 data: ${error}`);
333
- }
334
-
335
- // Extract backlink information from v3 witness
336
- let previousTxHash = '0x' + '00'.repeat(32);
337
- let previousWitnessIndex = 0;
338
- let previousChecksum = 0;
339
-
340
- if (ckbfsData.index !== undefined && ckbfsData.index < tx.witnesses.length) {
341
- const witnessHex = tx.witnesses[ckbfsData.index];
342
- const witness = Buffer.from(witnessHex.slice(2), 'hex');
343
-
344
- if (isCKBFSV3Witness(witness)) {
345
- try {
346
- const witnessData = extractCKBFSV3WitnessContent(witness, true);
347
- previousTxHash = witnessData.previousTxHash || previousTxHash;
348
- previousWitnessIndex = witnessData.previousWitnessIndex || 0;
349
- previousChecksum = witnessData.previousChecksum || 0;
350
-
351
- console.log('Extracted v3 backlink information:');
352
- console.log(`- Previous TX Hash: ${previousTxHash}`);
353
- console.log(`- Previous Witness Index: ${previousWitnessIndex}`);
354
- console.log(`- Previous Checksum: ${previousChecksum}`);
355
- } catch (error) {
356
- console.warn('Could not extract backlink info from witness:', error);
357
- }
358
- }
359
- }
360
-
361
- return {
362
- outPoint: {
363
- txHash,
364
- index: ckbfsCellIndex
365
- },
366
- type: output.type,
367
- lock: output.lock,
368
- capacity: output.capacity,
369
- data: ckbfsData,
370
- previousTxHash,
371
- previousWitnessIndex,
372
- previousChecksum
373
- };
374
- } catch (error) {
375
- console.error('Error retrieving v3 transaction data:', error);
376
- throw new Error(`Failed to retrieve or parse v3 cell data: ${error}`);
377
- }
378
- }
379
-
380
- async function testReresolve(ckbfsId: string) {
381
- const data = (await resolveCKBFSCell(client, ckbfsId, {network: NetworkType.Testnet}))!
382
- return data
383
- }
384
-
385
-
386
- // mintAll()
387
-
388
- //mint("X30125NMNVAP000201").then(console.log)
389
-
390
- //claim("ckt1qyq0zr47f0p8sm5d3cvtlpkljs7zvqcw7ngqnfscx0", "0xa3347c13f0419d9013a3f48a2b9ad993c2b6b5806827f3bf37480a58580d669d", "0x0084106b9bea08f512e35b725c4a710ebf09cb65c05601ebde8d911bc6c662bf")
391
-
392
- // getCkbfsCellInfo("0xdb0b0b637060d2f6c42c4429e712fa043c1937968c03c54a5014b4595f88413a").then((data) => {
393
- // console.log("ckbfs data=", data)
394
- // console.log("mintAll done");
395
- // })
396
-
397
- //giveName("bbb", "0x0084106b9bea08f512e35b725c4a710ebf09cb65c05601ebde8d911bc6c662bf").then(console.log)
398
-
399
- // getCkbfsCellInfo("0x52315569e5ff0d6d6392f047fcbea97bae1b32b688c29aca5251a157157278d3").then((data) => {
400
- // console.log("ckbfs data=", data)
401
- // })
402
-
403
-
404
- // getCellInfoFromV3Transaction("0x54c86dbdc6bdafb4616221d54cfc0ff186a4a772eba509838684f8e1ea271b40").then(console.log)
405
-
406
- //getCkbfsCellInfo("0xe58baa82c4844add60911bb890487fea3c45436b9d7b203cc1065301d0a9c503").then(console.log)
407
- giveName("bbb", "0xe58baa82c4844add60911bb890487fea3c45436b9d7b203cc1065301d0a9c503").then(console.log)
408
-
409
- // testReresolve("0x0084106b9bea08f512e35b725c4a710ebf09cb65c05601ebde8d911bc6c662bf").then(console.log)
@@ -1 +0,0 @@
1
- Hello CKBFS from direct content!
package/small-example.txt DELETED
@@ -1 +0,0 @@
1
- This is a small test file that should be published directly.
@@ -1 +0,0 @@
1
- Hello CKBFS from direct content!
@@ -1 +0,0 @@
1
- Hello CKBFS from direct content!