@shelby-protocol/sdk 0.3.0 → 0.4.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 (126) hide show
  1. package/dist/browser/index.d.ts +19 -10
  2. package/dist/browser/index.mjs +4200 -146
  3. package/dist/core/aptos-explorer.mjs +46 -5
  4. package/dist/core/blobs.mjs +12 -4
  5. package/dist/core/chunk.mjs +58 -9
  6. package/dist/core/clients/ShelbyBlobClient.d.ts +155 -83
  7. package/dist/core/clients/ShelbyBlobClient.mjs +1286 -17
  8. package/dist/core/clients/ShelbyClient.d.ts +39 -6
  9. package/dist/core/clients/ShelbyClient.mjs +3233 -23
  10. package/dist/core/clients/ShelbyClientConfig.d.ts +9 -1
  11. package/dist/core/clients/ShelbyClientConfig.mjs +0 -1
  12. package/dist/core/clients/ShelbyMetadataClient.d.ts +20 -6
  13. package/dist/core/clients/ShelbyMetadataClient.mjs +388 -6
  14. package/dist/core/clients/ShelbyMicropaymentChannelClient.d.ts +7 -7
  15. package/dist/core/clients/ShelbyMicropaymentChannelClient.mjs +894 -13
  16. package/dist/core/clients/ShelbyPlacementGroupClient.mjs +310 -8
  17. package/dist/core/clients/ShelbyRPCClient.d.ts +117 -25
  18. package/dist/core/clients/ShelbyRPCClient.mjs +1245 -12
  19. package/dist/core/clients/index.d.ts +4 -2
  20. package/dist/core/clients/index.mjs +3802 -39
  21. package/dist/core/clients/utils.mjs +65 -6
  22. package/dist/core/commitments.d.ts +12 -1
  23. package/dist/core/commitments.mjs +277 -11
  24. package/dist/core/constants.d.ts +3 -3
  25. package/dist/core/constants.mjs +39 -16
  26. package/dist/core/erasure/clay-codes.mjs +129 -4
  27. package/dist/core/erasure/constants.d.ts +16 -1
  28. package/dist/core/erasure/constants.mjs +48 -11
  29. package/dist/core/erasure/default.mjs +191 -9
  30. package/dist/core/erasure/index.d.ts +1 -1
  31. package/dist/core/erasure/index.mjs +281 -24
  32. package/dist/core/erasure/reed-solomon.mjs +68 -4
  33. package/dist/core/erasure/utils.mjs +0 -2
  34. package/dist/core/errors.d.ts +20 -1
  35. package/dist/core/errors.mjs +58 -8
  36. package/dist/core/index.d.ts +9 -9
  37. package/dist/core/index.mjs +4194 -146
  38. package/dist/core/layout.mjs +37 -5
  39. package/dist/core/networks.mjs +10 -5
  40. package/dist/core/operations/generated/sdk.d.ts +807 -42
  41. package/dist/core/operations/generated/sdk.mjs +267 -18
  42. package/dist/core/operations/index.d.ts +1 -1
  43. package/dist/core/operations/index.mjs +368 -24
  44. package/dist/core/promises.mjs +4 -4
  45. package/dist/core/rpc-responses.d.ts +1 -57
  46. package/dist/core/rpc-responses.mjs +14 -15
  47. package/dist/core/shelby-explorer.mjs +31 -6
  48. package/dist/core/sp/chunk_proof.d.ts +23 -0
  49. package/dist/core/sp/chunk_proof.mjs +113 -0
  50. package/dist/core/sp/index.d.ts +3 -0
  51. package/dist/core/sp/index.mjs +402 -0
  52. package/dist/core/sp/sp_write_client.d.ts +53 -0
  53. package/dist/core/sp/sp_write_client.mjs +302 -0
  54. package/dist/core/strings.mjs +0 -2
  55. package/dist/core/types/blobs.d.ts +24 -5
  56. package/dist/core/types/blobs.mjs +24 -1
  57. package/dist/core/types/index.d.ts +2 -2
  58. package/dist/core/types/index.mjs +275 -10
  59. package/dist/core/types/payments.d.ts +6 -6
  60. package/dist/core/types/payments.mjs +230 -5
  61. package/dist/core/types/placement_groups.mjs +0 -1
  62. package/dist/core/types/storage_providers.d.ts +32 -6
  63. package/dist/core/types/storage_providers.mjs +22 -1
  64. package/dist/core/utils.mjs +94 -8
  65. package/dist/gen/rpc_server_pb.d.ts +295 -0
  66. package/dist/gen/rpc_server_pb.mjs +28 -0
  67. package/dist/node/clients/ShelbyNodeClient.d.ts +2 -0
  68. package/dist/node/clients/ShelbyNodeClient.mjs +3237 -24
  69. package/dist/node/clients/index.d.ts +2 -0
  70. package/dist/node/clients/index.mjs +3236 -26
  71. package/dist/node/index.d.ts +9 -9
  72. package/dist/node/index.mjs +4217 -153
  73. package/dist/node/parallel/commitment_worker.d.ts +9 -0
  74. package/dist/node/parallel/commitment_worker.mjs +85 -0
  75. package/dist/node/parallel/commitment_worker_pool.d.ts +35 -0
  76. package/dist/node/parallel/commitment_worker_pool.mjs +339 -0
  77. package/dist/node/parallel/coverage_flush.d.ts +16 -0
  78. package/dist/node/parallel/coverage_flush.mjs +43 -0
  79. package/dist/node/parallel/default_commitment_worker_pool.d.ts +24 -0
  80. package/dist/node/parallel/default_commitment_worker_pool.mjs +355 -0
  81. package/dist/node/parallel/index.d.ts +12 -0
  82. package/dist/node/parallel/index.mjs +631 -0
  83. package/dist/node/parallel/parallel_commitments.d.ts +32 -0
  84. package/dist/node/parallel/parallel_commitments.mjs +614 -0
  85. package/dist/node/parallel/worker_pool.d.ts +74 -0
  86. package/dist/node/parallel/worker_pool.mjs +301 -0
  87. package/dist/node/testUtil.mjs +8 -4
  88. package/package.json +16 -5
  89. package/dist/chunk-3NRBHSMQ.mjs +0 -12
  90. package/dist/chunk-5BVSWXQJ.mjs +0 -801
  91. package/dist/chunk-6FJNAUU5.mjs +0 -278
  92. package/dist/chunk-6XSZRDLJ.mjs +0 -375
  93. package/dist/chunk-7P6ASYW6.mjs +0 -9
  94. package/dist/chunk-A4IG6GSE.mjs +0 -21
  95. package/dist/chunk-AD2G3QYD.mjs +0 -0
  96. package/dist/chunk-AUQDI5BS.mjs +0 -43
  97. package/dist/chunk-AY3HBWXA.mjs +0 -51
  98. package/dist/chunk-BDSW5PHM.mjs +0 -37
  99. package/dist/chunk-C6RQ3AEU.mjs +0 -51
  100. package/dist/chunk-CQ6QPIZK.mjs +0 -37
  101. package/dist/chunk-D6GQHO6G.mjs +0 -15
  102. package/dist/chunk-EM67QTMR.mjs +0 -0
  103. package/dist/chunk-I6NG5GNL.mjs +0 -8
  104. package/dist/chunk-JTXYKO3U.mjs +0 -38
  105. package/dist/chunk-KG2TMLEV.mjs +0 -207
  106. package/dist/chunk-M3CP5TFP.mjs +0 -39
  107. package/dist/chunk-M7W43K2Q.mjs +0 -505
  108. package/dist/chunk-MB7C7VQF.mjs +0 -0
  109. package/dist/chunk-MNCQBEMS.mjs +0 -55
  110. package/dist/chunk-MQUVYMNQ.mjs +0 -0
  111. package/dist/chunk-NEO7Z3ZQ.mjs +0 -49
  112. package/dist/chunk-NHWWORCH.mjs +0 -72
  113. package/dist/chunk-OEK24ON7.mjs +0 -135
  114. package/dist/chunk-QQ57OGQ2.mjs +0 -0
  115. package/dist/chunk-RNNJXTX2.mjs +0 -154
  116. package/dist/chunk-S6Q4OG7H.mjs +0 -83
  117. package/dist/chunk-TET3DJEO.mjs +0 -199
  118. package/dist/chunk-UEZNZBJO.mjs +0 -104
  119. package/dist/chunk-V46D5NBW.mjs +0 -11
  120. package/dist/chunk-V4B3GAMQ.mjs +0 -42
  121. package/dist/chunk-WFWRBNTW.mjs +0 -412
  122. package/dist/chunk-WTICJPDB.mjs +0 -0
  123. package/dist/chunk-XNEIWM4O.mjs +0 -0
  124. package/dist/chunk-Z4FZ7W6L.mjs +0 -39
  125. package/dist/chunk-Z7RFCADT.mjs +0 -0
  126. package/dist/chunk-ZHXCVRZX.mjs +0 -0
@@ -1,165 +1,4219 @@
1
- import "../chunk-MB7C7VQF.mjs";
2
- import {
3
- ShelbyNodeClient
4
- } from "../chunk-V46D5NBW.mjs";
5
- import "../chunk-EM67QTMR.mjs";
6
- import "../chunk-WTICJPDB.mjs";
7
- import {
8
- ShelbyPlacementGroupClient
9
- } from "../chunk-S6Q4OG7H.mjs";
10
- import {
11
- ShelbyClient
12
- } from "../chunk-6XSZRDLJ.mjs";
13
- import {
14
- ShelbyRPCClient
15
- } from "../chunk-WFWRBNTW.mjs";
16
- import {
17
- MissingTransactionSubmitterError,
18
- ShelbyBlobClient
19
- } from "../chunk-5BVSWXQJ.mjs";
20
- import "../chunk-XNEIWM4O.mjs";
21
- import {
22
- ReedSolomonErasureCodingProvider
23
- } from "../chunk-NHWWORCH.mjs";
24
- import {
25
- createDefaultErasureCodingProvider,
26
- defaultErasureCodingConfig,
27
- erasureCodingConfig16Total10Data13Helper,
28
- erasureCodingConfig4Total2Data3Helper
29
- } from "../chunk-AY3HBWXA.mjs";
30
- import {
31
- ClayErasureCodingProvider
32
- } from "../chunk-OEK24ON7.mjs";
33
- import "../chunk-Z7RFCADT.mjs";
34
- import {
35
- ShelbyMetadataClient
36
- } from "../chunk-6FJNAUU5.mjs";
37
- import {
38
- ShelbyMicropaymentChannelClient
39
- } from "../chunk-M7W43K2Q.mjs";
40
- import "../chunk-QQ57OGQ2.mjs";
41
- import "../chunk-MQUVYMNQ.mjs";
42
- import "../chunk-ZHXCVRZX.mjs";
43
- import "../chunk-AD2G3QYD.mjs";
44
- import {
45
- SenderBuiltMicropayment,
46
- StaleChannelStateError
47
- } from "../chunk-KG2TMLEV.mjs";
48
- import {
49
- createShelbyIndexerClient,
50
- getShelbyIndexerClient
51
- } from "../chunk-NEO7Z3ZQ.mjs";
52
- import {
53
- Blob_Activities_Select_Column,
54
- Blobs_Select_Column,
55
- Cursor_Ordering,
56
- GetBlobActivitiesCountDocument,
57
- GetBlobActivitiesDocument,
58
- GetBlobsCountDocument,
59
- GetBlobsDocument,
60
- GetPlacementGroupSlotsCountDocument,
61
- GetPlacementGroupSlotsDocument,
62
- GetProcessorStatusDocument,
63
- GetTotalBlobsSizeDocument,
64
- Order_By,
65
- Placement_Group_Slots_Select_Column,
66
- Processor_Status_Select_Column,
67
- getSdk
68
- } from "../chunk-TET3DJEO.mjs";
69
- import "../chunk-V4B3GAMQ.mjs";
70
- import {
71
- ShelbyErrorCodes,
72
- isAccessDeniedError,
73
- isBlobAlreadyExistsError,
74
- isBlobExpiredError,
75
- isBlobNotFoundError
76
- } from "../chunk-CQ6QPIZK.mjs";
77
- import {
78
- BlobNameSchema,
79
- ChunkKey
80
- } from "../chunk-Z4FZ7W6L.mjs";
81
- import {
82
- isShelbyNetwork,
83
- shelbyNetworks
84
- } from "../chunk-D6GQHO6G.mjs";
85
- import "../chunk-I6NG5GNL.mjs";
86
- import {
87
- ChallengeResponseSchema,
88
- CompleteMultipartUploadResponseSchema,
89
- MultipartUploadStatusResponseSchema,
90
- RPCErrorResponseSchema,
91
- StaleMicropaymentErrorResponseSchema,
92
- StartMultipartUploadResponseSchema,
93
- UploadPartResponseSchema
94
- } from "../chunk-M3CP5TFP.mjs";
95
- import {
96
- getShelbyAccountBlobsExplorerUrl,
97
- getShelbyAccountExplorerUrl,
98
- getShelbyBlobExplorerUrl
99
- } from "../chunk-BDSW5PHM.mjs";
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, { get: all[name], enumerable: true });
5
+ };
6
+
7
+ // src/core/aptos-explorer.ts
8
+ import { Network } from "@aptos-labs/ts-sdk";
9
+ function getAptosExplorerBaseUrl(network) {
10
+ const normalizedNetwork = network.toLowerCase();
11
+ switch (normalizedNetwork) {
12
+ case Network.MAINNET.toLowerCase():
13
+ return "https://explorer.aptoslabs.com";
14
+ case Network.TESTNET.toLowerCase():
15
+ return "https://explorer.aptoslabs.com";
16
+ case Network.DEVNET.toLowerCase():
17
+ return "https://explorer.aptoslabs.com";
18
+ case Network.LOCAL.toLowerCase():
19
+ return "https://explorer.aptoslabs.com";
20
+ case Network.SHELBYNET.toLowerCase():
21
+ return "https://explorer.aptoslabs.com";
22
+ default:
23
+ return "https://explorer.aptoslabs.com";
24
+ }
25
+ }
26
+ function getAptosExplorerNetworkParam(network) {
27
+ const normalizedNetwork = network.toLowerCase();
28
+ switch (normalizedNetwork) {
29
+ case Network.MAINNET.toLowerCase():
30
+ return "mainnet";
31
+ case Network.TESTNET.toLowerCase():
32
+ return "testnet";
33
+ case Network.DEVNET.toLowerCase():
34
+ return "devnet";
35
+ case Network.LOCAL.toLowerCase():
36
+ return "local";
37
+ case Network.SHELBYNET.toLowerCase():
38
+ return "shelbynet";
39
+ default:
40
+ return normalizedNetwork;
41
+ }
42
+ }
43
+ function getAptosTransactionExplorerUrl(network, transactionHash) {
44
+ const baseUrl = getAptosExplorerBaseUrl(network);
45
+ const networkParam = getAptosExplorerNetworkParam(network);
46
+ return `${baseUrl}/txn/${transactionHash}?network=${networkParam}`;
47
+ }
48
+ function getAptosAccountExplorerUrl(network, accountAddress) {
49
+ const baseUrl = getAptosExplorerBaseUrl(network);
50
+ const networkParam = getAptosExplorerNetworkParam(network);
51
+ return `${baseUrl}/account/${accountAddress}?network=${networkParam}`;
52
+ }
53
+
54
+ // src/core/utils.ts
100
55
  import {
101
- testUtil_exports
102
- } from "../chunk-A4IG6GSE.mjs";
56
+ AccountAddress,
57
+ Hex
58
+ } from "@aptos-labs/ts-sdk";
59
+ async function* readInChunks(input, chunkSize) {
60
+ let idx = 0;
61
+ if (isReadableStream(input)) {
62
+ const reader = input.getReader();
63
+ let buffer = new Uint8Array(chunkSize);
64
+ let bufferWriteOffset = 0;
65
+ try {
66
+ while (true) {
67
+ const { value, done } = await reader.read();
68
+ if (done) break;
69
+ if (value === void 0) continue;
70
+ let srcOffset = 0;
71
+ while (srcOffset < value.length) {
72
+ const remainingCapacity = chunkSize - bufferWriteOffset;
73
+ const bytesToCopy = Math.min(
74
+ remainingCapacity,
75
+ value.length - srcOffset
76
+ );
77
+ buffer.set(
78
+ value.subarray(srcOffset, srcOffset + bytesToCopy),
79
+ bufferWriteOffset
80
+ );
81
+ bufferWriteOffset += bytesToCopy;
82
+ srcOffset += bytesToCopy;
83
+ if (bufferWriteOffset >= chunkSize) {
84
+ yield [idx++, buffer];
85
+ buffer = new Uint8Array(chunkSize);
86
+ bufferWriteOffset = 0;
87
+ }
88
+ }
89
+ }
90
+ } finally {
91
+ reader.releaseLock();
92
+ }
93
+ if (bufferWriteOffset > 0) {
94
+ yield [idx++, buffer.subarray(0, bufferWriteOffset)];
95
+ }
96
+ return;
97
+ }
98
+ const view = toUint8Array(input);
99
+ for (let offset = 0; offset < view.byteLength; offset += chunkSize) {
100
+ yield [
101
+ idx++,
102
+ view.subarray(offset, Math.min(offset + chunkSize, view.byteLength))
103
+ ];
104
+ }
105
+ }
106
+ function zeroPadBytes(buffer, desiredLength) {
107
+ if (buffer.byteLength === desiredLength) {
108
+ return buffer;
109
+ }
110
+ if (buffer.byteLength > desiredLength) {
111
+ return buffer.subarray(0, desiredLength);
112
+ }
113
+ const paddedBuffer = new Uint8Array(desiredLength);
114
+ paddedBuffer.set(buffer);
115
+ return paddedBuffer;
116
+ }
117
+ async function concatHashes(parts) {
118
+ const chunks = parts.map((part) => Hex.fromHexInput(part).toUint8Array());
119
+ const totalLength = chunks.reduce((sum, chunk) => sum + chunk.byteLength, 0);
120
+ const combined = new Uint8Array(totalLength);
121
+ let offset = 0;
122
+ for (const chunk of chunks) {
123
+ combined.set(chunk, offset);
124
+ offset += chunk.byteLength;
125
+ }
126
+ return Hex.fromHexInput(
127
+ new Uint8Array(await crypto.subtle.digest("SHA-256", combined))
128
+ );
129
+ }
130
+ function isReadableStream(value) {
131
+ return typeof value === "object" && value !== null && "getReader" in value && typeof value.getReader === "function";
132
+ }
133
+ function toUint8Array(view) {
134
+ return view instanceof Uint8Array ? view : new Uint8Array(view.buffer, view.byteOffset, view.byteLength);
135
+ }
136
+ function buildRequestUrl(path, baseUrl) {
137
+ const baseHasSlash = baseUrl.endsWith("/");
138
+ const safeBase = baseHasSlash ? baseUrl : `${baseUrl}/`;
139
+ const safePath = path.replace(/^\/+/, "");
140
+ return new URL(safePath, safeBase);
141
+ }
142
+ function getBlobNameSuffix(blobName) {
143
+ const parts = blobName.split("/");
144
+ return parts.slice(1).join("/") || "";
145
+ }
146
+ function normalizeAddress(address) {
147
+ return AccountAddress.from(address, { maxMissingChars: 63 });
148
+ }
149
+
150
+ // src/core/blobs.ts
151
+ var createBlobKey = (params) => {
152
+ return `@${normalizeAddress(params.account).toStringLongWithoutPrefix()}/${params.blobName}`;
153
+ };
154
+
155
+ // src/core/erasure/constants.ts
156
+ var ErasureCodingScheme = /* @__PURE__ */ ((ErasureCodingScheme2) => {
157
+ ErasureCodingScheme2["ClayCode_16Total_10Data_13Helper"] = "ClayCode_16Total_10Data_13Helper";
158
+ ErasureCodingScheme2["ClayCode_4Total_2Data_3Helper"] = "ClayCode_4Total_2Data_3Helper";
159
+ return ErasureCodingScheme2;
160
+ })(ErasureCodingScheme || {});
161
+ var ERASURE_CODE_PARAMS = {
162
+ ["ClayCode_16Total_10Data_13Helper" /* ClayCode_16Total_10Data_13Helper */]: {
163
+ // total chunks (data + parity)
164
+ erasure_n: 16,
165
+ // data chunks
166
+ erasure_k: 10,
167
+ // helper nodes
168
+ erasure_d: 13,
169
+ // enum index
170
+ enumIndex: 0
171
+ },
172
+ ["ClayCode_4Total_2Data_3Helper" /* ClayCode_4Total_2Data_3Helper */]: {
173
+ // total chunks (data + parity)
174
+ erasure_n: 4,
175
+ // data chunks
176
+ erasure_k: 2,
177
+ // helper nodes
178
+ erasure_d: 3,
179
+ // enum index
180
+ enumIndex: 1
181
+ }
182
+ };
183
+ function findErasureSchemeByErasureN(erasureN) {
184
+ return Object.entries(ERASURE_CODE_PARAMS).find(
185
+ ([, params]) => params.erasure_n === erasureN
186
+ );
187
+ }
188
+ function requiredAckCount(erasureN) {
189
+ const scheme = findErasureSchemeByErasureN(erasureN);
190
+ if (!scheme) {
191
+ throw new Error(`Unknown erasure coding scheme with erasure_n=${erasureN}`);
192
+ }
193
+ return scheme[1].erasure_d;
194
+ }
195
+ var DEFAULT_ERASURE_N = ERASURE_CODE_PARAMS["ClayCode_16Total_10Data_13Helper" /* ClayCode_16Total_10Data_13Helper */].erasure_n;
196
+ var DEFAULT_ERASURE_K = ERASURE_CODE_PARAMS["ClayCode_16Total_10Data_13Helper" /* ClayCode_16Total_10Data_13Helper */].erasure_k;
197
+ var DEFAULT_ERASURE_D = ERASURE_CODE_PARAMS["ClayCode_16Total_10Data_13Helper" /* ClayCode_16Total_10Data_13Helper */].erasure_d;
198
+ var DEFAULT_ERASURE_M = DEFAULT_ERASURE_N - DEFAULT_ERASURE_K;
199
+ var DEFAULT_SAMPLE_SIZE = 1024;
200
+
201
+ // src/core/chunk.ts
202
+ var ChunkSizeScheme = /* @__PURE__ */ ((ChunkSizeScheme2) => {
203
+ ChunkSizeScheme2["ChunkSet10MiB_Chunk1MiB"] = "ChunkSet10MiB_Chunk1MiB";
204
+ ChunkSizeScheme2["ChunkSet2MiB_Chunk1MiB"] = "ChunkSet2MiB_Chunk1MiB";
205
+ return ChunkSizeScheme2;
206
+ })(ChunkSizeScheme || {});
207
+ var CHUNK_SIZE_PARAMS = {
208
+ ["ChunkSet10MiB_Chunk1MiB" /* ChunkSet10MiB_Chunk1MiB */]: {
209
+ // 1MiB
210
+ chunkSizeBytes: 1 * 1024 * 1024,
211
+ // 10MiB
212
+ chunksetSizeBytes: 10 * 1024 * 1024
213
+ },
214
+ ["ChunkSet2MiB_Chunk1MiB" /* ChunkSet2MiB_Chunk1MiB */]: {
215
+ // 1MiB
216
+ chunkSizeBytes: 1 * 1024 * 1024,
217
+ // 2MiB
218
+ chunksetSizeBytes: 2 * 1024 * 1024
219
+ }
220
+ };
221
+ var DEFAULT_CHUNK_SIZE_BYTES = CHUNK_SIZE_PARAMS["ChunkSet10MiB_Chunk1MiB" /* ChunkSet10MiB_Chunk1MiB */].chunkSizeBytes;
222
+ var DEFAULT_CHUNKSET_SIZE_BYTES = CHUNK_SIZE_PARAMS["ChunkSet10MiB_Chunk1MiB" /* ChunkSet10MiB_Chunk1MiB */].chunksetSizeBytes;
223
+ var ERASURE_CODE_AND_CHUNK_MAPPING = {
224
+ ["ClayCode_16Total_10Data_13Helper" /* ClayCode_16Total_10Data_13Helper */]: {
225
+ ...CHUNK_SIZE_PARAMS.ChunkSet10MiB_Chunk1MiB
226
+ },
227
+ ["ClayCode_4Total_2Data_3Helper" /* ClayCode_4Total_2Data_3Helper */]: {
228
+ ...CHUNK_SIZE_PARAMS.ChunkSet2MiB_Chunk1MiB
229
+ }
230
+ };
231
+
232
+ // src/core/clients/ShelbyBlobClient.ts
103
233
  import {
104
- getAptosAccountExplorerUrl,
105
- getAptosTransactionExplorerUrl
106
- } from "../chunk-C6RQ3AEU.mjs";
234
+ AccountAddress as AccountAddress2,
235
+ Aptos,
236
+ Hex as Hex3,
237
+ U32
238
+ } from "@aptos-labs/ts-sdk";
239
+
240
+ // src/core/commitments.ts
241
+ import { Hex as Hex2 } from "@aptos-labs/ts-sdk";
242
+ import { z } from "zod";
243
+ var COMMITMENT_SCHEMA_VERSION = "1.3";
244
+ var ChunksetCommitmentSchema = z.object({
245
+ // Chunkset root (vector commitment of child chunks)
246
+ chunkset_root: z.string(),
247
+ // the size is known statically from the current configuration
248
+ chunk_commitments: z.array(z.string())
249
+ }).refine(
250
+ (data) => {
251
+ return data.chunk_commitments.length === DEFAULT_ERASURE_K + DEFAULT_ERASURE_M;
252
+ },
253
+ {
254
+ message: `Chunkset must have exactly ${DEFAULT_ERASURE_K + DEFAULT_ERASURE_M} chunks (ERASURE_K + ERASURE_M = ${DEFAULT_ERASURE_K} + ${DEFAULT_ERASURE_M})`,
255
+ path: ["chunk_commitments"]
256
+ }
257
+ );
258
+ function expectedTotalChunksets(rawSize, chunksetSize = DEFAULT_CHUNKSET_SIZE_BYTES) {
259
+ if (chunksetSize <= 0) {
260
+ throw new Error("chunksetSize must be positive");
261
+ }
262
+ if (rawSize === 0) return 1;
263
+ return Math.ceil(rawSize / chunksetSize);
264
+ }
265
+ function expectedChunksetInclusionProofHashes(numChunksets) {
266
+ if (numChunksets < 1) {
267
+ throw new Error("numChunksets must be positive");
268
+ }
269
+ return Math.ceil(Math.log2(numChunksets));
270
+ }
271
+ var BlobCommitmentsSchema = z.object({
272
+ schema_version: z.string(),
273
+ raw_data_size: z.number(),
274
+ // FIXME I am not sure about this being here, or if it should be somewhere else
275
+ blob_merkle_root: z.string(),
276
+ chunkset_commitments: z.array(ChunksetCommitmentSchema)
277
+ }).refine(
278
+ (data) => {
279
+ return expectedTotalChunksets(data.raw_data_size) === data.chunkset_commitments.length;
280
+ },
281
+ {
282
+ message: "Total chunkset count mismatches with raw data size",
283
+ // FIXME put more details in here
284
+ path: ["chunkset_commitments"]
285
+ }
286
+ );
287
+ async function generateMerkleRoot(leafHashes) {
288
+ if (!leafHashes.length) {
289
+ throw new Error(
290
+ "An empty array cannot be used to construct a Merkle tree."
291
+ );
292
+ }
293
+ const zeroArray = new Uint8Array(leafHashes[0].toUint8Array().length);
294
+ const zeroBytes = Hex2.fromHexInput(zeroArray);
295
+ let currentLeaves = leafHashes;
296
+ while (currentLeaves.length > 1) {
297
+ if (currentLeaves.length % 2 !== 0) {
298
+ currentLeaves.push(zeroBytes);
299
+ }
300
+ const nextLeaves = [];
301
+ for (let i = 0; i < currentLeaves.length; i += 2) {
302
+ nextLeaves.push(
303
+ await concatHashes([
304
+ currentLeaves[i].toUint8Array(),
305
+ currentLeaves[i + 1].toUint8Array()
306
+ ])
307
+ );
308
+ }
309
+ currentLeaves = nextLeaves;
310
+ }
311
+ return currentLeaves[0];
312
+ }
313
+ async function generateChunksetCommitments(chunksetIdx, chunksetData, expectedChunksetSize, provider, onChunk) {
314
+ const { erasure_n } = provider.config;
315
+ const chunksetPayload = zeroPadBytes(chunksetData, expectedChunksetSize);
316
+ const { chunks } = provider.encode(chunksetPayload);
317
+ if (chunks.length !== erasure_n) {
318
+ throw new Error(
319
+ `Erasure provider produced ${chunks.length} chunks, expected ${erasure_n}.`
320
+ );
321
+ }
322
+ const chunkRoots = provider.getChunkMerkleRoots();
323
+ let chunkIdx = 0;
324
+ for (const chunkData of chunks) {
325
+ if (onChunk !== void 0) {
326
+ await onChunk(chunksetIdx, chunkIdx, chunkData);
327
+ }
328
+ chunkIdx += 1;
329
+ }
330
+ const a = await generateMerkleRoot(
331
+ chunkRoots.map((a2) => Hex2.fromHexInput(a2))
332
+ );
333
+ const entry = {
334
+ chunkset_root: a.toString(),
335
+ chunk_commitments: chunkRoots.map(
336
+ (chunk) => Hex2.fromHexInput(chunk).toString()
337
+ )
338
+ };
339
+ return { h: a, entry };
340
+ }
341
+ async function generateCommitments(provider, fullData, onChunk) {
342
+ const expectedChunksetSize = provider.config.chunkSizeBytes * provider.config.erasure_k;
343
+ const chunksetCommitments = [];
344
+ const chunksetCommitmentHashes = [];
345
+ let rawDataSize = 0;
346
+ const chunksetGen = readInChunks(fullData, expectedChunksetSize);
347
+ for await (const [chunksetIdx, chunksetData] of chunksetGen) {
348
+ rawDataSize += chunksetData.length;
349
+ const { h, entry } = await generateChunksetCommitments(
350
+ chunksetIdx,
351
+ chunksetData,
352
+ expectedChunksetSize,
353
+ provider,
354
+ onChunk
355
+ );
356
+ chunksetCommitments.push(entry);
357
+ chunksetCommitmentHashes.push(h);
358
+ }
359
+ if (rawDataSize === 0) {
360
+ const zeroChunkset = new Uint8Array(expectedChunksetSize);
361
+ const { h, entry } = await generateChunksetCommitments(
362
+ 0,
363
+ zeroChunkset,
364
+ expectedChunksetSize,
365
+ provider,
366
+ onChunk
367
+ );
368
+ chunksetCommitments.push(entry);
369
+ chunksetCommitmentHashes.push(h);
370
+ }
371
+ return {
372
+ schema_version: COMMITMENT_SCHEMA_VERSION,
373
+ raw_data_size: rawDataSize,
374
+ blob_merkle_root: (await generateMerkleRoot(chunksetCommitmentHashes)).toString(),
375
+ chunkset_commitments: chunksetCommitments
376
+ };
377
+ }
378
+
379
+ // src/core/constants.ts
380
+ import { Network as Network2 } from "@aptos-labs/ts-sdk";
381
+ var DEFAULT_PROJECT_NAME = "shelby";
382
+ var DEFAULT_PROJECT_DESCRIPTION = "High performance, decentralized storage";
383
+ var NetworkToShelbyRPCBaseUrl = {
384
+ [Network2.SHELBYNET]: "https://shelby.shelbynet.shelby.xyz/shelby",
385
+ [Network2.NETNA]: void 0,
386
+ [Network2.DEVNET]: void 0,
387
+ [Network2.TESTNET]: "https://api.testnet.shelby.xyz/shelby",
388
+ [Network2.MAINNET]: void 0,
389
+ [Network2.LOCAL]: "http://localhost:9090",
390
+ [Network2.CUSTOM]: void 0
391
+ };
392
+ var NetworkToShelbyBlobIndexerBaseUrl = {
393
+ [Network2.SHELBYNET]: "https://api.shelbynet.aptoslabs.com/nocode/v1/public/alias/shelby/shelbynet/v1/graphql",
394
+ [Network2.NETNA]: void 0,
395
+ [Network2.DEVNET]: void 0,
396
+ [Network2.TESTNET]: "https://api.testnet.aptoslabs.com/nocode/v1/public/alias/shelby/testnet/v1/graphql",
397
+ [Network2.MAINNET]: void 0,
398
+ [Network2.LOCAL]: "http://localhost:8091/v1/graphql",
399
+ [Network2.CUSTOM]: void 0
400
+ };
401
+ var NetworkToGasStationBaseUrl = {
402
+ [Network2.SHELBYNET]: "https://api.shelbynet.shelby.xyz/gs/v1",
403
+ [Network2.NETNA]: void 0,
404
+ [Network2.DEVNET]: void 0,
405
+ [Network2.TESTNET]: "https://api.testnet.shelby.xyz/gs/v1",
406
+ [Network2.MAINNET]: void 0,
407
+ [Network2.LOCAL]: void 0,
408
+ [Network2.CUSTOM]: void 0
409
+ };
410
+ var SHELBY_DEPLOYER = "0x85fdb9a176ab8ef1d9d9c1b60d60b3924f0800ac1de1cc2085fb0b8bb4988e6a";
411
+ var MICROPAYMENTS_DEPLOYER = "0x1ae7275148bf6ef742b658fd9cbcc2e094201606f4a7bc707bab0201da8043ee";
412
+ var TOKEN_DEPLOYER = "0x33009e852be7f93762dd0bf303383c2cb2c5cab7a30d8238ca5f9f177ae75124";
413
+ var TOKEN_OBJECT_ADDRESS = "0x249f5c642a63885ff88a5113b3ba0079840af5a1357706f8c7f3bfc5dd12511f";
414
+ var SHELBYUSD_TOKEN_ADDRESS = TOKEN_OBJECT_ADDRESS;
415
+ var SHELBYUSD_TOKEN_MODULE = "shelby_usd";
416
+ var SHELBYUSD_TOKEN_NAME = "ShelbyUSD";
417
+ var SHELBYUSD_FA_METADATA_ADDRESS = "0x1b18363a9f1fe5e6ebf247daba5cc1c18052bb232efdc4c50f556053922d98e1";
418
+
419
+ // src/core/types/blobs.ts
420
+ var BLOB_ENCRYPTION_TO_MOVE_ENUM_INDEX = {
421
+ Unencrypted: 0,
422
+ AES_GCM_V1: 1
423
+ };
424
+ function blobEncryptionToMoveEnumIndex(encryption) {
425
+ return BLOB_ENCRYPTION_TO_MOVE_ENUM_INDEX[encryption];
426
+ }
427
+ function blobEncryptionFromMoveVariant(variant) {
428
+ switch (variant) {
429
+ case "Unencrypted":
430
+ return "Unencrypted";
431
+ case "AES_GCM_V1":
432
+ return "AES_GCM_V1";
433
+ default:
434
+ throw new Error(
435
+ "Could not parse encryption from Shelby Smart Contract, this SDK is out of date."
436
+ );
437
+ }
438
+ }
439
+
440
+ // src/core/erasure/clay-codes.ts
107
441
  import {
108
- createBlobKey
109
- } from "../chunk-3NRBHSMQ.mjs";
442
+ createDecoder,
443
+ createEncoder
444
+ } from "@shelby-protocol/clay-codes";
445
+ function getTotalChunks(config) {
446
+ return config.erasure_n;
447
+ }
448
+ var ClayErasureCodingProvider = class _ClayErasureCodingProvider {
449
+ config;
450
+ encoderCache;
451
+ decoderCache;
452
+ lastFunction;
453
+ constructor(config) {
454
+ this.config = config;
455
+ this.lastFunction = "none" /* NONE */;
456
+ }
457
+ /**
458
+ * Static factory method to create an initialized ClayErasureCodingProvider
459
+ */
460
+ static async create(config) {
461
+ const provider = new _ClayErasureCodingProvider(config);
462
+ [provider.encoderCache, provider.decoderCache] = await Promise.all([
463
+ createEncoder({
464
+ n: getTotalChunks(config),
465
+ k: config.erasure_k,
466
+ d: config.erasure_d,
467
+ chunkSizeBytes: config.chunkSizeBytes
468
+ }),
469
+ createDecoder({
470
+ n: getTotalChunks(config),
471
+ k: config.erasure_k,
472
+ d: config.erasure_d,
473
+ chunkSizeBytes: config.chunkSizeBytes,
474
+ erasedChunkIndexes: []
475
+ })
476
+ ]);
477
+ return provider;
478
+ }
479
+ encode(data) {
480
+ const { erasure_k, chunkSizeBytes } = this.config;
481
+ if (!this.encoderCache) {
482
+ throw new Error("Encoder cache is missing");
483
+ }
484
+ const systematicCapacity = erasure_k * chunkSizeBytes;
485
+ if (data.byteLength > systematicCapacity) {
486
+ throw new Error(
487
+ `Data size ${data.byteLength} bytes exceeds systematic capacity ${systematicCapacity} bytes (erasure_k=${erasure_k} * chunkSizeBytes=${chunkSizeBytes}).`
488
+ );
489
+ }
490
+ if (this.requiresPadding(data.length)) {
491
+ throw new Error(
492
+ `Data size ${data.length} bytes does not match systematic capacity ${systematicCapacity} bytes (erasure_k=${erasure_k} * chunkSizeBytes=${chunkSizeBytes}). Provide pre-padded data before encoding.`
493
+ );
494
+ }
495
+ this.lastFunction = "encoded" /* ENCODED */;
496
+ return this.encoderCache.erasureCode(data);
497
+ }
498
+ decode(available, config) {
499
+ if (!this.decoderCache) {
500
+ throw new Error("Decoder cache is missing");
501
+ }
502
+ const { erasure_k, chunkSizeBytes } = this.config;
503
+ if (available.length < erasure_k) {
504
+ throw new Error(
505
+ `Insufficient available chunks: need at least ${erasure_k}, received ${available.length}.`
506
+ );
507
+ }
508
+ for (let i = 0; i < available.length; i++) {
509
+ const chunk = available[i];
510
+ if (chunk.length !== chunkSizeBytes) {
511
+ throw new Error(
512
+ `Chunk ${i} size ${chunk.length} bytes does not match expected chunkSizeBytes ${chunkSizeBytes}.`
513
+ );
514
+ }
515
+ }
516
+ this.lastFunction = "decoded" /* DECODED */;
517
+ return this.decoderCache.decode(available, config);
518
+ }
519
+ getChunkMerkleRoots() {
520
+ if (this.decoderCache && this.lastFunction === "decoded" /* DECODED */)
521
+ return this.decoderCache.getChunkMerkleRoots();
522
+ if (this.encoderCache && this.lastFunction === "encoded" /* ENCODED */)
523
+ return this.encoderCache.getChunkMerkleRoots();
524
+ throw new Error(
525
+ "You must call encode or decode before calling getChunkMerkleRoots"
526
+ );
527
+ }
528
+ /**
529
+ * Determines if data can be erasure coded as-is or requires padding.
530
+ *
531
+ * Data can be erasure coded without padding if its size exactly matches
532
+ * the total systematic data capacity (k * chunkSizeBytes).
533
+ *
534
+ * @param dataSize - Size of the data in bytes
535
+ * @returns true if data needs padding, false if it can be coded as-is
536
+ */
537
+ requiresPadding(dataSize) {
538
+ const { erasure_k, chunkSizeBytes } = this.config;
539
+ const systematicCapacity = erasure_k * chunkSizeBytes;
540
+ return dataSize !== systematicCapacity;
541
+ }
542
+ };
543
+
544
+ // src/core/erasure/default.ts
545
+ var defaultProviderPromise;
546
+ function createDefaultErasureCodingProvider() {
547
+ if (!defaultProviderPromise) {
548
+ defaultProviderPromise = ClayErasureCodingProvider.create(
549
+ defaultErasureCodingConfig()
550
+ );
551
+ }
552
+ return defaultProviderPromise;
553
+ }
554
+ function defaultErasureCodingConfig() {
555
+ const encoding = Number(process.env.SHELBY_ENCODING) || 0;
556
+ if (encoding === 0) {
557
+ return erasureCodingConfig16Total10Data13Helper();
558
+ }
559
+ return erasureCodingConfig4Total2Data3Helper();
560
+ }
561
+ function erasureCodingConfig16Total10Data13Helper() {
562
+ return erasureCodingConfig(
563
+ "ClayCode_16Total_10Data_13Helper" /* ClayCode_16Total_10Data_13Helper */
564
+ );
565
+ }
566
+ function erasureCodingConfig4Total2Data3Helper() {
567
+ return erasureCodingConfig("ClayCode_4Total_2Data_3Helper" /* ClayCode_4Total_2Data_3Helper */);
568
+ }
569
+ function erasureCodingConfig(encodingScheme) {
570
+ return {
571
+ erasure_n: ERASURE_CODE_PARAMS[encodingScheme].erasure_n,
572
+ erasure_k: ERASURE_CODE_PARAMS[encodingScheme].erasure_k,
573
+ erasure_d: ERASURE_CODE_PARAMS[encodingScheme].erasure_d,
574
+ chunkSizeBytes: DEFAULT_CHUNK_SIZE_BYTES,
575
+ enumIndex: ERASURE_CODE_PARAMS[encodingScheme].enumIndex
576
+ };
577
+ }
578
+
579
+ // src/core/erasure/reed-solomon.ts
580
+ import { createWasmReedSolomonBinding } from "@shelby-protocol/reed-solomon";
581
+ var DEFAULT_ERASURE_K2 = 10;
582
+ var DEFAULT_ERASURE_N2 = 16;
583
+ var DEFAULT_CHUNK_SIZE_BYTES2 = 2 * 1024 * 1024;
584
+ var ReedSolomonErasureCodingProvider = class {
585
+ config;
586
+ constructor(options) {
587
+ const erasure_k = options?.erasure_k ?? DEFAULT_ERASURE_K2;
588
+ const erasure_n = options?.erasure_n ?? DEFAULT_ERASURE_N2;
589
+ const chunkSizeBytes = options?.chunkSizeBytes ?? DEFAULT_CHUNK_SIZE_BYTES2;
590
+ const enumIndex = -1;
591
+ if (erasure_k <= 0)
592
+ throw new Error("erasure_k (number of data chunks) must be > 0");
593
+ if (erasure_n <= erasure_k)
594
+ throw new Error(
595
+ `erasure_n (${erasure_n}) must be > erasure_k (${erasure_k})`
596
+ );
597
+ if (chunkSizeBytes <= 0) throw new Error("chunkSizeBytes must be > 0");
598
+ this.config = {
599
+ erasure_n,
600
+ erasure_k,
601
+ chunkSizeBytes,
602
+ enumIndex
603
+ };
604
+ }
605
+ encode(data) {
606
+ const { erasure_k, erasure_n, chunkSizeBytes } = this.config;
607
+ const erasure_m = erasure_n - erasure_k;
608
+ const systematicCapacity = erasure_k * chunkSizeBytes;
609
+ if (data.byteLength > systematicCapacity) {
610
+ throw new Error(
611
+ `Data size ${data.byteLength} bytes exceeds systematic capacity ${systematicCapacity} bytes (erasure_k=${erasure_k} * chunkSizeBytes=${chunkSizeBytes}).`
612
+ );
613
+ }
614
+ if (data.byteLength !== systematicCapacity) {
615
+ throw new Error(
616
+ `Data size ${data.byteLength} bytes does not match systematic capacity ${systematicCapacity} bytes (erasure_k=${erasure_k} * chunkSizeBytes=${chunkSizeBytes}). Provide pre-padded data before encoding.`
617
+ );
618
+ }
619
+ const reedSolomon = createWasmReedSolomonBinding();
620
+ const shards = new Uint8Array(
621
+ systematicCapacity + erasure_m * chunkSizeBytes
622
+ );
623
+ shards.set(data, 0);
624
+ reedSolomon.encode(shards, erasure_k, erasure_m);
625
+ const chunks = new Array(erasure_n);
626
+ for (let idx = 0; idx < erasure_n; idx++) {
627
+ const start = idx * chunkSizeBytes;
628
+ chunks[idx] = shards.slice(start, start + chunkSizeBytes);
629
+ }
630
+ return {
631
+ chunks,
632
+ systematic: chunks.slice(0, erasure_k),
633
+ parity: chunks.slice(erasure_k)
634
+ };
635
+ }
636
+ decode(_available, _config) {
637
+ throw new Error(
638
+ "ReedSolomonErasureCodingProvider does not implement decode"
639
+ );
640
+ }
641
+ getChunkMerkleRoots() {
642
+ throw new Error(
643
+ "ReedSolomonErasureCodingProvider does not implement getChunkMerkleRoots"
644
+ );
645
+ }
646
+ };
647
+
648
+ // src/core/operations/index.ts
649
+ import { Network as Network3 } from "@aptos-labs/ts-sdk";
650
+ import { GraphQLClient } from "graphql-request";
651
+
652
+ // src/core/clients/utils.ts
653
+ import { AptosConfig } from "@aptos-labs/ts-sdk";
654
+ var getAptosConfig = (config) => {
655
+ const baseFaucetConfig = config.faucet?.authToken ? { AUTH_TOKEN: config.faucet.authToken } : void 0;
656
+ if (config.aptos) {
657
+ return new AptosConfig({
658
+ // Spread user's aptos config first
659
+ ...config.aptos,
660
+ // Network from top-level is authoritative - cannot be overridden
661
+ network: config.network,
662
+ // Merge clientConfig with API_KEY default
663
+ clientConfig: {
664
+ API_KEY: config.apiKey,
665
+ ...config.aptos.clientConfig
666
+ },
667
+ // Merge faucetConfig: aptos config first, then base authToken (authoritative)
668
+ faucetConfig: {
669
+ ...config.aptos.faucetConfig,
670
+ ...baseFaucetConfig
671
+ }
672
+ });
673
+ }
674
+ return new AptosConfig({
675
+ network: config.network,
676
+ clientConfig: {
677
+ API_KEY: config.apiKey
678
+ },
679
+ faucetConfig: baseFaucetConfig
680
+ });
681
+ };
682
+ var getShelbyRPCBaseUrl = (config) => {
683
+ return config.rpc?.baseUrl ?? NetworkToShelbyRPCBaseUrl[config.network] ?? NetworkToShelbyRPCBaseUrl.testnet;
684
+ };
685
+
686
+ // src/core/operations/generated/sdk.ts
687
+ import gql from "graphql-tag";
688
+ var Blob_Activities_Constraint = /* @__PURE__ */ ((Blob_Activities_Constraint2) => {
689
+ Blob_Activities_Constraint2["BlobActivitiesPkey"] = "blob_activities_pkey";
690
+ return Blob_Activities_Constraint2;
691
+ })(Blob_Activities_Constraint || {});
692
+ var Blob_Activities_Select_Column = /* @__PURE__ */ ((Blob_Activities_Select_Column2) => {
693
+ Blob_Activities_Select_Column2["EventIndex"] = "event_index";
694
+ Blob_Activities_Select_Column2["EventType"] = "event_type";
695
+ Blob_Activities_Select_Column2["ObjectName"] = "object_name";
696
+ Blob_Activities_Select_Column2["Owner"] = "owner";
697
+ Blob_Activities_Select_Column2["Timestamp"] = "timestamp";
698
+ Blob_Activities_Select_Column2["TransactionHash"] = "transaction_hash";
699
+ Blob_Activities_Select_Column2["TransactionVersion"] = "transaction_version";
700
+ Blob_Activities_Select_Column2["Uid"] = "uid";
701
+ return Blob_Activities_Select_Column2;
702
+ })(Blob_Activities_Select_Column || {});
703
+ var Blob_Activities_Update_Column = /* @__PURE__ */ ((Blob_Activities_Update_Column2) => {
704
+ Blob_Activities_Update_Column2["EventIndex"] = "event_index";
705
+ Blob_Activities_Update_Column2["EventType"] = "event_type";
706
+ Blob_Activities_Update_Column2["ObjectName"] = "object_name";
707
+ Blob_Activities_Update_Column2["Owner"] = "owner";
708
+ Blob_Activities_Update_Column2["Timestamp"] = "timestamp";
709
+ Blob_Activities_Update_Column2["TransactionHash"] = "transaction_hash";
710
+ Blob_Activities_Update_Column2["TransactionVersion"] = "transaction_version";
711
+ Blob_Activities_Update_Column2["Uid"] = "uid";
712
+ return Blob_Activities_Update_Column2;
713
+ })(Blob_Activities_Update_Column || {});
714
+ var Blobs_Constraint = /* @__PURE__ */ ((Blobs_Constraint2) => {
715
+ Blobs_Constraint2["BlobsPkey"] = "blobs_pkey";
716
+ return Blobs_Constraint2;
717
+ })(Blobs_Constraint || {});
718
+ var Blobs_Select_Column = /* @__PURE__ */ ((Blobs_Select_Column2) => {
719
+ Blobs_Select_Column2["BlobCommitment"] = "blob_commitment";
720
+ Blobs_Select_Column2["CreatedAt"] = "created_at";
721
+ Blobs_Select_Column2["DeletionReason"] = "deletion_reason";
722
+ Blobs_Select_Column2["Encoding"] = "encoding";
723
+ Blobs_Select_Column2["Encryption"] = "encryption";
724
+ Blobs_Select_Column2["Etag"] = "etag";
725
+ Blobs_Select_Column2["ExpiresAt"] = "expires_at";
726
+ Blobs_Select_Column2["IsCommitted"] = "is_committed";
727
+ Blobs_Select_Column2["IsDeleted"] = "is_deleted";
728
+ Blobs_Select_Column2["IsPersisted"] = "is_persisted";
729
+ Blobs_Select_Column2["NumChunksets"] = "num_chunksets";
730
+ Blobs_Select_Column2["ObjectName"] = "object_name";
731
+ Blobs_Select_Column2["Owner"] = "owner";
732
+ Blobs_Select_Column2["PaymentAmount"] = "payment_amount";
733
+ Blobs_Select_Column2["PlacementGroup"] = "placement_group";
734
+ Blobs_Select_Column2["Size"] = "size";
735
+ Blobs_Select_Column2["SliceAddress"] = "slice_address";
736
+ Blobs_Select_Column2["Uid"] = "uid";
737
+ Blobs_Select_Column2["UpdatedAt"] = "updated_at";
738
+ return Blobs_Select_Column2;
739
+ })(Blobs_Select_Column || {});
740
+ var Blobs_Update_Column = /* @__PURE__ */ ((Blobs_Update_Column2) => {
741
+ Blobs_Update_Column2["BlobCommitment"] = "blob_commitment";
742
+ Blobs_Update_Column2["CreatedAt"] = "created_at";
743
+ Blobs_Update_Column2["DeletionReason"] = "deletion_reason";
744
+ Blobs_Update_Column2["Encoding"] = "encoding";
745
+ Blobs_Update_Column2["Encryption"] = "encryption";
746
+ Blobs_Update_Column2["Etag"] = "etag";
747
+ Blobs_Update_Column2["ExpiresAt"] = "expires_at";
748
+ Blobs_Update_Column2["IsCommitted"] = "is_committed";
749
+ Blobs_Update_Column2["IsDeleted"] = "is_deleted";
750
+ Blobs_Update_Column2["IsPersisted"] = "is_persisted";
751
+ Blobs_Update_Column2["NumChunksets"] = "num_chunksets";
752
+ Blobs_Update_Column2["ObjectName"] = "object_name";
753
+ Blobs_Update_Column2["Owner"] = "owner";
754
+ Blobs_Update_Column2["PaymentAmount"] = "payment_amount";
755
+ Blobs_Update_Column2["PlacementGroup"] = "placement_group";
756
+ Blobs_Update_Column2["Size"] = "size";
757
+ Blobs_Update_Column2["SliceAddress"] = "slice_address";
758
+ Blobs_Update_Column2["Uid"] = "uid";
759
+ Blobs_Update_Column2["UpdatedAt"] = "updated_at";
760
+ return Blobs_Update_Column2;
761
+ })(Blobs_Update_Column || {});
762
+ var Cursor_Ordering = /* @__PURE__ */ ((Cursor_Ordering2) => {
763
+ Cursor_Ordering2["Asc"] = "ASC";
764
+ Cursor_Ordering2["Desc"] = "DESC";
765
+ return Cursor_Ordering2;
766
+ })(Cursor_Ordering || {});
767
+ var Order_By = /* @__PURE__ */ ((Order_By2) => {
768
+ Order_By2["Asc"] = "asc";
769
+ Order_By2["AscNullsFirst"] = "asc_nulls_first";
770
+ Order_By2["AscNullsLast"] = "asc_nulls_last";
771
+ Order_By2["Desc"] = "desc";
772
+ Order_By2["DescNullsFirst"] = "desc_nulls_first";
773
+ Order_By2["DescNullsLast"] = "desc_nulls_last";
774
+ return Order_By2;
775
+ })(Order_By || {});
776
+ var Placement_Group_Slots_Constraint = /* @__PURE__ */ ((Placement_Group_Slots_Constraint2) => {
777
+ Placement_Group_Slots_Constraint2["PlacementGroupSlotsPkey"] = "placement_group_slots_pkey";
778
+ return Placement_Group_Slots_Constraint2;
779
+ })(Placement_Group_Slots_Constraint || {});
780
+ var Placement_Group_Slots_Select_Column = /* @__PURE__ */ ((Placement_Group_Slots_Select_Column2) => {
781
+ Placement_Group_Slots_Select_Column2["PlacementGroup"] = "placement_group";
782
+ Placement_Group_Slots_Select_Column2["SlotIndex"] = "slot_index";
783
+ Placement_Group_Slots_Select_Column2["Status"] = "status";
784
+ Placement_Group_Slots_Select_Column2["StorageProvider"] = "storage_provider";
785
+ Placement_Group_Slots_Select_Column2["UpdatedAt"] = "updated_at";
786
+ return Placement_Group_Slots_Select_Column2;
787
+ })(Placement_Group_Slots_Select_Column || {});
788
+ var Placement_Group_Slots_Update_Column = /* @__PURE__ */ ((Placement_Group_Slots_Update_Column2) => {
789
+ Placement_Group_Slots_Update_Column2["PlacementGroup"] = "placement_group";
790
+ Placement_Group_Slots_Update_Column2["SlotIndex"] = "slot_index";
791
+ Placement_Group_Slots_Update_Column2["Status"] = "status";
792
+ Placement_Group_Slots_Update_Column2["StorageProvider"] = "storage_provider";
793
+ Placement_Group_Slots_Update_Column2["UpdatedAt"] = "updated_at";
794
+ return Placement_Group_Slots_Update_Column2;
795
+ })(Placement_Group_Slots_Update_Column || {});
796
+ var Processor_Status_Constraint = /* @__PURE__ */ ((Processor_Status_Constraint2) => {
797
+ Processor_Status_Constraint2["ProcessorStatusPkey"] = "processor_status_pkey";
798
+ return Processor_Status_Constraint2;
799
+ })(Processor_Status_Constraint || {});
800
+ var Processor_Status_Select_Column = /* @__PURE__ */ ((Processor_Status_Select_Column2) => {
801
+ Processor_Status_Select_Column2["LastSuccessVersion"] = "last_success_version";
802
+ Processor_Status_Select_Column2["LastTransactionTimestamp"] = "last_transaction_timestamp";
803
+ Processor_Status_Select_Column2["LastUpdated"] = "last_updated";
804
+ Processor_Status_Select_Column2["Processor"] = "processor";
805
+ return Processor_Status_Select_Column2;
806
+ })(Processor_Status_Select_Column || {});
807
+ var Processor_Status_Update_Column = /* @__PURE__ */ ((Processor_Status_Update_Column2) => {
808
+ Processor_Status_Update_Column2["LastSuccessVersion"] = "last_success_version";
809
+ Processor_Status_Update_Column2["LastTransactionTimestamp"] = "last_transaction_timestamp";
810
+ Processor_Status_Update_Column2["LastUpdated"] = "last_updated";
811
+ Processor_Status_Update_Column2["Processor"] = "processor";
812
+ return Processor_Status_Update_Column2;
813
+ })(Processor_Status_Update_Column || {});
814
+ var GetBlobsDocument = gql`
815
+ query getBlobs($where: blobs_bool_exp, $orderBy: [blobs_order_by!], $limit: Int, $offset: Int) {
816
+ blobs(where: $where, order_by: $orderBy, limit: $limit, offset: $offset) {
817
+ uid
818
+ object_name
819
+ owner
820
+ blob_commitment
821
+ created_at
822
+ expires_at
823
+ updated_at
824
+ num_chunksets
825
+ size
826
+ slice_address
827
+ placement_group
828
+ is_persisted
829
+ is_committed
830
+ is_deleted
831
+ }
832
+ }
833
+ `;
834
+ var GetBlobActivitiesDocument = gql`
835
+ query getBlobActivities($where: blob_activities_bool_exp, $orderBy: [blob_activities_order_by!], $limit: Int, $offset: Int) {
836
+ blob_activities(
837
+ where: $where
838
+ order_by: $orderBy
839
+ limit: $limit
840
+ offset: $offset
841
+ ) {
842
+ uid
843
+ object_name
844
+ event_index
845
+ event_type
846
+ transaction_hash
847
+ transaction_version
848
+ timestamp
849
+ owner
850
+ }
851
+ }
852
+ `;
853
+ var GetBlobsCountDocument = gql`
854
+ query getBlobsCount($where: blobs_bool_exp) {
855
+ blobs_aggregate(where: $where) {
856
+ aggregate {
857
+ count
858
+ }
859
+ }
860
+ }
861
+ `;
862
+ var GetBlobActivitiesCountDocument = gql`
863
+ query getBlobActivitiesCount($where: blob_activities_bool_exp) {
864
+ blob_activities_aggregate(where: $where) {
865
+ aggregate {
866
+ count
867
+ }
868
+ }
869
+ }
870
+ `;
871
+ var GetTotalBlobsSizeDocument = gql`
872
+ query getTotalBlobsSize($where: blobs_bool_exp) {
873
+ blobs_aggregate(where: $where) {
874
+ aggregate {
875
+ sum {
876
+ size
877
+ }
878
+ }
879
+ }
880
+ }
881
+ `;
882
+ var GetPlacementGroupSlotsDocument = gql`
883
+ query getPlacementGroupSlots($where: placement_group_slots_bool_exp, $orderBy: [placement_group_slots_order_by!], $limit: Int, $offset: Int) {
884
+ placement_group_slots(
885
+ where: $where
886
+ order_by: $orderBy
887
+ limit: $limit
888
+ offset: $offset
889
+ ) {
890
+ placement_group
891
+ slot_index
892
+ storage_provider
893
+ status
894
+ updated_at
895
+ }
896
+ }
897
+ `;
898
+ var GetPlacementGroupSlotsCountDocument = gql`
899
+ query getPlacementGroupSlotsCount($where: placement_group_slots_bool_exp) {
900
+ placement_group_slots_aggregate(where: $where) {
901
+ aggregate {
902
+ count
903
+ }
904
+ }
905
+ }
906
+ `;
907
+ var GetProcessorStatusDocument = gql`
908
+ query getProcessorStatus {
909
+ processor_status {
910
+ last_success_version
911
+ last_transaction_timestamp
912
+ last_updated
913
+ }
914
+ }
915
+ `;
916
+ var defaultWrapper = (action, _operationName, _operationType, _variables) => action();
917
+ function getSdk(client, withWrapper = defaultWrapper) {
918
+ return {
919
+ getBlobs(variables, requestHeaders, signal) {
920
+ return withWrapper((wrappedRequestHeaders) => client.request({ document: GetBlobsDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "getBlobs", "query", variables);
921
+ },
922
+ getBlobActivities(variables, requestHeaders, signal) {
923
+ return withWrapper((wrappedRequestHeaders) => client.request({ document: GetBlobActivitiesDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "getBlobActivities", "query", variables);
924
+ },
925
+ getBlobsCount(variables, requestHeaders, signal) {
926
+ return withWrapper((wrappedRequestHeaders) => client.request({ document: GetBlobsCountDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "getBlobsCount", "query", variables);
927
+ },
928
+ getBlobActivitiesCount(variables, requestHeaders, signal) {
929
+ return withWrapper((wrappedRequestHeaders) => client.request({ document: GetBlobActivitiesCountDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "getBlobActivitiesCount", "query", variables);
930
+ },
931
+ getTotalBlobsSize(variables, requestHeaders, signal) {
932
+ return withWrapper((wrappedRequestHeaders) => client.request({ document: GetTotalBlobsSizeDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "getTotalBlobsSize", "query", variables);
933
+ },
934
+ getPlacementGroupSlots(variables, requestHeaders, signal) {
935
+ return withWrapper((wrappedRequestHeaders) => client.request({ document: GetPlacementGroupSlotsDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "getPlacementGroupSlots", "query", variables);
936
+ },
937
+ getPlacementGroupSlotsCount(variables, requestHeaders, signal) {
938
+ return withWrapper((wrappedRequestHeaders) => client.request({ document: GetPlacementGroupSlotsCountDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "getPlacementGroupSlotsCount", "query", variables);
939
+ },
940
+ getProcessorStatus(variables, requestHeaders, signal) {
941
+ return withWrapper((wrappedRequestHeaders) => client.request({ document: GetProcessorStatusDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "getProcessorStatus", "query", variables);
942
+ }
943
+ };
944
+ }
945
+
946
+ // src/core/operations/index.ts
947
+ function createShelbyIndexerClient(baseUrl, options) {
948
+ const graphqlClient = new GraphQLClient(baseUrl, options);
949
+ return getSdk(graphqlClient);
950
+ }
951
+ function getShelbyIndexerClient(config) {
952
+ const aptosConfig = getAptosConfig(config);
953
+ let { apiKey: indexerApiKey, baseUrl } = config.indexer ?? {};
954
+ if (!baseUrl) {
955
+ switch (aptosConfig?.network) {
956
+ // TODO: Add endpoints for core networks
957
+ case Network3.MAINNET:
958
+ case Network3.TESTNET:
959
+ case Network3.DEVNET:
960
+ case Network3.SHELBYNET:
961
+ case Network3.LOCAL:
962
+ baseUrl = NetworkToShelbyBlobIndexerBaseUrl[aptosConfig.network];
963
+ break;
964
+ }
965
+ }
966
+ if (baseUrl === void 0) {
967
+ throw new Error(
968
+ "The ShelbyClientConfig does not support the Shelby indexer. Please configure the endpoint in the ShelbyClientConfig.indexer.endpoint or provide a supported Aptos network."
969
+ );
970
+ }
971
+ const apiKey = indexerApiKey ?? config.apiKey;
972
+ return createShelbyIndexerClient(baseUrl, {
973
+ headers: {
974
+ ...apiKey ? { Authorization: `Bearer ${apiKey}` } : {},
975
+ "x-aptos-client": "shelby-ts-sdk"
976
+ }
977
+ });
978
+ }
979
+
980
+ // src/core/clients/ShelbyBlobClient.ts
981
+ var MissingTransactionSubmitterError = class extends Error {
982
+ constructor() {
983
+ super(
984
+ "USD sponsorship (usdSponsor) requires a transaction submitter to be configured. The sponsored transaction is a multi-agent transaction that must be co-signed by the sponsor. Configure a transaction submitter via aptos.pluginSettings.TRANSACTION_SUBMITTER that routes transactions to a service (like a gas station) capable of providing the sponsor's signature."
985
+ );
986
+ this.name = "MissingTransactionSubmitterError";
987
+ }
988
+ };
989
+ var COMMIT_REJECTION_REASONS = /* @__PURE__ */ new Set([
990
+ "AlreadyExists",
991
+ "NoPriorVersion",
992
+ "EtagMismatch"
993
+ ]);
994
+ var ObjectCommitRejectedError = class extends Error {
995
+ constructor(blobName, uid, reason) {
996
+ super(
997
+ `commit_object rejected the write for '${blobName}' (uid ${uid}): ${reason}`
998
+ );
999
+ this.blobName = blobName;
1000
+ this.uid = uid;
1001
+ this.reason = reason;
1002
+ this.name = "ObjectCommitRejectedError";
1003
+ }
1004
+ };
1005
+ function encryptionFunctionArgs(params) {
1006
+ if (params.omitEncryptionArg) {
1007
+ if (params.encryption && params.encryption !== "Unencrypted") {
1008
+ throw new Error(
1009
+ `Blob encryption (${params.encryption}) is not supported on this network: the deployed contract predates the encryption upgrade (#1739).`
1010
+ );
1011
+ }
1012
+ return [];
1013
+ }
1014
+ return [blobEncryptionToMoveEnumIndex(params.encryption ?? "Unencrypted")];
1015
+ }
1016
+ var ShelbyBlobClient = class _ShelbyBlobClient {
1017
+ aptos;
1018
+ deployer;
1019
+ indexer;
1020
+ defaultOptions;
1021
+ orderless;
1022
+ /**
1023
+ * The ShelbyBlobClient is used to interact with the Shelby contract on the Aptos blockchain. This
1024
+ * includes functions for registering blob commitments and retrieving blob metadata.
1025
+ *
1026
+ * @param config - The client configuration object.
1027
+ * @param config.network - The Shelby network to use.
1028
+ * @param defaultOptions - Optional default options for blob operations.
1029
+ *
1030
+ * @example
1031
+ * ```typescript
1032
+ * const blobClient = new ShelbyBlobClient({
1033
+ * aptos: {
1034
+ * network: Network.SHELBYNET,
1035
+ * clientConfig: {
1036
+ * API_KEY: "AG-***",
1037
+ * },
1038
+ * },
1039
+ * });
1040
+ * ```
1041
+ *
1042
+ * @example
1043
+ * ```typescript
1044
+ * // With default options for USD sponsorship
1045
+ * const blobClient = new ShelbyBlobClient(
1046
+ * {
1047
+ * network: Network.SHELBYNET,
1048
+ * aptos: {
1049
+ * pluginSettings: {
1050
+ * TRANSACTION_SUBMITTER: myGasStationSubmitter,
1051
+ * },
1052
+ * },
1053
+ * },
1054
+ * {
1055
+ * usdSponsor: { feePayerAddress: sponsorAddress },
1056
+ * }
1057
+ * );
1058
+ * ```
1059
+ */
1060
+ constructor(config, defaultOptions) {
1061
+ this.aptos = new Aptos(getAptosConfig(config));
1062
+ this.deployer = config.deployer ?? AccountAddress2.fromString(SHELBY_DEPLOYER);
1063
+ this.indexer = getShelbyIndexerClient(config);
1064
+ this.defaultOptions = {
1065
+ locationHint: config.locationHint,
1066
+ ...defaultOptions
1067
+ };
1068
+ this.orderless = config.orderless ?? false;
1069
+ }
1070
+ /**
1071
+ * Merges method-level options with default options, giving precedence to method-level values.
1072
+ */
1073
+ mergeOptions(options) {
1074
+ return {
1075
+ build: options?.build ?? this.defaultOptions.build,
1076
+ submit: options?.submit ?? this.defaultOptions.submit,
1077
+ usdSponsor: options?.usdSponsor ?? this.defaultOptions.usdSponsor,
1078
+ chunksetSizeBytes: options?.chunksetSizeBytes ?? this.defaultOptions.chunksetSizeBytes,
1079
+ selectedLocation: options?.selectedLocation ?? this.defaultOptions.selectedLocation,
1080
+ locationHint: options?.locationHint ?? this.defaultOptions.locationHint
1081
+ };
1082
+ }
1083
+ /**
1084
+ * Validates that if USD sponsorship is requested, a transaction submitter is
1085
+ * configured as well. Checks both the client-level and method-level transaction
1086
+ * submitter configurations. Throws MissingTransactionSubmitterError if usdSponsor is
1087
+ * provided without a transaction submitter.
1088
+ */
1089
+ validateUsdSponsorConfig(usdSponsor, submit) {
1090
+ if (!usdSponsor) {
1091
+ return;
1092
+ }
1093
+ const hasClientSubmitter = this.aptos.config.getTransactionSubmitter();
1094
+ const hasMethodSubmitter = submit?.transactionSubmitter !== void 0 && submit?.transactionSubmitter !== null;
1095
+ if (!hasClientSubmitter && !hasMethodSubmitter) {
1096
+ throw new MissingTransactionSubmitterError();
1097
+ }
1098
+ }
1099
+ /**
1100
+ * Merges orderless replay protection into transaction options when
1101
+ * `config.orderless` is enabled. If the caller already supplies options
1102
+ * (e.g. custom gas limits), those are preserved and the nonce is injected
1103
+ * alongside them. When orderless mode is off, user options are returned as-is.
1104
+ */
1105
+ orderlessTxOptions(userOptions) {
1106
+ if (!this.orderless) return userOptions;
1107
+ return {
1108
+ replayProtectionNonce: crypto.getRandomValues(new Uint32Array(1))[0],
1109
+ ...userOptions
1110
+ };
1111
+ }
1112
+ /**
1113
+ * Retrieves the blob metadata from the blockchain. If it does not exist,
1114
+ * returns `undefined`.
1115
+ *
1116
+ * @param params.account - The account namespace the blob is stored in (e.g. "0x1")
1117
+ * @param params.name - The name of the blob (e.g. "foo/bar")
1118
+ * @returns The blob metadata.
1119
+ *
1120
+ * @example
1121
+ * ```typescript
1122
+ * const metadata = await client.getFullObjectMetadata({
1123
+ * account: AccountAddress.fromString("0x1"),
1124
+ * name: "foo/bar.txt",
1125
+ * });
1126
+ * ```
1127
+ */
1128
+ async getFullObjectMetadata(params) {
1129
+ try {
1130
+ const rawMetadata = await this.aptos.view({
1131
+ payload: {
1132
+ function: `${this.deployer.toString()}::blob_metadata::get_full_object_metadata`,
1133
+ functionArguments: [
1134
+ createBlobKey({
1135
+ account: params.account,
1136
+ blobName: params.name
1137
+ })
1138
+ ]
1139
+ }
1140
+ });
1141
+ if (!rawMetadata?.[0]?.vec?.[0]) {
1142
+ return void 0;
1143
+ }
1144
+ const view = rawMetadata[0].vec[0];
1145
+ return this.parseBlobMetadata(view.blob_metadata, {
1146
+ uid: BigInt(view.object_metadata.current_blob_uid),
1147
+ name: params.name,
1148
+ // Any blob bound under an object name has cleared the commit-time
1149
+ // `is_written()` check, so a resolved object is always written.
1150
+ isWritten: true
1151
+ });
1152
+ } catch (error) {
1153
+ if (error instanceof Error && // Depending on the network, the error message may show up differently.
1154
+ (error.message?.includes("sub_status: Some(404)") || error.message?.includes("EBLOB_NOT_FOUND") || error.message?.includes("EOBJECT_NOT_FOUND"))) {
1155
+ return void 0;
1156
+ }
1157
+ throw error;
1158
+ }
1159
+ }
1160
+ /**
1161
+ * Retrieves blob metadata directly by its on-chain UID, including blobs in
1162
+ * the pending (registered-but-not-yet-committed) state that
1163
+ * {@link getFullObjectMetadata} cannot resolve by object name. Returns `undefined`
1164
+ * if no blob has that UID.
1165
+ *
1166
+ * The returned `name`/`blobNameSuffix` are empty: the blob layer is keyed by
1167
+ * UID and carries no object name (a name binding is established only at
1168
+ * commit). `isWritten` reflects whether the blob has been committed.
1169
+ */
1170
+ async getFullObjectMetadataByUid(uid) {
1171
+ try {
1172
+ const rawMetadata = await this.aptos.view(
1173
+ {
1174
+ payload: {
1175
+ function: `${this.deployer.toString()}::blob_metadata::get_blob_metadata`,
1176
+ functionArguments: [uid]
1177
+ }
1178
+ }
1179
+ );
1180
+ if (!rawMetadata?.[0]?.vec?.[0]) {
1181
+ return void 0;
1182
+ }
1183
+ const raw = rawMetadata[0].vec[0];
1184
+ return this.parseBlobMetadata(raw, {
1185
+ uid,
1186
+ name: "",
1187
+ isWritten: raw.state.__variant__ === "CommittedObject"
1188
+ });
1189
+ } catch (error) {
1190
+ if (error instanceof Error && (error.message?.includes("sub_status: Some(404)") || error.message?.includes("EBLOB_NOT_FOUND"))) {
1191
+ return void 0;
1192
+ }
1193
+ throw error;
1194
+ }
1195
+ }
1196
+ /**
1197
+ * Parse the on-chain `BlobMetadata::V1` view shape into the SDK
1198
+ * {@link FullObjectMetadata}. `uid` / `name` / `isWritten` are supplied by the
1199
+ * caller since they depend on the lookup path (by object name vs by UID).
1200
+ */
1201
+ parseBlobMetadata(raw, extra) {
1202
+ const { content } = raw;
1203
+ const variant = content.encoding.__variant__;
1204
+ if (variant !== "ClayCode_16Total_10Data_13Helper" && variant !== "ClayCode_4Total_2Data_3Helper") {
1205
+ throw new Error(
1206
+ "Could not parse encoding from Shelby Smart Contract, this SDK is out of date."
1207
+ );
1208
+ }
1209
+ const encoding = {
1210
+ variant: "clay",
1211
+ ...ERASURE_CODE_PARAMS[variant],
1212
+ ...ERASURE_CODE_AND_CHUNK_MAPPING[variant]
1213
+ };
1214
+ const encryption = blobEncryptionFromMoveVariant(
1215
+ content.encryption?.__variant__ ?? "Unencrypted"
1216
+ );
1217
+ return {
1218
+ uid: extra.uid,
1219
+ blobMerkleRoot: Hex3.fromHexInput(content.blob_commitment).toUint8Array(),
1220
+ owner: normalizeAddress(raw.owner),
1221
+ name: extra.name,
1222
+ blobNameSuffix: extra.name ? getBlobNameSuffix(extra.name) : "",
1223
+ size: Number(content.blob_size),
1224
+ encoding,
1225
+ encryption,
1226
+ expirationMicros: Number(raw.expiration_micros),
1227
+ creationMicros: Number(raw.creation_micros),
1228
+ sliceAddress: normalizeAddress(raw.slice.inner),
1229
+ isWritten: extra.isWritten
1230
+ };
1231
+ }
1232
+ /**
1233
+ * Retrieves all the blobs and their metadata for an account from the
1234
+ * blockchain.
1235
+ *
1236
+ * @param params.account - The account namespace the blobs are stored in (e.g. "0x1")
1237
+ * @param params.pagination (optional) - The pagination options.
1238
+ * @param params.orderBy (optional) - The order by clause to sort the blobs by.
1239
+ * @returns The blob metadata for all the blobs for the account.
1240
+ *
1241
+ * @example
1242
+ * ```typescript
1243
+ * // FullObjectMetadata[]
1244
+ * const blobs = await client.getAccountBlobs({
1245
+ * account: AccountAddress.fromString("0x1"),
1246
+ * });
1247
+ * ```
1248
+ */
1249
+ getAccountBlobs(params) {
1250
+ const { where, ...rest } = params;
1251
+ return this.getBlobs({
1252
+ where: {
1253
+ ...where,
1254
+ owner: { _eq: normalizeAddress(params.account).toString() }
1255
+ },
1256
+ pagination: rest.pagination,
1257
+ orderBy: rest.orderBy
1258
+ });
1259
+ }
1260
+ /**
1261
+ * Object-facing default filter: only committed, non-deleted, unexpired rows.
1262
+ * The blobs table is UID-keyed, so during an atomic overwrite a single
1263
+ * object_name transiently has two non-deleted rows — the currently committed
1264
+ * blob and the new pending (is_committed = "0") blob. Filtering on
1265
+ * is_committed keeps name lookups/listings pinned to the committed object and
1266
+ * avoids returning or duplicating the in-flight pending row. Applied to
1267
+ * getBlobs *and* the getBlobsCount / getTotalBlobsSize aggregates so counts
1268
+ * and sizes agree with the listing mid-overwrite. Callers can override any
1269
+ * key (e.g. is_committed) via their own `where`.
1270
+ */
1271
+ activeBlobsWhere(where) {
1272
+ const defaultActiveFilter = {
1273
+ expires_at: { _gte: String(Date.now() * 1e3) },
1274
+ is_deleted: { _eq: "0" },
1275
+ is_committed: { _eq: "1" }
1276
+ };
1277
+ return { ...defaultActiveFilter, ...where };
1278
+ }
1279
+ /**
1280
+ * Retrieves blobs and their metadata from the blockchain.
1281
+ *
1282
+ * @param params.where (optional) - The where clause to filter the blobs by.
1283
+ * @param params.pagination (optional) - The pagination options.
1284
+ * @param params.orderBy (optional) - The order by clause to sort the blobs by.
1285
+ * @returns The blob metadata for all the blobs that match the where clause.
1286
+ *
1287
+ * @example
1288
+ * ```typescript
1289
+ * // FullObjectMetadata[]
1290
+ * const blobs = await client.getBlobs({
1291
+ * where: { owner: { _eq: AccountAddress.fromString("0x1").toString() } },
1292
+ * });
1293
+ * ```
1294
+ */
1295
+ async getBlobs(params = {}) {
1296
+ const { limit, offset } = params.pagination ?? {};
1297
+ const { orderBy, where } = params;
1298
+ const finalWhere = this.activeBlobsWhere(where);
1299
+ const { blobs } = await this.indexer.getBlobs({
1300
+ where: finalWhere,
1301
+ limit,
1302
+ offset,
1303
+ orderBy
1304
+ });
1305
+ return blobs.map(
1306
+ (blob) => ({
1307
+ uid: BigInt(blob.uid),
1308
+ owner: normalizeAddress(blob.owner),
1309
+ name: blob.object_name,
1310
+ blobNameSuffix: getBlobNameSuffix(blob.object_name),
1311
+ blobMerkleRoot: Hex3.fromHexInput(blob.blob_commitment).toUint8Array(),
1312
+ size: Number(blob.size),
1313
+ // TODO: Add encoding when supported in NCI
1314
+ encoding: {
1315
+ variant: "clay",
1316
+ ...ERASURE_CODE_PARAMS.ClayCode_16Total_10Data_13Helper,
1317
+ ...ERASURE_CODE_AND_CHUNK_MAPPING.ClayCode_16Total_10Data_13Helper
1318
+ },
1319
+ expirationMicros: Number(blob.expires_at),
1320
+ creationMicros: Number(blob.created_at),
1321
+ sliceAddress: normalizeAddress(blob.slice_address),
1322
+ isWritten: Boolean(Number(blob.is_persisted)),
1323
+ isDeleted: Boolean(Number(blob.is_deleted))
1324
+ })
1325
+ );
1326
+ }
1327
+ async getBlobActivities(params) {
1328
+ const { limit, offset } = params.pagination ?? {};
1329
+ const { orderBy, where } = params;
1330
+ const { blob_activities } = await this.indexer.getBlobActivities({
1331
+ where,
1332
+ limit,
1333
+ offset,
1334
+ orderBy
1335
+ });
1336
+ const activityTypeMapping = {
1337
+ [`${this.deployer.toStringLong()}::blob_metadata::BlobRegisteredEvent`]: "register_blob",
1338
+ [`${this.deployer.toStringLong()}::blob_metadata::BlobDeletedEvent`]: "delete_blob",
1339
+ [`${this.deployer.toStringLong()}::blob_metadata::BlobExpirationExtendedEvent`]: "extend_blob_expiration",
1340
+ [`${this.deployer.toStringLong()}::blob_metadata::BlobPersistedEvent`]: "write_blob",
1341
+ [`${this.deployer.toStringLong()}::blob_metadata::ObjectCommittedEvent`]: "commit_object",
1342
+ [`${this.deployer.toStringLong()}::blob_metadata::ObjectDeletedEvent`]: "delete_object",
1343
+ [`${this.deployer.toStringLong()}::blob_metadata::ObjectCommitRejectedEvent`]: "reject_object_commit"
1344
+ };
1345
+ return blob_activities.map(
1346
+ (activity) => ({
1347
+ blobName: activity.object_name,
1348
+ accountAddress: normalizeAddress(activity.object_name.substring(1, 65)),
1349
+ type: activityTypeMapping[activity.event_type] ?? "unknown",
1350
+ eventType: activity.event_type,
1351
+ eventIndex: Number(activity.event_index),
1352
+ transactionHash: activity.transaction_hash,
1353
+ // Using Number here in JS is technically not okay because txn version can be
1354
+ // as large as u64::MAX, but it should be fine for a long while.
1355
+ transactionVersion: Number(activity.transaction_version),
1356
+ timestamp: `${activity.timestamp}Z`
1357
+ })
1358
+ );
1359
+ }
1360
+ /**
1361
+ * Retrieves the total number of blobs from the blockchain.
1362
+ *
1363
+ * @param params.where (optional) - The where clause to filter the blobs by.
1364
+ * @returns The total number of blobs.
1365
+ *
1366
+ * @example
1367
+ * ```typescript
1368
+ * const count = await client.getBlobsCount();
1369
+ * ```
1370
+ */
1371
+ async getBlobsCount(params = {}) {
1372
+ const { blobs_aggregate } = await this.indexer.getBlobsCount({
1373
+ where: this.activeBlobsWhere(params.where)
1374
+ });
1375
+ return blobs_aggregate?.aggregate?.count ?? 0;
1376
+ }
1377
+ /**
1378
+ * Retrieves the total size of blobs from the blockchain.
1379
+ *
1380
+ * @param params.where (optional) - The where clause to filter the blobs by.
1381
+ * @returns The total size of blobs in bytes.
1382
+ *
1383
+ * @example
1384
+ * ```typescript
1385
+ * const size = await client.getTotalBlobsSize();
1386
+ * ```
1387
+ */
1388
+ async getTotalBlobsSize(params = {}) {
1389
+ const { blobs_aggregate } = await this.indexer.getTotalBlobsSize({
1390
+ where: this.activeBlobsWhere(params.where)
1391
+ });
1392
+ return Number(blobs_aggregate?.aggregate?.sum?.size ?? 0);
1393
+ }
1394
+ /**
1395
+ * Retrieves the total number of blob activities from the blockchain.
1396
+ *
1397
+ * @param params.where (optional) - The where clause to filter the blob activities by.
1398
+ * @returns The total number of blob activities.
1399
+ *
1400
+ * @example
1401
+ * ```typescript
1402
+ * const count = await client.getBlobActivitiesCount();
1403
+ * ```
1404
+ */
1405
+ async getBlobActivitiesCount(params) {
1406
+ const { where } = params;
1407
+ const { blob_activities_aggregate } = await this.indexer.getBlobActivitiesCount({ where });
1408
+ return blob_activities_aggregate?.aggregate?.count ?? 0;
1409
+ }
1410
+ /**
1411
+ * Registers a blob on the blockchain by writing its merkle root and metadata.
1412
+ *
1413
+ * @param params.account - The account that is signing and paying for the transaction.
1414
+ * @param params.blobName - The name/path of the blob (e.g. "foo/bar.txt").
1415
+ * @param params.blobMerkleRoot - The merkle root of the blob commitments.
1416
+ * @param params.size - The size of the blob in bytes.
1417
+ * @param params.expirationMicros - The expiration time of the blob in microseconds.
1418
+ * @param params.options - Optional transaction building options.
1419
+ * @param params.options.chunksetSizeBytes - Custom chunkset size (defaults to DEFAULT_CHUNKSET_SIZE_BYTES).
1420
+ * @param params.options.build - Additional Aptos transaction building options.
1421
+ *
1422
+ * @returns An object containing the pending transaction.
1423
+ *
1424
+ * @example
1425
+ * ```typescript
1426
+ * const provider = await ClayErasureCodingProvider.create();
1427
+ * const blobCommitments = await generateCommitments(provider, data);
1428
+ *
1429
+ * const { transaction } = await client.registerBlob({
1430
+ * account: signer,
1431
+ * blobName: "foo/bar.txt",
1432
+ * blobMerkleRoot: blobCommitments.blob_merkle_root,
1433
+ * size: data.length,
1434
+ * expirationMicros: Date.now() * 1000 + 3600_000_000, // 1 hour from now in microseconds
1435
+ * });
1436
+ * ```
1437
+ */
1438
+ async registerBlob(params) {
1439
+ const options = this.mergeOptions(params.options);
1440
+ this.validateUsdSponsorConfig(options.usdSponsor, options.submit);
1441
+ const config = params.config ?? defaultErasureCodingConfig();
1442
+ const chunksetSize = config.chunkSizeBytes * config.erasure_k;
1443
+ const buildArgs = {
1444
+ ...options.build,
1445
+ options: this.orderlessTxOptions(options.build?.options),
1446
+ data: _ShelbyBlobClient.createRegisterBlobPayload({
1447
+ deployer: this.deployer,
1448
+ account: params.account.accountAddress,
1449
+ blobName: params.blobName,
1450
+ selectedLocation: options.selectedLocation,
1451
+ locationHint: options.locationHint,
1452
+ blobSize: params.size,
1453
+ blobMerkleRoot: params.blobMerkleRoot,
1454
+ numChunksets: expectedTotalChunksets(params.size, chunksetSize),
1455
+ expirationMicros: params.expirationMicros,
1456
+ useSponsoredUsdVariant: options.usdSponsor !== void 0,
1457
+ encoding: config.enumIndex,
1458
+ encryption: params.encryption
1459
+ }),
1460
+ sender: params.account.accountAddress
1461
+ };
1462
+ const transaction = options.usdSponsor ? await this.aptos.transaction.build.multiAgent({
1463
+ ...buildArgs,
1464
+ secondarySignerAddresses: [options.usdSponsor.feePayerAddress]
1465
+ }) : await this.aptos.transaction.build.simple(buildArgs);
1466
+ return {
1467
+ transaction: await this.aptos.signAndSubmitTransaction({
1468
+ signer: params.account,
1469
+ transaction,
1470
+ ...options.submit
1471
+ })
1472
+ };
1473
+ }
1474
+ /**
1475
+ * Deletes a blob on the blockchain.
1476
+ *
1477
+ * @param params.account - The account that is signing and paying for the transaction.
1478
+ * @param params.blobName - The name/path of the blob (e.g. "foo/bar.txt").
1479
+ * @param params.options - Optional transaction building options.
1480
+ *
1481
+ * @returns An object containing the pending transaction.
1482
+ *
1483
+ * @example
1484
+ * ```typescript
1485
+ *
1486
+ * const { transaction } = await client.deleteObject({
1487
+ * account: signer,
1488
+ * blobName: "foo/bar.txt",
1489
+ * });
1490
+ * ```
1491
+ */
1492
+ async deleteObject(params) {
1493
+ const transaction = await this.aptos.transaction.build.simple({
1494
+ options: this.orderlessTxOptions(params.options),
1495
+ data: _ShelbyBlobClient.createDeleteObjectPayload({
1496
+ deployer: this.deployer,
1497
+ blobName: params.blobName
1498
+ }),
1499
+ sender: params.account.accountAddress
1500
+ });
1501
+ return {
1502
+ transaction: await this.aptos.signAndSubmitTransaction({
1503
+ signer: params.account,
1504
+ transaction
1505
+ })
1506
+ };
1507
+ }
1508
+ /**
1509
+ * Deletes multiple blobs on the blockchain in a single atomic transaction.
1510
+ *
1511
+ * This operation is atomic: if any blob deletion fails (e.g., blob not found),
1512
+ * the entire transaction fails and no blobs are deleted.
1513
+ *
1514
+ * @param params.account - The account that is signing and paying for the transaction.
1515
+ * @param params.blobNames - Array of blob name suffixes without the account address prefix
1516
+ * (e.g. ["foo/bar.txt", "baz.txt"], NOT ["0x1/foo/bar.txt"]). The account address
1517
+ * prefix is automatically derived from the signer.
1518
+ * @param params.options - Optional transaction building options.
1519
+ *
1520
+ * @returns An object containing the pending transaction.
1521
+ *
1522
+ * @example
1523
+ * ```typescript
1524
+ *
1525
+ * const { transaction } = await client.deleteMultipleObjects({
1526
+ * account: signer,
1527
+ * blobNames: ["foo/bar.txt", "baz.txt"],
1528
+ * });
1529
+ * ```
1530
+ */
1531
+ async deleteMultipleObjects(params) {
1532
+ const transaction = await this.aptos.transaction.build.simple({
1533
+ options: this.orderlessTxOptions(params.options),
1534
+ data: _ShelbyBlobClient.createDeleteMultipleObjectsPayload({
1535
+ deployer: this.deployer,
1536
+ blobNames: params.blobNames
1537
+ }),
1538
+ sender: params.account.accountAddress
1539
+ });
1540
+ return {
1541
+ transaction: await this.aptos.signAndSubmitTransaction({
1542
+ signer: params.account,
1543
+ transaction
1544
+ })
1545
+ };
1546
+ }
1547
+ /**
1548
+ * Registers multiple blobs on the blockchain by writing their merkle roots and metadata.
1549
+ *
1550
+ * @param params.account - The account that is signing and paying for the transaction.
1551
+ * @param params.expirationMicros - The expiration time of the blobs in microseconds.
1552
+ * @param params.blobs - The blobs to register.
1553
+ * @param params.blobs.blobName - The name/path of the blob (e.g. "foo/bar.txt").
1554
+ * @param params.blobs.blobSize - The size of the blob in bytes.
1555
+ * @param params.blobs.blobMerkleRoot - The merkle root of the blob commitments as a hex string.
1556
+ * @param params.options - Optional transaction building options.
1557
+ * @param params.options.chunksetSizeBytes - Custom chunkset size (defaults to DEFAULT_CHUNKSET_SIZE_BYTES).
1558
+ * @param params.options.build - Additional Aptos transaction building options.
1559
+ *
1560
+ * @returns An object containing the pending transaction.
1561
+ *
1562
+ * @example
1563
+ * ```typescript
1564
+ * const provider = await ClayErasureCodingProvider.create();
1565
+ * const blobCommitments = await generateCommitments(provider, data);
1566
+ *
1567
+ * const { transaction } = await client.batchRegisterBlobs({
1568
+ * account: signer,
1569
+ * expirationMicros: Date.now() * 1000 + 3600_000_000, // 1 hour from now in microseconds
1570
+ * blobs: [
1571
+ * {
1572
+ * blobName: "foo/bar.txt",
1573
+ * blobSize: data.length,
1574
+ * blobMerkleRoot: blobCommitments.blob_merkle_root,
1575
+ * },
1576
+ * ],
1577
+ * });
1578
+ * ```
1579
+ */
1580
+ async batchRegisterBlobs(params) {
1581
+ const options = this.mergeOptions(params.options);
1582
+ this.validateUsdSponsorConfig(options.usdSponsor, options.submit);
1583
+ const config = params.config ?? defaultErasureCodingConfig();
1584
+ const chunksetSize = config.chunkSizeBytes * config.erasure_k;
1585
+ const buildArgs = {
1586
+ ...options.build,
1587
+ options: this.orderlessTxOptions(options.build?.options),
1588
+ sender: params.account.accountAddress,
1589
+ data: _ShelbyBlobClient.createBatchRegisterBlobsPayload({
1590
+ deployer: this.deployer,
1591
+ account: params.account.accountAddress,
1592
+ selectedLocation: options.selectedLocation,
1593
+ locationHint: options.locationHint,
1594
+ expirationMicros: params.expirationMicros,
1595
+ blobs: params.blobs.map((blob) => ({
1596
+ blobName: blob.blobName,
1597
+ blobSize: blob.blobSize,
1598
+ blobMerkleRoot: blob.blobMerkleRoot,
1599
+ numChunksets: expectedTotalChunksets(blob.blobSize, chunksetSize)
1600
+ })),
1601
+ useSponsoredUsdVariant: options.usdSponsor !== void 0,
1602
+ encoding: config.enumIndex,
1603
+ encryption: params.encryption
1604
+ })
1605
+ };
1606
+ const transaction = options.usdSponsor ? await this.aptos.transaction.build.multiAgent({
1607
+ ...buildArgs,
1608
+ secondarySignerAddresses: [options.usdSponsor.feePayerAddress]
1609
+ }) : await this.aptos.transaction.build.simple(buildArgs);
1610
+ return {
1611
+ transaction: await this.aptos.signAndSubmitTransaction({
1612
+ signer: params.account,
1613
+ transaction,
1614
+ ...options.submit
1615
+ })
1616
+ };
1617
+ }
1618
+ /**
1619
+ * Extracts the on-chain UIDs assigned at registration from a committed
1620
+ * register transaction's events.
1621
+ *
1622
+ * `register_blob` / `register_multiple_blobs` create *pending* blobs and emit
1623
+ * one `BlobRegisteredEvent` per blob. The UID is published only on this event
1624
+ * (the blob is not yet in the `objects` map, so it cannot be read back by
1625
+ * name), so callers must parse it here before uploading bytes or committing.
1626
+ *
1627
+ * @param events - The committed transaction's events (from `waitForTransaction`).
1628
+ * @param deployer - The contract deployer address.
1629
+ * @returns One entry per registered blob, keyed by its full object name
1630
+ * (`@<owner>/<suffix>`, matching {@link createBlobKey}).
1631
+ */
1632
+ static registeredBlobUids(events, deployer) {
1633
+ const eventType = `${deployer.toStringLong()}::blob_metadata::BlobRegisteredEvent`;
1634
+ return events.filter((event) => event.type === eventType).map((event) => {
1635
+ const data = event.data;
1636
+ return { objectName: data.object_name, uid: BigInt(data.uid) };
1637
+ });
1638
+ }
1639
+ /**
1640
+ * Detects whether `commit_object` rejected the write for `uid` rather than
1641
+ * applying it. A rejected commit is still a *successful* transaction — the
1642
+ * contract tears down the pending blob and emits `ObjectCommitRejectedEvent`
1643
+ * instead of aborting — so callers must inspect the finalized transaction's
1644
+ * events to tell a durable write apart from a silent no-op.
1645
+ *
1646
+ * @param events - The committed transaction's events (from `waitForTransaction`).
1647
+ * @param deployer - The contract deployer address.
1648
+ * @param uid - The UID passed to `commit_object`.
1649
+ * @returns The rejection reason, or `undefined` if the commit was applied.
1650
+ */
1651
+ static findObjectCommitRejection(events, deployer, uid) {
1652
+ const eventType = `${deployer.toStringLong()}::blob_metadata::ObjectCommitRejectedEvent`;
1653
+ const rejection = events.find(
1654
+ (event) => event.type === eventType && BigInt(event.data.uid) === uid
1655
+ );
1656
+ if (!rejection) {
1657
+ return void 0;
1658
+ }
1659
+ const reason = rejection.data.rejection_reason.__variant__;
1660
+ if (!COMMIT_REJECTION_REASONS.has(reason)) {
1661
+ throw new Error(
1662
+ `Unrecognized ObjectCommitRejectedEvent rejection_reason '${reason}' for uid ${uid}`
1663
+ );
1664
+ }
1665
+ return reason;
1666
+ }
1667
+ /**
1668
+ * Creates a transaction payload to register a blob on the blockchain.
1669
+ * This is a static helper method for constructing the Move function call payload.
1670
+ *
1671
+ * @param params.deployer - Optional deployer account address. Defaults to SHELBY_DEPLOYER.
1672
+ * @param params.account - The account that will own the blob.
1673
+ * @param params.blobName - The name/path of the blob (e.g. "foo/bar.txt").
1674
+ * @param params.blobSize - The size of the blob in bytes.
1675
+ * @param params.blobMerkleRoot - The merkle root of the blob commitments as a hex string.
1676
+ * @param params.expirationMicros - The expiration time of the blob in microseconds.
1677
+ * @param params.numChunksets - The total number of chunksets in the blob.
1678
+ *
1679
+ * @returns An Aptos transaction payload data object for the register_blob Move function.
1680
+ */
1681
+ static createRegisterBlobPayload(params) {
1682
+ const functionName = params.useSponsoredUsdVariant ? "register_blob_with_sponsor" : "register_blob";
1683
+ return {
1684
+ function: `${(params.deployer ?? SHELBY_DEPLOYER).toString()}::blob_metadata::${functionName}`,
1685
+ functionArguments: [
1686
+ params.blobName,
1687
+ params.selectedLocation ?? null,
1688
+ params.locationHint ?? null,
1689
+ params.expirationMicros,
1690
+ Hex3.fromHexString(params.blobMerkleRoot).toUint8Array(),
1691
+ params.numChunksets,
1692
+ params.blobSize,
1693
+ // TODO
1694
+ 0,
1695
+ // payment tier
1696
+ params.encoding,
1697
+ ...encryptionFunctionArgs(params)
1698
+ ]
1699
+ };
1700
+ }
1701
+ /**
1702
+ * Creates a transaction payload to register multiple blobs on the blockchain.
1703
+ * This is a static helper method for constructing the Move function call payload.
1704
+ *
1705
+ * @param params.deployer - Optional deployer account address. Defaults to SHELBY_DEPLOYER.
1706
+ * @param params.account - The account that will own the blobs.
1707
+ * @param params.expirationMicros - The expiration time of the blobs in microseconds.
1708
+ * @param params.blobs - The blobs to register.
1709
+ * @param params.blobs.blobName - The name/path of the blob (e.g. "foo/bar.txt").
1710
+ * @param params.blobs.blobSize - The size of the blob in bytes.
1711
+ * @param params.blobs.blobMerkleRoot - The merkle root of the blob commitments as a hex string.
1712
+ * @param params.blobs.numChunksets - The total number of chunksets in the blob.
1713
+ *
1714
+ * @returns An Aptos transaction payload data object for the register_multiple_blobs Move function.
1715
+ */
1716
+ static createBatchRegisterBlobsPayload(params) {
1717
+ const functionName = params.useSponsoredUsdVariant ? "register_multiple_blobs_with_sponsor" : "register_multiple_blobs";
1718
+ const blobNames = [];
1719
+ const blobMerkleRoots = [];
1720
+ const blobNumChunksets = [];
1721
+ const blobSizes = [];
1722
+ params.blobs.forEach((blob) => {
1723
+ blobNames.push(blob.blobName);
1724
+ blobMerkleRoots.push(
1725
+ Hex3.fromHexString(blob.blobMerkleRoot).toUint8Array()
1726
+ );
1727
+ blobNumChunksets.push(blob.numChunksets);
1728
+ blobSizes.push(blob.blobSize);
1729
+ });
1730
+ return {
1731
+ function: `${(params.deployer ?? SHELBY_DEPLOYER).toString()}::blob_metadata::${functionName}`,
1732
+ functionArguments: [
1733
+ blobNames,
1734
+ params.selectedLocation ?? null,
1735
+ params.locationHint ?? null,
1736
+ params.expirationMicros,
1737
+ blobMerkleRoots,
1738
+ blobNumChunksets,
1739
+ blobSizes,
1740
+ // TODO
1741
+ 0,
1742
+ // payment tier
1743
+ params.encoding,
1744
+ ...encryptionFunctionArgs(params)
1745
+ ]
1746
+ };
1747
+ }
1748
+ /**
1749
+ * Creates a transaction payload to delete a blob on the blockchain.
1750
+ * This is a static helper method for constructing the Move function call payload.
1751
+ *
1752
+ * @param params.deployer - Optional deployer account address. Defaults to SHELBY_DEPLOYER.
1753
+ * @param params.blobName - The blob name (e.g. "bar.txt", without the account address prefix).
1754
+ *
1755
+ * @returns An Aptos transaction payload data object for the delete_object Move function.
1756
+ */
1757
+ static createDeleteObjectPayload(params) {
1758
+ return {
1759
+ function: `${(params.deployer ?? SHELBY_DEPLOYER).toString()}::blob_metadata::delete_object`,
1760
+ // Second arg is `if_match_etag: Option<vector<u8>>`; `null` => None
1761
+ // (unconditional delete).
1762
+ functionArguments: [params.blobName, null]
1763
+ };
1764
+ }
1765
+ /**
1766
+ * Creates a transaction payload to delete multiple blobs on the blockchain.
1767
+ * This is a static helper method for constructing the Move function call payload.
1768
+ *
1769
+ * This operation is atomic: if any blob deletion fails (e.g., blob not found),
1770
+ * the entire transaction fails and no blobs are deleted.
1771
+ *
1772
+ * @param params.deployer - Optional deployer account address. Defaults to SHELBY_DEPLOYER.
1773
+ * @param params.blobNames - Array of blob name suffixes without the account address prefix
1774
+ * (e.g. ["foo/bar.txt", "baz.txt"], NOT ["0x1/foo/bar.txt"]). The account address
1775
+ * prefix is automatically derived from the transaction sender.
1776
+ *
1777
+ * @returns An Aptos transaction payload data object for the delete_multiple_objects Move function.
1778
+ */
1779
+ static createDeleteMultipleObjectsPayload(params) {
1780
+ return {
1781
+ function: `${(params.deployer ?? SHELBY_DEPLOYER).toString()}::blob_metadata::delete_multiple_objects`,
1782
+ // Second arg is `if_match_etags: vector<Option<vector<u8>>>`; an empty
1783
+ // vector means "no etag check on any object" (unconditional delete).
1784
+ functionArguments: [params.blobNames, []]
1785
+ };
1786
+ }
1787
+ /**
1788
+ * Sort acks by slot and reduce to the `(ack_bits, signatures)` pair the
1789
+ * contract expects: it walks the set bits low-to-high and consumes the
1790
+ * signatures in that same order.
1791
+ */
1792
+ static encodeAcks(storageProviderAcks) {
1793
+ const sortedAcks = [...storageProviderAcks].sort((a, b) => a.slot - b.slot);
1794
+ const ackBitMask = sortedAcks.reduce(
1795
+ (acc, ack) => acc | 1 << ack.slot,
1796
+ 0
1797
+ );
1798
+ return {
1799
+ ackBits: new U32(Number(ackBitMask)),
1800
+ signatures: sortedAcks.map((ack) => ack.signature)
1801
+ };
1802
+ }
1803
+ /**
1804
+ * Payload for `commit_object(uid, object_name_suffix, overwrite, if_match_etag,
1805
+ * ack_bits, signatures)` — binds a written pending blob under its object name,
1806
+ * finalizing the upload. SP acks may be batched in here (the contract applies
1807
+ * them before the `is_written` check), so register → upload → commit needs
1808
+ * only a single finalize transaction.
1809
+ *
1810
+ * @param params.uid - The blob UID returned at registration.
1811
+ * @param params.blobName - The object name suffix the blob was registered under.
1812
+ * @param params.overwrite - Allow replacing an existing binding under this name.
1813
+ * @param params.storageProviderAcks - Acks applied atomically with the commit.
1814
+ */
1815
+ static createCommitObjectPayload(params) {
1816
+ const { ackBits, signatures } = _ShelbyBlobClient.encodeAcks(
1817
+ params.storageProviderAcks
1818
+ );
1819
+ return {
1820
+ function: `${(params.deployer ?? SHELBY_DEPLOYER).toString()}::blob_metadata::commit_object`,
1821
+ functionArguments: [
1822
+ params.uid,
1823
+ params.blobName,
1824
+ params.overwrite,
1825
+ // `if_match_etag: Option<vector<u8>>` is `null` => None; conditional
1826
+ // (CAS) writes are not yet exposed by the SDK.
1827
+ null,
1828
+ ackBits,
1829
+ signatures
1830
+ ]
1831
+ };
1832
+ }
1833
+ async commitObject(params) {
1834
+ const transaction = await this.aptos.transaction.build.simple({
1835
+ ...params.options?.build,
1836
+ options: this.orderlessTxOptions(params.options?.build?.options),
1837
+ data: _ShelbyBlobClient.createCommitObjectPayload({
1838
+ deployer: this.deployer,
1839
+ uid: params.uid,
1840
+ blobName: params.blobName,
1841
+ overwrite: params.overwrite,
1842
+ storageProviderAcks: params.storageProviderAcks
1843
+ }),
1844
+ sender: params.account.accountAddress
1845
+ });
1846
+ return {
1847
+ transaction: await this.aptos.signAndSubmitTransaction({
1848
+ signer: params.account,
1849
+ transaction
1850
+ })
1851
+ };
1852
+ }
1853
+ };
1854
+
1855
+ // src/core/clients/ShelbyClient.ts
110
1856
  import {
111
- BlobCommitmentsSchema,
112
- COMMITMENT_SCHEMA_VERSION,
113
- ChunksetCommitmentSchema,
114
- expectedTotalChunksets,
115
- generateCommitments,
116
- generateMerkleRoot
117
- } from "../chunk-RNNJXTX2.mjs";
1857
+ Aptos as Aptos3,
1858
+ DEFAULT_TXN_TIMEOUT_SEC,
1859
+ Network as Network4,
1860
+ TransactionResponseType
1861
+ } from "@aptos-labs/ts-sdk";
1862
+ import pLimit from "p-limit";
1863
+
1864
+ // src/core/errors.ts
1865
+ var ShelbyErrorCodes = {
1866
+ // blob_metadata.move errors
1867
+ E_BLOB_NOT_FOUND: "E_BLOB_NOT_FOUND",
1868
+ E_INVALID_EXPIRATION_TIME: "E_INVALID_EXPIRATION_TIME",
1869
+ E_TEST_ENCODING_NOT_ALLOWED: "E_TEST_ENCODING_NOT_ALLOWED",
1870
+ E_BLOB_NOT_EXPIRED: "E_BLOB_NOT_EXPIRED",
1871
+ E_INVALID_CHUNKSET_COUNT: "E_INVALID_CHUNKSET_COUNT",
1872
+ E_NOT_BLOB_OWNER: "E_NOT_BLOB_OWNER",
1873
+ E_NOT_ADMIN: "E_NOT_ADMIN",
1874
+ E_BLOB_EXPIRED: "E_BLOB_EXPIRED",
1875
+ E_BLOB_NAME_TOO_LONG: "E_BLOB_NAME_TOO_LONG",
1876
+ E_INVALID_PAYMENT_EPOCHS: "E_INVALID_PAYMENT_EPOCHS",
1877
+ E_NO_SLICES_AVAILABLE: "E_NO_SLICES_AVAILABLE",
1878
+ // Common Aptos/Move errors
1879
+ EALREADY_EXISTS: "EALREADY_EXISTS"
1880
+ };
1881
+ function isBlobAlreadyExistsError(errorMessage) {
1882
+ return errorMessage.includes(ShelbyErrorCodes.EALREADY_EXISTS) || errorMessage.includes("already exists");
1883
+ }
1884
+ function isAccessDeniedError(errorMessage) {
1885
+ return errorMessage.includes(ShelbyErrorCodes.E_NOT_BLOB_OWNER) || errorMessage.includes(ShelbyErrorCodes.E_NOT_ADMIN) || errorMessage.includes("ENOT_AUTHORIZED") || errorMessage.includes("not authorized") || errorMessage.includes("permission denied");
1886
+ }
1887
+ function isBlobNotFoundError(errorMessage) {
1888
+ return errorMessage.includes(ShelbyErrorCodes.E_BLOB_NOT_FOUND);
1889
+ }
1890
+ function isBlobExpiredError(errorMessage) {
1891
+ return errorMessage.includes(ShelbyErrorCodes.E_BLOB_EXPIRED);
1892
+ }
1893
+ var ShelbyLocationErrorCodes = {
1894
+ E_LOCATION_NOT_FOUND: "E_LOCATION_NOT_FOUND",
1895
+ E_SELECTED_LOCATION_CONFLICTS_WITH_LOCK: "E_SELECTED_LOCATION_CONFLICTS_WITH_LOCK",
1896
+ E_NO_LOCATION_SELECTED: "E_NO_LOCATION_SELECTED",
1897
+ E_LOCATION_WRITES_FROZEN: "E_LOCATION_WRITES_FROZEN",
1898
+ E_LOCATION_NOT_ACTIVATED: "E_LOCATION_NOT_ACTIVATED"
1899
+ };
1900
+ function describeLocationError(errorMessage) {
1901
+ if (errorMessage.includes(ShelbyLocationErrorCodes.E_LOCATION_WRITES_FROZEN)) {
1902
+ return "Cannot write: the resolved location is frozen and not currently accepting new data.";
1903
+ }
1904
+ if (errorMessage.includes(ShelbyLocationErrorCodes.E_LOCATION_NOT_ACTIVATED)) {
1905
+ return "Cannot write: the resolved location is not activated yet.";
1906
+ }
1907
+ if (errorMessage.includes(
1908
+ ShelbyLocationErrorCodes.E_SELECTED_LOCATION_CONFLICTS_WITH_LOCK
1909
+ )) {
1910
+ return "Cannot write: the selected location conflicts with the account's locked location preference.";
1911
+ }
1912
+ if (errorMessage.includes(ShelbyLocationErrorCodes.E_NO_LOCATION_SELECTED)) {
1913
+ return "No write location could be resolved: none was selected and the account has no default location or location hint.";
1914
+ }
1915
+ if (errorMessage.includes(ShelbyLocationErrorCodes.E_LOCATION_NOT_FOUND)) {
1916
+ return "Cannot write: the requested location does not exist.";
1917
+ }
1918
+ return void 0;
1919
+ }
1920
+
1921
+ // src/core/clients/ShelbyMetadataClient.ts
118
1922
  import {
119
- buildRequestUrl,
120
- concatHashes,
121
- getBlobNameSuffix,
122
- normalizeAddress,
123
- readInChunks,
124
- zeroPadBytes
125
- } from "../chunk-UEZNZBJO.mjs";
1923
+ AccountAddress as AccountAddress3,
1924
+ Aptos as Aptos2,
1925
+ Hex as Hex4
1926
+ } from "@aptos-labs/ts-sdk";
1927
+
1928
+ // src/core/types/storage_providers.ts
1929
+ var ACTIVE_PROVIDER_CONDITIONS = [
1930
+ "Normal",
1931
+ "Faulty",
1932
+ "Leaving",
1933
+ "Evicted",
1934
+ "PendingLeaving"
1935
+ ];
1936
+ function isActiveProviderCondition(value) {
1937
+ return typeof value === "string" && ACTIVE_PROVIDER_CONDITIONS.includes(value);
1938
+ }
1939
+ var TASK_ELIGIBLE_CONDITIONS = /* @__PURE__ */ new Set([
1940
+ "Normal",
1941
+ "PendingLeaving"
1942
+ ]);
1943
+ function isActiveForTasks(condition) {
1944
+ return TASK_ELIGIBLE_CONDITIONS.has(condition);
1945
+ }
1946
+
1947
+ // src/core/clients/ShelbyMetadataClient.ts
1948
+ function parseActiveProviderCondition(raw) {
1949
+ const variant = raw?.__variant__;
1950
+ if (!isActiveProviderCondition(variant)) {
1951
+ throw new Error(
1952
+ `Unknown ActiveProviderCondition variant: ${JSON.stringify(raw)}`
1953
+ );
1954
+ }
1955
+ return variant;
1956
+ }
1957
+ function parseStorageProviderState(raw) {
1958
+ switch (raw.__variant__) {
1959
+ case "Active":
1960
+ return {
1961
+ variant: "Active",
1962
+ quota: raw.quota.value,
1963
+ stakeAtStartOfStakingEpoch: raw.stake_at_start_of_staking_epoch,
1964
+ condition: parseActiveProviderCondition(raw.condition)
1965
+ };
1966
+ case "Waitlisted":
1967
+ return {
1968
+ variant: "Waitlisted"
1969
+ };
1970
+ case "Frozen":
1971
+ return {
1972
+ variant: "Frozen",
1973
+ frozenReason: raw.frozen_reason,
1974
+ frozenFrom: raw.frozen_from,
1975
+ frozenTill: raw.frozen_till
1976
+ };
1977
+ default:
1978
+ throw new Error(
1979
+ `Unknown StorageProviderStateDetails variant: ${JSON.stringify(raw)}`
1980
+ );
1981
+ }
1982
+ }
1983
+ var ShelbyMetadataClient = class {
1984
+ aptos;
1985
+ deployer;
1986
+ /**
1987
+ * The ShelbyMetadataClient is used to interact with the Shelby contract on the Aptos blockchain. This
1988
+ * includes functions like gathering basic details about the Shelby system, including storage provider information.
1989
+ *
1990
+ * @param config.aptos.config - The Aptos config.
1991
+ * @param config.shelbyDeployer - The deployer account address of the Shelby contract. If not provided, the default deployer address will be used.
1992
+ *
1993
+ * @example
1994
+ * ```typescript
1995
+ * const aptos = new Aptos(new AptosConfig({ network: Network.TESTNET }));
1996
+ * const metadataClient = new ShelbyMetadataClient({ aptos });
1997
+ * ```
1998
+ */
1999
+ constructor(config) {
2000
+ this.aptos = new Aptos2(getAptosConfig(config));
2001
+ this.deployer = config.deployer ?? AccountAddress3.fromString(SHELBY_DEPLOYER);
2002
+ }
2003
+ /**
2004
+ * Retrieves storage provider list from the blockchain.
2005
+ *
2006
+ * @returns A list of storage providers, or empty array if none exist.
2007
+ *
2008
+ * @example
2009
+ * ```typescript
2010
+ * const spList = await client.getStorageProviders();
2011
+ * ```
2012
+ */
2013
+ async getStorageProviders() {
2014
+ try {
2015
+ const rawMetadata = await this.aptos.view({
2016
+ payload: {
2017
+ function: `${this.deployer.toString()}::storage_provider_registry::get_all_storage_providers`,
2018
+ functionArguments: []
2019
+ }
2020
+ });
2021
+ const metadata = rawMetadata[0];
2022
+ return metadata.map((provider) => ({
2023
+ address: normalizeAddress(provider.address),
2024
+ ipAddress: provider.ip_address,
2025
+ port: provider.port,
2026
+ blsPublicKey: Hex4.fromHexInput(provider.bls_public_key).toUint8Array(),
2027
+ availabilityZone: provider.availability_zone,
2028
+ state: parseStorageProviderState(provider.state)
2029
+ }));
2030
+ } catch (error) {
2031
+ if (error instanceof Error && // Depending on the network, the error message may show up differently.
2032
+ error.message?.includes("sub_status: Some(404)")) {
2033
+ return [];
2034
+ }
2035
+ throw error;
2036
+ }
2037
+ }
2038
+ /**
2039
+ * Retrieves the names of every activated location (region). Locations that are
2040
+ * registered but not yet brought online are admin-internal and not listed.
2041
+ *
2042
+ * @returns The location name list.
2043
+ *
2044
+ * @example
2045
+ * ```typescript
2046
+ * const locations = await client.getLocationNames();
2047
+ * ```
2048
+ */
2049
+ async getLocationNames() {
2050
+ const names = await this.aptos.view({
2051
+ payload: {
2052
+ function: `${this.deployer.toString()}::location::activated_location_names`,
2053
+ functionArguments: []
2054
+ }
2055
+ });
2056
+ return names[0];
2057
+ }
2058
+ /**
2059
+ * Retrieves the list of placement group addresses in a location.
2060
+ *
2061
+ * @param locationName - The location whose placement groups to list.
2062
+ * @returns The placement group address list, or an empty array if none exist.
2063
+ *
2064
+ * @example
2065
+ * ```typescript
2066
+ * const pgList = await client.getPlacementGroupAddresses("us-east-1");
2067
+ * ```
2068
+ */
2069
+ async getPlacementGroupAddresses(locationName) {
2070
+ try {
2071
+ const pgSizeMetadata = await this.aptos.view({
2072
+ payload: {
2073
+ function: `${this.deployer.toString()}::placement_group_registry::get_number_of_placement_groups`,
2074
+ functionArguments: [locationName]
2075
+ }
2076
+ });
2077
+ if (Number(pgSizeMetadata[0]) === 0) {
2078
+ return [];
2079
+ }
2080
+ const finalPlacementGroupIndex = pgSizeMetadata[0] - 1;
2081
+ const addressMetadataArray = await this.aptos.view({
2082
+ payload: {
2083
+ function: `${this.deployer.toString()}::placement_group_registry::get_placement_group_addresses`,
2084
+ functionArguments: [locationName, 0, finalPlacementGroupIndex]
2085
+ }
2086
+ });
2087
+ const metadata = addressMetadataArray[0];
2088
+ return metadata.map((pg) => normalizeAddress(pg));
2089
+ } catch (error) {
2090
+ if (error instanceof Error && // Depending on the network, the error message may show up differently.
2091
+ (error.message?.includes("sub_status: Some(404)") || error.message?.includes("E_PLACEMENT_GROUP_NOT_FOUND"))) {
2092
+ return [];
2093
+ }
2094
+ throw error;
2095
+ }
2096
+ }
2097
+ /**
2098
+ * Retrieves the list of slice addresses in a location.
2099
+ *
2100
+ * @param locationName - The location whose slices to list.
2101
+ * @returns The slice group list, or an empty array if none exist.
2102
+ *
2103
+ * @example
2104
+ * ```typescript
2105
+ * const pgList = await client.getSliceAddresses("us-east-1");
2106
+ * ```
2107
+ */
2108
+ async getSliceAddresses(locationName) {
2109
+ try {
2110
+ const sliceSizeMetadata = await this.aptos.view({
2111
+ payload: {
2112
+ function: `${this.deployer.toString()}::slice_registry::get_number_of_slices`,
2113
+ functionArguments: [locationName]
2114
+ }
2115
+ });
2116
+ if (Number(sliceSizeMetadata[0]) === 0) {
2117
+ return [];
2118
+ }
2119
+ const finalSliceIndex = sliceSizeMetadata[0] - 1;
2120
+ const addressMetadataArray = await this.aptos.view({
2121
+ payload: {
2122
+ function: `${this.deployer.toString()}::slice_registry::get_slice_addresses`,
2123
+ functionArguments: [locationName, 0, finalSliceIndex]
2124
+ }
2125
+ });
2126
+ const metadata = addressMetadataArray[0];
2127
+ return metadata.map((slice) => normalizeAddress(slice));
2128
+ } catch (error) {
2129
+ if (error instanceof Error && // Depending on the network, the error message may show up differently.
2130
+ (error.message?.includes("sub_status: Some(404)") || error.message?.includes("E_SLICE_NOT_FOUND"))) {
2131
+ return [];
2132
+ }
2133
+ throw error;
2134
+ }
2135
+ }
2136
+ /**
2137
+ * Gets the placement group address for a slice.
2138
+ *
2139
+ * @param sliceAddress - The address of the slice account.
2140
+ * @returns The placement group address as a string.
2141
+ */
2142
+ async getPlacementGroupAddressForSlice(sliceAddress) {
2143
+ const sliceMetadata = await this.aptos.view({
2144
+ payload: {
2145
+ function: `${this.deployer.toString()}::slice::get_slice_info`,
2146
+ functionArguments: [sliceAddress.toString()]
2147
+ }
2148
+ });
2149
+ return sliceMetadata[0].placement_group_assignments[0].placement_group_address;
2150
+ }
2151
+ /**
2152
+ * Retrieves the designated storage providers for a slice.
2153
+ *
2154
+ * Designated SPs are those appointed to store data for their slots:
2155
+ * - Active: Currently serving data
2156
+ * - Receiving: Receiving data during slot transfer
2157
+ * - Repairing: Repairing data after crash or failed transfer
2158
+ * - Reconstructing: Reconstructing data if the repair fails
2159
+ *
2160
+ * @param params.account - The address of the slice account.
2161
+ * @returns An array where result[i] is the designated SP for slot i, or null if no SP is designated.
2162
+ *
2163
+ * @example
2164
+ * ```typescript
2165
+ * const providers = await client.getDesignatedStorageProvidersForSlice({ account: sliceAddress });
2166
+ * ```
2167
+ */
2168
+ async getDesignatedStorageProvidersForSlice(params) {
2169
+ const placementGroupAddress = await this.getPlacementGroupAddressForSlice(
2170
+ params.account
2171
+ );
2172
+ const rawMetadata = await this.aptos.view({
2173
+ payload: {
2174
+ function: `${this.deployer.toString()}::placement_group::get_designated_storage_providers`,
2175
+ functionArguments: [placementGroupAddress]
2176
+ }
2177
+ });
2178
+ const providers = rawMetadata[0];
2179
+ return providers.map(
2180
+ (opt) => opt.vec.length > 0 ? normalizeAddress(opt.vec[0]) : null
2181
+ );
2182
+ }
2183
+ /**
2184
+ * Retrieves the active storage providers for a slice.
2185
+ *
2186
+ * Active SPs have a complete copy of the data for the slot, and are not in any data transfer/repair/reconstruction phase.
2187
+ * Active SP can be audited for the data it contains.
2188
+ * Each slot has at most one active SP.
2189
+ *
2190
+ * @param params.account - The address of the slice account.
2191
+ * @returns An array where result[i] is the active SP for slot i, or null if no SP is active.
2192
+ *
2193
+ * @example
2194
+ * ```typescript
2195
+ * const providers = await client.getActiveStorageProvidersForSlice({ account: sliceAddress });
2196
+ * ```
2197
+ */
2198
+ async getActiveStorageProvidersForSlice(params) {
2199
+ const placementGroupAddress = await this.getPlacementGroupAddressForSlice(
2200
+ params.account
2201
+ );
2202
+ const rawMetadata = await this.aptos.view({
2203
+ payload: {
2204
+ function: `${this.deployer.toString()}::placement_group::get_active_storage_providers`,
2205
+ functionArguments: [placementGroupAddress]
2206
+ }
2207
+ });
2208
+ const providers = rawMetadata[0];
2209
+ return providers.map(
2210
+ (opt) => opt.vec.length > 0 ? normalizeAddress(opt.vec[0]) : null
2211
+ );
2212
+ }
2213
+ /**
2214
+ * Retrieves the serving storage providers for a slice.
2215
+ *
2216
+ * Serving SPs are those that can respond to read requests. The serving logic is:
2217
+ * - If an Active SP exists for a slot: Only the Active SP is serving
2218
+ * - If no Active SP (transition in progress): Both Designated and Vacating SPs serve
2219
+ *
2220
+ * Each slot may have multiple serving SPs during transitions.
2221
+ *
2222
+ * @param params.account - The address of the slice account.
2223
+ * @returns An array where result[i] contains the serving SPs for slot i.
2224
+ *
2225
+ * @example
2226
+ * ```typescript
2227
+ * const providers = await client.getServingStorageProvidersForSlice({ account: sliceAddress });
2228
+ * ```
2229
+ */
2230
+ async getServingStorageProvidersForSlice(params) {
2231
+ const placementGroupAddress = await this.getPlacementGroupAddressForSlice(
2232
+ params.account
2233
+ );
2234
+ const rawMetadata = await this.aptos.view({
2235
+ payload: {
2236
+ function: `${this.deployer.toString()}::placement_group::get_serving_storage_providers`,
2237
+ functionArguments: [placementGroupAddress]
2238
+ }
2239
+ });
2240
+ const providers = rawMetadata[0];
2241
+ return providers.map(
2242
+ (slotProviders) => slotProviders.map((addr) => normalizeAddress(addr))
2243
+ );
2244
+ }
2245
+ };
2246
+
2247
+ // src/core/clients/ShelbyRPCClient.ts
126
2248
  import {
127
- CHUNK_SIZE_PARAMS,
128
- ChunkSizeScheme,
129
- DEFAULT_CHUNKSET_SIZE_BYTES,
130
- DEFAULT_CHUNK_SIZE_BYTES,
131
- ERASURE_CODE_AND_CHUNK_MAPPING
132
- } from "../chunk-JTXYKO3U.mjs";
2249
+ Hex as Hex6
2250
+ } from "@aptos-labs/ts-sdk";
2251
+
2252
+ // src/core/layout.ts
2253
+ import { z as z2 } from "zod";
2254
+ var BlobNameSchema = z2.string().min(1, "Blob name path parameter cannot be empty.").max(
2255
+ 190,
2256
+ "Blob name suffix cannot exceed 190 characters (on-chain full key limit is 256 bytes)."
2257
+ ).refine((name) => !name.endsWith("/"), {
2258
+ message: "Blob name cannot end with a slash"
2259
+ });
2260
+ var ChunkKey = class {
2261
+ constructor(account, blobName, chunksetIdx, chunkIdx, config) {
2262
+ this.account = account;
2263
+ this.blobName = blobName;
2264
+ this.chunksetIdx = chunksetIdx;
2265
+ this.chunkIdx = chunkIdx;
2266
+ this.config = config;
2267
+ if (chunkIdx >= config.erasure_n) {
2268
+ throw new Error(
2269
+ `Cannot create a chunk with idx ${chunkIdx}. M+K=${config.erasure_n}`
2270
+ );
2271
+ }
2272
+ }
2273
+ key() {
2274
+ return `${this.account.toString()}.${this.blobName}.${this.chunksetIdx}.${this.chunkIdx}`;
2275
+ }
2276
+ // Returns the range in the blob that this key represents, or "parity" if this is parity chunk.
2277
+ range() {
2278
+ if (this.chunkIdx >= this.config.erasure_k) {
2279
+ return "parity";
2280
+ }
2281
+ const chunksetStart = this.chunksetIdx * this.config.chunkSizeBytes * this.config.erasure_k;
2282
+ const chunkStart = chunksetStart + this.chunkIdx * this.config.chunkSizeBytes;
2283
+ return {
2284
+ start: chunkStart,
2285
+ end: chunkStart + this.config.chunkSizeBytes
2286
+ };
2287
+ }
2288
+ };
2289
+
2290
+ // src/core/promises.ts
2291
+ function sleep(ms) {
2292
+ return new Promise((resolve) => setTimeout(resolve, ms));
2293
+ }
2294
+
2295
+ // src/core/rpc-responses.ts
2296
+ import { z as z3 } from "zod";
2297
+ var ChallengeResponseSchema = z3.object({
2298
+ challenge: z3.string(),
2299
+ expiresAt: z3.number()
2300
+ });
2301
+ var RPCErrorResponseSchema = z3.object({
2302
+ error: z3.string()
2303
+ });
2304
+ var StaleMicropaymentErrorResponseSchema = z3.object({
2305
+ error: z3.string().optional(),
2306
+ storedMicropayment: z3.string().optional()
2307
+ });
2308
+
2309
+ // src/core/types/payments.ts
133
2310
  import {
134
- DEFAULT_ERASURE_D,
135
- DEFAULT_ERASURE_K,
136
- DEFAULT_ERASURE_M,
137
- DEFAULT_ERASURE_N,
138
- DEFAULT_SAMPLE_SIZE,
139
- ERASURE_CODE_PARAMS,
140
- ErasureCodingScheme
141
- } from "../chunk-AUQDI5BS.mjs";
2311
+ AccountAddress as AccountAddress4,
2312
+ Deserializer,
2313
+ Hex as Hex5,
2314
+ Serializer
2315
+ } from "@aptos-labs/ts-sdk";
2316
+ var MICROPAYMENTS_MODULE_NAME = "micropayments";
2317
+ var WITHDRAW_APPROVAL_STRUCT_NAME = "WithdrawApproval";
2318
+ function serializeTypeInfo(serializer, moduleAddress, moduleName, structName) {
2319
+ moduleAddress.serialize(serializer);
2320
+ const moduleNameBytes = new TextEncoder().encode(moduleName);
2321
+ serializer.serializeBytes(moduleNameBytes);
2322
+ const structNameBytes = new TextEncoder().encode(structName);
2323
+ serializer.serializeBytes(structNameBytes);
2324
+ }
2325
+ var StaleChannelStateError = class _StaleChannelStateError extends Error {
2326
+ /**
2327
+ * The last valid micropayment stored by the server.
2328
+ * Clients can use this to reset their local channel state.
2329
+ */
2330
+ storedMicropayment;
2331
+ constructor(storedMicropayment, message) {
2332
+ super(
2333
+ message ?? "Client has stale channel state. Use the returned micropayment to reset local state."
2334
+ );
2335
+ this.name = "StaleChannelStateError";
2336
+ this.storedMicropayment = storedMicropayment;
2337
+ }
2338
+ /**
2339
+ * Returns the stored micropayment as a base64-encoded string.
2340
+ */
2341
+ toBase64() {
2342
+ const bytes = this.storedMicropayment.bcsToBytes();
2343
+ const binaryString = Array.from(
2344
+ bytes,
2345
+ (byte) => String.fromCharCode(byte)
2346
+ ).join("");
2347
+ return btoa(binaryString);
2348
+ }
2349
+ /**
2350
+ * Creates a StaleChannelStateError from a base64-encoded micropayment string.
2351
+ */
2352
+ static fromBase64(base64, message) {
2353
+ const binaryString = atob(base64);
2354
+ const bytes = Uint8Array.from(binaryString, (char) => char.charCodeAt(0));
2355
+ const micropayment = SenderBuiltMicropayment.deserialize(bytes);
2356
+ return new _StaleChannelStateError(micropayment, message);
2357
+ }
2358
+ };
2359
+ var SenderBuiltMicropayment = class _SenderBuiltMicropayment {
2360
+ /**
2361
+ * The sender's address (owner of the payment channel).
2362
+ */
2363
+ sender;
2364
+ /**
2365
+ * The receiver's address (beneficiary of the withdrawal).
2366
+ */
2367
+ receiver;
2368
+ /**
2369
+ * The unique ID of the payment channel.
2370
+ */
2371
+ paymentChannelId;
2372
+ /**
2373
+ * The cumulative amount the receiver is authorized to withdraw.
2374
+ */
2375
+ amount;
2376
+ /**
2377
+ * The fungible asset metadata address.
2378
+ */
2379
+ fungibleAssetAddress;
2380
+ /**
2381
+ * Monotonically increasing sequence number for replay protection.
2382
+ */
2383
+ sequenceNumber;
2384
+ /**
2385
+ * The sender's Ed25519 public key (32 bytes).
2386
+ * Used by the receiver to verify the signature before submitting.
2387
+ */
2388
+ publicKey;
2389
+ /**
2390
+ * The Ed25519 signature of the SignedMessage<WithdrawApproval> struct.
2391
+ * The SignedMessage includes TypeInfo for domain separation.
2392
+ */
2393
+ signature;
2394
+ /**
2395
+ * The deployer address of the micropayments module.
2396
+ * This is needed to reconstruct the TypeInfo for signature verification.
2397
+ */
2398
+ deployer;
2399
+ constructor(sender, receiver, paymentChannelId, amount, fungibleAssetAddress, sequenceNumber, publicKey, signature, deployer) {
2400
+ this.sender = sender;
2401
+ this.receiver = receiver;
2402
+ this.paymentChannelId = paymentChannelId;
2403
+ this.amount = amount;
2404
+ this.fungibleAssetAddress = fungibleAssetAddress;
2405
+ this.sequenceNumber = sequenceNumber;
2406
+ this.publicKey = publicKey;
2407
+ this.signature = signature;
2408
+ this.deployer = deployer ?? AccountAddress4.fromString(MICROPAYMENTS_DEPLOYER);
2409
+ }
2410
+ /**
2411
+ * Creates the BCS-serialized message that was signed.
2412
+ * This is a SignedMessage<WithdrawApproval> which includes:
2413
+ * 1. TypeInfo (module_address, module_name, struct_name)
2414
+ * 2. WithdrawApproval struct fields
2415
+ *
2416
+ * This format is used with signature_verify_strict_t for domain separation.
2417
+ */
2418
+ getSignedMessage() {
2419
+ return _SenderBuiltMicropayment.buildSignedMessage({
2420
+ deployer: this.deployer,
2421
+ sender: this.sender,
2422
+ receiver: this.receiver,
2423
+ fungibleAssetAddress: this.fungibleAssetAddress,
2424
+ amount: this.amount,
2425
+ paymentChannelId: this.paymentChannelId,
2426
+ sequenceNumber: this.sequenceNumber
2427
+ });
2428
+ }
2429
+ /**
2430
+ * Static helper to build the SignedMessage<WithdrawApproval> bytes from raw parameters.
2431
+ * This can be used to create the message for signing without constructing the full object.
2432
+ *
2433
+ * @param params - The withdrawal approval parameters.
2434
+ * @returns The BCS-serialized SignedMessage<WithdrawApproval> bytes.
2435
+ */
2436
+ static buildSignedMessage(params) {
2437
+ const serializer = new Serializer();
2438
+ serializeTypeInfo(
2439
+ serializer,
2440
+ params.deployer,
2441
+ MICROPAYMENTS_MODULE_NAME,
2442
+ WITHDRAW_APPROVAL_STRUCT_NAME
2443
+ );
2444
+ params.sender.serialize(serializer);
2445
+ params.receiver.serialize(serializer);
2446
+ params.fungibleAssetAddress.serialize(serializer);
2447
+ serializer.serializeU64(params.amount);
2448
+ serializer.serializeU64(params.paymentChannelId);
2449
+ serializer.serializeU64(params.sequenceNumber);
2450
+ return serializer.toUint8Array();
2451
+ }
2452
+ serialize(serializer) {
2453
+ this.sender.serialize(serializer);
2454
+ this.receiver.serialize(serializer);
2455
+ this.fungibleAssetAddress.serialize(serializer);
2456
+ serializer.serializeU64(this.amount);
2457
+ serializer.serializeU64(this.paymentChannelId);
2458
+ serializer.serializeU64(this.sequenceNumber);
2459
+ serializer.serializeBytes(this.publicKey);
2460
+ serializer.serializeBytes(this.signature);
2461
+ this.deployer.serialize(serializer);
2462
+ }
2463
+ bcsToBytes() {
2464
+ const serializer = new Serializer();
2465
+ this.serialize(serializer);
2466
+ return serializer.toUint8Array();
2467
+ }
2468
+ bcsToHex() {
2469
+ return Hex5.fromHexInput(this.bcsToBytes());
2470
+ }
2471
+ toStringWithoutPrefix() {
2472
+ return this.bcsToHex().toStringWithoutPrefix();
2473
+ }
2474
+ toString() {
2475
+ return this.bcsToHex().toString();
2476
+ }
2477
+ /**
2478
+ * Deserializes a SenderBuiltMicropayment from BCS bytes.
2479
+ * @param bytes - The bytes to deserialize from (Uint8Array or hex string).
2480
+ * @returns A new SenderBuiltMicropayment instance.
2481
+ */
2482
+ static deserialize(bytes) {
2483
+ const bytesArray = typeof bytes === "string" ? Hex5.fromHexInput(bytes).toUint8Array() : bytes;
2484
+ const deserializer = new Deserializer(bytesArray);
2485
+ const sender = AccountAddress4.deserialize(deserializer);
2486
+ const receiver = AccountAddress4.deserialize(deserializer);
2487
+ const fungibleAssetAddress = AccountAddress4.deserialize(deserializer);
2488
+ const amount = deserializer.deserializeU64();
2489
+ const paymentChannelId = deserializer.deserializeU64();
2490
+ const sequenceNumber = deserializer.deserializeU64();
2491
+ const publicKey = deserializer.deserializeBytes();
2492
+ const signature = deserializer.deserializeBytes();
2493
+ const deployer = AccountAddress4.deserialize(deserializer);
2494
+ return new _SenderBuiltMicropayment(
2495
+ sender,
2496
+ receiver,
2497
+ paymentChannelId,
2498
+ amount,
2499
+ fungibleAssetAddress,
2500
+ sequenceNumber,
2501
+ publicKey,
2502
+ signature,
2503
+ deployer
2504
+ );
2505
+ }
2506
+ };
2507
+
2508
+ // src/core/clients/ShelbyRPCClient.ts
2509
+ var MICROPAYMENT_HEADER = "X-Shelby-Micropayment";
2510
+ var BLOB_OWNER_CHALLENGE_HEADER = "X-Shelby-Challenge";
2511
+ var BLOB_OWNER_SIGNATURE_HEADER = "X-Shelby-Signature";
2512
+ var BLOB_OWNER_PUBLIC_KEY_HEADER = "X-Shelby-Public-Key";
2513
+ var BLOB_OWNER_AUTH_SCHEME_HEADER = "X-Shelby-Auth-Scheme";
2514
+ var BLOB_OWNER_IDENTITY_HEADER = "X-Shelby-Identity";
2515
+ var BLOB_OWNER_DOMAIN_HEADER = "X-Shelby-Domain";
2516
+ var BLOB_OWNER_AUTH_FUNCTION_HEADER = "X-Shelby-Auth-Function";
2517
+ var INCLUSION_PROOF_HEADER = "X-Shelby-Inclusion-Proof";
2518
+ function buildAuthHeaders(auth) {
2519
+ const signatureBase64 = btoa(
2520
+ Array.from(auth.signature, (byte) => String.fromCharCode(byte)).join("")
2521
+ );
2522
+ const publicKeyHex = Hex6.fromHexInput(auth.publicKey).toString();
2523
+ const headers = {
2524
+ [BLOB_OWNER_CHALLENGE_HEADER]: auth.challenge,
2525
+ [BLOB_OWNER_SIGNATURE_HEADER]: signatureBase64,
2526
+ [BLOB_OWNER_PUBLIC_KEY_HEADER]: publicKeyHex
2527
+ };
2528
+ if (auth.authScheme === "derivable") {
2529
+ headers[BLOB_OWNER_AUTH_SCHEME_HEADER] = auth.authScheme;
2530
+ headers[BLOB_OWNER_IDENTITY_HEADER] = auth.identity;
2531
+ headers[BLOB_OWNER_DOMAIN_HEADER] = auth.domain;
2532
+ headers[BLOB_OWNER_AUTH_FUNCTION_HEADER] = auth.authFunction;
2533
+ } else if (auth.authScheme) {
2534
+ headers[BLOB_OWNER_AUTH_SCHEME_HEADER] = auth.authScheme;
2535
+ }
2536
+ return headers;
2537
+ }
2538
+ function encodeURIComponentKeepSlashes(str) {
2539
+ return encodeURIComponent(str).replace(/%2F/g, "/");
2540
+ }
2541
+ async function generateChunksetInclusionProof(chunksetRoots, chunksetIndex) {
2542
+ if (chunksetRoots.length === 0) {
2543
+ throw new Error("Cannot generate inclusion proof for empty chunkset roots");
2544
+ }
2545
+ if (chunksetIndex < 0 || chunksetIndex >= chunksetRoots.length) {
2546
+ throw new Error(
2547
+ `Chunkset index ${chunksetIndex} out of range [0, ${chunksetRoots.length})`
2548
+ );
2549
+ }
2550
+ if (chunksetRoots.length === 1) {
2551
+ return [];
2552
+ }
2553
+ const zeroHash = new Uint8Array(32);
2554
+ const siblings = [];
2555
+ let currentLeaves = chunksetRoots.map((h) => h.toUint8Array());
2556
+ let currentIdx = chunksetIndex;
2557
+ while (currentLeaves.length > 1) {
2558
+ if (currentLeaves.length % 2 !== 0) {
2559
+ currentLeaves.push(zeroHash);
2560
+ }
2561
+ const siblingIdx = currentIdx % 2 === 0 ? currentIdx + 1 : currentIdx - 1;
2562
+ siblings.push(currentLeaves[siblingIdx]);
2563
+ const nextLeaves = [];
2564
+ for (let i = 0; i < currentLeaves.length; i += 2) {
2565
+ const combined = await concatHashes([
2566
+ currentLeaves[i],
2567
+ currentLeaves[i + 1]
2568
+ ]);
2569
+ nextLeaves.push(combined.toUint8Array());
2570
+ }
2571
+ currentLeaves = nextLeaves;
2572
+ currentIdx = Math.floor(currentIdx / 2);
2573
+ }
2574
+ return siblings;
2575
+ }
2576
+ function encodeInclusionProof(siblings) {
2577
+ if (siblings.length === 0) {
2578
+ return "NONE";
2579
+ }
2580
+ const totalBytes = siblings.length * 32;
2581
+ const combined = new Uint8Array(totalBytes);
2582
+ let offset = 0;
2583
+ for (const sibling of siblings) {
2584
+ combined.set(sibling, offset);
2585
+ offset += 32;
2586
+ }
2587
+ const binaryString = Array.from(
2588
+ combined,
2589
+ (byte) => String.fromCharCode(byte)
2590
+ ).join("");
2591
+ return btoa(binaryString);
2592
+ }
2593
+ function validateTotalBytes(totalBytes) {
2594
+ if (!Number.isInteger(totalBytes) || totalBytes < 0) {
2595
+ throw new Error("totalBytes must be a non-negative integer");
2596
+ }
2597
+ }
2598
+ function isRetryableStatus(status) {
2599
+ return status === 408 || status === 429 || status >= 500;
2600
+ }
2601
+ function getErrorCode(error) {
2602
+ if (typeof error === "object" && error !== null && "code" in error && typeof error.code === "string") {
2603
+ return error.code;
2604
+ }
2605
+ if (error instanceof Error) {
2606
+ const match = error.message.match(/\bE[A-Z0-9_]+\b/);
2607
+ return match?.[0];
2608
+ }
2609
+ return void 0;
2610
+ }
2611
+ var ShelbyRPCClient = class {
2612
+ baseUrl;
2613
+ apiKey;
2614
+ rpcConfig;
2615
+ indexer;
2616
+ #signChallengeOverride;
2617
+ /**
2618
+ * Creates a new ShelbyRPCClient for interacting with Shelby RPC nodes.
2619
+ * This client handles blob storage operations including upload and download.
2620
+ *
2621
+ * @param config - The client configuration object.
2622
+ * @param config.network - The Shelby network to use.
2623
+ * @param options.signChallengeHandler - Optional override for challenge
2624
+ * signing. When set, `putBlobChunksets` uses this instead of the built-in
2625
+ * `signChallenge`. Intended for kit-level overrides (e.g. Solana DAA).
2626
+ *
2627
+ * @example
2628
+ * ```typescript
2629
+ * const client = new ShelbyRPCClient({
2630
+ * network: Network.SHELBYNET,
2631
+ * apiKey: "AG-***",
2632
+ * });
2633
+ * ```
2634
+ */
2635
+ constructor(config, options) {
2636
+ this.baseUrl = getShelbyRPCBaseUrl(config);
2637
+ this.apiKey = config.apiKey ?? config.rpc?.apiKey;
2638
+ this.rpcConfig = config.rpc ?? {};
2639
+ this.indexer = getShelbyIndexerClient(config);
2640
+ this.#signChallengeOverride = options?.signChallengeHandler;
2641
+ }
2642
+ /**
2643
+ * Request an authentication challenge for the given account.
2644
+ * The challenge must be signed and included in subsequent authenticated requests.
2645
+ *
2646
+ * @param account - The Aptos account address to authenticate as.
2647
+ * @returns The challenge string and expiration timestamp.
2648
+ *
2649
+ * @example
2650
+ * ```typescript
2651
+ * const { challenge, expiresAt } = await client.getChallenge(account.accountAddress);
2652
+ * const auth = client.signChallenge(account, challenge);
2653
+ * ```
2654
+ */
2655
+ async getChallenge(account) {
2656
+ const response = await fetch(
2657
+ buildRequestUrl("/v1/auth/challenge", this.baseUrl),
2658
+ {
2659
+ method: "POST",
2660
+ headers: {
2661
+ "Content-Type": "application/json",
2662
+ ...this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {}
2663
+ },
2664
+ body: JSON.stringify({ account: account.toString() })
2665
+ }
2666
+ );
2667
+ if (!response.ok) {
2668
+ const errorBody = await response.text().catch(() => "");
2669
+ throw new Error(
2670
+ `Failed to get challenge: status ${response.status}, body: ${errorBody}`
2671
+ );
2672
+ }
2673
+ return ChallengeResponseSchema.parse(await response.json());
2674
+ }
2675
+ /**
2676
+ * Sign a challenge using the given account and return auth credentials.
2677
+ *
2678
+ * @param account - The Aptos account to sign with.
2679
+ * @param challenge - The hex-encoded challenge string from getChallenge().
2680
+ * @returns BlobOwnerAuth credentials for authenticated requests.
2681
+ */
2682
+ signChallenge(account, challenge) {
2683
+ const challengeBytes = Hex6.fromHexInput(challenge).toUint8Array();
2684
+ const signature = account.sign(challengeBytes);
2685
+ return {
2686
+ challenge,
2687
+ signature: signature.toUint8Array(),
2688
+ publicKey: account.publicKey.toUint8Array()
2689
+ };
2690
+ }
2691
+ /**
2692
+ * Upload a single chunkset via the v2 chunkset API.
2693
+ */
2694
+ async #uploadChunkset(params) {
2695
+ const maxNonBusyRetries = 5;
2696
+ let lastResponse;
2697
+ let lastError;
2698
+ let attempts = 0;
2699
+ let consecutive429s = 0;
2700
+ let nonBusyRetries = 0;
2701
+ const chunksetUrl = buildRequestUrl(
2702
+ `/v2/chunksets/${params.account}/${params.chunksetIndex}/${params.uid}`,
2703
+ this.baseUrl
2704
+ );
2705
+ const authHeaders = buildAuthHeaders(params.auth);
2706
+ while (true) {
2707
+ if (params.signal?.aborted) {
2708
+ throw new DOMException("Upload aborted", "AbortError");
2709
+ }
2710
+ attempts++;
2711
+ try {
2712
+ lastResponse = await fetch(chunksetUrl, {
2713
+ method: "PUT",
2714
+ headers: {
2715
+ "Content-Type": "application/octet-stream",
2716
+ ...this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {},
2717
+ ...authHeaders,
2718
+ [INCLUSION_PROOF_HEADER]: params.inclusionProof
2719
+ },
2720
+ body: params.chunksetData,
2721
+ signal: params.signal
2722
+ });
2723
+ lastError = void 0;
2724
+ } catch (error) {
2725
+ if (error instanceof DOMException && error.name === "AbortError") {
2726
+ throw error;
2727
+ }
2728
+ lastError = error;
2729
+ consecutive429s = 0;
2730
+ nonBusyRetries++;
2731
+ if (nonBusyRetries < maxNonBusyRetries) {
2732
+ const delay2 = 2 ** nonBusyRetries * 100;
2733
+ await sleep(delay2);
2734
+ continue;
2735
+ }
2736
+ break;
2737
+ }
2738
+ if (lastResponse.ok) {
2739
+ const json = await lastResponse.json();
2740
+ const spAcks = json.spAcks?.map((ack) => ({
2741
+ slot: ack.slot,
2742
+ signature: Uint8Array.from(
2743
+ atob(ack.signature),
2744
+ (c) => c.charCodeAt(0)
2745
+ )
2746
+ }));
2747
+ return {
2748
+ success: json.success,
2749
+ acksReceived: json.acksReceived,
2750
+ spAcks
2751
+ };
2752
+ }
2753
+ if (lastResponse.status === 429) {
2754
+ consecutive429s++;
2755
+ const baseDelay = 500;
2756
+ const jitter = Math.random() * 200;
2757
+ const delay2 = Math.min(
2758
+ 3e4,
2759
+ 2 ** consecutive429s * baseDelay + jitter
2760
+ );
2761
+ await sleep(delay2);
2762
+ continue;
2763
+ }
2764
+ consecutive429s = 0;
2765
+ if (!isRetryableStatus(lastResponse.status)) {
2766
+ break;
2767
+ }
2768
+ nonBusyRetries++;
2769
+ if (nonBusyRetries >= maxNonBusyRetries) {
2770
+ break;
2771
+ }
2772
+ const delay = 2 ** nonBusyRetries * 100;
2773
+ await sleep(delay);
2774
+ }
2775
+ if (lastError !== void 0) {
2776
+ const errorCode = getErrorCode(lastError);
2777
+ const errorMessage = lastError instanceof Error ? lastError.message : String(lastError);
2778
+ throw new Error(
2779
+ `Failed to upload chunkset ${params.chunksetIndex} after ${attempts} attempt${attempts === 1 ? "" : "s"}. ${errorCode ? `(${errorCode}) ` : ""}Last error: ${errorMessage}`,
2780
+ { cause: lastError }
2781
+ );
2782
+ }
2783
+ const errorBody = await lastResponse?.text().catch(() => "");
2784
+ throw new Error(
2785
+ `Failed to upload chunkset ${params.chunksetIndex} after ${attempts} attempt${attempts === 1 ? "" : "s"}. status: ${lastResponse?.status}, body: ${errorBody}`
2786
+ );
2787
+ }
2788
+ /**
2789
+ * Uploads blob data to the Shelby RPC node using the v2 chunkset API.
2790
+ * This method authenticates using challenge-response and uploads chunksets
2791
+ * directly to storage providers via the RPC's worker pool.
2792
+ *
2793
+ * This method:
2794
+ * - Sends raw chunkset data directly to the RPC for erasure encoding
2795
+ * - Requires pre-computed blob commitments to generate inclusion proofs
2796
+ * - Does not support resume (each chunkset is idempotent on the SP side)
2797
+ *
2798
+ * @param params.account - The Aptos Account (with signing capability) that owns the blob.
2799
+ * @param params.uid - The blob's on-chain UID (from `BlobRegisteredEvent` at registration).
2800
+ * @param params.blobData - The raw blob data as a Uint8Array or ReadableStream.
2801
+ * @param params.commitments - Pre-computed blob commitments (from generateCommitments).
2802
+ * @param params.totalBytes - Total byte length. Required for streams; optional for Uint8Array.
2803
+ * @param params.chunksetConcurrency - Number of chunksets to upload in parallel. Defaults to 4.
2804
+ * @param params.onProgress - Optional callback for upload progress.
2805
+ * @param params.signal - Optional AbortSignal for cancellation. When aborted, in-flight
2806
+ * HTTP requests are cancelled and an AbortError is thrown.
2807
+ *
2808
+ * @example
2809
+ * ```typescript
2810
+ * // First, generate commitments for the blob
2811
+ * const commitments = await generateCommitments(provider, fileData);
2812
+ *
2813
+ * // Register the blob on chain, then read its UID from the register tx's
2814
+ * // BlobRegisteredEvent (see ShelbyBlobClient.registeredBlobUids).
2815
+ *
2816
+ * // Upload using chunkset API
2817
+ * await rpcClient.putBlobChunksets({
2818
+ * account: myAccount,
2819
+ * uid: blobUid,
2820
+ * blobData: fileData,
2821
+ * commitments,
2822
+ * chunksetConcurrency: 8,
2823
+ * });
2824
+ * ```
2825
+ */
2826
+ async putBlobChunksets(params) {
2827
+ let totalBytes;
2828
+ if (params.blobData instanceof Uint8Array) {
2829
+ totalBytes = params.totalBytes ?? params.blobData.length;
2830
+ if (totalBytes !== params.blobData.length) {
2831
+ throw new Error(
2832
+ "totalBytes must match blobData.length when blobData is a Uint8Array"
2833
+ );
2834
+ }
2835
+ } else {
2836
+ if (params.totalBytes === void 0) {
2837
+ throw new Error(
2838
+ "totalBytes is required when blobData is a ReadableStream"
2839
+ );
2840
+ }
2841
+ totalBytes = params.totalBytes;
2842
+ }
2843
+ validateTotalBytes(totalBytes);
2844
+ const chunksetConcurrency = params.chunksetConcurrency ?? 4;
2845
+ const totalChunksets = params.commitments.chunkset_commitments.length;
2846
+ const rawDataSizeFromCommitments = params.commitments.raw_data_size;
2847
+ if (rawDataSizeFromCommitments !== totalBytes) {
2848
+ throw new Error(
2849
+ `Data size mismatch: commitments were generated for ${rawDataSizeFromCommitments} bytes, but totalBytes=${totalBytes}. This will cause inclusion proof verification to fail.`
2850
+ );
2851
+ }
2852
+ const chunksetRoots = params.commitments.chunkset_commitments.map(
2853
+ (c) => Hex6.fromHexString(c.chunkset_root)
2854
+ );
2855
+ const { challenge } = await this.getChallenge(
2856
+ params.account.accountAddress
2857
+ );
2858
+ const signFn = this.#signChallengeOverride ?? this.signChallenge.bind(this);
2859
+ const auth = signFn(params.account, challenge);
2860
+ const firstChunkset = params.commitments.chunkset_commitments[0];
2861
+ if (!firstChunkset) {
2862
+ throw new Error("Commitments must have at least one chunkset");
2863
+ }
2864
+ const erasure_n = firstChunkset.chunk_commitments.length;
2865
+ const matchingEntry = findErasureSchemeByErasureN(erasure_n);
2866
+ if (!matchingEntry) {
2867
+ throw new Error(
2868
+ `Unknown erasure coding scheme with erasure_n=${erasure_n}`
2869
+ );
2870
+ }
2871
+ const [schemeKey, matchingParams] = matchingEntry;
2872
+ const erasure_k = matchingParams.erasure_k;
2873
+ const { chunkSizeBytes } = ERASURE_CODE_AND_CHUNK_MAPPING[schemeKey];
2874
+ const chunksetSize = erasure_k * chunkSizeBytes;
2875
+ const expectedChunksetCount = totalBytes === 0 ? 1 : Math.ceil(totalBytes / chunksetSize);
2876
+ if (expectedChunksetCount !== totalChunksets) {
2877
+ throw new Error(
2878
+ `Chunkset count mismatch: expected ${expectedChunksetCount} chunksets for ${totalBytes} bytes with chunksetSize=${chunksetSize}, but commitments have ${totalChunksets} chunksets. This suggests the commitments were generated with a different encoding scheme.`
2879
+ );
2880
+ }
2881
+ let uploadedBytes = 0;
2882
+ let bytesReadFromSource = 0;
2883
+ const inFlight = /* @__PURE__ */ new Set();
2884
+ async function* chunksetsFromBlob() {
2885
+ if (totalBytes === 0) {
2886
+ yield [0, new Uint8Array(chunksetSize)];
2887
+ return;
2888
+ }
2889
+ yield* readInChunks(params.blobData, chunksetSize);
2890
+ }
2891
+ const chunksetIterator = chunksetsFromBlob();
2892
+ const aggregatedAcks = /* @__PURE__ */ new Map();
2893
+ const internalAbort = new AbortController();
2894
+ if (params.signal?.aborted) {
2895
+ internalAbort.abort();
2896
+ } else if (params.signal) {
2897
+ params.signal.addEventListener("abort", () => internalAbort.abort(), {
2898
+ once: true
2899
+ });
2900
+ }
2901
+ let iteratorDone = false;
2902
+ let firstError = null;
2903
+ while (!iteratorDone || inFlight.size > 0) {
2904
+ if (internalAbort.signal.aborted) {
2905
+ throw firstError ?? new DOMException("Upload aborted", "AbortError");
2906
+ }
2907
+ while (inFlight.size < chunksetConcurrency && !iteratorDone) {
2908
+ const { value, done } = await chunksetIterator.next();
2909
+ if (done) {
2910
+ iteratorDone = true;
2911
+ break;
2912
+ }
2913
+ const [chunksetIdx, chunksetData] = value;
2914
+ bytesReadFromSource += totalBytes === 0 ? 0 : chunksetData.byteLength;
2915
+ const expectedCommitment = params.commitments.chunkset_commitments[chunksetIdx];
2916
+ if (!expectedCommitment) {
2917
+ throw new Error(
2918
+ `Chunkset index ${chunksetIdx} out of range. Commitments only have ${totalChunksets} chunksets. This suggests a chunkset size mismatch between commitment generation and upload.`
2919
+ );
2920
+ }
2921
+ const proofSiblings = await generateChunksetInclusionProof(
2922
+ chunksetRoots,
2923
+ chunksetIdx
2924
+ );
2925
+ const inclusionProof = encodeInclusionProof(proofSiblings);
2926
+ const chunksetDataCopy = new Uint8Array(chunksetData);
2927
+ const chunksetBytes = chunksetDataCopy.length;
2928
+ const uploadPromise = (async () => {
2929
+ const result = await this.#uploadChunkset({
2930
+ account: params.account.accountAddress.toString(),
2931
+ uid: params.uid,
2932
+ chunksetIndex: chunksetIdx,
2933
+ inclusionProof,
2934
+ chunksetData: chunksetDataCopy,
2935
+ auth,
2936
+ signal: internalAbort.signal
2937
+ });
2938
+ const chunksetSpAcks = result.spAcks?.map((ack) => ({
2939
+ slot: ack.slot,
2940
+ signature: ack.signature
2941
+ }));
2942
+ if (chunksetSpAcks) {
2943
+ for (const ack of chunksetSpAcks) {
2944
+ aggregatedAcks.set(ack.slot, ack.signature);
2945
+ }
2946
+ }
2947
+ uploadedBytes += chunksetBytes;
2948
+ params.onProgress?.({
2949
+ phase: "uploading",
2950
+ chunksetIdx,
2951
+ totalChunksets,
2952
+ chunksetBytes,
2953
+ uploadedBytes,
2954
+ totalBytes,
2955
+ acksReceived: result.acksReceived,
2956
+ spAcks: chunksetSpAcks
2957
+ });
2958
+ })().catch((err) => {
2959
+ if (!firstError) {
2960
+ firstError = err;
2961
+ internalAbort.abort();
2962
+ }
2963
+ }).finally(() => {
2964
+ inFlight.delete(uploadPromise);
2965
+ });
2966
+ inFlight.add(uploadPromise);
2967
+ }
2968
+ if (inFlight.size > 0) {
2969
+ await Promise.race(inFlight);
2970
+ }
2971
+ }
2972
+ if (firstError) {
2973
+ throw firstError;
2974
+ }
2975
+ if (bytesReadFromSource !== totalBytes) {
2976
+ throw new Error(
2977
+ `Data source produced ${bytesReadFromSource} bytes, but expected ${totalBytes} bytes. The stream may have ended prematurely, resulting in an incomplete upload.`
2978
+ );
2979
+ }
2980
+ const spAcks = Array.from(
2981
+ aggregatedAcks.entries()
2982
+ ).map(([slot, signature]) => ({ slot, signature }));
2983
+ return { spAcks };
2984
+ }
2985
+ /**
2986
+ * Downloads a blob from the Shelby RPC node.
2987
+ * Returns a streaming response with validation to ensure data integrity.
2988
+ *
2989
+ * @param params.account - The account that owns the blob.
2990
+ * @param params.blobName - The name/path of the blob (e.g. "folder/file.txt").
2991
+ * @param params.range - Optional byte range for partial downloads.
2992
+ * @param params.range.start - Starting byte position (inclusive).
2993
+ * @param params.range.end - Ending byte position (inclusive, optional).
2994
+ * @param params.micropayment - Optional micropayment to attach to the request.
2995
+ *
2996
+ * @returns A ShelbyBlob object containing the account, name, readable stream, and content length.
2997
+ *
2998
+ * @throws Error if the download fails or content length doesn't match.
2999
+ * @throws StaleChannelStateError if the micropayment is stale (server has newer state).
3000
+ *
3001
+ * @example
3002
+ * ```typescript
3003
+ * // Download entire blob
3004
+ * const blob = await client.getBlob({
3005
+ * account: AccountAddress.from("0x1"),
3006
+ * blobName: "documents/report.pdf"
3007
+ * });
3008
+ *
3009
+ * // Download partial content (bytes 100-199)
3010
+ * const partial = await client.getBlob({
3011
+ * account: AccountAddress.from("0x1"),
3012
+ * blobName: "large-file.bin",
3013
+ * range: { start: 100, end: 199 }
3014
+ * });
3015
+ *
3016
+ * // Download with micropayment
3017
+ * const blob = await client.getBlob({
3018
+ * account: AccountAddress.from("0x1"),
3019
+ * blobName: "documents/report.pdf",
3020
+ * micropayment: senderBuiltMicropayment
3021
+ * });
3022
+ * ```
3023
+ */
3024
+ async getBlob(params) {
3025
+ BlobNameSchema.parse(params.blobName);
3026
+ const url = buildRequestUrl(
3027
+ `/v1/blobs/${params.account.toString()}/${encodeURIComponentKeepSlashes(
3028
+ params.blobName
3029
+ )}`,
3030
+ this.baseUrl
3031
+ );
3032
+ const headers = new Headers();
3033
+ if (params.range !== void 0) {
3034
+ const { start, end } = params.range;
3035
+ if (end === void 0) {
3036
+ headers.set("Range", `bytes=${start}-`);
3037
+ } else {
3038
+ if (end < start) {
3039
+ throw new Error("Range end cannot be less than start.");
3040
+ }
3041
+ headers.set("Range", `bytes=${start}-${end}`);
3042
+ }
3043
+ }
3044
+ if (this.apiKey) {
3045
+ headers.set("Authorization", `Bearer ${this.apiKey}`);
3046
+ }
3047
+ if (params.micropayment) {
3048
+ const bytes = params.micropayment.bcsToBytes();
3049
+ const binaryString = Array.from(
3050
+ bytes,
3051
+ (byte) => String.fromCharCode(byte)
3052
+ ).join("");
3053
+ headers.set(MICROPAYMENT_HEADER, btoa(binaryString));
3054
+ }
3055
+ const response = await fetch(url, { headers });
3056
+ if (response.status === 409) {
3057
+ let json;
3058
+ try {
3059
+ json = await response.json();
3060
+ } catch {
3061
+ throw new Error(
3062
+ `Failed to download blob: ${response.status} ${response.statusText}`
3063
+ );
3064
+ }
3065
+ const parseResult = StaleMicropaymentErrorResponseSchema.safeParse(json);
3066
+ if (!parseResult.success) {
3067
+ throw new Error(
3068
+ `Failed to download blob: ${response.status} ${response.statusText}`
3069
+ );
3070
+ }
3071
+ const errorBody = parseResult.data;
3072
+ if (errorBody.storedMicropayment) {
3073
+ throw StaleChannelStateError.fromBase64(
3074
+ errorBody.storedMicropayment,
3075
+ errorBody.error
3076
+ );
3077
+ }
3078
+ throw new Error(
3079
+ errorBody.error ?? `Failed to download blob: ${response.status} ${response.statusText}`
3080
+ );
3081
+ }
3082
+ if (!response.ok) {
3083
+ throw new Error(
3084
+ `Failed to download blob: ${response.status} ${response.statusText}`
3085
+ );
3086
+ }
3087
+ if (!response.body) {
3088
+ throw new Error("Response body is null");
3089
+ }
3090
+ const contentLengthHeader = response.headers.get("content-length");
3091
+ if (contentLengthHeader === null) {
3092
+ throw new Error(
3093
+ "Response did not have content-length header, which is required"
3094
+ );
3095
+ }
3096
+ const expectedContentLength = Number.parseInt(contentLengthHeader, 10);
3097
+ if (Number.isNaN(expectedContentLength)) {
3098
+ throw new Error(
3099
+ `Invalid content-length header received: ${contentLengthHeader}`
3100
+ );
3101
+ }
3102
+ const validatingStream = new ReadableStream({
3103
+ start(controller) {
3104
+ const maybeReader = response.body?.getReader();
3105
+ if (!maybeReader) {
3106
+ controller.error(new Error("Response body reader is unavailable"));
3107
+ return;
3108
+ }
3109
+ const reader = maybeReader;
3110
+ let bytesReceived = 0;
3111
+ function pump() {
3112
+ return reader.read().then(({ done, value }) => {
3113
+ if (done) {
3114
+ if (bytesReceived !== expectedContentLength) {
3115
+ controller.error(
3116
+ new Error(
3117
+ `Downloaded data size (${bytesReceived} bytes) does not match content-length header (${expectedContentLength} bytes). This might indicate a partial or corrupted download.`
3118
+ )
3119
+ );
3120
+ return;
3121
+ }
3122
+ controller.close();
3123
+ return;
3124
+ }
3125
+ bytesReceived += value.byteLength;
3126
+ controller.enqueue(value);
3127
+ return pump();
3128
+ }).catch((error) => {
3129
+ controller.error(error);
3130
+ });
3131
+ }
3132
+ return pump();
3133
+ }
3134
+ });
3135
+ return {
3136
+ account: normalizeAddress(params.account),
3137
+ name: params.blobName,
3138
+ readable: validatingStream,
3139
+ contentLength: expectedContentLength
3140
+ };
3141
+ }
3142
+ };
3143
+
3144
+ // src/core/clients/ShelbyClient.ts
3145
+ var ShelbyClient = class {
3146
+ /**
3147
+ * The coordination client is used to interact with the Aptos blockchain which handles the commitments
3148
+ * and metadata for blobs.
3149
+ */
3150
+ coordination;
3151
+ /**
3152
+ * The metadata client is used for protocol-level metadata queries.
3153
+ */
3154
+ metadata;
3155
+ /**
3156
+ * The RPC client is used to interact with the Shelby RPC node which can be responsible for storing,
3157
+ * confirming, and retrieving blobs from the storage layer.
3158
+ *
3159
+ * If not provided, the default RPC client will be created.
3160
+ */
3161
+ rpc;
3162
+ /**
3163
+ * The configuration for the Shelby client.
3164
+ */
3165
+ config;
3166
+ /**
3167
+ * The Aptos client.
3168
+ *
3169
+ * If not provided, a default Aptos client will be created.
3170
+ */
3171
+ aptos;
3172
+ /**
3173
+ * The erasure coding provider used for encoding/decoding operations.
3174
+ * Lazily initialized on first use if not provided.
3175
+ */
3176
+ _provider;
3177
+ /**
3178
+ * Creates a new ShelbyClient instance for interacting with the Shelby Protocol.
3179
+ * This client combines blockchain operations (via coordination) and storage operations (via RPC).
3180
+ *
3181
+ * @param config - The client configuration object.
3182
+ * @param config.aptos.config - The Aptos network configuration.
3183
+ * @param config.shelby.rpc.baseUrl - The base URL of the Shelby RPC node (optional, defaults to devnet).
3184
+ * @param config.shelby.indexer - The indexer configuration for GraphQL queries.
3185
+ * @param provider - Optional erasure coding provider for encoding/decoding operations.
3186
+ * If not provided, a ClayErasureCodingProvider will be created on first use.
3187
+ * Pass a shared provider to reuse across multiple clients.
3188
+ *
3189
+ * @example
3190
+ * ```typescript
3191
+ * // Basic usage (provider created automatically)
3192
+ * const client = new ShelbyClient({
3193
+ * network: Network.SHELBYNET,
3194
+ * });
3195
+ *
3196
+ * // Advanced: Share provider across multiple clients
3197
+ * const provider = await ClayErasureCodingProvider.create();
3198
+ * const mainnetClient = new ShelbyClient(mainnetConfig, provider);
3199
+ * const devnetClient = new ShelbyClient(devnetConfig, provider);
3200
+ * ```
3201
+ */
3202
+ constructor(config, provider) {
3203
+ this.config = config;
3204
+ this.aptos = new Aptos3(getAptosConfig(config));
3205
+ this.coordination = new ShelbyBlobClient(config);
3206
+ this.metadata = new ShelbyMetadataClient(config);
3207
+ this.rpc = new ShelbyRPCClient(config, {
3208
+ signChallengeHandler: (account, challenge) => this.signChallenge(account, challenge)
3209
+ });
3210
+ this._provider = provider;
3211
+ }
3212
+ /**
3213
+ * Sign an authentication challenge for blob owner verification.
3214
+ *
3215
+ * The default implementation delegates to `ShelbyRPCClient.signChallenge`
3216
+ * which works for standard Ed25519 accounts. Kits that use derived /
3217
+ * abstracted accounts (Solana, Ethereum) should override this method to
3218
+ * provide the correct public key bytes and derivation metadata.
3219
+ */
3220
+ signChallenge(account, challenge) {
3221
+ return this.rpc.signChallenge(account, challenge);
3222
+ }
3223
+ /**
3224
+ * Get the erasure coding provider, creating it if necessary.
3225
+ * This allows lazy initialization for users who don't provide a provider.
3226
+ */
3227
+ async getProvider() {
3228
+ if (!this._provider) {
3229
+ this._provider = await ClayErasureCodingProvider.create(
3230
+ defaultErasureCodingConfig()
3231
+ );
3232
+ }
3233
+ return this._provider;
3234
+ }
3235
+ /**
3236
+ * Build orderless transaction options (a random replay-protection nonce) for
3237
+ * the per-blob commit transactions. batchUpload finalizes blobs
3238
+ * concurrently, so without orderless replay protection the parallel
3239
+ * same-account submissions collide on the sequence number ("transaction
3240
+ * already in mempool with a different payload"). The nonce makes each commit
3241
+ * independent regardless of the client's `orderless` config flag.
3242
+ */
3243
+ orderlessCommitOptions() {
3244
+ return {
3245
+ build: {
3246
+ options: {
3247
+ replayProtectionNonce: crypto.getRandomValues(new Uint32Array(1))[0]
3248
+ }
3249
+ }
3250
+ };
3251
+ }
3252
+ /**
3253
+ * Resolve the on-chain UID assigned to `blobName` from a committed register
3254
+ * transaction. `register_blob` only publishes the uid -> name mapping via
3255
+ * `BlobRegisteredEvent` (a pending blob is not yet in the `objects` map, so it
3256
+ * cannot be read back by name), so the upload flow must parse it here before
3257
+ * uploading bytes or committing.
3258
+ */
3259
+ uidFromRegisterTx(tx, account, blobName) {
3260
+ const events = "events" in tx ? tx.events : [];
3261
+ const objectName = createBlobKey({ account, blobName });
3262
+ const match = ShelbyBlobClient.registeredBlobUids(
3263
+ events,
3264
+ this.coordination.deployer
3265
+ ).find((registered) => registered.objectName === objectName);
3266
+ if (match === void 0) {
3267
+ throw new Error(
3268
+ `No BlobRegisteredEvent for '${blobName}' in register transaction ${tx.hash}`
3269
+ );
3270
+ }
3271
+ return match.uid;
3272
+ }
3273
+ /**
3274
+ * Await a blob-registration transaction, rephrasing on-chain location
3275
+ * failures into a human-readable message.
3276
+ */
3277
+ async waitForRegistration(transactionHash) {
3278
+ try {
3279
+ return await this.coordination.aptos.waitForTransaction({
3280
+ transactionHash
3281
+ });
3282
+ } catch (error) {
3283
+ const message = error instanceof Error ? error.message : String(error);
3284
+ const described = describeLocationError(message);
3285
+ throw described ? new Error(described, { cause: error }) : error;
3286
+ }
3287
+ }
3288
+ /**
3289
+ * The base URL for the Shelby RPC node.
3290
+ */
3291
+ get baseUrl() {
3292
+ return getShelbyRPCBaseUrl(this.config);
3293
+ }
3294
+ /**
3295
+ * Uploads a blob to the Shelby network.
3296
+ * This method handles the complete upload flow including commitment generation,
3297
+ * blockchain registration, and storage upload.
3298
+ *
3299
+ * Note: This method accepts only `Uint8Array` and buffers the entire blob in memory.
3300
+ * For streaming uploads of large files (e.g. >2 GiB), orchestrate the steps manually
3301
+ * using `generateCommitments()`, `coordination.registerBlob()`, `rpc.putBlobChunksets()`,
3302
+ * and `coordination.commitObject()` with a `ReadableStream`.
3303
+ *
3304
+ * @param params.blobData - The raw data to upload as a Uint8Array.
3305
+ * @param params.signer - The account that signs and pays for the transaction.
3306
+ * @param params.blobName - The name/path of the blob (e.g. "folder/file.txt").
3307
+ * @param params.expirationMicros - The expiration time in microseconds since Unix epoch.
3308
+ * @param params.options - Optional upload configuration.
3309
+ * @param params.options.chunksetSizeBytes - Custom chunkset size.
3310
+ * @param params.options.build - Additional Aptos transaction options.
3311
+ *
3312
+ * @returns The transaction and generated blob commitments (when implemented).
3313
+ *
3314
+ * @example
3315
+ * ```typescript
3316
+ * await client.upload({
3317
+ * blobData: Buffer.from("Hello, World!"),
3318
+ * signer: account,
3319
+ * blobName: "hello.txt",
3320
+ * expirationMicros: Date.now() * 1000 + 86400_000_000 // 24 hours from now
3321
+ * });
3322
+ * ```
3323
+ */
3324
+ async upload(params) {
3325
+ const provider = await this.getProvider();
3326
+ const blobCommitments = await generateCommitments(
3327
+ provider,
3328
+ params.blobData
3329
+ );
3330
+ const { transaction: pendingRegisterBlobTransaction } = await this.coordination.registerBlob({
3331
+ account: params.signer,
3332
+ blobName: params.blobName,
3333
+ blobMerkleRoot: blobCommitments.blob_merkle_root,
3334
+ size: params.blobData.length,
3335
+ expirationMicros: params.expirationMicros,
3336
+ config: provider.config,
3337
+ options: params.options
3338
+ });
3339
+ const registerTx = await this.waitForRegistration(
3340
+ pendingRegisterBlobTransaction.hash
3341
+ );
3342
+ const uid = this.uidFromRegisterTx(
3343
+ registerTx,
3344
+ params.signer.accountAddress,
3345
+ params.blobName
3346
+ );
3347
+ const { spAcks } = await this.rpc.putBlobChunksets({
3348
+ account: params.signer,
3349
+ uid,
3350
+ blobData: params.blobData,
3351
+ commitments: blobCommitments,
3352
+ totalBytes: params.blobData.length
3353
+ });
3354
+ const requiredAcks = requiredAckCount(provider.config.erasure_n);
3355
+ if (spAcks.length < requiredAcks) {
3356
+ throw new Error(
3357
+ `Insufficient storage provider acknowledgements for '${params.blobName}': got ${spAcks.length}, need ${requiredAcks} (erasure_d) to finalize on chain`
3358
+ );
3359
+ }
3360
+ const { transaction: pendingCommitTransaction } = await this.coordination.commitObject({
3361
+ account: params.signer,
3362
+ uid,
3363
+ blobName: params.blobName,
3364
+ overwrite: true,
3365
+ storageProviderAcks: spAcks,
3366
+ options: this.orderlessCommitOptions()
3367
+ });
3368
+ const confirmedTx = await this.coordination.aptos.waitForTransaction({
3369
+ transactionHash: pendingCommitTransaction.hash
3370
+ });
3371
+ if (!confirmedTx.success) {
3372
+ throw new Error(
3373
+ `commit_object tx failed for '${params.blobName}': ${confirmedTx.vm_status}`
3374
+ );
3375
+ }
3376
+ }
3377
+ /**
3378
+ * Uploads a batch of blobs to the Shelby network.
3379
+ * This method handles the complete upload flow including commitment generation,
3380
+ * blockchain registration, and storage upload.
3381
+ *
3382
+ * Note: This method accepts only `Uint8Array` and buffers each blob in memory.
3383
+ * For streaming uploads of large files, orchestrate the steps manually using
3384
+ * `generateCommitments()`, `coordination.registerBlob()`, `rpc.putBlobChunksets()`,
3385
+ * and `coordination.commitObject()` with a `ReadableStream`.
3386
+ *
3387
+ * @param params.blobs - The blobs to upload.
3388
+ * @param params.blobs.blobData - The raw data to upload as a Uint8Array.
3389
+ * @param params.blobs.blobName - The name/path of the blob (e.g. "folder/file.txt").
3390
+ * @param params.expirationMicros - The expiration time in microseconds since Unix epoch.
3391
+ * @param params.signer - The account that signs and pays for the transaction.
3392
+ * @param params.options - Optional upload configuration.
3393
+ * @param params.options.chunksetSizeBytes - Custom chunkset size.
3394
+ * @param params.options.build - Additional Aptos transaction options.
3395
+ *
3396
+ * @returns The transaction and generated blob commitments (when implemented).
3397
+ *
3398
+ * @example
3399
+ * ```typescript
3400
+ * await client.batchUpload({
3401
+ * blobs: [
3402
+ * { blobData: Buffer.from("Hello, World!"), blobName: "hello.txt" },
3403
+ * { blobData: Buffer.from("Hello, World 2!"), blobName: "hello2.txt" },
3404
+ * ],
3405
+ * expirationMicros: Date.now() * 1000 + 86400_000_000 // 24 hours from now
3406
+ * });
3407
+ * ```
3408
+ */
3409
+ async batchUpload(params) {
3410
+ const provider = await this.getProvider();
3411
+ const prepared = await Promise.all(
3412
+ params.blobs.map(async (blob) => ({
3413
+ blob,
3414
+ commitments: await generateCommitments(provider, blob.blobData)
3415
+ }))
3416
+ );
3417
+ const { transaction: pendingRegisterBlobTransaction } = await this.coordination.batchRegisterBlobs({
3418
+ account: params.signer,
3419
+ expirationMicros: params.expirationMicros,
3420
+ blobs: prepared.map((p) => ({
3421
+ blobName: p.blob.blobName,
3422
+ blobSize: p.blob.blobData.length,
3423
+ blobMerkleRoot: p.commitments.blob_merkle_root
3424
+ })),
3425
+ config: provider.config,
3426
+ options: params.options
3427
+ });
3428
+ const registerTx = await this.waitForRegistration(
3429
+ pendingRegisterBlobTransaction.hash
3430
+ );
3431
+ const uidByObjectName = new Map(
3432
+ ShelbyBlobClient.registeredBlobUids(
3433
+ "events" in registerTx ? registerTx.events : [],
3434
+ this.coordination.deployer
3435
+ ).map((registered) => [registered.objectName, registered.uid])
3436
+ );
3437
+ const requiredAcks = requiredAckCount(provider.config.erasure_n);
3438
+ const limit = pLimit(3);
3439
+ await Promise.all(
3440
+ prepared.map(
3441
+ (p) => limit(async () => {
3442
+ const objectName = createBlobKey({
3443
+ account: params.signer.accountAddress,
3444
+ blobName: p.blob.blobName
3445
+ });
3446
+ const uid = uidByObjectName.get(objectName);
3447
+ if (uid === void 0) {
3448
+ throw new Error(
3449
+ `No BlobRegisteredEvent for '${p.blob.blobName}' in batch register transaction ${registerTx.hash}`
3450
+ );
3451
+ }
3452
+ const { spAcks } = await this.rpc.putBlobChunksets({
3453
+ account: params.signer,
3454
+ uid,
3455
+ blobData: p.blob.blobData,
3456
+ commitments: p.commitments,
3457
+ totalBytes: p.blob.blobData.length
3458
+ });
3459
+ if (spAcks.length < requiredAcks) {
3460
+ throw new Error(
3461
+ `Insufficient storage provider acknowledgements for '${p.blob.blobName}': got ${spAcks.length}, need ${requiredAcks} (erasure_d) to finalize on chain`
3462
+ );
3463
+ }
3464
+ const { transaction: pendingCommitTransaction } = await this.coordination.commitObject({
3465
+ account: params.signer,
3466
+ uid,
3467
+ blobName: p.blob.blobName,
3468
+ overwrite: true,
3469
+ storageProviderAcks: spAcks,
3470
+ options: this.orderlessCommitOptions()
3471
+ });
3472
+ const confirmedTx = await this.coordination.aptos.waitForTransaction({
3473
+ transactionHash: pendingCommitTransaction.hash
3474
+ });
3475
+ if (!confirmedTx.success) {
3476
+ throw new Error(
3477
+ `commit_object tx failed for '${p.blob.blobName}': ${confirmedTx.vm_status}`
3478
+ );
3479
+ }
3480
+ })
3481
+ )
3482
+ );
3483
+ }
3484
+ /**
3485
+ * Downloads a blob from the Shelby RPC node.
3486
+ *
3487
+ * @param params.account - The account namespace the blob is stored in (e.g. "0x1")
3488
+ * @param params.blobName - The name of the blob (e.g. "foo/bar")
3489
+ * @param params.range - The range of the blob to download.
3490
+ *
3491
+ * @returns A `ShelbyBlob` object containing the blob data.
3492
+ *
3493
+ * @example
3494
+ * ```typescript
3495
+ * const blob = await client.download({
3496
+ * account,
3497
+ * blobName: "foo/bar.txt",
3498
+ * });
3499
+ * ```
3500
+ */
3501
+ async download(params) {
3502
+ return await this.rpc.getBlob(params);
3503
+ }
3504
+ /**
3505
+ *
3506
+ * Funds an account with ShelbyUSD tokens.
3507
+ *
3508
+ * @param params.address - The address to fund.
3509
+ * @param params.amount - The amount to fund.
3510
+ * @returns The transaction hash of the funded account.
3511
+ *
3512
+ * @example
3513
+ * ```typescript
3514
+ * const hash = await client.fundAccountWithShelbyUSD({
3515
+ * address: "0x1",
3516
+ * amount: 100000000,
3517
+ * });
3518
+ * ```
3519
+ */
3520
+ async fundAccountWithShelbyUSD(params) {
3521
+ if (this.config.network === Network4.TESTNET) {
3522
+ throw new Error(
3523
+ `ShelbyUSD cannot be minted programmatically on ${Network4.TESTNET}. Please use the faucet at https://docs.shelby.xyz/apis/faucet/shelbyusd instead.`
3524
+ );
3525
+ }
3526
+ const { address, amount } = params;
3527
+ try {
3528
+ const faucet = this.config.faucet?.baseUrl ?? "https://faucet.shelbynet.shelby.xyz/fund?asset=shelbyusd";
3529
+ const authToken = this.config.faucet?.authToken;
3530
+ const response = await fetch(`${faucet}`, {
3531
+ method: "POST",
3532
+ body: JSON.stringify({
3533
+ address: normalizeAddress(address).toString(),
3534
+ amount
3535
+ }),
3536
+ headers: {
3537
+ "Content-Type": "application/json",
3538
+ ...authToken ? { Authorization: `Bearer ${authToken}` } : {}
3539
+ }
3540
+ });
3541
+ if (!response.ok) {
3542
+ const errorBody = await response.text();
3543
+ throw new Error(`Failed to fund account: ${errorBody}`);
3544
+ }
3545
+ const json = await response.json();
3546
+ const res = await this.aptos.waitForTransaction({
3547
+ transactionHash: json.txn_hashes[0],
3548
+ options: {
3549
+ timeoutSecs: DEFAULT_TXN_TIMEOUT_SEC,
3550
+ checkSuccess: true
3551
+ }
3552
+ });
3553
+ if (res.type === TransactionResponseType.User) {
3554
+ return res.hash;
3555
+ }
3556
+ throw new Error(
3557
+ `Unexpected transaction received for fund account: ${res.type}`
3558
+ );
3559
+ } catch (error) {
3560
+ throw new Error(`Failed to fund account: ${error}`);
3561
+ }
3562
+ }
3563
+ /**
3564
+ * Fund an account with APT tokens
3565
+ *
3566
+ * @param params.address - The address to fund
3567
+ * @param params.amount - The amount to fund
3568
+ * @returns The transaction hash of the funded account
3569
+ *
3570
+ * @example
3571
+ * ```typescript
3572
+ * const hash = await client.fundAccountWithAPT({
3573
+ * address: "0x1",
3574
+ * amount: 100000000,
3575
+ * });
3576
+ * ```
3577
+ */
3578
+ async fundAccountWithAPT(params) {
3579
+ const transaction = await this.aptos.fundAccount({
3580
+ accountAddress: params.address,
3581
+ amount: params.amount
3582
+ });
3583
+ return transaction.hash;
3584
+ }
3585
+ };
3586
+
3587
+ // src/core/clients/ShelbyMicropaymentChannelClient.ts
142
3588
  import {
143
- DEFAULT_PROJECT_DESCRIPTION,
144
- DEFAULT_PROJECT_NAME,
145
- MICROPAYMENTS_DEPLOYER,
146
- NetworkToGasStationBaseUrl,
147
- NetworkToShelbyBlobIndexerBaseUrl,
148
- NetworkToShelbyRPCBaseUrl,
149
- SHELBYUSD_FA_METADATA_ADDRESS,
150
- SHELBYUSD_TOKEN_ADDRESS,
151
- SHELBYUSD_TOKEN_MODULE,
152
- SHELBYUSD_TOKEN_NAME,
153
- SHELBY_DEPLOYER,
154
- TOKEN_DEPLOYER,
155
- TOKEN_OBJECT_ADDRESS
156
- } from "../chunk-MNCQBEMS.mjs";
157
- import "../chunk-7P6ASYW6.mjs";
3589
+ AccountAddress as AccountAddress5,
3590
+ Aptos as Aptos4,
3591
+ MoveVector
3592
+ } from "@aptos-labs/ts-sdk";
3593
+ var ShelbyMicropaymentChannelClient = class _ShelbyMicropaymentChannelClient {
3594
+ aptos;
3595
+ deployer;
3596
+ indexer;
3597
+ /**
3598
+ * The ShelbyMicropaymentChannelClient is used to interact with the Micropayment contract on the Aptos blockchain. This
3599
+ * includes functions for the full lifecycle of micropayment channels: creation, withdrawals, expiration extensions, etc.
3600
+ *
3601
+ * @param config - The client configuration object.
3602
+ * @param config.network - The Shelby network to use.
3603
+ *
3604
+ * @example
3605
+ * ```typescript
3606
+ * const client = new ShelbyMicropaymentChannelClient({
3607
+ * aptos: {
3608
+ * network: Network.SHELBYNET,
3609
+ * clientConfig: {
3610
+ * API_KEY: "AG-***",
3611
+ * },
3612
+ * },
3613
+ * });
3614
+ * ```
3615
+ */
3616
+ constructor(config) {
3617
+ this.aptos = new Aptos4(getAptosConfig(config));
3618
+ this.deployer = config.deployer ?? AccountAddress5.fromString(MICROPAYMENTS_DEPLOYER);
3619
+ this.indexer = getShelbyIndexerClient(config);
3620
+ }
3621
+ /**
3622
+ * Calls initialize function so caller can thereafter create micropayment channels.
3623
+ *
3624
+ * @param params.sender - The account that will be sending funds to various receivers in micropayment channels.
3625
+ * @param params.options - Optional transaction building options.
3626
+ *
3627
+ * @returns An object containing the pending transaction.
3628
+ *
3629
+ * @example
3630
+ * ```typescript
3631
+ *
3632
+ * const { transaction } = await client.initializePaymentChannels({
3633
+ * sender: sender,
3634
+ * });
3635
+ * ```
3636
+ */
3637
+ async initializePaymentChannels(params) {
3638
+ const transaction = await this.aptos.transaction.build.simple({
3639
+ options: params.options,
3640
+ data: {
3641
+ function: `${(this.deployer ?? MICROPAYMENTS_DEPLOYER).toString()}::micropayments::initialize_payment_channels`,
3642
+ functionArguments: []
3643
+ },
3644
+ sender: params.sender.accountAddress
3645
+ });
3646
+ return {
3647
+ transaction: await this.aptos.signAndSubmitTransaction({
3648
+ signer: params.sender,
3649
+ transaction
3650
+ })
3651
+ };
3652
+ }
3653
+ /**
3654
+ * Creates a micropayment channel to start a channel bweteen a sender and a receiver for a specific asset.
3655
+ *
3656
+ * @param params.deployer - Optional deployer account address. Defaults to SHELBY_DEPLOYER.
3657
+ * @param params.sender - The account that will be sending funds.
3658
+ * @param params.receiver - The account that will be receiving funds.
3659
+ * @param params.expirationMicros - The expiration of the micropayment channel.
3660
+ * @param params.depositAmount - The amount of the asset locked to the channel.
3661
+ * @param params.fungibleAssetAddress - The account address of the fungible asset.
3662
+ * @param params.options - Optional transaction building options.
3663
+ *
3664
+ * @returns An object containing the pending transaction.
3665
+ *
3666
+ * @example
3667
+ * ```typescript
3668
+ *
3669
+ * const { transaction } = await client.createChannel({
3670
+ * sender: sender,
3671
+ * receiver: receiver,
3672
+ * expirationMicros: Date.now() * 1000 + 86400_000_000, // 1 day from now in microseconds
3673
+ * depositAmount: 0.001,
3674
+ * fungibleAssetAddress: fungibleAssetAddress,
3675
+ * });
3676
+ * ```
3677
+ */
3678
+ async createChannel(params) {
3679
+ const transaction = await this.aptos.transaction.build.simple({
3680
+ options: params.options,
3681
+ data: _ShelbyMicropaymentChannelClient.makeCreateMicropaymentChannelPayload(
3682
+ {
3683
+ deployer: this.deployer,
3684
+ receiver: params.receiver,
3685
+ expirationMicros: params.expirationMicros,
3686
+ depositAmount: params.depositAmount,
3687
+ fungibleAssetAddress: params.fungibleAssetAddress,
3688
+ publicKey: params.publicKey ?? params.sender.publicKey.toUint8Array()
3689
+ }
3690
+ ),
3691
+ sender: params.sender.accountAddress
3692
+ });
3693
+ return {
3694
+ transaction: await this.aptos.signAndSubmitTransaction({
3695
+ signer: params.sender,
3696
+ transaction
3697
+ })
3698
+ };
3699
+ }
3700
+ /**
3701
+ * Creates a micropayment channel creation payload to start a channel between a sender and a receiver for a specific asset.
3702
+ * This is a static helper method for constructing the Move function call payload.
3703
+ *
3704
+ * @param params.deployer - Optional deployer account address. Defaults to MICROPAYMENTS_DEPLOYER.
3705
+ * @param params.sender - The account that will be sending funds.
3706
+ * @param params.receiver - The account that will be receiving funds.
3707
+ * @param params.expirationMicros - The expiration of the micropayment channel.
3708
+ * @param params.depositAmount - The amount of the asset locked to the channel.
3709
+ * @param params.fungibleAssetAddress - The account address of the fungible asset.
3710
+ * @param params.publicKey - The Ed25519 public key bytes for the channel.
3711
+ *
3712
+ * @returns An Aptos transaction payload data object for the create_channel Move function.
3713
+ */
3714
+ static makeCreateMicropaymentChannelPayload(params) {
3715
+ return {
3716
+ function: `${(params.deployer ?? MICROPAYMENTS_DEPLOYER).toString()}::micropayments::create_channel`,
3717
+ functionArguments: [
3718
+ params.receiver,
3719
+ params.expirationMicros,
3720
+ params.depositAmount,
3721
+ params.fungibleAssetAddress,
3722
+ MoveVector.U8(params.publicKey)
3723
+ ]
3724
+ };
3725
+ }
3726
+ /**
3727
+ * Withdraws funds from a micropayment channel as the sender.
3728
+ *
3729
+ * @param params.sender - The account that is withdrawing funds.
3730
+ * @param params.receiver - The account the channel is configured to send funds to.
3731
+ * @param params.fungibleAssetAddress - The account address of the fungible asset.
3732
+ * @param params.options - Optional transaction generation options.
3733
+ *
3734
+ * @returns An object containing the pending transaction.
3735
+ *
3736
+ * @example
3737
+ * ```typescript
3738
+ * const { transaction } = await client.senderWithdraw({
3739
+ * sender: sender,
3740
+ * receiver: receiver,
3741
+ * fungibleAssetAddress: fungibleAssetAddress,
3742
+ * });
3743
+ * ```
3744
+ */
3745
+ async senderWithdraw(params) {
3746
+ const transaction = await this.aptos.transaction.build.simple({
3747
+ options: params.options,
3748
+ data: _ShelbyMicropaymentChannelClient.createSenderWithdrawPayload({
3749
+ deployer: this.deployer,
3750
+ receiver: params.receiver,
3751
+ fungibleAssetAddress: params.fungibleAssetAddress
3752
+ }),
3753
+ sender: params.sender.accountAddress
3754
+ });
3755
+ return {
3756
+ transaction: await this.aptos.signAndSubmitTransaction({
3757
+ signer: params.sender,
3758
+ transaction
3759
+ })
3760
+ };
3761
+ }
3762
+ /**
3763
+ * Creates a static payload for the sender_withdraw Move function.
3764
+ * This is a helper method for constructing the transaction payload without signing.
3765
+ *
3766
+ * @param params.deployer - Optional deployer account address. Defaults to MICROPAYMENTS_DEPLOYER.
3767
+ * @param params.receiver - The account address of the receiver.
3768
+ * @param params.fungibleAssetAddress - The account address of the fungible asset.
3769
+ *
3770
+ * @returns An Aptos transaction payload data object for the sender_withdraw Move function.
3771
+ */
3772
+ static createSenderWithdrawPayload(params) {
3773
+ return {
3774
+ function: `${(params.deployer ?? MICROPAYMENTS_DEPLOYER).toString()}::micropayments::sender_withdraw`,
3775
+ functionArguments: [params.receiver, params.fungibleAssetAddress]
3776
+ };
3777
+ }
3778
+ /**
3779
+ * Creates a micropayment that can be sent to a receiver.
3780
+ * The sender signs a WithdrawApproval message that authorizes the receiver
3781
+ * to withdraw funds from the micropayment channel.
3782
+ *
3783
+ * @param params.sender - The account that owns the payment channel and signs the approval.
3784
+ * @param params.receiver - The account address that will receive funds.
3785
+ * @param params.fungibleAssetAddress - The account address of the fungible asset.
3786
+ * @param params.amount - The cumulative amount to authorize (not incremental).
3787
+ * @param params.paymentChannelId - The id of the payment channel.
3788
+ * @param params.sequenceNumber - The sequence number of the micropayment. Must be >= channel's next_withdrawn_sequence_number.
3789
+ *
3790
+ * @returns A SenderBuiltMicropayment containing the signed approval.
3791
+ *
3792
+ * @example
3793
+ * ```typescript
3794
+ * const senderBuiltMicropayment = client.createMicropayment({
3795
+ * sender: senderAccount,
3796
+ * receiver: receiverAddress,
3797
+ * fungibleAssetAddress: fungibleAssetAddress,
3798
+ * amount: 100,
3799
+ * paymentChannelId: channelId,
3800
+ * sequenceNumber: 1,
3801
+ * });
3802
+ * ```
3803
+ */
3804
+ createMicropayment(params) {
3805
+ const message = SenderBuiltMicropayment.buildSignedMessage({
3806
+ deployer: this.deployer,
3807
+ sender: params.sender.accountAddress,
3808
+ receiver: params.receiver,
3809
+ fungibleAssetAddress: params.fungibleAssetAddress,
3810
+ amount: params.amount,
3811
+ paymentChannelId: params.paymentChannelId,
3812
+ sequenceNumber: params.sequenceNumber
3813
+ });
3814
+ const signature = params.sender.sign(message);
3815
+ return new SenderBuiltMicropayment(
3816
+ params.sender.accountAddress,
3817
+ params.receiver,
3818
+ BigInt(params.paymentChannelId),
3819
+ BigInt(params.amount),
3820
+ params.fungibleAssetAddress,
3821
+ BigInt(params.sequenceNumber),
3822
+ params.sender.publicKey.toUint8Array(),
3823
+ signature.toUint8Array(),
3824
+ this.deployer
3825
+ );
3826
+ }
3827
+ /**
3828
+ * Creates a static payload for the receiver_withdraw Move function.
3829
+ * This is a helper method for constructing the transaction payload.
3830
+ *
3831
+ * @param params.deployer - Optional deployer account address. Defaults to MICROPAYMENTS_DEPLOYER.
3832
+ * @param params.sender - The sender's account address.
3833
+ * @param params.fungibleAssetAddress - The account address of the fungible asset.
3834
+ * @param params.amount - The cumulative amount authorized to withdraw.
3835
+ * @param params.paymentChannelId - The payment channel id.
3836
+ * @param params.sequenceNumber - The sequence number for this withdrawal.
3837
+ * @param params.signature - The Ed25519 signature bytes.
3838
+ *
3839
+ * @returns An Aptos transaction payload data object for the receiver_withdraw Move function.
3840
+ */
3841
+ static createMicropaymentTransactionPayload(params) {
3842
+ return {
3843
+ function: `${(params.deployer ?? MICROPAYMENTS_DEPLOYER).toString()}::micropayments::receiver_withdraw`,
3844
+ functionArguments: [
3845
+ params.sender,
3846
+ params.fungibleAssetAddress,
3847
+ params.amount,
3848
+ params.paymentChannelId,
3849
+ params.sequenceNumber,
3850
+ MoveVector.U8(params.signature)
3851
+ ]
3852
+ };
3853
+ }
3854
+ /**
3855
+ * Withdraws funds from a micropayment channel as the receiver.
3856
+ * The receiver submits the sender's signed approval to claim funds.
3857
+ *
3858
+ * @param params.receiver - The receiver account that will sign and submit the transaction.
3859
+ * @param params.micropayment - The sender's signed micropayment approval.
3860
+ * @param params.options - Optional transaction generation options.
3861
+ *
3862
+ * @returns An object containing the pending transaction.
3863
+ *
3864
+ * @example
3865
+ * ```typescript
3866
+ * const { transaction } = await client.receiverWithdraw({
3867
+ * receiver: receiverAccount,
3868
+ * micropayment: senderBuiltMicropayment,
3869
+ * });
3870
+ * ```
3871
+ */
3872
+ async receiverWithdraw(params) {
3873
+ const transaction = await this.aptos.transaction.build.simple({
3874
+ options: params.options,
3875
+ data: _ShelbyMicropaymentChannelClient.createMicropaymentTransactionPayload(
3876
+ {
3877
+ deployer: this.deployer,
3878
+ sender: params.micropayment.sender,
3879
+ fungibleAssetAddress: params.micropayment.fungibleAssetAddress,
3880
+ amount: params.micropayment.amount,
3881
+ paymentChannelId: params.micropayment.paymentChannelId,
3882
+ sequenceNumber: params.micropayment.sequenceNumber,
3883
+ signature: params.micropayment.signature
3884
+ }
3885
+ ),
3886
+ sender: params.receiver.accountAddress
3887
+ });
3888
+ return {
3889
+ transaction: await this.aptos.signAndSubmitTransaction({
3890
+ signer: params.receiver,
3891
+ transaction
3892
+ })
3893
+ };
3894
+ }
3895
+ /**
3896
+ * Extends the expiration time of a micropayment channel.
3897
+ *
3898
+ * @param params.sender - The owner of the account.
3899
+ * @param params.receiver - The account address of the receiver.
3900
+ * @param params.fungibleAssetAddress - The account address of the fungible asset.
3901
+ * @param params.newExpirationMicros - The new expiration time in microseconds.
3902
+ * @param params.options - Optional transaction generation options.
3903
+ *
3904
+ * @returns An object containing the pending transaction.
3905
+ *
3906
+ * @example
3907
+ * ```typescript
3908
+ * const { transaction } = await client.extendExpirationTime({
3909
+ * sender: sender,
3910
+ * receiver: receiverAddress,
3911
+ * fungibleAssetAddress: fungibleAssetAddress,
3912
+ * newExpirationMicros: Date.now() * 1000 + 172800_000_000, // 2 days from now
3913
+ * });
3914
+ * ```
3915
+ */
3916
+ async extendExpirationTime(params) {
3917
+ const transaction = await this.aptos.transaction.build.simple({
3918
+ options: params.options,
3919
+ data: _ShelbyMicropaymentChannelClient.makeExtendExpirationTimePayload({
3920
+ deployer: this.deployer,
3921
+ receiver: params.receiver,
3922
+ fungibleAssetAddress: params.fungibleAssetAddress,
3923
+ newExpirationMicros: params.newExpirationMicros
3924
+ }),
3925
+ sender: params.sender.accountAddress
3926
+ });
3927
+ return {
3928
+ transaction: await this.aptos.signAndSubmitTransaction({
3929
+ signer: params.sender,
3930
+ transaction
3931
+ })
3932
+ };
3933
+ }
3934
+ /**
3935
+ * Creates a payload to extend the expiration time on a micropayment channel.
3936
+ * This is a static helper method for constructing the Move function call payload.
3937
+ *
3938
+ * @param params.deployer - Optional deployer account address. Defaults to MICROPAYMENTS_DEPLOYER.
3939
+ * @param params.receiver - The account that will be receiving funds.
3940
+ * @param params.expirationMicros - The new expiration of the micropayment channel.
3941
+ * @param params.fungibleAssetAddress - The account address of the fungible asset.
3942
+ *
3943
+ * @returns An Aptos transaction payload data object for the extend_expiration_time Move function.
3944
+ */
3945
+ static makeExtendExpirationTimePayload(params) {
3946
+ return {
3947
+ function: `${(params.deployer ?? MICROPAYMENTS_DEPLOYER).toString()}::micropayments::extend_expiration_time`,
3948
+ functionArguments: [
3949
+ params.receiver,
3950
+ params.fungibleAssetAddress,
3951
+ params.newExpirationMicros
3952
+ ]
3953
+ };
3954
+ }
3955
+ /**
3956
+ * Increases the deposit amount locked in a micropayment channel.
3957
+ *
3958
+ * @param params.sender - The account that is increasing the deposit.
3959
+ * @param params.receiver - The account address of the receiver.
3960
+ * @param params.fungibleAssetAddress - The account address of the fungible asset.
3961
+ * @param params.additionalAmount - The additional amount to deposit.
3962
+ * @param params.options - Optional transaction generation options.
3963
+ *
3964
+ * @returns An object containing the pending transaction.
3965
+ *
3966
+ * @example
3967
+ * ```typescript
3968
+ * const { transaction } = await client.increaseDepositAmount({
3969
+ * sender: sender,
3970
+ * receiver: receiverAddress,
3971
+ * fungibleAssetAddress: fungibleAssetAddress,
3972
+ * additionalAmount: 500,
3973
+ * });
3974
+ * ```
3975
+ */
3976
+ async increaseDepositAmount(params) {
3977
+ const transaction = await this.aptos.transaction.build.simple({
3978
+ options: params.options,
3979
+ data: _ShelbyMicropaymentChannelClient.makeIncreaseDepositAmountPayload({
3980
+ deployer: this.deployer,
3981
+ receiver: params.receiver,
3982
+ fungibleAssetAddress: params.fungibleAssetAddress,
3983
+ additionalAmount: params.additionalAmount
3984
+ }),
3985
+ sender: params.sender.accountAddress
3986
+ });
3987
+ return {
3988
+ transaction: await this.aptos.signAndSubmitTransaction({
3989
+ signer: params.sender,
3990
+ transaction
3991
+ })
3992
+ };
3993
+ }
3994
+ /**
3995
+ * Creates a payload to increase the deposit amount on a micropayment channel.
3996
+ * This is a static helper method for constructing the Move function call payload.
3997
+ *
3998
+ * @param params.deployer - Optional deployer account address. Defaults to MICROPAYMENTS_DEPLOYER.
3999
+ * @param params.receiver - The account that will be receiving funds.
4000
+ * @param params.fungibleAssetAddress - The account address of the fungible asset.
4001
+ * @param params.additionalAmount - The amount of the fungible asset to add to the channel's balance.
4002
+ *
4003
+ * @returns An Aptos transaction payload data object for the extend_expiration_time Move function.
4004
+ */
4005
+ static makeIncreaseDepositAmountPayload(params) {
4006
+ return {
4007
+ function: `${(params.deployer ?? MICROPAYMENTS_DEPLOYER).toString()}::micropayments::increase_deposit_amount`,
4008
+ functionArguments: [
4009
+ params.receiver,
4010
+ params.fungibleAssetAddress,
4011
+ params.additionalAmount
4012
+ ]
4013
+ };
4014
+ }
4015
+ /**
4016
+ * Retrieves the vector of channels owned by the sender, optionally
4017
+ * filtered by the receiver.
4018
+ *
4019
+ * @param params.sender - The account namespace owning the micropayment channels.
4020
+ * @param params.receiver? - An optional receiver account address.
4021
+ * @returns A vector of ChannelInfo objects.
4022
+ *
4023
+ * @example
4024
+ * ```typescript
4025
+ * const channelInfoVec = await client.getChannelInfo({
4026
+ * sender: AccountAddress.fromString("0x1"),
4027
+ * receiver: AccountAddress.fromString("0x2"),
4028
+ * });
4029
+ * ```
4030
+ */
4031
+ async getChannelInfo(params) {
4032
+ const functionName = params.receiver ? "get_all_channels_from_sender_to_receiver" : "get_all_channels_from_sender";
4033
+ const functionArguments = [params.sender];
4034
+ if (params.receiver) {
4035
+ functionArguments.push(params.receiver);
4036
+ }
4037
+ const rawArray = await this.aptos.view({
4038
+ payload: {
4039
+ function: `${this.deployer.toString()}::micropayments::${functionName}`,
4040
+ functionArguments
4041
+ }
4042
+ });
4043
+ const channelInfoArray = rawArray[0];
4044
+ return channelInfoArray.map(
4045
+ (channelInfo) => {
4046
+ const publicKeyHex = channelInfo.public_key.startsWith("0x") ? channelInfo.public_key.slice(2) : channelInfo.public_key;
4047
+ const publicKey = new Uint8Array(
4048
+ publicKeyHex.match(/.{1,2}/g)?.map((byte) => Number.parseInt(byte, 16)) ?? []
4049
+ );
4050
+ return {
4051
+ sender: params.sender,
4052
+ receiver: params.receiver,
4053
+ fungibleAssetAddress: normalizeAddress(
4054
+ channelInfo.asset_metadata.inner
4055
+ ),
4056
+ balance: BigInt(channelInfo.balance),
4057
+ creationMicros: BigInt(channelInfo.creation_micros),
4058
+ expirationMicros: BigInt(channelInfo.expiration_micros),
4059
+ nextWithdrawnSequenceNumber: BigInt(
4060
+ channelInfo.next_withdrawn_sequence_number
4061
+ ),
4062
+ paymentChannelId: BigInt(channelInfo.payment_channel_id),
4063
+ receiverWithdrawnAmount: BigInt(
4064
+ channelInfo.receiver_withdrawn_amount
4065
+ ),
4066
+ publicKey
4067
+ };
4068
+ }
4069
+ );
4070
+ }
4071
+ };
4072
+
4073
+ // src/core/clients/ShelbyPlacementGroupClient.ts
4074
+ var ShelbyPlacementGroupClient = class {
4075
+ indexer;
4076
+ /**
4077
+ * Creates a new ShelbyPlacementGroupClient.
4078
+ *
4079
+ * @param config - The client configuration object.
4080
+ *
4081
+ * @example
4082
+ * ```typescript
4083
+ * const pgClient = new ShelbyPlacementGroupClient({
4084
+ * network: Network.SHELBYNET,
4085
+ * });
4086
+ * ```
4087
+ */
4088
+ constructor(config) {
4089
+ this.indexer = getShelbyIndexerClient(config);
4090
+ }
4091
+ /**
4092
+ * Retrieves placement group slots from the indexer.
4093
+ *
4094
+ * @param params.where (optional) - The where clause to filter slots by.
4095
+ * @param params.pagination (optional) - The pagination options.
4096
+ * @param params.orderBy (optional) - The order by clause to sort slots by.
4097
+ * @returns The placement group slots that match the filter.
4098
+ *
4099
+ * @example
4100
+ * ```typescript
4101
+ * // Get all active slots
4102
+ * const slots = await client.getPlacementGroupSlots({
4103
+ * where: { status: { _eq: "active" } },
4104
+ * });
4105
+ * ```
4106
+ */
4107
+ async getPlacementGroupSlots(params) {
4108
+ const { limit, offset } = params.pagination ?? {};
4109
+ const { orderBy, where } = params;
4110
+ const { placement_group_slots } = await this.indexer.getPlacementGroupSlots(
4111
+ {
4112
+ where,
4113
+ limit,
4114
+ offset,
4115
+ orderBy
4116
+ }
4117
+ );
4118
+ return placement_group_slots.map(
4119
+ (slot) => ({
4120
+ placementGroup: slot.placement_group,
4121
+ slotIndex: Number(slot.slot_index),
4122
+ storageProvider: slot.storage_provider,
4123
+ status: slot.status,
4124
+ updatedAt: Number(slot.updated_at)
4125
+ })
4126
+ );
4127
+ }
4128
+ /**
4129
+ * Retrieves the total count of placement group slots from the indexer.
4130
+ *
4131
+ * @param params.where (optional) - The where clause to filter slots by.
4132
+ * @returns The count of placement group slots that match the filter.
4133
+ *
4134
+ * @example
4135
+ * ```typescript
4136
+ * // Get count of active slots
4137
+ * const count = await client.getPlacementGroupSlotsCount({
4138
+ * where: { status: { _eq: "active" } },
4139
+ * });
4140
+ * ```
4141
+ */
4142
+ async getPlacementGroupSlotsCount(params) {
4143
+ const { where } = params;
4144
+ const { placement_group_slots_aggregate } = await this.indexer.getPlacementGroupSlotsCount({ where });
4145
+ return placement_group_slots_aggregate?.aggregate?.count ?? 0;
4146
+ }
4147
+ };
4148
+
4149
+ // src/core/networks.ts
4150
+ import { Network as Network5 } from "@aptos-labs/ts-sdk";
4151
+ var shelbyNetworks = [
4152
+ Network5.LOCAL,
4153
+ Network5.TESTNET,
4154
+ Network5.SHELBYNET
4155
+ ];
4156
+ var isShelbyNetwork = (network) => {
4157
+ return shelbyNetworks.includes(network.toLowerCase());
4158
+ };
4159
+
4160
+ // src/core/shelby-explorer.ts
4161
+ import { Network as Network6 } from "@aptos-labs/ts-sdk";
4162
+ function getShelbyExplorerBaseUrl(network) {
4163
+ const normalizedNetwork = network.toLowerCase();
4164
+ switch (normalizedNetwork) {
4165
+ case Network6.MAINNET.toLowerCase():
4166
+ return "https://explorer.shelby.xyz/mainnet";
4167
+ case Network6.TESTNET.toLowerCase():
4168
+ return "https://explorer.shelby.xyz/testnet";
4169
+ case Network6.DEVNET.toLowerCase():
4170
+ return "https://explorer.shelby.xyz/devnet";
4171
+ case Network6.LOCAL.toLowerCase():
4172
+ return "https://explorer.shelby.xyz/local";
4173
+ case Network6.SHELBYNET.toLowerCase():
4174
+ return "https://explorer.shelby.xyz/shelbynet";
4175
+ default:
4176
+ return `https://explorer.shelby.xyz/${normalizedNetwork}`;
4177
+ }
4178
+ }
4179
+ function getShelbyAccountBlobsExplorerUrl(network, accountAddress) {
4180
+ const baseUrl = getShelbyExplorerBaseUrl(network);
4181
+ return `${baseUrl}/account/${accountAddress}/blobs`;
4182
+ }
4183
+ function getShelbyBlobExplorerUrl(network, accountAddress, blobName) {
4184
+ const baseUrl = getShelbyExplorerBaseUrl(network);
4185
+ return `${baseUrl}/account/${accountAddress}/blob/${encodeURIComponent(blobName)}`;
4186
+ }
4187
+ function getShelbyAccountExplorerUrl(network, accountAddress) {
4188
+ const baseUrl = getShelbyExplorerBaseUrl(network);
4189
+ return `${baseUrl}/account/${accountAddress}`;
4190
+ }
4191
+
4192
+ // src/node/clients/ShelbyNodeClient.ts
4193
+ var ShelbyNodeClient = class extends ShelbyClient {
4194
+ };
4195
+
4196
+ // src/node/testUtil.ts
4197
+ var testUtil_exports = {};
4198
+ __export(testUtil_exports, {
4199
+ makeChunk: () => makeChunk
4200
+ });
4201
+ function makeChunk(n) {
4202
+ const c = Buffer.alloc(n);
4203
+ for (let i = 0; i < n; ++i) {
4204
+ c[i] = i % 256;
4205
+ }
4206
+ return c;
4207
+ }
158
4208
  export {
159
4209
  BlobCommitmentsSchema,
160
4210
  BlobNameSchema,
4211
+ Blob_Activities_Constraint,
161
4212
  Blob_Activities_Select_Column,
4213
+ Blob_Activities_Update_Column,
4214
+ Blobs_Constraint,
162
4215
  Blobs_Select_Column,
4216
+ Blobs_Update_Column,
163
4217
  CHUNK_SIZE_PARAMS,
164
4218
  COMMITMENT_SCHEMA_VERSION,
165
4219
  ChallengeResponseSchema,
@@ -167,7 +4221,6 @@ export {
167
4221
  ChunkSizeScheme,
168
4222
  ChunksetCommitmentSchema,
169
4223
  ClayErasureCodingProvider,
170
- CompleteMultipartUploadResponseSchema,
171
4224
  Cursor_Ordering,
172
4225
  DEFAULT_CHUNKSET_SIZE_BYTES,
173
4226
  DEFAULT_CHUNK_SIZE_BYTES,
@@ -191,13 +4244,17 @@ export {
191
4244
  GetTotalBlobsSizeDocument,
192
4245
  MICROPAYMENTS_DEPLOYER,
193
4246
  MissingTransactionSubmitterError,
194
- MultipartUploadStatusResponseSchema,
195
4247
  NetworkToGasStationBaseUrl,
196
4248
  NetworkToShelbyBlobIndexerBaseUrl,
197
4249
  NetworkToShelbyRPCBaseUrl,
4250
+ ObjectCommitRejectedError,
198
4251
  Order_By,
4252
+ Placement_Group_Slots_Constraint,
199
4253
  Placement_Group_Slots_Select_Column,
4254
+ Placement_Group_Slots_Update_Column,
4255
+ Processor_Status_Constraint,
200
4256
  Processor_Status_Select_Column,
4257
+ Processor_Status_Update_Column,
201
4258
  RPCErrorResponseSchema,
202
4259
  ReedSolomonErasureCodingProvider,
203
4260
  SHELBYUSD_FA_METADATA_ADDRESS,
@@ -209,6 +4266,7 @@ export {
209
4266
  ShelbyBlobClient,
210
4267
  ShelbyClient,
211
4268
  ShelbyErrorCodes,
4269
+ ShelbyLocationErrorCodes,
212
4270
  ShelbyMetadataClient,
213
4271
  ShelbyMicropaymentChannelClient,
214
4272
  ShelbyNodeClient,
@@ -216,19 +4274,22 @@ export {
216
4274
  ShelbyRPCClient,
217
4275
  StaleChannelStateError,
218
4276
  StaleMicropaymentErrorResponseSchema,
219
- StartMultipartUploadResponseSchema,
220
4277
  TOKEN_DEPLOYER,
221
4278
  TOKEN_OBJECT_ADDRESS,
222
- UploadPartResponseSchema,
4279
+ blobEncryptionFromMoveVariant,
4280
+ blobEncryptionToMoveEnumIndex,
223
4281
  buildRequestUrl,
224
4282
  concatHashes,
225
4283
  createBlobKey,
226
4284
  createDefaultErasureCodingProvider,
227
4285
  createShelbyIndexerClient,
228
4286
  defaultErasureCodingConfig,
4287
+ describeLocationError,
229
4288
  erasureCodingConfig16Total10Data13Helper,
230
4289
  erasureCodingConfig4Total2Data3Helper,
4290
+ expectedChunksetInclusionProofHashes,
231
4291
  expectedTotalChunksets,
4292
+ findErasureSchemeByErasureN,
232
4293
  generateCommitments,
233
4294
  generateMerkleRoot,
234
4295
  getAptosAccountExplorerUrl,
@@ -240,12 +4301,15 @@ export {
240
4301
  getShelbyBlobExplorerUrl,
241
4302
  getShelbyIndexerClient,
242
4303
  isAccessDeniedError,
4304
+ isActiveForTasks,
4305
+ isActiveProviderCondition,
243
4306
  isBlobAlreadyExistsError,
244
4307
  isBlobExpiredError,
245
4308
  isBlobNotFoundError,
246
4309
  isShelbyNetwork,
247
4310
  normalizeAddress,
248
4311
  readInChunks,
4312
+ requiredAckCount,
249
4313
  shelbyNetworks,
250
4314
  testUtil_exports as testUtil,
251
4315
  zeroPadBytes