@ckbfs/api 1.5.0 → 2.0.0
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/README.md +31 -6
- package/RFC.v3.md +210 -0
- package/dist/index.d.ts +72 -7
- package/dist/index.js +440 -75
- package/dist/utils/checksum.d.ts +16 -0
- package/dist/utils/checksum.js +74 -8
- package/dist/utils/constants.d.ts +2 -1
- package/dist/utils/constants.js +12 -2
- package/dist/utils/file.d.ts +44 -0
- package/dist/utils/file.js +303 -30
- package/dist/utils/molecule.d.ts +13 -1
- package/dist/utils/molecule.js +32 -5
- package/dist/utils/transaction-backup.d.ts +117 -0
- package/dist/utils/transaction-backup.js +624 -0
- package/dist/utils/transaction.d.ts +7 -105
- package/dist/utils/transaction.js +45 -565
- package/dist/utils/transactions/index.d.ts +8 -0
- package/dist/utils/transactions/index.js +31 -0
- package/dist/utils/transactions/shared.d.ts +57 -0
- package/dist/utils/transactions/shared.js +17 -0
- package/dist/utils/transactions/v1v2.d.ts +80 -0
- package/dist/utils/transactions/v1v2.js +592 -0
- package/dist/utils/transactions/v3.d.ts +124 -0
- package/dist/utils/transactions/v3.js +369 -0
- package/dist/utils/witness.d.ts +45 -0
- package/dist/utils/witness.js +145 -3
- package/examples/append-v3.ts +310 -0
- package/examples/chunked-publish.ts +307 -0
- package/examples/publish-v3.ts +152 -0
- package/examples/publish.ts +4 -4
- package/examples/retrieve-v3.ts +222 -0
- package/package.json +6 -2
- package/small-example.txt +1 -0
- package/src/index.ts +568 -87
- package/src/utils/checksum.ts +90 -9
- package/src/utils/constants.ts +19 -2
- package/src/utils/file.ts +386 -35
- package/src/utils/molecule.ts +43 -6
- package/src/utils/transaction-backup.ts +849 -0
- package/src/utils/transaction.ts +39 -848
- package/src/utils/transactions/index.ts +16 -0
- package/src/utils/transactions/shared.ts +64 -0
- package/src/utils/transactions/v1v2.ts +791 -0
- package/src/utils/transactions/v3.ts +564 -0
- package/src/utils/witness.ts +193 -0
package/dist/utils/witness.js
CHANGED
|
@@ -4,11 +4,12 @@ exports.createCKBFSWitness = createCKBFSWitness;
|
|
|
4
4
|
exports.createTextCKBFSWitness = createTextCKBFSWitness;
|
|
5
5
|
exports.extractCKBFSWitnessContent = extractCKBFSWitnessContent;
|
|
6
6
|
exports.isCKBFSWitness = isCKBFSWitness;
|
|
7
|
+
exports.createCKBFSV3Witness = createCKBFSV3Witness;
|
|
8
|
+
exports.createChunkedCKBFSV3Witnesses = createChunkedCKBFSV3Witnesses;
|
|
9
|
+
exports.extractCKBFSV3WitnessContent = extractCKBFSV3WitnessContent;
|
|
10
|
+
exports.isCKBFSV3Witness = isCKBFSV3Witness;
|
|
7
11
|
exports.createChunkedCKBFSWitnesses = createChunkedCKBFSWitnesses;
|
|
8
12
|
const molecule_1 = require("./molecule");
|
|
9
|
-
/**
|
|
10
|
-
* Utility functions for creating and handling CKBFS witnesses
|
|
11
|
-
*/
|
|
12
13
|
/**
|
|
13
14
|
* Creates a CKBFS witness with content
|
|
14
15
|
* @param content The content to include in the witness
|
|
@@ -62,6 +63,147 @@ function isCKBFSWitness(witness) {
|
|
|
62
63
|
const headerString = new TextDecoder().decode(header);
|
|
63
64
|
return headerString === 'CKBFS';
|
|
64
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Creates a CKBFS v3 witness with structured format
|
|
68
|
+
* @param options Witness options including backlink data and content
|
|
69
|
+
* @returns Uint8Array containing the v3 witness data
|
|
70
|
+
*/
|
|
71
|
+
function createCKBFSV3Witness(options) {
|
|
72
|
+
const { previousTxHash = '0x' + '00'.repeat(32), previousWitnessIndex = 0, previousChecksum = 0, nextIndex = 0, content } = options;
|
|
73
|
+
// Create witness components
|
|
74
|
+
const header = molecule_1.CKBFS_HEADER; // "CKBFS" (5 bytes)
|
|
75
|
+
const version = new Uint8Array([0x03]); // Version 3 (1 byte)
|
|
76
|
+
// Previous position: txHash (32 bytes) + witnessIndex (4 bytes)
|
|
77
|
+
const prevTxHashBytes = new Uint8Array(32);
|
|
78
|
+
if (previousTxHash !== '0x' + '00'.repeat(32)) {
|
|
79
|
+
const hexStr = previousTxHash.startsWith('0x') ? previousTxHash.slice(2) : previousTxHash;
|
|
80
|
+
for (let i = 0; i < 32; i++) {
|
|
81
|
+
prevTxHashBytes[i] = parseInt(hexStr.substr(i * 2, 2), 16);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const prevWitnessIndexBytes = new Uint8Array(4);
|
|
85
|
+
new DataView(prevWitnessIndexBytes.buffer).setUint32(0, previousWitnessIndex, true); // little-endian
|
|
86
|
+
// Previous checksum (4 bytes)
|
|
87
|
+
const prevChecksumBytes = new Uint8Array(4);
|
|
88
|
+
new DataView(prevChecksumBytes.buffer).setUint32(0, previousChecksum, true); // little-endian
|
|
89
|
+
// Next index (4 bytes)
|
|
90
|
+
const nextIndexBytes = new Uint8Array(4);
|
|
91
|
+
new DataView(nextIndexBytes.buffer).setUint32(0, nextIndex, true); // little-endian
|
|
92
|
+
// Combine all parts
|
|
93
|
+
return Buffer.concat([
|
|
94
|
+
header, // 5 bytes: "CKBFS"
|
|
95
|
+
version, // 1 byte: 0x03
|
|
96
|
+
prevTxHashBytes, // 32 bytes: previous tx hash
|
|
97
|
+
prevWitnessIndexBytes, // 4 bytes: previous witness index
|
|
98
|
+
prevChecksumBytes, // 4 bytes: previous checksum
|
|
99
|
+
nextIndexBytes, // 4 bytes: next index
|
|
100
|
+
content // variable: content bytes
|
|
101
|
+
]);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Creates an array of v3 witnesses for chunked content
|
|
105
|
+
* @param contentChunks Array of content chunks
|
|
106
|
+
* @param options Backlink options for head witness and start index
|
|
107
|
+
* @returns Array of Uint8Array witnesses
|
|
108
|
+
*/
|
|
109
|
+
function createChunkedCKBFSV3Witnesses(contentChunks, options = {}) {
|
|
110
|
+
if (contentChunks.length === 0) {
|
|
111
|
+
return [];
|
|
112
|
+
}
|
|
113
|
+
// Default start index to 1 if not provided (witness 0 is typically for signing)
|
|
114
|
+
const startIndex = options.startIndex || 1;
|
|
115
|
+
const witnesses = [];
|
|
116
|
+
for (let i = 0; i < contentChunks.length; i++) {
|
|
117
|
+
const isHead = i === 0;
|
|
118
|
+
const isTail = i === contentChunks.length - 1;
|
|
119
|
+
if (isHead) {
|
|
120
|
+
// Head witness with backlink info
|
|
121
|
+
witnesses.push(createCKBFSV3Witness({
|
|
122
|
+
...options,
|
|
123
|
+
nextIndex: isTail ? 0 : startIndex + i + 1, // Correct next witness index calculation
|
|
124
|
+
content: contentChunks[i]
|
|
125
|
+
}));
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
// Middle/tail witness with minimal header
|
|
129
|
+
const nextIndex = isTail ? 0 : startIndex + i + 1;
|
|
130
|
+
const nextIndexBytes = new Uint8Array(4);
|
|
131
|
+
new DataView(nextIndexBytes.buffer).setUint32(0, nextIndex, true);
|
|
132
|
+
witnesses.push(Buffer.concat([
|
|
133
|
+
nextIndexBytes, // 4 bytes: next index
|
|
134
|
+
contentChunks[i] // variable: content bytes
|
|
135
|
+
]));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return witnesses;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Extracts content from a CKBFS v3 witness
|
|
142
|
+
* @param witness The CKBFS v3 witness data
|
|
143
|
+
* @param isHeadWitness Whether this is the head witness or a continuation witness
|
|
144
|
+
* @returns Object containing the extracted data
|
|
145
|
+
*/
|
|
146
|
+
function extractCKBFSV3WitnessContent(witness, isHeadWitness = true) {
|
|
147
|
+
if (isHeadWitness) {
|
|
148
|
+
// Head witness format: CKBFS(5) + version(1) + prevTxHash(32) + prevWitnessIndex(4) + prevChecksum(4) + nextIndex(4) + content
|
|
149
|
+
if (witness.length < 50) {
|
|
150
|
+
throw new Error('Invalid CKBFS v3 head witness: too short');
|
|
151
|
+
}
|
|
152
|
+
const header = witness.slice(0, 5);
|
|
153
|
+
const headerString = new TextDecoder().decode(header);
|
|
154
|
+
if (headerString !== 'CKBFS') {
|
|
155
|
+
throw new Error('Invalid CKBFS v3 head witness: missing CKBFS header');
|
|
156
|
+
}
|
|
157
|
+
const version = witness[5];
|
|
158
|
+
if (version !== 0x03) {
|
|
159
|
+
throw new Error(`Invalid CKBFS v3 head witness: expected version 0x03, got 0x${version.toString(16)}`);
|
|
160
|
+
}
|
|
161
|
+
// Extract previous position
|
|
162
|
+
const prevTxHashBytes = witness.slice(6, 38);
|
|
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);
|
|
167
|
+
const content = witness.slice(50);
|
|
168
|
+
return {
|
|
169
|
+
version,
|
|
170
|
+
previousTxHash,
|
|
171
|
+
previousWitnessIndex,
|
|
172
|
+
previousChecksum,
|
|
173
|
+
nextIndex,
|
|
174
|
+
content
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
// Continuation witness format: nextIndex(4) + content
|
|
179
|
+
if (witness.length < 4) {
|
|
180
|
+
throw new Error('Invalid CKBFS v3 continuation witness: too short');
|
|
181
|
+
}
|
|
182
|
+
const nextIndex = new DataView(witness.slice(0, 4).buffer).getUint32(0, true);
|
|
183
|
+
const content = witness.slice(4);
|
|
184
|
+
return {
|
|
185
|
+
nextIndex,
|
|
186
|
+
content
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Checks if a witness is a valid CKBFS v3 witness
|
|
192
|
+
* @param witness The witness data to check
|
|
193
|
+
* @returns Boolean indicating whether the witness is a valid CKBFS v3 witness
|
|
194
|
+
*/
|
|
195
|
+
function isCKBFSV3Witness(witness) {
|
|
196
|
+
if (witness.length < 50) {
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
const header = witness.slice(0, 5);
|
|
200
|
+
const headerString = new TextDecoder().decode(header);
|
|
201
|
+
if (headerString !== 'CKBFS') {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
const version = witness[5];
|
|
205
|
+
return version === 0x03;
|
|
206
|
+
}
|
|
65
207
|
/**
|
|
66
208
|
* Creates an array of witnesses for a CKBFS transaction from content chunks
|
|
67
209
|
* @param contentChunks Array of content chunks
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import { CKBFS, NetworkType, ProtocolVersion, CKBFSDataType, extractCKBFSV3WitnessContent, isCKBFSV3Witness, CKBFSData } from '../src/index';
|
|
2
|
+
import { Script, ClientPublicTestnet, Transaction, ccc } from "@ckb-ccc/core";
|
|
3
|
+
|
|
4
|
+
// Replace with your actual private key
|
|
5
|
+
const privateKey = process.env.CKB_PRIVATE_KEY || 'your-private-key-here';
|
|
6
|
+
|
|
7
|
+
// Parse command line arguments for transaction hash
|
|
8
|
+
const txHashArg = process.argv.find(arg => arg.startsWith('--txhash='));
|
|
9
|
+
const publishTxHash = txHashArg ? txHashArg.split('=')[1] : process.env.PUBLISH_TX_HASH || '0x0000000000000000000000000000000000000000000000000000000000000000';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Ensures a string is prefixed with '0x'
|
|
13
|
+
* @param value The string to ensure is hex prefixed
|
|
14
|
+
* @returns A hex prefixed string
|
|
15
|
+
*/
|
|
16
|
+
function ensureHexPrefix(value: string): `0x${string}` {
|
|
17
|
+
if (value.startsWith('0x')) {
|
|
18
|
+
return value as `0x${string}`;
|
|
19
|
+
}
|
|
20
|
+
return `0x${value}` as `0x${string}`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Initialize the SDK for CKBFS v3
|
|
24
|
+
const ckbfs = new CKBFS(
|
|
25
|
+
privateKey,
|
|
26
|
+
NetworkType.Testnet, // Use testnet
|
|
27
|
+
{
|
|
28
|
+
version: ProtocolVersion.V3, // Use v3
|
|
29
|
+
chunkSize: 20 * 1024, // 20KB chunks
|
|
30
|
+
useTypeID: false, // Use code hash instead of type ID
|
|
31
|
+
}
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
// Initialize CKB client for testnet
|
|
35
|
+
const client = new ClientPublicTestnet();
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Get cell information from a v3 transaction using CKB client
|
|
39
|
+
* @param txHash The transaction hash to get cell information from
|
|
40
|
+
* @returns Promise resolving to the cell information including v3 backlink data
|
|
41
|
+
*/
|
|
42
|
+
async function getCellInfoFromV3Transaction(txHash: string): Promise<{
|
|
43
|
+
outPoint: { txHash: string; index: number };
|
|
44
|
+
type: Script;
|
|
45
|
+
data: CKBFSDataType;
|
|
46
|
+
lock: Script;
|
|
47
|
+
capacity: bigint;
|
|
48
|
+
previousTxHash: string;
|
|
49
|
+
previousWitnessIndex: number;
|
|
50
|
+
previousChecksum: number;
|
|
51
|
+
}> {
|
|
52
|
+
console.log(`Retrieving v3 transaction data for: ${txHash}`);
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
// Get transaction from RPC
|
|
56
|
+
const txWithStatus = await client.getTransaction(txHash);
|
|
57
|
+
if (!txWithStatus || !txWithStatus.transaction) {
|
|
58
|
+
throw new Error(`Transaction ${txHash} not found`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const tx = Transaction.from(txWithStatus.transaction);
|
|
62
|
+
console.log(`Transaction found with ${tx.outputs.length} outputs`);
|
|
63
|
+
|
|
64
|
+
// Find the CKBFS cell output (first output with type script)
|
|
65
|
+
let ckbfsCellIndex = 0;
|
|
66
|
+
const output = tx.outputs[ckbfsCellIndex];
|
|
67
|
+
if (!output || !output.type) {
|
|
68
|
+
throw new Error('No CKBFS cell found in the transaction');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
console.log(`Found CKBFS v3 cell at index ${ckbfsCellIndex}`);
|
|
72
|
+
console.log(`Cell type script hash: ${output.type.hash()}`);
|
|
73
|
+
|
|
74
|
+
// Get output data
|
|
75
|
+
const outputData = tx.outputsData[ckbfsCellIndex];
|
|
76
|
+
if (!outputData) {
|
|
77
|
+
throw new Error('Output data not found');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Parse the output data as CKBFS v3 data
|
|
81
|
+
const rawData = outputData.startsWith('0x')
|
|
82
|
+
? ccc.bytesFrom(outputData.slice(2), 'hex')
|
|
83
|
+
: Buffer.from(outputData, 'hex');
|
|
84
|
+
|
|
85
|
+
// Unpack the raw data using v3 format
|
|
86
|
+
const version = ProtocolVersion.V3;
|
|
87
|
+
console.log(`Using protocol version ${version} for unpacking v3 cell data`);
|
|
88
|
+
|
|
89
|
+
let ckbfsData: CKBFSDataType;
|
|
90
|
+
try {
|
|
91
|
+
ckbfsData = CKBFSData.unpack(rawData, version);
|
|
92
|
+
|
|
93
|
+
console.log('Successfully unpacked CKBFS v3 cell data:');
|
|
94
|
+
console.log(`- Checksum: ${ckbfsData.checksum}`);
|
|
95
|
+
console.log(`- File: ${ckbfsData.filename}`);
|
|
96
|
+
console.log(`- Content Type: ${ckbfsData.contentType}`);
|
|
97
|
+
console.log(`- Index: ${ckbfsData.index}`);
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.error('Error unpacking CKBFS v3 data:', error);
|
|
100
|
+
throw new Error(`Failed to unpack CKBFS v3 data: ${error}`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Extract backlink information from v3 witness
|
|
104
|
+
let previousTxHash = '0x' + '00'.repeat(32);
|
|
105
|
+
let previousWitnessIndex = 0;
|
|
106
|
+
let previousChecksum = 0;
|
|
107
|
+
|
|
108
|
+
if (ckbfsData.index !== undefined && ckbfsData.index < tx.witnesses.length) {
|
|
109
|
+
const witnessHex = tx.witnesses[ckbfsData.index];
|
|
110
|
+
const witness = Buffer.from(witnessHex.slice(2), 'hex');
|
|
111
|
+
|
|
112
|
+
if (isCKBFSV3Witness(witness)) {
|
|
113
|
+
try {
|
|
114
|
+
const witnessData = extractCKBFSV3WitnessContent(witness, true);
|
|
115
|
+
previousTxHash = witnessData.previousTxHash || previousTxHash;
|
|
116
|
+
previousWitnessIndex = witnessData.previousWitnessIndex || 0;
|
|
117
|
+
previousChecksum = witnessData.previousChecksum || 0;
|
|
118
|
+
|
|
119
|
+
console.log('Extracted v3 backlink information:');
|
|
120
|
+
console.log(`- Previous TX Hash: ${previousTxHash}`);
|
|
121
|
+
console.log(`- Previous Witness Index: ${previousWitnessIndex}`);
|
|
122
|
+
console.log(`- Previous Checksum: ${previousChecksum}`);
|
|
123
|
+
} catch (error) {
|
|
124
|
+
console.warn('Could not extract backlink info from witness:', error);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
outPoint: {
|
|
131
|
+
txHash,
|
|
132
|
+
index: ckbfsCellIndex
|
|
133
|
+
},
|
|
134
|
+
type: output.type,
|
|
135
|
+
lock: output.lock,
|
|
136
|
+
capacity: output.capacity,
|
|
137
|
+
data: ckbfsData,
|
|
138
|
+
previousTxHash,
|
|
139
|
+
previousWitnessIndex,
|
|
140
|
+
previousChecksum
|
|
141
|
+
};
|
|
142
|
+
} catch (error) {
|
|
143
|
+
console.error('Error retrieving v3 transaction data:', error);
|
|
144
|
+
throw new Error(`Failed to retrieve or parse v3 cell data: ${error}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Example of appending content to an existing CKBFS v3 file
|
|
150
|
+
*/
|
|
151
|
+
async function appendContentV3Example() {
|
|
152
|
+
try {
|
|
153
|
+
// Validate transaction hash
|
|
154
|
+
if (publishTxHash === '0x0000000000000000000000000000000000000000000000000000000000000000') {
|
|
155
|
+
throw new Error('Please provide a valid transaction hash by setting the PUBLISH_TX_HASH environment variable or using --txhash=0x... argument');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Get address info
|
|
159
|
+
const address = await ckbfs.getAddress();
|
|
160
|
+
console.log(`Using address: ${address.toString()}`);
|
|
161
|
+
|
|
162
|
+
// Get the cell information from the v3 transaction
|
|
163
|
+
console.log(`Getting v3 cell info from transaction: ${publishTxHash}`);
|
|
164
|
+
const cellInfo = await getCellInfoFromV3Transaction(publishTxHash);
|
|
165
|
+
|
|
166
|
+
// Create the CKBFS v3 cell structure
|
|
167
|
+
const ckbfsCell = {
|
|
168
|
+
outPoint: cellInfo.outPoint,
|
|
169
|
+
data: cellInfo.data,
|
|
170
|
+
type: cellInfo.type,
|
|
171
|
+
lock: cellInfo.lock,
|
|
172
|
+
capacity: cellInfo.capacity
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
// Content to append
|
|
176
|
+
const contentToAppend = "\n\nThis content was appended using CKBFS v3!";
|
|
177
|
+
console.log(`Appending content to CKBFS v3 file: "${contentToAppend}"`);
|
|
178
|
+
|
|
179
|
+
console.log('Note: CKBFS v3 append requires backlink information from the previous transaction.');
|
|
180
|
+
console.log('The SDK will create witnesses with structured backlinks.');
|
|
181
|
+
console.log('Make sure your account has enough CKB to cover the fees.');
|
|
182
|
+
|
|
183
|
+
const txHash = await ckbfs.appendContentV3(
|
|
184
|
+
contentToAppend,
|
|
185
|
+
ckbfsCell,
|
|
186
|
+
publishTxHash,
|
|
187
|
+
cellInfo.data.index!,
|
|
188
|
+
cellInfo.data.checksum!,
|
|
189
|
+
{
|
|
190
|
+
feeRate: 2000,
|
|
191
|
+
}
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
console.log(`Content appended successfully to CKBFS v3!`);
|
|
195
|
+
console.log(`Transaction Hash: ${txHash}`);
|
|
196
|
+
console.log(`View at: https://pudge.explorer.nervos.org/transaction/${txHash}`);
|
|
197
|
+
|
|
198
|
+
return txHash;
|
|
199
|
+
} catch (error) {
|
|
200
|
+
console.error('Error appending content to v3:', error);
|
|
201
|
+
throw error;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Example of transferring ownership of a CKBFS v3 file
|
|
207
|
+
*/
|
|
208
|
+
async function transferFileV3Example() {
|
|
209
|
+
try {
|
|
210
|
+
// Example CKBFS v3 cell (you need to replace with actual values)
|
|
211
|
+
const ckbfsCell = {
|
|
212
|
+
outPoint: {
|
|
213
|
+
txHash: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
|
|
214
|
+
index: 0
|
|
215
|
+
},
|
|
216
|
+
data: {
|
|
217
|
+
index: 1,
|
|
218
|
+
checksum: 12345678,
|
|
219
|
+
contentType: "text/plain",
|
|
220
|
+
filename: "v3-example.txt"
|
|
221
|
+
},
|
|
222
|
+
type: Script.from({
|
|
223
|
+
codeHash: "0x25a6d8a4017d675e457b76e9228bfc3942ddbf8227f8624db4fcf315e49a6b07",
|
|
224
|
+
hashType: "data1",
|
|
225
|
+
args: "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
|
|
226
|
+
}),
|
|
227
|
+
lock: Script.from({
|
|
228
|
+
codeHash: "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8",
|
|
229
|
+
hashType: "type",
|
|
230
|
+
args: "0x1234567890abcdef1234567890abcdef12345678"
|
|
231
|
+
}),
|
|
232
|
+
capacity: 200n * 100000000n
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
// New lock script for the transferred file
|
|
236
|
+
const newLock = Script.from({
|
|
237
|
+
codeHash: "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8",
|
|
238
|
+
hashType: "type",
|
|
239
|
+
args: "0xfedcba0987654321fedcba0987654321fedcba09" // New owner's lock args
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
// V3 backlink information (from previous transaction)
|
|
243
|
+
const previousTxHash = "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890";
|
|
244
|
+
const previousWitnessIndex = 1;
|
|
245
|
+
const previousChecksum = 12345678; // Same checksum (transfer doesn't change content)
|
|
246
|
+
|
|
247
|
+
console.log(`Transferring CKBFS v3 file ownership...`);
|
|
248
|
+
|
|
249
|
+
const txHash = await ckbfs.transferFileV3(
|
|
250
|
+
ckbfsCell,
|
|
251
|
+
newLock,
|
|
252
|
+
previousTxHash,
|
|
253
|
+
previousWitnessIndex,
|
|
254
|
+
previousChecksum,
|
|
255
|
+
{
|
|
256
|
+
feeRate: 2000,
|
|
257
|
+
}
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
console.log(`File ownership transferred successfully in CKBFS v3!`);
|
|
261
|
+
console.log(`Transaction Hash: ${txHash}`);
|
|
262
|
+
console.log(`View at: https://pudge.explorer.nervos.org/transaction/${txHash}`);
|
|
263
|
+
|
|
264
|
+
return txHash;
|
|
265
|
+
} catch (error) {
|
|
266
|
+
console.error('Error transferring v3 file:', error);
|
|
267
|
+
throw error;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Main function to run the v3 append/transfer example
|
|
273
|
+
*/
|
|
274
|
+
async function main() {
|
|
275
|
+
console.log('Running CKBFS v3 append/transfer example...');
|
|
276
|
+
console.log('==========================================');
|
|
277
|
+
console.log(`Using CKBFS protocol version: ${ProtocolVersion.V3}`);
|
|
278
|
+
console.log('Key v3 operations:');
|
|
279
|
+
console.log('- Append: Add content with backlink chain');
|
|
280
|
+
console.log('- Transfer: Change ownership with backlink');
|
|
281
|
+
console.log('- Backlinks stored in witnesses, not cell data');
|
|
282
|
+
console.log('==========================================');
|
|
283
|
+
|
|
284
|
+
try {
|
|
285
|
+
console.log('Note: This example requires an existing CKBFS v3 cell.');
|
|
286
|
+
console.log('Please run publish-v3.ts first to create a v3 file,');
|
|
287
|
+
console.log('then update the cell details in this example.');
|
|
288
|
+
console.log('');
|
|
289
|
+
console.log('Uncomment the desired operation below:');
|
|
290
|
+
console.log('');
|
|
291
|
+
|
|
292
|
+
// Uncomment to test append:
|
|
293
|
+
await appendContentV3Example();
|
|
294
|
+
|
|
295
|
+
// Uncomment to test transfer:
|
|
296
|
+
// await transferFileV3Example();
|
|
297
|
+
|
|
298
|
+
console.log('Example structure completed successfully!');
|
|
299
|
+
console.log('Update the cell details and uncomment operations to test.');
|
|
300
|
+
process.exit(0);
|
|
301
|
+
} catch (error) {
|
|
302
|
+
console.error('CKBFS v3 append/transfer example failed:', error);
|
|
303
|
+
process.exit(1);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Run the example if this file is executed directly
|
|
308
|
+
if (require.main === module) {
|
|
309
|
+
main().catch(console.error);
|
|
310
|
+
}
|