@shelby-protocol/sdk 0.3.1 → 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.
- package/dist/browser/index.d.ts +9 -9
- package/dist/browser/index.mjs +1068 -589
- package/dist/core/clients/ShelbyBlobClient.d.ts +155 -40
- package/dist/core/clients/ShelbyBlobClient.mjs +314 -112
- package/dist/core/clients/ShelbyClient.d.ts +27 -4
- package/dist/core/clients/ShelbyClient.mjs +869 -551
- package/dist/core/clients/ShelbyClientConfig.d.ts +9 -1
- package/dist/core/clients/ShelbyMetadataClient.d.ts +38 -6
- package/dist/core/clients/ShelbyMetadataClient.mjs +95 -13
- package/dist/core/clients/ShelbyMicropaymentChannelClient.d.ts +42 -0
- package/dist/core/clients/ShelbyMicropaymentChannelClient.mjs +62 -7
- package/dist/core/clients/ShelbyPlacementGroupClient.mjs +10 -7
- package/dist/core/clients/ShelbyRPCClient.d.ts +55 -66
- package/dist/core/clients/ShelbyRPCClient.mjs +344 -360
- package/dist/core/clients/index.d.ts +3 -2
- package/dist/core/clients/index.mjs +933 -551
- package/dist/core/clients/utils.mjs +1 -1
- package/dist/core/commitments.d.ts +12 -1
- package/dist/core/commitments.mjs +7 -0
- package/dist/core/constants.d.ts +1 -1
- package/dist/core/constants.mjs +1 -1
- package/dist/core/erasure/constants.d.ts +16 -1
- package/dist/core/erasure/constants.mjs +15 -1
- package/dist/core/erasure/index.d.ts +1 -1
- package/dist/core/erasure/index.mjs +15 -1
- package/dist/core/errors.d.ts +20 -1
- package/dist/core/errors.mjs +29 -0
- package/dist/core/index.d.ts +9 -9
- package/dist/core/index.mjs +1068 -589
- package/dist/core/operations/generated/sdk.d.ts +798 -42
- package/dist/core/operations/generated/sdk.mjs +93 -9
- package/dist/core/operations/index.d.ts +1 -1
- package/dist/core/operations/index.mjs +94 -10
- package/dist/core/rpc-responses.d.ts +1 -57
- package/dist/core/rpc-responses.mjs +1 -21
- package/dist/core/sp/chunk_proof.d.ts +23 -0
- package/dist/core/sp/chunk_proof.mjs +113 -0
- package/dist/core/sp/index.d.ts +3 -0
- package/dist/core/sp/index.mjs +402 -0
- package/dist/core/sp/sp_write_client.d.ts +53 -0
- package/dist/core/sp/sp_write_client.mjs +302 -0
- package/dist/core/types/blobs.d.ts +24 -5
- package/dist/core/types/blobs.mjs +24 -0
- package/dist/core/types/index.d.ts +2 -2
- package/dist/core/types/index.mjs +46 -2
- package/dist/core/types/payments.mjs +1 -1
- package/dist/core/types/storage_providers.d.ts +32 -6
- package/dist/core/types/storage_providers.mjs +22 -0
- package/dist/gen/rpc_server_pb.d.ts +295 -0
- package/dist/gen/rpc_server_pb.mjs +28 -0
- package/dist/node/clients/ShelbyNodeClient.d.ts +1 -0
- package/dist/node/clients/ShelbyNodeClient.mjs +869 -551
- package/dist/node/clients/index.d.ts +1 -0
- package/dist/node/clients/index.mjs +867 -551
- package/dist/node/index.d.ts +9 -9
- package/dist/node/index.mjs +1068 -589
- package/dist/node/parallel/commitment_worker.mjs +36 -249
- package/dist/node/parallel/commitment_worker_pool.mjs +56 -3
- package/dist/node/parallel/coverage_flush.d.ts +16 -0
- package/dist/node/parallel/coverage_flush.mjs +43 -0
- package/dist/node/parallel/default_commitment_worker_pool.mjs +56 -3
- package/dist/node/parallel/index.d.ts +1 -0
- package/dist/node/parallel/index.mjs +72 -4
- package/dist/node/parallel/parallel_commitments.mjs +56 -3
- package/dist/node/parallel/worker_pool.mjs +56 -3
- package/package.json +11 -4
package/dist/node/index.mjs
CHANGED
|
@@ -180,6 +180,18 @@ var ERASURE_CODE_PARAMS = {
|
|
|
180
180
|
enumIndex: 1
|
|
181
181
|
}
|
|
182
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
|
+
}
|
|
183
195
|
var DEFAULT_ERASURE_N = ERASURE_CODE_PARAMS["ClayCode_16Total_10Data_13Helper" /* ClayCode_16Total_10Data_13Helper */].erasure_n;
|
|
184
196
|
var DEFAULT_ERASURE_K = ERASURE_CODE_PARAMS["ClayCode_16Total_10Data_13Helper" /* ClayCode_16Total_10Data_13Helper */].erasure_k;
|
|
185
197
|
var DEFAULT_ERASURE_D = ERASURE_CODE_PARAMS["ClayCode_16Total_10Data_13Helper" /* ClayCode_16Total_10Data_13Helper */].erasure_d;
|
|
@@ -250,6 +262,12 @@ function expectedTotalChunksets(rawSize, chunksetSize = DEFAULT_CHUNKSET_SIZE_BY
|
|
|
250
262
|
if (rawSize === 0) return 1;
|
|
251
263
|
return Math.ceil(rawSize / chunksetSize);
|
|
252
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
|
+
}
|
|
253
271
|
var BlobCommitmentsSchema = z.object({
|
|
254
272
|
schema_version: z.string(),
|
|
255
273
|
raw_data_size: z.number(),
|
|
@@ -363,7 +381,7 @@ import { Network as Network2 } from "@aptos-labs/ts-sdk";
|
|
|
363
381
|
var DEFAULT_PROJECT_NAME = "shelby";
|
|
364
382
|
var DEFAULT_PROJECT_DESCRIPTION = "High performance, decentralized storage";
|
|
365
383
|
var NetworkToShelbyRPCBaseUrl = {
|
|
366
|
-
[Network2.SHELBYNET]: "https://
|
|
384
|
+
[Network2.SHELBYNET]: "https://shelby.shelbynet.shelby.xyz/shelby",
|
|
367
385
|
[Network2.NETNA]: void 0,
|
|
368
386
|
[Network2.DEVNET]: void 0,
|
|
369
387
|
[Network2.TESTNET]: "https://api.testnet.shelby.xyz/shelby",
|
|
@@ -398,6 +416,27 @@ var SHELBYUSD_TOKEN_MODULE = "shelby_usd";
|
|
|
398
416
|
var SHELBYUSD_TOKEN_NAME = "ShelbyUSD";
|
|
399
417
|
var SHELBYUSD_FA_METADATA_ADDRESS = "0x1b18363a9f1fe5e6ebf247daba5cc1c18052bb232efdc4c50f556053922d98e1";
|
|
400
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
|
+
|
|
401
440
|
// src/core/erasure/clay-codes.ts
|
|
402
441
|
import {
|
|
403
442
|
createDecoder,
|
|
@@ -646,31 +685,80 @@ var getShelbyRPCBaseUrl = (config) => {
|
|
|
646
685
|
|
|
647
686
|
// src/core/operations/generated/sdk.ts
|
|
648
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 || {});
|
|
649
692
|
var Blob_Activities_Select_Column = /* @__PURE__ */ ((Blob_Activities_Select_Column2) => {
|
|
650
|
-
Blob_Activities_Select_Column2["BlobName"] = "blob_name";
|
|
651
693
|
Blob_Activities_Select_Column2["EventIndex"] = "event_index";
|
|
652
694
|
Blob_Activities_Select_Column2["EventType"] = "event_type";
|
|
695
|
+
Blob_Activities_Select_Column2["ObjectName"] = "object_name";
|
|
653
696
|
Blob_Activities_Select_Column2["Owner"] = "owner";
|
|
654
697
|
Blob_Activities_Select_Column2["Timestamp"] = "timestamp";
|
|
655
698
|
Blob_Activities_Select_Column2["TransactionHash"] = "transaction_hash";
|
|
656
699
|
Blob_Activities_Select_Column2["TransactionVersion"] = "transaction_version";
|
|
700
|
+
Blob_Activities_Select_Column2["Uid"] = "uid";
|
|
657
701
|
return Blob_Activities_Select_Column2;
|
|
658
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 || {});
|
|
659
718
|
var Blobs_Select_Column = /* @__PURE__ */ ((Blobs_Select_Column2) => {
|
|
660
719
|
Blobs_Select_Column2["BlobCommitment"] = "blob_commitment";
|
|
661
|
-
Blobs_Select_Column2["BlobName"] = "blob_name";
|
|
662
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";
|
|
663
725
|
Blobs_Select_Column2["ExpiresAt"] = "expires_at";
|
|
726
|
+
Blobs_Select_Column2["IsCommitted"] = "is_committed";
|
|
664
727
|
Blobs_Select_Column2["IsDeleted"] = "is_deleted";
|
|
665
|
-
Blobs_Select_Column2["
|
|
728
|
+
Blobs_Select_Column2["IsPersisted"] = "is_persisted";
|
|
666
729
|
Blobs_Select_Column2["NumChunksets"] = "num_chunksets";
|
|
730
|
+
Blobs_Select_Column2["ObjectName"] = "object_name";
|
|
667
731
|
Blobs_Select_Column2["Owner"] = "owner";
|
|
732
|
+
Blobs_Select_Column2["PaymentAmount"] = "payment_amount";
|
|
668
733
|
Blobs_Select_Column2["PlacementGroup"] = "placement_group";
|
|
669
734
|
Blobs_Select_Column2["Size"] = "size";
|
|
670
735
|
Blobs_Select_Column2["SliceAddress"] = "slice_address";
|
|
736
|
+
Blobs_Select_Column2["Uid"] = "uid";
|
|
671
737
|
Blobs_Select_Column2["UpdatedAt"] = "updated_at";
|
|
672
738
|
return Blobs_Select_Column2;
|
|
673
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 || {});
|
|
674
762
|
var Cursor_Ordering = /* @__PURE__ */ ((Cursor_Ordering2) => {
|
|
675
763
|
Cursor_Ordering2["Asc"] = "ASC";
|
|
676
764
|
Cursor_Ordering2["Desc"] = "DESC";
|
|
@@ -685,6 +773,10 @@ var Order_By = /* @__PURE__ */ ((Order_By2) => {
|
|
|
685
773
|
Order_By2["DescNullsLast"] = "desc_nulls_last";
|
|
686
774
|
return Order_By2;
|
|
687
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 || {});
|
|
688
780
|
var Placement_Group_Slots_Select_Column = /* @__PURE__ */ ((Placement_Group_Slots_Select_Column2) => {
|
|
689
781
|
Placement_Group_Slots_Select_Column2["PlacementGroup"] = "placement_group";
|
|
690
782
|
Placement_Group_Slots_Select_Column2["SlotIndex"] = "slot_index";
|
|
@@ -693,27 +785,49 @@ var Placement_Group_Slots_Select_Column = /* @__PURE__ */ ((Placement_Group_Slot
|
|
|
693
785
|
Placement_Group_Slots_Select_Column2["UpdatedAt"] = "updated_at";
|
|
694
786
|
return Placement_Group_Slots_Select_Column2;
|
|
695
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 || {});
|
|
696
800
|
var Processor_Status_Select_Column = /* @__PURE__ */ ((Processor_Status_Select_Column2) => {
|
|
697
801
|
Processor_Status_Select_Column2["LastSuccessVersion"] = "last_success_version";
|
|
698
802
|
Processor_Status_Select_Column2["LastTransactionTimestamp"] = "last_transaction_timestamp";
|
|
699
803
|
Processor_Status_Select_Column2["LastUpdated"] = "last_updated";
|
|
804
|
+
Processor_Status_Select_Column2["Processor"] = "processor";
|
|
700
805
|
return Processor_Status_Select_Column2;
|
|
701
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 || {});
|
|
702
814
|
var GetBlobsDocument = gql`
|
|
703
815
|
query getBlobs($where: blobs_bool_exp, $orderBy: [blobs_order_by!], $limit: Int, $offset: Int) {
|
|
704
816
|
blobs(where: $where, order_by: $orderBy, limit: $limit, offset: $offset) {
|
|
817
|
+
uid
|
|
818
|
+
object_name
|
|
705
819
|
owner
|
|
706
820
|
blob_commitment
|
|
707
|
-
blob_name
|
|
708
821
|
created_at
|
|
709
822
|
expires_at
|
|
823
|
+
updated_at
|
|
710
824
|
num_chunksets
|
|
711
|
-
is_deleted
|
|
712
|
-
is_written
|
|
713
|
-
placement_group
|
|
714
825
|
size
|
|
715
|
-
updated_at
|
|
716
826
|
slice_address
|
|
827
|
+
placement_group
|
|
828
|
+
is_persisted
|
|
829
|
+
is_committed
|
|
830
|
+
is_deleted
|
|
717
831
|
}
|
|
718
832
|
}
|
|
719
833
|
`;
|
|
@@ -725,7 +839,8 @@ var GetBlobActivitiesDocument = gql`
|
|
|
725
839
|
limit: $limit
|
|
726
840
|
offset: $offset
|
|
727
841
|
) {
|
|
728
|
-
|
|
842
|
+
uid
|
|
843
|
+
object_name
|
|
729
844
|
event_index
|
|
730
845
|
event_type
|
|
731
846
|
transaction_hash
|
|
@@ -871,6 +986,33 @@ var MissingTransactionSubmitterError = class extends Error {
|
|
|
871
986
|
this.name = "MissingTransactionSubmitterError";
|
|
872
987
|
}
|
|
873
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
|
+
}
|
|
874
1016
|
var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
875
1017
|
aptos;
|
|
876
1018
|
deployer;
|
|
@@ -919,7 +1061,10 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
919
1061
|
this.aptos = new Aptos(getAptosConfig(config));
|
|
920
1062
|
this.deployer = config.deployer ?? AccountAddress2.fromString(SHELBY_DEPLOYER);
|
|
921
1063
|
this.indexer = getShelbyIndexerClient(config);
|
|
922
|
-
this.defaultOptions =
|
|
1064
|
+
this.defaultOptions = {
|
|
1065
|
+
locationHint: config.locationHint,
|
|
1066
|
+
...defaultOptions
|
|
1067
|
+
};
|
|
923
1068
|
this.orderless = config.orderless ?? false;
|
|
924
1069
|
}
|
|
925
1070
|
/**
|
|
@@ -930,7 +1075,9 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
930
1075
|
build: options?.build ?? this.defaultOptions.build,
|
|
931
1076
|
submit: options?.submit ?? this.defaultOptions.submit,
|
|
932
1077
|
usdSponsor: options?.usdSponsor ?? this.defaultOptions.usdSponsor,
|
|
933
|
-
chunksetSizeBytes: options?.chunksetSizeBytes ?? this.defaultOptions.chunksetSizeBytes
|
|
1078
|
+
chunksetSizeBytes: options?.chunksetSizeBytes ?? this.defaultOptions.chunksetSizeBytes,
|
|
1079
|
+
selectedLocation: options?.selectedLocation ?? this.defaultOptions.selectedLocation,
|
|
1080
|
+
locationHint: options?.locationHint ?? this.defaultOptions.locationHint
|
|
934
1081
|
};
|
|
935
1082
|
}
|
|
936
1083
|
/**
|
|
@@ -972,17 +1119,17 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
972
1119
|
*
|
|
973
1120
|
* @example
|
|
974
1121
|
* ```typescript
|
|
975
|
-
* const metadata = await client.
|
|
1122
|
+
* const metadata = await client.getFullObjectMetadata({
|
|
976
1123
|
* account: AccountAddress.fromString("0x1"),
|
|
977
1124
|
* name: "foo/bar.txt",
|
|
978
1125
|
* });
|
|
979
1126
|
* ```
|
|
980
1127
|
*/
|
|
981
|
-
async
|
|
1128
|
+
async getFullObjectMetadata(params) {
|
|
982
1129
|
try {
|
|
983
1130
|
const rawMetadata = await this.aptos.view({
|
|
984
1131
|
payload: {
|
|
985
|
-
function: `${this.deployer.toString()}::blob_metadata::
|
|
1132
|
+
function: `${this.deployer.toString()}::blob_metadata::get_full_object_metadata`,
|
|
986
1133
|
functionArguments: [
|
|
987
1134
|
createBlobKey({
|
|
988
1135
|
account: params.account,
|
|
@@ -994,47 +1141,94 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
994
1141
|
if (!rawMetadata?.[0]?.vec?.[0]) {
|
|
995
1142
|
return void 0;
|
|
996
1143
|
}
|
|
997
|
-
const
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
encoding = {
|
|
1001
|
-
variant: "clay",
|
|
1002
|
-
...ERASURE_CODE_PARAMS[metadata.encoding.__variant__],
|
|
1003
|
-
...ERASURE_CODE_AND_CHUNK_MAPPING[metadata.encoding.__variant__]
|
|
1004
|
-
};
|
|
1005
|
-
} else if (metadata.encoding.__variant__ === "ClayCode_4Total_2Data_3Helper") {
|
|
1006
|
-
encoding = {
|
|
1007
|
-
variant: "clay",
|
|
1008
|
-
...ERASURE_CODE_PARAMS[metadata.encoding.__variant__],
|
|
1009
|
-
...ERASURE_CODE_AND_CHUNK_MAPPING[metadata.encoding.__variant__]
|
|
1010
|
-
};
|
|
1011
|
-
} else {
|
|
1012
|
-
throw new Error(
|
|
1013
|
-
"Could not parse encoding from Shelby Smart Contract, this SDK is out of date."
|
|
1014
|
-
);
|
|
1015
|
-
}
|
|
1016
|
-
return {
|
|
1017
|
-
blobMerkleRoot: Hex3.fromHexInput(
|
|
1018
|
-
metadata.blob_commitment
|
|
1019
|
-
).toUint8Array(),
|
|
1020
|
-
owner: normalizeAddress(metadata.owner),
|
|
1144
|
+
const view = rawMetadata[0].vec[0];
|
|
1145
|
+
return this.parseBlobMetadata(view.blob_metadata, {
|
|
1146
|
+
uid: BigInt(view.object_metadata.current_blob_uid),
|
|
1021
1147
|
name: params.name,
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
creationMicros: Number(metadata.creation_micros),
|
|
1027
|
-
sliceAddress: normalizeAddress(metadata.slice.inner),
|
|
1028
|
-
isWritten: metadata.is_written
|
|
1029
|
-
};
|
|
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
|
+
});
|
|
1030
1152
|
} catch (error) {
|
|
1031
1153
|
if (error instanceof Error && // Depending on the network, the error message may show up differently.
|
|
1032
|
-
(error.message?.includes("sub_status: Some(404)") || error.message?.includes("EBLOB_NOT_FOUND"))) {
|
|
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"))) {
|
|
1033
1191
|
return void 0;
|
|
1034
1192
|
}
|
|
1035
1193
|
throw error;
|
|
1036
1194
|
}
|
|
1037
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
|
+
}
|
|
1038
1232
|
/**
|
|
1039
1233
|
* Retrieves all the blobs and their metadata for an account from the
|
|
1040
1234
|
* blockchain.
|
|
@@ -1046,7 +1240,7 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1046
1240
|
*
|
|
1047
1241
|
* @example
|
|
1048
1242
|
* ```typescript
|
|
1049
|
-
* //
|
|
1243
|
+
* // FullObjectMetadata[]
|
|
1050
1244
|
* const blobs = await client.getAccountBlobs({
|
|
1051
1245
|
* account: AccountAddress.fromString("0x1"),
|
|
1052
1246
|
* });
|
|
@@ -1063,6 +1257,25 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1063
1257
|
orderBy: rest.orderBy
|
|
1064
1258
|
});
|
|
1065
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
|
+
}
|
|
1066
1279
|
/**
|
|
1067
1280
|
* Retrieves blobs and their metadata from the blockchain.
|
|
1068
1281
|
*
|
|
@@ -1073,7 +1286,7 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1073
1286
|
*
|
|
1074
1287
|
* @example
|
|
1075
1288
|
* ```typescript
|
|
1076
|
-
* //
|
|
1289
|
+
* // FullObjectMetadata[]
|
|
1077
1290
|
* const blobs = await client.getBlobs({
|
|
1078
1291
|
* where: { owner: { _eq: AccountAddress.fromString("0x1").toString() } },
|
|
1079
1292
|
* });
|
|
@@ -1082,12 +1295,7 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1082
1295
|
async getBlobs(params = {}) {
|
|
1083
1296
|
const { limit, offset } = params.pagination ?? {};
|
|
1084
1297
|
const { orderBy, where } = params;
|
|
1085
|
-
const
|
|
1086
|
-
const defaultActiveFilter = {
|
|
1087
|
-
expires_at: { _gte: currentMicros },
|
|
1088
|
-
is_deleted: { _eq: "0" }
|
|
1089
|
-
};
|
|
1090
|
-
const finalWhere = where !== void 0 ? { ...defaultActiveFilter, ...where } : defaultActiveFilter;
|
|
1298
|
+
const finalWhere = this.activeBlobsWhere(where);
|
|
1091
1299
|
const { blobs } = await this.indexer.getBlobs({
|
|
1092
1300
|
where: finalWhere,
|
|
1093
1301
|
limit,
|
|
@@ -1096,9 +1304,10 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1096
1304
|
});
|
|
1097
1305
|
return blobs.map(
|
|
1098
1306
|
(blob) => ({
|
|
1307
|
+
uid: BigInt(blob.uid),
|
|
1099
1308
|
owner: normalizeAddress(blob.owner),
|
|
1100
|
-
name: blob.
|
|
1101
|
-
blobNameSuffix: getBlobNameSuffix(blob.
|
|
1309
|
+
name: blob.object_name,
|
|
1310
|
+
blobNameSuffix: getBlobNameSuffix(blob.object_name),
|
|
1102
1311
|
blobMerkleRoot: Hex3.fromHexInput(blob.blob_commitment).toUint8Array(),
|
|
1103
1312
|
size: Number(blob.size),
|
|
1104
1313
|
// TODO: Add encoding when supported in NCI
|
|
@@ -1110,7 +1319,7 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1110
1319
|
expirationMicros: Number(blob.expires_at),
|
|
1111
1320
|
creationMicros: Number(blob.created_at),
|
|
1112
1321
|
sliceAddress: normalizeAddress(blob.slice_address),
|
|
1113
|
-
isWritten: Boolean(Number(blob.
|
|
1322
|
+
isWritten: Boolean(Number(blob.is_persisted)),
|
|
1114
1323
|
isDeleted: Boolean(Number(blob.is_deleted))
|
|
1115
1324
|
})
|
|
1116
1325
|
);
|
|
@@ -1128,12 +1337,15 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1128
1337
|
[`${this.deployer.toStringLong()}::blob_metadata::BlobRegisteredEvent`]: "register_blob",
|
|
1129
1338
|
[`${this.deployer.toStringLong()}::blob_metadata::BlobDeletedEvent`]: "delete_blob",
|
|
1130
1339
|
[`${this.deployer.toStringLong()}::blob_metadata::BlobExpirationExtendedEvent`]: "extend_blob_expiration",
|
|
1131
|
-
[`${this.deployer.toStringLong()}::blob_metadata::
|
|
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"
|
|
1132
1344
|
};
|
|
1133
1345
|
return blob_activities.map(
|
|
1134
1346
|
(activity) => ({
|
|
1135
|
-
blobName: activity.
|
|
1136
|
-
accountAddress: normalizeAddress(activity.
|
|
1347
|
+
blobName: activity.object_name,
|
|
1348
|
+
accountAddress: normalizeAddress(activity.object_name.substring(1, 65)),
|
|
1137
1349
|
type: activityTypeMapping[activity.event_type] ?? "unknown",
|
|
1138
1350
|
eventType: activity.event_type,
|
|
1139
1351
|
eventIndex: Number(activity.event_index),
|
|
@@ -1156,9 +1368,10 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1156
1368
|
* const count = await client.getBlobsCount();
|
|
1157
1369
|
* ```
|
|
1158
1370
|
*/
|
|
1159
|
-
async getBlobsCount(params) {
|
|
1160
|
-
const {
|
|
1161
|
-
|
|
1371
|
+
async getBlobsCount(params = {}) {
|
|
1372
|
+
const { blobs_aggregate } = await this.indexer.getBlobsCount({
|
|
1373
|
+
where: this.activeBlobsWhere(params.where)
|
|
1374
|
+
});
|
|
1162
1375
|
return blobs_aggregate?.aggregate?.count ?? 0;
|
|
1163
1376
|
}
|
|
1164
1377
|
/**
|
|
@@ -1173,8 +1386,9 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1173
1386
|
* ```
|
|
1174
1387
|
*/
|
|
1175
1388
|
async getTotalBlobsSize(params = {}) {
|
|
1176
|
-
const {
|
|
1177
|
-
|
|
1389
|
+
const { blobs_aggregate } = await this.indexer.getTotalBlobsSize({
|
|
1390
|
+
where: this.activeBlobsWhere(params.where)
|
|
1391
|
+
});
|
|
1178
1392
|
return Number(blobs_aggregate?.aggregate?.sum?.size ?? 0);
|
|
1179
1393
|
}
|
|
1180
1394
|
/**
|
|
@@ -1233,12 +1447,15 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1233
1447
|
deployer: this.deployer,
|
|
1234
1448
|
account: params.account.accountAddress,
|
|
1235
1449
|
blobName: params.blobName,
|
|
1450
|
+
selectedLocation: options.selectedLocation,
|
|
1451
|
+
locationHint: options.locationHint,
|
|
1236
1452
|
blobSize: params.size,
|
|
1237
1453
|
blobMerkleRoot: params.blobMerkleRoot,
|
|
1238
1454
|
numChunksets: expectedTotalChunksets(params.size, chunksetSize),
|
|
1239
1455
|
expirationMicros: params.expirationMicros,
|
|
1240
1456
|
useSponsoredUsdVariant: options.usdSponsor !== void 0,
|
|
1241
|
-
encoding: config.enumIndex
|
|
1457
|
+
encoding: config.enumIndex,
|
|
1458
|
+
encryption: params.encryption
|
|
1242
1459
|
}),
|
|
1243
1460
|
sender: params.account.accountAddress
|
|
1244
1461
|
};
|
|
@@ -1266,16 +1483,16 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1266
1483
|
* @example
|
|
1267
1484
|
* ```typescript
|
|
1268
1485
|
*
|
|
1269
|
-
* const { transaction } = await client.
|
|
1486
|
+
* const { transaction } = await client.deleteObject({
|
|
1270
1487
|
* account: signer,
|
|
1271
1488
|
* blobName: "foo/bar.txt",
|
|
1272
1489
|
* });
|
|
1273
1490
|
* ```
|
|
1274
1491
|
*/
|
|
1275
|
-
async
|
|
1492
|
+
async deleteObject(params) {
|
|
1276
1493
|
const transaction = await this.aptos.transaction.build.simple({
|
|
1277
1494
|
options: this.orderlessTxOptions(params.options),
|
|
1278
|
-
data: _ShelbyBlobClient.
|
|
1495
|
+
data: _ShelbyBlobClient.createDeleteObjectPayload({
|
|
1279
1496
|
deployer: this.deployer,
|
|
1280
1497
|
blobName: params.blobName
|
|
1281
1498
|
}),
|
|
@@ -1291,10 +1508,6 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1291
1508
|
/**
|
|
1292
1509
|
* Deletes multiple blobs on the blockchain in a single atomic transaction.
|
|
1293
1510
|
*
|
|
1294
|
-
* **Note:** This function requires the `delete_multiple_blobs` entry function
|
|
1295
|
-
* which will be deployed to the smart contract on 2026-02-04. Using this
|
|
1296
|
-
* function before that date will result in a transaction failure.
|
|
1297
|
-
*
|
|
1298
1511
|
* This operation is atomic: if any blob deletion fails (e.g., blob not found),
|
|
1299
1512
|
* the entire transaction fails and no blobs are deleted.
|
|
1300
1513
|
*
|
|
@@ -1309,16 +1522,16 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1309
1522
|
* @example
|
|
1310
1523
|
* ```typescript
|
|
1311
1524
|
*
|
|
1312
|
-
* const { transaction } = await client.
|
|
1525
|
+
* const { transaction } = await client.deleteMultipleObjects({
|
|
1313
1526
|
* account: signer,
|
|
1314
1527
|
* blobNames: ["foo/bar.txt", "baz.txt"],
|
|
1315
1528
|
* });
|
|
1316
1529
|
* ```
|
|
1317
1530
|
*/
|
|
1318
|
-
async
|
|
1531
|
+
async deleteMultipleObjects(params) {
|
|
1319
1532
|
const transaction = await this.aptos.transaction.build.simple({
|
|
1320
1533
|
options: this.orderlessTxOptions(params.options),
|
|
1321
|
-
data: _ShelbyBlobClient.
|
|
1534
|
+
data: _ShelbyBlobClient.createDeleteMultipleObjectsPayload({
|
|
1322
1535
|
deployer: this.deployer,
|
|
1323
1536
|
blobNames: params.blobNames
|
|
1324
1537
|
}),
|
|
@@ -1376,6 +1589,8 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1376
1589
|
data: _ShelbyBlobClient.createBatchRegisterBlobsPayload({
|
|
1377
1590
|
deployer: this.deployer,
|
|
1378
1591
|
account: params.account.accountAddress,
|
|
1592
|
+
selectedLocation: options.selectedLocation,
|
|
1593
|
+
locationHint: options.locationHint,
|
|
1379
1594
|
expirationMicros: params.expirationMicros,
|
|
1380
1595
|
blobs: params.blobs.map((blob) => ({
|
|
1381
1596
|
blobName: blob.blobName,
|
|
@@ -1384,7 +1599,8 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1384
1599
|
numChunksets: expectedTotalChunksets(blob.blobSize, chunksetSize)
|
|
1385
1600
|
})),
|
|
1386
1601
|
useSponsoredUsdVariant: options.usdSponsor !== void 0,
|
|
1387
|
-
encoding: config.enumIndex
|
|
1602
|
+
encoding: config.enumIndex,
|
|
1603
|
+
encryption: params.encryption
|
|
1388
1604
|
})
|
|
1389
1605
|
};
|
|
1390
1606
|
const transaction = options.usdSponsor ? await this.aptos.transaction.build.multiAgent({
|
|
@@ -1399,6 +1615,55 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1399
1615
|
})
|
|
1400
1616
|
};
|
|
1401
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
|
+
}
|
|
1402
1667
|
/**
|
|
1403
1668
|
* Creates a transaction payload to register a blob on the blockchain.
|
|
1404
1669
|
* This is a static helper method for constructing the Move function call payload.
|
|
@@ -1412,8 +1677,6 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1412
1677
|
* @param params.numChunksets - The total number of chunksets in the blob.
|
|
1413
1678
|
*
|
|
1414
1679
|
* @returns An Aptos transaction payload data object for the register_blob Move function.
|
|
1415
|
-
*
|
|
1416
|
-
* @see https://github.com/shelby/shelby/blob/e08e84742cf2b80ad8bb7227deb3013398076d53/move/shelby_contract/sources/global_metadata.move#L357
|
|
1417
1680
|
*/
|
|
1418
1681
|
static createRegisterBlobPayload(params) {
|
|
1419
1682
|
const functionName = params.useSponsoredUsdVariant ? "register_blob_with_sponsor" : "register_blob";
|
|
@@ -1421,6 +1684,8 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1421
1684
|
function: `${(params.deployer ?? SHELBY_DEPLOYER).toString()}::blob_metadata::${functionName}`,
|
|
1422
1685
|
functionArguments: [
|
|
1423
1686
|
params.blobName,
|
|
1687
|
+
params.selectedLocation ?? null,
|
|
1688
|
+
params.locationHint ?? null,
|
|
1424
1689
|
params.expirationMicros,
|
|
1425
1690
|
Hex3.fromHexString(params.blobMerkleRoot).toUint8Array(),
|
|
1426
1691
|
params.numChunksets,
|
|
@@ -1428,7 +1693,8 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1428
1693
|
// TODO
|
|
1429
1694
|
0,
|
|
1430
1695
|
// payment tier
|
|
1431
|
-
params.encoding
|
|
1696
|
+
params.encoding,
|
|
1697
|
+
...encryptionFunctionArgs(params)
|
|
1432
1698
|
]
|
|
1433
1699
|
};
|
|
1434
1700
|
}
|
|
@@ -1446,8 +1712,6 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1446
1712
|
* @param params.blobs.numChunksets - The total number of chunksets in the blob.
|
|
1447
1713
|
*
|
|
1448
1714
|
* @returns An Aptos transaction payload data object for the register_multiple_blobs Move function.
|
|
1449
|
-
*
|
|
1450
|
-
* @see https://github.com/shelby/shelby/blob/e08e84742cf2b80ad8bb7227deb3013398076d53/move/shelby_contract/sources/global_metadata.move#L357
|
|
1451
1715
|
*/
|
|
1452
1716
|
static createBatchRegisterBlobsPayload(params) {
|
|
1453
1717
|
const functionName = params.useSponsoredUsdVariant ? "register_multiple_blobs_with_sponsor" : "register_multiple_blobs";
|
|
@@ -1467,6 +1731,8 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1467
1731
|
function: `${(params.deployer ?? SHELBY_DEPLOYER).toString()}::blob_metadata::${functionName}`,
|
|
1468
1732
|
functionArguments: [
|
|
1469
1733
|
blobNames,
|
|
1734
|
+
params.selectedLocation ?? null,
|
|
1735
|
+
params.locationHint ?? null,
|
|
1470
1736
|
params.expirationMicros,
|
|
1471
1737
|
blobMerkleRoots,
|
|
1472
1738
|
blobNumChunksets,
|
|
@@ -1474,7 +1740,8 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1474
1740
|
// TODO
|
|
1475
1741
|
0,
|
|
1476
1742
|
// payment tier
|
|
1477
|
-
params.encoding
|
|
1743
|
+
params.encoding,
|
|
1744
|
+
...encryptionFunctionArgs(params)
|
|
1478
1745
|
]
|
|
1479
1746
|
};
|
|
1480
1747
|
}
|
|
@@ -1485,24 +1752,20 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1485
1752
|
* @param params.deployer - Optional deployer account address. Defaults to SHELBY_DEPLOYER.
|
|
1486
1753
|
* @param params.blobName - The blob name (e.g. "bar.txt", without the account address prefix).
|
|
1487
1754
|
*
|
|
1488
|
-
* @returns An Aptos transaction payload data object for the
|
|
1489
|
-
*
|
|
1490
|
-
* @see https://github.com/shelby/shelby/blob/64e9d7b4f0005e586faeb1e4085c79159234b6b6/move/shelby_contract/sources/global_metadata.move#L616
|
|
1755
|
+
* @returns An Aptos transaction payload data object for the delete_object Move function.
|
|
1491
1756
|
*/
|
|
1492
|
-
static
|
|
1757
|
+
static createDeleteObjectPayload(params) {
|
|
1493
1758
|
return {
|
|
1494
|
-
function: `${(params.deployer ?? SHELBY_DEPLOYER).toString()}::blob_metadata::
|
|
1495
|
-
|
|
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]
|
|
1496
1763
|
};
|
|
1497
1764
|
}
|
|
1498
1765
|
/**
|
|
1499
1766
|
* Creates a transaction payload to delete multiple blobs on the blockchain.
|
|
1500
1767
|
* This is a static helper method for constructing the Move function call payload.
|
|
1501
1768
|
*
|
|
1502
|
-
* **Note:** This function requires the `delete_multiple_blobs` entry function
|
|
1503
|
-
* which will be deployed to the smart contract on 2026-02-04. Using this
|
|
1504
|
-
* function before that date will result in a transaction failure.
|
|
1505
|
-
*
|
|
1506
1769
|
* This operation is atomic: if any blob deletion fails (e.g., blob not found),
|
|
1507
1770
|
* the entire transaction fails and no blobs are deleted.
|
|
1508
1771
|
*
|
|
@@ -1511,42 +1774,71 @@ var ShelbyBlobClient = class _ShelbyBlobClient {
|
|
|
1511
1774
|
* (e.g. ["foo/bar.txt", "baz.txt"], NOT ["0x1/foo/bar.txt"]). The account address
|
|
1512
1775
|
* prefix is automatically derived from the transaction sender.
|
|
1513
1776
|
*
|
|
1514
|
-
* @returns An Aptos transaction payload data object for the
|
|
1515
|
-
*
|
|
1516
|
-
* @see https://github.com/shelby/shelby/blob/main/move/shelby_contract/sources/blob_metadata.move
|
|
1777
|
+
* @returns An Aptos transaction payload data object for the delete_multiple_objects Move function.
|
|
1517
1778
|
*/
|
|
1518
|
-
static
|
|
1779
|
+
static createDeleteMultipleObjectsPayload(params) {
|
|
1519
1780
|
return {
|
|
1520
|
-
function: `${(params.deployer ?? SHELBY_DEPLOYER).toString()}::blob_metadata::
|
|
1521
|
-
|
|
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, []]
|
|
1522
1785
|
};
|
|
1523
1786
|
}
|
|
1524
|
-
|
|
1525
|
-
|
|
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(
|
|
1526
1795
|
(acc, ack) => acc | 1 << ack.slot,
|
|
1527
1796
|
0
|
|
1528
1797
|
);
|
|
1529
1798
|
return {
|
|
1530
|
-
|
|
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`,
|
|
1531
1821
|
functionArguments: [
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
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
|
|
1539
1830
|
]
|
|
1540
1831
|
};
|
|
1541
1832
|
}
|
|
1542
|
-
async
|
|
1833
|
+
async commitObject(params) {
|
|
1543
1834
|
const transaction = await this.aptos.transaction.build.simple({
|
|
1544
1835
|
...params.options?.build,
|
|
1545
1836
|
options: this.orderlessTxOptions(params.options?.build?.options),
|
|
1546
|
-
data: _ShelbyBlobClient.
|
|
1547
|
-
|
|
1837
|
+
data: _ShelbyBlobClient.createCommitObjectPayload({
|
|
1838
|
+
deployer: this.deployer,
|
|
1839
|
+
uid: params.uid,
|
|
1548
1840
|
blobName: params.blobName,
|
|
1549
|
-
|
|
1841
|
+
overwrite: params.overwrite,
|
|
1550
1842
|
storageProviderAcks: params.storageProviderAcks
|
|
1551
1843
|
}),
|
|
1552
1844
|
sender: params.account.accountAddress
|
|
@@ -1569,12 +1861,99 @@ import {
|
|
|
1569
1861
|
} from "@aptos-labs/ts-sdk";
|
|
1570
1862
|
import pLimit from "p-limit";
|
|
1571
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
|
+
|
|
1572
1921
|
// src/core/clients/ShelbyMetadataClient.ts
|
|
1573
1922
|
import {
|
|
1574
1923
|
AccountAddress as AccountAddress3,
|
|
1575
1924
|
Aptos as Aptos2,
|
|
1576
1925
|
Hex as Hex4
|
|
1577
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
|
+
}
|
|
1578
1957
|
function parseStorageProviderState(raw) {
|
|
1579
1958
|
switch (raw.__variant__) {
|
|
1580
1959
|
case "Active":
|
|
@@ -1582,8 +1961,7 @@ function parseStorageProviderState(raw) {
|
|
|
1582
1961
|
variant: "Active",
|
|
1583
1962
|
quota: raw.quota.value,
|
|
1584
1963
|
stakeAtStartOfStakingEpoch: raw.stake_at_start_of_staking_epoch,
|
|
1585
|
-
|
|
1586
|
-
leaving: raw.leaving
|
|
1964
|
+
condition: parseActiveProviderCondition(raw.condition)
|
|
1587
1965
|
};
|
|
1588
1966
|
case "Waitlisted":
|
|
1589
1967
|
return {
|
|
@@ -1596,6 +1974,10 @@ function parseStorageProviderState(raw) {
|
|
|
1596
1974
|
frozenFrom: raw.frozen_from,
|
|
1597
1975
|
frozenTill: raw.frozen_till
|
|
1598
1976
|
};
|
|
1977
|
+
default:
|
|
1978
|
+
throw new Error(
|
|
1979
|
+
`Unknown StorageProviderStateDetails variant: ${JSON.stringify(raw)}`
|
|
1980
|
+
);
|
|
1599
1981
|
}
|
|
1600
1982
|
}
|
|
1601
1983
|
var ShelbyMetadataClient = class {
|
|
@@ -1654,28 +2036,52 @@ var ShelbyMetadataClient = class {
|
|
|
1654
2036
|
}
|
|
1655
2037
|
}
|
|
1656
2038
|
/**
|
|
1657
|
-
* Retrieves the
|
|
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.
|
|
1658
2060
|
*
|
|
2061
|
+
* @param locationName - The location whose placement groups to list.
|
|
1659
2062
|
* @returns The placement group address list, or an empty array if none exist.
|
|
1660
2063
|
*
|
|
1661
2064
|
* @example
|
|
1662
2065
|
* ```typescript
|
|
1663
|
-
* const pgList = await client.getPlacementGroupAddresses();
|
|
2066
|
+
* const pgList = await client.getPlacementGroupAddresses("us-east-1");
|
|
1664
2067
|
* ```
|
|
1665
2068
|
*/
|
|
1666
|
-
async getPlacementGroupAddresses() {
|
|
2069
|
+
async getPlacementGroupAddresses(locationName) {
|
|
1667
2070
|
try {
|
|
1668
2071
|
const pgSizeMetadata = await this.aptos.view({
|
|
1669
2072
|
payload: {
|
|
1670
2073
|
function: `${this.deployer.toString()}::placement_group_registry::get_number_of_placement_groups`,
|
|
1671
|
-
functionArguments: []
|
|
2074
|
+
functionArguments: [locationName]
|
|
1672
2075
|
}
|
|
1673
2076
|
});
|
|
2077
|
+
if (Number(pgSizeMetadata[0]) === 0) {
|
|
2078
|
+
return [];
|
|
2079
|
+
}
|
|
1674
2080
|
const finalPlacementGroupIndex = pgSizeMetadata[0] - 1;
|
|
1675
2081
|
const addressMetadataArray = await this.aptos.view({
|
|
1676
2082
|
payload: {
|
|
1677
2083
|
function: `${this.deployer.toString()}::placement_group_registry::get_placement_group_addresses`,
|
|
1678
|
-
functionArguments: [0, finalPlacementGroupIndex]
|
|
2084
|
+
functionArguments: [locationName, 0, finalPlacementGroupIndex]
|
|
1679
2085
|
}
|
|
1680
2086
|
});
|
|
1681
2087
|
const metadata = addressMetadataArray[0];
|
|
@@ -1689,28 +2095,32 @@ var ShelbyMetadataClient = class {
|
|
|
1689
2095
|
}
|
|
1690
2096
|
}
|
|
1691
2097
|
/**
|
|
1692
|
-
* Retrieves the list of slice addresses.
|
|
2098
|
+
* Retrieves the list of slice addresses in a location.
|
|
1693
2099
|
*
|
|
2100
|
+
* @param locationName - The location whose slices to list.
|
|
1694
2101
|
* @returns The slice group list, or an empty array if none exist.
|
|
1695
2102
|
*
|
|
1696
2103
|
* @example
|
|
1697
2104
|
* ```typescript
|
|
1698
|
-
* const pgList = await client.getSliceAddresses();
|
|
2105
|
+
* const pgList = await client.getSliceAddresses("us-east-1");
|
|
1699
2106
|
* ```
|
|
1700
2107
|
*/
|
|
1701
|
-
async getSliceAddresses() {
|
|
2108
|
+
async getSliceAddresses(locationName) {
|
|
1702
2109
|
try {
|
|
1703
2110
|
const sliceSizeMetadata = await this.aptos.view({
|
|
1704
2111
|
payload: {
|
|
1705
2112
|
function: `${this.deployer.toString()}::slice_registry::get_number_of_slices`,
|
|
1706
|
-
functionArguments: []
|
|
2113
|
+
functionArguments: [locationName]
|
|
1707
2114
|
}
|
|
1708
2115
|
});
|
|
2116
|
+
if (Number(sliceSizeMetadata[0]) === 0) {
|
|
2117
|
+
return [];
|
|
2118
|
+
}
|
|
1709
2119
|
const finalSliceIndex = sliceSizeMetadata[0] - 1;
|
|
1710
2120
|
const addressMetadataArray = await this.aptos.view({
|
|
1711
2121
|
payload: {
|
|
1712
2122
|
function: `${this.deployer.toString()}::slice_registry::get_slice_addresses`,
|
|
1713
|
-
functionArguments: [0, finalSliceIndex]
|
|
2123
|
+
functionArguments: [locationName, 0, finalSliceIndex]
|
|
1714
2124
|
}
|
|
1715
2125
|
});
|
|
1716
2126
|
const metadata = addressMetadataArray[0];
|
|
@@ -1770,6 +2180,36 @@ var ShelbyMetadataClient = class {
|
|
|
1770
2180
|
(opt) => opt.vec.length > 0 ? normalizeAddress(opt.vec[0]) : null
|
|
1771
2181
|
);
|
|
1772
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
|
+
}
|
|
1773
2213
|
/**
|
|
1774
2214
|
* Retrieves the serving storage providers for a slice.
|
|
1775
2215
|
*
|
|
@@ -1858,22 +2298,6 @@ var ChallengeResponseSchema = z3.object({
|
|
|
1858
2298
|
challenge: z3.string(),
|
|
1859
2299
|
expiresAt: z3.number()
|
|
1860
2300
|
});
|
|
1861
|
-
var MultipartUploadStatusResponseSchema = z3.object({
|
|
1862
|
-
uploadId: z3.string(),
|
|
1863
|
-
completedParts: z3.array(z3.number()),
|
|
1864
|
-
partSize: z3.number(),
|
|
1865
|
-
nParts: z3.number(),
|
|
1866
|
-
uploadedBytes: z3.number()
|
|
1867
|
-
});
|
|
1868
|
-
var StartMultipartUploadResponseSchema = z3.object({
|
|
1869
|
-
uploadId: z3.string()
|
|
1870
|
-
});
|
|
1871
|
-
var UploadPartResponseSchema = z3.object({
|
|
1872
|
-
success: z3.literal(true)
|
|
1873
|
-
});
|
|
1874
|
-
var CompleteMultipartUploadResponseSchema = z3.object({
|
|
1875
|
-
success: z3.literal(true)
|
|
1876
|
-
});
|
|
1877
2301
|
var RPCErrorResponseSchema = z3.object({
|
|
1878
2302
|
error: z3.string()
|
|
1879
2303
|
});
|
|
@@ -2090,6 +2514,7 @@ var BLOB_OWNER_AUTH_SCHEME_HEADER = "X-Shelby-Auth-Scheme";
|
|
|
2090
2514
|
var BLOB_OWNER_IDENTITY_HEADER = "X-Shelby-Identity";
|
|
2091
2515
|
var BLOB_OWNER_DOMAIN_HEADER = "X-Shelby-Domain";
|
|
2092
2516
|
var BLOB_OWNER_AUTH_FUNCTION_HEADER = "X-Shelby-Auth-Function";
|
|
2517
|
+
var INCLUSION_PROOF_HEADER = "X-Shelby-Inclusion-Proof";
|
|
2093
2518
|
function buildAuthHeaders(auth) {
|
|
2094
2519
|
const signatureBase64 = btoa(
|
|
2095
2520
|
Array.from(auth.signature, (byte) => String.fromCharCode(byte)).join("")
|
|
@@ -2113,6 +2538,58 @@ function buildAuthHeaders(auth) {
|
|
|
2113
2538
|
function encodeURIComponentKeepSlashes(str) {
|
|
2114
2539
|
return encodeURIComponent(str).replace(/%2F/g, "/");
|
|
2115
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
|
+
}
|
|
2116
2593
|
function validateTotalBytes(totalBytes) {
|
|
2117
2594
|
if (!Number.isInteger(totalBytes) || totalBytes < 0) {
|
|
2118
2595
|
throw new Error("totalBytes must be a non-negative integer");
|
|
@@ -2144,7 +2621,7 @@ var ShelbyRPCClient = class {
|
|
|
2144
2621
|
* @param config - The client configuration object.
|
|
2145
2622
|
* @param config.network - The Shelby network to use.
|
|
2146
2623
|
* @param options.signChallengeHandler - Optional override for challenge
|
|
2147
|
-
* signing. When set, `
|
|
2624
|
+
* signing. When set, `putBlobChunksets` uses this instead of the built-in
|
|
2148
2625
|
* `signChallenge`. Intended for kit-level overrides (e.g. Solana DAA).
|
|
2149
2626
|
*
|
|
2150
2627
|
* @example
|
|
@@ -2195,43 +2672,6 @@ var ShelbyRPCClient = class {
|
|
|
2195
2672
|
}
|
|
2196
2673
|
return ChallengeResponseSchema.parse(await response.json());
|
|
2197
2674
|
}
|
|
2198
|
-
/**
|
|
2199
|
-
* Check if there's an existing multipart upload for a blob.
|
|
2200
|
-
* Returns the upload status including which parts have been uploaded.
|
|
2201
|
-
*
|
|
2202
|
-
* @param account - The account that owns the blob.
|
|
2203
|
-
* @param blobName - The name of the blob.
|
|
2204
|
-
* @returns The upload status, or undefined if no pending upload exists.
|
|
2205
|
-
*
|
|
2206
|
-
* @example
|
|
2207
|
-
* ```typescript
|
|
2208
|
-
* const status = await client.getMultipartUploadStatus(account, "myblob.txt");
|
|
2209
|
-
* if (status) {
|
|
2210
|
-
* console.log(`Resuming upload ${status.uploadId}, ${status.completedParts.length} parts done`);
|
|
2211
|
-
* }
|
|
2212
|
-
* ```
|
|
2213
|
-
*/
|
|
2214
|
-
async getMultipartUploadStatus(account, blobName) {
|
|
2215
|
-
const url = new URL(buildRequestUrl("/v1/multipart-uploads", this.baseUrl));
|
|
2216
|
-
url.searchParams.set("account", account.toString());
|
|
2217
|
-
url.searchParams.set("blobName", blobName);
|
|
2218
|
-
const response = await fetch(url.toString(), {
|
|
2219
|
-
method: "GET",
|
|
2220
|
-
headers: {
|
|
2221
|
-
...this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {}
|
|
2222
|
-
}
|
|
2223
|
-
});
|
|
2224
|
-
if (response.status === 404) {
|
|
2225
|
-
return void 0;
|
|
2226
|
-
}
|
|
2227
|
-
if (!response.ok) {
|
|
2228
|
-
const errorBody = await response.text().catch(() => "");
|
|
2229
|
-
throw new Error(
|
|
2230
|
-
`Failed to get multipart upload status: status ${response.status}, body: ${errorBody}`
|
|
2231
|
-
);
|
|
2232
|
-
}
|
|
2233
|
-
return MultipartUploadStatusResponseSchema.parse(await response.json());
|
|
2234
|
-
}
|
|
2235
2675
|
/**
|
|
2236
2676
|
* Sign a challenge using the given account and return auth credentials.
|
|
2237
2677
|
*
|
|
@@ -2248,164 +2688,142 @@ var ShelbyRPCClient = class {
|
|
|
2248
2688
|
publicKey: account.publicKey.toUint8Array()
|
|
2249
2689
|
};
|
|
2250
2690
|
}
|
|
2251
|
-
|
|
2252
|
-
|
|
2691
|
+
/**
|
|
2692
|
+
* Upload a single chunkset via the v2 chunkset API.
|
|
2693
|
+
*/
|
|
2694
|
+
async #uploadChunkset(params) {
|
|
2695
|
+
const maxNonBusyRetries = 5;
|
|
2253
2696
|
let lastResponse;
|
|
2254
2697
|
let lastError;
|
|
2255
2698
|
let attempts = 0;
|
|
2256
|
-
|
|
2257
|
-
|
|
2699
|
+
let consecutive429s = 0;
|
|
2700
|
+
let nonBusyRetries = 0;
|
|
2701
|
+
const chunksetUrl = buildRequestUrl(
|
|
2702
|
+
`/v2/chunksets/${params.account}/${params.chunksetIndex}/${params.uid}`,
|
|
2258
2703
|
this.baseUrl
|
|
2259
2704
|
);
|
|
2260
|
-
|
|
2705
|
+
const authHeaders = buildAuthHeaders(params.auth);
|
|
2706
|
+
while (true) {
|
|
2707
|
+
if (params.signal?.aborted) {
|
|
2708
|
+
throw new DOMException("Upload aborted", "AbortError");
|
|
2709
|
+
}
|
|
2261
2710
|
attempts++;
|
|
2262
2711
|
try {
|
|
2263
|
-
lastResponse = await fetch(
|
|
2712
|
+
lastResponse = await fetch(chunksetUrl, {
|
|
2264
2713
|
method: "PUT",
|
|
2265
2714
|
headers: {
|
|
2266
2715
|
"Content-Type": "application/octet-stream",
|
|
2267
|
-
...this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {}
|
|
2716
|
+
...this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {},
|
|
2717
|
+
...authHeaders,
|
|
2718
|
+
[INCLUSION_PROOF_HEADER]: params.inclusionProof
|
|
2268
2719
|
},
|
|
2269
|
-
body:
|
|
2720
|
+
body: params.chunksetData,
|
|
2721
|
+
signal: params.signal
|
|
2270
2722
|
});
|
|
2271
2723
|
lastError = void 0;
|
|
2272
2724
|
} catch (error) {
|
|
2725
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
2726
|
+
throw error;
|
|
2727
|
+
}
|
|
2273
2728
|
lastError = error;
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2729
|
+
consecutive429s = 0;
|
|
2730
|
+
nonBusyRetries++;
|
|
2731
|
+
if (nonBusyRetries < maxNonBusyRetries) {
|
|
2732
|
+
const delay2 = 2 ** nonBusyRetries * 100;
|
|
2733
|
+
await sleep(delay2);
|
|
2277
2734
|
continue;
|
|
2278
2735
|
}
|
|
2279
2736
|
break;
|
|
2280
2737
|
}
|
|
2281
|
-
if (lastResponse.ok)
|
|
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;
|
|
2282
2765
|
if (!isRetryableStatus(lastResponse.status)) {
|
|
2283
2766
|
break;
|
|
2284
2767
|
}
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2768
|
+
nonBusyRetries++;
|
|
2769
|
+
if (nonBusyRetries >= maxNonBusyRetries) {
|
|
2770
|
+
break;
|
|
2288
2771
|
}
|
|
2772
|
+
const delay = 2 ** nonBusyRetries * 100;
|
|
2773
|
+
await sleep(delay);
|
|
2289
2774
|
}
|
|
2290
2775
|
if (lastError !== void 0) {
|
|
2291
2776
|
const errorCode = getErrorCode(lastError);
|
|
2292
2777
|
const errorMessage = lastError instanceof Error ? lastError.message : String(lastError);
|
|
2293
2778
|
throw new Error(
|
|
2294
|
-
`Failed to upload
|
|
2779
|
+
`Failed to upload chunkset ${params.chunksetIndex} after ${attempts} attempt${attempts === 1 ? "" : "s"}. ${errorCode ? `(${errorCode}) ` : ""}Last error: ${errorMessage}`,
|
|
2295
2780
|
{ cause: lastError }
|
|
2296
2781
|
);
|
|
2297
2782
|
}
|
|
2298
2783
|
const errorBody = await lastResponse?.text().catch(() => "");
|
|
2299
2784
|
throw new Error(
|
|
2300
|
-
`Failed to upload
|
|
2785
|
+
`Failed to upload chunkset ${params.chunksetIndex} after ${attempts} attempt${attempts === 1 ? "" : "s"}. status: ${lastResponse?.status}, body: ${errorBody}`
|
|
2301
2786
|
);
|
|
2302
2787
|
}
|
|
2303
|
-
async #putBlobMultipart(account, blobName, blobData, totalBytes, partSize = 5 * 1024 * 1024, onProgress) {
|
|
2304
|
-
validateTotalBytes(totalBytes);
|
|
2305
|
-
const startResponse = await fetch(
|
|
2306
|
-
buildRequestUrl("/v1/multipart-uploads", this.baseUrl),
|
|
2307
|
-
{
|
|
2308
|
-
method: "POST",
|
|
2309
|
-
headers: {
|
|
2310
|
-
"Content-Type": "application/json",
|
|
2311
|
-
...this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {}
|
|
2312
|
-
},
|
|
2313
|
-
body: JSON.stringify({
|
|
2314
|
-
rawAccount: account.toString(),
|
|
2315
|
-
rawBlobName: blobName,
|
|
2316
|
-
rawPartSize: partSize
|
|
2317
|
-
})
|
|
2318
|
-
}
|
|
2319
|
-
);
|
|
2320
|
-
if (!startResponse.ok) {
|
|
2321
|
-
let errorBodyText = "Could not read error body";
|
|
2322
|
-
try {
|
|
2323
|
-
errorBodyText = await startResponse.text();
|
|
2324
|
-
} catch (_e) {
|
|
2325
|
-
}
|
|
2326
|
-
throw new Error(
|
|
2327
|
-
`Failed to start multipart upload! status: ${startResponse.status}, body: ${errorBodyText}`
|
|
2328
|
-
);
|
|
2329
|
-
}
|
|
2330
|
-
const { uploadId } = StartMultipartUploadResponseSchema.parse(
|
|
2331
|
-
await startResponse.json()
|
|
2332
|
-
);
|
|
2333
|
-
const totalParts = Math.ceil(totalBytes / partSize);
|
|
2334
|
-
let uploadedBytes = 0;
|
|
2335
|
-
for await (const [partIdx, partData] of readInChunks(blobData, partSize)) {
|
|
2336
|
-
await this.#uploadPart(uploadId, partIdx, partData);
|
|
2337
|
-
uploadedBytes += partData.length;
|
|
2338
|
-
onProgress?.({
|
|
2339
|
-
phase: "uploading",
|
|
2340
|
-
partIdx,
|
|
2341
|
-
totalParts,
|
|
2342
|
-
partBytes: partData.length,
|
|
2343
|
-
uploadedBytes,
|
|
2344
|
-
totalBytes
|
|
2345
|
-
});
|
|
2346
|
-
}
|
|
2347
|
-
if (uploadedBytes !== totalBytes) {
|
|
2348
|
-
throw new Error(
|
|
2349
|
-
`Uploaded bytes (${uploadedBytes}) did not match declared totalBytes (${totalBytes})`
|
|
2350
|
-
);
|
|
2351
|
-
}
|
|
2352
|
-
const finalPartIdx = totalParts > 0 ? totalParts - 1 : 0;
|
|
2353
|
-
onProgress?.({
|
|
2354
|
-
phase: "finalizing",
|
|
2355
|
-
partIdx: finalPartIdx,
|
|
2356
|
-
totalParts,
|
|
2357
|
-
// no part uploaded in this phase
|
|
2358
|
-
partBytes: 0,
|
|
2359
|
-
uploadedBytes: totalBytes,
|
|
2360
|
-
totalBytes
|
|
2361
|
-
});
|
|
2362
|
-
const completeResponse = await fetch(
|
|
2363
|
-
buildRequestUrl(
|
|
2364
|
-
`/v1/multipart-uploads/${uploadId}/complete`,
|
|
2365
|
-
this.baseUrl
|
|
2366
|
-
),
|
|
2367
|
-
{
|
|
2368
|
-
method: "POST",
|
|
2369
|
-
headers: {
|
|
2370
|
-
"Content-Type": "application/json",
|
|
2371
|
-
...this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {}
|
|
2372
|
-
}
|
|
2373
|
-
}
|
|
2374
|
-
);
|
|
2375
|
-
if (!completeResponse.ok) {
|
|
2376
|
-
let errorBodyText = "Could not read error body";
|
|
2377
|
-
try {
|
|
2378
|
-
errorBodyText = await completeResponse.text();
|
|
2379
|
-
} catch (_e) {
|
|
2380
|
-
}
|
|
2381
|
-
throw new Error(
|
|
2382
|
-
`Failed to complete multipart upload! status: ${completeResponse.status}, body: ${errorBodyText}`
|
|
2383
|
-
);
|
|
2384
|
-
}
|
|
2385
|
-
}
|
|
2386
2788
|
/**
|
|
2387
|
-
* Uploads blob data to the Shelby RPC node
|
|
2388
|
-
* This method
|
|
2389
|
-
*
|
|
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.
|
|
2390
2792
|
*
|
|
2391
|
-
*
|
|
2392
|
-
*
|
|
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).
|
|
2393
2800
|
* @param params.blobData - The raw blob data as a Uint8Array or ReadableStream.
|
|
2801
|
+
* @param params.commitments - Pre-computed blob commitments (from generateCommitments).
|
|
2394
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.
|
|
2395
2807
|
*
|
|
2396
2808
|
* @example
|
|
2397
2809
|
* ```typescript
|
|
2398
|
-
*
|
|
2810
|
+
* // First, generate commitments for the blob
|
|
2811
|
+
* const commitments = await generateCommitments(provider, fileData);
|
|
2399
2812
|
*
|
|
2400
|
-
*
|
|
2401
|
-
*
|
|
2402
|
-
*
|
|
2403
|
-
*
|
|
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,
|
|
2404
2823
|
* });
|
|
2405
2824
|
* ```
|
|
2406
2825
|
*/
|
|
2407
|
-
async
|
|
2408
|
-
BlobNameSchema.parse(params.blobName);
|
|
2826
|
+
async putBlobChunksets(params) {
|
|
2409
2827
|
let totalBytes;
|
|
2410
2828
|
if (params.blobData instanceof Uint8Array) {
|
|
2411
2829
|
totalBytes = params.totalBytes ?? params.blobData.length;
|
|
@@ -2423,215 +2841,146 @@ var ShelbyRPCClient = class {
|
|
|
2423
2841
|
totalBytes = params.totalBytes;
|
|
2424
2842
|
}
|
|
2425
2843
|
validateTotalBytes(totalBytes);
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
totalBytes,
|
|
2431
|
-
void 0,
|
|
2432
|
-
params.onProgress
|
|
2433
|
-
);
|
|
2434
|
-
}
|
|
2435
|
-
/**
|
|
2436
|
-
* Upload a part with authentication headers.
|
|
2437
|
-
*/
|
|
2438
|
-
async #uploadPartWithAuth(uploadId, partIdx, partData, auth) {
|
|
2439
|
-
const nRetries = 5;
|
|
2440
|
-
let lastResponse;
|
|
2441
|
-
let lastError;
|
|
2442
|
-
let attempts = 0;
|
|
2443
|
-
const partUrl = buildRequestUrl(
|
|
2444
|
-
`/v1/multipart-uploads/${uploadId}/parts/${partIdx}`,
|
|
2445
|
-
this.baseUrl
|
|
2446
|
-
);
|
|
2447
|
-
const authHeaders = buildAuthHeaders(auth);
|
|
2448
|
-
for (let i = 0; i < nRetries; ++i) {
|
|
2449
|
-
attempts++;
|
|
2450
|
-
try {
|
|
2451
|
-
lastResponse = await fetch(partUrl, {
|
|
2452
|
-
method: "PUT",
|
|
2453
|
-
headers: {
|
|
2454
|
-
"Content-Type": "application/octet-stream",
|
|
2455
|
-
...this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {},
|
|
2456
|
-
...authHeaders
|
|
2457
|
-
},
|
|
2458
|
-
body: partData
|
|
2459
|
-
});
|
|
2460
|
-
lastError = void 0;
|
|
2461
|
-
} catch (error) {
|
|
2462
|
-
lastError = error;
|
|
2463
|
-
if (i < nRetries - 1) {
|
|
2464
|
-
const delay = 2 ** i * 100;
|
|
2465
|
-
await sleep(delay);
|
|
2466
|
-
continue;
|
|
2467
|
-
}
|
|
2468
|
-
break;
|
|
2469
|
-
}
|
|
2470
|
-
if (lastResponse.ok) return;
|
|
2471
|
-
if (!isRetryableStatus(lastResponse.status)) {
|
|
2472
|
-
break;
|
|
2473
|
-
}
|
|
2474
|
-
if (i < nRetries - 1) {
|
|
2475
|
-
const delay = 2 ** i * 100;
|
|
2476
|
-
await sleep(delay);
|
|
2477
|
-
}
|
|
2478
|
-
}
|
|
2479
|
-
if (lastError !== void 0) {
|
|
2480
|
-
const errorCode = getErrorCode(lastError);
|
|
2481
|
-
const errorMessage = lastError instanceof Error ? lastError.message : String(lastError);
|
|
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) {
|
|
2482
2848
|
throw new Error(
|
|
2483
|
-
`
|
|
2484
|
-
{ cause: lastError }
|
|
2849
|
+
`Data size mismatch: commitments were generated for ${rawDataSizeFromCommitments} bytes, but totalBytes=${totalBytes}. This will cause inclusion proof verification to fail.`
|
|
2485
2850
|
);
|
|
2486
2851
|
}
|
|
2487
|
-
const
|
|
2488
|
-
|
|
2489
|
-
`Failed to upload part ${partIdx} for multipart upload ${uploadId} after ${attempts} attempt${attempts === 1 ? "" : "s"}. status: ${lastResponse?.status}, body: ${errorBody}`
|
|
2852
|
+
const chunksetRoots = params.commitments.chunkset_commitments.map(
|
|
2853
|
+
(c) => Hex6.fromHexString(c.chunkset_root)
|
|
2490
2854
|
);
|
|
2491
|
-
}
|
|
2492
|
-
/**
|
|
2493
|
-
* Uploads blob data to the Shelby RPC node with authentication and resume support.
|
|
2494
|
-
* This method authenticates using challenge-response and can resume interrupted uploads.
|
|
2495
|
-
*
|
|
2496
|
-
* @param params.account - The Aptos Account (with signing capability) that owns the blob.
|
|
2497
|
-
* @param params.blobName - The name/path of the blob (e.g. "folder/file.txt").
|
|
2498
|
-
* @param params.blobData - The raw blob data as a Uint8Array or ReadableStream.
|
|
2499
|
-
* @param params.totalBytes - Total byte length. Required for streams; optional for Uint8Array.
|
|
2500
|
-
* @param params.onProgress - Optional callback for upload progress.
|
|
2501
|
-
*
|
|
2502
|
-
* @example
|
|
2503
|
-
* ```typescript
|
|
2504
|
-
* await client.putBlobResumable({
|
|
2505
|
-
* account: myAccount, // Aptos Account with signing capability
|
|
2506
|
-
* blobName: "documents/report.pdf",
|
|
2507
|
-
* blobData: fileData,
|
|
2508
|
-
* totalBytes: fileData.length,
|
|
2509
|
-
* });
|
|
2510
|
-
* ```
|
|
2511
|
-
*/
|
|
2512
|
-
async putBlobResumable(params) {
|
|
2513
|
-
BlobNameSchema.parse(params.blobName);
|
|
2514
|
-
let totalBytes;
|
|
2515
|
-
if (params.blobData instanceof Uint8Array) {
|
|
2516
|
-
totalBytes = params.totalBytes ?? params.blobData.length;
|
|
2517
|
-
if (totalBytes !== params.blobData.length) {
|
|
2518
|
-
throw new Error(
|
|
2519
|
-
"totalBytes must match blobData.length when blobData is a Uint8Array"
|
|
2520
|
-
);
|
|
2521
|
-
}
|
|
2522
|
-
} else {
|
|
2523
|
-
if (params.totalBytes === void 0) {
|
|
2524
|
-
throw new Error(
|
|
2525
|
-
"totalBytes is required when blobData is a ReadableStream"
|
|
2526
|
-
);
|
|
2527
|
-
}
|
|
2528
|
-
totalBytes = params.totalBytes;
|
|
2529
|
-
}
|
|
2530
|
-
validateTotalBytes(totalBytes);
|
|
2531
|
-
const partSize = params.partSize ?? 5 * 1024 * 1024;
|
|
2532
2855
|
const { challenge } = await this.getChallenge(
|
|
2533
2856
|
params.account.accountAddress
|
|
2534
2857
|
);
|
|
2535
2858
|
const signFn = this.#signChallengeOverride ?? this.signChallenge.bind(this);
|
|
2536
2859
|
const auth = signFn(params.account, challenge);
|
|
2537
|
-
const
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
uploadId = existingUpload.uploadId;
|
|
2547
|
-
completedPartsSet = new Set(existingUpload.completedParts);
|
|
2548
|
-
totalParts = existingUpload.nParts;
|
|
2549
|
-
if (existingUpload.partSize !== partSize) {
|
|
2550
|
-
throw new Error(
|
|
2551
|
-
`Cannot resume upload: part size mismatch. Existing upload uses ${existingUpload.partSize} bytes, but ${partSize} was requested.`
|
|
2552
|
-
);
|
|
2553
|
-
}
|
|
2554
|
-
} else {
|
|
2555
|
-
const startResponse = await fetch(
|
|
2556
|
-
buildRequestUrl("/v1/multipart-uploads", this.baseUrl),
|
|
2557
|
-
{
|
|
2558
|
-
method: "POST",
|
|
2559
|
-
headers: {
|
|
2560
|
-
"Content-Type": "application/json",
|
|
2561
|
-
...this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {},
|
|
2562
|
-
...authHeaders
|
|
2563
|
-
},
|
|
2564
|
-
body: JSON.stringify({
|
|
2565
|
-
rawAccount: params.account.accountAddress.toString(),
|
|
2566
|
-
rawBlobName: params.blobName,
|
|
2567
|
-
rawPartSize: partSize
|
|
2568
|
-
})
|
|
2569
|
-
}
|
|
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}`
|
|
2570
2869
|
);
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
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.`
|
|
2579
2879
|
);
|
|
2580
|
-
uploadId = parsed.uploadId;
|
|
2581
|
-
completedPartsSet = /* @__PURE__ */ new Set();
|
|
2582
|
-
totalParts = Math.ceil(totalBytes / partSize);
|
|
2583
2880
|
}
|
|
2584
2881
|
let uploadedBytes = 0;
|
|
2585
|
-
let
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
if (completedPartsSet.has(partIdx)) {
|
|
2592
|
-
uploadedBytes += partData.length;
|
|
2593
|
-
continue;
|
|
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;
|
|
2594
2888
|
}
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
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
|
|
2604
2899
|
});
|
|
2605
2900
|
}
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
...authHeaders
|
|
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
|
+
);
|
|
2626
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);
|
|
2627
2967
|
}
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2968
|
+
if (inFlight.size > 0) {
|
|
2969
|
+
await Promise.race(inFlight);
|
|
2970
|
+
}
|
|
2971
|
+
}
|
|
2972
|
+
if (firstError) {
|
|
2973
|
+
throw firstError;
|
|
2974
|
+
}
|
|
2975
|
+
if (bytesReadFromSource !== totalBytes) {
|
|
2631
2976
|
throw new Error(
|
|
2632
|
-
`
|
|
2977
|
+
`Data source produced ${bytesReadFromSource} bytes, but expected ${totalBytes} bytes. The stream may have ended prematurely, resulting in an incomplete upload.`
|
|
2633
2978
|
);
|
|
2634
2979
|
}
|
|
2980
|
+
const spAcks = Array.from(
|
|
2981
|
+
aggregatedAcks.entries()
|
|
2982
|
+
).map(([slot, signature]) => ({ slot, signature }));
|
|
2983
|
+
return { spAcks };
|
|
2635
2984
|
}
|
|
2636
2985
|
/**
|
|
2637
2986
|
* Downloads a blob from the Shelby RPC node.
|
|
@@ -2883,6 +3232,59 @@ var ShelbyClient = class {
|
|
|
2883
3232
|
}
|
|
2884
3233
|
return this._provider;
|
|
2885
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
|
+
}
|
|
2886
3288
|
/**
|
|
2887
3289
|
* The base URL for the Shelby RPC node.
|
|
2888
3290
|
*/
|
|
@@ -2896,8 +3298,8 @@ var ShelbyClient = class {
|
|
|
2896
3298
|
*
|
|
2897
3299
|
* Note: This method accepts only `Uint8Array` and buffers the entire blob in memory.
|
|
2898
3300
|
* For streaming uploads of large files (e.g. >2 GiB), orchestrate the steps manually
|
|
2899
|
-
* using `generateCommitments()`, `coordination.registerBlob()`,
|
|
2900
|
-
* with a `ReadableStream`.
|
|
3301
|
+
* using `generateCommitments()`, `coordination.registerBlob()`, `rpc.putBlobChunksets()`,
|
|
3302
|
+
* and `coordination.commitObject()` with a `ReadableStream`.
|
|
2901
3303
|
*
|
|
2902
3304
|
* @param params.blobData - The raw data to upload as a Uint8Array.
|
|
2903
3305
|
* @param params.signer - The account that signs and pays for the transaction.
|
|
@@ -2920,34 +3322,57 @@ var ShelbyClient = class {
|
|
|
2920
3322
|
* ```
|
|
2921
3323
|
*/
|
|
2922
3324
|
async upload(params) {
|
|
2923
|
-
const
|
|
2924
|
-
|
|
2925
|
-
|
|
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
|
|
2926
3353
|
});
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
provider,
|
|
2931
|
-
params.blobData
|
|
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`
|
|
2932
3358
|
);
|
|
2933
|
-
const { transaction: pendingRegisterBlobTransaction } = await this.coordination.registerBlob({
|
|
2934
|
-
account: params.signer,
|
|
2935
|
-
blobName: params.blobName,
|
|
2936
|
-
blobMerkleRoot: blobCommitments.blob_merkle_root,
|
|
2937
|
-
size: params.blobData.length,
|
|
2938
|
-
expirationMicros: params.expirationMicros,
|
|
2939
|
-
config: provider.config,
|
|
2940
|
-
options: params.options
|
|
2941
|
-
});
|
|
2942
|
-
await this.coordination.aptos.waitForTransaction({
|
|
2943
|
-
transactionHash: pendingRegisterBlobTransaction.hash
|
|
2944
|
-
});
|
|
2945
3359
|
}
|
|
2946
|
-
await this.
|
|
3360
|
+
const { transaction: pendingCommitTransaction } = await this.coordination.commitObject({
|
|
2947
3361
|
account: params.signer,
|
|
3362
|
+
uid,
|
|
2948
3363
|
blobName: params.blobName,
|
|
2949
|
-
|
|
3364
|
+
overwrite: true,
|
|
3365
|
+
storageProviderAcks: spAcks,
|
|
3366
|
+
options: this.orderlessCommitOptions()
|
|
2950
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
|
+
}
|
|
2951
3376
|
}
|
|
2952
3377
|
/**
|
|
2953
3378
|
* Uploads a batch of blobs to the Shelby network.
|
|
@@ -2956,8 +3381,8 @@ var ShelbyClient = class {
|
|
|
2956
3381
|
*
|
|
2957
3382
|
* Note: This method accepts only `Uint8Array` and buffers each blob in memory.
|
|
2958
3383
|
* For streaming uploads of large files, orchestrate the steps manually using
|
|
2959
|
-
* `generateCommitments()`, `coordination.registerBlob()`,
|
|
2960
|
-
* with a `ReadableStream`.
|
|
3384
|
+
* `generateCommitments()`, `coordination.registerBlob()`, `rpc.putBlobChunksets()`,
|
|
3385
|
+
* and `coordination.commitObject()` with a `ReadableStream`.
|
|
2961
3386
|
*
|
|
2962
3387
|
* @param params.blobs - The blobs to upload.
|
|
2963
3388
|
* @param params.blobs.blobData - The raw data to upload as a Uint8Array.
|
|
@@ -2982,59 +3407,77 @@ var ShelbyClient = class {
|
|
|
2982
3407
|
* ```
|
|
2983
3408
|
*/
|
|
2984
3409
|
async batchUpload(params) {
|
|
2985
|
-
const
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
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
|
|
2996
3427
|
});
|
|
2997
|
-
const
|
|
2998
|
-
|
|
2999
|
-
(existingBlob) => existingBlob.name === createBlobKey({
|
|
3000
|
-
account: params.signer.accountAddress,
|
|
3001
|
-
blobName: blob.blobName
|
|
3002
|
-
})
|
|
3003
|
-
)
|
|
3428
|
+
const registerTx = await this.waitForRegistration(
|
|
3429
|
+
pendingRegisterBlobTransaction.hash
|
|
3004
3430
|
);
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
const { transaction: pendingRegisterBlobTransaction } = await this.coordination.batchRegisterBlobs({
|
|
3013
|
-
account: params.signer,
|
|
3014
|
-
expirationMicros: params.expirationMicros,
|
|
3015
|
-
blobs: blobsToRegister.map((blob, index) => ({
|
|
3016
|
-
blobName: blob.blobName,
|
|
3017
|
-
blobSize: blob.blobData.length,
|
|
3018
|
-
blobMerkleRoot: blobCommitments[index].blob_merkle_root
|
|
3019
|
-
})),
|
|
3020
|
-
config: provider.config,
|
|
3021
|
-
options: params.options
|
|
3022
|
-
});
|
|
3023
|
-
await this.coordination.aptos.waitForTransaction({
|
|
3024
|
-
transactionHash: pendingRegisterBlobTransaction.hash,
|
|
3025
|
-
options: { waitForIndexer: true }
|
|
3026
|
-
});
|
|
3027
|
-
}
|
|
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);
|
|
3028
3438
|
const limit = pLimit(3);
|
|
3029
3439
|
await Promise.all(
|
|
3030
|
-
|
|
3031
|
-
(
|
|
3032
|
-
|
|
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({
|
|
3033
3453
|
account: params.signer,
|
|
3034
|
-
|
|
3035
|
-
blobData: blob.blobData
|
|
3036
|
-
|
|
3037
|
-
|
|
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
|
+
})
|
|
3038
3481
|
)
|
|
3039
3482
|
);
|
|
3040
3483
|
}
|
|
@@ -3280,6 +3723,58 @@ var ShelbyMicropaymentChannelClient = class _ShelbyMicropaymentChannelClient {
|
|
|
3280
3723
|
]
|
|
3281
3724
|
};
|
|
3282
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
|
+
}
|
|
3283
3778
|
/**
|
|
3284
3779
|
* Creates a micropayment that can be sent to a receiver.
|
|
3285
3780
|
* The sender signs a WithdrawApproval message that authorizes the receiver
|
|
@@ -3651,36 +4146,6 @@ var ShelbyPlacementGroupClient = class {
|
|
|
3651
4146
|
}
|
|
3652
4147
|
};
|
|
3653
4148
|
|
|
3654
|
-
// src/core/errors.ts
|
|
3655
|
-
var ShelbyErrorCodes = {
|
|
3656
|
-
// blob_metadata.move errors
|
|
3657
|
-
E_BLOB_NOT_FOUND: "E_BLOB_NOT_FOUND",
|
|
3658
|
-
E_INVALID_EXPIRATION_TIME: "E_INVALID_EXPIRATION_TIME",
|
|
3659
|
-
E_TEST_ENCODING_NOT_ALLOWED: "E_TEST_ENCODING_NOT_ALLOWED",
|
|
3660
|
-
E_BLOB_NOT_EXPIRED: "E_BLOB_NOT_EXPIRED",
|
|
3661
|
-
E_INVALID_CHUNKSET_COUNT: "E_INVALID_CHUNKSET_COUNT",
|
|
3662
|
-
E_NOT_BLOB_OWNER: "E_NOT_BLOB_OWNER",
|
|
3663
|
-
E_NOT_ADMIN: "E_NOT_ADMIN",
|
|
3664
|
-
E_BLOB_EXPIRED: "E_BLOB_EXPIRED",
|
|
3665
|
-
E_BLOB_NAME_TOO_LONG: "E_BLOB_NAME_TOO_LONG",
|
|
3666
|
-
E_INVALID_PAYMENT_EPOCHS: "E_INVALID_PAYMENT_EPOCHS",
|
|
3667
|
-
E_NO_SLICES_AVAILABLE: "E_NO_SLICES_AVAILABLE",
|
|
3668
|
-
// Common Aptos/Move errors
|
|
3669
|
-
EALREADY_EXISTS: "EALREADY_EXISTS"
|
|
3670
|
-
};
|
|
3671
|
-
function isBlobAlreadyExistsError(errorMessage) {
|
|
3672
|
-
return errorMessage.includes(ShelbyErrorCodes.EALREADY_EXISTS) || errorMessage.includes("already exists");
|
|
3673
|
-
}
|
|
3674
|
-
function isAccessDeniedError(errorMessage) {
|
|
3675
|
-
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");
|
|
3676
|
-
}
|
|
3677
|
-
function isBlobNotFoundError(errorMessage) {
|
|
3678
|
-
return errorMessage.includes(ShelbyErrorCodes.E_BLOB_NOT_FOUND);
|
|
3679
|
-
}
|
|
3680
|
-
function isBlobExpiredError(errorMessage) {
|
|
3681
|
-
return errorMessage.includes(ShelbyErrorCodes.E_BLOB_EXPIRED);
|
|
3682
|
-
}
|
|
3683
|
-
|
|
3684
4149
|
// src/core/networks.ts
|
|
3685
4150
|
import { Network as Network5 } from "@aptos-labs/ts-sdk";
|
|
3686
4151
|
var shelbyNetworks = [
|
|
@@ -3743,8 +4208,12 @@ function makeChunk(n) {
|
|
|
3743
4208
|
export {
|
|
3744
4209
|
BlobCommitmentsSchema,
|
|
3745
4210
|
BlobNameSchema,
|
|
4211
|
+
Blob_Activities_Constraint,
|
|
3746
4212
|
Blob_Activities_Select_Column,
|
|
4213
|
+
Blob_Activities_Update_Column,
|
|
4214
|
+
Blobs_Constraint,
|
|
3747
4215
|
Blobs_Select_Column,
|
|
4216
|
+
Blobs_Update_Column,
|
|
3748
4217
|
CHUNK_SIZE_PARAMS,
|
|
3749
4218
|
COMMITMENT_SCHEMA_VERSION,
|
|
3750
4219
|
ChallengeResponseSchema,
|
|
@@ -3752,7 +4221,6 @@ export {
|
|
|
3752
4221
|
ChunkSizeScheme,
|
|
3753
4222
|
ChunksetCommitmentSchema,
|
|
3754
4223
|
ClayErasureCodingProvider,
|
|
3755
|
-
CompleteMultipartUploadResponseSchema,
|
|
3756
4224
|
Cursor_Ordering,
|
|
3757
4225
|
DEFAULT_CHUNKSET_SIZE_BYTES,
|
|
3758
4226
|
DEFAULT_CHUNK_SIZE_BYTES,
|
|
@@ -3776,13 +4244,17 @@ export {
|
|
|
3776
4244
|
GetTotalBlobsSizeDocument,
|
|
3777
4245
|
MICROPAYMENTS_DEPLOYER,
|
|
3778
4246
|
MissingTransactionSubmitterError,
|
|
3779
|
-
MultipartUploadStatusResponseSchema,
|
|
3780
4247
|
NetworkToGasStationBaseUrl,
|
|
3781
4248
|
NetworkToShelbyBlobIndexerBaseUrl,
|
|
3782
4249
|
NetworkToShelbyRPCBaseUrl,
|
|
4250
|
+
ObjectCommitRejectedError,
|
|
3783
4251
|
Order_By,
|
|
4252
|
+
Placement_Group_Slots_Constraint,
|
|
3784
4253
|
Placement_Group_Slots_Select_Column,
|
|
4254
|
+
Placement_Group_Slots_Update_Column,
|
|
4255
|
+
Processor_Status_Constraint,
|
|
3785
4256
|
Processor_Status_Select_Column,
|
|
4257
|
+
Processor_Status_Update_Column,
|
|
3786
4258
|
RPCErrorResponseSchema,
|
|
3787
4259
|
ReedSolomonErasureCodingProvider,
|
|
3788
4260
|
SHELBYUSD_FA_METADATA_ADDRESS,
|
|
@@ -3794,6 +4266,7 @@ export {
|
|
|
3794
4266
|
ShelbyBlobClient,
|
|
3795
4267
|
ShelbyClient,
|
|
3796
4268
|
ShelbyErrorCodes,
|
|
4269
|
+
ShelbyLocationErrorCodes,
|
|
3797
4270
|
ShelbyMetadataClient,
|
|
3798
4271
|
ShelbyMicropaymentChannelClient,
|
|
3799
4272
|
ShelbyNodeClient,
|
|
@@ -3801,19 +4274,22 @@ export {
|
|
|
3801
4274
|
ShelbyRPCClient,
|
|
3802
4275
|
StaleChannelStateError,
|
|
3803
4276
|
StaleMicropaymentErrorResponseSchema,
|
|
3804
|
-
StartMultipartUploadResponseSchema,
|
|
3805
4277
|
TOKEN_DEPLOYER,
|
|
3806
4278
|
TOKEN_OBJECT_ADDRESS,
|
|
3807
|
-
|
|
4279
|
+
blobEncryptionFromMoveVariant,
|
|
4280
|
+
blobEncryptionToMoveEnumIndex,
|
|
3808
4281
|
buildRequestUrl,
|
|
3809
4282
|
concatHashes,
|
|
3810
4283
|
createBlobKey,
|
|
3811
4284
|
createDefaultErasureCodingProvider,
|
|
3812
4285
|
createShelbyIndexerClient,
|
|
3813
4286
|
defaultErasureCodingConfig,
|
|
4287
|
+
describeLocationError,
|
|
3814
4288
|
erasureCodingConfig16Total10Data13Helper,
|
|
3815
4289
|
erasureCodingConfig4Total2Data3Helper,
|
|
4290
|
+
expectedChunksetInclusionProofHashes,
|
|
3816
4291
|
expectedTotalChunksets,
|
|
4292
|
+
findErasureSchemeByErasureN,
|
|
3817
4293
|
generateCommitments,
|
|
3818
4294
|
generateMerkleRoot,
|
|
3819
4295
|
getAptosAccountExplorerUrl,
|
|
@@ -3825,12 +4301,15 @@ export {
|
|
|
3825
4301
|
getShelbyBlobExplorerUrl,
|
|
3826
4302
|
getShelbyIndexerClient,
|
|
3827
4303
|
isAccessDeniedError,
|
|
4304
|
+
isActiveForTasks,
|
|
4305
|
+
isActiveProviderCondition,
|
|
3828
4306
|
isBlobAlreadyExistsError,
|
|
3829
4307
|
isBlobExpiredError,
|
|
3830
4308
|
isBlobNotFoundError,
|
|
3831
4309
|
isShelbyNetwork,
|
|
3832
4310
|
normalizeAddress,
|
|
3833
4311
|
readInChunks,
|
|
4312
|
+
requiredAckCount,
|
|
3834
4313
|
shelbyNetworks,
|
|
3835
4314
|
testUtil_exports as testUtil,
|
|
3836
4315
|
zeroPadBytes
|