@cofhe/sdk 1.1.0-alpha.0 → 1.1.0-alpha.2

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/node.cjs CHANGED
@@ -1925,19 +1925,22 @@ var zkProve = async (builder, crs, metadata) => {
1925
1925
  }, 0);
1926
1926
  });
1927
1927
  };
1928
- var constructZkPoKMetadata = (accountAddr, securityZone, chainId) => {
1928
+ var constructZkPoKMetadata = (accountAddr, securityZone, chainId, consumingContract) => {
1929
1929
  const accountAddrNoPrefix = accountAddr.startsWith("0x") ? accountAddr.slice(2) : accountAddr;
1930
1930
  const accountBytes = hexToBytes(accountAddrNoPrefix);
1931
+ const contractNoPrefix = consumingContract.startsWith("0x") ? consumingContract.slice(2) : consumingContract;
1932
+ const contractBytes = hexToBytes(contractNoPrefix);
1931
1933
  const chainIdBytes = new Uint8Array(32);
1932
1934
  let value = chainId;
1933
1935
  for (let i = 31; i >= 0 && value > 0; i--) {
1934
1936
  chainIdBytes[i] = value & 255;
1935
1937
  value = value >>> 8;
1936
1938
  }
1937
- const metadata = new Uint8Array(1 + accountBytes.length + 32);
1939
+ const metadata = new Uint8Array(1 + accountBytes.length + 32 + contractBytes.length);
1938
1940
  metadata[0] = securityZone;
1939
1941
  metadata.set(accountBytes, 1);
1940
1942
  metadata.set(chainIdBytes, 1 + accountBytes.length);
1943
+ metadata.set(contractBytes, 1 + accountBytes.length + 32);
1941
1944
  return metadata;
1942
1945
  };
1943
1946
  var zkVerifyBatch = async (verifierUrl, serializedBytes, address, securityZone, chainId, consumingContract) => {
@@ -2850,20 +2853,33 @@ var EncryptInputsBuilder = class extends BaseBuilder {
2850
2853
  return this.consumingContract;
2851
2854
  }
2852
2855
  /**
2853
- * Asserts that this.consumingContract is populated
2854
- * @throws {CofheError} If consumingContract is not set
2856
+ * Asserts that this.consumingContract is populated and is an address.
2857
+ * Runs before TFHE init, key fetching and proving, so a bad address costs
2858
+ * nothing: the contract is bound into the proof, and a proof built for a
2859
+ * non-address could only fail at the verifier, after the expensive step.
2860
+ * @throws {CofheError} If consumingContract is not set or is not an address
2855
2861
  */
2856
2862
  assertConsumingContract() {
2857
- if (this.consumingContract)
2858
- return;
2859
- throw new CofheError({
2860
- code: "CONSUMING_CONTRACT_UNINITIALIZED" /* ConsumingContractUninitialized */,
2861
- message: "Consuming contract is not set",
2862
- hint: "Use setConsumingContract(...) to set the contract that will consume the encrypted inputs.",
2863
- context: {
2864
- consumingContract: this.consumingContract
2865
- }
2866
- });
2863
+ if (!this.consumingContract) {
2864
+ throw new CofheError({
2865
+ code: "CONSUMING_CONTRACT_UNINITIALIZED" /* ConsumingContractUninitialized */,
2866
+ message: "Consuming contract is not set",
2867
+ hint: "Use setConsumingContract(...) to set the contract that will consume the encrypted inputs.",
2868
+ context: {
2869
+ consumingContract: this.consumingContract
2870
+ }
2871
+ });
2872
+ }
2873
+ if (!viem.isAddress(this.consumingContract, { strict: false })) {
2874
+ throw new CofheError({
2875
+ code: "CONSUMING_CONTRACT_INVALID" /* ConsumingContractInvalid */,
2876
+ message: "Consuming contract is not an address",
2877
+ hint: "setConsumingContract(...) takes the 20-byte address of the contract that will consume the encrypted inputs.",
2878
+ context: {
2879
+ consumingContract: this.consumingContract
2880
+ }
2881
+ });
2882
+ }
2867
2883
  }
2868
2884
  setUseWorker(useWorker) {
2869
2885
  this.useWorker = useWorker;
@@ -3079,7 +3095,7 @@ var EncryptInputsBuilder = class extends BaseBuilder {
3079
3095
  zkBuilder = zkPack(this.inputItems, zkBuilder);
3080
3096
  this.fireStepEnd("pack" /* Pack */);
3081
3097
  this.fireStepStart("prove" /* Prove */);
3082
- const metadata = constructZkPoKMetadata(this.account, this.securityZone, this.chainId);
3098
+ const metadata = constructZkPoKMetadata(this.account, this.securityZone, this.chainId, this.consumingContract);
3083
3099
  let proof = null;
3084
3100
  let usedWorker = false;
3085
3101
  let workerFailedError;
@@ -3770,6 +3786,16 @@ function mapApiErrorCodeToCofheErrorCode(apiErrorCode, fallback) {
3770
3786
 
3771
3787
  // core/decrypt/submitRetry.ts
3772
3788
  var DEFAULT_404_RETRY_TIMEOUT_MS = 1e4;
3789
+ var DEFAULT_DECRYPT_TIMEOUT_MS = 5 * 60 * 1e3;
3790
+ function assertDecryptTimeoutMs(timeoutMs, operationLabel) {
3791
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
3792
+ throw new CofheError({
3793
+ code: "INTERNAL_ERROR" /* InternalError */,
3794
+ message: `${operationLabel}: setTimeout(timeoutMs) expects a finite number greater than 0.`,
3795
+ context: { timeoutMs }
3796
+ });
3797
+ }
3798
+ }
3773
3799
  function normalize404RetryTimeoutMs(params) {
3774
3800
  const { timeoutMs, operationLabel, errorCode } = params;
3775
3801
  if (timeoutMs === void 0)
@@ -3908,7 +3934,6 @@ function parseDecryptedBytesToBigInt(decrypted) {
3908
3934
  // core/decrypt/tnSealOutputV2.ts
3909
3935
  var POLL_INTERVAL_MS = 1e3;
3910
3936
  var POLL_MAX_INTERVAL_MS = 1e4;
3911
- var SEAL_OUTPUT_TIMEOUT_MS = 5 * 60 * 1e3;
3912
3937
  var SUBMIT_RETRY_INTERVAL_MS = 1e3;
3913
3938
  function numberArrayToUint8Array(arr) {
3914
3939
  return new Uint8Array(arr);
@@ -3966,7 +3991,7 @@ function parseCompletedSealOutputResponse(params) {
3966
3991
  }
3967
3992
  return convertSealedData(sealed);
3968
3993
  }
3969
- async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, acp, overallStartTime, retry404TimeoutMs, onPoll) {
3994
+ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, acp, overallStartTime, retry404TimeoutMs, timeoutMs, onPoll) {
3970
3995
  const body = {
3971
3996
  ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
3972
3997
  host_chain_id: chainId,
@@ -4069,7 +4094,7 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, acp
4069
4094
  status: responseClassification.status,
4070
4095
  elapsedMs,
4071
4096
  retry404TimeoutMs,
4072
- overallTimeoutMs: SEAL_OUTPUT_TIMEOUT_MS,
4097
+ overallTimeoutMs: timeoutMs,
4073
4098
  thresholdNetworkUrl,
4074
4099
  body,
4075
4100
  attemptIndex,
@@ -4081,13 +4106,13 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, acp
4081
4106
  attemptIndex,
4082
4107
  elapsedMs,
4083
4108
  intervalMs: SUBMIT_RETRY_INTERVAL_MS,
4084
- timeoutMs: SEAL_OUTPUT_TIMEOUT_MS
4109
+ timeoutMs
4085
4110
  });
4086
4111
  await new Promise((resolve) => setTimeout(resolve, SUBMIT_RETRY_INTERVAL_MS));
4087
4112
  attemptIndex += 1;
4088
4113
  }
4089
4114
  }
4090
- async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStartTime, onPoll) {
4115
+ async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStartTime, timeoutMs, onPoll) {
4091
4116
  let attemptIndex = 0;
4092
4117
  while (true) {
4093
4118
  const elapsedMs = Date.now() - overallStartTime;
@@ -4101,17 +4126,17 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStart
4101
4126
  attemptIndex,
4102
4127
  elapsedMs,
4103
4128
  intervalMs,
4104
- timeoutMs: SEAL_OUTPUT_TIMEOUT_MS
4129
+ timeoutMs
4105
4130
  });
4106
- if (elapsedMs > SEAL_OUTPUT_TIMEOUT_MS) {
4131
+ if (elapsedMs > timeoutMs) {
4107
4132
  throw new CofheError({
4108
4133
  code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
4109
- message: `sealOutput polling timed out after ${SEAL_OUTPUT_TIMEOUT_MS}ms`,
4134
+ message: `sealOutput polling timed out after ${timeoutMs}ms`,
4110
4135
  hint: "The request may still be processing. Try again later.",
4111
4136
  context: {
4112
4137
  thresholdNetworkUrl,
4113
4138
  requestId,
4114
- timeoutMs: SEAL_OUTPUT_TIMEOUT_MS
4139
+ timeoutMs
4115
4140
  }
4116
4141
  });
4117
4142
  }
@@ -4199,6 +4224,7 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStart
4199
4224
  }
4200
4225
  async function tnSealOutputV2(params) {
4201
4226
  const { thresholdNetworkUrl, ctHash, chainId, acp, retry404TimeoutMs, onPoll } = params;
4227
+ const timeoutMs = params.timeoutMs ?? DEFAULT_DECRYPT_TIMEOUT_MS;
4202
4228
  const normalized404RetryTimeoutMs = normalize404RetryTimeoutMs({
4203
4229
  timeoutMs: retry404TimeoutMs,
4204
4230
  operationLabel: "sealOutput",
@@ -4212,12 +4238,13 @@ async function tnSealOutputV2(params) {
4212
4238
  acp,
4213
4239
  overallStartTime,
4214
4240
  normalized404RetryTimeoutMs,
4241
+ timeoutMs,
4215
4242
  onPoll
4216
4243
  );
4217
4244
  if (submitResult.kind === "completed") {
4218
4245
  return submitResult.sealed;
4219
4246
  }
4220
- return await pollSealOutputStatus(thresholdNetworkUrl, submitResult.requestId, overallStartTime, onPoll);
4247
+ return await pollSealOutputStatus(thresholdNetworkUrl, submitResult.requestId, overallStartTime, timeoutMs, onPoll);
4221
4248
  }
4222
4249
 
4223
4250
  // core/decrypt/decryptForViewBuilder.ts
@@ -4229,6 +4256,7 @@ var DecryptForViewBuilder = class extends BaseBuilder {
4229
4256
  acp;
4230
4257
  pollCallback;
4231
4258
  retry404TimeoutMs = DEFAULT_404_RETRY_TIMEOUT_MS2;
4259
+ timeoutMs;
4232
4260
  constructor(params) {
4233
4261
  super({
4234
4262
  config: params.config,
@@ -4302,6 +4330,16 @@ var DecryptForViewBuilder = class extends BaseBuilder {
4302
4330
  this.retry404TimeoutMs = timeoutMs;
4303
4331
  return this;
4304
4332
  }
4333
+ /**
4334
+ * The whole budget of this decrypt in milliseconds, submit retries and status polling together
4335
+ * (5 minutes by default). Past it, `execute()` rejects with `SealOutputFailed`; a request still
4336
+ * processing on the threshold network is not cancelled.
4337
+ */
4338
+ setTimeout(timeoutMs) {
4339
+ assertDecryptTimeoutMs(timeoutMs, "decryptForView");
4340
+ this.timeoutMs = timeoutMs;
4341
+ return this;
4342
+ }
4305
4343
  withACP(acpOrACPHash) {
4306
4344
  if (typeof acpOrACPHash === "string") {
4307
4345
  this.acpHash = acpOrACPHash;
@@ -4431,6 +4469,7 @@ var DecryptForViewBuilder = class extends BaseBuilder {
4431
4469
  acp: wireAcp,
4432
4470
  thresholdNetworkUrl,
4433
4471
  retry404TimeoutMs: this.retry404TimeoutMs,
4472
+ timeoutMs: this.timeoutMs,
4434
4473
  onPoll: this.pollCallback
4435
4474
  });
4436
4475
  return ACPUtils.unseal(acp, sealed);
@@ -4533,7 +4572,6 @@ async function cofheMocksDecryptForTx(ctHash, utype, acp, publicClient) {
4533
4572
  // core/decrypt/tnDecryptV2.ts
4534
4573
  var POLL_INTERVAL_MS2 = 1e3;
4535
4574
  var POLL_MAX_INTERVAL_MS2 = 1e4;
4536
- var DECRYPT_TIMEOUT_MS = 5 * 60 * 1e3;
4537
4575
  var SUBMIT_RETRY_INTERVAL_MS2 = 1e3;
4538
4576
  function assertDecryptSubmitResponseV2(value) {
4539
4577
  if (value == null || typeof value !== "object") {
@@ -4650,7 +4688,7 @@ function assertDecryptStatusResponseV2(value) {
4650
4688
  }
4651
4689
  return value;
4652
4690
  }
4653
- async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, acp, overallStartTime, retry404TimeoutMs, onPoll) {
4691
+ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, acp, overallStartTime, retry404TimeoutMs, timeoutMs, onPoll) {
4654
4692
  const body = {
4655
4693
  ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
4656
4694
  host_chain_id: chainId
@@ -4757,7 +4795,7 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, acp,
4757
4795
  status: responseClassification.status,
4758
4796
  elapsedMs,
4759
4797
  retry404TimeoutMs,
4760
- overallTimeoutMs: DECRYPT_TIMEOUT_MS,
4798
+ overallTimeoutMs: timeoutMs,
4761
4799
  thresholdNetworkUrl,
4762
4800
  body,
4763
4801
  attemptIndex,
@@ -4769,13 +4807,13 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, acp,
4769
4807
  attemptIndex,
4770
4808
  elapsedMs,
4771
4809
  intervalMs: SUBMIT_RETRY_INTERVAL_MS2,
4772
- timeoutMs: DECRYPT_TIMEOUT_MS
4810
+ timeoutMs
4773
4811
  });
4774
4812
  await new Promise((resolve) => setTimeout(resolve, SUBMIT_RETRY_INTERVAL_MS2));
4775
4813
  attemptIndex += 1;
4776
4814
  }
4777
4815
  }
4778
- async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartTime, onPoll) {
4816
+ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartTime, timeoutMs, onPoll) {
4779
4817
  let attemptIndex = 0;
4780
4818
  while (true) {
4781
4819
  const elapsedMs = Date.now() - overallStartTime;
@@ -4789,17 +4827,17 @@ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartT
4789
4827
  attemptIndex,
4790
4828
  elapsedMs,
4791
4829
  intervalMs,
4792
- timeoutMs: DECRYPT_TIMEOUT_MS
4830
+ timeoutMs
4793
4831
  });
4794
- if (elapsedMs > DECRYPT_TIMEOUT_MS) {
4832
+ if (elapsedMs > timeoutMs) {
4795
4833
  throw new CofheError({
4796
4834
  code: "DECRYPT_FAILED" /* DecryptFailed */,
4797
- message: `decrypt polling timed out after ${DECRYPT_TIMEOUT_MS}ms`,
4835
+ message: `decrypt polling timed out after ${timeoutMs}ms`,
4798
4836
  hint: "The request may still be processing. Try again later.",
4799
4837
  context: {
4800
4838
  thresholdNetworkUrl,
4801
4839
  requestId,
4802
- timeoutMs: DECRYPT_TIMEOUT_MS
4840
+ timeoutMs
4803
4841
  }
4804
4842
  });
4805
4843
  }
@@ -4888,6 +4926,7 @@ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartT
4888
4926
  }
4889
4927
  async function tnDecryptV2(params) {
4890
4928
  const { thresholdNetworkUrl, ctHash, chainId, acp, retry404TimeoutMs, onPoll } = params;
4929
+ const timeoutMs = params.timeoutMs ?? DEFAULT_DECRYPT_TIMEOUT_MS;
4891
4930
  const normalized404RetryTimeoutMs = normalize404RetryTimeoutMs({
4892
4931
  timeoutMs: retry404TimeoutMs,
4893
4932
  operationLabel: "decrypt",
@@ -4901,12 +4940,13 @@ async function tnDecryptV2(params) {
4901
4940
  acp,
4902
4941
  overallStartTime,
4903
4942
  normalized404RetryTimeoutMs,
4943
+ timeoutMs,
4904
4944
  onPoll
4905
4945
  );
4906
4946
  if (submitResult.kind === "completed") {
4907
4947
  return submitResult;
4908
4948
  }
4909
- return await pollDecryptStatusV2(thresholdNetworkUrl, submitResult.requestId, overallStartTime, onPoll);
4949
+ return await pollDecryptStatusV2(thresholdNetworkUrl, submitResult.requestId, overallStartTime, timeoutMs, onPoll);
4910
4950
  }
4911
4951
 
4912
4952
  // core/decrypt/decryptForTxBuilder.ts
@@ -4918,6 +4958,7 @@ var DecryptForTxBuilder = class extends BaseBuilder {
4918
4958
  acpSelection = "unset";
4919
4959
  pollCallback;
4920
4960
  retry404TimeoutMs = DEFAULT_404_RETRY_TIMEOUT_MS3;
4961
+ timeoutMs;
4921
4962
  constructor(params) {
4922
4963
  super({
4923
4964
  config: params.config,
@@ -4960,6 +5001,11 @@ var DecryptForTxBuilder = class extends BaseBuilder {
4960
5001
  this.retry404TimeoutMs = timeoutMs;
4961
5002
  return this;
4962
5003
  }
5004
+ setTimeout(timeoutMs) {
5005
+ assertDecryptTimeoutMs(timeoutMs, "decryptForTx");
5006
+ this.timeoutMs = timeoutMs;
5007
+ return this;
5008
+ }
4963
5009
  withACP(acpOrACPHash) {
4964
5010
  if (this.acpSelection === "with-acp") {
4965
5011
  throw new CofheError({
@@ -5093,6 +5139,7 @@ var DecryptForTxBuilder = class extends BaseBuilder {
5093
5139
  acp: wireAcp,
5094
5140
  thresholdNetworkUrl,
5095
5141
  retry404TimeoutMs: this.retry404TimeoutMs,
5142
+ timeoutMs: this.timeoutMs,
5096
5143
  onPoll: this.pollCallback
5097
5144
  });
5098
5145
  return {
package/dist/node.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as CofheInputConfig, a as CofheConfig, b as CofheClient } from './clientTypes-RXwLVWou.cjs';
1
+ import { C as CofheInputConfig, a as CofheConfig, b as CofheClient } from './clientTypes-BCAMwrqk.cjs';
2
2
  import 'viem';
3
3
  import './types-C07FK-cL.cjs';
4
4
  import 'zod';
package/dist/node.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as CofheInputConfig, a as CofheConfig, b as CofheClient } from './clientTypes-CnslFzxB.js';
1
+ import { C as CofheInputConfig, a as CofheConfig, b as CofheClient } from './clientTypes-LvslG7o0.js';
2
2
  import 'viem';
3
3
  import './types-C07FK-cL.js';
4
4
  import 'zod';
package/dist/node.js CHANGED
@@ -1,8 +1,8 @@
1
- import { createCofheConfigBase, createCofheClientBase } from './chunk-2EO4JSR7.js';
1
+ import { createCofheConfigBase, createCofheClientBase } from './chunk-KHM6LYLU.js';
2
2
  import './chunk-UKQAJK4N.js';
3
- import './chunk-3L2IVPMI.js';
4
- import { fromHexString } from './chunk-WJGTPW7K.js';
5
- import { TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT } from './chunk-J23FYAI2.js';
3
+ import './chunk-WAA2U7CT.js';
4
+ import { fromHexString } from './chunk-3SD2UCRE.js';
5
+ import { TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT } from './chunk-OC5TGQGG.js';
6
6
  import { promises } from 'fs';
7
7
  import { join } from 'path';
8
8
  import { init_panic_hook, ProvenCompactCiphertextList, CompactPkeCrs, TfheCompactPublicKey } from 'node-tfhe';
package/dist/web.cjs CHANGED
@@ -1960,19 +1960,22 @@ var zkProve = async (builder, crs, metadata) => {
1960
1960
  }, 0);
1961
1961
  });
1962
1962
  };
1963
- var constructZkPoKMetadata = (accountAddr, securityZone, chainId) => {
1963
+ var constructZkPoKMetadata = (accountAddr, securityZone, chainId, consumingContract) => {
1964
1964
  const accountAddrNoPrefix = accountAddr.startsWith("0x") ? accountAddr.slice(2) : accountAddr;
1965
1965
  const accountBytes = hexToBytes(accountAddrNoPrefix);
1966
+ const contractNoPrefix = consumingContract.startsWith("0x") ? consumingContract.slice(2) : consumingContract;
1967
+ const contractBytes = hexToBytes(contractNoPrefix);
1966
1968
  const chainIdBytes = new Uint8Array(32);
1967
1969
  let value = chainId;
1968
1970
  for (let i = 31; i >= 0 && value > 0; i--) {
1969
1971
  chainIdBytes[i] = value & 255;
1970
1972
  value = value >>> 8;
1971
1973
  }
1972
- const metadata = new Uint8Array(1 + accountBytes.length + 32);
1974
+ const metadata = new Uint8Array(1 + accountBytes.length + 32 + contractBytes.length);
1973
1975
  metadata[0] = securityZone;
1974
1976
  metadata.set(accountBytes, 1);
1975
1977
  metadata.set(chainIdBytes, 1 + accountBytes.length);
1978
+ metadata.set(contractBytes, 1 + accountBytes.length + 32);
1976
1979
  return metadata;
1977
1980
  };
1978
1981
  var zkVerifyBatch = async (verifierUrl, serializedBytes, address, securityZone, chainId, consumingContract) => {
@@ -2885,20 +2888,33 @@ var EncryptInputsBuilder = class extends BaseBuilder {
2885
2888
  return this.consumingContract;
2886
2889
  }
2887
2890
  /**
2888
- * Asserts that this.consumingContract is populated
2889
- * @throws {CofheError} If consumingContract is not set
2891
+ * Asserts that this.consumingContract is populated and is an address.
2892
+ * Runs before TFHE init, key fetching and proving, so a bad address costs
2893
+ * nothing: the contract is bound into the proof, and a proof built for a
2894
+ * non-address could only fail at the verifier, after the expensive step.
2895
+ * @throws {CofheError} If consumingContract is not set or is not an address
2890
2896
  */
2891
2897
  assertConsumingContract() {
2892
- if (this.consumingContract)
2893
- return;
2894
- throw new CofheError({
2895
- code: "CONSUMING_CONTRACT_UNINITIALIZED" /* ConsumingContractUninitialized */,
2896
- message: "Consuming contract is not set",
2897
- hint: "Use setConsumingContract(...) to set the contract that will consume the encrypted inputs.",
2898
- context: {
2899
- consumingContract: this.consumingContract
2900
- }
2901
- });
2898
+ if (!this.consumingContract) {
2899
+ throw new CofheError({
2900
+ code: "CONSUMING_CONTRACT_UNINITIALIZED" /* ConsumingContractUninitialized */,
2901
+ message: "Consuming contract is not set",
2902
+ hint: "Use setConsumingContract(...) to set the contract that will consume the encrypted inputs.",
2903
+ context: {
2904
+ consumingContract: this.consumingContract
2905
+ }
2906
+ });
2907
+ }
2908
+ if (!viem.isAddress(this.consumingContract, { strict: false })) {
2909
+ throw new CofheError({
2910
+ code: "CONSUMING_CONTRACT_INVALID" /* ConsumingContractInvalid */,
2911
+ message: "Consuming contract is not an address",
2912
+ hint: "setConsumingContract(...) takes the 20-byte address of the contract that will consume the encrypted inputs.",
2913
+ context: {
2914
+ consumingContract: this.consumingContract
2915
+ }
2916
+ });
2917
+ }
2902
2918
  }
2903
2919
  setUseWorker(useWorker) {
2904
2920
  this.useWorker = useWorker;
@@ -3114,7 +3130,7 @@ var EncryptInputsBuilder = class extends BaseBuilder {
3114
3130
  zkBuilder = zkPack(this.inputItems, zkBuilder);
3115
3131
  this.fireStepEnd("pack" /* Pack */);
3116
3132
  this.fireStepStart("prove" /* Prove */);
3117
- const metadata = constructZkPoKMetadata(this.account, this.securityZone, this.chainId);
3133
+ const metadata = constructZkPoKMetadata(this.account, this.securityZone, this.chainId, this.consumingContract);
3118
3134
  let proof = null;
3119
3135
  let usedWorker = false;
3120
3136
  let workerFailedError;
@@ -3805,6 +3821,16 @@ function mapApiErrorCodeToCofheErrorCode(apiErrorCode, fallback) {
3805
3821
 
3806
3822
  // core/decrypt/submitRetry.ts
3807
3823
  var DEFAULT_404_RETRY_TIMEOUT_MS = 1e4;
3824
+ var DEFAULT_DECRYPT_TIMEOUT_MS = 5 * 60 * 1e3;
3825
+ function assertDecryptTimeoutMs(timeoutMs, operationLabel) {
3826
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
3827
+ throw new CofheError({
3828
+ code: "INTERNAL_ERROR" /* InternalError */,
3829
+ message: `${operationLabel}: setTimeout(timeoutMs) expects a finite number greater than 0.`,
3830
+ context: { timeoutMs }
3831
+ });
3832
+ }
3833
+ }
3808
3834
  function normalize404RetryTimeoutMs(params) {
3809
3835
  const { timeoutMs, operationLabel, errorCode } = params;
3810
3836
  if (timeoutMs === void 0)
@@ -3943,7 +3969,6 @@ function parseDecryptedBytesToBigInt(decrypted) {
3943
3969
  // core/decrypt/tnSealOutputV2.ts
3944
3970
  var POLL_INTERVAL_MS = 1e3;
3945
3971
  var POLL_MAX_INTERVAL_MS = 1e4;
3946
- var SEAL_OUTPUT_TIMEOUT_MS = 5 * 60 * 1e3;
3947
3972
  var SUBMIT_RETRY_INTERVAL_MS = 1e3;
3948
3973
  function numberArrayToUint8Array(arr) {
3949
3974
  return new Uint8Array(arr);
@@ -4001,7 +4026,7 @@ function parseCompletedSealOutputResponse(params) {
4001
4026
  }
4002
4027
  return convertSealedData(sealed);
4003
4028
  }
4004
- async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, acp, overallStartTime, retry404TimeoutMs, onPoll) {
4029
+ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, acp, overallStartTime, retry404TimeoutMs, timeoutMs, onPoll) {
4005
4030
  const body = {
4006
4031
  ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
4007
4032
  host_chain_id: chainId,
@@ -4104,7 +4129,7 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, acp
4104
4129
  status: responseClassification.status,
4105
4130
  elapsedMs,
4106
4131
  retry404TimeoutMs,
4107
- overallTimeoutMs: SEAL_OUTPUT_TIMEOUT_MS,
4132
+ overallTimeoutMs: timeoutMs,
4108
4133
  thresholdNetworkUrl,
4109
4134
  body,
4110
4135
  attemptIndex,
@@ -4116,13 +4141,13 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, acp
4116
4141
  attemptIndex,
4117
4142
  elapsedMs,
4118
4143
  intervalMs: SUBMIT_RETRY_INTERVAL_MS,
4119
- timeoutMs: SEAL_OUTPUT_TIMEOUT_MS
4144
+ timeoutMs
4120
4145
  });
4121
4146
  await new Promise((resolve) => setTimeout(resolve, SUBMIT_RETRY_INTERVAL_MS));
4122
4147
  attemptIndex += 1;
4123
4148
  }
4124
4149
  }
4125
- async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStartTime, onPoll) {
4150
+ async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStartTime, timeoutMs, onPoll) {
4126
4151
  let attemptIndex = 0;
4127
4152
  while (true) {
4128
4153
  const elapsedMs = Date.now() - overallStartTime;
@@ -4136,17 +4161,17 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStart
4136
4161
  attemptIndex,
4137
4162
  elapsedMs,
4138
4163
  intervalMs,
4139
- timeoutMs: SEAL_OUTPUT_TIMEOUT_MS
4164
+ timeoutMs
4140
4165
  });
4141
- if (elapsedMs > SEAL_OUTPUT_TIMEOUT_MS) {
4166
+ if (elapsedMs > timeoutMs) {
4142
4167
  throw new CofheError({
4143
4168
  code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
4144
- message: `sealOutput polling timed out after ${SEAL_OUTPUT_TIMEOUT_MS}ms`,
4169
+ message: `sealOutput polling timed out after ${timeoutMs}ms`,
4145
4170
  hint: "The request may still be processing. Try again later.",
4146
4171
  context: {
4147
4172
  thresholdNetworkUrl,
4148
4173
  requestId,
4149
- timeoutMs: SEAL_OUTPUT_TIMEOUT_MS
4174
+ timeoutMs
4150
4175
  }
4151
4176
  });
4152
4177
  }
@@ -4234,6 +4259,7 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStart
4234
4259
  }
4235
4260
  async function tnSealOutputV2(params) {
4236
4261
  const { thresholdNetworkUrl, ctHash, chainId, acp, retry404TimeoutMs, onPoll } = params;
4262
+ const timeoutMs = params.timeoutMs ?? DEFAULT_DECRYPT_TIMEOUT_MS;
4237
4263
  const normalized404RetryTimeoutMs = normalize404RetryTimeoutMs({
4238
4264
  timeoutMs: retry404TimeoutMs,
4239
4265
  operationLabel: "sealOutput",
@@ -4247,12 +4273,13 @@ async function tnSealOutputV2(params) {
4247
4273
  acp,
4248
4274
  overallStartTime,
4249
4275
  normalized404RetryTimeoutMs,
4276
+ timeoutMs,
4250
4277
  onPoll
4251
4278
  );
4252
4279
  if (submitResult.kind === "completed") {
4253
4280
  return submitResult.sealed;
4254
4281
  }
4255
- return await pollSealOutputStatus(thresholdNetworkUrl, submitResult.requestId, overallStartTime, onPoll);
4282
+ return await pollSealOutputStatus(thresholdNetworkUrl, submitResult.requestId, overallStartTime, timeoutMs, onPoll);
4256
4283
  }
4257
4284
 
4258
4285
  // core/decrypt/decryptForViewBuilder.ts
@@ -4264,6 +4291,7 @@ var DecryptForViewBuilder = class extends BaseBuilder {
4264
4291
  acp;
4265
4292
  pollCallback;
4266
4293
  retry404TimeoutMs = DEFAULT_404_RETRY_TIMEOUT_MS2;
4294
+ timeoutMs;
4267
4295
  constructor(params) {
4268
4296
  super({
4269
4297
  config: params.config,
@@ -4337,6 +4365,16 @@ var DecryptForViewBuilder = class extends BaseBuilder {
4337
4365
  this.retry404TimeoutMs = timeoutMs;
4338
4366
  return this;
4339
4367
  }
4368
+ /**
4369
+ * The whole budget of this decrypt in milliseconds, submit retries and status polling together
4370
+ * (5 minutes by default). Past it, `execute()` rejects with `SealOutputFailed`; a request still
4371
+ * processing on the threshold network is not cancelled.
4372
+ */
4373
+ setTimeout(timeoutMs) {
4374
+ assertDecryptTimeoutMs(timeoutMs, "decryptForView");
4375
+ this.timeoutMs = timeoutMs;
4376
+ return this;
4377
+ }
4340
4378
  withACP(acpOrACPHash) {
4341
4379
  if (typeof acpOrACPHash === "string") {
4342
4380
  this.acpHash = acpOrACPHash;
@@ -4466,6 +4504,7 @@ var DecryptForViewBuilder = class extends BaseBuilder {
4466
4504
  acp: wireAcp,
4467
4505
  thresholdNetworkUrl,
4468
4506
  retry404TimeoutMs: this.retry404TimeoutMs,
4507
+ timeoutMs: this.timeoutMs,
4469
4508
  onPoll: this.pollCallback
4470
4509
  });
4471
4510
  return ACPUtils.unseal(acp, sealed);
@@ -4568,7 +4607,6 @@ async function cofheMocksDecryptForTx(ctHash, utype, acp, publicClient) {
4568
4607
  // core/decrypt/tnDecryptV2.ts
4569
4608
  var POLL_INTERVAL_MS2 = 1e3;
4570
4609
  var POLL_MAX_INTERVAL_MS2 = 1e4;
4571
- var DECRYPT_TIMEOUT_MS = 5 * 60 * 1e3;
4572
4610
  var SUBMIT_RETRY_INTERVAL_MS2 = 1e3;
4573
4611
  function assertDecryptSubmitResponseV2(value) {
4574
4612
  if (value == null || typeof value !== "object") {
@@ -4685,7 +4723,7 @@ function assertDecryptStatusResponseV2(value) {
4685
4723
  }
4686
4724
  return value;
4687
4725
  }
4688
- async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, acp, overallStartTime, retry404TimeoutMs, onPoll) {
4726
+ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, acp, overallStartTime, retry404TimeoutMs, timeoutMs, onPoll) {
4689
4727
  const body = {
4690
4728
  ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
4691
4729
  host_chain_id: chainId
@@ -4792,7 +4830,7 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, acp,
4792
4830
  status: responseClassification.status,
4793
4831
  elapsedMs,
4794
4832
  retry404TimeoutMs,
4795
- overallTimeoutMs: DECRYPT_TIMEOUT_MS,
4833
+ overallTimeoutMs: timeoutMs,
4796
4834
  thresholdNetworkUrl,
4797
4835
  body,
4798
4836
  attemptIndex,
@@ -4804,13 +4842,13 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, acp,
4804
4842
  attemptIndex,
4805
4843
  elapsedMs,
4806
4844
  intervalMs: SUBMIT_RETRY_INTERVAL_MS2,
4807
- timeoutMs: DECRYPT_TIMEOUT_MS
4845
+ timeoutMs
4808
4846
  });
4809
4847
  await new Promise((resolve) => setTimeout(resolve, SUBMIT_RETRY_INTERVAL_MS2));
4810
4848
  attemptIndex += 1;
4811
4849
  }
4812
4850
  }
4813
- async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartTime, onPoll) {
4851
+ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartTime, timeoutMs, onPoll) {
4814
4852
  let attemptIndex = 0;
4815
4853
  while (true) {
4816
4854
  const elapsedMs = Date.now() - overallStartTime;
@@ -4824,17 +4862,17 @@ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartT
4824
4862
  attemptIndex,
4825
4863
  elapsedMs,
4826
4864
  intervalMs,
4827
- timeoutMs: DECRYPT_TIMEOUT_MS
4865
+ timeoutMs
4828
4866
  });
4829
- if (elapsedMs > DECRYPT_TIMEOUT_MS) {
4867
+ if (elapsedMs > timeoutMs) {
4830
4868
  throw new CofheError({
4831
4869
  code: "DECRYPT_FAILED" /* DecryptFailed */,
4832
- message: `decrypt polling timed out after ${DECRYPT_TIMEOUT_MS}ms`,
4870
+ message: `decrypt polling timed out after ${timeoutMs}ms`,
4833
4871
  hint: "The request may still be processing. Try again later.",
4834
4872
  context: {
4835
4873
  thresholdNetworkUrl,
4836
4874
  requestId,
4837
- timeoutMs: DECRYPT_TIMEOUT_MS
4875
+ timeoutMs
4838
4876
  }
4839
4877
  });
4840
4878
  }
@@ -4923,6 +4961,7 @@ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartT
4923
4961
  }
4924
4962
  async function tnDecryptV2(params) {
4925
4963
  const { thresholdNetworkUrl, ctHash, chainId, acp, retry404TimeoutMs, onPoll } = params;
4964
+ const timeoutMs = params.timeoutMs ?? DEFAULT_DECRYPT_TIMEOUT_MS;
4926
4965
  const normalized404RetryTimeoutMs = normalize404RetryTimeoutMs({
4927
4966
  timeoutMs: retry404TimeoutMs,
4928
4967
  operationLabel: "decrypt",
@@ -4936,12 +4975,13 @@ async function tnDecryptV2(params) {
4936
4975
  acp,
4937
4976
  overallStartTime,
4938
4977
  normalized404RetryTimeoutMs,
4978
+ timeoutMs,
4939
4979
  onPoll
4940
4980
  );
4941
4981
  if (submitResult.kind === "completed") {
4942
4982
  return submitResult;
4943
4983
  }
4944
- return await pollDecryptStatusV2(thresholdNetworkUrl, submitResult.requestId, overallStartTime, onPoll);
4984
+ return await pollDecryptStatusV2(thresholdNetworkUrl, submitResult.requestId, overallStartTime, timeoutMs, onPoll);
4945
4985
  }
4946
4986
 
4947
4987
  // core/decrypt/decryptForTxBuilder.ts
@@ -4953,6 +4993,7 @@ var DecryptForTxBuilder = class extends BaseBuilder {
4953
4993
  acpSelection = "unset";
4954
4994
  pollCallback;
4955
4995
  retry404TimeoutMs = DEFAULT_404_RETRY_TIMEOUT_MS3;
4996
+ timeoutMs;
4956
4997
  constructor(params) {
4957
4998
  super({
4958
4999
  config: params.config,
@@ -4995,6 +5036,11 @@ var DecryptForTxBuilder = class extends BaseBuilder {
4995
5036
  this.retry404TimeoutMs = timeoutMs;
4996
5037
  return this;
4997
5038
  }
5039
+ setTimeout(timeoutMs) {
5040
+ assertDecryptTimeoutMs(timeoutMs, "decryptForTx");
5041
+ this.timeoutMs = timeoutMs;
5042
+ return this;
5043
+ }
4998
5044
  withACP(acpOrACPHash) {
4999
5045
  if (this.acpSelection === "with-acp") {
5000
5046
  throw new CofheError({
@@ -5128,6 +5174,7 @@ var DecryptForTxBuilder = class extends BaseBuilder {
5128
5174
  acp: wireAcp,
5129
5175
  thresholdNetworkUrl,
5130
5176
  retry404TimeoutMs: this.retry404TimeoutMs,
5177
+ timeoutMs: this.timeoutMs,
5131
5178
  onPoll: this.pollCallback
5132
5179
  });
5133
5180
  return {