calldatauploader-sdk 0.0.0-stage → 5.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 CHANGED
@@ -1,3 +1,208 @@
1
- # Temporary Holding Version
1
+ # calldatauploader-sdk
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ This SDK aims to standardize the interaction between applications and the EthStorage network to achieve reliable and
4
+ efficient data management functionality.
5
+
6
+ This SDK provides the `FlatDirectory` class, a higher-level data management tool that provides methods for uploading
7
+ and downloading data of arbitrary size. Uploads are performed by sending the data through calldata.
8
+
9
+ Click here to view [spec](./spec.md).
10
+
11
+ # Installation
12
+
13
+ Install the SDK using [npm](https://www.npmjs.com/package/calldatauploader-sdk):
14
+
15
+ ```bash
16
+ $ npm install calldatauploader-sdk
17
+ ```
18
+
19
+ # Example Usage
20
+
21
+ ## FlatDirectory
22
+
23
+ ### create
24
+
25
+ Create a `FlatDirectory` instance.
26
+
27
+ ```js
28
+ const { FlatDirectory } = require("calldatauploader-sdk");
29
+
30
+ const rpc = "https://rpc.beta.testnet.l2.quarkchain.io:8545";
31
+ const ethStorageRpc = "https://rpc.beta.testnet.l2.ethstorage.io:9596";
32
+ const privateKey = "0xabcd...";
33
+
34
+ const flatDirectory = await FlatDirectory.create({
35
+ rpc: rpc,
36
+ ethStorageRpc: ethStorageRpc,
37
+ privateKey: privateKey,
38
+ });
39
+ ```
40
+
41
+ If `FlatDirectory` has been deployed, it can be set through the `address` field.
42
+
43
+ ```js
44
+ const address = "0x987..."; // FlatDirectory address
45
+ const flatDirectory = await FlatDirectory.create({
46
+ rpc: rpc,
47
+ ethStorageRpc: ethStorageRpc,
48
+ privateKey: privateKey,
49
+ address: address,
50
+ });
51
+ ```
52
+
53
+ If you only need the `download` function, you can create a `FlatDirectory` using the following pattern.
54
+
55
+ ```js
56
+ const address = "0x987..."; // FlatDirectory address
57
+ const flatDirectory = await FlatDirectory.create({
58
+ ethStorageRpc: 'https://rpc.beta.testnet.l2.ethstorage.io:9596',
59
+ address: address
60
+ });
61
+ ```
62
+
63
+ ### deploy
64
+
65
+ Deploy the implementation
66
+ contract [FlatDirectory](https://github.com/ethstorage/evm-large-storage)
67
+ for [EIP-5018](https://eips.ethereum.org/EIPS/eip-5018) standard.
68
+
69
+ ```js
70
+ const contractAddress = await flatDirectory.deploy();
71
+ console.log(`FlatDirectory address is ${contractAddress}.`);
72
+ ```
73
+
74
+ ### upload
75
+
76
+ Upload `buffer | file` to the FlatDirectory. The content is sliced into chunks and each chunk is sent through calldata.
77
+
78
+ ```js
79
+ const callback = {
80
+ onProgress: function (progress, count, isChange) {
81
+ console.log(`Uploaded ${progress} of ${count} chunks`);
82
+ },
83
+ onFail: function (err) {
84
+ console.log(err);
85
+ },
86
+ onFinish: function (totalUploadChunks, totalUploadSize, totalCost) {
87
+ console.log(`Total upload chunk count is ${totalUploadChunks}, size is ${totalUploadSize}, total cost is ${totalCost}`);
88
+ }
89
+ };
90
+
91
+ const request = {
92
+ key: "test.txt",
93
+ content: Buffer.from("big data"),
94
+ callback: callback
95
+ }
96
+ await flatDirectory.upload(request);
97
+ ```
98
+
99
+ If you want to use `file`, it can be divided into browser and Node.js.
100
+
101
+ Browser
102
+ ```javascript
103
+ // <input id='fileToUpload' />
104
+ const file = document.getElementById('fileToUpload').files[0];
105
+
106
+ const request = {
107
+ key: "test.txt",
108
+ content: file,
109
+ callback: callback
110
+ }
111
+ await flatDirectory.upload(request);
112
+ ```
113
+
114
+ Node.js
115
+ ```javascript
116
+ const {NodeFile} = require("calldatauploader-sdk/file");
117
+ const file = new NodeFile("/usr/download/test.jpg");
118
+
119
+ const request = {
120
+ key: "test.txt",
121
+ content: file,
122
+ callback: callback
123
+ }
124
+ await flatDirectory.upload(request);
125
+ ```
126
+
127
+ ### download
128
+
129
+ Monitor the download progress by passing in a callback function.
130
+
131
+ ```js
132
+ const key = "test.txt";
133
+ await flatDirectory.download(key, {
134
+ onProgress: function (progress, count, chunk) {
135
+ console.log(`Download ${progress} of ${count} chunks, this chunk is ${Buffer.from(chunk).toString()}`);
136
+ },
137
+ onFail: function (error) {
138
+ console.error("Error download data:", error);
139
+ },
140
+ onFinish: function () {
141
+ console.log("Download success.");
142
+ }
143
+ });
144
+ ```
145
+
146
+ ### estimateCost
147
+
148
+ Estimate gas costs before uploading.
149
+
150
+ ```js
151
+ const request = {
152
+ key: "example1.txt",
153
+ content: Buffer.from("large data to upload")
154
+ }
155
+
156
+ const cost = await flatDirectory.estimateCost(request);
157
+ console.log(`Gas Cost: ${cost.gasCost}, Storage Cost: ${cost.storageCost}`);
158
+ ```
159
+
160
+ Use `file`.
161
+
162
+ Browser
163
+ ```javascript
164
+ // <input id='fileToUpload' />
165
+ const file = document.getElementById('fileToUpload').files[0];
166
+
167
+ const request = {
168
+ key: "example1.txt",
169
+ content: file
170
+ }
171
+ const cost = await flatDirectory.estimateCost(request);
172
+ console.log(`Gas Cost: ${cost.gasCost}, Storage Cost: ${cost.storageCost}`);
173
+ ```
174
+
175
+ Node.js
176
+ ```javascript
177
+ const {NodeFile} = require("calldatauploader-sdk/file");
178
+ const file = new NodeFile("/usr/download/test.jpg");
179
+
180
+ const request = {
181
+ key: "example1.txt",
182
+ content: file
183
+ }
184
+ const cost = await flatDirectory.estimateCost(request);
185
+ ```
186
+
187
+
188
+ ### Chunk options
189
+
190
+ Uploads are sliced into calldata chunks. Both `estimateCost` and `upload`
191
+ requests accept two optional fields:
192
+
193
+ | Field | Type | Default | Description |
194
+ |----------------|--------|---------|----------------------------------------------------------|
195
+ | `maxChunkSize` | number | `64` | data size of each chunk, in KB |
196
+ | `maxChunks` | number | `100` | maximum number of chunks requested in a single call |
197
+
198
+ ```js
199
+ const request = {
200
+ key: "example1.txt",
201
+ content: Buffer.from("large data to upload"),
202
+ maxChunkSize: 32, // 32 KB per chunk
203
+ maxChunks: 120 // at most 120 chunks per request
204
+ }
205
+ await flatDirectory.upload({ ...request, callback });
206
+ ```
207
+
208
+ `fetchHashes(keys, maxChunks)` accepts the same chunk limit as its second argument.
package/package.json CHANGED
@@ -1,6 +1,62 @@
1
- {
2
- "name": "calldatauploader-sdk",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
1
+ {
2
+ "name": "calldatauploader-sdk",
3
+ "version": "5.0.0",
4
+ "description": "EthStorage flat directory upload sdk (calldata only)",
5
+ "main": "./dist/node/index.cjs",
6
+ "types": "./dist/node/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "browser": "./dist/browser/index.mjs",
10
+ "node": {
11
+ "import": "./dist/node/index.mjs",
12
+ "require": "./dist/node/index.cjs"
13
+ },
14
+ "types": "./dist/node/index.d.ts",
15
+ "default": "./dist/node/index.mjs"
16
+ },
17
+ "./file": {
18
+ "node": {
19
+ "import": "./dist/node/file.mjs",
20
+ "require": "./dist/node/file.cjs"
21
+ },
22
+ "types": "./dist/node/file.d.ts"
23
+ }
24
+ },
25
+ "scripts": {
26
+ "build": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && tsup",
27
+ "dev": "tsup --watch --env.NODE_ENV development",
28
+ "prepublishOnly": "npm run build"
29
+ },
30
+ "dependencies": {
31
+ "dotenv": "^16.4.5",
32
+ "ethers": "^6.17.0",
33
+ "p-limit": "^7.2.0"
34
+ },
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "git+https://github.com/0xCampanula/calldatauploader-sdk.git"
38
+ },
39
+ "bugs": {
40
+ "url": "https://github.com/0xCampanula/calldatauploader-sdk/issues"
41
+ },
42
+ "homepage": "https://github.com/0xCampanula/calldatauploader-sdk/main/",
43
+ "keywords": [
44
+ "File",
45
+ "Upload"
46
+ ],
47
+ "author": "ethsorage",
48
+ "license": "ISC",
49
+ "devDependencies": {
50
+ "tsup": "^8.5.1",
51
+ "typescript": "^5.9.3"
52
+ },
53
+ "resolutions": {
54
+ "strip-ansi": "7.1.0",
55
+ "color-convert": "2.0.1",
56
+ "color-name": "1.1.4"
57
+ },
58
+ "overrides": {
59
+ "rollup": ">=4.59.0",
60
+ "picomatch": ">=4.0.4"
61
+ }
62
+ }
package/spec.md ADDED
@@ -0,0 +1,325 @@
1
+ # EthStorage SDK Interface Specification
2
+
3
+ # Table of Contents
4
+
5
+ - [1. Introduction](#Introduction)
6
+ - [2. Class Overview](#Class_Overview)
7
+ - [3. FlatDirectory Class](#FlatDirectory)
8
+ - Static Methods
9
+ - create
10
+ - Methods
11
+ - deploy
12
+ - estimateCost
13
+ - upload
14
+ - download
15
+ - fetchHashes
16
+ - setDefault
17
+ - remove
18
+ - [4. Version History](#Version)
19
+
20
+ ---
21
+
22
+ <p id="Introduction"></p>
23
+
24
+ # 1. Introduction
25
+
26
+ This SDK aims to standardize the interaction between applications and the EthStorage network to achieve reliable and
27
+ efficient data management functionality.
28
+
29
+ This SDK includes the `FlatDirectory` class, a higher-level data management tool that provides methods for uploading
30
+ and downloading data of arbitrary size. Uploading is performed by sending the data through calldata in fixed-size
31
+ chunks, and each chunk is written to the FlatDirectory contract with `writeChunkByCalldata`.
32
+
33
+ <p id="Class_Overview"></p>
34
+
35
+ # 2. Class Overview
36
+
37
+ ## FlatDirectory Class
38
+
39
+ | Method Name | Description |
40
+ |--------------|----------------------------------------------------------------|
41
+ | create | Create an instance of FlatDirectory |
42
+ | deploy | Deploy a FlatDirectory contract |
43
+ | estimateCost | Estimate the cost of uploading data (gas cost) |
44
+ | upload | Asynchronously upload data of arbitrary size via calldata |
45
+ | download | Asynchronously download data |
46
+ | fetchHashes | Get chunk hashes of data in batches |
47
+ | setDefault | Set the default file for FlatDirectory |
48
+ | remove | Remove a file from the FlatDirectory contract |
49
+
50
+ <p id="FlatDirectory"></p>
51
+
52
+ # 3. FlatDirectory Class
53
+
54
+ ## Static Methods
55
+
56
+ ### create
57
+
58
+ **Description**: Create an instance of `FlatDirectory`.
59
+
60
+ **Parameters**
61
+ - `config` (object): Configuration object containing necessary settings.
62
+ - `rpc` (string, optional): RPC for any evm network. Required for operations that send transactions.
63
+ - `ethStorageRpc` (string, optional): The EthStorage network rpc corresponding to this evm network, the data is obtained from
64
+ the EthStorage network.
65
+ - `privateKey` (string, optional): Wallet private key. Required for operations that send transactions.
66
+ - `address` (string, optional): FlatDirectory contract address. If it does not exist, the `deploy` method can be
67
+ called to create one.
68
+
69
+ **Example**
70
+ ```javascript
71
+ const config = {
72
+ rpc: "your_rpc",
73
+ ethStorageRpc: "ethstorage_rpc",
74
+ privateKey: "your_private_key",
75
+ address: "flat_directory_address"
76
+ };
77
+
78
+ const flatDirectory = await FlatDirectory.create(config);
79
+ ```
80
+
81
+ ## Methods
82
+
83
+ ### deploy
84
+
85
+ **Description**: Deploy a FlatDirectory contract. If the `address` is not set when creating a `FlatDirectory`, you must
86
+ call deploy before other functions.
87
+
88
+ **Returns**
89
+ - `address` (Promise<string | null>): A Promise that resolves to the FlatDirectory address, or `null` on failure.
90
+
91
+ **Example**
92
+ ```javascript
93
+ const address = await flatDirectory.deploy();
94
+ ```
95
+
96
+ ### estimateCost
97
+
98
+ **Description**: Estimate the cost of uploading data|file through calldata.
99
+
100
+ **Parameters**
101
+ - `request` (object): Configuration of the upload object containing necessary settings.
102
+ - `key` (string): The key of the data.
103
+ - `content` (Buffer|File): The content to be uploaded, which can be either a Buffer or a File.
104
+ - `maxFeePerGas` (bigint, optional): Custom max fee per gas, in wei (EIP-1559). Defaults to `1.1 × latest-block base fee + maxPriorityFeePerGas` (i.e. `baseFee * 11 / 10`, base fee from the node).
105
+ - `maxPriorityFeePerGas` (bigint, optional): Custom max priority fee per gas, in wei (EIP-1559). Defaults to `100` wei.
106
+ - `gasPrice` (bigint, optional): Custom gas price, in wei (legacy chains without EIP-1559, e.g. BNB Chain). Defaults to the node-suggested gas price.
107
+ - `chunkHashes` (string[], optional): The chunk hashes corresponding to the content. If this parameter exists, no
108
+ request to retrieve the hashes will be triggered.
109
+ - `maxChunkSize` (number, optional): Size of each data chunk, in KB. Defaults to `DEFAULT_MAX_CHUNK_SIZE_KB` (64).
110
+ - `maxChunks` (number, optional): Maximum number of chunks requested in a single call. Defaults to `MAX_CHUNKS`.
111
+
112
+ **Returns**
113
+ - `cost` (`Promise<object>`): A Promise that resolves to an object containing:
114
+ - `gasCost` (BigInt): The estimated gas cost.
115
+ - `storageCost` (BigInt): The estimated storage cost.
116
+
117
+ **Example**
118
+ ```javascript
119
+ const request = {
120
+ key: "example1.txt",
121
+ maxFeePerGas: 30000000000n, // 30 gwei, in wei
122
+ maxPriorityFeePerGas: 1500000000n, // 1.5 gwei, in wei
123
+ content: Buffer.from("large data to upload")
124
+ }
125
+ const cost = await flatDirectory.estimateCost(request);
126
+ console.log(`Gas Cost: ${cost.gasCost}, Storage Cost: ${cost.storageCost}`);
127
+ ```
128
+
129
+ If you want to use `file`, it can be divided into browser and Node.js.
130
+
131
+ Browser
132
+ ```javascript
133
+ // <input id='fileToUpload' />
134
+ const file = document.getElementById('fileToUpload').files[0];
135
+
136
+ const request = {
137
+ key: "example1.txt",
138
+ content: file
139
+ }
140
+ const cost = await flatDirectory.estimateCost(request);
141
+ console.log(`Gas Cost: ${cost.gasCost}, Storage Cost: ${cost.storageCost}`);
142
+ ```
143
+
144
+ Node.js
145
+ ```javascript
146
+ const {NodeFile} = require("calldatauploader-sdk/file");
147
+ const file = new NodeFile("/usr/download/test.jpg");
148
+
149
+ const request = {
150
+ key: "example1.txt",
151
+ content: file
152
+ }
153
+ const cost = await flatDirectory.estimateCost(request);
154
+ console.log(`Gas Cost: ${cost.gasCost}, Storage Cost: ${cost.storageCost}`);
155
+ ```
156
+
157
+ ### upload
158
+
159
+ **Description**: Upload data of arbitrary size via calldata.
160
+
161
+ **Parameters**
162
+ - `request` (object): Configuration of the upload object containing necessary settings.
163
+ - `key` (string): The key of the data.
164
+ - `content` (Buffer|File): The content to be uploaded, which can be either a Buffer or a File.
165
+ - `maxFeePerGas` (bigint, optional): Custom max fee per gas, in wei (EIP-1559). Defaults to `1.1 × latest-block base fee + maxPriorityFeePerGas` (i.e. `baseFee * 11 / 10`, base fee from the node).
166
+ - `maxPriorityFeePerGas` (bigint, optional): Custom max priority fee per gas, in wei (EIP-1559). Defaults to `100` wei.
167
+ - `gasPrice` (bigint, optional): Custom gas price, in wei (legacy chains without EIP-1559, e.g. BNB Chain). Defaults to the node-suggested gas price.
168
+ - `chunkHashes` (string[], optional): The chunk hashes corresponding to the content. If this parameter exists, no
169
+ request to retrieve the hashes will be triggered.
170
+ - `maxChunkSize` (number, optional): Size of each data chunk, in KB. Defaults to `DEFAULT_MAX_CHUNK_SIZE_KB` (64).
171
+ - `maxChunks` (number, optional): Maximum number of chunks requested in a single call. Defaults to `MAX_CHUNKS`.
172
+ - `callback` (object): An object containing callback functions:
173
+ - `onProgress(currentChunk, totalChunks, isChange)` (function): Called during the upload process to track progress.
174
+ - **`currentChunk`** (number): The index of the currently uploading chunk.
175
+ - **`totalChunks`** (number): The total number of chunks to be uploaded.
176
+ - **`isChange`** (boolean): Indicates whether the content has changed.
177
+ - `onFail(error)` (function): Called when an error occurs during the upload process.
178
+ - **`error`** (Error): The error object describing the failure.
179
+ - `onFinish(totalUploadChunks, totalUploadSize, totalCost)` (function): Called when the upload is completed.
180
+ - **`totalUploadChunks`** (number): The total number of uploaded chunks.
181
+ - **`totalUploadSize`** (number): The total uploaded size (in bytes).
182
+ - **`totalCost`** (bigint): The total cost of the upload, including **storage cost** and **gas cost**.
183
+ - `onTransactionSent(txHash, chunkIds)` (function, optional): Called right after a transaction is sent.
184
+ - **`txHash`** (string): The transaction hash.
185
+ - **`chunkIds`** (number[] | number): The chunk id(s) contained in the transaction.
186
+
187
+ **Example**
188
+ ```javascript
189
+ const cb = {
190
+ onProgress: function (progress, count, isChange) {
191
+ console.log(`Uploaded ${progress} of ${count} chunks`);
192
+ },
193
+ onFail: function (error) {
194
+ console.error("Error uploading data:", error);
195
+ },
196
+ onFinish: function (totalUploadChunks, totalUploadSize, totalCost) {
197
+ console.log(`Total upload chunk count is ${totalUploadChunks}, size is ${totalUploadSize}, total cost is ${totalCost}`);
198
+ }
199
+ };
200
+ const request = {
201
+ key: "example1.txt",
202
+ maxFeePerGas: 30000000000n, // 30 gwei, in wei
203
+ maxPriorityFeePerGas: 1500000000n, // 1.5 gwei, in wei
204
+ content: Buffer.from("large data to upload"),
205
+ callback: cb
206
+ }
207
+ await flatDirectory.upload(request);
208
+ ```
209
+
210
+ Use `file`.
211
+
212
+ Browser
213
+ ```javascript
214
+ // <input id='fileToUpload' />
215
+ const file = document.getElementById('fileToUpload').files[0];
216
+
217
+ const request = {
218
+ key: "example1.txt",
219
+ maxFeePerGas: 30000000000n, // 30 gwei, in wei
220
+ maxPriorityFeePerGas: 1500000000n, // 1.5 gwei, in wei
221
+ content: file,
222
+ callback: cb
223
+ }
224
+ await flatDirectory.upload(request);
225
+ ```
226
+
227
+ Node.js
228
+ ```javascript
229
+ const {NodeFile} = require("calldatauploader-sdk/file");
230
+ const file = new NodeFile("/usr/download/test.jpg");
231
+
232
+ const request = {
233
+ key: "example1.txt",
234
+ maxFeePerGas: 30000000000n, // 30 gwei, in wei
235
+ maxPriorityFeePerGas: 1500000000n, // 1.5 gwei, in wei
236
+ content: file,
237
+ callback: cb
238
+ }
239
+ await flatDirectory.upload(request);
240
+ ```
241
+
242
+ ### download
243
+
244
+ **Description**: Asynchronously download data by key. Get the progress and data in the callback function.
245
+
246
+ **Parameters**
247
+ - `key` (string): The key for the data to be read.
248
+ - `callback` (object): An object containing callback functions:
249
+ - `onProgress(currentChunk, totalChunks, chunkData)` (function): Called during the download process to track progress and receive chunk data.
250
+ - **`currentChunk`** (number): The index of the currently downloading chunk.
251
+ - **`totalChunks`** (number): The total number of chunks to be downloaded.
252
+ - **`chunkData`** (Uint8Array): The binary data of the current chunk.
253
+ - `onFail(error)` (function): Called when an error occurs during the download process.
254
+ - **`error`** (Error): The error object describing the failure.
255
+ - `onFinish()` (function): Indicates that the download was finish.
256
+
257
+ **Example**
258
+ ```javascript
259
+ flatDirectory.download("example.txt", {
260
+ onProgress: function (progress, count, chunk) {
261
+ console.log(`Download ${progress} of ${count} chunks, this chunk is ${Buffer.from(chunk).toString()}`);
262
+ },
263
+ onFail: function (error) {
264
+ console.error("Error download data:", error);
265
+ },
266
+ onFinish: function () {
267
+ console.log("Download finish.");
268
+ }
269
+ });
270
+ ```
271
+
272
+ ### fetchHashes
273
+
274
+ **Description**: Retrieve the chunk hashes corresponding to the batch of keys.
275
+
276
+ **Parameters**
277
+ - `keys` (string[]): The keys to be retrieved.
278
+ - `maxChunks` (number, optional): Maximum number of chunks requested in a single call, defaults to `MAX_CHUNKS`.
279
+
280
+ **Returns**
281
+ - `result` (Promise<Record<string, string[]>>): A Promise that resolves to an object where each key (from the input keys) maps to an array of chunk hashes.
282
+
283
+ **Example**
284
+ ```javascript
285
+ const keys = ["key1", "key2"];
286
+ const result = await flatDirectory.fetchHashes(keys);
287
+ ```
288
+
289
+ ### setDefault
290
+
291
+ **Description**: Set the default file for FlatDirectory, the file that is accessed by default when no file name is
292
+ provided.
293
+
294
+ **Parameters**
295
+ - `filename` (string): The filename of the default file.
296
+
297
+ **Returns**
298
+ - `status` (Promise<boolean>): A Promise that resolves to the execution result. `true|false`
299
+
300
+ **Example**
301
+ ```javascript
302
+ const defaultFile = "index.html";
303
+ const status = await flatDirectory.setDefault(defaultFile);
304
+ ```
305
+
306
+ ### remove
307
+
308
+ **Description**: Remove a file from the FlatDirectory contract.
309
+
310
+ **Parameters**
311
+ - `key` (string): The key of the file to be removed.
312
+
313
+ **Returns**
314
+ - `status` (Promise<boolean>): A Promise that resolves to the execution result. `true|false`
315
+
316
+ **Example**
317
+ ```javascript
318
+ const status = await flatDirectory.remove("index.html");
319
+ ```
320
+
321
+ <p id="Version"></p>
322
+
323
+ # 4. Version History
324
+
325
+ - v1.1.1: Initial release with basic storage and data management functionalities.