@cofhe/sdk 1.1.0-alpha.3 → 1.1.0-alpha.5

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.
@@ -224,6 +224,12 @@ type CofheConfig = {
224
224
  supportedChains: CofheChain[];
225
225
  /** Default acp expiration in seconds, default is 30 days */
226
226
  defaultACPExpiration: number;
227
+ /**
228
+ * How many decrypts (`decryptForView` / `decryptForTx`) this client sends to the threshold
229
+ * network at a time; the rest wait their turn. A list of values decrypted at once stays within
230
+ * it without a limiter of its own. `Infinity` disables the cap. Default: 8
231
+ */
232
+ decryptConcurrency: number;
227
233
  /**
228
234
  * Storage scheme for the fetched fhe keys
229
235
  * FHE keys are large, and caching prevents re-fetching them on each encryptInputs call
@@ -337,6 +343,7 @@ declare const CofheConfigSchema: z.ZodObject<{
337
343
  environment: "MOCK" | "TESTNET" | "MAINNET";
338
344
  }>>;
339
345
  defaultACPExpiration: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
346
+ decryptConcurrency: z.ZodDefault<z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodLiteral<number>]>>>;
340
347
  fheKeyStorage: z.ZodDefault<z.ZodUnion<[z.ZodObject<{
341
348
  getItem: z.ZodCustom<(name: string) => Promise<any>, (name: string) => Promise<any>>;
342
349
  setItem: z.ZodCustom<(name: string, value: any) => Promise<void>, (name: string, value: any) => Promise<void>>;
@@ -432,6 +439,9 @@ declare abstract class BaseBuilder {
432
439
  };
433
440
  }
434
441
 
442
+ /** Runs a threshold-network call when a slot is free; see `createDecryptLimiter`. */
443
+ type DecryptLimiter = <T>(task: () => Promise<T>, operationLabel: string, signal?: AbortSignal) => Promise<T>;
444
+
435
445
  /**
436
446
  * API
437
447
  *
@@ -457,6 +467,8 @@ type DecryptForViewBuilderParams<U extends FheTypes> = BaseBuilderParams & {
457
467
  utype: U;
458
468
  acpHash?: string;
459
469
  acp?: ACP;
470
+ /** The client's decrypt cap; a builder made without one runs unlimited. */
471
+ limit?: DecryptLimiter;
460
472
  };
461
473
  declare class DecryptForViewBuilder<U extends FheTypes> extends BaseBuilder {
462
474
  private ctHash;
@@ -466,6 +478,8 @@ declare class DecryptForViewBuilder<U extends FheTypes> extends BaseBuilder {
466
478
  private pollCallback?;
467
479
  private retry404TimeoutMs;
468
480
  private timeoutMs?;
481
+ private signal?;
482
+ private limit;
469
483
  constructor(params: DecryptForViewBuilderParams<U>);
470
484
  /**
471
485
  * @param chainId - Chain to decrypt values from. Used to fetch the threshold network URL and use the correct acp.
@@ -507,6 +521,12 @@ declare class DecryptForViewBuilder<U extends FheTypes> extends BaseBuilder {
507
521
  * processing on the threshold network is not cancelled.
508
522
  */
509
523
  setTimeout(timeoutMs: number): DecryptForViewBuilder<U>;
524
+ /**
525
+ * Stops the decrypt when `signal` fires: the pending request is aborted, no further attempt is
526
+ * sent, and `execute()` rejects with `Aborted`. A request already processing on the threshold
527
+ * network is not cancelled.
528
+ */
529
+ setSignal(signal: AbortSignal): DecryptForViewBuilder<U>;
510
530
  /**
511
531
  * Select "use acp" mode (optional).
512
532
  *
@@ -589,6 +609,8 @@ declare class DecryptForViewBuilder<U extends FheTypes> extends BaseBuilder {
589
609
 
590
610
  type DecryptForTxBuilderParams = BaseBuilderParams & {
591
611
  ctHash: bigint | string;
612
+ /** The client's decrypt cap; a builder made without one runs unlimited. */
613
+ limit?: DecryptLimiter;
592
614
  };
593
615
  type DecryptForTxResult = {
594
616
  ctHash: bigint | string;
@@ -611,6 +633,8 @@ declare class DecryptForTxBuilder extends BaseBuilder {
611
633
  private pollCallback?;
612
634
  private retry404TimeoutMs;
613
635
  private timeoutMs?;
636
+ private signal?;
637
+ private limit;
614
638
  constructor(params: DecryptForTxBuilderParams);
615
639
  /**
616
640
  * @param chainId - Chain to decrypt values from. Used to fetch the threshold network URL and use the correct acp.
@@ -657,6 +681,13 @@ declare class DecryptForTxBuilder extends BaseBuilder {
657
681
  */
658
682
  setTimeout(this: DecryptForTxBuilderUnset, timeoutMs: number): DecryptForTxBuilderUnset;
659
683
  setTimeout(this: DecryptForTxBuilderSelected, timeoutMs: number): DecryptForTxBuilderSelected;
684
+ /**
685
+ * Stops the decrypt when `signal` fires: the pending request is aborted, no further attempt is
686
+ * sent, and `execute()` rejects with `Aborted`. A request already processing on the threshold
687
+ * network is not cancelled.
688
+ */
689
+ setSignal(this: DecryptForTxBuilderUnset, signal: AbortSignal): DecryptForTxBuilderUnset;
690
+ setSignal(this: DecryptForTxBuilderSelected, signal: AbortSignal): DecryptForTxBuilderSelected;
660
691
  /**
661
692
  * Select "use acp" mode.
662
693
  *
@@ -224,6 +224,12 @@ type CofheConfig = {
224
224
  supportedChains: CofheChain[];
225
225
  /** Default acp expiration in seconds, default is 30 days */
226
226
  defaultACPExpiration: number;
227
+ /**
228
+ * How many decrypts (`decryptForView` / `decryptForTx`) this client sends to the threshold
229
+ * network at a time; the rest wait their turn. A list of values decrypted at once stays within
230
+ * it without a limiter of its own. `Infinity` disables the cap. Default: 8
231
+ */
232
+ decryptConcurrency: number;
227
233
  /**
228
234
  * Storage scheme for the fetched fhe keys
229
235
  * FHE keys are large, and caching prevents re-fetching them on each encryptInputs call
@@ -337,6 +343,7 @@ declare const CofheConfigSchema: z.ZodObject<{
337
343
  environment: "MOCK" | "TESTNET" | "MAINNET";
338
344
  }>>;
339
345
  defaultACPExpiration: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
346
+ decryptConcurrency: z.ZodDefault<z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodLiteral<number>]>>>;
340
347
  fheKeyStorage: z.ZodDefault<z.ZodUnion<[z.ZodObject<{
341
348
  getItem: z.ZodCustom<(name: string) => Promise<any>, (name: string) => Promise<any>>;
342
349
  setItem: z.ZodCustom<(name: string, value: any) => Promise<void>, (name: string, value: any) => Promise<void>>;
@@ -432,6 +439,9 @@ declare abstract class BaseBuilder {
432
439
  };
433
440
  }
434
441
 
442
+ /** Runs a threshold-network call when a slot is free; see `createDecryptLimiter`. */
443
+ type DecryptLimiter = <T>(task: () => Promise<T>, operationLabel: string, signal?: AbortSignal) => Promise<T>;
444
+
435
445
  /**
436
446
  * API
437
447
  *
@@ -457,6 +467,8 @@ type DecryptForViewBuilderParams<U extends FheTypes> = BaseBuilderParams & {
457
467
  utype: U;
458
468
  acpHash?: string;
459
469
  acp?: ACP;
470
+ /** The client's decrypt cap; a builder made without one runs unlimited. */
471
+ limit?: DecryptLimiter;
460
472
  };
461
473
  declare class DecryptForViewBuilder<U extends FheTypes> extends BaseBuilder {
462
474
  private ctHash;
@@ -466,6 +478,8 @@ declare class DecryptForViewBuilder<U extends FheTypes> extends BaseBuilder {
466
478
  private pollCallback?;
467
479
  private retry404TimeoutMs;
468
480
  private timeoutMs?;
481
+ private signal?;
482
+ private limit;
469
483
  constructor(params: DecryptForViewBuilderParams<U>);
470
484
  /**
471
485
  * @param chainId - Chain to decrypt values from. Used to fetch the threshold network URL and use the correct acp.
@@ -507,6 +521,12 @@ declare class DecryptForViewBuilder<U extends FheTypes> extends BaseBuilder {
507
521
  * processing on the threshold network is not cancelled.
508
522
  */
509
523
  setTimeout(timeoutMs: number): DecryptForViewBuilder<U>;
524
+ /**
525
+ * Stops the decrypt when `signal` fires: the pending request is aborted, no further attempt is
526
+ * sent, and `execute()` rejects with `Aborted`. A request already processing on the threshold
527
+ * network is not cancelled.
528
+ */
529
+ setSignal(signal: AbortSignal): DecryptForViewBuilder<U>;
510
530
  /**
511
531
  * Select "use acp" mode (optional).
512
532
  *
@@ -589,6 +609,8 @@ declare class DecryptForViewBuilder<U extends FheTypes> extends BaseBuilder {
589
609
 
590
610
  type DecryptForTxBuilderParams = BaseBuilderParams & {
591
611
  ctHash: bigint | string;
612
+ /** The client's decrypt cap; a builder made without one runs unlimited. */
613
+ limit?: DecryptLimiter;
592
614
  };
593
615
  type DecryptForTxResult = {
594
616
  ctHash: bigint | string;
@@ -611,6 +633,8 @@ declare class DecryptForTxBuilder extends BaseBuilder {
611
633
  private pollCallback?;
612
634
  private retry404TimeoutMs;
613
635
  private timeoutMs?;
636
+ private signal?;
637
+ private limit;
614
638
  constructor(params: DecryptForTxBuilderParams);
615
639
  /**
616
640
  * @param chainId - Chain to decrypt values from. Used to fetch the threshold network URL and use the correct acp.
@@ -657,6 +681,13 @@ declare class DecryptForTxBuilder extends BaseBuilder {
657
681
  */
658
682
  setTimeout(this: DecryptForTxBuilderUnset, timeoutMs: number): DecryptForTxBuilderUnset;
659
683
  setTimeout(this: DecryptForTxBuilderSelected, timeoutMs: number): DecryptForTxBuilderSelected;
684
+ /**
685
+ * Stops the decrypt when `signal` fires: the pending request is aborted, no further attempt is
686
+ * sent, and `execute()` rejects with `Aborted`. A request already processing on the threshold
687
+ * network is not cancelled.
688
+ */
689
+ setSignal(this: DecryptForTxBuilderUnset, signal: AbortSignal): DecryptForTxBuilderUnset;
690
+ setSignal(this: DecryptForTxBuilderSelected, signal: AbortSignal): DecryptForTxBuilderSelected;
660
691
  /**
661
692
  * Select "use acp" mode.
662
693
  *
package/dist/core.cjs CHANGED
@@ -107,6 +107,7 @@ var CofheErrorCode = /* @__PURE__ */ ((CofheErrorCode2) => {
107
107
  CofheErrorCode2["ACPVerifierTimeout"] = "ACP_VERIFIER_TIMEOUT";
108
108
  CofheErrorCode2["ACPRequired"] = "ACP_REQUIRED";
109
109
  CofheErrorCode2["SealFailed"] = "SEAL_FAILED";
110
+ CofheErrorCode2["Aborted"] = "ABORTED";
110
111
  return CofheErrorCode2;
111
112
  })(CofheErrorCode || {});
112
113
  var CofheError = class _CofheError extends Error {
@@ -2537,6 +2538,8 @@ var CofheConfigSchema = zod.z.object({
2537
2538
  supportedChains: zod.z.array(zod.z.custom()),
2538
2539
  /** Default acp expiration in seconds, default is 30 days */
2539
2540
  defaultACPExpiration: zod.z.number().optional().default(60 * 60 * 24 * 30),
2541
+ /** Decrypts sent to the threshold network at a time per client; `Infinity` disables the cap (default 8) */
2542
+ decryptConcurrency: zod.z.union([zod.z.number().min(1), zod.z.literal(Infinity)]).optional().default(8),
2540
2543
  /** Storage method for fhe keys (defaults to indexedDB on web, filesystem on node) */
2541
2544
  fheKeyStorage: zod.z.object({
2542
2545
  getItem: zod.z.custom((val) => typeof val === "function", {
@@ -4089,6 +4092,32 @@ function throwIfSubmitRetryTimedOut(params) {
4089
4092
  });
4090
4093
  }
4091
4094
  }
4095
+ function decryptAbortedError(operationLabel, signal) {
4096
+ return new CofheError({
4097
+ code: "ABORTED" /* Aborted */,
4098
+ message: `${operationLabel} aborted by the caller`,
4099
+ cause: signal.reason instanceof Error ? signal.reason : void 0
4100
+ });
4101
+ }
4102
+ function throwIfAborted(signal, operationLabel) {
4103
+ if (signal?.aborted)
4104
+ throw decryptAbortedError(operationLabel, signal);
4105
+ }
4106
+ function sleepUnlessAborted(ms, signal, operationLabel) {
4107
+ return new Promise((resolve, reject) => {
4108
+ if (signal?.aborted)
4109
+ return reject(decryptAbortedError(operationLabel, signal));
4110
+ const onAbort = () => {
4111
+ clearTimeout(timer);
4112
+ reject(decryptAbortedError(operationLabel, signal));
4113
+ };
4114
+ const timer = setTimeout(() => {
4115
+ signal?.removeEventListener("abort", onAbort);
4116
+ resolve();
4117
+ }, ms);
4118
+ signal?.addEventListener("abort", onAbort, { once: true });
4119
+ });
4120
+ }
4092
4121
  function normalizeTnSignature(signature) {
4093
4122
  if (typeof signature !== "string") {
4094
4123
  throw new CofheError({
@@ -4206,7 +4235,7 @@ function parseCompletedSealOutputResponse(params) {
4206
4235
  }
4207
4236
  return convertSealedData(sealed);
4208
4237
  }
4209
- async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, acp, overallStartTime, retry404TimeoutMs, timeoutMs, onPoll) {
4238
+ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, acp, overallStartTime, retry404TimeoutMs, timeoutMs, onPoll, signal) {
4210
4239
  const body = {
4211
4240
  ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
4212
4241
  host_chain_id: chainId,
@@ -4215,6 +4244,7 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, acp
4215
4244
  let attemptIndex = 0;
4216
4245
  let last404ApiErrorMessage;
4217
4246
  for (; ; ) {
4247
+ throwIfAborted(signal, "sealOutput");
4218
4248
  let response;
4219
4249
  try {
4220
4250
  response = await cofheFetch(
@@ -4225,10 +4255,12 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, acp
4225
4255
  headers: {
4226
4256
  "Content-Type": "application/json"
4227
4257
  },
4228
- body: JSON.stringify(body)
4258
+ body: JSON.stringify(body),
4259
+ signal
4229
4260
  }
4230
4261
  );
4231
4262
  } catch (e) {
4263
+ throwIfAborted(signal, "sealOutput");
4232
4264
  throw new CofheError({
4233
4265
  code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
4234
4266
  message: `sealOutput request failed`,
@@ -4323,13 +4355,14 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, acp
4323
4355
  intervalMs: SUBMIT_RETRY_INTERVAL_MS,
4324
4356
  timeoutMs
4325
4357
  });
4326
- await new Promise((resolve) => setTimeout(resolve, SUBMIT_RETRY_INTERVAL_MS));
4358
+ await sleepUnlessAborted(SUBMIT_RETRY_INTERVAL_MS, signal, "sealOutput");
4327
4359
  attemptIndex += 1;
4328
4360
  }
4329
4361
  }
4330
- async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStartTime, timeoutMs, onPoll) {
4362
+ async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStartTime, timeoutMs, onPoll, signal) {
4331
4363
  let attemptIndex = 0;
4332
4364
  while (true) {
4365
+ throwIfAborted(signal, "sealOutput");
4333
4366
  const elapsedMs = Date.now() - overallStartTime;
4334
4367
  const intervalMs = computeMinuteRampPollIntervalMs(elapsedMs, {
4335
4368
  minIntervalMs: POLL_INTERVAL_MS,
@@ -4364,7 +4397,8 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStart
4364
4397
  method: "GET",
4365
4398
  headers: {
4366
4399
  "Content-Type": "application/json"
4367
- }
4400
+ },
4401
+ signal
4368
4402
  }
4369
4403
  );
4370
4404
  } catch (e) {
@@ -4425,7 +4459,7 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStart
4425
4459
  requestId
4426
4460
  });
4427
4461
  }
4428
- await new Promise((resolve) => setTimeout(resolve, intervalMs));
4462
+ await sleepUnlessAborted(intervalMs, signal, "sealOutput");
4429
4463
  attemptIndex += 1;
4430
4464
  }
4431
4465
  throw new CofheError({
@@ -4438,7 +4472,7 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStart
4438
4472
  });
4439
4473
  }
4440
4474
  async function tnSealOutputV2(params) {
4441
- const { thresholdNetworkUrl, ctHash, chainId, acp, retry404TimeoutMs, onPoll } = params;
4475
+ const { thresholdNetworkUrl, ctHash, chainId, acp, retry404TimeoutMs, onPoll, signal } = params;
4442
4476
  const timeoutMs = params.timeoutMs ?? DEFAULT_DECRYPT_TIMEOUT_MS;
4443
4477
  const normalized404RetryTimeoutMs = normalize404RetryTimeoutMs({
4444
4478
  timeoutMs: retry404TimeoutMs,
@@ -4454,12 +4488,20 @@ async function tnSealOutputV2(params) {
4454
4488
  overallStartTime,
4455
4489
  normalized404RetryTimeoutMs,
4456
4490
  timeoutMs,
4457
- onPoll
4491
+ onPoll,
4492
+ signal
4458
4493
  );
4459
4494
  if (submitResult.kind === "completed") {
4460
4495
  return submitResult.sealed;
4461
4496
  }
4462
- return await pollSealOutputStatus(thresholdNetworkUrl, submitResult.requestId, overallStartTime, timeoutMs, onPoll);
4497
+ return await pollSealOutputStatus(
4498
+ thresholdNetworkUrl,
4499
+ submitResult.requestId,
4500
+ overallStartTime,
4501
+ timeoutMs,
4502
+ onPoll,
4503
+ signal
4504
+ );
4463
4505
  }
4464
4506
 
4465
4507
  // core/decrypt/decryptForViewBuilder.ts
@@ -4472,6 +4514,8 @@ var DecryptForViewBuilder = class extends BaseBuilder {
4472
4514
  pollCallback;
4473
4515
  retry404TimeoutMs = DEFAULT_404_RETRY_TIMEOUT_MS2;
4474
4516
  timeoutMs;
4517
+ signal;
4518
+ limit;
4475
4519
  constructor(params) {
4476
4520
  super({
4477
4521
  config: params.config,
@@ -4485,6 +4529,7 @@ var DecryptForViewBuilder = class extends BaseBuilder {
4485
4529
  this.utype = params.utype;
4486
4530
  this.acpHash = params.acpHash;
4487
4531
  this.acp = params.acp;
4532
+ this.limit = params.limit ?? ((task) => task());
4488
4533
  }
4489
4534
  /**
4490
4535
  * @param chainId - Chain to decrypt values from. Used to fetch the threshold network URL and use the correct acp.
@@ -4555,6 +4600,15 @@ var DecryptForViewBuilder = class extends BaseBuilder {
4555
4600
  this.timeoutMs = timeoutMs;
4556
4601
  return this;
4557
4602
  }
4603
+ /**
4604
+ * Stops the decrypt when `signal` fires: the pending request is aborted, no further attempt is
4605
+ * sent, and `execute()` rejects with `Aborted`. A request already processing on the threshold
4606
+ * network is not cancelled.
4607
+ */
4608
+ setSignal(signal) {
4609
+ this.signal = signal;
4610
+ return this;
4611
+ }
4558
4612
  withACP(acpOrACPHash) {
4559
4613
  if (typeof acpOrACPHash === "string") {
4560
4614
  this.acpHash = acpOrACPHash;
@@ -4678,15 +4732,20 @@ var DecryptForViewBuilder = class extends BaseBuilder {
4678
4732
  this.assertPublicClient();
4679
4733
  const thresholdNetworkUrl = await this.getThresholdNetworkUrl();
4680
4734
  const wireAcp = ACPUtils.getPublic(acp, true);
4681
- const sealed = await tnSealOutputV2({
4682
- ctHash: this.ctHash,
4683
- chainId: this.chainId,
4684
- acp: wireAcp,
4685
- thresholdNetworkUrl,
4686
- retry404TimeoutMs: this.retry404TimeoutMs,
4687
- timeoutMs: this.timeoutMs,
4688
- onPoll: this.pollCallback
4689
- });
4735
+ const sealed = await this.limit(
4736
+ () => tnSealOutputV2({
4737
+ ctHash: this.ctHash,
4738
+ chainId: this.chainId,
4739
+ acp: wireAcp,
4740
+ thresholdNetworkUrl,
4741
+ retry404TimeoutMs: this.retry404TimeoutMs,
4742
+ timeoutMs: this.timeoutMs,
4743
+ onPoll: this.pollCallback,
4744
+ signal: this.signal
4745
+ }),
4746
+ "sealOutput",
4747
+ this.signal
4748
+ );
4690
4749
  return ACPUtils.unseal(acp, sealed);
4691
4750
  }
4692
4751
  /**
@@ -4903,7 +4962,7 @@ function assertDecryptStatusResponseV2(value) {
4903
4962
  }
4904
4963
  return value;
4905
4964
  }
4906
- async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, acp, overallStartTime, retry404TimeoutMs, timeoutMs, onPoll) {
4965
+ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, acp, overallStartTime, retry404TimeoutMs, timeoutMs, onPoll, signal) {
4907
4966
  const body = {
4908
4967
  ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
4909
4968
  host_chain_id: chainId
@@ -4914,6 +4973,7 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, acp,
4914
4973
  let attemptIndex = 0;
4915
4974
  let last404ApiErrorMessage;
4916
4975
  for (; ; ) {
4976
+ throwIfAborted(signal, "decrypt");
4917
4977
  let response;
4918
4978
  try {
4919
4979
  response = await cofheFetch(
@@ -4924,10 +4984,12 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, acp,
4924
4984
  headers: {
4925
4985
  "Content-Type": "application/json"
4926
4986
  },
4927
- body: JSON.stringify(body)
4987
+ body: JSON.stringify(body),
4988
+ signal
4928
4989
  }
4929
4990
  );
4930
4991
  } catch (e) {
4992
+ throwIfAborted(signal, "decrypt");
4931
4993
  throw new CofheError({
4932
4994
  code: "DECRYPT_FAILED" /* DecryptFailed */,
4933
4995
  message: `decrypt request failed`,
@@ -5024,13 +5086,14 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, acp,
5024
5086
  intervalMs: SUBMIT_RETRY_INTERVAL_MS2,
5025
5087
  timeoutMs
5026
5088
  });
5027
- await new Promise((resolve) => setTimeout(resolve, SUBMIT_RETRY_INTERVAL_MS2));
5089
+ await sleepUnlessAborted(SUBMIT_RETRY_INTERVAL_MS2, signal, "decrypt");
5028
5090
  attemptIndex += 1;
5029
5091
  }
5030
5092
  }
5031
- async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartTime, timeoutMs, onPoll) {
5093
+ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartTime, timeoutMs, onPoll, signal) {
5032
5094
  let attemptIndex = 0;
5033
5095
  while (true) {
5096
+ throwIfAborted(signal, "decrypt");
5034
5097
  const elapsedMs = Date.now() - overallStartTime;
5035
5098
  const intervalMs = computeMinuteRampPollIntervalMs(elapsedMs, {
5036
5099
  minIntervalMs: POLL_INTERVAL_MS2,
@@ -5065,7 +5128,8 @@ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartT
5065
5128
  method: "GET",
5066
5129
  headers: {
5067
5130
  "Content-Type": "application/json"
5068
- }
5131
+ },
5132
+ signal
5069
5133
  }
5070
5134
  );
5071
5135
  } catch (e) {
@@ -5127,7 +5191,7 @@ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartT
5127
5191
  requestId
5128
5192
  });
5129
5193
  }
5130
- await new Promise((resolve) => setTimeout(resolve, intervalMs));
5194
+ await sleepUnlessAborted(intervalMs, signal, "decrypt");
5131
5195
  attemptIndex += 1;
5132
5196
  }
5133
5197
  throw new CofheError({
@@ -5140,7 +5204,7 @@ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartT
5140
5204
  });
5141
5205
  }
5142
5206
  async function tnDecryptV2(params) {
5143
- const { thresholdNetworkUrl, ctHash, chainId, acp, retry404TimeoutMs, onPoll } = params;
5207
+ const { thresholdNetworkUrl, ctHash, chainId, acp, retry404TimeoutMs, onPoll, signal } = params;
5144
5208
  const timeoutMs = params.timeoutMs ?? DEFAULT_DECRYPT_TIMEOUT_MS;
5145
5209
  const normalized404RetryTimeoutMs = normalize404RetryTimeoutMs({
5146
5210
  timeoutMs: retry404TimeoutMs,
@@ -5156,12 +5220,20 @@ async function tnDecryptV2(params) {
5156
5220
  overallStartTime,
5157
5221
  normalized404RetryTimeoutMs,
5158
5222
  timeoutMs,
5159
- onPoll
5223
+ onPoll,
5224
+ signal
5160
5225
  );
5161
5226
  if (submitResult.kind === "completed") {
5162
5227
  return submitResult;
5163
5228
  }
5164
- return await pollDecryptStatusV2(thresholdNetworkUrl, submitResult.requestId, overallStartTime, timeoutMs, onPoll);
5229
+ return await pollDecryptStatusV2(
5230
+ thresholdNetworkUrl,
5231
+ submitResult.requestId,
5232
+ overallStartTime,
5233
+ timeoutMs,
5234
+ onPoll,
5235
+ signal
5236
+ );
5165
5237
  }
5166
5238
 
5167
5239
  // core/decrypt/decryptForTxBuilder.ts
@@ -5174,6 +5246,8 @@ var DecryptForTxBuilder = class extends BaseBuilder {
5174
5246
  pollCallback;
5175
5247
  retry404TimeoutMs = DEFAULT_404_RETRY_TIMEOUT_MS3;
5176
5248
  timeoutMs;
5249
+ signal;
5250
+ limit;
5177
5251
  constructor(params) {
5178
5252
  super({
5179
5253
  config: params.config,
@@ -5184,6 +5258,7 @@ var DecryptForTxBuilder = class extends BaseBuilder {
5184
5258
  requireConnected: params.requireConnected
5185
5259
  });
5186
5260
  this.ctHash = params.ctHash;
5261
+ this.limit = params.limit ?? ((task) => task());
5187
5262
  }
5188
5263
  setChainId(chainId) {
5189
5264
  this.chainId = chainId;
@@ -5221,6 +5296,10 @@ var DecryptForTxBuilder = class extends BaseBuilder {
5221
5296
  this.timeoutMs = timeoutMs;
5222
5297
  return this;
5223
5298
  }
5299
+ setSignal(signal) {
5300
+ this.signal = signal;
5301
+ return this;
5302
+ }
5224
5303
  withACP(acpOrACPHash) {
5225
5304
  if (this.acpSelection === "with-acp") {
5226
5305
  throw new CofheError({
@@ -5348,15 +5427,20 @@ var DecryptForTxBuilder = class extends BaseBuilder {
5348
5427
  this.assertPublicClient();
5349
5428
  const thresholdNetworkUrl = await this.getThresholdNetworkUrl();
5350
5429
  const wireAcp = acp ? ACPUtils.getPublic(acp, true) : null;
5351
- const { decryptedValue, signature } = await tnDecryptV2({
5352
- ctHash: this.ctHash,
5353
- chainId: this.chainId,
5354
- acp: wireAcp,
5355
- thresholdNetworkUrl,
5356
- retry404TimeoutMs: this.retry404TimeoutMs,
5357
- timeoutMs: this.timeoutMs,
5358
- onPoll: this.pollCallback
5359
- });
5430
+ const { decryptedValue, signature } = await this.limit(
5431
+ () => tnDecryptV2({
5432
+ ctHash: this.ctHash,
5433
+ chainId: this.chainId,
5434
+ acp: wireAcp,
5435
+ thresholdNetworkUrl,
5436
+ retry404TimeoutMs: this.retry404TimeoutMs,
5437
+ timeoutMs: this.timeoutMs,
5438
+ onPoll: this.pollCallback,
5439
+ signal: this.signal
5440
+ }),
5441
+ "decrypt",
5442
+ this.signal
5443
+ );
5360
5444
  return {
5361
5445
  ctHash: this.ctHash,
5362
5446
  decryptedValue,
@@ -5394,6 +5478,39 @@ var DecryptForTxBuilder = class extends BaseBuilder {
5394
5478
  }
5395
5479
  }
5396
5480
  };
5481
+
5482
+ // core/decrypt/decryptLimiter.ts
5483
+ function createDecryptLimiter(max) {
5484
+ let active = 0;
5485
+ const waiting = [];
5486
+ return async (task, operationLabel, signal) => {
5487
+ if (signal?.aborted)
5488
+ throw decryptAbortedError(operationLabel, signal);
5489
+ if (active >= max) {
5490
+ await new Promise((resume, reject) => {
5491
+ const onAbort = () => {
5492
+ const index = waiting.indexOf(start);
5493
+ if (index >= 0)
5494
+ waiting.splice(index, 1);
5495
+ reject(decryptAbortedError(operationLabel, signal));
5496
+ };
5497
+ const start = () => {
5498
+ signal?.removeEventListener("abort", onAbort);
5499
+ resume();
5500
+ };
5501
+ signal?.addEventListener("abort", onAbort, { once: true });
5502
+ waiting.push(start);
5503
+ });
5504
+ }
5505
+ active += 1;
5506
+ try {
5507
+ return await task();
5508
+ } finally {
5509
+ active -= 1;
5510
+ waiting.shift()?.();
5511
+ }
5512
+ };
5513
+ }
5397
5514
  var decryptResultSignerAbi = viem.parseAbi(["function decryptResultSigner() view returns (address)"]);
5398
5515
  var UINT_TYPE_MASK2 = 0x7fn;
5399
5516
  var TYPE_BYTE_OFFSET2 = 8n;
@@ -5539,11 +5656,13 @@ function createCofheClientBase(opts) {
5539
5656
  requireConnected: _requireConnected
5540
5657
  });
5541
5658
  }
5659
+ const decryptLimiter = createDecryptLimiter(opts.config.decryptConcurrency);
5542
5660
  function decryptForView(ctHash, utype) {
5543
5661
  const state = connectStore.getState();
5544
5662
  return new DecryptForViewBuilder({
5545
5663
  ctHash,
5546
5664
  utype,
5665
+ limit: decryptLimiter,
5547
5666
  chainId: state.chainId,
5548
5667
  account: state.account,
5549
5668
  config: opts.config,
@@ -5556,6 +5675,7 @@ function createCofheClientBase(opts) {
5556
5675
  const state = connectStore.getState();
5557
5676
  return new DecryptForTxBuilder({
5558
5677
  ctHash,
5678
+ limit: decryptLimiter,
5559
5679
  chainId: state.chainId,
5560
5680
  account: state.account,
5561
5681
  config: opts.config,
package/dist/core.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { a as CofheConfig, c as CofheClientParams, b as CofheClient, d as CofheClientConnectionState, F as FheTypes } from './clientTypes-BCAMwrqk.cjs';
2
- export { A as AnyExternalHash, i as CofheClientACPs, C as CofheInputConfig, h as CofheInternalConfig, K as DecryptEndpoint, a4 as DecryptForTxBuilder, a5 as DecryptForTxResult, a3 as DecryptForViewBuilder, J as DecryptPollCallbackContext, G as DecryptPollCallbackFunction, a1 as EncryptInputsBuilder, a2 as EncryptInputsBuilderUnset, M as EncryptSetStateFn, W as EncryptStep, N as EncryptStepCallbackContext, S as Encryptable, p as EncryptableAddress, j as EncryptableBool, E as EncryptableItem, B as EncryptableToExternalHashMap, o as EncryptableUint128, l as EncryptableUint16, m as EncryptableUint32, n as EncryptableUint64, k as EncryptableUint8, q as EncryptedNumber, y as ExternalAddressHash, s as ExternalBoolHash, z as ExternalHashProof, D as ExternalItemHashes, x as ExternalUint128Hash, u as ExternalUint16Hash, v as ExternalUint32Hash, w as ExternalUint64Hash, t as ExternalUint8Hash, R as FheAllUTypes, Z as FheKeyDeserializer, r as FheTypeValue, Q as FheUintUTypes, H as HashPlusProofResult, I as IStorage, $ as KeysStorage, a0 as KeysStore, L as LiteralToPrimitive, P as Primitive, T as TfheInitializer, O as TfheThreadsSetting, U as UnsealedItem, a6 as ZkBuilderAndCrsGenerator, a7 as ZkProveWorkerFunction, a8 as ZkProveWorkerRequest, a9 as ZkProveWorkerResponse, f as assertNoRenamedConfigKeys, e as createCofheConfigBase, _ as createKeysStore, Y as fetchKeys, g as getCofheConfigItem, V as isEncryptableItem, X as isLastEncryptionStep, aa as zkProveWithWorker } from './clientTypes-BCAMwrqk.cjs';
1
+ import { a as CofheConfig, c as CofheClientParams, b as CofheClient, d as CofheClientConnectionState, F as FheTypes } from './clientTypes-K6XNB9H2.cjs';
2
+ export { A as AnyExternalHash, i as CofheClientACPs, C as CofheInputConfig, h as CofheInternalConfig, K as DecryptEndpoint, a4 as DecryptForTxBuilder, a5 as DecryptForTxResult, a3 as DecryptForViewBuilder, J as DecryptPollCallbackContext, G as DecryptPollCallbackFunction, a1 as EncryptInputsBuilder, a2 as EncryptInputsBuilderUnset, M as EncryptSetStateFn, W as EncryptStep, N as EncryptStepCallbackContext, S as Encryptable, p as EncryptableAddress, j as EncryptableBool, E as EncryptableItem, B as EncryptableToExternalHashMap, o as EncryptableUint128, l as EncryptableUint16, m as EncryptableUint32, n as EncryptableUint64, k as EncryptableUint8, q as EncryptedNumber, y as ExternalAddressHash, s as ExternalBoolHash, z as ExternalHashProof, D as ExternalItemHashes, x as ExternalUint128Hash, u as ExternalUint16Hash, v as ExternalUint32Hash, w as ExternalUint64Hash, t as ExternalUint8Hash, R as FheAllUTypes, Z as FheKeyDeserializer, r as FheTypeValue, Q as FheUintUTypes, H as HashPlusProofResult, I as IStorage, $ as KeysStorage, a0 as KeysStore, L as LiteralToPrimitive, P as Primitive, T as TfheInitializer, O as TfheThreadsSetting, U as UnsealedItem, a6 as ZkBuilderAndCrsGenerator, a7 as ZkProveWorkerFunction, a8 as ZkProveWorkerRequest, a9 as ZkProveWorkerResponse, f as assertNoRenamedConfigKeys, e as createCofheConfigBase, _ as createKeysStore, Y as fetchKeys, g as getCofheConfigItem, V as isEncryptableItem, X as isLastEncryptionStep, aa as zkProveWithWorker } from './clientTypes-K6XNB9H2.cjs';
3
3
  import { PublicClient, Address, Hex } from 'viem';
4
4
  import './types-C07FK-cL.cjs';
5
5
  import 'zod';
@@ -101,7 +101,9 @@ declare enum CofheErrorCode {
101
101
  CtSourceTimeout = "CT_SOURCE_TIMEOUT",
102
102
  ACPVerifierTimeout = "ACP_VERIFIER_TIMEOUT",
103
103
  ACPRequired = "ACP_REQUIRED",
104
- SealFailed = "SEAL_FAILED"
104
+ SealFailed = "SEAL_FAILED",
105
+ /** The caller's `AbortSignal` fired; the operation stopped at its next await. */
106
+ Aborted = "ABORTED"
105
107
  }
106
108
  type CofheErrorParams = {
107
109
  code: CofheErrorCode;
package/dist/core.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { a as CofheConfig, c as CofheClientParams, b as CofheClient, d as CofheClientConnectionState, F as FheTypes } from './clientTypes-LvslG7o0.js';
2
- export { A as AnyExternalHash, i as CofheClientACPs, C as CofheInputConfig, h as CofheInternalConfig, K as DecryptEndpoint, a4 as DecryptForTxBuilder, a5 as DecryptForTxResult, a3 as DecryptForViewBuilder, J as DecryptPollCallbackContext, G as DecryptPollCallbackFunction, a1 as EncryptInputsBuilder, a2 as EncryptInputsBuilderUnset, M as EncryptSetStateFn, W as EncryptStep, N as EncryptStepCallbackContext, S as Encryptable, p as EncryptableAddress, j as EncryptableBool, E as EncryptableItem, B as EncryptableToExternalHashMap, o as EncryptableUint128, l as EncryptableUint16, m as EncryptableUint32, n as EncryptableUint64, k as EncryptableUint8, q as EncryptedNumber, y as ExternalAddressHash, s as ExternalBoolHash, z as ExternalHashProof, D as ExternalItemHashes, x as ExternalUint128Hash, u as ExternalUint16Hash, v as ExternalUint32Hash, w as ExternalUint64Hash, t as ExternalUint8Hash, R as FheAllUTypes, Z as FheKeyDeserializer, r as FheTypeValue, Q as FheUintUTypes, H as HashPlusProofResult, I as IStorage, $ as KeysStorage, a0 as KeysStore, L as LiteralToPrimitive, P as Primitive, T as TfheInitializer, O as TfheThreadsSetting, U as UnsealedItem, a6 as ZkBuilderAndCrsGenerator, a7 as ZkProveWorkerFunction, a8 as ZkProveWorkerRequest, a9 as ZkProveWorkerResponse, f as assertNoRenamedConfigKeys, e as createCofheConfigBase, _ as createKeysStore, Y as fetchKeys, g as getCofheConfigItem, V as isEncryptableItem, X as isLastEncryptionStep, aa as zkProveWithWorker } from './clientTypes-LvslG7o0.js';
1
+ import { a as CofheConfig, c as CofheClientParams, b as CofheClient, d as CofheClientConnectionState, F as FheTypes } from './clientTypes-DFXuL9kz.js';
2
+ export { A as AnyExternalHash, i as CofheClientACPs, C as CofheInputConfig, h as CofheInternalConfig, K as DecryptEndpoint, a4 as DecryptForTxBuilder, a5 as DecryptForTxResult, a3 as DecryptForViewBuilder, J as DecryptPollCallbackContext, G as DecryptPollCallbackFunction, a1 as EncryptInputsBuilder, a2 as EncryptInputsBuilderUnset, M as EncryptSetStateFn, W as EncryptStep, N as EncryptStepCallbackContext, S as Encryptable, p as EncryptableAddress, j as EncryptableBool, E as EncryptableItem, B as EncryptableToExternalHashMap, o as EncryptableUint128, l as EncryptableUint16, m as EncryptableUint32, n as EncryptableUint64, k as EncryptableUint8, q as EncryptedNumber, y as ExternalAddressHash, s as ExternalBoolHash, z as ExternalHashProof, D as ExternalItemHashes, x as ExternalUint128Hash, u as ExternalUint16Hash, v as ExternalUint32Hash, w as ExternalUint64Hash, t as ExternalUint8Hash, R as FheAllUTypes, Z as FheKeyDeserializer, r as FheTypeValue, Q as FheUintUTypes, H as HashPlusProofResult, I as IStorage, $ as KeysStorage, a0 as KeysStore, L as LiteralToPrimitive, P as Primitive, T as TfheInitializer, O as TfheThreadsSetting, U as UnsealedItem, a6 as ZkBuilderAndCrsGenerator, a7 as ZkProveWorkerFunction, a8 as ZkProveWorkerRequest, a9 as ZkProveWorkerResponse, f as assertNoRenamedConfigKeys, e as createCofheConfigBase, _ as createKeysStore, Y as fetchKeys, g as getCofheConfigItem, V as isEncryptableItem, X as isLastEncryptionStep, aa as zkProveWithWorker } from './clientTypes-DFXuL9kz.js';
3
3
  import { PublicClient, Address, Hex } from 'viem';
4
4
  import './types-C07FK-cL.js';
5
5
  import 'zod';
@@ -101,7 +101,9 @@ declare enum CofheErrorCode {
101
101
  CtSourceTimeout = "CT_SOURCE_TIMEOUT",
102
102
  ACPVerifierTimeout = "ACP_VERIFIER_TIMEOUT",
103
103
  ACPRequired = "ACP_REQUIRED",
104
- SealFailed = "SEAL_FAILED"
104
+ SealFailed = "SEAL_FAILED",
105
+ /** The caller's `AbortSignal` fired; the operation stopped at its next await. */
106
+ Aborted = "ABORTED"
105
107
  }
106
108
  type CofheErrorParams = {
107
109
  code: CofheErrorCode;
package/dist/core.js CHANGED
@@ -1,5 +1,5 @@
1
- export { InitialConnectStore as CONNECT_STORE_DEFAULTS, DecryptForTxBuilder, DecryptForViewBuilder, EncryptInputsBuilder, assertNoRenamedConfigKeys, cofheFetch, createCofheClientBase, createCofheConfigBase, createKeysStore, fetchKeys, getCofheConfigItem, getCofheDebugInterceptors, setCofheDebugInterceptors, verifyDecryptResult, zkProveWithWorker } from './chunk-KHM6LYLU.js';
1
+ export { InitialConnectStore as CONNECT_STORE_DEFAULTS, DecryptForTxBuilder, DecryptForViewBuilder, EncryptInputsBuilder, assertNoRenamedConfigKeys, cofheFetch, createCofheClientBase, createCofheConfigBase, createKeysStore, fetchKeys, getCofheConfigItem, getCofheDebugInterceptors, setCofheDebugInterceptors, verifyDecryptResult, zkProveWithWorker } from './chunk-ZYCIUX5C.js';
2
2
  import './chunk-UKQAJK4N.js';
3
- export { getTaskManagerAddress } from './chunk-WAA2U7CT.js';
4
- export { EncryptStep, Encryptable, FheAllUTypes, FheTypes, FheUintUTypes, fheTypeToString, isEncryptableItem, isLastEncryptionStep } from './chunk-3SD2UCRE.js';
5
- export { COFHE_ADDRESS_BOOK_ADDRESS, CofheError, CofheErrorCode, MOCKS_DECRYPT_RESULT_SIGNER_PRIVATE_KEY, MOCKS_TASK_MANAGER_ADDRESS, MOCKS_THRESHOLD_NETWORK_ADDRESS, MOCKS_ZK_VERIFIER_ADDRESS, MOCKS_ZK_VERIFIER_SIGNER_ADDRESS, MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY, TASK_MANAGER_ID, TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT, TFHE_RS_ZK_MAX_BITS, isCofheError } from './chunk-OC5TGQGG.js';
3
+ export { getTaskManagerAddress } from './chunk-37SG44CR.js';
4
+ export { EncryptStep, Encryptable, FheAllUTypes, FheTypes, FheUintUTypes, fheTypeToString, isEncryptableItem, isLastEncryptionStep } from './chunk-PLHQYVND.js';
5
+ export { COFHE_ADDRESS_BOOK_ADDRESS, CofheError, CofheErrorCode, MOCKS_DECRYPT_RESULT_SIGNER_PRIVATE_KEY, MOCKS_TASK_MANAGER_ADDRESS, MOCKS_THRESHOLD_NETWORK_ADDRESS, MOCKS_ZK_VERIFIER_ADDRESS, MOCKS_ZK_VERIFIER_SIGNER_ADDRESS, MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY, TASK_MANAGER_ID, TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT, TFHE_RS_ZK_MAX_BITS, isCofheError } from './chunk-NJTYZ3CW.js';