gethstorage-sdk 5.0.2 → 5.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/README.md +208 -208
- package/dist/browser/index.d.mts +44 -4
- package/dist/browser/index.mjs +65 -8
- package/dist/node/index.cjs +65 -8
- package/dist/node/index.d.mts +44 -4
- package/dist/node/index.d.ts +44 -4
- package/dist/node/index.mjs +65 -8
- package/package.json +65 -65
package/README.md
CHANGED
|
@@ -1,208 +1,208 @@
|
|
|
1
|
-
# gethstorage-sdk
|
|
2
|
-
|
|
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/gethstorage-sdk):
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
$ npm install gethstorage-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("gethstorage-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("gethstorage-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("gethstorage-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.
|
|
1
|
+
# gethstorage-sdk
|
|
2
|
+
|
|
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/gethstorage-sdk):
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
$ npm install gethstorage-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("gethstorage-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("gethstorage-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("gethstorage-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/dist/browser/index.d.mts
CHANGED
|
@@ -29,7 +29,7 @@ declare const DEFAULT_PRIORITY_FEE_PER_GAS: bigint;
|
|
|
29
29
|
/**
|
|
30
30
|
* Fraction applied to the latest-block base fee when deriving the default
|
|
31
31
|
* maxFeePerGas: baseFee * NUMERATOR / DENOMINATOR + priority fee.
|
|
32
|
-
*
|
|
32
|
+
* 12/10 = 1.2x, leaving headroom for one ~20% base-fee increase between blocks.
|
|
33
33
|
*/
|
|
34
34
|
declare const BASE_FEE_MULTIPLIER_NUMERATOR: bigint;
|
|
35
35
|
declare const BASE_FEE_MULTIPLIER_DENOMINATOR: bigint;
|
|
@@ -162,8 +162,44 @@ interface ChunkHashResult {
|
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
declare const stringToHex: (s: string) => string;
|
|
165
|
+
/**
|
|
166
|
+
* EIP-3541 forbids deploying new contract code whose first byte is 0xEF.
|
|
167
|
+
* EthStorage stores each chunk as a contract via CREATE2, so a chunk whose
|
|
168
|
+
* first byte is 0xEF will revert. We avoid this by shifting chunk boundaries.
|
|
169
|
+
*/
|
|
170
|
+
declare const EF_MAGIC: number;
|
|
171
|
+
/**
|
|
172
|
+
* Number of bytes reserved at the end of each chunk as extension headroom.
|
|
173
|
+
*
|
|
174
|
+
* The base chunk size is reduced by this many bytes; when a boundary would
|
|
175
|
+
* leave the next chunk starting with 0xEF, the current chunk is extended by
|
|
176
|
+
* up to this many bytes to absorb the run. The extended size never exceeds
|
|
177
|
+
* the original (unreserved) chunk size, so the contract's maxChunkSize limit
|
|
178
|
+
* is never violated.
|
|
179
|
+
*
|
|
180
|
+
* Probability justification (uniform random bytes):
|
|
181
|
+
* P(16 consecutive 0xEF) = (1/256)^16 ≈ 1e-38, effectively zero.
|
|
182
|
+
* Even across billions of boundaries the probability remains negligible.
|
|
183
|
+
* If a longer run ever occurs, the shrink fallback handles it.
|
|
184
|
+
*/
|
|
185
|
+
declare const EF_RESERVED_BYTES: number;
|
|
186
|
+
interface ChunkBoundary {
|
|
187
|
+
start: number;
|
|
188
|
+
end: number;
|
|
189
|
+
}
|
|
165
190
|
declare function getChainId(rpc: string): Promise<number>;
|
|
166
191
|
declare function getContentChunk(content: ContentLike, start: number, end: number): Promise<Uint8Array<ArrayBuffer>>;
|
|
192
|
+
/**
|
|
193
|
+
* Compute chunk boundaries for a calldata upload, shifting any boundary that
|
|
194
|
+
* would leave the next chunk starting with the 0xEF magic byte (EIP-3541).
|
|
195
|
+
*
|
|
196
|
+
* Strategy: for each boundary, if the byte at the boundary (first byte of the
|
|
197
|
+
* next chunk) is 0xEF, extend the current chunk to absorb it. If extension
|
|
198
|
+
* would exceed maxChunkSize, shrink the current chunk instead. In the extremely
|
|
199
|
+
* unlikely case that every byte in the adjustment window is 0xEF, the original
|
|
200
|
+
* fixed boundary is kept.
|
|
201
|
+
*/
|
|
202
|
+
declare function computeCalldataChunkBoundaries(content: ContentLike, baseChunkSize: number, maxChunkSize: number): Promise<ChunkBoundary[]>;
|
|
167
203
|
declare function isBuffer(content: ContentLike): content is BufferLike;
|
|
168
204
|
declare function isFile(content: ContentLike): content is FileLike;
|
|
169
205
|
declare function isNodejs(): boolean;
|
|
@@ -190,8 +226,8 @@ declare class TxSender {
|
|
|
190
226
|
* taken from the node unless overridden via custom.gasPrice.
|
|
191
227
|
* - Avalanche C-Chain: EIP-1559 with a protocol-enforced minimum base fee of
|
|
192
228
|
* 25 nAVAX; the node-reported base fee is clamped to that floor.
|
|
193
|
-
* - Other (EIP-1559) chains: tip defaults to
|
|
194
|
-
* maxFeePerGas defaults to 1.
|
|
229
|
+
* - Other (EIP-1559) chains: tip defaults to 150 wei,
|
|
230
|
+
* maxFeePerGas defaults to 1.2 * baseFee + tip (baseFee from the latest block).
|
|
195
231
|
* Caller-provided fields take precedence. effectiveGasPrice is the expected
|
|
196
232
|
* price actually charged per gas unit.
|
|
197
233
|
*/
|
|
@@ -212,9 +248,13 @@ declare function getChunkHashes(contract: Contract, batch: FileBatch[]): Promise
|
|
|
212
248
|
|
|
213
249
|
declare function stableRetry<T>(fn: (...args: unknown[]) => Promise<T>, ...args: unknown[]): Promise<T>;
|
|
214
250
|
|
|
251
|
+
type index_ChunkBoundary = ChunkBoundary;
|
|
252
|
+
declare const index_EF_MAGIC: typeof EF_MAGIC;
|
|
253
|
+
declare const index_EF_RESERVED_BYTES: typeof EF_RESERVED_BYTES;
|
|
215
254
|
type index_TxSender = TxSender;
|
|
216
255
|
declare const index_TxSender: typeof TxSender;
|
|
217
256
|
declare const index_calcTxCost: typeof calcTxCost;
|
|
257
|
+
declare const index_computeCalldataChunkBoundaries: typeof computeCalldataChunkBoundaries;
|
|
218
258
|
declare const index_getChainId: typeof getChainId;
|
|
219
259
|
declare const index_getChunkCounts: typeof getChunkCounts;
|
|
220
260
|
declare const index_getChunkHashes: typeof getChunkHashes;
|
|
@@ -226,7 +266,7 @@ declare const index_isNodejs: typeof isNodejs;
|
|
|
226
266
|
declare const index_stableRetry: typeof stableRetry;
|
|
227
267
|
declare const index_stringToHex: typeof stringToHex;
|
|
228
268
|
declare namespace index {
|
|
229
|
-
export { index_TxSender as TxSender, index_calcTxCost as calcTxCost, index_getChainId as getChainId, index_getChunkCounts as getChunkCounts, index_getChunkHashes as getChunkHashes, index_getContentChunk as getContentChunk, index_getUploadInfo as getUploadInfo, index_isBuffer as isBuffer, index_isFile as isFile, index_isNodejs as isNodejs, index_stableRetry as stableRetry, index_stringToHex as stringToHex };
|
|
269
|
+
export { type index_ChunkBoundary as ChunkBoundary, index_EF_MAGIC as EF_MAGIC, index_EF_RESERVED_BYTES as EF_RESERVED_BYTES, index_TxSender as TxSender, index_calcTxCost as calcTxCost, index_computeCalldataChunkBoundaries as computeCalldataChunkBoundaries, index_getChainId as getChainId, index_getChunkCounts as getChunkCounts, index_getChunkHashes as getChunkHashes, index_getContentChunk as getContentChunk, index_getUploadInfo as getUploadInfo, index_isBuffer as isBuffer, index_isFile as isFile, index_isNodejs as isNodejs, index_stableRetry as stableRetry, index_stringToHex as stringToHex };
|
|
230
270
|
}
|
|
231
271
|
|
|
232
272
|
declare class FlatDirectory {
|
package/dist/browser/index.mjs
CHANGED
|
@@ -7,8 +7,11 @@ var __export = (target, all) => {
|
|
|
7
7
|
// src/utils/index.ts
|
|
8
8
|
var utils_exports = {};
|
|
9
9
|
__export(utils_exports, {
|
|
10
|
+
EF_MAGIC: () => EF_MAGIC,
|
|
11
|
+
EF_RESERVED_BYTES: () => EF_RESERVED_BYTES,
|
|
10
12
|
TxSender: () => TxSender,
|
|
11
13
|
calcTxCost: () => calcTxCost,
|
|
14
|
+
computeCalldataChunkBoundaries: () => computeCalldataChunkBoundaries,
|
|
12
15
|
getChainId: () => getChainId,
|
|
13
16
|
getChunkCounts: () => getChunkCounts,
|
|
14
17
|
getChunkHashes: () => getChunkHashes,
|
|
@@ -24,6 +27,8 @@ __export(utils_exports, {
|
|
|
24
27
|
// src/utils/util.ts
|
|
25
28
|
import { ethers } from "ethers";
|
|
26
29
|
var stringToHex = (s) => ethers.hexlify(ethers.toUtf8Bytes(s));
|
|
30
|
+
var EF_MAGIC = 239;
|
|
31
|
+
var EF_RESERVED_BYTES = 16;
|
|
27
32
|
async function getChainId(rpc) {
|
|
28
33
|
const provider = new ethers.JsonRpcProvider(rpc);
|
|
29
34
|
const network = await provider.getNetwork();
|
|
@@ -38,6 +43,50 @@ async function getContentChunk(content, start, end) {
|
|
|
38
43
|
return new Uint8Array(data);
|
|
39
44
|
}
|
|
40
45
|
}
|
|
46
|
+
async function computeCalldataChunkBoundaries(content, baseChunkSize, maxChunkSize) {
|
|
47
|
+
const size = isFile(content) ? content.size : content.length;
|
|
48
|
+
const boundaries = [];
|
|
49
|
+
let pos = 0;
|
|
50
|
+
while (pos < size) {
|
|
51
|
+
let end = Math.min(pos + baseChunkSize, size);
|
|
52
|
+
if (end < size) {
|
|
53
|
+
const maxExtendEnd = Math.min(pos + maxChunkSize, size);
|
|
54
|
+
if (maxExtendEnd > end) {
|
|
55
|
+
const extWindow = await getContentChunk(content, end, maxExtendEnd);
|
|
56
|
+
let safeOffset = -1;
|
|
57
|
+
for (let i = 0; i < extWindow.length; i++) {
|
|
58
|
+
if (extWindow[i] !== EF_MAGIC) {
|
|
59
|
+
safeOffset = i;
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (safeOffset >= 0) {
|
|
64
|
+
end = end + safeOffset;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (end < size) {
|
|
68
|
+
const firstByte = await getContentChunk(content, end, end + 1);
|
|
69
|
+
if (firstByte.length > 0 && firstByte[0] === EF_MAGIC) {
|
|
70
|
+
const shrinkStart = Math.max(pos, end - 256);
|
|
71
|
+
const shrinkWindow = await getContentChunk(content, shrinkStart, end);
|
|
72
|
+
let lastSafe = -1;
|
|
73
|
+
for (let i = shrinkWindow.length - 1; i >= 0; i--) {
|
|
74
|
+
if (shrinkWindow[i] !== EF_MAGIC) {
|
|
75
|
+
lastSafe = shrinkStart + i;
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (lastSafe > pos) {
|
|
80
|
+
end = lastSafe;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
boundaries.push({ start: pos, end });
|
|
86
|
+
pos = end;
|
|
87
|
+
}
|
|
88
|
+
return boundaries;
|
|
89
|
+
}
|
|
41
90
|
function isBuffer(content) {
|
|
42
91
|
return content instanceof Uint8Array;
|
|
43
92
|
}
|
|
@@ -187,8 +236,8 @@ var CONTRACT_MAX_CHUNK_SIZE = (4 * 31 + 3) * 1024 - 4;
|
|
|
187
236
|
var MAX_CHUNKS = 100;
|
|
188
237
|
var CALLDATA_CHUNK_OVERHEAD = 326;
|
|
189
238
|
var DEFAULT_MAX_CHUNK_SIZE_KB = 64;
|
|
190
|
-
var DEFAULT_PRIORITY_FEE_PER_GAS =
|
|
191
|
-
var BASE_FEE_MULTIPLIER_NUMERATOR =
|
|
239
|
+
var DEFAULT_PRIORITY_FEE_PER_GAS = 150n;
|
|
240
|
+
var BASE_FEE_MULTIPLIER_NUMERATOR = 12n;
|
|
192
241
|
var BASE_FEE_MULTIPLIER_DENOMINATOR = 10n;
|
|
193
242
|
var LEGACY_GAS_CHAIN_IDS = /* @__PURE__ */ new Set([56, 97]);
|
|
194
243
|
var AVALANCHE_GAS_CHAIN_IDS = /* @__PURE__ */ new Set([43114, 43113]);
|
|
@@ -234,8 +283,8 @@ var TxSender = class {
|
|
|
234
283
|
* taken from the node unless overridden via custom.gasPrice.
|
|
235
284
|
* - Avalanche C-Chain: EIP-1559 with a protocol-enforced minimum base fee of
|
|
236
285
|
* 25 nAVAX; the node-reported base fee is clamped to that floor.
|
|
237
|
-
* - Other (EIP-1559) chains: tip defaults to
|
|
238
|
-
* maxFeePerGas defaults to 1.
|
|
286
|
+
* - Other (EIP-1559) chains: tip defaults to 150 wei,
|
|
287
|
+
* maxFeePerGas defaults to 1.2 * baseFee + tip (baseFee from the latest block).
|
|
239
288
|
* Caller-provided fields take precedence. effectiveGasPrice is the expected
|
|
240
289
|
* price actually charged per gas unit.
|
|
241
290
|
*/
|
|
@@ -762,10 +811,13 @@ var FlatDirectory = class _FlatDirectory {
|
|
|
762
811
|
if (toChunkSizeBytes(maxChunkSize) > CONTRACT_MAX_CHUNK_SIZE) {
|
|
763
812
|
throw new Error(`FlatDirectory: Chunk size ${maxChunkSize} KB exceeds the on-chain max payload of ${CONTRACT_MAX_CHUNK_SIZE} bytes.`);
|
|
764
813
|
}
|
|
765
|
-
const { chunkDataSize
|
|
814
|
+
const { chunkDataSize } = this.#calculateCalldataChunkDetails(content, maxChunkSize);
|
|
766
815
|
if (chunkDataSize === -1) {
|
|
767
816
|
throw new Error(`FlatDirectory: Invalid upload content!`);
|
|
768
817
|
}
|
|
818
|
+
const baseChunkSize = Math.max(1, chunkDataSize - EF_RESERVED_BYTES);
|
|
819
|
+
const boundaries = await computeCalldataChunkBoundaries(content, baseChunkSize, chunkDataSize);
|
|
820
|
+
const calldataChunkCount = boundaries.length;
|
|
769
821
|
const hexName = stringToHex(key);
|
|
770
822
|
const fileContract = new ethers3.Contract(this.#contractAddrChecked, FlatDirectoryAbi, this.#walletChecked);
|
|
771
823
|
const [{ oldChunkCount, fileMode }, resolvedFees] = await Promise.all([
|
|
@@ -791,7 +843,8 @@ var FlatDirectory = class _FlatDirectory {
|
|
|
791
843
|
() => fileContract["writeChunkByCalldata"].estimateGas(hexName, chunkId, hexData)
|
|
792
844
|
);
|
|
793
845
|
for (let i = 0; i < calldataChunkCount; i++) {
|
|
794
|
-
const
|
|
846
|
+
const { start, end } = boundaries[i];
|
|
847
|
+
const chunk = await getContentChunk(content, start, end);
|
|
795
848
|
if (i < chunkHashes.length && ethers3.keccak256(chunk) === chunkHashes[i]) {
|
|
796
849
|
continue;
|
|
797
850
|
}
|
|
@@ -830,12 +883,15 @@ var FlatDirectory = class _FlatDirectory {
|
|
|
830
883
|
callback.onFinish(totalUploadChunks, totalUploadSize, totalCost);
|
|
831
884
|
return;
|
|
832
885
|
}
|
|
833
|
-
const { chunkDataSize
|
|
886
|
+
const { chunkDataSize } = this.#calculateCalldataChunkDetails(content, maxChunkSize);
|
|
834
887
|
if (chunkDataSize === -1) {
|
|
835
888
|
callback.onFail(new Error(`FlatDirectory: Invalid upload content!`));
|
|
836
889
|
callback.onFinish(totalUploadChunks, totalUploadSize, totalCost);
|
|
837
890
|
return;
|
|
838
891
|
}
|
|
892
|
+
const baseChunkSize = Math.max(1, chunkDataSize - EF_RESERVED_BYTES);
|
|
893
|
+
const boundaries = await computeCalldataChunkBoundaries(content, baseChunkSize, chunkDataSize);
|
|
894
|
+
const calldataChunkCount = boundaries.length;
|
|
839
895
|
const hexName = stringToHex(key);
|
|
840
896
|
const fileContract = new ethers3.Contract(this.#contractAddrChecked, FlatDirectoryAbi, this.#walletChecked);
|
|
841
897
|
const { oldChunkCount, fileMode } = await getUploadInfo(fileContract, hexName);
|
|
@@ -876,7 +932,8 @@ var FlatDirectory = class _FlatDirectory {
|
|
|
876
932
|
}
|
|
877
933
|
}
|
|
878
934
|
for (let i = 0; i < calldataChunkCount; i++) {
|
|
879
|
-
const
|
|
935
|
+
const { start, end } = boundaries[i];
|
|
936
|
+
const chunk = await getContentChunk(content, start, end);
|
|
880
937
|
if (i < chunkHashes.length && ethers3.keccak256(chunk) === chunkHashes[i]) {
|
|
881
938
|
callback.onProgress(i, calldataChunkCount, false);
|
|
882
939
|
continue;
|
package/dist/node/index.cjs
CHANGED
|
@@ -52,8 +52,11 @@ module.exports = __toCommonJS(index_exports);
|
|
|
52
52
|
// src/utils/index.ts
|
|
53
53
|
var utils_exports = {};
|
|
54
54
|
__export(utils_exports, {
|
|
55
|
+
EF_MAGIC: () => EF_MAGIC,
|
|
56
|
+
EF_RESERVED_BYTES: () => EF_RESERVED_BYTES,
|
|
55
57
|
TxSender: () => TxSender,
|
|
56
58
|
calcTxCost: () => calcTxCost,
|
|
59
|
+
computeCalldataChunkBoundaries: () => computeCalldataChunkBoundaries,
|
|
57
60
|
getChainId: () => getChainId,
|
|
58
61
|
getChunkCounts: () => getChunkCounts,
|
|
59
62
|
getChunkHashes: () => getChunkHashes,
|
|
@@ -69,6 +72,8 @@ __export(utils_exports, {
|
|
|
69
72
|
// src/utils/util.ts
|
|
70
73
|
var import_ethers = require("ethers");
|
|
71
74
|
var stringToHex = (s) => import_ethers.ethers.hexlify(import_ethers.ethers.toUtf8Bytes(s));
|
|
75
|
+
var EF_MAGIC = 239;
|
|
76
|
+
var EF_RESERVED_BYTES = 16;
|
|
72
77
|
async function getChainId(rpc) {
|
|
73
78
|
const provider = new import_ethers.ethers.JsonRpcProvider(rpc);
|
|
74
79
|
const network = await provider.getNetwork();
|
|
@@ -83,6 +88,50 @@ async function getContentChunk(content, start, end) {
|
|
|
83
88
|
return new Uint8Array(data);
|
|
84
89
|
}
|
|
85
90
|
}
|
|
91
|
+
async function computeCalldataChunkBoundaries(content, baseChunkSize, maxChunkSize) {
|
|
92
|
+
const size = isFile(content) ? content.size : content.length;
|
|
93
|
+
const boundaries = [];
|
|
94
|
+
let pos = 0;
|
|
95
|
+
while (pos < size) {
|
|
96
|
+
let end = Math.min(pos + baseChunkSize, size);
|
|
97
|
+
if (end < size) {
|
|
98
|
+
const maxExtendEnd = Math.min(pos + maxChunkSize, size);
|
|
99
|
+
if (maxExtendEnd > end) {
|
|
100
|
+
const extWindow = await getContentChunk(content, end, maxExtendEnd);
|
|
101
|
+
let safeOffset = -1;
|
|
102
|
+
for (let i = 0; i < extWindow.length; i++) {
|
|
103
|
+
if (extWindow[i] !== EF_MAGIC) {
|
|
104
|
+
safeOffset = i;
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (safeOffset >= 0) {
|
|
109
|
+
end = end + safeOffset;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (end < size) {
|
|
113
|
+
const firstByte = await getContentChunk(content, end, end + 1);
|
|
114
|
+
if (firstByte.length > 0 && firstByte[0] === EF_MAGIC) {
|
|
115
|
+
const shrinkStart = Math.max(pos, end - 256);
|
|
116
|
+
const shrinkWindow = await getContentChunk(content, shrinkStart, end);
|
|
117
|
+
let lastSafe = -1;
|
|
118
|
+
for (let i = shrinkWindow.length - 1; i >= 0; i--) {
|
|
119
|
+
if (shrinkWindow[i] !== EF_MAGIC) {
|
|
120
|
+
lastSafe = shrinkStart + i;
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (lastSafe > pos) {
|
|
125
|
+
end = lastSafe;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
boundaries.push({ start: pos, end });
|
|
131
|
+
pos = end;
|
|
132
|
+
}
|
|
133
|
+
return boundaries;
|
|
134
|
+
}
|
|
86
135
|
function isBuffer(content) {
|
|
87
136
|
return content instanceof Uint8Array;
|
|
88
137
|
}
|
|
@@ -232,8 +281,8 @@ var CONTRACT_MAX_CHUNK_SIZE = (4 * 31 + 3) * 1024 - 4;
|
|
|
232
281
|
var MAX_CHUNKS = 100;
|
|
233
282
|
var CALLDATA_CHUNK_OVERHEAD = 326;
|
|
234
283
|
var DEFAULT_MAX_CHUNK_SIZE_KB = 64;
|
|
235
|
-
var DEFAULT_PRIORITY_FEE_PER_GAS =
|
|
236
|
-
var BASE_FEE_MULTIPLIER_NUMERATOR =
|
|
284
|
+
var DEFAULT_PRIORITY_FEE_PER_GAS = 150n;
|
|
285
|
+
var BASE_FEE_MULTIPLIER_NUMERATOR = 12n;
|
|
237
286
|
var BASE_FEE_MULTIPLIER_DENOMINATOR = 10n;
|
|
238
287
|
var LEGACY_GAS_CHAIN_IDS = /* @__PURE__ */ new Set([56, 97]);
|
|
239
288
|
var AVALANCHE_GAS_CHAIN_IDS = /* @__PURE__ */ new Set([43114, 43113]);
|
|
@@ -279,8 +328,8 @@ var TxSender = class {
|
|
|
279
328
|
* taken from the node unless overridden via custom.gasPrice.
|
|
280
329
|
* - Avalanche C-Chain: EIP-1559 with a protocol-enforced minimum base fee of
|
|
281
330
|
* 25 nAVAX; the node-reported base fee is clamped to that floor.
|
|
282
|
-
* - Other (EIP-1559) chains: tip defaults to
|
|
283
|
-
* maxFeePerGas defaults to 1.
|
|
331
|
+
* - Other (EIP-1559) chains: tip defaults to 150 wei,
|
|
332
|
+
* maxFeePerGas defaults to 1.2 * baseFee + tip (baseFee from the latest block).
|
|
284
333
|
* Caller-provided fields take precedence. effectiveGasPrice is the expected
|
|
285
334
|
* price actually charged per gas unit.
|
|
286
335
|
*/
|
|
@@ -807,10 +856,13 @@ var FlatDirectory = class _FlatDirectory {
|
|
|
807
856
|
if (toChunkSizeBytes(maxChunkSize) > CONTRACT_MAX_CHUNK_SIZE) {
|
|
808
857
|
throw new Error(`FlatDirectory: Chunk size ${maxChunkSize} KB exceeds the on-chain max payload of ${CONTRACT_MAX_CHUNK_SIZE} bytes.`);
|
|
809
858
|
}
|
|
810
|
-
const { chunkDataSize
|
|
859
|
+
const { chunkDataSize } = this.#calculateCalldataChunkDetails(content, maxChunkSize);
|
|
811
860
|
if (chunkDataSize === -1) {
|
|
812
861
|
throw new Error(`FlatDirectory: Invalid upload content!`);
|
|
813
862
|
}
|
|
863
|
+
const baseChunkSize = Math.max(1, chunkDataSize - EF_RESERVED_BYTES);
|
|
864
|
+
const boundaries = await computeCalldataChunkBoundaries(content, baseChunkSize, chunkDataSize);
|
|
865
|
+
const calldataChunkCount = boundaries.length;
|
|
814
866
|
const hexName = stringToHex(key);
|
|
815
867
|
const fileContract = new import_ethers3.ethers.Contract(this.#contractAddrChecked, FlatDirectoryAbi, this.#walletChecked);
|
|
816
868
|
const [{ oldChunkCount, fileMode }, resolvedFees] = await Promise.all([
|
|
@@ -836,7 +888,8 @@ var FlatDirectory = class _FlatDirectory {
|
|
|
836
888
|
() => fileContract["writeChunkByCalldata"].estimateGas(hexName, chunkId, hexData)
|
|
837
889
|
);
|
|
838
890
|
for (let i = 0; i < calldataChunkCount; i++) {
|
|
839
|
-
const
|
|
891
|
+
const { start, end } = boundaries[i];
|
|
892
|
+
const chunk = await getContentChunk(content, start, end);
|
|
840
893
|
if (i < chunkHashes.length && import_ethers3.ethers.keccak256(chunk) === chunkHashes[i]) {
|
|
841
894
|
continue;
|
|
842
895
|
}
|
|
@@ -875,12 +928,15 @@ var FlatDirectory = class _FlatDirectory {
|
|
|
875
928
|
callback.onFinish(totalUploadChunks, totalUploadSize, totalCost);
|
|
876
929
|
return;
|
|
877
930
|
}
|
|
878
|
-
const { chunkDataSize
|
|
931
|
+
const { chunkDataSize } = this.#calculateCalldataChunkDetails(content, maxChunkSize);
|
|
879
932
|
if (chunkDataSize === -1) {
|
|
880
933
|
callback.onFail(new Error(`FlatDirectory: Invalid upload content!`));
|
|
881
934
|
callback.onFinish(totalUploadChunks, totalUploadSize, totalCost);
|
|
882
935
|
return;
|
|
883
936
|
}
|
|
937
|
+
const baseChunkSize = Math.max(1, chunkDataSize - EF_RESERVED_BYTES);
|
|
938
|
+
const boundaries = await computeCalldataChunkBoundaries(content, baseChunkSize, chunkDataSize);
|
|
939
|
+
const calldataChunkCount = boundaries.length;
|
|
884
940
|
const hexName = stringToHex(key);
|
|
885
941
|
const fileContract = new import_ethers3.ethers.Contract(this.#contractAddrChecked, FlatDirectoryAbi, this.#walletChecked);
|
|
886
942
|
const { oldChunkCount, fileMode } = await getUploadInfo(fileContract, hexName);
|
|
@@ -921,7 +977,8 @@ var FlatDirectory = class _FlatDirectory {
|
|
|
921
977
|
}
|
|
922
978
|
}
|
|
923
979
|
for (let i = 0; i < calldataChunkCount; i++) {
|
|
924
|
-
const
|
|
980
|
+
const { start, end } = boundaries[i];
|
|
981
|
+
const chunk = await getContentChunk(content, start, end);
|
|
925
982
|
if (i < chunkHashes.length && import_ethers3.ethers.keccak256(chunk) === chunkHashes[i]) {
|
|
926
983
|
callback.onProgress(i, calldataChunkCount, false);
|
|
927
984
|
continue;
|
package/dist/node/index.d.mts
CHANGED
|
@@ -29,7 +29,7 @@ declare const DEFAULT_PRIORITY_FEE_PER_GAS: bigint;
|
|
|
29
29
|
/**
|
|
30
30
|
* Fraction applied to the latest-block base fee when deriving the default
|
|
31
31
|
* maxFeePerGas: baseFee * NUMERATOR / DENOMINATOR + priority fee.
|
|
32
|
-
*
|
|
32
|
+
* 12/10 = 1.2x, leaving headroom for one ~20% base-fee increase between blocks.
|
|
33
33
|
*/
|
|
34
34
|
declare const BASE_FEE_MULTIPLIER_NUMERATOR: bigint;
|
|
35
35
|
declare const BASE_FEE_MULTIPLIER_DENOMINATOR: bigint;
|
|
@@ -162,8 +162,44 @@ interface ChunkHashResult {
|
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
declare const stringToHex: (s: string) => string;
|
|
165
|
+
/**
|
|
166
|
+
* EIP-3541 forbids deploying new contract code whose first byte is 0xEF.
|
|
167
|
+
* EthStorage stores each chunk as a contract via CREATE2, so a chunk whose
|
|
168
|
+
* first byte is 0xEF will revert. We avoid this by shifting chunk boundaries.
|
|
169
|
+
*/
|
|
170
|
+
declare const EF_MAGIC: number;
|
|
171
|
+
/**
|
|
172
|
+
* Number of bytes reserved at the end of each chunk as extension headroom.
|
|
173
|
+
*
|
|
174
|
+
* The base chunk size is reduced by this many bytes; when a boundary would
|
|
175
|
+
* leave the next chunk starting with 0xEF, the current chunk is extended by
|
|
176
|
+
* up to this many bytes to absorb the run. The extended size never exceeds
|
|
177
|
+
* the original (unreserved) chunk size, so the contract's maxChunkSize limit
|
|
178
|
+
* is never violated.
|
|
179
|
+
*
|
|
180
|
+
* Probability justification (uniform random bytes):
|
|
181
|
+
* P(16 consecutive 0xEF) = (1/256)^16 ≈ 1e-38, effectively zero.
|
|
182
|
+
* Even across billions of boundaries the probability remains negligible.
|
|
183
|
+
* If a longer run ever occurs, the shrink fallback handles it.
|
|
184
|
+
*/
|
|
185
|
+
declare const EF_RESERVED_BYTES: number;
|
|
186
|
+
interface ChunkBoundary {
|
|
187
|
+
start: number;
|
|
188
|
+
end: number;
|
|
189
|
+
}
|
|
165
190
|
declare function getChainId(rpc: string): Promise<number>;
|
|
166
191
|
declare function getContentChunk(content: ContentLike, start: number, end: number): Promise<Uint8Array<ArrayBuffer>>;
|
|
192
|
+
/**
|
|
193
|
+
* Compute chunk boundaries for a calldata upload, shifting any boundary that
|
|
194
|
+
* would leave the next chunk starting with the 0xEF magic byte (EIP-3541).
|
|
195
|
+
*
|
|
196
|
+
* Strategy: for each boundary, if the byte at the boundary (first byte of the
|
|
197
|
+
* next chunk) is 0xEF, extend the current chunk to absorb it. If extension
|
|
198
|
+
* would exceed maxChunkSize, shrink the current chunk instead. In the extremely
|
|
199
|
+
* unlikely case that every byte in the adjustment window is 0xEF, the original
|
|
200
|
+
* fixed boundary is kept.
|
|
201
|
+
*/
|
|
202
|
+
declare function computeCalldataChunkBoundaries(content: ContentLike, baseChunkSize: number, maxChunkSize: number): Promise<ChunkBoundary[]>;
|
|
167
203
|
declare function isBuffer(content: ContentLike): content is BufferLike;
|
|
168
204
|
declare function isFile(content: ContentLike): content is FileLike;
|
|
169
205
|
declare function isNodejs(): boolean;
|
|
@@ -190,8 +226,8 @@ declare class TxSender {
|
|
|
190
226
|
* taken from the node unless overridden via custom.gasPrice.
|
|
191
227
|
* - Avalanche C-Chain: EIP-1559 with a protocol-enforced minimum base fee of
|
|
192
228
|
* 25 nAVAX; the node-reported base fee is clamped to that floor.
|
|
193
|
-
* - Other (EIP-1559) chains: tip defaults to
|
|
194
|
-
* maxFeePerGas defaults to 1.
|
|
229
|
+
* - Other (EIP-1559) chains: tip defaults to 150 wei,
|
|
230
|
+
* maxFeePerGas defaults to 1.2 * baseFee + tip (baseFee from the latest block).
|
|
195
231
|
* Caller-provided fields take precedence. effectiveGasPrice is the expected
|
|
196
232
|
* price actually charged per gas unit.
|
|
197
233
|
*/
|
|
@@ -212,9 +248,13 @@ declare function getChunkHashes(contract: Contract, batch: FileBatch[]): Promise
|
|
|
212
248
|
|
|
213
249
|
declare function stableRetry<T>(fn: (...args: unknown[]) => Promise<T>, ...args: unknown[]): Promise<T>;
|
|
214
250
|
|
|
251
|
+
type index_ChunkBoundary = ChunkBoundary;
|
|
252
|
+
declare const index_EF_MAGIC: typeof EF_MAGIC;
|
|
253
|
+
declare const index_EF_RESERVED_BYTES: typeof EF_RESERVED_BYTES;
|
|
215
254
|
type index_TxSender = TxSender;
|
|
216
255
|
declare const index_TxSender: typeof TxSender;
|
|
217
256
|
declare const index_calcTxCost: typeof calcTxCost;
|
|
257
|
+
declare const index_computeCalldataChunkBoundaries: typeof computeCalldataChunkBoundaries;
|
|
218
258
|
declare const index_getChainId: typeof getChainId;
|
|
219
259
|
declare const index_getChunkCounts: typeof getChunkCounts;
|
|
220
260
|
declare const index_getChunkHashes: typeof getChunkHashes;
|
|
@@ -226,7 +266,7 @@ declare const index_isNodejs: typeof isNodejs;
|
|
|
226
266
|
declare const index_stableRetry: typeof stableRetry;
|
|
227
267
|
declare const index_stringToHex: typeof stringToHex;
|
|
228
268
|
declare namespace index {
|
|
229
|
-
export { index_TxSender as TxSender, index_calcTxCost as calcTxCost, index_getChainId as getChainId, index_getChunkCounts as getChunkCounts, index_getChunkHashes as getChunkHashes, index_getContentChunk as getContentChunk, index_getUploadInfo as getUploadInfo, index_isBuffer as isBuffer, index_isFile as isFile, index_isNodejs as isNodejs, index_stableRetry as stableRetry, index_stringToHex as stringToHex };
|
|
269
|
+
export { type index_ChunkBoundary as ChunkBoundary, index_EF_MAGIC as EF_MAGIC, index_EF_RESERVED_BYTES as EF_RESERVED_BYTES, index_TxSender as TxSender, index_calcTxCost as calcTxCost, index_computeCalldataChunkBoundaries as computeCalldataChunkBoundaries, index_getChainId as getChainId, index_getChunkCounts as getChunkCounts, index_getChunkHashes as getChunkHashes, index_getContentChunk as getContentChunk, index_getUploadInfo as getUploadInfo, index_isBuffer as isBuffer, index_isFile as isFile, index_isNodejs as isNodejs, index_stableRetry as stableRetry, index_stringToHex as stringToHex };
|
|
230
270
|
}
|
|
231
271
|
|
|
232
272
|
declare class FlatDirectory {
|
package/dist/node/index.d.ts
CHANGED
|
@@ -29,7 +29,7 @@ declare const DEFAULT_PRIORITY_FEE_PER_GAS: bigint;
|
|
|
29
29
|
/**
|
|
30
30
|
* Fraction applied to the latest-block base fee when deriving the default
|
|
31
31
|
* maxFeePerGas: baseFee * NUMERATOR / DENOMINATOR + priority fee.
|
|
32
|
-
*
|
|
32
|
+
* 12/10 = 1.2x, leaving headroom for one ~20% base-fee increase between blocks.
|
|
33
33
|
*/
|
|
34
34
|
declare const BASE_FEE_MULTIPLIER_NUMERATOR: bigint;
|
|
35
35
|
declare const BASE_FEE_MULTIPLIER_DENOMINATOR: bigint;
|
|
@@ -162,8 +162,44 @@ interface ChunkHashResult {
|
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
declare const stringToHex: (s: string) => string;
|
|
165
|
+
/**
|
|
166
|
+
* EIP-3541 forbids deploying new contract code whose first byte is 0xEF.
|
|
167
|
+
* EthStorage stores each chunk as a contract via CREATE2, so a chunk whose
|
|
168
|
+
* first byte is 0xEF will revert. We avoid this by shifting chunk boundaries.
|
|
169
|
+
*/
|
|
170
|
+
declare const EF_MAGIC: number;
|
|
171
|
+
/**
|
|
172
|
+
* Number of bytes reserved at the end of each chunk as extension headroom.
|
|
173
|
+
*
|
|
174
|
+
* The base chunk size is reduced by this many bytes; when a boundary would
|
|
175
|
+
* leave the next chunk starting with 0xEF, the current chunk is extended by
|
|
176
|
+
* up to this many bytes to absorb the run. The extended size never exceeds
|
|
177
|
+
* the original (unreserved) chunk size, so the contract's maxChunkSize limit
|
|
178
|
+
* is never violated.
|
|
179
|
+
*
|
|
180
|
+
* Probability justification (uniform random bytes):
|
|
181
|
+
* P(16 consecutive 0xEF) = (1/256)^16 ≈ 1e-38, effectively zero.
|
|
182
|
+
* Even across billions of boundaries the probability remains negligible.
|
|
183
|
+
* If a longer run ever occurs, the shrink fallback handles it.
|
|
184
|
+
*/
|
|
185
|
+
declare const EF_RESERVED_BYTES: number;
|
|
186
|
+
interface ChunkBoundary {
|
|
187
|
+
start: number;
|
|
188
|
+
end: number;
|
|
189
|
+
}
|
|
165
190
|
declare function getChainId(rpc: string): Promise<number>;
|
|
166
191
|
declare function getContentChunk(content: ContentLike, start: number, end: number): Promise<Uint8Array<ArrayBuffer>>;
|
|
192
|
+
/**
|
|
193
|
+
* Compute chunk boundaries for a calldata upload, shifting any boundary that
|
|
194
|
+
* would leave the next chunk starting with the 0xEF magic byte (EIP-3541).
|
|
195
|
+
*
|
|
196
|
+
* Strategy: for each boundary, if the byte at the boundary (first byte of the
|
|
197
|
+
* next chunk) is 0xEF, extend the current chunk to absorb it. If extension
|
|
198
|
+
* would exceed maxChunkSize, shrink the current chunk instead. In the extremely
|
|
199
|
+
* unlikely case that every byte in the adjustment window is 0xEF, the original
|
|
200
|
+
* fixed boundary is kept.
|
|
201
|
+
*/
|
|
202
|
+
declare function computeCalldataChunkBoundaries(content: ContentLike, baseChunkSize: number, maxChunkSize: number): Promise<ChunkBoundary[]>;
|
|
167
203
|
declare function isBuffer(content: ContentLike): content is BufferLike;
|
|
168
204
|
declare function isFile(content: ContentLike): content is FileLike;
|
|
169
205
|
declare function isNodejs(): boolean;
|
|
@@ -190,8 +226,8 @@ declare class TxSender {
|
|
|
190
226
|
* taken from the node unless overridden via custom.gasPrice.
|
|
191
227
|
* - Avalanche C-Chain: EIP-1559 with a protocol-enforced minimum base fee of
|
|
192
228
|
* 25 nAVAX; the node-reported base fee is clamped to that floor.
|
|
193
|
-
* - Other (EIP-1559) chains: tip defaults to
|
|
194
|
-
* maxFeePerGas defaults to 1.
|
|
229
|
+
* - Other (EIP-1559) chains: tip defaults to 150 wei,
|
|
230
|
+
* maxFeePerGas defaults to 1.2 * baseFee + tip (baseFee from the latest block).
|
|
195
231
|
* Caller-provided fields take precedence. effectiveGasPrice is the expected
|
|
196
232
|
* price actually charged per gas unit.
|
|
197
233
|
*/
|
|
@@ -212,9 +248,13 @@ declare function getChunkHashes(contract: Contract, batch: FileBatch[]): Promise
|
|
|
212
248
|
|
|
213
249
|
declare function stableRetry<T>(fn: (...args: unknown[]) => Promise<T>, ...args: unknown[]): Promise<T>;
|
|
214
250
|
|
|
251
|
+
type index_ChunkBoundary = ChunkBoundary;
|
|
252
|
+
declare const index_EF_MAGIC: typeof EF_MAGIC;
|
|
253
|
+
declare const index_EF_RESERVED_BYTES: typeof EF_RESERVED_BYTES;
|
|
215
254
|
type index_TxSender = TxSender;
|
|
216
255
|
declare const index_TxSender: typeof TxSender;
|
|
217
256
|
declare const index_calcTxCost: typeof calcTxCost;
|
|
257
|
+
declare const index_computeCalldataChunkBoundaries: typeof computeCalldataChunkBoundaries;
|
|
218
258
|
declare const index_getChainId: typeof getChainId;
|
|
219
259
|
declare const index_getChunkCounts: typeof getChunkCounts;
|
|
220
260
|
declare const index_getChunkHashes: typeof getChunkHashes;
|
|
@@ -226,7 +266,7 @@ declare const index_isNodejs: typeof isNodejs;
|
|
|
226
266
|
declare const index_stableRetry: typeof stableRetry;
|
|
227
267
|
declare const index_stringToHex: typeof stringToHex;
|
|
228
268
|
declare namespace index {
|
|
229
|
-
export { index_TxSender as TxSender, index_calcTxCost as calcTxCost, index_getChainId as getChainId, index_getChunkCounts as getChunkCounts, index_getChunkHashes as getChunkHashes, index_getContentChunk as getContentChunk, index_getUploadInfo as getUploadInfo, index_isBuffer as isBuffer, index_isFile as isFile, index_isNodejs as isNodejs, index_stableRetry as stableRetry, index_stringToHex as stringToHex };
|
|
269
|
+
export { type index_ChunkBoundary as ChunkBoundary, index_EF_MAGIC as EF_MAGIC, index_EF_RESERVED_BYTES as EF_RESERVED_BYTES, index_TxSender as TxSender, index_calcTxCost as calcTxCost, index_computeCalldataChunkBoundaries as computeCalldataChunkBoundaries, index_getChainId as getChainId, index_getChunkCounts as getChunkCounts, index_getChunkHashes as getChunkHashes, index_getContentChunk as getContentChunk, index_getUploadInfo as getUploadInfo, index_isBuffer as isBuffer, index_isFile as isFile, index_isNodejs as isNodejs, index_stableRetry as stableRetry, index_stringToHex as stringToHex };
|
|
230
270
|
}
|
|
231
271
|
|
|
232
272
|
declare class FlatDirectory {
|
package/dist/node/index.mjs
CHANGED
|
@@ -7,8 +7,11 @@ var __export = (target, all) => {
|
|
|
7
7
|
// src/utils/index.ts
|
|
8
8
|
var utils_exports = {};
|
|
9
9
|
__export(utils_exports, {
|
|
10
|
+
EF_MAGIC: () => EF_MAGIC,
|
|
11
|
+
EF_RESERVED_BYTES: () => EF_RESERVED_BYTES,
|
|
10
12
|
TxSender: () => TxSender,
|
|
11
13
|
calcTxCost: () => calcTxCost,
|
|
14
|
+
computeCalldataChunkBoundaries: () => computeCalldataChunkBoundaries,
|
|
12
15
|
getChainId: () => getChainId,
|
|
13
16
|
getChunkCounts: () => getChunkCounts,
|
|
14
17
|
getChunkHashes: () => getChunkHashes,
|
|
@@ -24,6 +27,8 @@ __export(utils_exports, {
|
|
|
24
27
|
// src/utils/util.ts
|
|
25
28
|
import { ethers } from "ethers";
|
|
26
29
|
var stringToHex = (s) => ethers.hexlify(ethers.toUtf8Bytes(s));
|
|
30
|
+
var EF_MAGIC = 239;
|
|
31
|
+
var EF_RESERVED_BYTES = 16;
|
|
27
32
|
async function getChainId(rpc) {
|
|
28
33
|
const provider = new ethers.JsonRpcProvider(rpc);
|
|
29
34
|
const network = await provider.getNetwork();
|
|
@@ -38,6 +43,50 @@ async function getContentChunk(content, start, end) {
|
|
|
38
43
|
return new Uint8Array(data);
|
|
39
44
|
}
|
|
40
45
|
}
|
|
46
|
+
async function computeCalldataChunkBoundaries(content, baseChunkSize, maxChunkSize) {
|
|
47
|
+
const size = isFile(content) ? content.size : content.length;
|
|
48
|
+
const boundaries = [];
|
|
49
|
+
let pos = 0;
|
|
50
|
+
while (pos < size) {
|
|
51
|
+
let end = Math.min(pos + baseChunkSize, size);
|
|
52
|
+
if (end < size) {
|
|
53
|
+
const maxExtendEnd = Math.min(pos + maxChunkSize, size);
|
|
54
|
+
if (maxExtendEnd > end) {
|
|
55
|
+
const extWindow = await getContentChunk(content, end, maxExtendEnd);
|
|
56
|
+
let safeOffset = -1;
|
|
57
|
+
for (let i = 0; i < extWindow.length; i++) {
|
|
58
|
+
if (extWindow[i] !== EF_MAGIC) {
|
|
59
|
+
safeOffset = i;
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (safeOffset >= 0) {
|
|
64
|
+
end = end + safeOffset;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (end < size) {
|
|
68
|
+
const firstByte = await getContentChunk(content, end, end + 1);
|
|
69
|
+
if (firstByte.length > 0 && firstByte[0] === EF_MAGIC) {
|
|
70
|
+
const shrinkStart = Math.max(pos, end - 256);
|
|
71
|
+
const shrinkWindow = await getContentChunk(content, shrinkStart, end);
|
|
72
|
+
let lastSafe = -1;
|
|
73
|
+
for (let i = shrinkWindow.length - 1; i >= 0; i--) {
|
|
74
|
+
if (shrinkWindow[i] !== EF_MAGIC) {
|
|
75
|
+
lastSafe = shrinkStart + i;
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (lastSafe > pos) {
|
|
80
|
+
end = lastSafe;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
boundaries.push({ start: pos, end });
|
|
86
|
+
pos = end;
|
|
87
|
+
}
|
|
88
|
+
return boundaries;
|
|
89
|
+
}
|
|
41
90
|
function isBuffer(content) {
|
|
42
91
|
return content instanceof Uint8Array;
|
|
43
92
|
}
|
|
@@ -187,8 +236,8 @@ var CONTRACT_MAX_CHUNK_SIZE = (4 * 31 + 3) * 1024 - 4;
|
|
|
187
236
|
var MAX_CHUNKS = 100;
|
|
188
237
|
var CALLDATA_CHUNK_OVERHEAD = 326;
|
|
189
238
|
var DEFAULT_MAX_CHUNK_SIZE_KB = 64;
|
|
190
|
-
var DEFAULT_PRIORITY_FEE_PER_GAS =
|
|
191
|
-
var BASE_FEE_MULTIPLIER_NUMERATOR =
|
|
239
|
+
var DEFAULT_PRIORITY_FEE_PER_GAS = 150n;
|
|
240
|
+
var BASE_FEE_MULTIPLIER_NUMERATOR = 12n;
|
|
192
241
|
var BASE_FEE_MULTIPLIER_DENOMINATOR = 10n;
|
|
193
242
|
var LEGACY_GAS_CHAIN_IDS = /* @__PURE__ */ new Set([56, 97]);
|
|
194
243
|
var AVALANCHE_GAS_CHAIN_IDS = /* @__PURE__ */ new Set([43114, 43113]);
|
|
@@ -234,8 +283,8 @@ var TxSender = class {
|
|
|
234
283
|
* taken from the node unless overridden via custom.gasPrice.
|
|
235
284
|
* - Avalanche C-Chain: EIP-1559 with a protocol-enforced minimum base fee of
|
|
236
285
|
* 25 nAVAX; the node-reported base fee is clamped to that floor.
|
|
237
|
-
* - Other (EIP-1559) chains: tip defaults to
|
|
238
|
-
* maxFeePerGas defaults to 1.
|
|
286
|
+
* - Other (EIP-1559) chains: tip defaults to 150 wei,
|
|
287
|
+
* maxFeePerGas defaults to 1.2 * baseFee + tip (baseFee from the latest block).
|
|
239
288
|
* Caller-provided fields take precedence. effectiveGasPrice is the expected
|
|
240
289
|
* price actually charged per gas unit.
|
|
241
290
|
*/
|
|
@@ -762,10 +811,13 @@ var FlatDirectory = class _FlatDirectory {
|
|
|
762
811
|
if (toChunkSizeBytes(maxChunkSize) > CONTRACT_MAX_CHUNK_SIZE) {
|
|
763
812
|
throw new Error(`FlatDirectory: Chunk size ${maxChunkSize} KB exceeds the on-chain max payload of ${CONTRACT_MAX_CHUNK_SIZE} bytes.`);
|
|
764
813
|
}
|
|
765
|
-
const { chunkDataSize
|
|
814
|
+
const { chunkDataSize } = this.#calculateCalldataChunkDetails(content, maxChunkSize);
|
|
766
815
|
if (chunkDataSize === -1) {
|
|
767
816
|
throw new Error(`FlatDirectory: Invalid upload content!`);
|
|
768
817
|
}
|
|
818
|
+
const baseChunkSize = Math.max(1, chunkDataSize - EF_RESERVED_BYTES);
|
|
819
|
+
const boundaries = await computeCalldataChunkBoundaries(content, baseChunkSize, chunkDataSize);
|
|
820
|
+
const calldataChunkCount = boundaries.length;
|
|
769
821
|
const hexName = stringToHex(key);
|
|
770
822
|
const fileContract = new ethers3.Contract(this.#contractAddrChecked, FlatDirectoryAbi, this.#walletChecked);
|
|
771
823
|
const [{ oldChunkCount, fileMode }, resolvedFees] = await Promise.all([
|
|
@@ -791,7 +843,8 @@ var FlatDirectory = class _FlatDirectory {
|
|
|
791
843
|
() => fileContract["writeChunkByCalldata"].estimateGas(hexName, chunkId, hexData)
|
|
792
844
|
);
|
|
793
845
|
for (let i = 0; i < calldataChunkCount; i++) {
|
|
794
|
-
const
|
|
846
|
+
const { start, end } = boundaries[i];
|
|
847
|
+
const chunk = await getContentChunk(content, start, end);
|
|
795
848
|
if (i < chunkHashes.length && ethers3.keccak256(chunk) === chunkHashes[i]) {
|
|
796
849
|
continue;
|
|
797
850
|
}
|
|
@@ -830,12 +883,15 @@ var FlatDirectory = class _FlatDirectory {
|
|
|
830
883
|
callback.onFinish(totalUploadChunks, totalUploadSize, totalCost);
|
|
831
884
|
return;
|
|
832
885
|
}
|
|
833
|
-
const { chunkDataSize
|
|
886
|
+
const { chunkDataSize } = this.#calculateCalldataChunkDetails(content, maxChunkSize);
|
|
834
887
|
if (chunkDataSize === -1) {
|
|
835
888
|
callback.onFail(new Error(`FlatDirectory: Invalid upload content!`));
|
|
836
889
|
callback.onFinish(totalUploadChunks, totalUploadSize, totalCost);
|
|
837
890
|
return;
|
|
838
891
|
}
|
|
892
|
+
const baseChunkSize = Math.max(1, chunkDataSize - EF_RESERVED_BYTES);
|
|
893
|
+
const boundaries = await computeCalldataChunkBoundaries(content, baseChunkSize, chunkDataSize);
|
|
894
|
+
const calldataChunkCount = boundaries.length;
|
|
839
895
|
const hexName = stringToHex(key);
|
|
840
896
|
const fileContract = new ethers3.Contract(this.#contractAddrChecked, FlatDirectoryAbi, this.#walletChecked);
|
|
841
897
|
const { oldChunkCount, fileMode } = await getUploadInfo(fileContract, hexName);
|
|
@@ -876,7 +932,8 @@ var FlatDirectory = class _FlatDirectory {
|
|
|
876
932
|
}
|
|
877
933
|
}
|
|
878
934
|
for (let i = 0; i < calldataChunkCount; i++) {
|
|
879
|
-
const
|
|
935
|
+
const { start, end } = boundaries[i];
|
|
936
|
+
const chunk = await getContentChunk(content, start, end);
|
|
880
937
|
if (i < chunkHashes.length && ethers3.keccak256(chunk) === chunkHashes[i]) {
|
|
881
938
|
callback.onProgress(i, calldataChunkCount, false);
|
|
882
939
|
continue;
|
package/package.json
CHANGED
|
@@ -1,65 +1,65 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "gethstorage-sdk",
|
|
3
|
-
"version": "5.0.
|
|
4
|
-
"description": "EthStorage flat directory upload sdk (calldata only)",
|
|
5
|
-
"files": [
|
|
6
|
-
"dist"
|
|
7
|
-
],
|
|
8
|
-
"main": "./dist/node/index.cjs",
|
|
9
|
-
"types": "./dist/node/index.d.ts",
|
|
10
|
-
"exports": {
|
|
11
|
-
".": {
|
|
12
|
-
"browser": "./dist/browser/index.mjs",
|
|
13
|
-
"node": {
|
|
14
|
-
"import": "./dist/node/index.mjs",
|
|
15
|
-
"require": "./dist/node/index.cjs"
|
|
16
|
-
},
|
|
17
|
-
"types": "./dist/node/index.d.ts",
|
|
18
|
-
"default": "./dist/node/index.mjs"
|
|
19
|
-
},
|
|
20
|
-
"./file": {
|
|
21
|
-
"node": {
|
|
22
|
-
"import": "./dist/node/file.mjs",
|
|
23
|
-
"require": "./dist/node/file.cjs"
|
|
24
|
-
},
|
|
25
|
-
"types": "./dist/node/file.d.ts"
|
|
26
|
-
}
|
|
27
|
-
},
|
|
28
|
-
"scripts": {
|
|
29
|
-
"build": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && tsup",
|
|
30
|
-
"dev": "tsup --watch --env.NODE_ENV development",
|
|
31
|
-
"prepublishOnly": "npm run build"
|
|
32
|
-
},
|
|
33
|
-
"dependencies": {
|
|
34
|
-
"dotenv": "^16.4.5",
|
|
35
|
-
"ethers": "^6.17.0",
|
|
36
|
-
"p-limit": "^7.2.0"
|
|
37
|
-
},
|
|
38
|
-
"repository": {
|
|
39
|
-
"type": "git",
|
|
40
|
-
"url": "git+https://github.com/0xCampanula/gethstorage-sdk.git"
|
|
41
|
-
},
|
|
42
|
-
"bugs": {
|
|
43
|
-
"url": "https://github.com/0xCampanula/gethstorage-sdk/issues"
|
|
44
|
-
},
|
|
45
|
-
"homepage": "https://github.com/0xCampanula/gethstorage-sdk/main/",
|
|
46
|
-
"keywords": [
|
|
47
|
-
"File",
|
|
48
|
-
"Upload"
|
|
49
|
-
],
|
|
50
|
-
"author": "ethsorage",
|
|
51
|
-
"license": "ISC",
|
|
52
|
-
"devDependencies": {
|
|
53
|
-
"tsup": "^8.5.1",
|
|
54
|
-
"typescript": "^5.9.3"
|
|
55
|
-
},
|
|
56
|
-
"resolutions": {
|
|
57
|
-
"strip-ansi": "7.1.0",
|
|
58
|
-
"color-convert": "2.0.1",
|
|
59
|
-
"color-name": "1.1.4"
|
|
60
|
-
},
|
|
61
|
-
"overrides": {
|
|
62
|
-
"rollup": ">=4.59.0",
|
|
63
|
-
"picomatch": ">=4.0.4"
|
|
64
|
-
}
|
|
65
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "gethstorage-sdk",
|
|
3
|
+
"version": "5.0.4",
|
|
4
|
+
"description": "EthStorage flat directory upload sdk (calldata only)",
|
|
5
|
+
"files": [
|
|
6
|
+
"dist"
|
|
7
|
+
],
|
|
8
|
+
"main": "./dist/node/index.cjs",
|
|
9
|
+
"types": "./dist/node/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"browser": "./dist/browser/index.mjs",
|
|
13
|
+
"node": {
|
|
14
|
+
"import": "./dist/node/index.mjs",
|
|
15
|
+
"require": "./dist/node/index.cjs"
|
|
16
|
+
},
|
|
17
|
+
"types": "./dist/node/index.d.ts",
|
|
18
|
+
"default": "./dist/node/index.mjs"
|
|
19
|
+
},
|
|
20
|
+
"./file": {
|
|
21
|
+
"node": {
|
|
22
|
+
"import": "./dist/node/file.mjs",
|
|
23
|
+
"require": "./dist/node/file.cjs"
|
|
24
|
+
},
|
|
25
|
+
"types": "./dist/node/file.d.ts"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && tsup",
|
|
30
|
+
"dev": "tsup --watch --env.NODE_ENV development",
|
|
31
|
+
"prepublishOnly": "npm run build"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"dotenv": "^16.4.5",
|
|
35
|
+
"ethers": "^6.17.0",
|
|
36
|
+
"p-limit": "^7.2.0"
|
|
37
|
+
},
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "git+https://github.com/0xCampanula/gethstorage-sdk.git"
|
|
41
|
+
},
|
|
42
|
+
"bugs": {
|
|
43
|
+
"url": "https://github.com/0xCampanula/gethstorage-sdk/issues"
|
|
44
|
+
},
|
|
45
|
+
"homepage": "https://github.com/0xCampanula/gethstorage-sdk/main/",
|
|
46
|
+
"keywords": [
|
|
47
|
+
"File",
|
|
48
|
+
"Upload"
|
|
49
|
+
],
|
|
50
|
+
"author": "ethsorage",
|
|
51
|
+
"license": "ISC",
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"tsup": "^8.5.1",
|
|
54
|
+
"typescript": "^5.9.3"
|
|
55
|
+
},
|
|
56
|
+
"resolutions": {
|
|
57
|
+
"strip-ansi": "7.1.0",
|
|
58
|
+
"color-convert": "2.0.1",
|
|
59
|
+
"color-name": "1.1.4"
|
|
60
|
+
},
|
|
61
|
+
"overrides": {
|
|
62
|
+
"rollup": ">=4.59.0",
|
|
63
|
+
"picomatch": ">=4.0.4"
|
|
64
|
+
}
|
|
65
|
+
}
|