@cofhe/sdk 1.0.1 → 1.1.0-alpha.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.
Files changed (41) hide show
  1. package/CHANGELOG.md +0 -8
  2. package/core/acps.ts +64 -23
  3. package/core/client.ts +32 -1
  4. package/core/clientTypes.ts +22 -1
  5. package/core/decrypt/decryptForTxBuilder.ts +16 -0
  6. package/core/decrypt/decryptForViewBuilder.ts +14 -0
  7. package/core/decrypt/submitRetry.ts +16 -0
  8. package/core/decrypt/tnDecryptV2.ts +19 -9
  9. package/core/decrypt/tnSealOutputV2.ts +19 -9
  10. package/core/encrypt/encryptInputsBuilder.ts +13 -31
  11. package/core/encrypt/zkPackProveVerify.ts +4 -16
  12. package/core/error.ts +0 -1
  13. package/core/test/acpsPrepare.test.ts +77 -0
  14. package/core/test/decryptBuilders.test.ts +51 -0
  15. package/core/test/encryptInputsBuilder.test.ts +4 -56
  16. package/dist/acps.d.cts +4 -358
  17. package/dist/acps.d.ts +4 -358
  18. package/dist/acps.js +2 -2
  19. package/dist/{chunk-WAA2U7CT.js → chunk-3L2IVPMI.js} +1 -1
  20. package/dist/{chunk-OC5TGQGG.js → chunk-J23FYAI2.js} +0 -1
  21. package/dist/{chunk-GKEJHZ52.js → chunk-VE7DKXSF.js} +132 -75
  22. package/dist/{chunk-3SD2UCRE.js → chunk-WJGTPW7K.js} +1 -1
  23. package/dist/{clientTypes-DEKYh0cw.d.ts → clientTypes-B-qOZCx0.d.ts} +55 -7
  24. package/dist/{clientTypes-C2b_qub5.d.cts → clientTypes-D2djRDoH.d.cts} +55 -7
  25. package/dist/core.cjs +128 -72
  26. package/dist/core.d.cts +3 -4
  27. package/dist/core.d.ts +3 -4
  28. package/dist/core.js +4 -4
  29. package/dist/node.cjs +128 -71
  30. package/dist/node.d.cts +2 -2
  31. package/dist/node.d.ts +2 -2
  32. package/dist/node.js +4 -4
  33. package/dist/{onchain-utils-CgOslubH.d.ts → onchain-utils-Ns56cBm0.d.cts} +356 -2
  34. package/dist/{onchain-utils-CgOslubH.d.cts → onchain-utils-Ns56cBm0.d.ts} +356 -2
  35. package/dist/web.cjs +128 -71
  36. package/dist/web.d.cts +2 -2
  37. package/dist/web.d.ts +2 -2
  38. package/dist/web.js +4 -4
  39. package/dist/zkProve.worker.js +2 -2
  40. package/package.json +1 -1
  41. package/core/test/zkPoKMetadata.test.ts +0 -27
@@ -1,9 +1,9 @@
1
1
  import { hardhat as hardhat$1 } from './chunk-UKQAJK4N.js';
2
- import { acpStore, clearAclServedAddresses, getAclServedAddresses, computeShareId, ACPUtils, getTaskManagerAddress, verifyShareLabels, decodeShareMetadata, shareAppKey, ACP_SHARE_REGISTRY_ABI, readShare, readSharesFor, toChainShare, ACP_REVOKER_ABI, decodeShareAppKey, encodeShareMetadata } from './chunk-WAA2U7CT.js';
3
- import { sleep, getPublicClientChainID, getWalletClientAccount, validateBigIntInRange, toBigIntOrThrow, hexToBytes, toHexString, FheUintUTypes } from './chunk-3SD2UCRE.js';
4
- import { TFHE_RS_KEY_VERSION, CofheError, TFHE_RS_ZK_MAX_BITS, TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT, MOCKS_THRESHOLD_NETWORK_ADDRESS, MOCKS_DECRYPT_RESULT_SIGNER_PRIVATE_KEY, MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY, MOCKS_ZK_VERIFIER_ADDRESS } from './chunk-OC5TGQGG.js';
2
+ import { acpStore, clearAclServedAddresses, getAclServedAddresses, computeShareId, ACP_SHARE_REGISTRY_ABI, ACPUtils, getTaskManagerAddress, verifyShareLabels, decodeShareMetadata, shareAppKey, readShare, readSharesFor, toChainShare, ACP_REVOKER_ABI, decodeShareAppKey, encodeShareMetadata } from './chunk-3L2IVPMI.js';
3
+ import { sleep, getPublicClientChainID, getWalletClientAccount, validateBigIntInRange, toBigIntOrThrow, hexToBytes, toHexString, FheUintUTypes } from './chunk-WJGTPW7K.js';
4
+ import { TFHE_RS_KEY_VERSION, CofheError, TFHE_RS_ZK_MAX_BITS, TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT, MOCKS_THRESHOLD_NETWORK_ADDRESS, MOCKS_DECRYPT_RESULT_SIGNER_PRIVATE_KEY, MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY, MOCKS_ZK_VERIFIER_ADDRESS } from './chunk-J23FYAI2.js';
5
5
  import { createStore } from 'zustand/vanilla';
6
- import { parseAbi, isAddress, isAddressEqual, zeroAddress, recoverAddress, encodePacked, keccak256, createWalletClient, http, getAddress, parseSignature, serializeSignature } from 'viem';
6
+ import { parseAbi, isAddressEqual, zeroAddress, recoverAddress, encodePacked, keccak256, createWalletClient, http, getAddress, parseSignature, serializeSignature } from 'viem';
7
7
  import { hardhat } from 'viem/chains';
8
8
  import { sign, privateKeyToAccount } from 'viem/accounts';
9
9
  import { z } from 'zod';
@@ -110,22 +110,19 @@ var zkProve = async (builder, crs, metadata) => {
110
110
  }, 0);
111
111
  });
112
112
  };
113
- var constructZkPoKMetadata = (accountAddr, securityZone, chainId, consumingContract) => {
113
+ var constructZkPoKMetadata = (accountAddr, securityZone, chainId) => {
114
114
  const accountAddrNoPrefix = accountAddr.startsWith("0x") ? accountAddr.slice(2) : accountAddr;
115
115
  const accountBytes = hexToBytes(accountAddrNoPrefix);
116
- const contractNoPrefix = consumingContract.startsWith("0x") ? consumingContract.slice(2) : consumingContract;
117
- const contractBytes = hexToBytes(contractNoPrefix);
118
116
  const chainIdBytes = new Uint8Array(32);
119
117
  let value = chainId;
120
118
  for (let i = 31; i >= 0 && value > 0; i--) {
121
119
  chainIdBytes[i] = value & 255;
122
120
  value = value >>> 8;
123
121
  }
124
- const metadata = new Uint8Array(1 + accountBytes.length + 32 + contractBytes.length);
122
+ const metadata = new Uint8Array(1 + accountBytes.length + 32);
125
123
  metadata[0] = securityZone;
126
124
  metadata.set(accountBytes, 1);
127
125
  metadata.set(chainIdBytes, 1 + accountBytes.length);
128
- metadata.set(contractBytes, 1 + accountBytes.length + 32);
129
126
  return metadata;
130
127
  };
131
128
  var zkVerifyBatch = async (verifierUrl, serializedBytes, address, securityZone, chainId, consumingContract) => {
@@ -1005,33 +1002,20 @@ var EncryptInputsBuilder = class extends BaseBuilder {
1005
1002
  return this.consumingContract;
1006
1003
  }
1007
1004
  /**
1008
- * Asserts that this.consumingContract is populated and is an address.
1009
- * Runs before TFHE init, key fetching and proving, so a bad address costs
1010
- * nothing: the contract is bound into the proof, and a proof built for a
1011
- * non-address could only fail at the verifier, after the expensive step.
1012
- * @throws {CofheError} If consumingContract is not set or is not an address
1005
+ * Asserts that this.consumingContract is populated
1006
+ * @throws {CofheError} If consumingContract is not set
1013
1007
  */
1014
1008
  assertConsumingContract() {
1015
- if (!this.consumingContract) {
1016
- throw new CofheError({
1017
- code: "CONSUMING_CONTRACT_UNINITIALIZED" /* ConsumingContractUninitialized */,
1018
- message: "Consuming contract is not set",
1019
- hint: "Use setConsumingContract(...) to set the contract that will consume the encrypted inputs.",
1020
- context: {
1021
- consumingContract: this.consumingContract
1022
- }
1023
- });
1024
- }
1025
- if (!isAddress(this.consumingContract, { strict: false })) {
1026
- throw new CofheError({
1027
- code: "CONSUMING_CONTRACT_INVALID" /* ConsumingContractInvalid */,
1028
- message: "Consuming contract is not an address",
1029
- hint: "setConsumingContract(...) takes the 20-byte address of the contract that will consume the encrypted inputs.",
1030
- context: {
1031
- consumingContract: this.consumingContract
1032
- }
1033
- });
1034
- }
1009
+ if (this.consumingContract)
1010
+ return;
1011
+ throw new CofheError({
1012
+ code: "CONSUMING_CONTRACT_UNINITIALIZED" /* ConsumingContractUninitialized */,
1013
+ message: "Consuming contract is not set",
1014
+ hint: "Use setConsumingContract(...) to set the contract that will consume the encrypted inputs.",
1015
+ context: {
1016
+ consumingContract: this.consumingContract
1017
+ }
1018
+ });
1035
1019
  }
1036
1020
  setUseWorker(useWorker) {
1037
1021
  this.useWorker = useWorker;
@@ -1247,7 +1231,7 @@ var EncryptInputsBuilder = class extends BaseBuilder {
1247
1231
  zkBuilder = zkPack(this.inputItems, zkBuilder);
1248
1232
  this.fireStepEnd("pack" /* Pack */);
1249
1233
  this.fireStepStart("prove" /* Prove */);
1250
- const metadata = constructZkPoKMetadata(this.account, this.securityZone, this.chainId, this.consumingContract);
1234
+ const metadata = constructZkPoKMetadata(this.account, this.securityZone, this.chainId);
1251
1235
  let proof = null;
1252
1236
  let usedWorker = false;
1253
1237
  let workerFailedError;
@@ -1425,23 +1409,25 @@ var getBlockRevokerData = async (publicClient) => {
1425
1409
  }
1426
1410
  return revokerData;
1427
1411
  };
1428
- var revokeACP = async (acp, walletClient) => {
1412
+ var prepareRevokeACP = (acp) => {
1429
1413
  if (acp.revokerContract === zeroAddress || acp.revokerData === 0) {
1430
1414
  throw new Error("ACP is not revocable: it has no revoker (revokerContract/revokerData unset)");
1431
1415
  }
1416
+ return {
1417
+ address: acp.revokerContract,
1418
+ abi: ACP_REVOKER_ABI,
1419
+ functionName: "revokeSingle",
1420
+ args: [BigInt(acp.revokerData)]
1421
+ };
1422
+ };
1423
+ var revokeACP = async (acp, walletClient) => {
1424
+ const write = prepareRevokeACP(acp);
1432
1425
  if (walletClient.account == null)
1433
1426
  throw new Error("Missing walletClient account");
1434
1427
  if (walletClient.account.address.toLowerCase() !== acp.issuer.toLowerCase()) {
1435
1428
  throw new Error("Only the acp issuer can revoke it");
1436
1429
  }
1437
- return walletClient.writeContract({
1438
- address: acp.revokerContract,
1439
- abi: ACP_REVOKER_ABI,
1440
- functionName: "revokeSingle",
1441
- args: [BigInt(acp.revokerData)],
1442
- account: walletClient.account,
1443
- chain: walletClient.chain
1444
- });
1430
+ return walletClient.writeContract({ ...write, account: walletClient.account, chain: walletClient.chain });
1445
1431
  };
1446
1432
  var revokeAllACPs = async (walletClient, publicClient, revokerContract) => {
1447
1433
  if (walletClient.account == null)
@@ -1492,28 +1478,36 @@ var metadataOf = (acp, { labels, metadata, appKey }) => {
1492
1478
  }
1493
1479
  return encodeShareMetadata(labels, { issuer: acp.issuer, appKey });
1494
1480
  };
1495
- var shareOnChain = async (acp, walletClient, registry, options = {}) => {
1481
+ var prepareShareOnChain = (acp, registry, options = {}) => {
1496
1482
  if (acp.type !== "sharing") {
1497
1483
  throw new Error(`Cannot share a '${acp.type}' ACP on-chain \u2014 only 'sharing' ACPs are shareable.`);
1498
1484
  }
1499
1485
  if (acp.issuerSignature === "0x") {
1500
1486
  throw new Error("Cannot share an unsigned sharing ACP \u2014 sign it first.");
1501
1487
  }
1488
+ return {
1489
+ write: {
1490
+ address: registry,
1491
+ abi: ACP_SHARE_REGISTRY_ABI,
1492
+ functionName: "share",
1493
+ args: [toChainShare(acp), metadataOf(acp, options)]
1494
+ },
1495
+ shareId: computeShareId(acp)
1496
+ };
1497
+ };
1498
+ var shareOnChain = async (acp, walletClient, registry, options = {}) => {
1499
+ const { write, shareId } = prepareShareOnChain(acp, registry, options);
1502
1500
  if (walletClient.account == null)
1503
1501
  throw new Error("Missing walletClient account");
1504
1502
  if (walletClient.account.address.toLowerCase() !== acp.issuer.toLowerCase()) {
1505
1503
  throw new Error("Only the ACP issuer can share it on-chain");
1506
1504
  }
1507
- const metadata = metadataOf(acp, options);
1508
1505
  const txHash = await walletClient.writeContract({
1509
- address: registry,
1510
- abi: ACP_SHARE_REGISTRY_ABI,
1511
- functionName: "share",
1512
- args: [toChainShare(acp), metadata],
1506
+ ...write,
1513
1507
  account: walletClient.account,
1514
1508
  chain: walletClient.chain ?? null
1515
1509
  });
1516
- return { txHash, shareId: computeShareId(acp) };
1510
+ return { txHash, shareId };
1517
1511
  };
1518
1512
  var toIncomingShare = ({ shareId, share: s, metadata }) => ({
1519
1513
  shareId,
@@ -1548,14 +1542,17 @@ var importFromChain = async (share, publicClient, walletClient, importOptions =
1548
1542
  const { shareId: _shareId, appKey: _appKey, ...options } = share;
1549
1543
  return importShared({ ...options, type: "sharing" }, publicClient, walletClient, importOptions);
1550
1544
  };
1545
+ var prepareRemoveShare = (shareId, registry) => ({
1546
+ address: registry,
1547
+ abi: ACP_SHARE_REGISTRY_ABI,
1548
+ functionName: "removeShare",
1549
+ args: [shareId]
1550
+ });
1551
1551
  var removeShareOnChain = async (shareId, walletClient, registry) => {
1552
1552
  if (walletClient.account == null)
1553
1553
  throw new Error("Missing walletClient account");
1554
1554
  return walletClient.writeContract({
1555
- address: registry,
1556
- abi: ACP_SHARE_REGISTRY_ABI,
1557
- functionName: "removeShare",
1558
- args: [shareId],
1555
+ ...prepareRemoveShare(shareId, registry),
1559
1556
  account: walletClient.account,
1560
1557
  chain: walletClient.chain ?? null
1561
1558
  });
@@ -1582,14 +1579,17 @@ var acps = {
1582
1579
  selectActiveACP,
1583
1580
  removeActiveACP,
1584
1581
  revokeACP,
1582
+ prepareRevokeACP,
1585
1583
  revokeAllACPs,
1586
1584
  isACPRevoked,
1587
1585
  checkAccess,
1588
1586
  shareOnChain,
1587
+ prepareShareOnChain,
1589
1588
  getIncomingShares,
1590
1589
  getShareFromChain,
1591
1590
  importFromChain,
1592
1591
  removeShareOnChain,
1592
+ prepareRemoveShare,
1593
1593
  computeShareId,
1594
1594
  applyACPDefaultsFromChain,
1595
1595
  getAclServedAddresses,
@@ -1929,6 +1929,16 @@ function mapApiErrorCodeToCofheErrorCode(apiErrorCode, fallback) {
1929
1929
 
1930
1930
  // core/decrypt/submitRetry.ts
1931
1931
  var DEFAULT_404_RETRY_TIMEOUT_MS = 1e4;
1932
+ var DEFAULT_DECRYPT_TIMEOUT_MS = 5 * 60 * 1e3;
1933
+ function assertDecryptTimeoutMs(timeoutMs, operationLabel) {
1934
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
1935
+ throw new CofheError({
1936
+ code: "INTERNAL_ERROR" /* InternalError */,
1937
+ message: `${operationLabel}: setTimeout(timeoutMs) expects a finite number greater than 0.`,
1938
+ context: { timeoutMs }
1939
+ });
1940
+ }
1941
+ }
1932
1942
  function normalize404RetryTimeoutMs(params) {
1933
1943
  const { timeoutMs, operationLabel, errorCode } = params;
1934
1944
  if (timeoutMs === void 0)
@@ -2067,7 +2077,6 @@ function parseDecryptedBytesToBigInt(decrypted) {
2067
2077
  // core/decrypt/tnSealOutputV2.ts
2068
2078
  var POLL_INTERVAL_MS = 1e3;
2069
2079
  var POLL_MAX_INTERVAL_MS = 1e4;
2070
- var SEAL_OUTPUT_TIMEOUT_MS = 5 * 60 * 1e3;
2071
2080
  var SUBMIT_RETRY_INTERVAL_MS = 1e3;
2072
2081
  function numberArrayToUint8Array(arr) {
2073
2082
  return new Uint8Array(arr);
@@ -2125,7 +2134,7 @@ function parseCompletedSealOutputResponse(params) {
2125
2134
  }
2126
2135
  return convertSealedData(sealed);
2127
2136
  }
2128
- async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, acp, overallStartTime, retry404TimeoutMs, onPoll) {
2137
+ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, acp, overallStartTime, retry404TimeoutMs, timeoutMs, onPoll) {
2129
2138
  const body = {
2130
2139
  ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
2131
2140
  host_chain_id: chainId,
@@ -2228,7 +2237,7 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, acp
2228
2237
  status: responseClassification.status,
2229
2238
  elapsedMs,
2230
2239
  retry404TimeoutMs,
2231
- overallTimeoutMs: SEAL_OUTPUT_TIMEOUT_MS,
2240
+ overallTimeoutMs: timeoutMs,
2232
2241
  thresholdNetworkUrl,
2233
2242
  body,
2234
2243
  attemptIndex,
@@ -2240,13 +2249,13 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, acp
2240
2249
  attemptIndex,
2241
2250
  elapsedMs,
2242
2251
  intervalMs: SUBMIT_RETRY_INTERVAL_MS,
2243
- timeoutMs: SEAL_OUTPUT_TIMEOUT_MS
2252
+ timeoutMs
2244
2253
  });
2245
2254
  await new Promise((resolve) => setTimeout(resolve, SUBMIT_RETRY_INTERVAL_MS));
2246
2255
  attemptIndex += 1;
2247
2256
  }
2248
2257
  }
2249
- async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStartTime, onPoll) {
2258
+ async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStartTime, timeoutMs, onPoll) {
2250
2259
  let attemptIndex = 0;
2251
2260
  while (true) {
2252
2261
  const elapsedMs = Date.now() - overallStartTime;
@@ -2260,17 +2269,17 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStart
2260
2269
  attemptIndex,
2261
2270
  elapsedMs,
2262
2271
  intervalMs,
2263
- timeoutMs: SEAL_OUTPUT_TIMEOUT_MS
2272
+ timeoutMs
2264
2273
  });
2265
- if (elapsedMs > SEAL_OUTPUT_TIMEOUT_MS) {
2274
+ if (elapsedMs > timeoutMs) {
2266
2275
  throw new CofheError({
2267
2276
  code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
2268
- message: `sealOutput polling timed out after ${SEAL_OUTPUT_TIMEOUT_MS}ms`,
2277
+ message: `sealOutput polling timed out after ${timeoutMs}ms`,
2269
2278
  hint: "The request may still be processing. Try again later.",
2270
2279
  context: {
2271
2280
  thresholdNetworkUrl,
2272
2281
  requestId,
2273
- timeoutMs: SEAL_OUTPUT_TIMEOUT_MS
2282
+ timeoutMs
2274
2283
  }
2275
2284
  });
2276
2285
  }
@@ -2358,6 +2367,7 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStart
2358
2367
  }
2359
2368
  async function tnSealOutputV2(params) {
2360
2369
  const { thresholdNetworkUrl, ctHash, chainId, acp, retry404TimeoutMs, onPoll } = params;
2370
+ const timeoutMs = params.timeoutMs ?? DEFAULT_DECRYPT_TIMEOUT_MS;
2361
2371
  const normalized404RetryTimeoutMs = normalize404RetryTimeoutMs({
2362
2372
  timeoutMs: retry404TimeoutMs,
2363
2373
  operationLabel: "sealOutput",
@@ -2371,12 +2381,13 @@ async function tnSealOutputV2(params) {
2371
2381
  acp,
2372
2382
  overallStartTime,
2373
2383
  normalized404RetryTimeoutMs,
2384
+ timeoutMs,
2374
2385
  onPoll
2375
2386
  );
2376
2387
  if (submitResult.kind === "completed") {
2377
2388
  return submitResult.sealed;
2378
2389
  }
2379
- return await pollSealOutputStatus(thresholdNetworkUrl, submitResult.requestId, overallStartTime, onPoll);
2390
+ return await pollSealOutputStatus(thresholdNetworkUrl, submitResult.requestId, overallStartTime, timeoutMs, onPoll);
2380
2391
  }
2381
2392
 
2382
2393
  // core/decrypt/decryptForViewBuilder.ts
@@ -2388,6 +2399,7 @@ var DecryptForViewBuilder = class extends BaseBuilder {
2388
2399
  acp;
2389
2400
  pollCallback;
2390
2401
  retry404TimeoutMs = DEFAULT_404_RETRY_TIMEOUT_MS2;
2402
+ timeoutMs;
2391
2403
  constructor(params) {
2392
2404
  super({
2393
2405
  config: params.config,
@@ -2461,6 +2473,16 @@ var DecryptForViewBuilder = class extends BaseBuilder {
2461
2473
  this.retry404TimeoutMs = timeoutMs;
2462
2474
  return this;
2463
2475
  }
2476
+ /**
2477
+ * The whole budget of this decrypt in milliseconds, submit retries and status polling together
2478
+ * (5 minutes by default). Past it, `execute()` rejects with `SealOutputFailed`; a request still
2479
+ * processing on the threshold network is not cancelled.
2480
+ */
2481
+ setTimeout(timeoutMs) {
2482
+ assertDecryptTimeoutMs(timeoutMs, "decryptForView");
2483
+ this.timeoutMs = timeoutMs;
2484
+ return this;
2485
+ }
2464
2486
  withACP(acpOrACPHash) {
2465
2487
  if (typeof acpOrACPHash === "string") {
2466
2488
  this.acpHash = acpOrACPHash;
@@ -2590,6 +2612,7 @@ var DecryptForViewBuilder = class extends BaseBuilder {
2590
2612
  acp: wireAcp,
2591
2613
  thresholdNetworkUrl,
2592
2614
  retry404TimeoutMs: this.retry404TimeoutMs,
2615
+ timeoutMs: this.timeoutMs,
2593
2616
  onPoll: this.pollCallback
2594
2617
  });
2595
2618
  return ACPUtils.unseal(acp, sealed);
@@ -2692,7 +2715,6 @@ async function cofheMocksDecryptForTx(ctHash, utype, acp, publicClient) {
2692
2715
  // core/decrypt/tnDecryptV2.ts
2693
2716
  var POLL_INTERVAL_MS2 = 1e3;
2694
2717
  var POLL_MAX_INTERVAL_MS2 = 1e4;
2695
- var DECRYPT_TIMEOUT_MS = 5 * 60 * 1e3;
2696
2718
  var SUBMIT_RETRY_INTERVAL_MS2 = 1e3;
2697
2719
  function assertDecryptSubmitResponseV2(value) {
2698
2720
  if (value == null || typeof value !== "object") {
@@ -2809,7 +2831,7 @@ function assertDecryptStatusResponseV2(value) {
2809
2831
  }
2810
2832
  return value;
2811
2833
  }
2812
- async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, acp, overallStartTime, retry404TimeoutMs, onPoll) {
2834
+ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, acp, overallStartTime, retry404TimeoutMs, timeoutMs, onPoll) {
2813
2835
  const body = {
2814
2836
  ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
2815
2837
  host_chain_id: chainId
@@ -2916,7 +2938,7 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, acp,
2916
2938
  status: responseClassification.status,
2917
2939
  elapsedMs,
2918
2940
  retry404TimeoutMs,
2919
- overallTimeoutMs: DECRYPT_TIMEOUT_MS,
2941
+ overallTimeoutMs: timeoutMs,
2920
2942
  thresholdNetworkUrl,
2921
2943
  body,
2922
2944
  attemptIndex,
@@ -2928,13 +2950,13 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, acp,
2928
2950
  attemptIndex,
2929
2951
  elapsedMs,
2930
2952
  intervalMs: SUBMIT_RETRY_INTERVAL_MS2,
2931
- timeoutMs: DECRYPT_TIMEOUT_MS
2953
+ timeoutMs
2932
2954
  });
2933
2955
  await new Promise((resolve) => setTimeout(resolve, SUBMIT_RETRY_INTERVAL_MS2));
2934
2956
  attemptIndex += 1;
2935
2957
  }
2936
2958
  }
2937
- async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartTime, onPoll) {
2959
+ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartTime, timeoutMs, onPoll) {
2938
2960
  let attemptIndex = 0;
2939
2961
  while (true) {
2940
2962
  const elapsedMs = Date.now() - overallStartTime;
@@ -2948,17 +2970,17 @@ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartT
2948
2970
  attemptIndex,
2949
2971
  elapsedMs,
2950
2972
  intervalMs,
2951
- timeoutMs: DECRYPT_TIMEOUT_MS
2973
+ timeoutMs
2952
2974
  });
2953
- if (elapsedMs > DECRYPT_TIMEOUT_MS) {
2975
+ if (elapsedMs > timeoutMs) {
2954
2976
  throw new CofheError({
2955
2977
  code: "DECRYPT_FAILED" /* DecryptFailed */,
2956
- message: `decrypt polling timed out after ${DECRYPT_TIMEOUT_MS}ms`,
2978
+ message: `decrypt polling timed out after ${timeoutMs}ms`,
2957
2979
  hint: "The request may still be processing. Try again later.",
2958
2980
  context: {
2959
2981
  thresholdNetworkUrl,
2960
2982
  requestId,
2961
- timeoutMs: DECRYPT_TIMEOUT_MS
2983
+ timeoutMs
2962
2984
  }
2963
2985
  });
2964
2986
  }
@@ -3047,6 +3069,7 @@ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartT
3047
3069
  }
3048
3070
  async function tnDecryptV2(params) {
3049
3071
  const { thresholdNetworkUrl, ctHash, chainId, acp, retry404TimeoutMs, onPoll } = params;
3072
+ const timeoutMs = params.timeoutMs ?? DEFAULT_DECRYPT_TIMEOUT_MS;
3050
3073
  const normalized404RetryTimeoutMs = normalize404RetryTimeoutMs({
3051
3074
  timeoutMs: retry404TimeoutMs,
3052
3075
  operationLabel: "decrypt",
@@ -3060,12 +3083,13 @@ async function tnDecryptV2(params) {
3060
3083
  acp,
3061
3084
  overallStartTime,
3062
3085
  normalized404RetryTimeoutMs,
3086
+ timeoutMs,
3063
3087
  onPoll
3064
3088
  );
3065
3089
  if (submitResult.kind === "completed") {
3066
3090
  return submitResult;
3067
3091
  }
3068
- return await pollDecryptStatusV2(thresholdNetworkUrl, submitResult.requestId, overallStartTime, onPoll);
3092
+ return await pollDecryptStatusV2(thresholdNetworkUrl, submitResult.requestId, overallStartTime, timeoutMs, onPoll);
3069
3093
  }
3070
3094
 
3071
3095
  // core/decrypt/decryptForTxBuilder.ts
@@ -3077,6 +3101,7 @@ var DecryptForTxBuilder = class extends BaseBuilder {
3077
3101
  acpSelection = "unset";
3078
3102
  pollCallback;
3079
3103
  retry404TimeoutMs = DEFAULT_404_RETRY_TIMEOUT_MS3;
3104
+ timeoutMs;
3080
3105
  constructor(params) {
3081
3106
  super({
3082
3107
  config: params.config,
@@ -3119,6 +3144,11 @@ var DecryptForTxBuilder = class extends BaseBuilder {
3119
3144
  this.retry404TimeoutMs = timeoutMs;
3120
3145
  return this;
3121
3146
  }
3147
+ setTimeout(timeoutMs) {
3148
+ assertDecryptTimeoutMs(timeoutMs, "decryptForTx");
3149
+ this.timeoutMs = timeoutMs;
3150
+ return this;
3151
+ }
3122
3152
  withACP(acpOrACPHash) {
3123
3153
  if (this.acpSelection === "with-acp") {
3124
3154
  throw new CofheError({
@@ -3252,6 +3282,7 @@ var DecryptForTxBuilder = class extends BaseBuilder {
3252
3282
  acp: wireAcp,
3253
3283
  thresholdNetworkUrl,
3254
3284
  retry404TimeoutMs: this.retry404TimeoutMs,
3285
+ timeoutMs: this.timeoutMs,
3255
3286
  onPoll: this.pollCallback
3256
3287
  });
3257
3288
  return {
@@ -3372,6 +3403,12 @@ function createCofheClientBase(opts) {
3372
3403
  });
3373
3404
  }
3374
3405
  };
3406
+ const _requireIssuer = (acp, what) => {
3407
+ const sender = connectStore.getState().walletClient?.account?.address;
3408
+ if (sender == null || sender.toLowerCase() !== acp.issuer.toLowerCase()) {
3409
+ throw new Error(`Only the acp issuer can ${what}`);
3410
+ }
3411
+ };
3375
3412
  async function connect(publicClient, walletClient) {
3376
3413
  const state = connectStore.getState();
3377
3414
  if (state.connected && state.publicClient === publicClient && state.walletClient === walletClient)
@@ -3539,6 +3576,11 @@ function createCofheClientBase(opts) {
3539
3576
  const { walletClient } = connectStore.getState();
3540
3577
  return acps.revokeACP(acp, walletClient);
3541
3578
  },
3579
+ prepareRevokeACP: (acp) => {
3580
+ _requireConnected();
3581
+ _requireIssuer(acp, "revoke it");
3582
+ return acps.prepareRevokeACP(acp);
3583
+ },
3542
3584
  revokeAllACPs: async (revokerContract) => {
3543
3585
  _requireConnected();
3544
3586
  const { publicClient, walletClient } = connectStore.getState();
@@ -3562,6 +3604,21 @@ function createCofheClientBase(opts) {
3562
3604
  const sharingRegistry = await _resolveSharingRegistry(publicClient, chainId);
3563
3605
  return acps.shareOnChain(acp, walletClient, sharingRegistry, { ...withAppKey(), ...options });
3564
3606
  },
3607
+ prepareShareOnChain: async (acp, options) => {
3608
+ _requireConnected();
3609
+ _requireIssuer(acp, "share it on-chain");
3610
+ const { publicClient } = connectStore.getState();
3611
+ const chainId = await publicClient.getChainId();
3612
+ const sharingRegistry = await _resolveSharingRegistry(publicClient, chainId);
3613
+ return acps.prepareShareOnChain(acp, sharingRegistry, { ...withAppKey(), ...options });
3614
+ },
3615
+ prepareRemoveShare: async (shareId) => {
3616
+ _requireConnected();
3617
+ const { publicClient } = connectStore.getState();
3618
+ const chainId = await publicClient.getChainId();
3619
+ const sharingRegistry = await _resolveSharingRegistry(publicClient, chainId);
3620
+ return acps.prepareRemoveShare(shareId, sharingRegistry);
3621
+ },
3565
3622
  getIncomingShares: async () => {
3566
3623
  _requireConnected();
3567
3624
  const { publicClient, walletClient } = connectStore.getState();
@@ -1,4 +1,4 @@
1
- import { CofheError } from './chunk-OC5TGQGG.js';
1
+ import { CofheError } from './chunk-J23FYAI2.js';
2
2
  import 'viem';
3
3
 
4
4
  // core/types.ts
@@ -1,7 +1,7 @@
1
- import { WalletClient, PublicClient, Hex } from 'viem';
1
+ import { WalletClient, PublicClient, Hex, ContractFunctionParameters } from 'viem';
2
2
  import { C as CofheChain } from './types-C07FK-cL.js';
3
3
  import { z } from 'zod';
4
- import { A as ACP, k as EIP712Domain, C as CreateSelfACPOptions, J as SelfACP, g as CreateSharingACPOptions, K as SharingACP, I as ImportSharedACPOptions, R as RecipientACP, P as ACPHashFields, f as SerializedACP, O as ACPAccessStatus, S as ShareLabel, j as IncomingShare, p as AclServedAddresses, L as LabelledShare, w as ShareLabelVerifyMode, x as ShareLabelCheck, l as ACPUtils } from './onchain-utils-CgOslubH.js';
4
+ import { A as ACP, k as EIP712Domain, C as CreateSelfACPOptions, $ as SelfACP, g as CreateSharingACPOptions, a0 as SharingACP, I as ImportSharedACPOptions, a1 as RecipientACP, a5 as ACPHashFields, f as SerializedACP, t as ACP_REVOKER_ABI, a4 as ACPAccessStatus, S as ShareLabel, v as ACP_SHARE_REGISTRY_ABI, j as IncomingShare, p as AclServedAddresses, L as LabelledShare, Q as ShareLabelVerifyMode, R as ShareLabelCheck, l as ACPUtils } from './onchain-utils-Ns56cBm0.js';
5
5
  import { StoreApi } from 'zustand/vanilla';
6
6
 
7
7
  type TfheInitializer = () => Promise<boolean>;
@@ -465,6 +465,7 @@ declare class DecryptForViewBuilder<U extends FheTypes> extends BaseBuilder {
465
465
  private acp?;
466
466
  private pollCallback?;
467
467
  private retry404TimeoutMs;
468
+ private timeoutMs?;
468
469
  constructor(params: DecryptForViewBuilderParams<U>);
469
470
  /**
470
471
  * @param chainId - Chain to decrypt values from. Used to fetch the threshold network URL and use the correct acp.
@@ -500,6 +501,12 @@ declare class DecryptForViewBuilder<U extends FheTypes> extends BaseBuilder {
500
501
  getAccount(): string | undefined;
501
502
  onPoll(callback: DecryptPollCallbackFunction): DecryptForViewBuilder<U>;
502
503
  set404RetryTimeout(timeoutMs: number): DecryptForViewBuilder<U>;
504
+ /**
505
+ * The whole budget of this decrypt in milliseconds, submit retries and status polling together
506
+ * (5 minutes by default). Past it, `execute()` rejects with `SealOutputFailed`; a request still
507
+ * processing on the threshold network is not cancelled.
508
+ */
509
+ setTimeout(timeoutMs: number): DecryptForViewBuilder<U>;
503
510
  /**
504
511
  * Select "use acp" mode (optional).
505
512
  *
@@ -603,6 +610,7 @@ declare class DecryptForTxBuilder extends BaseBuilder {
603
610
  private acpSelection;
604
611
  private pollCallback?;
605
612
  private retry404TimeoutMs;
613
+ private timeoutMs?;
606
614
  constructor(params: DecryptForTxBuilderParams);
607
615
  /**
608
616
  * @param chainId - Chain to decrypt values from. Used to fetch the threshold network URL and use the correct acp.
@@ -642,6 +650,13 @@ declare class DecryptForTxBuilder extends BaseBuilder {
642
650
  onPoll(this: DecryptForTxBuilderSelected, callback: DecryptPollCallbackFunction): DecryptForTxBuilderSelected;
643
651
  set404RetryTimeout(this: DecryptForTxBuilderUnset, timeoutMs: number): DecryptForTxBuilderUnset;
644
652
  set404RetryTimeout(this: DecryptForTxBuilderSelected, timeoutMs: number): DecryptForTxBuilderSelected;
653
+ /**
654
+ * The whole budget of this decrypt in milliseconds, submit retries and status polling together
655
+ * (5 minutes by default). Past it, `execute()` rejects with `DecryptFailed`; a request still
656
+ * processing on the threshold network is not cancelled.
657
+ */
658
+ setTimeout(this: DecryptForTxBuilderUnset, timeoutMs: number): DecryptForTxBuilderUnset;
659
+ setTimeout(this: DecryptForTxBuilderSelected, timeoutMs: number): DecryptForTxBuilderSelected;
645
660
  /**
646
661
  * Select "use acp" mode.
647
662
  *
@@ -896,11 +911,8 @@ declare class EncryptInputsBuilder<T extends EncryptableItem[]> extends BaseBuil
896
911
  setConsumingContract(address: string): EncryptInputsBuilder<T>;
897
912
  getConsumingContract(): string | undefined;
898
913
  /**
899
- * Asserts that this.consumingContract is populated and is an address.
900
- * Runs before TFHE init, key fetching and proving, so a bad address costs
901
- * nothing: the contract is bound into the proof, and a proof built for a
902
- * non-address could only fail at the verifier, after the expensive step.
903
- * @throws {CofheError} If consumingContract is not set or is not an address
914
+ * Asserts that this.consumingContract is populated
915
+ * @throws {CofheError} If consumingContract is not set
904
916
  */
905
917
  private assertConsumingContract;
906
918
  /**
@@ -1034,6 +1046,21 @@ type ImportSharedOptions = ImportActivationOptions & {
1034
1046
  */
1035
1047
  name?: string;
1036
1048
  };
1049
+ /**
1050
+ * Revoke a single acp on-chain via its revoker contract.
1051
+ * Only the acp's issuer can revoke it (enforced by the revoker: revocations
1052
+ * are keyed by msg.sender). The acp stays in local storage — on-chain
1053
+ * validation will reject it from the next block onwards.
1054
+ *
1055
+ * @returns the revocation transaction hash
1056
+ */
1057
+ /**
1058
+ * A registry or revoker write built but not sent: what a simulation or `writeContract` takes,
1059
+ * minus the sender. For a caller that sends through its own path (simulate first, record the
1060
+ * transaction) instead of the plain `writeContract` the senders below do.
1061
+ */
1062
+ type ShareRegistryWrite<functionName extends 'share' | 'removeShare'> = ContractFunctionParameters<typeof ACP_SHARE_REGISTRY_ABI, 'nonpayable', functionName>;
1063
+ type RevokerWrite = ContractFunctionParameters<typeof ACP_REVOKER_ABI, 'nonpayable', 'revokeSingle'>;
1037
1064
  /**
1038
1065
  * What `shareOnChain` posts with a share: the labels of its handles (one per handle, in order;
1039
1066
  * encoded with `encodeShareMetadata`), or an already encoded metadata blob. Written once, with the
@@ -1194,6 +1221,7 @@ declare const acps: {
1194
1221
  selectActiveACP: (chainId: number, account: string, hash: string) => void;
1195
1222
  removeActiveACP: (chainId: number, account: string) => Promise<void>;
1196
1223
  revokeACP: (acp: ACP, walletClient: WalletClient) => Promise<Hex>;
1224
+ prepareRevokeACP: (acp: ACP) => RevokerWrite;
1197
1225
  revokeAllACPs: (walletClient: WalletClient, publicClient: PublicClient, revokerContract?: Hex) => Promise<Hex>;
1198
1226
  isACPRevoked: (acp: ACP, publicClient: PublicClient) => Promise<boolean>;
1199
1227
  checkAccess: (acp: ACP, publicClient: PublicClient, handle?: bigint | Hex) => Promise<ACPAccessStatus>;
@@ -1201,12 +1229,17 @@ declare const acps: {
1201
1229
  txHash: Hex;
1202
1230
  shareId: Hex;
1203
1231
  }>;
1232
+ prepareShareOnChain: (acp: ACP, registry: Hex, options?: ShareOnChainOptions) => {
1233
+ write: ShareRegistryWrite<"share">;
1234
+ shareId: Hex;
1235
+ };
1204
1236
  getIncomingShares: (publicClient: PublicClient, registry: Hex, recipient: Hex, { appKey }?: {
1205
1237
  appKey?: Hex;
1206
1238
  }) => Promise<IncomingShare[]>;
1207
1239
  getShareFromChain: (publicClient: PublicClient, registry: Hex, shareId: Hex) => Promise<IncomingShare | null>;
1208
1240
  importFromChain: (share: IncomingShare, publicClient: PublicClient, walletClient: WalletClient, importOptions?: ImportSharedOptions) => Promise<RecipientACP>;
1209
1241
  removeShareOnChain: (shareId: Hex, walletClient: WalletClient, registry: Hex) => Promise<Hex>;
1242
+ prepareRemoveShare: (shareId: Hex, registry: Hex) => ShareRegistryWrite<"removeShare">;
1210
1243
  computeShareId: (acp: ACP) => Hex;
1211
1244
  applyACPDefaultsFromChain: <T extends {
1212
1245
  revokerData?: number;
@@ -1289,6 +1322,11 @@ type CofheClientACPs = {
1289
1322
  removeACP: (hash: string, chainId?: number, account?: string) => void;
1290
1323
  removeActiveACP: (chainId?: number, account?: string) => void;
1291
1324
  revokeACP: (acp: ACP) => Promise<`0x${string}`>;
1325
+ /**
1326
+ * The revoker write `revokeACP` sends, built but not sent — for an app that sends through its own
1327
+ * path (a simulation first, a transaction store). Issuer only; throws for an acp without a revoker.
1328
+ */
1329
+ prepareRevokeACP: (acp: ACP) => RevokerWrite;
1292
1330
  revokeAllACPs: (revokerContract?: `0x${string}`) => Promise<`0x${string}`>;
1293
1331
  isACPRevoked: (acp: ACP) => Promise<boolean>;
1294
1332
  /**
@@ -1306,6 +1344,16 @@ type CofheClientACPs = {
1306
1344
  txHash: `0x${string}`;
1307
1345
  shareId: `0x${string}`;
1308
1346
  }>;
1347
+ /**
1348
+ * The registry write `shareOnChain` sends and the share id it gets, built but not sent — for an
1349
+ * app that sends through its own path (a simulation first, a transaction store). Issuer only.
1350
+ */
1351
+ prepareShareOnChain: (acp: ACP, options?: ShareOnChainOptions) => Promise<{
1352
+ write: ShareRegistryWrite<'share'>;
1353
+ shareId: `0x${string}`;
1354
+ }>;
1355
+ /** The registry write `dismissShare` / `cancelShare` sends, built but not sent. */
1356
+ prepareRemoveShare: (shareId: `0x${string}`) => Promise<ShareRegistryWrite<'removeShare'>>;
1309
1357
  /** Importable shares addressed to the connected account (unexpired, not revoked), with their metadata. */
1310
1358
  getIncomingShares: () => Promise<IncomingShare[]>;
1311
1359
  /** One share by id, as posted; null when unknown or removed. */