@orbinum/sdk 0.7.10 → 0.8.1
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/index.d.mts +47 -23
- package/dist/index.d.ts +47 -23
- package/dist/index.js +68 -28
- package/dist/index.mjs +68 -28
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -530,8 +530,6 @@ interface ShieldedCommitment {
|
|
|
530
530
|
assetId: string;
|
|
531
531
|
/** Origin of the commitment: direct shield, output of private transfer, or change from unshield. */
|
|
532
532
|
source: 'shield' | 'transfer' | 'unshield';
|
|
533
|
-
/** SS58 or 0x-prefixed depositor address, null if not tracked. */
|
|
534
|
-
sender: string | null;
|
|
535
533
|
/** 0x-prefixed encrypted memo hex, null if not present. */
|
|
536
534
|
encryptedMemo: string | null;
|
|
537
535
|
timestampMs: number | null;
|
|
@@ -728,17 +726,29 @@ interface RegisteredAsset {
|
|
|
728
726
|
timestampMs: number | null;
|
|
729
727
|
}
|
|
730
728
|
/**
|
|
731
|
-
*
|
|
732
|
-
*
|
|
733
|
-
* unshield,
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
kind: '
|
|
741
|
-
|
|
729
|
+
* One shielded-pool BOUNDARY event for an address, as served by
|
|
730
|
+
* `GET /shielded/address/:addr`. Only boundary facts are exposed — block,
|
|
731
|
+
* asset, amount (unshield), time, tx hash. Note internals (commitment hex,
|
|
732
|
+
* leaf index, nullifier, memo, sender/recipient) are never returned
|
|
733
|
+
* per-address: a public sender→leaf mapping would shrink the shielded pool's
|
|
734
|
+
* anonymity set. Private transfers carry no address and are never included.
|
|
735
|
+
*/
|
|
736
|
+
interface ShieldedAddressEvent {
|
|
737
|
+
/** 'shield' = deposit into the pool by this address; 'unshield' = withdrawal received by it. */
|
|
738
|
+
kind: 'shield' | 'unshield';
|
|
739
|
+
blockNumber: number;
|
|
740
|
+
extrinsicIndex: number | null;
|
|
741
|
+
/** Asset ID as decimal string. */
|
|
742
|
+
assetId: string;
|
|
743
|
+
/**
|
|
744
|
+
* Amount as decimal string (bigint-safe) for unshields.
|
|
745
|
+
* Always null for shields — the shield amount lives in the extrinsic, not the index.
|
|
746
|
+
*/
|
|
747
|
+
amount: string | null;
|
|
748
|
+
timestampMs: number | null;
|
|
749
|
+
/** Blake2-256 hash of the enclosing extrinsic, 0x-prefixed. Null if not decoded. */
|
|
750
|
+
hash: string | null;
|
|
751
|
+
}
|
|
742
752
|
/** A validator node indexed from pallet-validator-set events. */
|
|
743
753
|
interface IndexedValidator {
|
|
744
754
|
account: string;
|
|
@@ -834,18 +844,35 @@ declare class IndexerClient {
|
|
|
834
844
|
* For the current Orbinum testnet/mainnet scale this is the recommended approach.
|
|
835
845
|
*/
|
|
836
846
|
getAllSpentNullifiers(): Promise<Set<string>>;
|
|
847
|
+
/** Server-enforced max items per by-nullifiers / by-commitments request. */
|
|
848
|
+
private static readonly TRANSFER_LOOKUP_CHUNK;
|
|
849
|
+
/**
|
|
850
|
+
* Chunked fetch for the transfer timestamp lookups. The reader silently
|
|
851
|
+
* truncates each request to 50 items, so larger inputs MUST be split or
|
|
852
|
+
* results are silently lost. Responses are merged per extrinsic
|
|
853
|
+
* (`blockNumber:extrinsicIndex`), concatenating the matched arrays, and
|
|
854
|
+
* sorted by block descending.
|
|
855
|
+
*
|
|
856
|
+
* Privacy note: these lookups send the wallet's own note identifiers to
|
|
857
|
+
* the indexer — a bounded, documented linkage tradeoff for timestamp
|
|
858
|
+
* recovery. They are NEVER used for spent-STATUS checks (PIR-A: status
|
|
859
|
+
* comes from the anonymous full-set `/shielded/nullifiers/all` download).
|
|
860
|
+
*/
|
|
861
|
+
private fetchTransfersChunked;
|
|
837
862
|
/**
|
|
838
863
|
* Returns temporal metadata for private transfers that spent any of the given nullifiers.
|
|
839
864
|
* Only blockNumber, extrinsicIndex, timestampMs, and hash are returned — no cross-link
|
|
840
865
|
* between inputs and outputs to prevent graph reconstruction.
|
|
841
|
-
*
|
|
866
|
+
* Inputs of any size are transparently chunked into requests of 50 (the server cap)
|
|
867
|
+
* and merged per extrinsic.
|
|
842
868
|
*/
|
|
843
869
|
getTransfersByNullifiers(nullifiers: string[]): Promise<PrivateTransferTimestamp[]>;
|
|
844
870
|
/**
|
|
845
871
|
* Returns temporal metadata for private transfers that produced any of the given commitments.
|
|
846
872
|
* Only blockNumber, extrinsicIndex, timestampMs, and hash are returned — no cross-link
|
|
847
873
|
* between outputs and inputs to prevent graph reconstruction.
|
|
848
|
-
*
|
|
874
|
+
* Inputs of any size are transparently chunked into requests of 50 (the server cap)
|
|
875
|
+
* and merged per extrinsic.
|
|
849
876
|
*/
|
|
850
877
|
getTransfersByCommitments(commitments: string[]): Promise<PrivateTransferTimestamp[]>;
|
|
851
878
|
/** Returns a paginated list of unshield events. */
|
|
@@ -881,11 +908,6 @@ declare class IndexerClient {
|
|
|
881
908
|
}): Promise<PaginatedResult<IndexedBlock>>;
|
|
882
909
|
/** Returns a single block by number or hash, or null if not found. */
|
|
883
910
|
getBlock(numberOrHash: string | number): Promise<IndexedBlock | null>;
|
|
884
|
-
/** Returns a paginated list of shielded commitments initiated by an address. */
|
|
885
|
-
getAddressCommitments(address: string, params?: {
|
|
886
|
-
page?: number;
|
|
887
|
-
limit?: number;
|
|
888
|
-
}): Promise<PaginatedResult<ShieldedCommitment>>;
|
|
889
911
|
/**
|
|
890
912
|
* Returns a paginated list of unshield events where the given address is the recipient.
|
|
891
913
|
* Accepts a 0x-prefixed EVM address or an SS58 Substrate address.
|
|
@@ -895,9 +917,11 @@ declare class IndexerClient {
|
|
|
895
917
|
limit?: number;
|
|
896
918
|
}): Promise<PaginatedResult<Unshield>>;
|
|
897
919
|
/**
|
|
898
|
-
* Returns
|
|
899
|
-
*
|
|
900
|
-
*
|
|
920
|
+
* Returns the shielded-pool BOUNDARY activity for an address: shields it
|
|
921
|
+
* deposited and unshields it received, tagged `kind: 'shield' | 'unshield'`.
|
|
922
|
+
* Only boundary fields are returned (block, asset, amount for unshields,
|
|
923
|
+
* timestamp, tx hash) — note internals are never served per-address, and
|
|
924
|
+
* private transfers carry no address at all (PIR-A).
|
|
901
925
|
*/
|
|
902
926
|
getAddressShieldedActivity(address: string, params?: {
|
|
903
927
|
page?: number;
|
package/dist/index.d.ts
CHANGED
|
@@ -530,8 +530,6 @@ interface ShieldedCommitment {
|
|
|
530
530
|
assetId: string;
|
|
531
531
|
/** Origin of the commitment: direct shield, output of private transfer, or change from unshield. */
|
|
532
532
|
source: 'shield' | 'transfer' | 'unshield';
|
|
533
|
-
/** SS58 or 0x-prefixed depositor address, null if not tracked. */
|
|
534
|
-
sender: string | null;
|
|
535
533
|
/** 0x-prefixed encrypted memo hex, null if not present. */
|
|
536
534
|
encryptedMemo: string | null;
|
|
537
535
|
timestampMs: number | null;
|
|
@@ -728,17 +726,29 @@ interface RegisteredAsset {
|
|
|
728
726
|
timestampMs: number | null;
|
|
729
727
|
}
|
|
730
728
|
/**
|
|
731
|
-
*
|
|
732
|
-
*
|
|
733
|
-
* unshield,
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
kind: '
|
|
741
|
-
|
|
729
|
+
* One shielded-pool BOUNDARY event for an address, as served by
|
|
730
|
+
* `GET /shielded/address/:addr`. Only boundary facts are exposed — block,
|
|
731
|
+
* asset, amount (unshield), time, tx hash. Note internals (commitment hex,
|
|
732
|
+
* leaf index, nullifier, memo, sender/recipient) are never returned
|
|
733
|
+
* per-address: a public sender→leaf mapping would shrink the shielded pool's
|
|
734
|
+
* anonymity set. Private transfers carry no address and are never included.
|
|
735
|
+
*/
|
|
736
|
+
interface ShieldedAddressEvent {
|
|
737
|
+
/** 'shield' = deposit into the pool by this address; 'unshield' = withdrawal received by it. */
|
|
738
|
+
kind: 'shield' | 'unshield';
|
|
739
|
+
blockNumber: number;
|
|
740
|
+
extrinsicIndex: number | null;
|
|
741
|
+
/** Asset ID as decimal string. */
|
|
742
|
+
assetId: string;
|
|
743
|
+
/**
|
|
744
|
+
* Amount as decimal string (bigint-safe) for unshields.
|
|
745
|
+
* Always null for shields — the shield amount lives in the extrinsic, not the index.
|
|
746
|
+
*/
|
|
747
|
+
amount: string | null;
|
|
748
|
+
timestampMs: number | null;
|
|
749
|
+
/** Blake2-256 hash of the enclosing extrinsic, 0x-prefixed. Null if not decoded. */
|
|
750
|
+
hash: string | null;
|
|
751
|
+
}
|
|
742
752
|
/** A validator node indexed from pallet-validator-set events. */
|
|
743
753
|
interface IndexedValidator {
|
|
744
754
|
account: string;
|
|
@@ -834,18 +844,35 @@ declare class IndexerClient {
|
|
|
834
844
|
* For the current Orbinum testnet/mainnet scale this is the recommended approach.
|
|
835
845
|
*/
|
|
836
846
|
getAllSpentNullifiers(): Promise<Set<string>>;
|
|
847
|
+
/** Server-enforced max items per by-nullifiers / by-commitments request. */
|
|
848
|
+
private static readonly TRANSFER_LOOKUP_CHUNK;
|
|
849
|
+
/**
|
|
850
|
+
* Chunked fetch for the transfer timestamp lookups. The reader silently
|
|
851
|
+
* truncates each request to 50 items, so larger inputs MUST be split or
|
|
852
|
+
* results are silently lost. Responses are merged per extrinsic
|
|
853
|
+
* (`blockNumber:extrinsicIndex`), concatenating the matched arrays, and
|
|
854
|
+
* sorted by block descending.
|
|
855
|
+
*
|
|
856
|
+
* Privacy note: these lookups send the wallet's own note identifiers to
|
|
857
|
+
* the indexer — a bounded, documented linkage tradeoff for timestamp
|
|
858
|
+
* recovery. They are NEVER used for spent-STATUS checks (PIR-A: status
|
|
859
|
+
* comes from the anonymous full-set `/shielded/nullifiers/all` download).
|
|
860
|
+
*/
|
|
861
|
+
private fetchTransfersChunked;
|
|
837
862
|
/**
|
|
838
863
|
* Returns temporal metadata for private transfers that spent any of the given nullifiers.
|
|
839
864
|
* Only blockNumber, extrinsicIndex, timestampMs, and hash are returned — no cross-link
|
|
840
865
|
* between inputs and outputs to prevent graph reconstruction.
|
|
841
|
-
*
|
|
866
|
+
* Inputs of any size are transparently chunked into requests of 50 (the server cap)
|
|
867
|
+
* and merged per extrinsic.
|
|
842
868
|
*/
|
|
843
869
|
getTransfersByNullifiers(nullifiers: string[]): Promise<PrivateTransferTimestamp[]>;
|
|
844
870
|
/**
|
|
845
871
|
* Returns temporal metadata for private transfers that produced any of the given commitments.
|
|
846
872
|
* Only blockNumber, extrinsicIndex, timestampMs, and hash are returned — no cross-link
|
|
847
873
|
* between outputs and inputs to prevent graph reconstruction.
|
|
848
|
-
*
|
|
874
|
+
* Inputs of any size are transparently chunked into requests of 50 (the server cap)
|
|
875
|
+
* and merged per extrinsic.
|
|
849
876
|
*/
|
|
850
877
|
getTransfersByCommitments(commitments: string[]): Promise<PrivateTransferTimestamp[]>;
|
|
851
878
|
/** Returns a paginated list of unshield events. */
|
|
@@ -881,11 +908,6 @@ declare class IndexerClient {
|
|
|
881
908
|
}): Promise<PaginatedResult<IndexedBlock>>;
|
|
882
909
|
/** Returns a single block by number or hash, or null if not found. */
|
|
883
910
|
getBlock(numberOrHash: string | number): Promise<IndexedBlock | null>;
|
|
884
|
-
/** Returns a paginated list of shielded commitments initiated by an address. */
|
|
885
|
-
getAddressCommitments(address: string, params?: {
|
|
886
|
-
page?: number;
|
|
887
|
-
limit?: number;
|
|
888
|
-
}): Promise<PaginatedResult<ShieldedCommitment>>;
|
|
889
911
|
/**
|
|
890
912
|
* Returns a paginated list of unshield events where the given address is the recipient.
|
|
891
913
|
* Accepts a 0x-prefixed EVM address or an SS58 Substrate address.
|
|
@@ -895,9 +917,11 @@ declare class IndexerClient {
|
|
|
895
917
|
limit?: number;
|
|
896
918
|
}): Promise<PaginatedResult<Unshield>>;
|
|
897
919
|
/**
|
|
898
|
-
* Returns
|
|
899
|
-
*
|
|
900
|
-
*
|
|
920
|
+
* Returns the shielded-pool BOUNDARY activity for an address: shields it
|
|
921
|
+
* deposited and unshields it received, tagged `kind: 'shield' | 'unshield'`.
|
|
922
|
+
* Only boundary fields are returned (block, asset, amount for unshields,
|
|
923
|
+
* timestamp, tx hash) — note internals are never served per-address, and
|
|
924
|
+
* private transfers carry no address at all (PIR-A).
|
|
901
925
|
*/
|
|
902
926
|
getAddressShieldedActivity(address: string, params?: {
|
|
903
927
|
page?: number;
|
package/dist/index.js
CHANGED
|
@@ -1147,7 +1147,7 @@ var EvmExplorer = class _EvmExplorer {
|
|
|
1147
1147
|
};
|
|
1148
1148
|
|
|
1149
1149
|
// src/indexer/IndexerClient.ts
|
|
1150
|
-
var IndexerClient = class {
|
|
1150
|
+
var IndexerClient = class _IndexerClient {
|
|
1151
1151
|
baseUrl;
|
|
1152
1152
|
timeoutMs;
|
|
1153
1153
|
constructor(config) {
|
|
@@ -1247,37 +1247,82 @@ var IndexerClient = class {
|
|
|
1247
1247
|
return new Set(res.data.map((h) => h.toLowerCase()));
|
|
1248
1248
|
}
|
|
1249
1249
|
// ─── Private transfers ─────────────────────────────────────────────────────
|
|
1250
|
+
/** Server-enforced max items per by-nullifiers / by-commitments request. */
|
|
1251
|
+
static TRANSFER_LOOKUP_CHUNK = 50;
|
|
1252
|
+
/**
|
|
1253
|
+
* Chunked fetch for the transfer timestamp lookups. The reader silently
|
|
1254
|
+
* truncates each request to 50 items, so larger inputs MUST be split or
|
|
1255
|
+
* results are silently lost. Responses are merged per extrinsic
|
|
1256
|
+
* (`blockNumber:extrinsicIndex`), concatenating the matched arrays, and
|
|
1257
|
+
* sorted by block descending.
|
|
1258
|
+
*
|
|
1259
|
+
* Privacy note: these lookups send the wallet's own note identifiers to
|
|
1260
|
+
* the indexer — a bounded, documented linkage tradeoff for timestamp
|
|
1261
|
+
* recovery. They are NEVER used for spent-STATUS checks (PIR-A: status
|
|
1262
|
+
* comes from the anonymous full-set `/shielded/nullifiers/all` download).
|
|
1263
|
+
*/
|
|
1264
|
+
async fetchTransfersChunked(path, param, items, matchedField) {
|
|
1265
|
+
if (items.length === 0) return [];
|
|
1266
|
+
const normalized = items.map((i) => i.toLowerCase());
|
|
1267
|
+
const chunks = [];
|
|
1268
|
+
for (let i = 0; i < normalized.length; i += _IndexerClient.TRANSFER_LOOKUP_CHUNK) {
|
|
1269
|
+
chunks.push(normalized.slice(i, i + _IndexerClient.TRANSFER_LOOKUP_CHUNK));
|
|
1270
|
+
}
|
|
1271
|
+
const responses = await Promise.all(
|
|
1272
|
+
chunks.map((chunk) => {
|
|
1273
|
+
const qs = this.buildQuery({ [param]: chunk.join(",") });
|
|
1274
|
+
return this.get(
|
|
1275
|
+
`${path}${qs}`
|
|
1276
|
+
);
|
|
1277
|
+
})
|
|
1278
|
+
);
|
|
1279
|
+
const byExtrinsic = /* @__PURE__ */ new Map();
|
|
1280
|
+
for (const res of responses) {
|
|
1281
|
+
for (const transfer of res.data) {
|
|
1282
|
+
const key = `${transfer.blockNumber}:${transfer.extrinsicIndex ?? "null"}`;
|
|
1283
|
+
const existing = byExtrinsic.get(key);
|
|
1284
|
+
if (!existing) {
|
|
1285
|
+
byExtrinsic.set(key, transfer);
|
|
1286
|
+
continue;
|
|
1287
|
+
}
|
|
1288
|
+
const merged = /* @__PURE__ */ new Set([
|
|
1289
|
+
...existing[matchedField] ?? [],
|
|
1290
|
+
...transfer[matchedField] ?? []
|
|
1291
|
+
]);
|
|
1292
|
+
existing[matchedField] = [...merged];
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
return [...byExtrinsic.values()].sort((a, b) => b.blockNumber - a.blockNumber);
|
|
1296
|
+
}
|
|
1250
1297
|
/**
|
|
1251
1298
|
* Returns temporal metadata for private transfers that spent any of the given nullifiers.
|
|
1252
1299
|
* Only blockNumber, extrinsicIndex, timestampMs, and hash are returned — no cross-link
|
|
1253
1300
|
* between inputs and outputs to prevent graph reconstruction.
|
|
1254
|
-
*
|
|
1301
|
+
* Inputs of any size are transparently chunked into requests of 50 (the server cap)
|
|
1302
|
+
* and merged per extrinsic.
|
|
1255
1303
|
*/
|
|
1256
1304
|
async getTransfersByNullifiers(nullifiers) {
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
nullifiers
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
`/shielded/transfers/by-nullifiers${qs}`
|
|
1305
|
+
return this.fetchTransfersChunked(
|
|
1306
|
+
"/shielded/transfers/by-nullifiers",
|
|
1307
|
+
"nullifiers",
|
|
1308
|
+
nullifiers,
|
|
1309
|
+
"matchedNullifiers"
|
|
1263
1310
|
);
|
|
1264
|
-
return res.data;
|
|
1265
1311
|
}
|
|
1266
1312
|
/**
|
|
1267
1313
|
* Returns temporal metadata for private transfers that produced any of the given commitments.
|
|
1268
1314
|
* Only blockNumber, extrinsicIndex, timestampMs, and hash are returned — no cross-link
|
|
1269
1315
|
* between outputs and inputs to prevent graph reconstruction.
|
|
1270
|
-
*
|
|
1316
|
+
* Inputs of any size are transparently chunked into requests of 50 (the server cap)
|
|
1317
|
+
* and merged per extrinsic.
|
|
1271
1318
|
*/
|
|
1272
1319
|
async getTransfersByCommitments(commitments) {
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
commitments
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
`/shielded/transfers/by-commitments${qs}`
|
|
1320
|
+
return this.fetchTransfersChunked(
|
|
1321
|
+
"/shielded/transfers/by-commitments",
|
|
1322
|
+
"commitments",
|
|
1323
|
+
commitments,
|
|
1324
|
+
"matchedCommitments"
|
|
1279
1325
|
);
|
|
1280
|
-
return res.data;
|
|
1281
1326
|
}
|
|
1282
1327
|
// ─── Unshields ─────────────────────────────────────────────────────────────
|
|
1283
1328
|
/** Returns a paginated list of unshield events. */
|
|
@@ -1329,14 +1374,7 @@ var IndexerClient = class {
|
|
|
1329
1374
|
async getBlock(numberOrHash) {
|
|
1330
1375
|
return this.getOrNull(`/blocks/${encodeURIComponent(String(numberOrHash))}`);
|
|
1331
1376
|
}
|
|
1332
|
-
// ─── Address
|
|
1333
|
-
/** Returns a paginated list of shielded commitments initiated by an address. */
|
|
1334
|
-
async getAddressCommitments(address, params) {
|
|
1335
|
-
const qs = this.buildQuery({ page: params?.page, limit: params?.limit });
|
|
1336
|
-
return this.get(
|
|
1337
|
-
`/address/${encodeURIComponent(address.toLowerCase())}/shielded${qs}`
|
|
1338
|
-
);
|
|
1339
|
-
}
|
|
1377
|
+
// ─── Address-scoped shielded activity ─────────────────────────────────────
|
|
1340
1378
|
/**
|
|
1341
1379
|
* Returns a paginated list of unshield events where the given address is the recipient.
|
|
1342
1380
|
* Accepts a 0x-prefixed EVM address or an SS58 Substrate address.
|
|
@@ -1348,9 +1386,11 @@ var IndexerClient = class {
|
|
|
1348
1386
|
);
|
|
1349
1387
|
}
|
|
1350
1388
|
/**
|
|
1351
|
-
* Returns
|
|
1352
|
-
*
|
|
1353
|
-
*
|
|
1389
|
+
* Returns the shielded-pool BOUNDARY activity for an address: shields it
|
|
1390
|
+
* deposited and unshields it received, tagged `kind: 'shield' | 'unshield'`.
|
|
1391
|
+
* Only boundary fields are returned (block, asset, amount for unshields,
|
|
1392
|
+
* timestamp, tx hash) — note internals are never served per-address, and
|
|
1393
|
+
* private transfers carry no address at all (PIR-A).
|
|
1354
1394
|
*/
|
|
1355
1395
|
async getAddressShieldedActivity(address, params) {
|
|
1356
1396
|
const qs = this.buildQuery({ page: params?.page, limit: params?.limit });
|
package/dist/index.mjs
CHANGED
|
@@ -1020,7 +1020,7 @@ var EvmExplorer = class _EvmExplorer {
|
|
|
1020
1020
|
};
|
|
1021
1021
|
|
|
1022
1022
|
// src/indexer/IndexerClient.ts
|
|
1023
|
-
var IndexerClient = class {
|
|
1023
|
+
var IndexerClient = class _IndexerClient {
|
|
1024
1024
|
baseUrl;
|
|
1025
1025
|
timeoutMs;
|
|
1026
1026
|
constructor(config) {
|
|
@@ -1120,37 +1120,82 @@ var IndexerClient = class {
|
|
|
1120
1120
|
return new Set(res.data.map((h) => h.toLowerCase()));
|
|
1121
1121
|
}
|
|
1122
1122
|
// ─── Private transfers ─────────────────────────────────────────────────────
|
|
1123
|
+
/** Server-enforced max items per by-nullifiers / by-commitments request. */
|
|
1124
|
+
static TRANSFER_LOOKUP_CHUNK = 50;
|
|
1125
|
+
/**
|
|
1126
|
+
* Chunked fetch for the transfer timestamp lookups. The reader silently
|
|
1127
|
+
* truncates each request to 50 items, so larger inputs MUST be split or
|
|
1128
|
+
* results are silently lost. Responses are merged per extrinsic
|
|
1129
|
+
* (`blockNumber:extrinsicIndex`), concatenating the matched arrays, and
|
|
1130
|
+
* sorted by block descending.
|
|
1131
|
+
*
|
|
1132
|
+
* Privacy note: these lookups send the wallet's own note identifiers to
|
|
1133
|
+
* the indexer — a bounded, documented linkage tradeoff for timestamp
|
|
1134
|
+
* recovery. They are NEVER used for spent-STATUS checks (PIR-A: status
|
|
1135
|
+
* comes from the anonymous full-set `/shielded/nullifiers/all` download).
|
|
1136
|
+
*/
|
|
1137
|
+
async fetchTransfersChunked(path, param, items, matchedField) {
|
|
1138
|
+
if (items.length === 0) return [];
|
|
1139
|
+
const normalized = items.map((i) => i.toLowerCase());
|
|
1140
|
+
const chunks = [];
|
|
1141
|
+
for (let i = 0; i < normalized.length; i += _IndexerClient.TRANSFER_LOOKUP_CHUNK) {
|
|
1142
|
+
chunks.push(normalized.slice(i, i + _IndexerClient.TRANSFER_LOOKUP_CHUNK));
|
|
1143
|
+
}
|
|
1144
|
+
const responses = await Promise.all(
|
|
1145
|
+
chunks.map((chunk) => {
|
|
1146
|
+
const qs = this.buildQuery({ [param]: chunk.join(",") });
|
|
1147
|
+
return this.get(
|
|
1148
|
+
`${path}${qs}`
|
|
1149
|
+
);
|
|
1150
|
+
})
|
|
1151
|
+
);
|
|
1152
|
+
const byExtrinsic = /* @__PURE__ */ new Map();
|
|
1153
|
+
for (const res of responses) {
|
|
1154
|
+
for (const transfer of res.data) {
|
|
1155
|
+
const key = `${transfer.blockNumber}:${transfer.extrinsicIndex ?? "null"}`;
|
|
1156
|
+
const existing = byExtrinsic.get(key);
|
|
1157
|
+
if (!existing) {
|
|
1158
|
+
byExtrinsic.set(key, transfer);
|
|
1159
|
+
continue;
|
|
1160
|
+
}
|
|
1161
|
+
const merged = /* @__PURE__ */ new Set([
|
|
1162
|
+
...existing[matchedField] ?? [],
|
|
1163
|
+
...transfer[matchedField] ?? []
|
|
1164
|
+
]);
|
|
1165
|
+
existing[matchedField] = [...merged];
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
return [...byExtrinsic.values()].sort((a, b) => b.blockNumber - a.blockNumber);
|
|
1169
|
+
}
|
|
1123
1170
|
/**
|
|
1124
1171
|
* Returns temporal metadata for private transfers that spent any of the given nullifiers.
|
|
1125
1172
|
* Only blockNumber, extrinsicIndex, timestampMs, and hash are returned — no cross-link
|
|
1126
1173
|
* between inputs and outputs to prevent graph reconstruction.
|
|
1127
|
-
*
|
|
1174
|
+
* Inputs of any size are transparently chunked into requests of 50 (the server cap)
|
|
1175
|
+
* and merged per extrinsic.
|
|
1128
1176
|
*/
|
|
1129
1177
|
async getTransfersByNullifiers(nullifiers) {
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
nullifiers
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
`/shielded/transfers/by-nullifiers${qs}`
|
|
1178
|
+
return this.fetchTransfersChunked(
|
|
1179
|
+
"/shielded/transfers/by-nullifiers",
|
|
1180
|
+
"nullifiers",
|
|
1181
|
+
nullifiers,
|
|
1182
|
+
"matchedNullifiers"
|
|
1136
1183
|
);
|
|
1137
|
-
return res.data;
|
|
1138
1184
|
}
|
|
1139
1185
|
/**
|
|
1140
1186
|
* Returns temporal metadata for private transfers that produced any of the given commitments.
|
|
1141
1187
|
* Only blockNumber, extrinsicIndex, timestampMs, and hash are returned — no cross-link
|
|
1142
1188
|
* between outputs and inputs to prevent graph reconstruction.
|
|
1143
|
-
*
|
|
1189
|
+
* Inputs of any size are transparently chunked into requests of 50 (the server cap)
|
|
1190
|
+
* and merged per extrinsic.
|
|
1144
1191
|
*/
|
|
1145
1192
|
async getTransfersByCommitments(commitments) {
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
commitments
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
`/shielded/transfers/by-commitments${qs}`
|
|
1193
|
+
return this.fetchTransfersChunked(
|
|
1194
|
+
"/shielded/transfers/by-commitments",
|
|
1195
|
+
"commitments",
|
|
1196
|
+
commitments,
|
|
1197
|
+
"matchedCommitments"
|
|
1152
1198
|
);
|
|
1153
|
-
return res.data;
|
|
1154
1199
|
}
|
|
1155
1200
|
// ─── Unshields ─────────────────────────────────────────────────────────────
|
|
1156
1201
|
/** Returns a paginated list of unshield events. */
|
|
@@ -1202,14 +1247,7 @@ var IndexerClient = class {
|
|
|
1202
1247
|
async getBlock(numberOrHash) {
|
|
1203
1248
|
return this.getOrNull(`/blocks/${encodeURIComponent(String(numberOrHash))}`);
|
|
1204
1249
|
}
|
|
1205
|
-
// ─── Address
|
|
1206
|
-
/** Returns a paginated list of shielded commitments initiated by an address. */
|
|
1207
|
-
async getAddressCommitments(address, params) {
|
|
1208
|
-
const qs = this.buildQuery({ page: params?.page, limit: params?.limit });
|
|
1209
|
-
return this.get(
|
|
1210
|
-
`/address/${encodeURIComponent(address.toLowerCase())}/shielded${qs}`
|
|
1211
|
-
);
|
|
1212
|
-
}
|
|
1250
|
+
// ─── Address-scoped shielded activity ─────────────────────────────────────
|
|
1213
1251
|
/**
|
|
1214
1252
|
* Returns a paginated list of unshield events where the given address is the recipient.
|
|
1215
1253
|
* Accepts a 0x-prefixed EVM address or an SS58 Substrate address.
|
|
@@ -1221,9 +1259,11 @@ var IndexerClient = class {
|
|
|
1221
1259
|
);
|
|
1222
1260
|
}
|
|
1223
1261
|
/**
|
|
1224
|
-
* Returns
|
|
1225
|
-
*
|
|
1226
|
-
*
|
|
1262
|
+
* Returns the shielded-pool BOUNDARY activity for an address: shields it
|
|
1263
|
+
* deposited and unshields it received, tagged `kind: 'shield' | 'unshield'`.
|
|
1264
|
+
* Only boundary fields are returned (block, asset, amount for unshields,
|
|
1265
|
+
* timestamp, tx hash) — note internals are never served per-address, and
|
|
1266
|
+
* private transfers carry no address at all (PIR-A).
|
|
1227
1267
|
*/
|
|
1228
1268
|
async getAddressShieldedActivity(address, params) {
|
|
1229
1269
|
const qs = this.buildQuery({ page: params?.page, limit: params?.limit });
|