@shelby-protocol/sdk 0.0.1-experimental.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.
Files changed (63) hide show
  1. package/README.md +60 -0
  2. package/dist/browser/index.d.ts +10 -0
  3. package/dist/browser/index.mjs +55 -0
  4. package/dist/chunk-7P6ASYW6.mjs +9 -0
  5. package/dist/chunk-A4IG6GSE.mjs +21 -0
  6. package/dist/chunk-D2FERD4A.mjs +39 -0
  7. package/dist/chunk-DBTBUKCW.mjs +235 -0
  8. package/dist/chunk-E3QOKRQ4.mjs +50 -0
  9. package/dist/chunk-EFE5Y7IE.mjs +331 -0
  10. package/dist/chunk-GGYTHP5F.mjs +84 -0
  11. package/dist/chunk-I6NG5GNL.mjs +8 -0
  12. package/dist/chunk-IHTPXUYI.mjs +0 -0
  13. package/dist/chunk-MWDW4ROU.mjs +0 -0
  14. package/dist/chunk-NPM7WXK3.mjs +49 -0
  15. package/dist/chunk-OWIIKLFI.mjs +43 -0
  16. package/dist/chunk-PZPMURE4.mjs +0 -0
  17. package/dist/chunk-QEMIORTL.mjs +9 -0
  18. package/dist/chunk-VLLCOFH7.mjs +73 -0
  19. package/dist/chunk-WVWL2OPB.mjs +0 -0
  20. package/dist/chunk-XZMYTH4K.mjs +90 -0
  21. package/dist/chunk-YV67F5NY.mjs +38 -0
  22. package/dist/chunk-ZHXCVRZX.mjs +0 -0
  23. package/dist/core/ShelbyClient.d.ts +34 -0
  24. package/dist/core/ShelbyClient.mjs +8 -0
  25. package/dist/core/blobs.d.ts +52 -0
  26. package/dist/core/blobs.mjs +7 -0
  27. package/dist/core/commitments.d.ts +102 -0
  28. package/dist/core/commitments.mjs +11 -0
  29. package/dist/core/constants.d.ts +26 -0
  30. package/dist/core/constants.mjs +27 -0
  31. package/dist/core/index.d.ts +10 -0
  32. package/dist/core/index.mjs +55 -0
  33. package/dist/core/layout.d.ts +41 -0
  34. package/dist/core/layout.mjs +14 -0
  35. package/dist/core/promises.d.ts +10 -0
  36. package/dist/core/promises.mjs +7 -0
  37. package/dist/core/types/blobs.d.ts +132 -0
  38. package/dist/core/types/blobs.mjs +1 -0
  39. package/dist/core/types/encodings.d.ts +19 -0
  40. package/dist/core/types/encodings.mjs +1 -0
  41. package/dist/core/types/index.d.ts +5 -0
  42. package/dist/core/types/index.mjs +3 -0
  43. package/dist/node/clients/ShelbyBlobClient.d.ts +215 -0
  44. package/dist/node/clients/ShelbyBlobClient.mjs +19 -0
  45. package/dist/node/clients/ShelbyNodeClient.d.ts +95 -0
  46. package/dist/node/clients/ShelbyNodeClient.mjs +22 -0
  47. package/dist/node/clients/ShelbyRPCClient.d.ts +72 -0
  48. package/dist/node/clients/ShelbyRPCClient.mjs +17 -0
  49. package/dist/node/clients/index.d.ts +12 -0
  50. package/dist/node/clients/index.mjs +29 -0
  51. package/dist/node/commitments.d.ts +35 -0
  52. package/dist/node/commitments.mjs +18 -0
  53. package/dist/node/erasure.d.ts +12 -0
  54. package/dist/node/erasure.mjs +7 -0
  55. package/dist/node/index.d.ts +18 -0
  56. package/dist/node/index.mjs +85 -0
  57. package/dist/node/readableUtil.d.ts +2 -0
  58. package/dist/node/readableUtil.mjs +9 -0
  59. package/dist/node/testUtil.d.ts +1 -0
  60. package/dist/node/testUtil.mjs +7 -0
  61. package/dist/readableUtil-BW_7enT-.d.ts +12 -0
  62. package/dist/testUtil-BnxAchIN.d.ts +8 -0
  63. package/package.json +60 -0
@@ -0,0 +1,331 @@
1
+ import {
2
+ generateCommitments
3
+ } from "./chunk-VLLCOFH7.mjs";
4
+ import {
5
+ createBlobKey
6
+ } from "./chunk-QEMIORTL.mjs";
7
+ import {
8
+ SHELBY_DEPLOYER
9
+ } from "./chunk-D2FERD4A.mjs";
10
+
11
+ // src/node/clients/ShelbyBlobClient.ts
12
+ import { Readable } from "stream";
13
+ import {
14
+ AccountAddress,
15
+ Aptos,
16
+ Hex,
17
+ MoveVector
18
+ } from "@aptos-labs/ts-sdk";
19
+ var ShelbyBlobClient = class _ShelbyBlobClient {
20
+ aptos;
21
+ deployer;
22
+ /**
23
+ * The ShelbyBlobClient is used to interact with the Shelby contract on the Aptos blockchain. This
24
+ * includes functions like writing blob commitments, confirming chunks, and retrieving blob metadata.
25
+ *
26
+ * @param config.aptos.config - The Aptos config.
27
+ * @param config.shelbyDeployer - The deployer account address of the Shelby contract. If not provided, the default deployer address will be used.
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * const aptos = new Aptos(new AptosConfig({ network: Network.TESTNET }));
32
+ * const blobClient = new ShelbyBlobClient({ aptos });
33
+ * ```
34
+ */
35
+ constructor(config) {
36
+ this.aptos = new Aptos(config.aptos.config);
37
+ this.deployer = config.shelbyDeployer ?? AccountAddress.fromString(SHELBY_DEPLOYER);
38
+ }
39
+ /**
40
+ * Retrieves the blob metadata from the blockchain. If it does not exist,
41
+ * returns `undefined`.
42
+ *
43
+ * @param params.account - The account namespace the blob is stored in (e.g. "0x1")
44
+ * @param params.name - The name of the blob (e.g. "foo/bar")
45
+ * @returns The blob metadata.
46
+ *
47
+ * @example
48
+ * ```typescript
49
+ * const metadata = await client.getBlobMetadata({
50
+ * account: AccountAddress.fromString("0x1"),
51
+ * name: "foo/bar.txt",
52
+ * });
53
+ * ```
54
+ */
55
+ async getBlobMetadata(params) {
56
+ try {
57
+ const rawMetadata = await this.aptos.view({
58
+ payload: {
59
+ function: `${this.deployer.toString()}::prototype_interface::get_metadata`,
60
+ functionArguments: [
61
+ createBlobKey({
62
+ account: params.account,
63
+ blobName: params.name
64
+ })
65
+ ]
66
+ }
67
+ });
68
+ const metadata = rawMetadata[0];
69
+ return {
70
+ blobMerkleRoot: Hex.fromHexInput(
71
+ metadata.blob_merkle_root
72
+ ).toUint8Array(),
73
+ owner: AccountAddress.fromString(metadata.owner),
74
+ name: metadata.name,
75
+ size: metadata.size,
76
+ encoding: {
77
+ variant: "clay",
78
+ erasureK: metadata.encoding.num_data_chunks,
79
+ erasureM: metadata.encoding.num_parity_chunks,
80
+ chunksetSize: metadata.encoding.chunkset_size
81
+ },
82
+ expirationMicros: metadata.expiration_micros
83
+ };
84
+ } catch (error) {
85
+ if (error instanceof Error && // Depending on the network, the error message may show up differently.
86
+ (error.message?.includes("sub_status: Some(404)") || error.message?.includes("EBLOB_NOT_FOUND"))) {
87
+ return void 0;
88
+ }
89
+ throw error;
90
+ }
91
+ }
92
+ /**
93
+ * Retrieves all the blobs and their metadata for an account from the
94
+ * blockchain.
95
+ *
96
+ * @param params.account - The account namespace the blobs are stored in (e.g. "0x1")
97
+ * @returns The blob metadata for all the blobs for the account.
98
+ *
99
+ * @example
100
+ * ```typescript
101
+ * // BlobMetadata[]
102
+ * const blobs = await client.getAccountBlobs({
103
+ * account: AccountAddress.fromString("0x1"),
104
+ * });
105
+ * ```
106
+ */
107
+ async getAccountBlobs(params) {
108
+ const rawBlobMetadatas = await this.aptos.view({
109
+ payload: {
110
+ function: `${this.deployer.toString()}::prototype_interface::get_blobs_for_owner`,
111
+ functionArguments: [params.account.toString()]
112
+ }
113
+ });
114
+ return rawBlobMetadatas[0].map((blob) => ({
115
+ blobMerkleRoot: Hex.fromHexInput(blob.blob_merkle_root).toUint8Array(),
116
+ owner: AccountAddress.fromString(blob.owner),
117
+ name: blob.name,
118
+ size: blob.size,
119
+ encoding: {
120
+ variant: "clay",
121
+ erasureK: blob.encoding.num_data_chunks,
122
+ erasureM: blob.encoding.num_parity_chunks,
123
+ chunksetSize: blob.encoding.chunkset_size
124
+ },
125
+ expirationMicros: blob.expiration_micros
126
+ }));
127
+ }
128
+ /**
129
+ * Retrieves the blob chunks for a given blob from the blockchain. The blob chunk will contain
130
+ * the commitment, the storage provider location, and the status of the chunk (stored or pending).
131
+ *
132
+ * @param params.account - The account namespace the blob is stored in (e.g. "0x1")
133
+ * @param params.name - The name of the blob (e.g. "foo/bar")
134
+ * @returns The chunks that make up the blob.
135
+ *
136
+ * @example
137
+ * ```typescript
138
+ * // BlobChunk[]
139
+ * const chunks = await client.getBlobChunks({
140
+ * account: AccountAddress.fromString("0x1"),
141
+ * name: "foo/bar.txt",
142
+ * });
143
+ *
144
+ * const isStored = chunks.every((c) => c.location.variant === "stored");
145
+ * ```
146
+ */
147
+ async getBlobChunks(params) {
148
+ const chunks = await this.aptos.view({
149
+ payload: {
150
+ function: `${this.deployer.toString()}::prototype_interface::get_chunks`,
151
+ functionArguments: [
152
+ createBlobKey({
153
+ account: params.account,
154
+ blobName: params.name
155
+ })
156
+ ]
157
+ }
158
+ });
159
+ return chunks[0].map((c) => ({
160
+ commitment: Hex.fromHexInput(c.commitment).toUint8Array(),
161
+ location: {
162
+ variant: c.location.__variant__ === "Stored" ? "stored" : "pending",
163
+ provider: AccountAddress.fromString(c.location.provider)
164
+ }
165
+ }));
166
+ }
167
+ /**
168
+ * Writes the blob commitments to the blockchain.
169
+ *
170
+ * If `data` is provided instead of `blobCommitments`, the data will be encoded into commitments before being written
171
+ * to the blockchain.
172
+ *
173
+ * @param params.signer - The account that is signing the transaction.
174
+ * @param params.blobName - The name of the blob (e.g. "foo/bar")
175
+ * @param params.expirationMicros - The expiration time of the blob in microseconds.
176
+ * @param params.options - Additional options for transaction building and encoding.
177
+ * @param params.blobCommitments - The blob commitments to write to the blockchain (required if `data` is not provided).
178
+ * @param params.data - The data to encode into commitments before writing to the blockchain (required if `blobCommitments` is not provided).
179
+ *
180
+ * @returns The blob commitments and the pending transaction.
181
+ *
182
+ * @example
183
+ * ```typescript
184
+ * const blobCommitments = await generateCommitments(Readable.from(data));
185
+ *
186
+ * const { blobCommitments, transaction } = await client.writeBlobCommitments({
187
+ * signer,
188
+ * blobName: "foo/bar.txt",
189
+ * blobCommitments,
190
+ * expirationMicros: Date.now() * 1000 + 3600_000_000, // 1 hour from now in microseconds
191
+ * });
192
+ * ```
193
+ */
194
+ async writeBlobCommitments(params) {
195
+ let blobCommitments;
196
+ if ("blobCommitments" in params) {
197
+ blobCommitments = params.blobCommitments;
198
+ } else {
199
+ blobCommitments = await generateCommitments(
200
+ Readable.from(params.blobData),
201
+ void 0,
202
+ params.options?.encoding
203
+ );
204
+ }
205
+ const transaction = await this.aptos.transaction.build.simple({
206
+ ...params.options?.build,
207
+ data: _ShelbyBlobClient.createWriteBlobCommitmentsPayload({
208
+ deployer: this.deployer,
209
+ account: params.signer.accountAddress,
210
+ blobName: params.blobName,
211
+ blobMerkleRoot: blobCommitments.blob_merkle_root,
212
+ chunksetChunkCommitments: blobCommitments.chunkset_commitments.map(
213
+ (chunkset) => chunkset.chunk_commitments
214
+ ),
215
+ size: blobCommitments.raw_data_size,
216
+ expirationMicros: params.expirationMicros
217
+ }),
218
+ sender: params.signer.accountAddress
219
+ });
220
+ return {
221
+ blobCommitments,
222
+ transaction: await this.aptos.signAndSubmitTransaction({
223
+ signer: params.signer,
224
+ transaction
225
+ })
226
+ };
227
+ }
228
+ /**
229
+ * Confirms an array of signed chunk commitments for a blob. Once all chunks for a blob are confirmed, the blob is
230
+ * considered "stored" and can be retrieved by RPC nodes.
231
+ *
232
+ * @param params.signer - The account that is signing the transaction.
233
+ * @param params.account - The account namespace the blob is stored in (e.g. "0x1")
234
+ * @param params.blobName - The name of the blob (e.g. "foo/bar")
235
+ * @param params.signedChunksetChunkCommitments - The signed chunk commitments, signed by their storage provider.
236
+ * @param params.options - Additional options for transaction building and encoding.
237
+ *
238
+ * @returns The pending transaction response.
239
+ *
240
+ * @example
241
+ * ```typescript
242
+ * const { transaction } = await client.confirmBlobChunks({
243
+ * signer,
244
+ * account: AccountAddress.fromString("0x1"),
245
+ * blobName: "foo/bar.txt",
246
+ * signedChunksetChunkCommitments,
247
+ * });
248
+ * ```
249
+ */
250
+ async confirmBlobChunks(params) {
251
+ const transaction = await this.aptos.transaction.build.simple({
252
+ ...params.options?.build,
253
+ data: _ShelbyBlobClient.createConfirmBlobChunksPayload({
254
+ deployer: this.deployer,
255
+ account: params.account,
256
+ blobName: params.blobName,
257
+ signedChunksetChunkCommitments: params.signedChunksetChunkCommitments
258
+ }),
259
+ sender: params.signer.accountAddress
260
+ });
261
+ return {
262
+ transaction: await this.aptos.signAndSubmitTransaction({
263
+ signer: params.signer,
264
+ transaction
265
+ })
266
+ };
267
+ }
268
+ /**
269
+ * Creates a transaction payload to write blob commitments to the blockchain.
270
+ *
271
+ * @param params.deployer - The deployer account address of the Shelby contract. If not provided, the default deployer address will be used.
272
+ * @param params.account - The account namespace the blob is stored in (e.g. "0x1")
273
+ * @param params.blobName - The name of the blob (e.g. "foo/bar")
274
+ * @param params.blobMerkleRoot - The blob merkle root.
275
+ * @param params.chunksetChunkCommitments - The chunk commitments for each chunkset.
276
+ * @param params.expirationMicros - The expiration time of the blob in microseconds.
277
+ * @param params.size - The size of the blob in bytes.
278
+ *
279
+ * @see https://github.com/JumpCrypto/shelby/blob/e009607aad330ccddb08d80bf9addfaadae7972b/move/prototype/move/sources/prototype_interface.move#L211-L220
280
+ */
281
+ static createWriteBlobCommitmentsPayload(params) {
282
+ return {
283
+ function: `${(params.deployer ?? SHELBY_DEPLOYER).toString()}::prototype_interface::write_commitments`,
284
+ functionArguments: [
285
+ createBlobKey({
286
+ account: params.account,
287
+ blobName: params.blobName
288
+ }),
289
+ params.size,
290
+ MoveVector.U8(params.blobMerkleRoot),
291
+ params.chunksetChunkCommitments.map(
292
+ (chunkset) => chunkset.map((chunkCommitment) => MoveVector.U8(chunkCommitment))
293
+ ),
294
+ params.expirationMicros,
295
+ true
296
+ ]
297
+ };
298
+ }
299
+ /**
300
+ * Creates a transaction payload to confirm the chunks of a blob.
301
+ *
302
+ * @param params.deployer - The deployer account address of the Shelby contract. If not provided, the default deployer address will be used.
303
+ * @param params.account - The account namespace the blob is stored in (e.g. "0x1")
304
+ * @param params.blobName - The name of the blob (e.g. "foo/bar")
305
+ * @param params.signedChunksetChunkCommitments - The signed chunk commitments, signed by their storage provider.
306
+ *
307
+ * @see https://github.com/JumpCrypto/shelby/blob/e009607aad330ccddb08d80bf9addfaadae7972b/move/prototype/move/sources/prototype_interface.move#L343-L349
308
+ */
309
+ static createConfirmBlobChunksPayload(params) {
310
+ return {
311
+ function: `${(params.deployer ?? SHELBY_DEPLOYER).toString()}::prototype_interface::write_complete`,
312
+ functionArguments: [
313
+ createBlobKey({
314
+ account: params.account,
315
+ blobName: params.blobName
316
+ }),
317
+ params.signedChunksetChunkCommitments.map(
318
+ (chunkset) => chunkset.map((chunk) => AccountAddress.from(chunk.provider))
319
+ ),
320
+ params.signedChunksetChunkCommitments.map(
321
+ (chunkset) => chunkset.map((chunk) => MoveVector.U8(chunk.signedCommitment))
322
+ ),
323
+ true
324
+ ]
325
+ };
326
+ }
327
+ };
328
+
329
+ export {
330
+ ShelbyBlobClient
331
+ };
@@ -0,0 +1,84 @@
1
+ import {
2
+ ERASURE_K,
3
+ ERASURE_M,
4
+ getChunkSizeBytes,
5
+ getChunksetSizeBytes
6
+ } from "./chunk-D2FERD4A.mjs";
7
+
8
+ // src/core/layout.ts
9
+ import { AccountAddress } from "@aptos-labs/ts-sdk";
10
+ import { z } from "zod";
11
+ var BlobNameSchema = z.string().min(1, "Blob name path parameter cannot be empty.").max(1024, "Blob name cannot exceed 1024 characters.").refine((name) => !name.endsWith("/"), {
12
+ message: "Blob name cannot end with a slash"
13
+ });
14
+ var ChunkKey = class _ChunkKey {
15
+ constructor(account, blobName, chunksetIdx, chunkIdx) {
16
+ this.account = account;
17
+ this.blobName = blobName;
18
+ this.chunksetIdx = chunksetIdx;
19
+ this.chunkIdx = chunkIdx;
20
+ const N = ERASURE_K + ERASURE_M;
21
+ if (chunkIdx >= N) {
22
+ throw new Error(`Cannot create a chunk with idx ${chunkIdx}. M+K=${N}`);
23
+ }
24
+ }
25
+ key() {
26
+ return `${this.account.toString()}.${this.blobName}.${this.chunksetIdx}.${this.chunkIdx}`;
27
+ }
28
+ // Returns the range in the blob that this key represents, or "partity" if this is parity chunk.
29
+ range() {
30
+ if (this.chunkIdx >= ERASURE_K) {
31
+ return "parity";
32
+ }
33
+ const chunksetStart = this.chunksetIdx * getChunksetSizeBytes();
34
+ const chunkStart = chunksetStart + this.chunkIdx * getChunkSizeBytes();
35
+ return {
36
+ start: chunkStart,
37
+ end: chunkStart + getChunkSizeBytes()
38
+ };
39
+ }
40
+ static fromJSON(json) {
41
+ return new _ChunkKey(
42
+ AccountAddress.fromString(json.account),
43
+ json.blobName,
44
+ json.chunksetIdx,
45
+ json.chunkIdx
46
+ );
47
+ }
48
+ toJSON() {
49
+ return {
50
+ account: this.account.toString(),
51
+ blobName: this.blobName,
52
+ chunksetIdx: this.chunksetIdx,
53
+ chunkIdx: this.chunkIdx
54
+ };
55
+ }
56
+ };
57
+ function roundSize(size) {
58
+ let ret = 0;
59
+ let remain = size;
60
+ while (remain > 0) {
61
+ ret += getChunksetSizeBytes();
62
+ remain -= getChunksetSizeBytes();
63
+ }
64
+ return ret;
65
+ }
66
+ function allChunksForBlob(account, blobName, _size) {
67
+ const ret = [];
68
+ const size = roundSize(_size);
69
+ const nChunksets = size / getChunksetSizeBytes();
70
+ for (let chunksetIdx = 0; chunksetIdx < nChunksets; ++chunksetIdx) {
71
+ const n = ERASURE_K + ERASURE_M;
72
+ for (let chunkIdx = 0; chunkIdx < n; ++chunkIdx) {
73
+ ret.push(new ChunkKey(account, blobName, chunksetIdx, chunkIdx));
74
+ }
75
+ }
76
+ return ret;
77
+ }
78
+
79
+ export {
80
+ BlobNameSchema,
81
+ ChunkKey,
82
+ roundSize,
83
+ allChunksForBlob
84
+ };
@@ -0,0 +1,8 @@
1
+ // src/core/promises.ts
2
+ function sleep(ms) {
3
+ return new Promise((resolve) => setTimeout(resolve, ms));
4
+ }
5
+
6
+ export {
7
+ sleep
8
+ };
File without changes
File without changes
@@ -0,0 +1,49 @@
1
+ import {
2
+ roundSize
3
+ } from "./chunk-GGYTHP5F.mjs";
4
+ import {
5
+ ERASURE_K,
6
+ ERASURE_M,
7
+ getChunksetSizeBytes
8
+ } from "./chunk-D2FERD4A.mjs";
9
+
10
+ // src/core/commitments.ts
11
+ import { z } from "zod";
12
+ var ChunksetCommitmentSchema = z.object({
13
+ // Chunkset root (vector commitment of child chunks)
14
+ chunkset_root: z.string().nullable(),
15
+ // the size is known statically from the current configuration
16
+ chunk_commitments: z.array(z.string())
17
+ }).refine(
18
+ (data) => {
19
+ return data.chunk_commitments.length === ERASURE_K + ERASURE_M;
20
+ },
21
+ {
22
+ message: `Chunkset must have exactly ${ERASURE_K + ERASURE_M} chunks (ERASURE_K + ERASURE_M = ${ERASURE_K} + ${ERASURE_M})`,
23
+ path: ["chunk_commitments"]
24
+ }
25
+ );
26
+ function expectedTotalChunksets(rawSize) {
27
+ return roundSize(rawSize) / getChunksetSizeBytes();
28
+ }
29
+ var BlobCommitmentsSchema = z.object({
30
+ schema_version: z.string(),
31
+ raw_data_size: z.number(),
32
+ // FIXME I am not sure about this being here, or if it should be somewhere else
33
+ blob_merkle_root: z.string(),
34
+ chunkset_commitments: z.array(ChunksetCommitmentSchema)
35
+ }).refine(
36
+ (data) => {
37
+ return expectedTotalChunksets(data.raw_data_size) === data.chunkset_commitments.length;
38
+ },
39
+ {
40
+ message: "Total chunkset count mismatches with raw data size",
41
+ // FIXME put more details in here
42
+ path: ["chunkset_commitments"]
43
+ }
44
+ );
45
+
46
+ export {
47
+ ChunksetCommitmentSchema,
48
+ BlobCommitmentsSchema
49
+ };
@@ -0,0 +1,43 @@
1
+ // src/node/erasure.ts
2
+ import { Buffer } from "buffer";
3
+ import { RS } from "@shelby-protocol/reed-solomon";
4
+ async function erasureEncode(data, k, m) {
5
+ const rawShardSize = Math.ceil(data.length / k);
6
+ const shardSize = Math.ceil(rawShardSize / 8) * 8;
7
+ const dataSize = shardSize * k;
8
+ const paritySize = shardSize * m;
9
+ const dataBuf = Buffer.alloc(dataSize);
10
+ data.copy(dataBuf, 0);
11
+ const parityBuf = Buffer.alloc(paritySize);
12
+ let sources = 0;
13
+ for (let i = 0; i < k; i++) sources |= 1 << i;
14
+ let targets = 0;
15
+ for (let i = k; i < k + m; i++) targets |= 1 << i;
16
+ const context = RS.create(k, m);
17
+ await new Promise((resolve, reject) => {
18
+ RS.encode(
19
+ context,
20
+ sources,
21
+ targets,
22
+ dataBuf,
23
+ 0,
24
+ dataSize,
25
+ parityBuf,
26
+ 0,
27
+ paritySize,
28
+ (err) => err ? reject(err) : resolve()
29
+ );
30
+ });
31
+ const shards = [];
32
+ for (let i = 0; i < k; i++) {
33
+ shards.push(dataBuf.slice(i * shardSize, i * shardSize + shardSize));
34
+ }
35
+ for (let j = 0; j < m; j++) {
36
+ shards.push(parityBuf.slice(j * shardSize, j * shardSize + shardSize));
37
+ }
38
+ return shards;
39
+ }
40
+
41
+ export {
42
+ erasureEncode
43
+ };
File without changes
@@ -0,0 +1,9 @@
1
+ // src/core/blobs.ts
2
+ import { AccountAddress } from "@aptos-labs/ts-sdk";
3
+ var createBlobKey = (params) => {
4
+ return `${AccountAddress.from(params.account).toString()}.${params.blobName}`;
5
+ };
6
+
7
+ export {
8
+ createBlobKey
9
+ };
@@ -0,0 +1,73 @@
1
+ import {
2
+ erasureEncode
3
+ } from "./chunk-OWIIKLFI.mjs";
4
+ import {
5
+ readInChunks,
6
+ zeroPadBuffer
7
+ } from "./chunk-E3QOKRQ4.mjs";
8
+ import {
9
+ ERASURE_K,
10
+ ERASURE_M,
11
+ getChunksetSizeBytes
12
+ } from "./chunk-D2FERD4A.mjs";
13
+
14
+ // src/node/commitments.ts
15
+ import { createHash } from "crypto";
16
+ import { Hex } from "@aptos-labs/ts-sdk";
17
+ function concatHashes(parts) {
18
+ const combined = Buffer.concat(
19
+ parts.map((part) => Hex.fromHexInput(part).toUint8Array())
20
+ );
21
+ return Hex.fromHexInput(createHash("sha256").update(combined).digest());
22
+ }
23
+ async function generateCommitments(fullData, onChunk, options) {
24
+ const chunksetCommitments = [];
25
+ const chunksetCommitmentHashes = [];
26
+ let rawDataSize = 0;
27
+ const chunksetGen = readInChunks(
28
+ fullData,
29
+ options?.chunksetSize ?? getChunksetSizeBytes()
30
+ );
31
+ for await (let [chunksetIdx, chunksetData] of chunksetGen) {
32
+ const chunkCommitments = [];
33
+ rawDataSize += chunksetData.length;
34
+ chunksetData = zeroPadBuffer(
35
+ chunksetData,
36
+ options?.chunksetSize ?? getChunksetSizeBytes()
37
+ );
38
+ const chunks = await erasureEncode(
39
+ chunksetData,
40
+ options?.erasureK ?? ERASURE_K,
41
+ options?.erasureM ?? ERASURE_M
42
+ );
43
+ let chunkIdx = 0;
44
+ for (const chunkData of chunks) {
45
+ if (onChunk !== void 0) {
46
+ await onChunk(chunksetIdx, chunkIdx, chunkData);
47
+ }
48
+ const chunkHash = concatHashes([chunkData]);
49
+ chunkCommitments.push(chunkHash);
50
+ chunkIdx += 1;
51
+ }
52
+ const h = concatHashes(
53
+ chunkCommitments.map((chunk) => chunk.toUint8Array())
54
+ );
55
+ chunksetCommitments.push({
56
+ chunkset_root: h.toString(),
57
+ chunk_commitments: chunkCommitments.map((chunk) => chunk.toString())
58
+ });
59
+ chunksetCommitmentHashes.push(h);
60
+ }
61
+ return {
62
+ schema_version: "1.3",
63
+ raw_data_size: rawDataSize,
64
+ blob_merkle_root: concatHashes(
65
+ chunksetCommitmentHashes.map((chunk) => chunk.toUint8Array())
66
+ ).toString(),
67
+ chunkset_commitments: chunksetCommitments
68
+ };
69
+ }
70
+
71
+ export {
72
+ generateCommitments
73
+ };
File without changes
@@ -0,0 +1,90 @@
1
+ import {
2
+ ShelbyBlobClient
3
+ } from "./chunk-EFE5Y7IE.mjs";
4
+ import {
5
+ ShelbyRPCClient
6
+ } from "./chunk-DBTBUKCW.mjs";
7
+ import {
8
+ ShelbyClient
9
+ } from "./chunk-YV67F5NY.mjs";
10
+
11
+ // src/node/clients/ShelbyNodeClient.ts
12
+ var ShelbyNodeClient = class extends ShelbyClient {
13
+ /**
14
+ * The coordination client is used to interact with the Aptos blockchain which handles the commitments
15
+ * and metadata for blobs.
16
+ */
17
+ coordination;
18
+ /**
19
+ * The RPC client is used to interact with the Shelby RPC node which can be responsible for storing,
20
+ * confirming, and retrieving blobs from the storage layer.
21
+ */
22
+ rpc;
23
+ /**
24
+ * The ShelbyNodeClient is used to interact with the Shelby network.
25
+ *
26
+ * @param config.aptos.config - The Aptos config.
27
+ * @param config.shelby.baseUrl - The base URL of the Shelby RPC node. If not provided, the default base URL will be used.
28
+ * @param config.shelby.deployer - The deployer account address of the Shelby contract. If not provided, the default deployer address will be used.
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * const aptos = new Aptos(new AptosConfig({ network: Network.DEVNET }));
33
+ * const client = new ShelbyNodeClient({ aptos, shelby: { baseUrl: "https://api.shelby.dev" } });
34
+ * ```
35
+ */
36
+ constructor(config) {
37
+ super(config);
38
+ this.coordination = new ShelbyBlobClient({
39
+ aptos: this.aptos,
40
+ shelbyDeployer: config.shelby?.deployer
41
+ });
42
+ this.rpc = new ShelbyRPCClient({ aptos: this.aptos });
43
+ }
44
+ /**
45
+ * Uploads a blob to the Shelby network.
46
+ *
47
+ * @param params.blobData - The data to upload.
48
+ * @param params.signer - The signer of the transaction.
49
+ * @param params.blobName - The name of the blob.
50
+ * @param params.expirationMicros - The expiration time of the blob in microseconds.
51
+ * @param params.options - The options for the upload.
52
+ *
53
+ * @returns The transaction and generated blob commitments.
54
+ */
55
+ async upload(params) {
56
+ const { transaction, blobCommitments } = await this.coordination.writeBlobCommitments(params);
57
+ const confirmedTransaction = await this.aptos.waitForTransaction({
58
+ transactionHash: transaction.hash
59
+ });
60
+ await this.rpc.putBlob({
61
+ ...params,
62
+ account: params.signer.accountAddress
63
+ });
64
+ return { transaction: confirmedTransaction, blobCommitments };
65
+ }
66
+ /**
67
+ * Downloads a blob from the Shelby RPC node.
68
+ *
69
+ * @param params.account - The account namespace the blob is stored in (e.g. "0x1")
70
+ * @param params.blobName - The name of the blob (e.g. "foo/bar")
71
+ * @param params.range - The range of the blob to download.
72
+ *
73
+ * @returns A `ShelbyBlob` object containing the blob data.
74
+ *
75
+ * @example
76
+ * ```typescript
77
+ * const blob = await client.download({
78
+ * account,
79
+ * blobName: "foo/bar.txt",
80
+ * });
81
+ * ```
82
+ */
83
+ async download(params) {
84
+ return await this.rpc.getBlob(params);
85
+ }
86
+ };
87
+
88
+ export {
89
+ ShelbyNodeClient
90
+ };