@cofhe/sdk 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/acps/acp.ts +411 -0
  3. package/acps/index.ts +70 -0
  4. package/{permits → acps}/onchain-utils.ts +49 -24
  5. package/acps/sealing.ts +90 -0
  6. package/acps/signature.ts +89 -0
  7. package/acps/store.ts +172 -0
  8. package/acps/test/acp.test.ts +615 -0
  9. package/acps/test/localstorage.test.ts +105 -0
  10. package/acps/test/sealing.test.ts +77 -0
  11. package/acps/test/store.test.ts +88 -0
  12. package/acps/test/validation.test.ts +361 -0
  13. package/acps/test-utils.ts +32 -0
  14. package/acps/types.ts +252 -0
  15. package/acps/validation.ts +392 -0
  16. package/adapters/test/ethers5.test.ts +4 -1
  17. package/adapters/test/ethers6.test.ts +4 -1
  18. package/adapters/test/wagmi.test.ts +5 -2
  19. package/chains/chains/stagingCofhe.ts +21 -0
  20. package/chains/index.ts +3 -1
  21. package/chains/test/chains.test.ts +2 -1
  22. package/core/acps.ts +625 -0
  23. package/core/client.ts +136 -39
  24. package/core/clientTypes.ts +52 -41
  25. package/core/config.ts +66 -5
  26. package/core/debug.ts +72 -0
  27. package/core/decrypt/MockThresholdNetworkAbi.ts +20 -11
  28. package/core/decrypt/apiError.ts +104 -0
  29. package/core/decrypt/cofheMocksDecryptForTx.ts +11 -11
  30. package/core/decrypt/cofheMocksDecryptForView.ts +7 -7
  31. package/core/decrypt/decryptForTxBuilder.ts +102 -102
  32. package/core/decrypt/decryptForViewBuilder.ts +90 -90
  33. package/core/decrypt/submitRetry.ts +38 -30
  34. package/core/decrypt/tnDecryptV1.ts +5 -5
  35. package/core/decrypt/tnDecryptV2.ts +45 -34
  36. package/core/decrypt/tnSealOutputV1.ts +4 -3
  37. package/core/decrypt/tnSealOutputV2.ts +44 -31
  38. package/core/encrypt/cofheMocksZkVerifySign.ts +59 -74
  39. package/core/encrypt/encryptInputsBuilder.ts +86 -52
  40. package/core/encrypt/zkPackProveVerify.ts +25 -18
  41. package/core/error.ts +34 -6
  42. package/core/index.ts +14 -14
  43. package/core/test/acpDefaults.test.ts +52 -0
  44. package/core/test/acps.test.ts +596 -0
  45. package/core/test/apiError.test.ts +130 -0
  46. package/core/test/client.test.ts +22 -19
  47. package/core/test/config.test.ts +25 -5
  48. package/core/test/decrypt.test.ts +40 -35
  49. package/core/test/decryptBuilders.test.ts +68 -68
  50. package/core/test/decryptErrorCodes.test.ts +217 -0
  51. package/core/test/encryptInputsBuilder.test.ts +72 -41
  52. package/core/test/pollCallbacks.test.ts +89 -18
  53. package/core/test/stagingRedirect.ts +18 -0
  54. package/core/test/submitRetry.test.ts +182 -0
  55. package/core/types.ts +9 -69
  56. package/dist/acp-Wi6isVQI.d.cts +407 -0
  57. package/dist/acp-Wi6isVQI.d.ts +407 -0
  58. package/dist/acps.cjs +1081 -0
  59. package/dist/acps.d.cts +480 -0
  60. package/dist/acps.d.ts +480 -0
  61. package/dist/acps.js +2 -0
  62. package/dist/chains.cjs +14 -1
  63. package/dist/chains.d.cts +30 -1
  64. package/dist/chains.d.ts +30 -1
  65. package/dist/chains.js +1 -1
  66. package/dist/{chunk-PE5V5CCV.js → chunk-43USWPEH.js} +1000 -604
  67. package/dist/{chunk-MTRAXQXC.js → chunk-N6IDQRRU.js} +14 -2
  68. package/dist/chunk-Q7CBWGQX.js +1029 -0
  69. package/dist/{clientTypes-CyUvRRzA.d.ts → clientTypes-BN3nbzYM.d.ts} +342 -165
  70. package/dist/{clientTypes-BDy1qIBu.d.cts → clientTypes-CYZjFznO.d.cts} +342 -165
  71. package/dist/core.cjs +1431 -1026
  72. package/dist/core.d.cts +55 -10
  73. package/dist/core.d.ts +55 -10
  74. package/dist/core.js +3 -3
  75. package/dist/node.cjs +1356 -976
  76. package/dist/node.d.cts +2 -2
  77. package/dist/node.d.ts +2 -2
  78. package/dist/node.js +3 -3
  79. package/dist/web.cjs +1356 -976
  80. package/dist/web.d.cts +2 -2
  81. package/dist/web.d.ts +2 -2
  82. package/dist/web.js +3 -3
  83. package/node/test/inherited.test.ts +75 -65
  84. package/node/test/tfheinit.test.ts +23 -8
  85. package/package.json +6 -6
  86. package/web/test/client.web.test.ts +5 -1
  87. package/web/test/inherited.web.test.ts +75 -65
  88. package/web/test/tfheinit.web.test.ts +14 -5
  89. package/web/test/worker.config.web.test.ts +38 -23
  90. package/web/test/worker.output.web.test.ts +25 -24
  91. package/core/encrypt/encryptUtils.ts +0 -67
  92. package/core/permits.ts +0 -206
  93. package/core/test/permits.test.ts +0 -534
  94. package/dist/chunk-VB62WYPL.js +0 -978
  95. package/dist/permit-DnVMDT5h.d.cts +0 -376
  96. package/dist/permit-DnVMDT5h.d.ts +0 -376
  97. package/dist/permits.cjs +0 -1026
  98. package/dist/permits.d.cts +0 -353
  99. package/dist/permits.d.ts +0 -353
  100. package/dist/permits.js +0 -2
  101. package/permits/index.ts +0 -68
  102. package/permits/permit.ts +0 -385
  103. package/permits/sealing.ts +0 -131
  104. package/permits/signature.ts +0 -79
  105. package/permits/store.ts +0 -157
  106. package/permits/test/localstorage.test.ts +0 -113
  107. package/permits/test/permit.test.ts +0 -557
  108. package/permits/test/sealing.test.ts +0 -84
  109. package/permits/test/store.test.ts +0 -88
  110. package/permits/test/validation.test.ts +0 -361
  111. package/permits/test-utils.ts +0 -28
  112. package/permits/types.ts +0 -204
  113. package/permits/validation.ts +0 -327
  114. /package/{permits → acps}/utils.ts +0 -0
package/dist/node.cjs CHANGED
@@ -24,7 +24,8 @@ var CofheError = class _CofheError extends Error {
24
24
  cause;
25
25
  hint;
26
26
  context;
27
- constructor({ code, message, cause, hint, context }) {
27
+ apiErrorCode;
28
+ constructor({ code, message, cause, hint, context, apiErrorCode }) {
28
29
  const fullMessage = cause ? `${message} | Caused by: ${cause.message}` : message;
29
30
  super(fullMessage);
30
31
  this.name = "CofheError";
@@ -32,6 +33,7 @@ var CofheError = class _CofheError extends Error {
32
33
  this.cause = cause;
33
34
  this.hint = hint;
34
35
  this.context = context;
36
+ this.apiErrorCode = apiErrorCode;
35
37
  if (Error.captureStackTrace) {
36
38
  Error.captureStackTrace(this, _CofheError);
37
39
  }
@@ -50,6 +52,7 @@ var CofheError = class _CofheError extends Error {
50
52
  message: wrapperError?.message ?? "An internal error occurred",
51
53
  hint: wrapperError?.hint,
52
54
  context: wrapperError?.context,
55
+ apiErrorCode: wrapperError?.apiErrorCode,
53
56
  cause
54
57
  });
55
58
  }
@@ -63,6 +66,7 @@ var CofheError = class _CofheError extends Error {
63
66
  message: this.message,
64
67
  hint: this.hint,
65
68
  context: this.context,
69
+ apiErrorCode: this.apiErrorCode,
66
70
  cause: this.cause ? {
67
71
  name: this.cause.name,
68
72
  message: this.cause.message,
@@ -75,7 +79,8 @@ var CofheError = class _CofheError extends Error {
75
79
  * Returns a human-readable string representation of the error
76
80
  */
77
81
  toString() {
78
- const parts = [`${this.name} [${this.code}]: ${this.message}`];
82
+ const codeSuffix = this.apiErrorCode ? ` (api: ${this.apiErrorCode})` : "";
83
+ const parts = [`${this.name} [${this.code}]${codeSuffix}: ${this.message}`];
79
84
  if (this.hint) {
80
85
  parts.push(`Hint: ${this.hint}`);
81
86
  }
@@ -311,18 +316,19 @@ var constructZkPoKMetadata = (accountAddr, securityZone, chainId) => {
311
316
  metadata.set(chainIdBytes, 1 + accountBytes.length);
312
317
  return metadata;
313
318
  };
314
- var zkVerify = async (verifierUrl, serializedBytes, address, securityZone, chainId) => {
319
+ var zkVerifyBatch = async (verifierUrl, serializedBytes, address, securityZone, chainId, consumingContract) => {
315
320
  const packed_list = toHexString(serializedBytes);
316
321
  const sz_byte = new Uint8Array([securityZone]);
317
322
  const payload = {
318
323
  packed_list,
319
324
  account_addr: address,
320
325
  security_zone: sz_byte[0],
321
- chain_id: chainId
326
+ chain_id: chainId,
327
+ contract_address: consumingContract
322
328
  };
323
329
  const body = JSON.stringify(payload);
324
330
  try {
325
- const response = await fetch(`${verifierUrl}/verify`, {
331
+ const response = await fetch(`${verifierUrl}/verifyBatch`, {
326
332
  method: "POST",
327
333
  headers: {
328
334
  "Content-Type": "application/json"
@@ -333,26 +339,25 @@ var zkVerify = async (verifierUrl, serializedBytes, address, securityZone, chain
333
339
  const errorBody = await response.text();
334
340
  throw new CofheError({
335
341
  code: "ZK_VERIFY_FAILED" /* ZkVerifyFailed */,
336
- message: `HTTP error! ZK proof verification failed - ${errorBody}`
342
+ message: `HTTP error! ZK batch proof verification failed - ${errorBody}`
337
343
  });
338
344
  }
339
345
  const json = await response.json();
340
346
  if (json.status !== "success") {
341
347
  throw new CofheError({
342
348
  code: "ZK_VERIFY_FAILED" /* ZkVerifyFailed */,
343
- message: `ZK proof verification response malformed - ${json.error}`
349
+ message: `ZK batch proof verification response malformed - ${json.error}`
344
350
  });
345
351
  }
346
- return json.data.map(({ ct_hash, signature, recid }) => {
347
- return {
348
- ct_hash,
349
- signature: concatSigRecid(signature, recid)
350
- };
351
- });
352
+ const { ciphertexts, signature, recid } = json.data;
353
+ return {
354
+ outputs: ciphertexts,
355
+ signature: concatSigRecid(signature, recid)
356
+ };
352
357
  } catch (e) {
353
358
  throw new CofheError({
354
359
  code: "ZK_VERIFY_FAILED" /* ZkVerifyFailed */,
355
- message: `ZK proof verification failed`,
360
+ message: `ZK batch proof verification failed`,
356
361
  cause: e instanceof Error ? e : void 0
357
362
  });
358
363
  }
@@ -597,67 +602,59 @@ async function insertCtHashes(items, walletClient) {
597
602
  });
598
603
  }
599
604
  }
600
- async function createProofSignatures(items, securityZone, account) {
601
- let signatures = [];
602
- let encInputSignerClient;
605
+ async function createBatchProofSignature(items, securityZone, account, consumingContract) {
603
606
  try {
604
- encInputSignerClient = createMockZkVerifierSigner();
605
- } catch (err) {
606
- throw new CofheError({
607
- code: "ZK_MOCKS_CREATE_PROOF_SIGNATURE_FAILED" /* ZkMocksCreateProofSignatureFailed */,
608
- message: `mockZkVerifySign createProofSignatures failed while creating wallet client`,
609
- cause: err instanceof Error ? err : void 0,
610
- context: {
611
- MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY
612
- }
607
+ const itemHashes = items.map(
608
+ (item) => viem.keccak256(
609
+ viem.encodePacked(
610
+ ["uint256", "uint8", "uint8", "address", "uint256", "address"],
611
+ [
612
+ BigInt(item.ctHash),
613
+ item.utype,
614
+ securityZone,
615
+ account,
616
+ BigInt(chains.hardhat.id),
617
+ consumingContract
618
+ ]
619
+ )
620
+ )
621
+ );
622
+ const batchDigest = viem.keccak256(
623
+ viem.encodePacked(
624
+ itemHashes.map(() => "bytes32"),
625
+ itemHashes
626
+ )
627
+ );
628
+ return await accounts.sign({
629
+ hash: batchDigest,
630
+ privateKey: MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY,
631
+ to: "hex"
613
632
  });
614
- }
615
- try {
616
- for (const item of items) {
617
- const packedData = viem.encodePacked(
618
- ["uint256", "uint8", "uint8", "address", "uint256"],
619
- [BigInt(item.ctHash), item.utype, securityZone, account, BigInt(chains.hardhat.id)]
620
- );
621
- const messageHash = viem.keccak256(packedData);
622
- const signature = await accounts.sign({
623
- hash: messageHash,
624
- privateKey: MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY,
625
- to: "hex"
626
- });
627
- signatures.push(signature);
628
- }
629
633
  } catch (err) {
630
634
  throw new CofheError({
631
635
  code: "ZK_MOCKS_CREATE_PROOF_SIGNATURE_FAILED" /* ZkMocksCreateProofSignatureFailed */,
632
- message: `mockZkVerifySign createProofSignatures failed while calling signMessage`,
636
+ message: `mockZkVerifySign createBatchProofSignature failed while signing the batch digest`,
633
637
  cause: err instanceof Error ? err : void 0,
634
638
  context: {
635
639
  items,
636
- securityZone
637
- }
638
- });
639
- }
640
- if (signatures.length !== items.length) {
641
- throw new CofheError({
642
- code: "ZK_MOCKS_CREATE_PROOF_SIGNATURE_FAILED" /* ZkMocksCreateProofSignatureFailed */,
643
- message: `mockZkVerifySign createProofSignatures returned incorrect number of signatures`,
644
- context: {
645
- items,
646
- securityZone
640
+ securityZone,
641
+ consumingContract
647
642
  }
648
643
  });
649
644
  }
650
- return signatures;
651
645
  }
652
- async function cofheMocksZkVerifySign(items, account, securityZone, publicClient, walletClient, zkvWalletClient) {
646
+ async function cofheMocksZkVerifySign(items, account, securityZone, consumingContract, publicClient, walletClient, zkvWalletClient) {
653
647
  const _walletClient = zkvWalletClient ?? createMockZkVerifierSigner();
654
648
  const encryptableItems = await calcCtHashes(items, account, securityZone, publicClient);
655
649
  await insertCtHashes(encryptableItems, _walletClient);
656
- const signatures = await createProofSignatures(encryptableItems, securityZone, account);
657
- return encryptableItems.map((item, index) => ({
658
- ct_hash: item.ctHash.toString(),
659
- signature: signatures[index]
660
- }));
650
+ const signature = await createBatchProofSignature(encryptableItems, securityZone, account, consumingContract);
651
+ return {
652
+ outputs: encryptableItems.map((item) => ({
653
+ ct_hash: item.ctHash.toString(),
654
+ ct_type: item.utype
655
+ })),
656
+ signature
657
+ };
661
658
  }
662
659
  var EnvironmentSchema = zod.z.enum(["MOCK", "TESTNET", "MAINNET"]);
663
660
  var CofheChainSchema = zod.z.object({
@@ -700,8 +697,8 @@ var CofheConfigSchema = zod.z.object({
700
697
  environment: zod.z.enum(["node", "hardhat", "web", "react"]).optional().default("node"),
701
698
  /** List of supported chain configurations */
702
699
  supportedChains: zod.z.array(zod.z.custom()),
703
- /** Default permit expiration in seconds, default is 30 days */
704
- defaultPermitExpiration: zod.z.number().optional().default(60 * 60 * 24 * 30),
700
+ /** Default acp expiration in seconds, default is 30 days */
701
+ defaultACPExpiration: zod.z.number().optional().default(60 * 60 * 24 * 30),
705
702
  /** Storage method for fhe keys (defaults to indexedDB on web, filesystem on node) */
706
703
  fheKeyStorage: zod.z.object({
707
704
  getItem: zod.z.custom((val) => typeof val === "function", {
@@ -716,6 +713,12 @@ var CofheConfigSchema = zod.z.object({
716
713
  }).or(zod.z.null()).default(null),
717
714
  /** Whether to use Web Workers for ZK proof generation (web platform only) */
718
715
  useWorkers: zod.z.boolean().optional().default(true),
716
+ /** ACP acp defaults */
717
+ acp: zod.z.object({
718
+ defaultRevoker: zod.z.custom().optional(),
719
+ defaultContractScopes: zod.z.custom().optional(),
720
+ sharingRegistry: zod.z.custom().optional()
721
+ }).optional().default({}),
719
722
  /** Mocks configs */
720
723
  mocks: zod.z.object({
721
724
  decryptDelay: zod.z.number().optional().default(0),
@@ -726,8 +729,19 @@ var CofheConfigSchema = zod.z.object({
726
729
  zkvWalletClient: zod.z.any().optional()
727
730
  }).optional()
728
731
  });
732
+ var RENAMED_COFHE_CONFIG_KEYS = {
733
+ defaultPermitExpiration: "defaultACPExpiration"
734
+ };
735
+ function assertNoRenamedConfigKeys(config, renamedKeys, label) {
736
+ const stale = Object.keys(config).filter((key) => key in renamedKeys);
737
+ if (stale.length === 0)
738
+ return;
739
+ const renames = stale.map((key) => `\`${key}\` is now \`${renamedKeys[key]}\``).join("; ");
740
+ throw new Error(`Invalid ${label}: ${renames}. See the v0.7.0 migration guide.`);
741
+ }
729
742
  function createCofheConfigBase(config) {
730
- const result = CofheConfigSchema.safeParse(config);
743
+ assertNoRenamedConfigKeys(config, RENAMED_COFHE_CONFIG_KEYS, "cofhe configuration");
744
+ const result = CofheConfigSchema.strict().safeParse(config);
731
745
  if (!result.success) {
732
746
  throw new Error(`Invalid cofhe configuration: ${zod.z.prettifyError(result.error)}`, { cause: result.error });
733
747
  }
@@ -1076,9 +1090,9 @@ var BaseBuilder = class {
1076
1090
  // core/encrypt/encryptInputsBuilder.ts
1077
1091
  var EncryptInputsBuilder = class extends BaseBuilder {
1078
1092
  securityZone;
1093
+ consumingContract;
1079
1094
  stepCallback;
1080
1095
  inputItems;
1081
- hpp = false;
1082
1096
  zkvWalletClient;
1083
1097
  tfhePublicKeyDeserializer;
1084
1098
  compactPkeCrsDeserializer;
@@ -1145,20 +1159,6 @@ var EncryptInputsBuilder = class extends BaseBuilder {
1145
1159
  this.keysStorage = params.keysStorage;
1146
1160
  this.useWorker = params.config?.useWorkers ?? true;
1147
1161
  }
1148
- /**
1149
- * @param account - Account that will create the tx using the encrypted inputs.
1150
- *
1151
- * If not provided, the account will be fetched from the connected walletClient.
1152
- *
1153
- * Example:
1154
- * ```typescript
1155
- * const encrypted = await encryptInputs([Encryptable.uint128(10n)])
1156
- * .setAccount("0x123")
1157
- * .execute();
1158
- * ```
1159
- *
1160
- * @returns The chainable EncryptInputsBuilder instance.
1161
- */
1162
1162
  setAccount(account) {
1163
1163
  this.account = account;
1164
1164
  return this;
@@ -1166,20 +1166,6 @@ var EncryptInputsBuilder = class extends BaseBuilder {
1166
1166
  getAccount() {
1167
1167
  return this.account;
1168
1168
  }
1169
- /**
1170
- * @param chainId - Chain that will consume the encrypted inputs.
1171
- *
1172
- * If not provided, the chainId will be fetched from the connected publicClient.
1173
- *
1174
- * Example:
1175
- * ```typescript
1176
- * const encrypted = await encryptInputs([Encryptable.uint128(10n)])
1177
- * .setChainId(11155111)
1178
- * .execute();
1179
- * ```
1180
- *
1181
- * @returns The chainable EncryptInputsBuilder instance.
1182
- */
1183
1169
  setChainId(chainId) {
1184
1170
  this.chainId = chainId;
1185
1171
  return this;
@@ -1187,20 +1173,6 @@ var EncryptInputsBuilder = class extends BaseBuilder {
1187
1173
  getChainId() {
1188
1174
  return this.chainId;
1189
1175
  }
1190
- /**
1191
- * @param securityZone - Security zone to encrypt the inputs for.
1192
- *
1193
- * If not provided, the default securityZone 0 will be used.
1194
- *
1195
- * Example:
1196
- * ```typescript
1197
- * const encrypted = await encryptInputs([Encryptable.uint128(10n)])
1198
- * .setSecurityZone(1)
1199
- * .execute();
1200
- * ```
1201
- *
1202
- * @returns The chainable EncryptInputsBuilder instance.
1203
- */
1204
1176
  setSecurityZone(securityZone) {
1205
1177
  this.securityZone = securityZone;
1206
1178
  return this;
@@ -1209,33 +1181,44 @@ var EncryptInputsBuilder = class extends BaseBuilder {
1209
1181
  return this.securityZone;
1210
1182
  }
1211
1183
  /**
1184
+ * @param address - The contract that will consume the resulting hashes+signature (i.e. the
1185
+ * contract that will call `FHE.asEuint*`/`FHE.asEuint*s` with them).
1186
+ *
1187
+ * Required before `execute()` - the verifier binds this address into the signed digest, so a
1188
+ * batch signed for one contract cannot be replayed into another.
1189
+ *
1212
1190
  * Example:
1213
1191
  * ```typescript
1214
1192
  * const encrypted = await encryptInputs([Encryptable.uint128(10n)])
1215
- * .asHashPlusProof()
1193
+ * .setConsumingContract("0x123...890")
1216
1194
  * .execute();
1217
1195
  * ```
1218
1196
  *
1219
- * @returns Chainable EncryptInputsBuilder instance that will return a HashPlusProofResult instead of an array of EncryptedItemInputs.
1197
+ * @returns The chainable EncryptInputsBuilder instance.
1220
1198
  */
1221
- asHashPlusProof() {
1222
- this.hpp = true;
1199
+ setConsumingContract(address) {
1200
+ this.consumingContract = address;
1223
1201
  return this;
1224
1202
  }
1203
+ getConsumingContract() {
1204
+ return this.consumingContract;
1205
+ }
1225
1206
  /**
1226
- * @param useWorker - Whether to use Web Workers for ZK proof generation.
1227
- *
1228
- * Overrides the config-level useWorkers setting for this specific encryption.
1229
- *
1230
- * Example:
1231
- * ```typescript
1232
- * const encrypted = await encryptInputs([Encryptable.uint128(10n)])
1233
- * .setUseWorker(false)
1234
- * .execute();
1235
- * ```
1236
- *
1237
- * @returns The chainable EncryptInputsBuilder instance.
1207
+ * Asserts that this.consumingContract is populated
1208
+ * @throws {CofheError} If consumingContract is not set
1238
1209
  */
1210
+ assertConsumingContract() {
1211
+ if (this.consumingContract)
1212
+ return;
1213
+ throw new CofheError({
1214
+ code: "CONSUMING_CONTRACT_UNINITIALIZED" /* ConsumingContractUninitialized */,
1215
+ message: "Consuming contract is not set",
1216
+ hint: "Use setConsumingContract(...) to set the contract that will consume the encrypted inputs.",
1217
+ context: {
1218
+ consumingContract: this.consumingContract
1219
+ }
1220
+ });
1221
+ }
1239
1222
  setUseWorker(useWorker) {
1240
1223
  this.useWorker = useWorker;
1241
1224
  return this;
@@ -1256,21 +1239,6 @@ var EncryptInputsBuilder = class extends BaseBuilder {
1256
1239
  getUseWorker() {
1257
1240
  return this.useWorker;
1258
1241
  }
1259
- /**
1260
- * @param callback - Function to be called with the encryption step.
1261
- *
1262
- * Useful for debugging and tracking the progress of the encryption process.
1263
- * Useful for a UI element that shows the progress of the encryption process.
1264
- *
1265
- * Example:
1266
- * ```typescript
1267
- * const encrypted = await encryptInputs([Encryptable.uint128(10n)])
1268
- * .onStep((step: EncryptStep) => console.log(step))
1269
- * .execute();
1270
- * ```
1271
- *
1272
- * @returns The EncryptInputsBuilder instance.
1273
- */
1274
1242
  onStep(callback) {
1275
1243
  this.stepCallback = callback;
1276
1244
  return this;
@@ -1409,6 +1377,7 @@ var EncryptInputsBuilder = class extends BaseBuilder {
1409
1377
  this.assertAccount();
1410
1378
  this.assertPublicClient();
1411
1379
  this.assertWalletClient();
1380
+ this.assertConsumingContract();
1412
1381
  const [initTfheDelay, fetchKeysDelay, packDelay, proveDelay, verifyDelay] = this.resolveEncryptDelays();
1413
1382
  this.fireStepStart("initTfhe" /* InitTfhe */);
1414
1383
  await sleep(initTfheDelay);
@@ -1434,22 +1403,17 @@ var EncryptInputsBuilder = class extends BaseBuilder {
1434
1403
  this.fireStepEnd("prove" /* Prove */, { isMocks: true, mockSleep: proveDelay });
1435
1404
  this.fireStepStart("verify" /* Verify */);
1436
1405
  await sleep(verifyDelay);
1437
- const signedResults = await cofheMocksZkVerifySign(
1406
+ const result = await cofheMocksZkVerifySign(
1438
1407
  this.inputItems,
1439
1408
  this.account,
1440
1409
  this.securityZone,
1410
+ this.consumingContract,
1441
1411
  this.publicClient,
1442
1412
  this.walletClient,
1443
1413
  this.zkvWalletClient
1444
1414
  );
1445
- const encryptedInputs = signedResults.map(({ ct_hash, signature }, index) => ({
1446
- ctHash: BigInt(ct_hash),
1447
- securityZone: this.securityZone,
1448
- utype: this.inputItems[index].utype,
1449
- signature
1450
- }));
1451
1415
  this.fireStepEnd("verify" /* Verify */, { isMocks: true, mockSleep: verifyDelay });
1452
- return encryptedInputs;
1416
+ return result;
1453
1417
  }
1454
1418
  /**
1455
1419
  * In the production context, perform a true encryption with the CoFHE coprocessor.
@@ -1457,6 +1421,7 @@ var EncryptInputsBuilder = class extends BaseBuilder {
1457
1421
  async productionExecute() {
1458
1422
  this.assertAccount();
1459
1423
  this.assertChainId();
1424
+ this.assertConsumingContract();
1460
1425
  this.fireStepStart("initTfhe" /* InitTfhe */);
1461
1426
  const tfheInitializationExecuted = await this.initTfheOrThrow();
1462
1427
  this.fireStepEnd("initTfhe" /* InitTfhe */, { tfheInitializationExecuted });
@@ -1491,26 +1456,24 @@ var EncryptInputsBuilder = class extends BaseBuilder {
1491
1456
  });
1492
1457
  this.fireStepStart("verify" /* Verify */);
1493
1458
  const zkVerifierUrl = await this.getZkVerifierUrl();
1494
- const verifyResults = await zkVerify(zkVerifierUrl, proof, this.account, this.securityZone, this.chainId);
1495
- const encryptedInputs = verifyResults.map(
1496
- ({ ct_hash, signature }, index) => ({
1497
- ctHash: BigInt(ct_hash),
1498
- securityZone: this.securityZone,
1499
- utype: this.inputItems[index].utype,
1500
- signature
1501
- })
1459
+ const result = await zkVerifyBatch(
1460
+ zkVerifierUrl,
1461
+ proof,
1462
+ this.account,
1463
+ this.securityZone,
1464
+ this.chainId,
1465
+ this.consumingContract
1502
1466
  );
1503
1467
  this.fireStepEnd("verify" /* Verify */);
1504
- return encryptedInputs;
1505
- }
1506
- structsToHashPlusProof(inItems) {
1507
- let hashes = [];
1508
- let proof = "";
1509
- for (const item of inItems) {
1510
- hashes.push("0x" + item.ctHash.toString(16).padStart(64, "0"));
1511
- proof += item.signature;
1512
- }
1513
- return [...hashes, proof];
1468
+ return result;
1469
+ }
1470
+ /**
1471
+ * Converts a batch-verified result (per-item ctHash/ctType + one shared signature) into the
1472
+ * tuple returned by `execute()`: per-item hashes in input order, followed by the single signature.
1473
+ */
1474
+ buildBatchResult(result) {
1475
+ const hashes = result.outputs.map((output) => "0x" + BigInt(output.ct_hash).toString(16).padStart(64, "0"));
1476
+ return [...hashes, result.signature];
1514
1477
  }
1515
1478
  /**
1516
1479
  * Final step of the encryption process. MUST BE CALLED LAST IN THE CHAIN.
@@ -1532,18 +1495,16 @@ var EncryptInputsBuilder = class extends BaseBuilder {
1532
1495
  * @returns The encrypted inputs.
1533
1496
  */
1534
1497
  async execute() {
1535
- let items;
1498
+ let result;
1536
1499
  if (this.chainId === chains.hardhat.id)
1537
- items = await this.mocksExecute();
1500
+ result = await this.mocksExecute();
1538
1501
  else
1539
- items = await this.productionExecute();
1540
- if (this.hpp)
1541
- return this.structsToHashPlusProof(items);
1542
- return items;
1502
+ result = await this.productionExecute();
1503
+ return this.buildBatchResult(result);
1543
1504
  }
1544
1505
  };
1545
1506
 
1546
- // permits/utils.ts
1507
+ // acps/utils.ts
1547
1508
  var fromHexString = (hexString) => {
1548
1509
  const cleanString = hexString.length % 2 === 1 ? `0${hexString}` : hexString;
1549
1510
  const arr = cleanString.replace(/^0x/, "").match(/.{1,2}/g);
@@ -1563,120 +1524,33 @@ function toBigInt(value) {
1563
1524
  return value;
1564
1525
  }
1565
1526
  }
1566
- function toBeArray(value) {
1567
- const bigIntValue = typeof value === "number" ? BigInt(value) : value;
1568
- const hex = bigIntValue.toString(16);
1569
- const paddedHex = hex.length % 2 === 0 ? hex : "0" + hex;
1570
- return fromHexString(paddedHex);
1571
- }
1572
- function isString(value) {
1573
- if (typeof value !== "string") {
1574
- throw new Error(`Expected value which is \`string\`, received value of type \`${typeof value}\`.`);
1575
- }
1576
- }
1577
- function isNumber(value) {
1578
- const is = typeof value === "number" && !Number.isNaN(value);
1579
- if (!is) {
1580
- throw new Error(`Expected value which is \`number\`, received value of type \`${typeof value}\`.`);
1581
- }
1582
- }
1583
- function isBigIntOrNumber(value) {
1584
- const is = typeof value === "bigint";
1585
- if (!is) {
1586
- try {
1587
- isNumber(value);
1588
- } catch (e) {
1589
- throw new Error(`Value ${value} is not a number or bigint: ${typeof value}`);
1590
- }
1591
- }
1592
- }
1593
1527
 
1594
- // permits/sealing.ts
1595
- var PRIVATE_KEY_LENGTH = 64;
1596
- var PUBLIC_KEY_LENGTH = 64;
1597
- var SealingKey = class _SealingKey {
1598
- /**
1599
- * The private key used for decryption.
1600
- */
1601
- privateKey;
1602
- /**
1603
- * The public key used for encryption.
1604
- */
1605
- publicKey;
1606
- /**
1607
- * Constructs a SealingKey instance with the given private and public keys.
1608
- *
1609
- * @param {string} privateKey - The private key used for decryption.
1610
- * @param {string} publicKey - The public key used for encryption.
1611
- * @throws Will throw an error if the provided keys lengths do not match
1612
- * the required lengths for private and public keys.
1613
- */
1614
- constructor(privateKey, publicKey) {
1615
- if (privateKey.length !== PRIVATE_KEY_LENGTH) {
1616
- throw new Error(`Private key must be of length ${PRIVATE_KEY_LENGTH}`);
1617
- }
1618
- if (publicKey.length !== PUBLIC_KEY_LENGTH) {
1619
- throw new Error(`Public key must be of length ${PUBLIC_KEY_LENGTH}`);
1620
- }
1621
- this.privateKey = privateKey;
1622
- this.publicKey = publicKey;
1623
- }
1624
- unseal = (parsedData) => {
1625
- const nonce = parsedData.nonce instanceof Uint8Array ? parsedData.nonce : new Uint8Array(parsedData.nonce);
1626
- const ephemPublicKey = parsedData.public_key instanceof Uint8Array ? parsedData.public_key : new Uint8Array(parsedData.public_key);
1627
- const dataToDecrypt = parsedData.data instanceof Uint8Array ? parsedData.data : new Uint8Array(parsedData.data);
1628
- const privateKeyBytes = fromHexString(this.privateKey);
1629
- const decryptedMessage = nacl__default.default.box.open(dataToDecrypt, nonce, ephemPublicKey, privateKeyBytes);
1630
- if (!decryptedMessage) {
1631
- throw new Error("Failed to decrypt message");
1632
- }
1633
- return toBigInt(decryptedMessage);
1634
- };
1635
- /**
1636
- * Serializes the SealingKey to a JSON object.
1637
- */
1638
- serialize = () => {
1639
- return {
1640
- privateKey: this.privateKey,
1641
- publicKey: this.publicKey
1642
- };
1643
- };
1644
- /**
1645
- * Deserializes the SealingKey from a JSON object.
1646
- */
1647
- static deserialize = (privateKey, publicKey) => {
1648
- return new _SealingKey(privateKey, publicKey);
1649
- };
1650
- /**
1651
- * Seals (encrypts) the provided message for a receiver with the specified public key.
1652
- *
1653
- * @param {bigint | number} value - The message to be encrypted.
1654
- * @param {string} publicKey - The public key of the intended recipient.
1655
- * @returns string - The encrypted message in hexadecimal format.
1656
- * @static
1657
- * @throws Will throw if the provided publicKey or value do not meet defined preconditions.
1658
- */
1659
- static seal = (value, publicKey) => {
1660
- isString(publicKey);
1661
- isBigIntOrNumber(value);
1662
- const ephemeralKeyPair = nacl__default.default.box.keyPair();
1663
- const nonce = nacl__default.default.randomBytes(nacl__default.default.box.nonceLength);
1664
- const encryptedMessage = nacl__default.default.box(toBeArray(value), nonce, fromHexString(publicKey), ephemeralKeyPair.secretKey);
1665
- return {
1666
- data: encryptedMessage,
1667
- public_key: ephemeralKeyPair.publicKey,
1668
- nonce
1669
- };
1670
- };
1671
- };
1528
+ // acps/sealing.ts
1529
+ var KEY_HEX_LENGTH = 64;
1672
1530
  var GenerateSealingKey = () => {
1673
1531
  const sodiumKeypair = nacl__default.default.box.keyPair();
1674
- return new SealingKey(toHexString2(sodiumKeypair.secretKey), toHexString2(sodiumKeypair.publicKey));
1532
+ return {
1533
+ privateKey: `0x${toHexString2(sodiumKeypair.secretKey)}`,
1534
+ publicKey: `0x${toHexString2(sodiumKeypair.publicKey)}`
1535
+ };
1536
+ };
1537
+ var unsealWithPrivateKey = (privateKey, parsedData) => {
1538
+ assertKeyLength(privateKey, "Private");
1539
+ const nonce = parsedData.nonce instanceof Uint8Array ? parsedData.nonce : new Uint8Array(parsedData.nonce);
1540
+ const ephemPublicKey = parsedData.public_key instanceof Uint8Array ? parsedData.public_key : new Uint8Array(parsedData.public_key);
1541
+ const dataToDecrypt = parsedData.data instanceof Uint8Array ? parsedData.data : new Uint8Array(parsedData.data);
1542
+ const decryptedMessage = nacl__default.default.box.open(dataToDecrypt, nonce, ephemPublicKey, fromHexString(privateKey));
1543
+ if (!decryptedMessage) {
1544
+ throw new Error("Failed to decrypt message");
1545
+ }
1546
+ return toBigInt(decryptedMessage);
1547
+ };
1548
+ var assertKeyLength = (key, kind) => {
1549
+ const bare = key.startsWith("0x") ? key.slice(2) : key;
1550
+ if (bare.length !== KEY_HEX_LENGTH) {
1551
+ throw new Error(`${kind} key must be of length ${KEY_HEX_LENGTH}`);
1552
+ }
1675
1553
  };
1676
- var SerializedSealingPair = zod.z.object({
1677
- privateKey: zod.z.string(),
1678
- publicKey: zod.z.string()
1679
- });
1680
1554
  var addressSchema = zod.z.string().refine((val) => viem.isAddress(val), {
1681
1555
  error: "Invalid address"
1682
1556
  }).transform((val) => viem.getAddress(val));
@@ -1695,46 +1569,70 @@ var bytesNotEmptySchema = bytesSchema.refine((val) => val !== "0x", {
1695
1569
  error: "Must not be empty"
1696
1570
  });
1697
1571
  var DEFAULT_EXPIRATION_FN = () => Math.round(Date.now() / 1e3) + 7 * 24 * 60 * 60;
1698
- var zPermitWithDefaults = zod.z.object({
1699
- name: zod.z.string().optional().default("Unnamed Permit"),
1572
+ var handlesSchema = zod.z.array(zod.z.string().regex(/^0x[0-9a-fA-F]{64}$/, "Invalid handle: expected 32-byte hex")).optional().default([]);
1573
+ var contractsSchema = zod.z.array(addressSchema).optional().default([]);
1574
+ var SCOPE_GLOBAL = 0;
1575
+ var SCOPE_CONTRACT = 1;
1576
+ var SCOPE_HANDLES = 2;
1577
+ var ScopeConsistencyRefinement = [
1578
+ (data) => data.scope === SCOPE_GLOBAL && data.contracts.length === 0 && data.handles.length === 0 || data.scope === SCOPE_CONTRACT && data.contracts.length > 0 && data.handles.length === 0 || data.scope === SCOPE_HANDLES && data.handles.length > 0 && data.contracts.length === 0,
1579
+ {
1580
+ error: "ACP scope :: arrays must match the scope mode (Global: both empty; Contract: contracts only; Handles: handles only)",
1581
+ path: ["scope"]
1582
+ }
1583
+ ];
1584
+ var withDerivedScope = (data) => ({
1585
+ ...data,
1586
+ scope: data.scope ?? (data.contracts.length > 0 ? SCOPE_CONTRACT : data.handles.length > 0 ? SCOPE_HANDLES : SCOPE_GLOBAL)
1587
+ });
1588
+ var zACPWithDefaults = zod.z.object({
1589
+ name: zod.z.string().optional().default("Unnamed ACP"),
1700
1590
  type: zod.z.enum(["self", "sharing", "recipient"]),
1701
1591
  issuer: addressNotZeroSchema,
1702
1592
  expiration: zod.z.int().optional().default(DEFAULT_EXPIRATION_FN),
1703
1593
  recipient: addressSchema.optional().default(viem.zeroAddress),
1704
- validatorId: zod.z.int().optional().default(0),
1705
- validatorContract: addressSchema.optional().default(viem.zeroAddress),
1594
+ revokerData: zod.z.int().optional().default(0),
1595
+ revokerContract: addressSchema.optional().default(viem.zeroAddress),
1596
+ scope: zod.z.int().min(0).max(2).optional().default(0),
1597
+ contracts: contractsSchema,
1598
+ handles: handlesSchema,
1706
1599
  issuerSignature: bytesSchema.optional().default("0x"),
1707
1600
  recipientSignature: bytesSchema.optional().default("0x")
1708
1601
  });
1709
- var zPermitWithSealingPair = zPermitWithDefaults.extend({
1710
- sealingPair: SerializedSealingPair.optional()
1602
+ var zACPWithSealingKeys = zACPWithDefaults.extend({
1603
+ /** X25519 private key, 0x-prefixed 32-byte hex; never leaves the client */
1604
+ sealingPrivateKey: zod.z.string().regex(/^0x[0-9a-fA-F]{64}$/, "Invalid sealing private key").optional(),
1605
+ sealingKey: zod.z.string().regex(/^0x[0-9a-fA-F]{64}$/, "Invalid sealing key").optional()
1711
1606
  });
1712
1607
  var ExternalValidatorRefinement = [
1713
- (data) => data.validatorId !== 0 && data.validatorContract !== viem.zeroAddress || data.validatorId === 0 && data.validatorContract === viem.zeroAddress,
1608
+ (data) => data.revokerData !== 0 && data.revokerContract !== viem.zeroAddress || data.revokerData === 0 && data.revokerContract === viem.zeroAddress,
1714
1609
  {
1715
- error: "Permit external validator :: validatorId and validatorContract must either both be set or both be unset.",
1716
- path: ["validatorId", "validatorContract"]
1610
+ error: "ACP external revoker :: revokerData and revokerContract must either both be set or both be unset.",
1611
+ path: ["revokerData", "revokerContract"]
1717
1612
  }
1718
1613
  ];
1719
1614
  var RecipientRefinement = [
1720
1615
  (data) => data.issuer !== data.recipient,
1721
1616
  {
1722
- error: "Sharing permit :: issuer and recipient must not be the same",
1617
+ error: "Sharing acp :: issuer and recipient must not be the same",
1723
1618
  path: ["issuer", "recipient"]
1724
1619
  }
1725
1620
  ];
1726
- var SelfPermitOptionsValidator = zod.z.object({
1621
+ var SelfACPOptionsValidator = zod.z.object({
1727
1622
  type: zod.z.literal("self").optional().default("self"),
1728
1623
  issuer: addressNotZeroSchema,
1729
- name: zod.z.string().optional().default("Unnamed Permit"),
1624
+ name: zod.z.string().optional().default("Unnamed ACP"),
1730
1625
  expiration: zod.z.int().optional().default(DEFAULT_EXPIRATION_FN),
1731
1626
  recipient: addressSchema.optional().default(viem.zeroAddress),
1732
- validatorId: zod.z.int().optional().default(0),
1733
- validatorContract: addressSchema.optional().default(viem.zeroAddress),
1627
+ revokerData: zod.z.int().optional().default(0),
1628
+ revokerContract: addressSchema.optional().default(viem.zeroAddress),
1629
+ scope: zod.z.int().min(0).max(2).optional(),
1630
+ contracts: contractsSchema,
1631
+ handles: handlesSchema,
1734
1632
  issuerSignature: bytesSchema.optional().default("0x"),
1735
1633
  recipientSignature: bytesSchema.optional().default("0x")
1736
- }).refine(...ExternalValidatorRefinement);
1737
- var SelfPermitValidator = zPermitWithSealingPair.refine((data) => data.type === "self", {
1634
+ }).refine(...ExternalValidatorRefinement).transform(withDerivedScope).refine(...ScopeConsistencyRefinement);
1635
+ var SelfACPValidator = zACPWithSealingKeys.refine((data) => data.type === "self", {
1738
1636
  error: "Type must be 'self'"
1739
1637
  }).refine((data) => data.recipient === viem.zeroAddress, {
1740
1638
  error: "Recipient must be zeroAddress"
@@ -1743,18 +1641,21 @@ var SelfPermitValidator = zPermitWithSealingPair.refine((data) => data.type ===
1743
1641
  }).refine((data) => data.recipientSignature === "0x", {
1744
1642
  error: "RecipientSignature must be empty"
1745
1643
  }).refine(...ExternalValidatorRefinement);
1746
- var SharingPermitOptionsValidator = zod.z.object({
1644
+ var SharingACPOptionsValidator = zod.z.object({
1747
1645
  type: zod.z.literal("sharing").optional().default("sharing"),
1748
1646
  issuer: addressNotZeroSchema,
1749
1647
  recipient: addressNotZeroSchema,
1750
- name: zod.z.string().optional().default("Unnamed Permit"),
1648
+ name: zod.z.string().optional().default("Unnamed ACP"),
1751
1649
  expiration: zod.z.int().optional().default(DEFAULT_EXPIRATION_FN),
1752
- validatorId: zod.z.int().optional().default(0),
1753
- validatorContract: addressSchema.optional().default(viem.zeroAddress),
1650
+ revokerData: zod.z.int().optional().default(0),
1651
+ revokerContract: addressSchema.optional().default(viem.zeroAddress),
1652
+ scope: zod.z.int().min(0).max(2).optional(),
1653
+ contracts: contractsSchema,
1654
+ handles: handlesSchema,
1754
1655
  issuerSignature: bytesSchema.optional().default("0x"),
1755
1656
  recipientSignature: bytesSchema.optional().default("0x")
1756
- }).refine(...RecipientRefinement).refine(...ExternalValidatorRefinement);
1757
- var SharingPermitValidator = zPermitWithSealingPair.refine((data) => data.type === "sharing", {
1657
+ }).refine(...RecipientRefinement).refine(...ExternalValidatorRefinement).transform(withDerivedScope).refine(...ScopeConsistencyRefinement);
1658
+ var SharingACPValidator = zACPWithSealingKeys.refine((data) => data.type === "sharing", {
1758
1659
  error: "Type must be 'sharing'"
1759
1660
  }).refine((data) => data.recipient !== viem.zeroAddress, {
1760
1661
  error: "Recipient must not be zeroAddress"
@@ -1763,18 +1664,21 @@ var SharingPermitValidator = zPermitWithSealingPair.refine((data) => data.type =
1763
1664
  }).refine((data) => data.recipientSignature === "0x", {
1764
1665
  error: "RecipientSignature must be empty"
1765
1666
  }).refine(...ExternalValidatorRefinement);
1766
- var ImportPermitOptionsValidator = zod.z.object({
1667
+ var ImportACPOptionsValidator = zod.z.object({
1767
1668
  type: zod.z.literal("recipient").optional().default("recipient"),
1768
1669
  issuer: addressNotZeroSchema,
1769
1670
  recipient: addressNotZeroSchema,
1770
- name: zod.z.string().optional().default("Unnamed Permit"),
1671
+ name: zod.z.string().optional().default("Unnamed ACP"),
1771
1672
  expiration: zod.z.int(),
1772
- validatorId: zod.z.int().optional().default(0),
1773
- validatorContract: addressSchema.optional().default(viem.zeroAddress),
1673
+ revokerData: zod.z.int().optional().default(0),
1674
+ revokerContract: addressSchema.optional().default(viem.zeroAddress),
1675
+ scope: zod.z.int().min(0).max(2).optional(),
1676
+ contracts: contractsSchema,
1677
+ handles: handlesSchema,
1774
1678
  issuerSignature: bytesNotEmptySchema,
1775
1679
  recipientSignature: bytesSchema.optional().default("0x")
1776
- }).refine(...ExternalValidatorRefinement);
1777
- var ImportPermitValidator = zPermitWithSealingPair.refine((data) => data.type === "recipient", {
1680
+ }).refine(...ExternalValidatorRefinement).transform(withDerivedScope).refine(...ScopeConsistencyRefinement);
1681
+ var ImportACPValidator = zACPWithSealingKeys.refine((data) => data.type === "recipient", {
1778
1682
  error: "Type must be 'recipient'"
1779
1683
  }).refine((data) => data.recipient !== viem.zeroAddress, {
1780
1684
  error: "Recipient must not be zeroAddress"
@@ -1790,116 +1694,125 @@ var safeParseAndThrowFormatted = (schema, data, message) => {
1790
1694
  }
1791
1695
  return result.data;
1792
1696
  };
1793
- var validateSelfPermitOptions = (options) => {
1794
- return safeParseAndThrowFormatted(SelfPermitOptionsValidator, options, "Invalid self permit options");
1697
+ var validateSelfACPOptions = (options) => {
1698
+ return safeParseAndThrowFormatted(SelfACPOptionsValidator, options, "Invalid self acp options");
1795
1699
  };
1796
- var validateSharingPermitOptions = (options) => {
1797
- return safeParseAndThrowFormatted(SharingPermitOptionsValidator, options, "Invalid sharing permit options");
1700
+ var validateSharingACPOptions = (options) => {
1701
+ return safeParseAndThrowFormatted(SharingACPOptionsValidator, options, "Invalid sharing acp options");
1798
1702
  };
1799
- var validateImportPermitOptions = (options) => {
1800
- return safeParseAndThrowFormatted(ImportPermitOptionsValidator, options, "Invalid import permit options");
1703
+ var validateImportACPOptions = (options) => {
1704
+ return safeParseAndThrowFormatted(ImportACPOptionsValidator, options, "Invalid import acp options");
1801
1705
  };
1802
- var validateSelfPermit = (permit) => {
1803
- return safeParseAndThrowFormatted(SelfPermitValidator, permit, "Invalid self permit");
1706
+ var validateSelfACP = (acp) => {
1707
+ return safeParseAndThrowFormatted(SelfACPValidator, acp, "Invalid self acp");
1804
1708
  };
1805
- var validateSharingPermit = (permit) => {
1806
- return safeParseAndThrowFormatted(SharingPermitValidator, permit, "Invalid sharing permit");
1709
+ var validateSharingACP = (acp) => {
1710
+ return safeParseAndThrowFormatted(SharingACPValidator, acp, "Invalid sharing acp");
1807
1711
  };
1808
- var validateImportPermit = (permit) => {
1809
- return safeParseAndThrowFormatted(ImportPermitValidator, permit, "Invalid import permit");
1712
+ var validateImportACP = (acp) => {
1713
+ return safeParseAndThrowFormatted(ImportACPValidator, acp, "Invalid import acp");
1810
1714
  };
1811
1715
  var ValidationUtils = {
1812
1716
  /**
1813
- * Check if permit is expired
1717
+ * Check if acp is expired
1814
1718
  */
1815
- isExpired: (permit) => {
1816
- return permit.expiration < Math.floor(Date.now() / 1e3);
1719
+ isExpired: (acp) => {
1720
+ return acp.expiration < Math.floor(Date.now() / 1e3);
1817
1721
  },
1818
1722
  /**
1819
- * Check if permit is signed by the active party
1723
+ * Check if acp is signed by the active party
1820
1724
  */
1821
- isSigned: (permit) => {
1822
- if (permit.type === "self" || permit.type === "sharing") {
1823
- return permit.issuerSignature !== "0x";
1725
+ isSigned: (acp) => {
1726
+ if (acp.type === "self" || acp.type === "sharing") {
1727
+ return acp.issuerSignature !== "0x";
1824
1728
  }
1825
- if (permit.type === "recipient") {
1826
- return permit.recipientSignature !== "0x";
1729
+ if (acp.type === "recipient") {
1730
+ return acp.recipientSignature !== "0x";
1827
1731
  }
1828
1732
  return false;
1829
1733
  },
1830
1734
  /**
1831
- * Checks that a permit is signed and not expired.
1735
+ * Checks that an ACP is signed and not expired.
1832
1736
  */
1833
- isSignedAndNotExpired: (permit) => {
1834
- if (ValidationUtils.isExpired(permit)) {
1737
+ isSignedAndNotExpired: (acp) => {
1738
+ if (ValidationUtils.isExpired(acp)) {
1835
1739
  return { valid: false, error: "expired" };
1836
1740
  }
1837
- if (!ValidationUtils.isSigned(permit)) {
1741
+ if (!ValidationUtils.isSigned(acp)) {
1838
1742
  return { valid: false, error: "not-signed" };
1839
1743
  }
1840
1744
  return { valid: true, error: null };
1841
1745
  },
1842
1746
  /**
1843
- * Asserts that a permit is signed and not expired.
1747
+ * Asserts that an ACP is signed and not expired.
1844
1748
  *
1845
1749
  * Throws `Error` with message:
1846
- * - `Permit is expired`
1847
- * - `Permit is not signed`
1750
+ * - `ACP is expired`
1751
+ * - `ACP is not signed`
1848
1752
  */
1849
- assertSignedAndNotExpired: (permit) => {
1850
- const result = ValidationUtils.isSignedAndNotExpired(permit);
1753
+ assertSignedAndNotExpired: (acp) => {
1754
+ const result = ValidationUtils.isSignedAndNotExpired(acp);
1851
1755
  if (result.valid)
1852
1756
  return;
1853
1757
  if (result.error === "expired") {
1854
- throw new Error("Permit is expired");
1758
+ throw new Error("ACP is expired");
1855
1759
  }
1856
1760
  if (result.error === "not-signed") {
1857
- throw new Error("Permit is not signed");
1761
+ throw new Error("ACP is not signed");
1858
1762
  }
1859
- throw new Error("Permit is invalid");
1763
+ throw new Error("ACP is invalid");
1860
1764
  },
1861
- isValid: (permit) => {
1862
- const schema = permit.type === "self" ? SelfPermitValidator : permit.type === "sharing" ? SharingPermitValidator : permit.type === "recipient" ? ImportPermitValidator : null;
1765
+ isValid: (acp) => {
1766
+ const schema = acp.type === "self" ? SelfACPValidator : acp.type === "sharing" ? SharingACPValidator : acp.type === "recipient" ? ImportACPValidator : null;
1863
1767
  if (schema == null)
1864
1768
  return { valid: false, error: "invalid-schema" };
1865
- const schemaResult = schema.safeParse(permit);
1769
+ const schemaResult = schema.safeParse(acp);
1866
1770
  if (!schemaResult.success)
1867
1771
  return { valid: false, error: "invalid-schema" };
1868
- return ValidationUtils.isSignedAndNotExpired(permit);
1772
+ return ValidationUtils.isSignedAndNotExpired(acp);
1869
1773
  }
1870
1774
  };
1871
1775
 
1872
- // permits/signature.ts
1873
- var PermitSignatureAllFields = [
1776
+ // acps/signature.ts
1777
+ var ACPSignatureAllFields = [
1874
1778
  { name: "issuer", type: "address" },
1875
1779
  { name: "expiration", type: "uint64" },
1876
1780
  { name: "recipient", type: "address" },
1877
- { name: "validatorId", type: "uint256" },
1878
- { name: "validatorContract", type: "address" },
1781
+ { name: "revokerData", type: "uint256" },
1782
+ { name: "revokerContract", type: "address" },
1783
+ { name: "scope", type: "uint8" },
1784
+ { name: "contracts", type: "address[]" },
1785
+ { name: "handles", type: "bytes32[]" },
1879
1786
  { name: "sealingKey", type: "bytes32" },
1880
1787
  { name: "issuerSignature", type: "bytes" }
1881
1788
  ];
1882
1789
  var SignatureTypes = {
1883
- PermissionedV2IssuerSelf: [
1790
+ ACPIssuerSelf: [
1884
1791
  "issuer",
1885
1792
  "expiration",
1886
1793
  "recipient",
1887
- "validatorId",
1888
- "validatorContract",
1794
+ "revokerData",
1795
+ "revokerContract",
1796
+ "scope",
1797
+ "contracts",
1798
+ "handles",
1889
1799
  "sealingKey"
1890
1800
  ],
1891
- PermissionedV2IssuerShared: [
1801
+ ACPIssuerShared: [
1892
1802
  "issuer",
1893
1803
  "expiration",
1894
1804
  "recipient",
1895
- "validatorId",
1896
- "validatorContract"
1805
+ "revokerData",
1806
+ "revokerContract",
1807
+ "scope",
1808
+ "contracts",
1809
+ "handles"
1897
1810
  ],
1898
- PermissionedV2Recipient: ["sealingKey", "issuerSignature"]
1811
+ ACPRecipient: ["sealingKey", "issuerSignature"]
1899
1812
  };
1900
1813
  var getSignatureTypesAndMessage = (primaryType, fields, values) => {
1901
1814
  const types = {
1902
- [primaryType]: PermitSignatureAllFields.filter((fieldType) => fields.includes(fieldType.name))
1815
+ [primaryType]: ACPSignatureAllFields.filter((fieldType) => fields.includes(fieldType.name))
1903
1816
  };
1904
1817
  const message = {};
1905
1818
  fields.forEach((field) => {
@@ -1911,22 +1824,22 @@ var getSignatureTypesAndMessage = (primaryType, fields, values) => {
1911
1824
  };
1912
1825
  var SignatureUtils = {
1913
1826
  /**
1914
- * Get signature parameters for a permit
1827
+ * Get signature parameters for an ACP
1915
1828
  */
1916
- getSignatureParams: (permit, primaryType) => {
1917
- return getSignatureTypesAndMessage(primaryType, SignatureTypes[primaryType], permit);
1829
+ getSignatureParams: (acp, primaryType) => {
1830
+ return getSignatureTypesAndMessage(primaryType, SignatureTypes[primaryType], acp);
1918
1831
  },
1919
1832
  /**
1920
- * Determine the required signature type based on permit type
1833
+ * Determine the required signature type based on acp type
1921
1834
  */
1922
- getPrimaryType: (permitType) => {
1923
- if (permitType === "self")
1924
- return "PermissionedV2IssuerSelf";
1925
- if (permitType === "sharing")
1926
- return "PermissionedV2IssuerShared";
1927
- if (permitType === "recipient")
1928
- return "PermissionedV2Recipient";
1929
- throw new Error(`Unknown permit type: ${permitType}`);
1835
+ getPrimaryType: (acpType) => {
1836
+ if (acpType === "self")
1837
+ return "ACPIssuerSelf";
1838
+ if (acpType === "sharing")
1839
+ return "ACPIssuerShared";
1840
+ if (acpType === "recipient")
1841
+ return "ACPRecipient";
1842
+ throw new Error(`Unknown acp type: ${acpType}`);
1930
1843
  }
1931
1844
  };
1932
1845
  var getAclAddress = async (publicClient) => {
@@ -1948,6 +1861,11 @@ var getAclEIP712Domain = async (publicClient) => {
1948
1861
  functionName: "eip712Domain"
1949
1862
  });
1950
1863
  const [_fields, name, version, chainId, verifyingContract, _salt, _extensions] = domain;
1864
+ if (version !== "2") {
1865
+ throw new Error(
1866
+ `Chain ${chainId}'s ACL serves EIP-712 domain version "${version}" \u2014 this SDK requires the upgraded (ACP-era) ACL, which signs as version "2". Pre-upgrade (V2 Permission) chains are not supported.`
1867
+ );
1868
+ }
1951
1869
  return {
1952
1870
  name,
1953
1871
  version,
@@ -1955,23 +1873,26 @@ var getAclEIP712Domain = async (publicClient) => {
1955
1873
  verifyingContract
1956
1874
  };
1957
1875
  };
1958
- var checkPermitValidityOnChain = async (permission, publicClient) => {
1876
+ var checkACPValidityOnChain = async (acp, publicClient) => {
1959
1877
  const aclAddress = await getAclAddress(publicClient);
1960
1878
  try {
1961
1879
  await publicClient.simulateContract({
1962
1880
  address: aclAddress,
1963
- abi: checkPermitValidityAbi,
1964
- functionName: "checkPermitValidity",
1881
+ abi: checkACPValidityAbi,
1882
+ functionName: "checkPermissionValidity",
1965
1883
  args: [
1966
1884
  {
1967
- issuer: permission.issuer,
1968
- expiration: BigInt(permission.expiration),
1969
- recipient: permission.recipient,
1970
- validatorId: BigInt(permission.validatorId),
1971
- validatorContract: permission.validatorContract,
1972
- sealingKey: permission.sealingKey,
1973
- issuerSignature: permission.issuerSignature,
1974
- recipientSignature: permission.recipientSignature
1885
+ issuer: acp.issuer,
1886
+ expiration: BigInt(acp.expiration),
1887
+ recipient: acp.recipient,
1888
+ revokerData: BigInt(acp.revokerData),
1889
+ revokerContract: acp.revokerContract,
1890
+ scope: acp.scope,
1891
+ contracts: acp.contracts,
1892
+ handles: acp.handles,
1893
+ sealingKey: acp.sealingKey,
1894
+ issuerSignature: acp.issuerSignature,
1895
+ recipientSignature: acp.recipientSignature
1975
1896
  }
1976
1897
  ]
1977
1898
  });
@@ -1984,14 +1905,14 @@ var checkPermitValidityOnChain = async (permission, publicClient) => {
1984
1905
  throw new Error(errorName);
1985
1906
  }
1986
1907
  }
1987
- const customErrorName = extractCustomErrorFromDetails(err, checkPermitValidityAbi);
1908
+ const customErrorName = extractCustomErrorFromDetails(err, checkACPValidityAbi);
1988
1909
  if (customErrorName) {
1989
1910
  throw new Error(customErrorName);
1990
1911
  }
1991
1912
  const hhDetailsData = extractReturnData(err);
1992
1913
  if (hhDetailsData != null) {
1993
1914
  const decoded = viem.decodeErrorResult({
1994
- abi: checkPermitValidityAbi,
1915
+ abi: checkACPValidityAbi,
1995
1916
  data: hhDetailsData
1996
1917
  });
1997
1918
  throw new Error(decoded.errorName);
@@ -2019,15 +1940,15 @@ function extractReturnData(err) {
2019
1940
  const s = anyErr?.details ?? anyErr?.cause?.details ?? anyErr?.shortMessage ?? anyErr?.message ?? String(err);
2020
1941
  return s.match(/return data:\s*(0x[a-fA-F0-9]+)/)?.[1];
2021
1942
  }
2022
- var checkPermitValidityAbi = [
1943
+ var checkACPValidityAbi = [
2023
1944
  {
2024
1945
  type: "function",
2025
- name: "checkPermitValidity",
1946
+ name: "checkPermissionValidity",
2026
1947
  inputs: [
2027
1948
  {
2028
- name: "permission",
1949
+ name: "acp",
2029
1950
  type: "tuple",
2030
- internalType: "struct Permission",
1951
+ internalType: "struct ACP",
2031
1952
  components: [
2032
1953
  {
2033
1954
  name: "issuer",
@@ -2045,15 +1966,30 @@ var checkPermitValidityAbi = [
2045
1966
  internalType: "address"
2046
1967
  },
2047
1968
  {
2048
- name: "validatorId",
1969
+ name: "revokerData",
2049
1970
  type: "uint256",
2050
1971
  internalType: "uint256"
2051
1972
  },
2052
1973
  {
2053
- name: "validatorContract",
1974
+ name: "revokerContract",
2054
1975
  type: "address",
2055
1976
  internalType: "address"
2056
1977
  },
1978
+ {
1979
+ name: "scope",
1980
+ type: "uint8",
1981
+ internalType: "uint8"
1982
+ },
1983
+ {
1984
+ name: "contracts",
1985
+ type: "address[]",
1986
+ internalType: "address[]"
1987
+ },
1988
+ {
1989
+ name: "handles",
1990
+ type: "bytes32[]",
1991
+ internalType: "bytes32[]"
1992
+ },
2057
1993
  {
2058
1994
  name: "sealingKey",
2059
1995
  type: "bytes32",
@@ -2103,38 +2039,40 @@ var checkPermitValidityAbi = [
2103
2039
  }
2104
2040
  ];
2105
2041
 
2106
- // permits/permit.ts
2107
- var PermitUtils = {
2042
+ // acps/acp.ts
2043
+ var ACPUtils = {
2108
2044
  /**
2109
- * Create a self permit for personal use
2045
+ * Create a self acp for personal use
2110
2046
  */
2111
2047
  createSelf: (options) => {
2112
- const validation = validateSelfPermitOptions(options);
2048
+ const validation = validateSelfACPOptions(options);
2113
2049
  const sealingPair = GenerateSealingKey();
2114
- const permit = {
2115
- hash: PermitUtils.getHash(validation),
2050
+ const acp = {
2051
+ hash: ACPUtils.getHash(validation),
2116
2052
  ...validation,
2117
- sealingPair,
2053
+ sealingPrivateKey: sealingPair.privateKey,
2054
+ sealingKey: sealingPair.publicKey,
2118
2055
  _signedDomain: void 0
2119
2056
  };
2120
- return permit;
2057
+ return acp;
2121
2058
  },
2122
2059
  /**
2123
- * Create a sharing permit to be shared with another user
2060
+ * Create a sharing acp to be shared with another user
2124
2061
  */
2125
2062
  createSharing: (options) => {
2126
- const validation = validateSharingPermitOptions(options);
2063
+ const validation = validateSharingACPOptions(options);
2127
2064
  const sealingPair = GenerateSealingKey();
2128
- const permit = {
2129
- hash: PermitUtils.getHash(validation),
2065
+ const acp = {
2066
+ hash: ACPUtils.getHash(validation),
2130
2067
  ...validation,
2131
- sealingPair,
2068
+ sealingPrivateKey: sealingPair.privateKey,
2069
+ sealingKey: sealingPair.publicKey,
2132
2070
  _signedDomain: void 0
2133
2071
  };
2134
- return permit;
2072
+ return acp;
2135
2073
  },
2136
2074
  /**
2137
- * Import a shared permit from various input formats
2075
+ * Import a shared acp from various input formats
2138
2076
  */
2139
2077
  importShared: (options) => {
2140
2078
  let parsedOptions;
@@ -2147,33 +2085,34 @@ var PermitUtils = {
2147
2085
  } else if (typeof options === "object" && options !== null) {
2148
2086
  parsedOptions = options;
2149
2087
  } else {
2150
- throw new Error("Invalid input type, expected ImportSharedPermitOptions, object, or string");
2088
+ throw new Error("Invalid input type, expected ImportSharedACPOptions, object, or string");
2151
2089
  }
2152
2090
  if (parsedOptions.type != null && parsedOptions.type !== "sharing") {
2153
- throw new Error(`Invalid permit type <${parsedOptions.type}>, must be "sharing"`);
2091
+ throw new Error(`Invalid acp type <${parsedOptions.type}>, must be "sharing"`);
2154
2092
  }
2155
- const validation = validateImportPermitOptions({ ...parsedOptions, type: "recipient" });
2093
+ const validation = validateImportACPOptions({ ...parsedOptions, type: "recipient" });
2156
2094
  const sealingPair = GenerateSealingKey();
2157
- const permit = {
2158
- hash: PermitUtils.getHash(validation),
2095
+ const acp = {
2096
+ hash: ACPUtils.getHash(validation),
2159
2097
  ...validation,
2160
- sealingPair,
2098
+ sealingPrivateKey: sealingPair.privateKey,
2099
+ sealingKey: sealingPair.publicKey,
2161
2100
  _signedDomain: void 0
2162
2101
  };
2163
- return permit;
2102
+ return acp;
2164
2103
  },
2165
2104
  /**
2166
- * Sign a permit with the provided wallet client
2105
+ * Sign an ACP with the provided wallet client
2167
2106
  */
2168
- sign: async (permit, publicClient, walletClient) => {
2107
+ sign: async (acp, publicClient, walletClient) => {
2169
2108
  if (walletClient == null || walletClient.account == null) {
2170
2109
  throw new Error(
2171
- "Missing walletClient, you must pass in a `walletClient` for the connected user to create a permit signature"
2110
+ "Missing walletClient, you must pass in a `walletClient` for the connected user to create an ACP signature"
2172
2111
  );
2173
2112
  }
2174
- const primaryType = SignatureUtils.getPrimaryType(permit.type);
2113
+ const primaryType = SignatureUtils.getPrimaryType(acp.type);
2175
2114
  const domain = await getAclEIP712Domain(publicClient);
2176
- const { types, message } = SignatureUtils.getSignatureParams(PermitUtils.getPermission(permit, true), primaryType);
2115
+ const { types, message } = SignatureUtils.getSignatureParams(ACPUtils.getPublic(acp, true), primaryType);
2177
2116
  const signature = await walletClient.signTypedData({
2178
2117
  domain,
2179
2118
  types,
@@ -2181,190 +2120,209 @@ var PermitUtils = {
2181
2120
  message,
2182
2121
  account: walletClient.account
2183
2122
  });
2184
- let updatedPermit;
2185
- if (permit.type === "self" || permit.type === "sharing") {
2186
- updatedPermit = {
2187
- ...permit,
2123
+ let updatedACP;
2124
+ if (acp.type === "self" || acp.type === "sharing") {
2125
+ updatedACP = {
2126
+ ...acp,
2188
2127
  issuerSignature: signature,
2189
2128
  _signedDomain: domain
2190
2129
  };
2191
2130
  } else {
2192
- updatedPermit = {
2193
- ...permit,
2131
+ updatedACP = {
2132
+ ...acp,
2194
2133
  recipientSignature: signature,
2195
2134
  _signedDomain: domain
2196
2135
  };
2197
2136
  }
2198
- return updatedPermit;
2137
+ return updatedACP;
2199
2138
  },
2200
2139
  /**
2201
- * Create and sign a self permit in one operation
2140
+ * Create and sign a self acp in one operation
2202
2141
  */
2203
2142
  createSelfAndSign: async (options, publicClient, walletClient) => {
2204
- const permit = PermitUtils.createSelf(options);
2205
- return PermitUtils.sign(permit, publicClient, walletClient);
2143
+ const acp = ACPUtils.createSelf(options);
2144
+ return ACPUtils.sign(acp, publicClient, walletClient);
2206
2145
  },
2207
2146
  /**
2208
- * Create and sign a sharing permit in one operation
2147
+ * Create and sign a sharing acp in one operation
2209
2148
  */
2210
2149
  createSharingAndSign: async (options, publicClient, walletClient) => {
2211
- const permit = PermitUtils.createSharing(options);
2212
- return PermitUtils.sign(permit, publicClient, walletClient);
2150
+ const acp = ACPUtils.createSharing(options);
2151
+ return ACPUtils.sign(acp, publicClient, walletClient);
2213
2152
  },
2214
2153
  /**
2215
- * Import and sign a shared permit in one operation from various input formats
2154
+ * Import and sign a shared acp in one operation from various input formats
2216
2155
  */
2217
2156
  importSharedAndSign: async (options, publicClient, walletClient) => {
2218
- const permit = PermitUtils.importShared(options);
2219
- return PermitUtils.sign(permit, publicClient, walletClient);
2157
+ const acp = ACPUtils.importShared(options);
2158
+ return ACPUtils.sign(acp, publicClient, walletClient);
2220
2159
  },
2221
2160
  /**
2222
- * Deserialize a permit from serialized data
2161
+ * Deserialize an ACP from serialized data
2223
2162
  */
2224
2163
  deserialize: (data) => {
2225
- return {
2226
- ...data,
2227
- sealingPair: SealingKey.deserialize(data.sealingPair.privateKey, data.sealingPair.publicKey)
2228
- };
2164
+ return { ...data };
2229
2165
  },
2230
2166
  /**
2231
- * Serialize a permit for storage
2167
+ * Serialize an ACP for storage
2232
2168
  */
2233
- serialize: (permit) => {
2169
+ serialize: (acp) => {
2234
2170
  return {
2235
- hash: permit.hash,
2236
- name: permit.name,
2237
- type: permit.type,
2238
- issuer: permit.issuer,
2239
- expiration: permit.expiration,
2240
- recipient: permit.recipient,
2241
- validatorId: permit.validatorId,
2242
- validatorContract: permit.validatorContract,
2243
- issuerSignature: permit.issuerSignature,
2244
- recipientSignature: permit.recipientSignature,
2245
- _signedDomain: permit._signedDomain,
2246
- sealingPair: permit.sealingPair.serialize()
2171
+ hash: acp.hash,
2172
+ name: acp.name,
2173
+ type: acp.type,
2174
+ issuer: acp.issuer,
2175
+ expiration: acp.expiration,
2176
+ recipient: acp.recipient,
2177
+ revokerData: acp.revokerData,
2178
+ revokerContract: acp.revokerContract,
2179
+ scope: acp.scope,
2180
+ contracts: acp.contracts,
2181
+ handles: acp.handles,
2182
+ sealingKey: acp.sealingKey,
2183
+ issuerSignature: acp.issuerSignature,
2184
+ recipientSignature: acp.recipientSignature,
2185
+ _signedDomain: acp._signedDomain,
2186
+ sealingPrivateKey: acp.sealingPrivateKey
2247
2187
  };
2248
2188
  },
2249
2189
  /**
2250
- * Validate a permit (schema-level validation)
2190
+ * Validate an ACP (schema-level validation)
2251
2191
  */
2252
- validateSchema: (permit) => {
2253
- if (permit.type === "self") {
2254
- return validateSelfPermit(permit);
2255
- } else if (permit.type === "sharing") {
2256
- return validateSharingPermit(permit);
2257
- } else if (permit.type === "recipient") {
2258
- return validateImportPermit(permit);
2192
+ validateSchema: (acp) => {
2193
+ if (acp.type === "self") {
2194
+ return validateSelfACP(acp);
2195
+ } else if (acp.type === "sharing") {
2196
+ return validateSharingACP(acp);
2197
+ } else if (acp.type === "recipient") {
2198
+ return validateImportACP(acp);
2259
2199
  } else {
2260
- throw new Error("Invalid permit type");
2200
+ throw new Error("Invalid ACP type");
2261
2201
  }
2262
2202
  },
2263
2203
  /**
2264
- * Validate a permit (holistic validation).
2204
+ * Validate an ACP (holistic validation).
2265
2205
  *
2266
2206
  * This validates:
2267
- * - Permit schema (shape + invariants)
2268
- * - Permit is signed
2269
- * - Permit is not expired
2207
+ * - ACP schema (shape + invariants)
2208
+ * - ACP is signed
2209
+ * - ACP is not expired
2270
2210
  *
2271
- * For schema-only validation, use `validateSchema(permit)`.
2211
+ * For schema-only validation, use `validateSchema(acp)`.
2272
2212
  */
2273
- validate: (permit) => {
2274
- const validated = PermitUtils.validateSchema(permit);
2213
+ validate: (acp) => {
2214
+ const validated = ACPUtils.validateSchema(acp);
2275
2215
  ValidationUtils.assertSignedAndNotExpired(validated);
2276
2216
  return validated;
2277
2217
  },
2278
2218
  /**
2279
- * Get the permission object from a permit (for use in contracts)
2219
+ * Get the public component of an ACP the signed struct sent on-chain / to the decryption backend.
2220
+ * Strips the private component (hash, name, type, sealing pair).
2280
2221
  */
2281
- getPermission: (permit, skipValidation = false) => {
2222
+ getPublic: (acp, skipValidation = false) => {
2282
2223
  if (!skipValidation) {
2283
- PermitUtils.validateSchema(permit);
2224
+ ACPUtils.validateSchema(acp);
2284
2225
  }
2285
2226
  return {
2286
- issuer: permit.issuer,
2287
- expiration: permit.expiration,
2288
- recipient: permit.recipient,
2289
- validatorId: permit.validatorId,
2290
- validatorContract: permit.validatorContract,
2291
- sealingKey: `0x${permit.sealingPair.publicKey}`,
2292
- issuerSignature: permit.issuerSignature,
2293
- recipientSignature: permit.recipientSignature
2227
+ issuer: acp.issuer,
2228
+ expiration: acp.expiration,
2229
+ recipient: acp.recipient,
2230
+ revokerData: acp.revokerData,
2231
+ revokerContract: acp.revokerContract,
2232
+ scope: acp.scope,
2233
+ contracts: acp.contracts,
2234
+ handles: acp.handles,
2235
+ sealingKey: acp.sealingKey,
2236
+ issuerSignature: acp.issuerSignature,
2237
+ recipientSignature: acp.recipientSignature
2294
2238
  };
2295
2239
  },
2296
2240
  /**
2297
- * Get a stable hash for the permit (used as key in storage)
2241
+ * Get a stable hash for the acp (used as key in storage)
2298
2242
  */
2299
- getHash: (permit) => {
2243
+ getHash: (acp) => {
2300
2244
  const data = JSON.stringify({
2301
- type: permit.type,
2302
- issuer: permit.issuer,
2303
- expiration: permit.expiration,
2304
- recipient: permit.recipient,
2305
- validatorId: permit.validatorId,
2306
- validatorContract: permit.validatorContract
2245
+ type: acp.type,
2246
+ issuer: acp.issuer,
2247
+ expiration: acp.expiration,
2248
+ recipient: acp.recipient,
2249
+ revokerData: acp.revokerData,
2250
+ revokerContract: acp.revokerContract,
2251
+ scope: acp.scope,
2252
+ contracts: acp.contracts,
2253
+ handles: acp.handles
2307
2254
  });
2308
2255
  return viem.keccak256(viem.toHex(data));
2309
2256
  },
2310
2257
  /**
2311
- * Export permit data for sharing (removes sensitive fields)
2258
+ * Export acp data for sharing (strips the private component).
2259
+ * Fixed `SharedACP` shape — every field always present, aligned with
2260
+ * `ACPPublic` and the on-chain sharing payload.
2312
2261
  */
2313
- export: (permit) => {
2314
- const cleanedPermit = {
2315
- name: permit.name,
2316
- type: permit.type,
2317
- issuer: permit.issuer,
2318
- expiration: permit.expiration
2262
+ export: (acp) => {
2263
+ if (acp.type !== "sharing") {
2264
+ throw new Error(
2265
+ `Cannot export a '${acp.type}' ACP \u2014 only 'sharing' ACPs are exportable. The export includes the issuer signature.`
2266
+ );
2267
+ }
2268
+ if (acp.issuerSignature === "0x") {
2269
+ throw new Error(
2270
+ "Cannot export an unsigned sharing ACP \u2014 sign it first (the recipient needs the issuer signature)."
2271
+ );
2272
+ }
2273
+ const shared = {
2274
+ name: acp.name,
2275
+ type: acp.type,
2276
+ issuer: acp.issuer,
2277
+ expiration: acp.expiration,
2278
+ recipient: acp.recipient,
2279
+ revokerData: acp.revokerData,
2280
+ revokerContract: acp.revokerContract,
2281
+ scope: acp.scope,
2282
+ contracts: acp.contracts,
2283
+ handles: acp.handles,
2284
+ issuerSignature: acp.issuerSignature
2319
2285
  };
2320
- if (permit.recipient !== viem.zeroAddress)
2321
- cleanedPermit.recipient = permit.recipient;
2322
- if (permit.validatorId !== 0)
2323
- cleanedPermit.validatorId = permit.validatorId;
2324
- if (permit.validatorContract !== viem.zeroAddress)
2325
- cleanedPermit.validatorContract = permit.validatorContract;
2326
- if (permit.type === "sharing" && permit.issuerSignature !== "0x")
2327
- cleanedPermit.issuerSignature = permit.issuerSignature;
2328
- return JSON.stringify(cleanedPermit, void 0, 2);
2286
+ return JSON.stringify(shared, void 0, 2);
2329
2287
  },
2330
2288
  /**
2331
- * Unseal encrypted data using the permit's sealing key
2289
+ * Unseal encrypted data using the acp's sealing key
2332
2290
  */
2333
- unseal: (permit, ciphertext) => {
2334
- return permit.sealingPair.unseal(ciphertext);
2291
+ unseal: (acp, ciphertext) => {
2292
+ return unsealWithPrivateKey(acp.sealingPrivateKey, ciphertext);
2335
2293
  },
2336
2294
  /**
2337
- * Check if permit is expired
2295
+ * Check if acp is expired
2338
2296
  */
2339
- isExpired: (permit) => {
2340
- return ValidationUtils.isExpired(permit);
2297
+ isExpired: (acp) => {
2298
+ return ValidationUtils.isExpired(acp);
2341
2299
  },
2342
2300
  /**
2343
- * Check if permit is signed
2301
+ * Check if acp is signed
2344
2302
  */
2345
- isSigned: (permit) => {
2346
- return ValidationUtils.isSigned(permit);
2303
+ isSigned: (acp) => {
2304
+ return ValidationUtils.isSigned(acp);
2347
2305
  },
2348
2306
  /**
2349
- * Check if permit is signed and not expired
2307
+ * Check if acp is signed and not expired
2350
2308
  */
2351
- isSignedAndNotExpired: (permit) => {
2352
- return ValidationUtils.isSignedAndNotExpired(permit);
2309
+ isSignedAndNotExpired: (acp) => {
2310
+ return ValidationUtils.isSignedAndNotExpired(acp);
2353
2311
  },
2354
2312
  /**
2355
- * Assert that permit is signed and not expired
2313
+ * Assert that acp is signed and not expired
2356
2314
  */
2357
- assertSignedAndNotExpired: (permit) => {
2358
- return ValidationUtils.assertSignedAndNotExpired(permit);
2315
+ assertSignedAndNotExpired: (acp) => {
2316
+ return ValidationUtils.assertSignedAndNotExpired(acp);
2359
2317
  },
2360
- isValid: (permit) => {
2361
- return ValidationUtils.isValid(permit);
2318
+ isValid: (acp) => {
2319
+ return ValidationUtils.isValid(acp);
2362
2320
  },
2363
2321
  /**
2364
- * Update permit name (returns new permit instance)
2322
+ * Update acp name (returns new acp instance)
2365
2323
  */
2366
- updateName: (permit, name) => {
2367
- return { ...permit, name };
2324
+ updateName: (acp, name) => {
2325
+ return { ...acp, name };
2368
2326
  },
2369
2327
  /**
2370
2328
  * Fetch EIP712 domain from the blockchain
@@ -2373,230 +2331,468 @@ var PermitUtils = {
2373
2331
  return getAclEIP712Domain(publicClient);
2374
2332
  },
2375
2333
  /**
2376
- * Check if permit's signed domain matches the provided domain
2334
+ * Check if acp's signed domain matches the provided domain
2377
2335
  */
2378
- matchesDomain: (permit, domain) => {
2379
- return permit._signedDomain?.name === domain.name && permit._signedDomain?.version === domain.version && permit._signedDomain?.verifyingContract === domain.verifyingContract && permit._signedDomain?.chainId === domain.chainId;
2336
+ matchesDomain: (acp, domain) => {
2337
+ return acp._signedDomain?.name === domain.name && acp._signedDomain?.version === domain.version && acp._signedDomain?.verifyingContract === domain.verifyingContract && acp._signedDomain?.chainId === domain.chainId;
2380
2338
  },
2381
2339
  /**
2382
- * Check if permit's signed domain is valid for the current chain
2340
+ * Check if acp's signed domain is valid for the current chain
2383
2341
  */
2384
- checkSignedDomainValid: async (permit, publicClient) => {
2385
- if (permit._signedDomain == null)
2342
+ checkSignedDomainValid: async (acp, publicClient) => {
2343
+ if (acp._signedDomain == null)
2386
2344
  return false;
2387
2345
  const domain = await getAclEIP712Domain(publicClient);
2388
- return PermitUtils.matchesDomain(permit, domain);
2346
+ return ACPUtils.matchesDomain(acp, domain);
2389
2347
  },
2390
2348
  /**
2391
- * Check if permit passes the on-chain validation
2349
+ * Check if acp passes the on-chain validation
2392
2350
  */
2393
- checkValidityOnChain: async (permit, publicClient) => {
2394
- const permission = PermitUtils.getPermission(permit);
2395
- return checkPermitValidityOnChain(permission, publicClient);
2351
+ checkValidityOnChain: async (acp, publicClient) => {
2352
+ const publicAcp = ACPUtils.getPublic(acp);
2353
+ return checkACPValidityOnChain(publicAcp, publicClient);
2396
2354
  }
2397
2355
  };
2398
- var PERMIT_STORE_DEFAULTS = {
2399
- permits: {},
2400
- activePermitHash: {}
2356
+ var ACP_STORE_DEFAULTS = {
2357
+ acps: {},
2358
+ activeACPHash: {}
2401
2359
  };
2402
- var _permitStore = vanilla.createStore()(
2403
- middleware.persist(() => PERMIT_STORE_DEFAULTS, { name: "cofhesdk-permits" })
2360
+ var ACP_STORE_VERSION = 3;
2361
+ var _acpStore = vanilla.createStore()(
2362
+ middleware.persist(() => ACP_STORE_DEFAULTS, {
2363
+ name: "cofhesdk-acps",
2364
+ version: ACP_STORE_VERSION,
2365
+ migrate: (persistedState, version) => {
2366
+ if (version < ACP_STORE_VERSION)
2367
+ return ACP_STORE_DEFAULTS;
2368
+ return persistedState;
2369
+ }
2370
+ })
2404
2371
  );
2405
2372
  var clearStaleStore = () => {
2406
- const state = _permitStore.getState();
2407
- const hasExpectedStructure = state && typeof state === "object" && "permits" in state && "activePermitHash" in state && typeof state.permits === "object" && typeof state.activePermitHash === "object";
2373
+ const state = _acpStore.getState();
2374
+ const hasExpectedStructure = state && typeof state === "object" && "acps" in state && "activeACPHash" in state && typeof state.acps === "object" && typeof state.activeACPHash === "object";
2408
2375
  if (hasExpectedStructure)
2409
2376
  return;
2410
- _permitStore.setState({ permits: {}, activePermitHash: {} });
2377
+ _acpStore.setState({ acps: {}, activeACPHash: {} });
2411
2378
  };
2412
- var getPermit = (chainId, account, hash) => {
2379
+ var getACP = (chainId, account, hash) => {
2413
2380
  clearStaleStore();
2414
2381
  if (chainId == null || account == null || hash == null)
2415
2382
  return;
2416
- const savedPermit = _permitStore.getState().permits[chainId]?.[account]?.[hash];
2417
- if (savedPermit == null)
2383
+ const savedACP = _acpStore.getState().acps[chainId]?.[account]?.[hash];
2384
+ if (savedACP == null)
2418
2385
  return;
2419
- return PermitUtils.deserialize(savedPermit);
2386
+ return ACPUtils.deserialize(savedACP);
2420
2387
  };
2421
- var getActivePermit = (chainId, account) => {
2388
+ var getActiveACP = (chainId, account) => {
2422
2389
  clearStaleStore();
2423
2390
  if (chainId == null || account == null)
2424
2391
  return;
2425
- const activePermitHash = _permitStore.getState().activePermitHash[chainId]?.[account];
2426
- return getPermit(chainId, account, activePermitHash);
2392
+ const activeACPHash = _acpStore.getState().activeACPHash[chainId]?.[account];
2393
+ return getACP(chainId, account, activeACPHash);
2427
2394
  };
2428
- var getPermits = (chainId, account) => {
2395
+ var getACPs = (chainId, account) => {
2429
2396
  clearStaleStore();
2430
2397
  if (chainId == null || account == null)
2431
2398
  return {};
2432
- return Object.entries(_permitStore.getState().permits[chainId]?.[account] ?? {}).reduce(
2433
- (acc, [hash, permit]) => {
2434
- if (permit == void 0)
2399
+ return Object.entries(_acpStore.getState().acps[chainId]?.[account] ?? {}).reduce(
2400
+ (acc, [hash, acp]) => {
2401
+ if (acp == void 0)
2435
2402
  return acc;
2436
- return { ...acc, [hash]: PermitUtils.deserialize(permit) };
2403
+ return { ...acc, [hash]: ACPUtils.deserialize(acp) };
2437
2404
  },
2438
2405
  {}
2439
2406
  );
2440
2407
  };
2441
- var setPermit = (chainId, account, permit) => {
2408
+ var setACP = (chainId, account, acp) => {
2442
2409
  clearStaleStore();
2443
- _permitStore.setState(
2410
+ _acpStore.setState(
2444
2411
  immer.produce((state) => {
2445
- if (state.permits[chainId] == null)
2446
- state.permits[chainId] = {};
2447
- if (state.permits[chainId][account] == null)
2448
- state.permits[chainId][account] = {};
2449
- state.permits[chainId][account][permit.hash] = PermitUtils.serialize(permit);
2412
+ if (state.acps[chainId] == null)
2413
+ state.acps[chainId] = {};
2414
+ if (state.acps[chainId][account] == null)
2415
+ state.acps[chainId][account] = {};
2416
+ state.acps[chainId][account][acp.hash] = ACPUtils.serialize(acp);
2450
2417
  })
2451
2418
  );
2452
2419
  };
2453
- var removePermit = (chainId, account, hash) => {
2420
+ var removeACP = (chainId, account, hash) => {
2454
2421
  clearStaleStore();
2455
- _permitStore.setState(
2422
+ _acpStore.setState(
2456
2423
  immer.produce((state) => {
2457
- if (state.permits[chainId] == null)
2458
- state.permits[chainId] = {};
2459
- if (state.activePermitHash[chainId] == null)
2460
- state.activePermitHash[chainId] = {};
2461
- const accountPermits = state.permits[chainId][account];
2462
- if (accountPermits == null)
2424
+ if (state.acps[chainId] == null)
2425
+ state.acps[chainId] = {};
2426
+ if (state.activeACPHash[chainId] == null)
2427
+ state.activeACPHash[chainId] = {};
2428
+ const accountACPs = state.acps[chainId][account];
2429
+ if (accountACPs == null)
2463
2430
  return;
2464
- if (accountPermits[hash] == null)
2431
+ if (accountACPs[hash] == null)
2465
2432
  return;
2466
- if (state.activePermitHash[chainId][account] === hash) {
2467
- state.activePermitHash[chainId][account] = void 0;
2433
+ if (state.activeACPHash[chainId][account] === hash) {
2434
+ state.activeACPHash[chainId][account] = void 0;
2468
2435
  }
2469
- accountPermits[hash] = void 0;
2436
+ accountACPs[hash] = void 0;
2470
2437
  })
2471
2438
  );
2472
2439
  };
2473
- var getActivePermitHash = (chainId, account) => {
2440
+ var getActiveACPHash = (chainId, account) => {
2474
2441
  clearStaleStore();
2475
2442
  if (chainId == null || account == null)
2476
2443
  return void 0;
2477
- return _permitStore.getState().activePermitHash[chainId]?.[account];
2444
+ return _acpStore.getState().activeACPHash[chainId]?.[account];
2478
2445
  };
2479
- var setActivePermitHash = (chainId, account, hash) => {
2446
+ var setActiveACPHash = (chainId, account, hash) => {
2480
2447
  clearStaleStore();
2481
- _permitStore.setState(
2448
+ _acpStore.setState(
2482
2449
  immer.produce((state) => {
2483
- if (state.activePermitHash[chainId] == null)
2484
- state.activePermitHash[chainId] = {};
2485
- state.activePermitHash[chainId][account] = hash;
2450
+ if (state.activeACPHash[chainId] == null)
2451
+ state.activeACPHash[chainId] = {};
2452
+ state.activeACPHash[chainId][account] = hash;
2486
2453
  })
2487
2454
  );
2488
2455
  };
2489
- var removeActivePermitHash = (chainId, account) => {
2456
+ var removeActiveACPHash = (chainId, account) => {
2490
2457
  clearStaleStore();
2491
- _permitStore.setState(
2458
+ _acpStore.setState(
2492
2459
  immer.produce((state) => {
2493
- if (state.activePermitHash[chainId])
2494
- state.activePermitHash[chainId][account] = void 0;
2460
+ if (state.activeACPHash[chainId])
2461
+ state.activeACPHash[chainId][account] = void 0;
2495
2462
  })
2496
2463
  );
2497
2464
  };
2498
2465
  var resetStore = () => {
2499
2466
  clearStaleStore();
2500
- _permitStore.setState({ permits: {}, activePermitHash: {} });
2467
+ _acpStore.setState({ acps: {}, activeACPHash: {} });
2501
2468
  };
2502
- var permitStore = {
2503
- store: _permitStore,
2504
- getPermit,
2505
- getActivePermit,
2506
- getPermits,
2507
- setPermit,
2508
- removePermit,
2509
- getActivePermitHash,
2510
- setActivePermitHash,
2511
- removeActivePermitHash,
2469
+ var acpStore = {
2470
+ store: _acpStore,
2471
+ getACP,
2472
+ getActiveACP,
2473
+ getACPs,
2474
+ setACP,
2475
+ removeACP,
2476
+ getActiveACPHash,
2477
+ setActiveACPHash,
2478
+ removeActiveACPHash,
2512
2479
  resetStore
2513
2480
  };
2514
- var storeActivePermit = async (permit, publicClient, walletClient) => {
2481
+ var ACP_VALIDATOR_ABI = viem.parseAbi([
2482
+ "function revokeSingle(uint256 id)",
2483
+ "function revokeAllExisting()",
2484
+ "function disabled(address issuer, uint256 id) view returns (bool)"
2485
+ ]);
2486
+ var storeACP = async (acp, publicClient, walletClient) => {
2515
2487
  const chainId = await publicClient.getChainId();
2516
2488
  const account = walletClient.account.address;
2517
- permitStore.setPermit(chainId, account, permit);
2518
- permitStore.setActivePermitHash(chainId, account, permit.hash);
2489
+ acpStore.setACP(chainId, account, acp);
2519
2490
  };
2520
- var createPermitWithSign = async (options, publicClient, walletClient, permitMethod) => {
2521
- const permit = await permitMethod(options, publicClient, walletClient);
2522
- await storeActivePermit(permit, publicClient, walletClient);
2523
- return permit;
2491
+ var storeActiveACP = async (acp, publicClient, walletClient) => {
2492
+ await storeACP(acp, publicClient, walletClient);
2493
+ const chainId = await publicClient.getChainId();
2494
+ const account = walletClient.account.address;
2495
+ acpStore.setActiveACPHash(chainId, account, acp.hash);
2496
+ };
2497
+ var createACPWithSign = async (options, publicClient, walletClient, acpMethod, activate = true) => {
2498
+ const acp = await acpMethod(options, publicClient, walletClient);
2499
+ if (activate) {
2500
+ await storeActiveACP(acp, publicClient, walletClient);
2501
+ } else {
2502
+ await storeACP(acp, publicClient, walletClient);
2503
+ }
2504
+ return acp;
2524
2505
  };
2525
2506
  var createSelf = async (options, publicClient, walletClient) => {
2526
- return createPermitWithSign(options, publicClient, walletClient, PermitUtils.createSelfAndSign);
2507
+ return createACPWithSign(options, publicClient, walletClient, ACPUtils.createSelfAndSign);
2527
2508
  };
2528
2509
  var createSharing = async (options, publicClient, walletClient) => {
2529
- return createPermitWithSign(options, publicClient, walletClient, PermitUtils.createSharingAndSign);
2510
+ return createACPWithSign(options, publicClient, walletClient, ACPUtils.createSharingAndSign, false);
2530
2511
  };
2531
2512
  var importShared = async (options, publicClient, walletClient) => {
2532
- return createPermitWithSign(options, publicClient, walletClient, PermitUtils.importSharedAndSign);
2513
+ return createACPWithSign(options, publicClient, walletClient, ACPUtils.importSharedAndSign);
2533
2514
  };
2534
- var getHash = (permit) => {
2535
- return PermitUtils.getHash(permit);
2515
+ var getHash = (acp) => {
2516
+ return ACPUtils.getHash(acp);
2536
2517
  };
2537
- var exportShared = (permit) => {
2538
- return PermitUtils.export(permit);
2518
+ var exportShared = (acp) => {
2519
+ return ACPUtils.export(acp);
2539
2520
  };
2540
- var serialize = (permit) => {
2541
- return PermitUtils.serialize(permit);
2521
+ var serialize = (acp) => {
2522
+ return ACPUtils.serialize(acp);
2542
2523
  };
2543
2524
  var deserialize = (serialized) => {
2544
- return PermitUtils.deserialize(serialized);
2525
+ return ACPUtils.deserialize(serialized);
2545
2526
  };
2546
- var getPermit2 = (chainId, account, hash) => {
2547
- return permitStore.getPermit(chainId, account, hash);
2527
+ var getACP2 = (chainId, account, hash) => {
2528
+ return acpStore.getACP(chainId, account, hash);
2548
2529
  };
2549
- var getPermits2 = (chainId, account) => {
2550
- return permitStore.getPermits(chainId, account);
2530
+ var getACPs2 = (chainId, account) => {
2531
+ return acpStore.getACPs(chainId, account);
2551
2532
  };
2552
- var getActivePermit2 = (chainId, account) => {
2553
- return permitStore.getActivePermit(chainId, account);
2533
+ var getActiveACP2 = (chainId, account) => {
2534
+ return acpStore.getActiveACP(chainId, account);
2554
2535
  };
2555
- var getActivePermitHash2 = (chainId, account) => {
2556
- return permitStore.getActivePermitHash(chainId, account);
2536
+ var getActiveACPHash2 = (chainId, account) => {
2537
+ return acpStore.getActiveACPHash(chainId, account);
2557
2538
  };
2558
- var selectActivePermit = (chainId, account, hash) => {
2559
- permitStore.setActivePermitHash(chainId, account, hash);
2539
+ var selectActiveACP = (chainId, account, hash) => {
2540
+ acpStore.setActiveACPHash(chainId, account, hash);
2560
2541
  };
2561
- var getOrCreateSelfPermit = async (publicClient, walletClient, chainId, account, options) => {
2542
+ var getOrCreateSelfACP = async (publicClient, walletClient, chainId, account, options) => {
2562
2543
  const _chainId = chainId ?? await publicClient.getChainId();
2563
2544
  const _account = account ?? walletClient.account.address;
2564
- const activePermit = await getActivePermit2(_chainId, _account);
2565
- if (activePermit && activePermit.type === "self") {
2566
- return activePermit;
2545
+ const activeACP = await getActiveACP2(_chainId, _account);
2546
+ if (activeACP && activeACP.type === "self" && ACPUtils.isValid(activeACP).valid) {
2547
+ return activeACP;
2567
2548
  }
2568
- return createSelf(options ?? { issuer: _account, name: "Autogenerated Self Permit" }, publicClient, walletClient);
2549
+ return createSelf(options ?? { issuer: _account, name: "Autogenerated Self ACP" }, publicClient, walletClient);
2569
2550
  };
2570
- var getOrCreateSharingPermit = async (publicClient, walletClient, options, chainId, account) => {
2551
+ var getOrCreateSharingACP = async (publicClient, walletClient, options, chainId, account) => {
2571
2552
  const _chainId = chainId ?? await publicClient.getChainId();
2572
2553
  const _account = account ?? walletClient.account.address;
2573
- const activePermit = await getActivePermit2(_chainId, _account);
2574
- if (activePermit && activePermit.type === "sharing") {
2575
- return activePermit;
2554
+ const activeACP = await getActiveACP2(_chainId, _account);
2555
+ if (activeACP && activeACP.type === "sharing" && ACPUtils.isValid(activeACP).valid) {
2556
+ return activeACP;
2576
2557
  }
2577
2558
  return createSharing(options, publicClient, walletClient);
2578
2559
  };
2579
- var removePermit2 = async (chainId, account, hash) => permitStore.removePermit(chainId, account, hash);
2580
- var removeActivePermit = async (chainId, account) => permitStore.removeActivePermitHash(chainId, account);
2581
- var permits = {
2582
- getSnapshot: permitStore.store.getState,
2583
- subscribe: permitStore.store.subscribe,
2560
+ var applyACPDefaults = (options, acpConfig, chainId) => {
2561
+ const result = { ...options };
2562
+ const defaultRevoker = acpConfig?.defaultRevoker?.[chainId];
2563
+ const hasValidatorOptions = options.revokerData != null || options.revokerContract != null;
2564
+ if (defaultRevoker != null && !hasValidatorOptions) {
2565
+ result.revokerContract = defaultRevoker;
2566
+ result.revokerData = Math.round(Date.now() / 1e3) - 60;
2567
+ }
2568
+ const defaultContracts = acpConfig?.defaultContractScopes?.[chainId];
2569
+ const hasScopeOptions = options.scope != null || options.contracts != null || options.handles != null;
2570
+ if (defaultContracts != null && defaultContracts.length > 0 && !hasScopeOptions) {
2571
+ result.contracts = defaultContracts;
2572
+ }
2573
+ return result;
2574
+ };
2575
+ var ACL_SERVED_ADDRESSES_ABI = viem.parseAbi([
2576
+ "function acl() view returns (address)",
2577
+ "function defaultRevokerContract() view returns (address)",
2578
+ "function shareRegistry() view returns (address)"
2579
+ ]);
2580
+ var aclServedAddressesCache = /* @__PURE__ */ new Map();
2581
+ var clearAclServedAddresses = () => aclServedAddressesCache.clear();
2582
+ var getAclServedAddresses = async (publicClient, chainId) => {
2583
+ const cached = aclServedAddressesCache.get(chainId);
2584
+ if (cached != null)
2585
+ return cached;
2586
+ let aclAddress;
2587
+ try {
2588
+ aclAddress = await publicClient.readContract({
2589
+ address: TASK_MANAGER_ADDRESS,
2590
+ abi: ACL_SERVED_ADDRESSES_ABI,
2591
+ functionName: "acl"
2592
+ });
2593
+ } catch {
2594
+ return {};
2595
+ }
2596
+ const [defaultRevoker, shareRegistry] = await Promise.all([
2597
+ publicClient.readContract({ address: aclAddress, abi: ACL_SERVED_ADDRESSES_ABI, functionName: "defaultRevokerContract" }).catch(() => void 0),
2598
+ publicClient.readContract({ address: aclAddress, abi: ACL_SERVED_ADDRESSES_ABI, functionName: "shareRegistry" }).catch(() => void 0)
2599
+ ]);
2600
+ const resolved = {
2601
+ defaultRevoker: defaultRevoker != null && defaultRevoker !== viem.zeroAddress ? defaultRevoker : void 0,
2602
+ shareRegistry: shareRegistry != null && shareRegistry !== viem.zeroAddress ? shareRegistry : void 0
2603
+ };
2604
+ aclServedAddressesCache.set(chainId, resolved);
2605
+ return resolved;
2606
+ };
2607
+ var applyACPDefaultsFromChain = async (options, acpConfig, publicClient, chainId) => {
2608
+ const hasExplicitRevoker = acpConfig?.defaultRevoker?.[chainId] != null || options.revokerData != null || options.revokerContract != null;
2609
+ if (hasExplicitRevoker)
2610
+ return applyACPDefaults(options, acpConfig, chainId);
2611
+ const served = await getAclServedAddresses(publicClient, chainId);
2612
+ const effectiveConfig = served.defaultRevoker != null ? { ...acpConfig, defaultRevoker: { ...acpConfig?.defaultRevoker, [chainId]: served.defaultRevoker } } : acpConfig;
2613
+ return applyACPDefaults(options, effectiveConfig, chainId);
2614
+ };
2615
+ var revokeACP = async (acp, walletClient) => {
2616
+ if (acp.revokerContract === viem.zeroAddress || acp.revokerData === 0) {
2617
+ throw new Error("ACP is not revocable: it has no revoker (revokerContract/revokerData unset)");
2618
+ }
2619
+ if (walletClient.account == null)
2620
+ throw new Error("Missing walletClient account");
2621
+ if (walletClient.account.address.toLowerCase() !== acp.issuer.toLowerCase()) {
2622
+ throw new Error("Only the acp issuer can revoke it");
2623
+ }
2624
+ return walletClient.writeContract({
2625
+ address: acp.revokerContract,
2626
+ abi: ACP_VALIDATOR_ABI,
2627
+ functionName: "revokeSingle",
2628
+ args: [BigInt(acp.revokerData)],
2629
+ account: walletClient.account,
2630
+ chain: walletClient.chain
2631
+ });
2632
+ };
2633
+ var revokeAllACPs = async (walletClient, publicClient, revokerContract) => {
2634
+ if (walletClient.account == null)
2635
+ throw new Error("Missing walletClient account");
2636
+ let revoker = revokerContract;
2637
+ if (revoker == null) {
2638
+ const chainId = await publicClient.getChainId();
2639
+ const active = getActiveACP2(chainId, walletClient.account.address);
2640
+ revoker = active?.revokerContract;
2641
+ }
2642
+ if (revoker == null || revoker === viem.zeroAddress) {
2643
+ throw new Error("No revoker contract: pass `revokerContract` or activate a revocable acp first");
2644
+ }
2645
+ return walletClient.writeContract({
2646
+ address: revoker,
2647
+ abi: ACP_VALIDATOR_ABI,
2648
+ functionName: "revokeAllExisting",
2649
+ args: [],
2650
+ account: walletClient.account,
2651
+ chain: walletClient.chain
2652
+ });
2653
+ };
2654
+ var isACPRevoked = async (acp, publicClient) => {
2655
+ if (acp.revokerContract === viem.zeroAddress || acp.revokerData === 0)
2656
+ return false;
2657
+ return publicClient.readContract({
2658
+ address: acp.revokerContract,
2659
+ abi: ACP_VALIDATOR_ABI,
2660
+ functionName: "disabled",
2661
+ args: [acp.issuer, BigInt(acp.revokerData)]
2662
+ });
2663
+ };
2664
+ var ACP_SHARE_REGISTRY_ABI = viem.parseAbi([
2665
+ "struct ACP { address issuer; uint64 expiration; address recipient; uint256 revokerData; address revokerContract; uint8 scope; address[] contracts; bytes32[] handles; bytes32 sealingKey; bytes issuerSignature; bytes recipientSignature; }",
2666
+ "function share(ACP calldata acp) external returns (bytes32)",
2667
+ "function removeShare(bytes32 shareId) external",
2668
+ "function sharesFor(address recipient) external view returns (ACP[] memory)",
2669
+ "function getShare(bytes32 shareId) external view returns (ACP memory)",
2670
+ "function isShareValid(bytes32 shareId) external view returns (bool)"
2671
+ ]);
2672
+ var ACP_TUPLE = [
2673
+ {
2674
+ type: "tuple",
2675
+ components: [
2676
+ { name: "issuer", type: "address" },
2677
+ { name: "expiration", type: "uint64" },
2678
+ { name: "recipient", type: "address" },
2679
+ { name: "revokerData", type: "uint256" },
2680
+ { name: "revokerContract", type: "address" },
2681
+ { name: "scope", type: "uint8" },
2682
+ { name: "contracts", type: "address[]" },
2683
+ { name: "handles", type: "bytes32[]" },
2684
+ { name: "sealingKey", type: "bytes32" },
2685
+ { name: "issuerSignature", type: "bytes" },
2686
+ { name: "recipientSignature", type: "bytes" }
2687
+ ]
2688
+ }
2689
+ ];
2690
+ var ZERO_BYTES32 = `0x${"0".repeat(64)}`;
2691
+ var toChainShare = (acp) => {
2692
+ const pub = ACPUtils.getPublic(acp, true);
2693
+ return {
2694
+ ...pub,
2695
+ expiration: BigInt(pub.expiration),
2696
+ revokerData: BigInt(pub.revokerData),
2697
+ sealingKey: ZERO_BYTES32,
2698
+ recipientSignature: "0x"
2699
+ };
2700
+ };
2701
+ var computeShareId = (acp) => {
2702
+ const p = toChainShare(acp);
2703
+ return viem.keccak256(viem.encodeAbiParameters(ACP_TUPLE, [p]));
2704
+ };
2705
+ var shareOnChain = async (acp, walletClient, registry) => {
2706
+ if (acp.type !== "sharing") {
2707
+ throw new Error(`Cannot share a '${acp.type}' ACP on-chain \u2014 only 'sharing' ACPs are shareable.`);
2708
+ }
2709
+ if (acp.issuerSignature === "0x") {
2710
+ throw new Error("Cannot share an unsigned sharing ACP \u2014 sign it first.");
2711
+ }
2712
+ if (walletClient.account == null)
2713
+ throw new Error("Missing walletClient account");
2714
+ if (walletClient.account.address.toLowerCase() !== acp.issuer.toLowerCase()) {
2715
+ throw new Error("Only the ACP issuer can share it on-chain");
2716
+ }
2717
+ const txHash = await walletClient.writeContract({
2718
+ address: registry,
2719
+ abi: ACP_SHARE_REGISTRY_ABI,
2720
+ functionName: "share",
2721
+ args: [toChainShare(acp)],
2722
+ account: walletClient.account,
2723
+ chain: walletClient.chain ?? null
2724
+ });
2725
+ return { txHash, shareId: computeShareId(acp) };
2726
+ };
2727
+ var getIncomingShares = async (publicClient, registry, recipient) => {
2728
+ const raw = await publicClient.readContract({
2729
+ address: registry,
2730
+ abi: ACP_SHARE_REGISTRY_ABI,
2731
+ functionName: "sharesFor",
2732
+ args: [recipient]
2733
+ });
2734
+ return raw.map((s) => ({
2735
+ shareId: viem.keccak256(viem.encodeAbiParameters(ACP_TUPLE, [s])),
2736
+ issuer: s.issuer,
2737
+ expiration: Number(s.expiration),
2738
+ recipient: s.recipient,
2739
+ revokerData: Number(s.revokerData),
2740
+ revokerContract: s.revokerContract,
2741
+ scope: Number(s.scope),
2742
+ contracts: [...s.contracts],
2743
+ handles: [...s.handles],
2744
+ issuerSignature: s.issuerSignature
2745
+ }));
2746
+ };
2747
+ var importFromChain = async (share, publicClient, walletClient) => {
2748
+ const { shareId: _shareId, ...options } = share;
2749
+ return importShared({ ...options, type: "sharing" }, publicClient, walletClient);
2750
+ };
2751
+ var removeShareOnChain = async (shareId, walletClient, registry) => {
2752
+ if (walletClient.account == null)
2753
+ throw new Error("Missing walletClient account");
2754
+ return walletClient.writeContract({
2755
+ address: registry,
2756
+ abi: ACP_SHARE_REGISTRY_ABI,
2757
+ functionName: "removeShare",
2758
+ args: [shareId],
2759
+ account: walletClient.account,
2760
+ chain: walletClient.chain ?? null
2761
+ });
2762
+ };
2763
+ var removeACP2 = async (chainId, account, hash) => acpStore.removeACP(chainId, account, hash);
2764
+ var removeActiveACP = async (chainId, account) => acpStore.removeActiveACPHash(chainId, account);
2765
+ var acps = {
2766
+ getSnapshot: acpStore.store.getState,
2767
+ subscribe: acpStore.store.subscribe,
2584
2768
  createSelf,
2585
2769
  createSharing,
2586
2770
  importShared,
2587
- getOrCreateSelfPermit,
2588
- getOrCreateSharingPermit,
2771
+ getOrCreateSelfACP,
2772
+ getOrCreateSharingACP,
2589
2773
  getHash,
2590
2774
  export: exportShared,
2591
2775
  serialize,
2592
2776
  deserialize,
2593
- getPermit: getPermit2,
2594
- getPermits: getPermits2,
2595
- getActivePermit: getActivePermit2,
2596
- getActivePermitHash: getActivePermitHash2,
2597
- removePermit: removePermit2,
2598
- selectActivePermit,
2599
- removeActivePermit
2777
+ getACP: getACP2,
2778
+ getACPs: getACPs2,
2779
+ getActiveACP: getActiveACP2,
2780
+ getActiveACPHash: getActiveACPHash2,
2781
+ removeACP: removeACP2,
2782
+ selectActiveACP,
2783
+ removeActiveACP,
2784
+ revokeACP,
2785
+ revokeAllACPs,
2786
+ isACPRevoked,
2787
+ shareOnChain,
2788
+ getIncomingShares,
2789
+ importFromChain,
2790
+ removeShareOnChain,
2791
+ computeShareId,
2792
+ applyACPDefaults,
2793
+ applyACPDefaultsFromChain,
2794
+ getAclServedAddresses,
2795
+ clearAclServedAddresses
2600
2796
  };
2601
2797
  function uint160ToAddress(uint160) {
2602
2798
  const hexStr = uint160.toString(16).padStart(40, "0");
@@ -2659,13 +2855,16 @@ var MockThresholdNetworkAbi = [
2659
2855
  {
2660
2856
  name: "permission",
2661
2857
  type: "tuple",
2662
- internalType: "struct Permission",
2858
+ internalType: "struct ACPermission",
2663
2859
  components: [
2664
2860
  { name: "issuer", type: "address", internalType: "address" },
2665
2861
  { name: "expiration", type: "uint64", internalType: "uint64" },
2666
2862
  { name: "recipient", type: "address", internalType: "address" },
2667
- { name: "validatorId", type: "uint256", internalType: "uint256" },
2668
- { name: "validatorContract", type: "address", internalType: "address" },
2863
+ { name: "revokerData", type: "uint256", internalType: "uint256" },
2864
+ { name: "revokerContract", type: "address", internalType: "address" },
2865
+ { name: "scope", type: "uint8", internalType: "uint8" },
2866
+ { name: "contracts", type: "address[]", internalType: "address[]" },
2867
+ { name: "handles", type: "bytes32[]", internalType: "bytes32[]" },
2669
2868
  { name: "sealingKey", type: "bytes32", internalType: "bytes32" },
2670
2869
  { name: "issuerSignature", type: "bytes", internalType: "bytes" },
2671
2870
  { name: "recipientSignature", type: "bytes", internalType: "bytes" }
@@ -2688,13 +2887,16 @@ var MockThresholdNetworkAbi = [
2688
2887
  {
2689
2888
  name: "permission",
2690
2889
  type: "tuple",
2691
- internalType: "struct Permission",
2890
+ internalType: "struct ACPermission",
2692
2891
  components: [
2693
2892
  { name: "issuer", type: "address", internalType: "address" },
2694
2893
  { name: "expiration", type: "uint64", internalType: "uint64" },
2695
2894
  { name: "recipient", type: "address", internalType: "address" },
2696
- { name: "validatorId", type: "uint256", internalType: "uint256" },
2697
- { name: "validatorContract", type: "address", internalType: "address" },
2895
+ { name: "revokerData", type: "uint256", internalType: "uint256" },
2896
+ { name: "revokerContract", type: "address", internalType: "address" },
2897
+ { name: "scope", type: "uint8", internalType: "uint8" },
2898
+ { name: "contracts", type: "address[]", internalType: "address[]" },
2899
+ { name: "handles", type: "bytes32[]", internalType: "bytes32[]" },
2698
2900
  { name: "sealingKey", type: "bytes32", internalType: "bytes32" },
2699
2901
  { name: "issuerSignature", type: "bytes", internalType: "bytes" },
2700
2902
  { name: "recipientSignature", type: "bytes", internalType: "bytes" }
@@ -2759,19 +2961,22 @@ var MockThresholdNetworkAbi = [
2759
2961
  },
2760
2962
  {
2761
2963
  type: "function",
2762
- name: "decryptForTxWithPermit",
2964
+ name: "decryptForTxWithACP",
2763
2965
  inputs: [
2764
2966
  { name: "ctHash", type: "uint256", internalType: "uint256" },
2765
2967
  {
2766
2968
  name: "permission",
2767
2969
  type: "tuple",
2768
- internalType: "struct Permission",
2970
+ internalType: "struct ACPermission",
2769
2971
  components: [
2770
2972
  { name: "issuer", type: "address", internalType: "address" },
2771
2973
  { name: "expiration", type: "uint64", internalType: "uint64" },
2772
2974
  { name: "recipient", type: "address", internalType: "address" },
2773
- { name: "validatorId", type: "uint256", internalType: "uint256" },
2774
- { name: "validatorContract", type: "address", internalType: "address" },
2975
+ { name: "revokerData", type: "uint256", internalType: "uint256" },
2976
+ { name: "revokerContract", type: "address", internalType: "address" },
2977
+ { name: "scope", type: "uint8", internalType: "uint8" },
2978
+ { name: "contracts", type: "address[]", internalType: "address[]" },
2979
+ { name: "handles", type: "bytes32[]", internalType: "bytes32[]" },
2775
2980
  { name: "sealingKey", type: "bytes32", internalType: "bytes32" },
2776
2981
  { name: "issuerSignature", type: "bytes", internalType: "bytes" },
2777
2982
  { name: "recipientSignature", type: "bytes", internalType: "bytes" }
@@ -2787,7 +2992,7 @@ var MockThresholdNetworkAbi = [
2787
2992
  },
2788
2993
  {
2789
2994
  type: "function",
2790
- name: "decryptForTxWithoutPermit",
2995
+ name: "decryptForTxWithoutACP",
2791
2996
  inputs: [{ name: "ctHash", type: "uint256", internalType: "uint256" }],
2792
2997
  outputs: [
2793
2998
  { name: "allowed", type: "bool", internalType: "bool" },
@@ -2799,12 +3004,12 @@ var MockThresholdNetworkAbi = [
2799
3004
  ];
2800
3005
 
2801
3006
  // core/decrypt/cofheMocksDecryptForView.ts
2802
- async function cofheMocksDecryptForView(ctHash, utype, permit, publicClient) {
2803
- const permission = PermitUtils.getPermission(permit, true);
3007
+ async function cofheMocksDecryptForView(ctHash, utype, acp, publicClient) {
3008
+ const wireAcp = ACPUtils.getPublic(acp, true);
2804
3009
  const permissionWithBigInts = {
2805
- ...permission,
2806
- expiration: BigInt(permission.expiration),
2807
- validatorId: BigInt(permission.validatorId)
3010
+ ...wireAcp,
3011
+ expiration: BigInt(wireAcp.expiration),
3012
+ revokerData: BigInt(wireAcp.revokerData)
2808
3013
  };
2809
3014
  const [allowed, error, result] = await publicClient.readContract({
2810
3015
  address: MOCKS_THRESHOLD_NETWORK_ADDRESS,
@@ -2825,11 +3030,34 @@ async function cofheMocksDecryptForView(ctHash, utype, permit, publicClient) {
2825
3030
  });
2826
3031
  }
2827
3032
  const sealedBigInt = BigInt(result);
2828
- const sealingKeyBigInt = BigInt(permission.sealingKey);
3033
+ const sealingKeyBigInt = BigInt(acp.sealingKey);
2829
3034
  const unsealed = sealedBigInt ^ sealingKeyBigInt;
2830
3035
  return unsealed;
2831
3036
  }
2832
3037
 
3038
+ // core/debug.ts
3039
+ var interceptors = {};
3040
+ async function cofheFetch(url, init, ctx = { op: "request" }) {
3041
+ let finalUrl = url;
3042
+ let finalInit = init;
3043
+ if (interceptors.onRequest) {
3044
+ const override = await interceptors.onRequest(finalUrl, finalInit, ctx);
3045
+ if (override) {
3046
+ if (override.url !== void 0)
3047
+ finalUrl = override.url;
3048
+ if (override.init !== void 0)
3049
+ finalInit = override.init;
3050
+ }
3051
+ }
3052
+ let response = await fetch(finalUrl, finalInit);
3053
+ if (interceptors.onResponse) {
3054
+ const replaced = await interceptors.onResponse(response, ctx);
3055
+ if (replaced)
3056
+ response = replaced;
3057
+ }
3058
+ return response;
3059
+ }
3060
+
2833
3061
  // core/decrypt/polling.ts
2834
3062
  function computeMinuteRampPollIntervalMs(elapsedMs, params) {
2835
3063
  const elapsedSeconds = Math.floor(elapsedMs / 1e3);
@@ -2838,11 +3066,61 @@ function computeMinuteRampPollIntervalMs(elapsedMs, params) {
2838
3066
  return Math.min(params.maxIntervalMs, Math.max(params.minIntervalMs, intervalMs));
2839
3067
  }
2840
3068
 
3069
+ // core/decrypt/apiError.ts
3070
+ var BACKEND_ERROR_CODE_TO_COFHE_ERROR_CODE = {
3071
+ bad_request: "BAD_REQUEST" /* BadRequest */,
3072
+ unknown_chain: "UNKNOWN_CHAIN" /* UnknownChain */,
3073
+ acp_malformed: "ACP_MALFORMED" /* ACPMalformed */,
3074
+ acp_denied: "ACP_DENIED" /* ACPDenied */,
3075
+ // ACP-era backends fold revoked into denied
3076
+ acp_expired: "ACP_EXPIRED" /* ACPExpired */,
3077
+ acp_invalid: "ACP_INVALID" /* ACPInvalid */,
3078
+ acp_required: "ACP_REQUIRED" /* ACPRequired */,
3079
+ acp_verifier_error: "ACP_VERIFIER_ERROR" /* ACPVerifierError */,
3080
+ acp_verifier_timeout: "ACP_VERIFIER_TIMEOUT" /* ACPVerifierTimeout */,
3081
+ not_publicly_allowed: "NOT_PUBLICLY_ALLOWED" /* NotPubliclyAllowed */,
3082
+ ct_not_found: "CT_NOT_FOUND" /* CtNotFound */,
3083
+ unsupported_security_zone: "UNSUPPORTED_SECURITY_ZONE" /* UnsupportedSecurityZone */,
3084
+ unsupported_type: "UNSUPPORTED_TYPE" /* UnsupportedType */,
3085
+ internal_error: "INTERNAL_ERROR" /* InternalError */,
3086
+ signing_failed: "SIGNING_FAILED" /* SigningFailed */,
3087
+ ct_source_error: "CT_SOURCE_ERROR" /* CtSourceError */,
3088
+ ct_source_timeout: "CT_SOURCE_TIMEOUT" /* CtSourceTimeout */,
3089
+ seal_failed: "SEAL_FAILED" /* SealFailed */
3090
+ };
3091
+ function isBackendApiErrorCode(value) {
3092
+ return value in BACKEND_ERROR_CODE_TO_COFHE_ERROR_CODE;
3093
+ }
3094
+ async function parseApiErrorResponseBody(response) {
3095
+ let errorMessage = `HTTP ${response.status}`;
3096
+ let apiErrorCode;
3097
+ try {
3098
+ const body = await response.json();
3099
+ if (body && typeof body === "object") {
3100
+ const record = body;
3101
+ if (typeof record.error === "string" && record.error.length > 0) {
3102
+ apiErrorCode = record.error;
3103
+ }
3104
+ if (typeof record.error_message === "string" && record.error_message.length > 0) {
3105
+ errorMessage = record.error_message;
3106
+ } else if (typeof record.message === "string" && record.message.length > 0) {
3107
+ errorMessage = record.message;
3108
+ }
3109
+ }
3110
+ } catch {
3111
+ errorMessage = response.statusText || errorMessage;
3112
+ }
3113
+ return { apiErrorCode, errorMessage };
3114
+ }
3115
+ function mapApiErrorCodeToCofheErrorCode(apiErrorCode, fallback) {
3116
+ if (apiErrorCode && isBackendApiErrorCode(apiErrorCode)) {
3117
+ return BACKEND_ERROR_CODE_TO_COFHE_ERROR_CODE[apiErrorCode];
3118
+ }
3119
+ return fallback;
3120
+ }
3121
+
2841
3122
  // core/decrypt/submitRetry.ts
2842
3123
  var DEFAULT_404_RETRY_TIMEOUT_MS = 1e4;
2843
- function isRetryableSubmitStatus(status) {
2844
- return status === 204 || status === 404;
2845
- }
2846
3124
  function normalize404RetryTimeoutMs(params) {
2847
3125
  const { timeoutMs, operationLabel, errorCode } = params;
2848
3126
  if (timeoutMs === void 0)
@@ -2859,32 +3137,24 @@ function normalize404RetryTimeoutMs(params) {
2859
3137
  return timeoutMs;
2860
3138
  }
2861
3139
  async function classifySubmitResponse(params) {
2862
- const { response, extractErrorMessage } = params;
2863
- if (isRetryableSubmitStatus(response.status)) {
2864
- return { kind: "retryable", status: response.status };
3140
+ const { response, fallbackErrorCode } = params;
3141
+ if (response.status === 204) {
3142
+ return { kind: "retryable", status: 204 };
2865
3143
  }
2866
3144
  if (response.ok) {
2867
3145
  return { kind: "parse-json" };
2868
3146
  }
2869
- let errorMessage = `HTTP ${response.status}`;
2870
- try {
2871
- const errorBody = await response.json();
2872
- const maybeErrorMessage = extractErrorMessage?.(errorBody);
2873
- if (typeof maybeErrorMessage === "string" && maybeErrorMessage.length > 0) {
2874
- errorMessage = maybeErrorMessage;
2875
- } else if (errorBody && typeof errorBody === "object") {
2876
- const defaultMessage = errorBody.error_message;
2877
- const fallbackMessage = errorBody.message;
2878
- if (typeof defaultMessage === "string" && defaultMessage.length > 0) {
2879
- errorMessage = defaultMessage;
2880
- } else if (typeof fallbackMessage === "string" && fallbackMessage.length > 0) {
2881
- errorMessage = fallbackMessage;
2882
- }
2883
- }
2884
- } catch {
2885
- errorMessage = response.statusText || errorMessage;
3147
+ const { apiErrorCode, errorMessage } = await parseApiErrorResponseBody(response);
3148
+ if (response.status === 404) {
3149
+ return { kind: "retryable", status: 404, apiErrorMessage: errorMessage };
2886
3150
  }
2887
- return { kind: "fatal-http", errorMessage };
3151
+ return {
3152
+ kind: "fatal-http",
3153
+ status: response.status,
3154
+ cofheErrorCode: mapApiErrorCodeToCofheErrorCode(apiErrorCode, fallbackErrorCode),
3155
+ apiErrorCode,
3156
+ errorMessage
3157
+ };
2888
3158
  }
2889
3159
  function throwIfSubmitRetryTimedOut(params) {
2890
3160
  const {
@@ -2896,12 +3166,14 @@ function throwIfSubmitRetryTimedOut(params) {
2896
3166
  overallTimeoutMs,
2897
3167
  thresholdNetworkUrl,
2898
3168
  body,
2899
- attemptIndex
3169
+ attemptIndex,
3170
+ lastKnownErrorMessage
2900
3171
  } = params;
2901
3172
  if (status === 404 && elapsedMs > retry404TimeoutMs) {
2902
3173
  throw new CofheError({
2903
- code: errorCode,
2904
- message: `${operationLabel} submit retried 404 responses without receiving request_id for ${retry404TimeoutMs}ms`,
3174
+ code: "CT_NOT_FOUND" /* CtNotFound */,
3175
+ apiErrorCode: "ct_not_found",
3176
+ message: `${operationLabel} ciphertext not found after retrying for ${retry404TimeoutMs}ms` + (lastKnownErrorMessage ? `: ${lastKnownErrorMessage}` : ""),
2905
3177
  hint: "The ciphertext may not be indexed yet. Increase set404RetryTimeout(...) if the backend is slow to index ciphertexts.",
2906
3178
  context: {
2907
3179
  thresholdNetworkUrl,
@@ -2927,6 +3199,62 @@ function throwIfSubmitRetryTimedOut(params) {
2927
3199
  });
2928
3200
  }
2929
3201
  }
3202
+ function normalizeTnSignature(signature) {
3203
+ if (typeof signature !== "string") {
3204
+ throw new CofheError({
3205
+ code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
3206
+ message: "decrypt response missing signature",
3207
+ context: {
3208
+ signature
3209
+ }
3210
+ });
3211
+ }
3212
+ const trimmed = signature.trim();
3213
+ if (trimmed.length === 0) {
3214
+ throw new CofheError({
3215
+ code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
3216
+ message: "decrypt response returned empty signature"
3217
+ });
3218
+ }
3219
+ const prefixed = trimmed.startsWith("0x") ? trimmed : `0x${trimmed}`;
3220
+ const parsed = viem.parseSignature(prefixed);
3221
+ return viem.serializeSignature(parsed);
3222
+ }
3223
+ function parseDecryptedBytesToBigInt(decrypted) {
3224
+ if (!Array.isArray(decrypted)) {
3225
+ throw new CofheError({
3226
+ code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
3227
+ message: "decrypt response field <decrypted> must be a byte array",
3228
+ context: {
3229
+ decrypted
3230
+ }
3231
+ });
3232
+ }
3233
+ if (decrypted.length === 0) {
3234
+ throw new CofheError({
3235
+ code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
3236
+ message: "decrypt response field <decrypted> was an empty byte array",
3237
+ context: {
3238
+ decrypted
3239
+ }
3240
+ });
3241
+ }
3242
+ let hex = "";
3243
+ for (const b of decrypted) {
3244
+ if (typeof b !== "number" || !Number.isInteger(b) || b < 0 || b > 255) {
3245
+ throw new CofheError({
3246
+ code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
3247
+ message: "decrypt response field <decrypted> contained a non-byte value",
3248
+ context: {
3249
+ badElement: b,
3250
+ decrypted
3251
+ }
3252
+ });
3253
+ }
3254
+ hex += b.toString(16).padStart(2, "0");
3255
+ }
3256
+ return BigInt(`0x${hex}`);
3257
+ }
2930
3258
 
2931
3259
  // core/decrypt/tnSealOutputV2.ts
2932
3260
  var POLL_INTERVAL_MS = 1e3;
@@ -2989,23 +3317,28 @@ function parseCompletedSealOutputResponse(params) {
2989
3317
  }
2990
3318
  return convertSealedData(sealed);
2991
3319
  }
2992
- async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, permission, overallStartTime, retry404TimeoutMs, onPoll) {
3320
+ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, acp, overallStartTime, retry404TimeoutMs, onPoll) {
2993
3321
  const body = {
2994
3322
  ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
2995
3323
  host_chain_id: chainId,
2996
- permit: permission
3324
+ acp
2997
3325
  };
2998
3326
  let attemptIndex = 0;
3327
+ let last404ApiErrorMessage;
2999
3328
  for (; ; ) {
3000
3329
  let response;
3001
3330
  try {
3002
- response = await fetch(`${thresholdNetworkUrl}/v2/sealoutput`, {
3003
- method: "POST",
3004
- headers: {
3005
- "Content-Type": "application/json"
3006
- },
3007
- body: JSON.stringify(body)
3008
- });
3331
+ response = await cofheFetch(
3332
+ `${thresholdNetworkUrl}/v2/sealoutput`,
3333
+ /*op:sealoutput*/
3334
+ {
3335
+ method: "POST",
3336
+ headers: {
3337
+ "Content-Type": "application/json"
3338
+ },
3339
+ body: JSON.stringify(body)
3340
+ }
3341
+ );
3009
3342
  } catch (e) {
3010
3343
  throw new CofheError({
3011
3344
  code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
@@ -3019,16 +3352,19 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, per
3019
3352
  }
3020
3353
  });
3021
3354
  }
3022
- const responseClassification = await classifySubmitResponse({ response });
3355
+ const responseClassification = await classifySubmitResponse({
3356
+ response,
3357
+ fallbackErrorCode: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */
3358
+ });
3023
3359
  if (responseClassification.kind === "fatal-http") {
3024
3360
  throw new CofheError({
3025
- code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
3361
+ code: responseClassification.cofheErrorCode,
3362
+ apiErrorCode: responseClassification.apiErrorCode,
3026
3363
  message: `sealOutput request failed: ${responseClassification.errorMessage}`,
3027
3364
  hint: "Check the threshold network URL and request parameters.",
3028
3365
  context: {
3029
3366
  thresholdNetworkUrl,
3030
- status: response.status,
3031
- statusText: response.statusText,
3367
+ status: responseClassification.status,
3032
3368
  body,
3033
3369
  attemptIndex
3034
3370
  }
@@ -3074,6 +3410,9 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, per
3074
3410
  }
3075
3411
  });
3076
3412
  }
3413
+ if (responseClassification.status === 404) {
3414
+ last404ApiErrorMessage = responseClassification.apiErrorMessage;
3415
+ }
3077
3416
  const elapsedMs = Date.now() - overallStartTime;
3078
3417
  throwIfSubmitRetryTimedOut({
3079
3418
  operationLabel: "sealOutput",
@@ -3084,7 +3423,8 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, per
3084
3423
  overallTimeoutMs: SEAL_OUTPUT_TIMEOUT_MS,
3085
3424
  thresholdNetworkUrl,
3086
3425
  body,
3087
- attemptIndex
3426
+ attemptIndex,
3427
+ lastKnownErrorMessage: last404ApiErrorMessage
3088
3428
  });
3089
3429
  onPoll?.({
3090
3430
  operation: "sealoutput",
@@ -3128,12 +3468,16 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStart
3128
3468
  }
3129
3469
  let response;
3130
3470
  try {
3131
- response = await fetch(`${thresholdNetworkUrl}/v2/sealoutput/${requestId}`, {
3132
- method: "GET",
3133
- headers: {
3134
- "Content-Type": "application/json"
3471
+ response = await cofheFetch(
3472
+ `${thresholdNetworkUrl}/v2/sealoutput/${requestId}`,
3473
+ /*op:sealoutput-poll*/
3474
+ {
3475
+ method: "GET",
3476
+ headers: {
3477
+ "Content-Type": "application/json"
3478
+ }
3135
3479
  }
3136
- });
3480
+ );
3137
3481
  } catch (e) {
3138
3482
  throw new CofheError({
3139
3483
  code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
@@ -3158,15 +3502,10 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStart
3158
3502
  });
3159
3503
  }
3160
3504
  if (!response.ok) {
3161
- let errorMessage = `HTTP ${response.status}`;
3162
- try {
3163
- const errorBody = await response.json();
3164
- errorMessage = errorBody.error_message || errorBody.message || errorMessage;
3165
- } catch {
3166
- errorMessage = response.statusText || errorMessage;
3167
- }
3505
+ const { apiErrorCode, errorMessage } = await parseApiErrorResponseBody(response);
3168
3506
  throw new CofheError({
3169
- code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
3507
+ code: mapApiErrorCodeToCofheErrorCode(apiErrorCode, "SEAL_OUTPUT_FAILED" /* SealOutputFailed */),
3508
+ apiErrorCode,
3170
3509
  message: `sealOutput status poll failed: ${errorMessage}`,
3171
3510
  context: {
3172
3511
  thresholdNetworkUrl,
@@ -3210,7 +3549,7 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStart
3210
3549
  });
3211
3550
  }
3212
3551
  async function tnSealOutputV2(params) {
3213
- const { thresholdNetworkUrl, ctHash, chainId, permission, retry404TimeoutMs, onPoll } = params;
3552
+ const { thresholdNetworkUrl, ctHash, chainId, acp, retry404TimeoutMs, onPoll } = params;
3214
3553
  const normalized404RetryTimeoutMs = normalize404RetryTimeoutMs({
3215
3554
  timeoutMs: retry404TimeoutMs,
3216
3555
  operationLabel: "sealOutput",
@@ -3221,7 +3560,7 @@ async function tnSealOutputV2(params) {
3221
3560
  thresholdNetworkUrl,
3222
3561
  ctHash,
3223
3562
  chainId,
3224
- permission,
3563
+ acp,
3225
3564
  overallStartTime,
3226
3565
  normalized404RetryTimeoutMs,
3227
3566
  onPoll
@@ -3237,8 +3576,8 @@ var DEFAULT_404_RETRY_TIMEOUT_MS2 = 1e4;
3237
3576
  var DecryptForViewBuilder = class extends BaseBuilder {
3238
3577
  ctHash;
3239
3578
  utype;
3240
- permitHash;
3241
- permit;
3579
+ acpHash;
3580
+ acp;
3242
3581
  pollCallback;
3243
3582
  retry404TimeoutMs = DEFAULT_404_RETRY_TIMEOUT_MS2;
3244
3583
  constructor(params) {
@@ -3252,11 +3591,11 @@ var DecryptForViewBuilder = class extends BaseBuilder {
3252
3591
  });
3253
3592
  this.ctHash = params.ctHash;
3254
3593
  this.utype = params.utype;
3255
- this.permitHash = params.permitHash;
3256
- this.permit = params.permit;
3594
+ this.acpHash = params.acpHash;
3595
+ this.acp = params.acp;
3257
3596
  }
3258
3597
  /**
3259
- * @param chainId - Chain to decrypt values from. Used to fetch the threshold network URL and use the correct permit.
3598
+ * @param chainId - Chain to decrypt values from. Used to fetch the threshold network URL and use the correct acp.
3260
3599
  *
3261
3600
  * If not provided, the chainId will be fetched from the connected publicClient.
3262
3601
  *
@@ -3277,7 +3616,7 @@ var DecryptForViewBuilder = class extends BaseBuilder {
3277
3616
  return this.chainId;
3278
3617
  }
3279
3618
  /**
3280
- * @param account - Account to decrypt values from. Used to fetch the correct permit.
3619
+ * @param account - Account to decrypt values from. Used to fetch the correct acp.
3281
3620
  *
3282
3621
  * If not provided, the account will be fetched from the connected walletClient.
3283
3622
  *
@@ -3314,61 +3653,61 @@ var DecryptForViewBuilder = class extends BaseBuilder {
3314
3653
  this.retry404TimeoutMs = timeoutMs;
3315
3654
  return this;
3316
3655
  }
3317
- withPermit(permitOrPermitHash) {
3318
- if (typeof permitOrPermitHash === "string") {
3319
- this.permitHash = permitOrPermitHash;
3320
- this.permit = void 0;
3321
- } else if (permitOrPermitHash === void 0) {
3322
- this.permitHash = void 0;
3323
- this.permit = void 0;
3656
+ withACP(acpOrACPHash) {
3657
+ if (typeof acpOrACPHash === "string") {
3658
+ this.acpHash = acpOrACPHash;
3659
+ this.acp = void 0;
3660
+ } else if (acpOrACPHash === void 0) {
3661
+ this.acpHash = void 0;
3662
+ this.acp = void 0;
3324
3663
  } else {
3325
- this.permit = permitOrPermitHash;
3326
- this.permitHash = void 0;
3664
+ this.acp = acpOrACPHash;
3665
+ this.acpHash = void 0;
3327
3666
  }
3328
3667
  return this;
3329
3668
  }
3330
3669
  /**
3331
- * @param permitHash - Permit hash to decrypt values from. Used to fetch the correct permit.
3670
+ * @param acpHash - ACP hash to decrypt values from. Used to fetch the correct acp.
3332
3671
  *
3333
- * If not provided, the active permit for the chainId and account will be used.
3334
- * If `setPermit()` is called, it will be used regardless of chainId, account, or permitHash.
3672
+ * If not provided, the active acp for the chainId and account will be used.
3673
+ * If `setACP()` is called, it will be used regardless of chainId, account, or acpHash.
3335
3674
  *
3336
3675
  * Example:
3337
3676
  * ```typescript
3338
3677
  * const unsealed = await client.decryptForView(ctHash, utype)
3339
- * .setPermitHash('0x1234567890123456789012345678901234567890')
3678
+ * .setACPHash('0x1234567890123456789012345678901234567890')
3340
3679
  * .execute();
3341
3680
  * ```
3342
3681
  *
3343
3682
  * @returns The chainable DecryptForViewBuilder instance.
3344
3683
  */
3345
- /** @deprecated Use `withPermit(permitHash)` instead. */
3346
- setPermitHash(permitHash) {
3347
- return this.withPermit(permitHash);
3684
+ /** @deprecated Use `withACP(acpHash)` instead. */
3685
+ setACPHash(acpHash) {
3686
+ return this.withACP(acpHash);
3348
3687
  }
3349
- getPermitHash() {
3350
- return this.permitHash;
3688
+ getACPHash() {
3689
+ return this.acpHash;
3351
3690
  }
3352
3691
  /**
3353
- * @param permit - Permit to decrypt values with. If provided, it will be used regardless of chainId, account, or permitHash.
3692
+ * @param acp - ACP to decrypt values with. If provided, it will be used regardless of chainId, account, or acpHash.
3354
3693
  *
3355
- * If not provided, the permit will be determined by chainId, account, and permitHash.
3694
+ * If not provided, the acp will be determined by chainId, account, and acpHash.
3356
3695
  *
3357
3696
  * Example:
3358
3697
  * ```typescript
3359
3698
  * const unsealed = await client.decryptForView(ctHash, utype)
3360
- * .setPermit(permit)
3699
+ * .setACP(acp)
3361
3700
  * .execute();
3362
3701
  * ```
3363
3702
  *
3364
3703
  * @returns The chainable DecryptForViewBuilder instance.
3365
3704
  */
3366
- /** @deprecated Use `withPermit(permit)` instead. */
3367
- setPermit(permit) {
3368
- return this.withPermit(permit);
3705
+ /** @deprecated Use `withACP(acp)` instead. */
3706
+ setACP(acp) {
3707
+ return this.withACP(acp);
3369
3708
  }
3370
- getPermit() {
3371
- return this.permit;
3709
+ getACP() {
3710
+ return this.acp;
3372
3711
  }
3373
3712
  async getThresholdNetworkUrl() {
3374
3713
  this.assertChainId();
@@ -3384,77 +3723,77 @@ var DecryptForViewBuilder = class extends BaseBuilder {
3384
3723
  }
3385
3724
  });
3386
3725
  }
3387
- async getResolvedPermit() {
3388
- if (this.permit)
3389
- return this.permit;
3726
+ async getResolvedACP() {
3727
+ if (this.acp)
3728
+ return this.acp;
3390
3729
  this.assertChainId();
3391
3730
  this.assertAccount();
3392
- if (this.permitHash) {
3393
- const permit2 = await permits.getPermit(this.chainId, this.account, this.permitHash);
3394
- if (!permit2) {
3731
+ if (this.acpHash) {
3732
+ const acp2 = await acps.getACP(this.chainId, this.account, this.acpHash);
3733
+ if (!acp2) {
3395
3734
  throw new CofheError({
3396
- code: "PERMIT_NOT_FOUND" /* PermitNotFound */,
3397
- message: `Permit with hash <${this.permitHash}> not found for account <${this.account}> and chainId <${this.chainId}>`,
3398
- hint: "Ensure the permit exists and is valid.",
3735
+ code: "ACP_NOT_FOUND" /* ACPNotFound */,
3736
+ message: `ACP with hash <${this.acpHash}> not found for account <${this.account}> and chainId <${this.chainId}>`,
3737
+ hint: "Ensure the acp exists and is valid.",
3399
3738
  context: {
3400
3739
  chainId: this.chainId,
3401
3740
  account: this.account,
3402
- permitHash: this.permitHash
3741
+ acpHash: this.acpHash
3403
3742
  }
3404
3743
  });
3405
3744
  }
3406
- return permit2;
3745
+ return acp2;
3407
3746
  }
3408
- const permit = await permits.getActivePermit(this.chainId, this.account);
3409
- if (!permit) {
3747
+ const acp = await acps.getActiveACP(this.chainId, this.account);
3748
+ if (!acp) {
3410
3749
  throw new CofheError({
3411
- code: "PERMIT_NOT_FOUND" /* PermitNotFound */,
3412
- message: `Active permit not found for chainId <${this.chainId}> and account <${this.account}>`,
3413
- hint: "Ensure a permit exists for this account on this chain.",
3750
+ code: "ACP_NOT_FOUND" /* ACPNotFound */,
3751
+ message: `Active acp not found for chainId <${this.chainId}> and account <${this.account}>`,
3752
+ hint: "Ensure an ACP exists for this account on this chain.",
3414
3753
  context: {
3415
3754
  chainId: this.chainId,
3416
3755
  account: this.account
3417
3756
  }
3418
3757
  });
3419
3758
  }
3420
- return permit;
3759
+ return acp;
3421
3760
  }
3422
3761
  /**
3423
3762
  * On hardhat, interact with MockZkVerifier contract instead of CoFHE
3424
3763
  */
3425
- async mocksSealOutput(permit) {
3764
+ async mocksSealOutput(acp) {
3426
3765
  this.assertPublicClient();
3427
3766
  const mocksDecryptDelay = this.config.mocks.decryptDelay;
3428
3767
  if (mocksDecryptDelay > 0)
3429
3768
  await sleep(mocksDecryptDelay);
3430
- return cofheMocksDecryptForView(this.ctHash, this.utype, permit, this.publicClient);
3769
+ return cofheMocksDecryptForView(this.ctHash, this.utype, acp, this.publicClient);
3431
3770
  }
3432
3771
  /**
3433
3772
  * In the production context, perform a true decryption with the CoFHE coprocessor.
3434
3773
  */
3435
- async productionSealOutput(permit) {
3774
+ async productionSealOutput(acp) {
3436
3775
  this.assertChainId();
3437
3776
  this.assertPublicClient();
3438
3777
  const thresholdNetworkUrl = await this.getThresholdNetworkUrl();
3439
- const permission = PermitUtils.getPermission(permit, true);
3778
+ const wireAcp = ACPUtils.getPublic(acp, true);
3440
3779
  const sealed = await tnSealOutputV2({
3441
3780
  ctHash: this.ctHash,
3442
3781
  chainId: this.chainId,
3443
- permission,
3782
+ acp: wireAcp,
3444
3783
  thresholdNetworkUrl,
3445
3784
  retry404TimeoutMs: this.retry404TimeoutMs,
3446
3785
  onPoll: this.pollCallback
3447
3786
  });
3448
- return PermitUtils.unseal(permit, sealed);
3787
+ return ACPUtils.unseal(acp, sealed);
3449
3788
  }
3450
3789
  /**
3451
3790
  * Final step of the decryption process. MUST BE CALLED LAST IN THE CHAIN.
3452
3791
  *
3453
3792
  * This will:
3454
- * - Use a permit based on provided permit OR chainId + account + permitHash
3455
- * - Check permit validity
3456
- * - Call CoFHE `/sealoutput` with the permit, which returns a sealed (encrypted) item
3457
- * - Unseal the sealed item with the permit
3793
+ * - Use an ACP based on provided acp OR chainId + account + acpHash
3794
+ * - Check acp validity
3795
+ * - Call CoFHE `/sealoutput` with the acp, which returns a sealed (encrypted) item
3796
+ * - Unseal the sealed item with the acp
3458
3797
  * - Return the unsealed item
3459
3798
  *
3460
3799
  * Example:
@@ -3462,7 +3801,7 @@ var DecryptForViewBuilder = class extends BaseBuilder {
3462
3801
  * const unsealed = await client.decryptForView(ctHash, utype)
3463
3802
  * .setChainId(11155111) // optional
3464
3803
  * .setAccount('0x123...890') // optional
3465
- * .withPermit() // optional
3804
+ * .withACP() // optional
3466
3805
  * .execute(); // execute
3467
3806
  * ```
3468
3807
  *
@@ -3470,14 +3809,14 @@ var DecryptForViewBuilder = class extends BaseBuilder {
3470
3809
  */
3471
3810
  async execute() {
3472
3811
  this.validateUtypeOrThrow();
3473
- const permit = await this.getResolvedPermit();
3474
- PermitUtils.validate(permit);
3475
- const chainId = permit._signedDomain.chainId;
3812
+ const acp = await this.getResolvedACP();
3813
+ ACPUtils.validate(acp);
3814
+ const chainId = acp._signedDomain.chainId;
3476
3815
  let unsealed;
3477
3816
  if (chainId === hardhat2.id) {
3478
- unsealed = await this.mocksSealOutput(permit);
3817
+ unsealed = await this.mocksSealOutput(acp);
3479
3818
  } else {
3480
- unsealed = await this.productionSealOutput(permit);
3819
+ unsealed = await this.productionSealOutput(acp);
3481
3820
  }
3482
3821
  return convertViaUtype(this.utype, unsealed);
3483
3822
  }
@@ -3485,28 +3824,28 @@ var DecryptForViewBuilder = class extends BaseBuilder {
3485
3824
  var UINT_TYPE_MASK = 0x7fn;
3486
3825
  var TYPE_BYTE_OFFSET = 8n;
3487
3826
  var getEncryptionTypeFromCtHash = (ctHash) => Number(ctHash >> TYPE_BYTE_OFFSET & UINT_TYPE_MASK);
3488
- async function cofheMocksDecryptForTx(ctHash, utype, permit, publicClient) {
3827
+ async function cofheMocksDecryptForTx(ctHash, utype, acp, publicClient) {
3489
3828
  let allowed;
3490
3829
  let error;
3491
3830
  let decryptedValue;
3492
- if (permit !== null) {
3493
- let permission = PermitUtils.getPermission(permit, true);
3831
+ if (acp !== null) {
3832
+ const wireAcp = ACPUtils.getPublic(acp, true);
3494
3833
  const permissionWithBigInts = {
3495
- ...permission,
3496
- expiration: BigInt(permission.expiration),
3497
- validatorId: BigInt(permission.validatorId)
3834
+ ...wireAcp,
3835
+ expiration: BigInt(wireAcp.expiration),
3836
+ revokerData: BigInt(wireAcp.revokerData)
3498
3837
  };
3499
3838
  [allowed, error, decryptedValue] = await publicClient.readContract({
3500
3839
  address: MOCKS_THRESHOLD_NETWORK_ADDRESS,
3501
3840
  abi: MockThresholdNetworkAbi,
3502
- functionName: "decryptForTxWithPermit",
3841
+ functionName: "decryptForTxWithACP",
3503
3842
  args: [BigInt(ctHash), permissionWithBigInts]
3504
3843
  });
3505
3844
  } else {
3506
3845
  [allowed, error, decryptedValue] = await publicClient.readContract({
3507
3846
  address: MOCKS_THRESHOLD_NETWORK_ADDRESS,
3508
3847
  abi: MockThresholdNetworkAbi,
3509
- functionName: "decryptForTxWithoutPermit",
3848
+ functionName: "decryptForTxWithoutACP",
3510
3849
  args: [BigInt(ctHash)]
3511
3850
  });
3512
3851
  }
@@ -3541,62 +3880,6 @@ async function cofheMocksDecryptForTx(ctHash, utype, permit, publicClient) {
3541
3880
  signature
3542
3881
  };
3543
3882
  }
3544
- function normalizeTnSignature(signature) {
3545
- if (typeof signature !== "string") {
3546
- throw new CofheError({
3547
- code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
3548
- message: "decrypt response missing signature",
3549
- context: {
3550
- signature
3551
- }
3552
- });
3553
- }
3554
- const trimmed = signature.trim();
3555
- if (trimmed.length === 0) {
3556
- throw new CofheError({
3557
- code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
3558
- message: "decrypt response returned empty signature"
3559
- });
3560
- }
3561
- const prefixed = trimmed.startsWith("0x") ? trimmed : `0x${trimmed}`;
3562
- const parsed = viem.parseSignature(prefixed);
3563
- return viem.serializeSignature(parsed);
3564
- }
3565
- function parseDecryptedBytesToBigInt(decrypted) {
3566
- if (!Array.isArray(decrypted)) {
3567
- throw new CofheError({
3568
- code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
3569
- message: "decrypt response field <decrypted> must be a byte array",
3570
- context: {
3571
- decrypted
3572
- }
3573
- });
3574
- }
3575
- if (decrypted.length === 0) {
3576
- throw new CofheError({
3577
- code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
3578
- message: "decrypt response field <decrypted> was an empty byte array",
3579
- context: {
3580
- decrypted
3581
- }
3582
- });
3583
- }
3584
- let hex = "";
3585
- for (const b of decrypted) {
3586
- if (typeof b !== "number" || !Number.isInteger(b) || b < 0 || b > 255) {
3587
- throw new CofheError({
3588
- code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
3589
- message: "decrypt response field <decrypted> contained a non-byte value",
3590
- context: {
3591
- badElement: b,
3592
- decrypted
3593
- }
3594
- });
3595
- }
3596
- hex += b.toString(16).padStart(2, "0");
3597
- }
3598
- return BigInt(`0x${hex}`);
3599
- }
3600
3883
 
3601
3884
  // core/decrypt/tnDecryptV2.ts
3602
3885
  var POLL_INTERVAL_MS2 = 1e3;
@@ -3718,25 +4001,30 @@ function assertDecryptStatusResponseV2(value) {
3718
4001
  }
3719
4002
  return value;
3720
4003
  }
3721
- async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, permission, overallStartTime, retry404TimeoutMs, onPoll) {
4004
+ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, acp, overallStartTime, retry404TimeoutMs, onPoll) {
3722
4005
  const body = {
3723
4006
  ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
3724
4007
  host_chain_id: chainId
3725
4008
  };
3726
- if (permission) {
3727
- body.permit = permission;
4009
+ if (acp) {
4010
+ body.acp = acp;
3728
4011
  }
3729
4012
  let attemptIndex = 0;
4013
+ let last404ApiErrorMessage;
3730
4014
  for (; ; ) {
3731
4015
  let response;
3732
4016
  try {
3733
- response = await fetch(`${thresholdNetworkUrl}/v2/decrypt`, {
3734
- method: "POST",
3735
- headers: {
3736
- "Content-Type": "application/json"
3737
- },
3738
- body: JSON.stringify(body)
3739
- });
4017
+ response = await cofheFetch(
4018
+ `${thresholdNetworkUrl}/v2/decrypt`,
4019
+ /*op:decrypt*/
4020
+ {
4021
+ method: "POST",
4022
+ headers: {
4023
+ "Content-Type": "application/json"
4024
+ },
4025
+ body: JSON.stringify(body)
4026
+ }
4027
+ );
3740
4028
  } catch (e) {
3741
4029
  throw new CofheError({
3742
4030
  code: "DECRYPT_FAILED" /* DecryptFailed */,
@@ -3750,16 +4038,19 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, perm
3750
4038
  }
3751
4039
  });
3752
4040
  }
3753
- const responseClassification = await classifySubmitResponse({ response });
4041
+ const responseClassification = await classifySubmitResponse({
4042
+ response,
4043
+ fallbackErrorCode: "DECRYPT_FAILED" /* DecryptFailed */
4044
+ });
3754
4045
  if (responseClassification.kind === "fatal-http") {
3755
4046
  throw new CofheError({
3756
- code: "DECRYPT_FAILED" /* DecryptFailed */,
4047
+ code: responseClassification.cofheErrorCode,
4048
+ apiErrorCode: responseClassification.apiErrorCode,
3757
4049
  message: `decrypt request failed: ${responseClassification.errorMessage}`,
3758
4050
  hint: "Check the threshold network URL and request parameters.",
3759
4051
  context: {
3760
4052
  thresholdNetworkUrl,
3761
- status: response.status,
3762
- statusText: response.statusText,
4053
+ status: responseClassification.status,
3763
4054
  body,
3764
4055
  attemptIndex
3765
4056
  }
@@ -3807,6 +4098,9 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, perm
3807
4098
  }
3808
4099
  });
3809
4100
  }
4101
+ if (responseClassification.status === 404) {
4102
+ last404ApiErrorMessage = responseClassification.apiErrorMessage;
4103
+ }
3810
4104
  const elapsedMs = Date.now() - overallStartTime;
3811
4105
  throwIfSubmitRetryTimedOut({
3812
4106
  operationLabel: "decrypt",
@@ -3817,7 +4111,8 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, perm
3817
4111
  overallTimeoutMs: DECRYPT_TIMEOUT_MS,
3818
4112
  thresholdNetworkUrl,
3819
4113
  body,
3820
- attemptIndex
4114
+ attemptIndex,
4115
+ lastKnownErrorMessage: last404ApiErrorMessage
3821
4116
  });
3822
4117
  onPoll?.({
3823
4118
  operation: "decrypt",
@@ -3861,12 +4156,16 @@ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartT
3861
4156
  }
3862
4157
  let response;
3863
4158
  try {
3864
- response = await fetch(`${thresholdNetworkUrl}/v2/decrypt/${requestId}`, {
3865
- method: "GET",
3866
- headers: {
3867
- "Content-Type": "application/json"
4159
+ response = await cofheFetch(
4160
+ `${thresholdNetworkUrl}/v2/decrypt/${requestId}`,
4161
+ /*op:decrypt-poll*/
4162
+ {
4163
+ method: "GET",
4164
+ headers: {
4165
+ "Content-Type": "application/json"
4166
+ }
3868
4167
  }
3869
- });
4168
+ );
3870
4169
  } catch (e) {
3871
4170
  throw new CofheError({
3872
4171
  code: "DECRYPT_FAILED" /* DecryptFailed */,
@@ -3891,17 +4190,10 @@ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartT
3891
4190
  });
3892
4191
  }
3893
4192
  if (!response.ok) {
3894
- let errorMessage = `HTTP ${response.status}`;
3895
- try {
3896
- const errorBody = await response.json();
3897
- const maybeMessage = errorBody.error_message || errorBody.message;
3898
- if (typeof maybeMessage === "string" && maybeMessage.length > 0)
3899
- errorMessage = maybeMessage;
3900
- } catch {
3901
- errorMessage = response.statusText || errorMessage;
3902
- }
4193
+ const { apiErrorCode, errorMessage } = await parseApiErrorResponseBody(response);
3903
4194
  throw new CofheError({
3904
- code: "DECRYPT_FAILED" /* DecryptFailed */,
4195
+ code: mapApiErrorCodeToCofheErrorCode(apiErrorCode, "DECRYPT_FAILED" /* DecryptFailed */),
4196
+ apiErrorCode,
3905
4197
  message: `decrypt status poll failed: ${errorMessage}`,
3906
4198
  context: {
3907
4199
  thresholdNetworkUrl,
@@ -3946,7 +4238,7 @@ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartT
3946
4238
  });
3947
4239
  }
3948
4240
  async function tnDecryptV2(params) {
3949
- const { thresholdNetworkUrl, ctHash, chainId, permission, retry404TimeoutMs, onPoll } = params;
4241
+ const { thresholdNetworkUrl, ctHash, chainId, acp, retry404TimeoutMs, onPoll } = params;
3950
4242
  const normalized404RetryTimeoutMs = normalize404RetryTimeoutMs({
3951
4243
  timeoutMs: retry404TimeoutMs,
3952
4244
  operationLabel: "decrypt",
@@ -3957,7 +4249,7 @@ async function tnDecryptV2(params) {
3957
4249
  thresholdNetworkUrl,
3958
4250
  ctHash,
3959
4251
  chainId,
3960
- permission,
4252
+ acp,
3961
4253
  overallStartTime,
3962
4254
  normalized404RetryTimeoutMs,
3963
4255
  onPoll
@@ -3972,9 +4264,9 @@ async function tnDecryptV2(params) {
3972
4264
  var DEFAULT_404_RETRY_TIMEOUT_MS3 = 1e4;
3973
4265
  var DecryptForTxBuilder = class extends BaseBuilder {
3974
4266
  ctHash;
3975
- permitHash;
3976
- permit;
3977
- permitSelection = "unset";
4267
+ acpHash;
4268
+ acp;
4269
+ acpSelection = "unset";
3978
4270
  pollCallback;
3979
4271
  retry404TimeoutMs = DEFAULT_404_RETRY_TIMEOUT_MS3;
3980
4272
  constructor(params) {
@@ -4019,137 +4311,137 @@ var DecryptForTxBuilder = class extends BaseBuilder {
4019
4311
  this.retry404TimeoutMs = timeoutMs;
4020
4312
  return this;
4021
4313
  }
4022
- withPermit(permitOrPermitHash) {
4023
- if (this.permitSelection === "with-permit") {
4314
+ withACP(acpOrACPHash) {
4315
+ if (this.acpSelection === "with-acp") {
4024
4316
  throw new CofheError({
4025
4317
  code: "INTERNAL_ERROR" /* InternalError */,
4026
- message: "decryptForTx: withPermit() can only be selected once.",
4027
- hint: "Choose the permit mode once. If you need a different permit, start a new decryptForTx() builder chain."
4318
+ message: "decryptForTx: withACP() can only be selected once.",
4319
+ hint: "Choose the acp mode once. If you need a different acp, start a new decryptForTx() builder chain."
4028
4320
  });
4029
4321
  }
4030
- if (this.permitSelection === "without-permit") {
4322
+ if (this.acpSelection === "without-acp") {
4031
4323
  throw new CofheError({
4032
4324
  code: "INTERNAL_ERROR" /* InternalError */,
4033
- message: "decryptForTx: cannot call withPermit() after withoutPermit() has been selected.",
4034
- hint: "Choose exactly one permit mode: either call .withPermit(...) or .withoutPermit(), but not both."
4325
+ message: "decryptForTx: cannot call withACP() after withoutACP() has been selected.",
4326
+ hint: "Choose exactly one acp mode: either call .withACP(...) or .withoutACP(), but not both."
4035
4327
  });
4036
4328
  }
4037
- this.permitSelection = "with-permit";
4038
- if (typeof permitOrPermitHash === "string") {
4039
- this.permitHash = permitOrPermitHash;
4040
- this.permit = void 0;
4041
- } else if (permitOrPermitHash === void 0) {
4042
- this.permitHash = void 0;
4043
- this.permit = void 0;
4329
+ this.acpSelection = "with-acp";
4330
+ if (typeof acpOrACPHash === "string") {
4331
+ this.acpHash = acpOrACPHash;
4332
+ this.acp = void 0;
4333
+ } else if (acpOrACPHash === void 0) {
4334
+ this.acpHash = void 0;
4335
+ this.acp = void 0;
4044
4336
  } else {
4045
- this.permit = permitOrPermitHash;
4046
- this.permitHash = void 0;
4337
+ this.acp = acpOrACPHash;
4338
+ this.acpHash = void 0;
4047
4339
  }
4048
4340
  return this;
4049
4341
  }
4050
4342
  /**
4051
- * Select "no permit" mode.
4343
+ * Select "no acp" mode.
4052
4344
  *
4053
- * This uses global allowance (no permit required) and sends an empty permission payload to `/decrypt`.
4345
+ * This uses global allowance (no acp required) and sends an empty permission payload to `/decrypt`.
4054
4346
  */
4055
- withoutPermit() {
4056
- if (this.permitSelection === "without-permit") {
4347
+ withoutACP() {
4348
+ if (this.acpSelection === "without-acp") {
4057
4349
  throw new CofheError({
4058
4350
  code: "INTERNAL_ERROR" /* InternalError */,
4059
- message: "decryptForTx: withoutPermit() can only be selected once.",
4060
- hint: "Choose the permit mode once. If you need a different mode, start a new decryptForTx() builder chain."
4351
+ message: "decryptForTx: withoutACP() can only be selected once.",
4352
+ hint: "Choose the acp mode once. If you need a different mode, start a new decryptForTx() builder chain."
4061
4353
  });
4062
4354
  }
4063
- if (this.permitSelection === "with-permit") {
4355
+ if (this.acpSelection === "with-acp") {
4064
4356
  throw new CofheError({
4065
4357
  code: "INTERNAL_ERROR" /* InternalError */,
4066
- message: "decryptForTx: cannot call withoutPermit() after withPermit() has been selected.",
4067
- hint: "Choose exactly one permit mode: either call .withPermit(...) or .withoutPermit(), but not both."
4358
+ message: "decryptForTx: cannot call withoutACP() after withACP() has been selected.",
4359
+ hint: "Choose exactly one acp mode: either call .withACP(...) or .withoutACP(), but not both."
4068
4360
  });
4069
4361
  }
4070
- this.permitSelection = "without-permit";
4071
- this.permitHash = void 0;
4072
- this.permit = void 0;
4362
+ this.acpSelection = "without-acp";
4363
+ this.acpHash = void 0;
4364
+ this.acp = void 0;
4073
4365
  return this;
4074
4366
  }
4075
- getPermit() {
4076
- return this.permit;
4367
+ getACP() {
4368
+ return this.acp;
4077
4369
  }
4078
- getPermitHash() {
4079
- return this.permitHash;
4370
+ getACPHash() {
4371
+ return this.acpHash;
4080
4372
  }
4081
4373
  async getThresholdNetworkUrl() {
4082
4374
  this.assertChainId();
4083
4375
  return getThresholdNetworkUrlOrThrow(this.config, this.chainId);
4084
4376
  }
4085
- async getResolvedPermit() {
4086
- if (this.permitSelection === "unset") {
4377
+ async getResolvedACP() {
4378
+ if (this.acpSelection === "unset") {
4087
4379
  throw new CofheError({
4088
4380
  code: "INTERNAL_ERROR" /* InternalError */,
4089
- message: "decryptForTx: missing permit selection; call withPermit(...) or withoutPermit() before execute().",
4090
- hint: "Call .withPermit() to use the active permit, or .withoutPermit() for global allowance."
4381
+ message: "decryptForTx: missing acp selection; call withACP(...) or withoutACP() before execute().",
4382
+ hint: "Call .withACP() to use the active acp, or .withoutACP() for global allowance."
4091
4383
  });
4092
4384
  }
4093
- if (this.permitSelection === "without-permit") {
4385
+ if (this.acpSelection === "without-acp") {
4094
4386
  return null;
4095
4387
  }
4096
- if (this.permit)
4097
- return this.permit;
4388
+ if (this.acp)
4389
+ return this.acp;
4098
4390
  this.assertChainId();
4099
4391
  this.assertAccount();
4100
- if (this.permitHash) {
4101
- const permit2 = await permits.getPermit(this.chainId, this.account, this.permitHash);
4102
- if (!permit2) {
4392
+ if (this.acpHash) {
4393
+ const acp2 = await acps.getACP(this.chainId, this.account, this.acpHash);
4394
+ if (!acp2) {
4103
4395
  throw new CofheError({
4104
- code: "PERMIT_NOT_FOUND" /* PermitNotFound */,
4105
- message: `Permit with hash <${this.permitHash}> not found for account <${this.account}> and chainId <${this.chainId}>`,
4106
- hint: "Ensure the permit exists and is valid.",
4396
+ code: "ACP_NOT_FOUND" /* ACPNotFound */,
4397
+ message: `ACP with hash <${this.acpHash}> not found for account <${this.account}> and chainId <${this.chainId}>`,
4398
+ hint: "Ensure the acp exists and is valid.",
4107
4399
  context: {
4108
4400
  chainId: this.chainId,
4109
4401
  account: this.account,
4110
- permitHash: this.permitHash
4402
+ acpHash: this.acpHash
4111
4403
  }
4112
4404
  });
4113
4405
  }
4114
- return permit2;
4406
+ return acp2;
4115
4407
  }
4116
- const permit = await permits.getActivePermit(this.chainId, this.account);
4117
- if (!permit) {
4408
+ const acp = await acps.getActiveACP(this.chainId, this.account);
4409
+ if (!acp) {
4118
4410
  throw new CofheError({
4119
- code: "PERMIT_NOT_FOUND" /* PermitNotFound */,
4120
- message: `Active permit not found for chainId <${this.chainId}> and account <${this.account}>`,
4121
- hint: "Create a permit (e.g. client.permits.createSelf(...)) and/or set it active (client.permits.selectActivePermit(hash)).",
4411
+ code: "ACP_NOT_FOUND" /* ACPNotFound */,
4412
+ message: `Active acp not found for chainId <${this.chainId}> and account <${this.account}>`,
4413
+ hint: "Create an ACP (e.g. client.acp.createSelf(...)) and/or set it active (client.acp.selectActiveACP(hash)).",
4122
4414
  context: {
4123
4415
  chainId: this.chainId,
4124
4416
  account: this.account
4125
4417
  }
4126
4418
  });
4127
4419
  }
4128
- return permit;
4420
+ return acp;
4129
4421
  }
4130
4422
  /**
4131
4423
  * On hardhat, interact with MockThresholdNetwork contract
4132
4424
  */
4133
- async mocksDecryptForTx(permit) {
4425
+ async mocksDecryptForTx(acp) {
4134
4426
  this.assertPublicClient();
4135
4427
  const delay = this.config.mocks.decryptDelay;
4136
4428
  if (delay > 0)
4137
4429
  await sleep(delay);
4138
- const result = await cofheMocksDecryptForTx(this.ctHash, 0, permit, this.publicClient);
4430
+ const result = await cofheMocksDecryptForTx(this.ctHash, 0, acp, this.publicClient);
4139
4431
  return result;
4140
4432
  }
4141
4433
  /**
4142
4434
  * In the production context, perform a true decryption with the CoFHE coprocessor.
4143
4435
  */
4144
- async productionDecryptForTx(permit) {
4436
+ async productionDecryptForTx(acp) {
4145
4437
  this.assertChainId();
4146
4438
  this.assertPublicClient();
4147
4439
  const thresholdNetworkUrl = await this.getThresholdNetworkUrl();
4148
- const permission = permit ? PermitUtils.getPermission(permit, true) : null;
4440
+ const wireAcp = acp ? ACPUtils.getPublic(acp, true) : null;
4149
4441
  const { decryptedValue, signature } = await tnDecryptV2({
4150
4442
  ctHash: this.ctHash,
4151
4443
  chainId: this.chainId,
4152
- permission,
4444
+ acp: wireAcp,
4153
4445
  thresholdNetworkUrl,
4154
4446
  retry404TimeoutMs: this.retry404TimeoutMs,
4155
4447
  onPoll: this.pollCallback
@@ -4163,19 +4455,19 @@ var DecryptForTxBuilder = class extends BaseBuilder {
4163
4455
  /**
4164
4456
  * Final step of the decryptForTx process. MUST BE CALLED LAST IN THE CHAIN.
4165
4457
  *
4166
- * You must explicitly choose one permit mode before calling `execute()`:
4167
- * - `withPermit(permit)` / `withPermit(permitHash)` / `withPermit()` (active permit)
4168
- * - `withoutPermit()` (global allowance)
4458
+ * You must explicitly choose one acp mode before calling `execute()`:
4459
+ * - `withACP(acp)` / `withACP(acpHash)` / `withACP()` (active acp)
4460
+ * - `withoutACP()` (global allowance)
4169
4461
  */
4170
4462
  async execute() {
4171
- const permit = await this.getResolvedPermit();
4172
- if (permit !== null) {
4173
- PermitUtils.validate(permit);
4174
- const chainId = permit._signedDomain.chainId;
4463
+ const acp = await this.getResolvedACP();
4464
+ if (acp !== null) {
4465
+ ACPUtils.validate(acp);
4466
+ const chainId = acp._signedDomain.chainId;
4175
4467
  if (chainId === hardhat2.id) {
4176
- return await this.mocksDecryptForTx(permit);
4468
+ return await this.mocksDecryptForTx(acp);
4177
4469
  } else {
4178
- return await this.productionDecryptForTx(permit);
4470
+ return await this.productionDecryptForTx(acp);
4179
4471
  }
4180
4472
  } else {
4181
4473
  if (!this.chainId) {
@@ -4238,6 +4530,21 @@ function createCofheClientBase(opts) {
4238
4530
  const updateConnectState = (partial) => {
4239
4531
  connectStore.setState((state) => ({ ...state, ...partial }));
4240
4532
  };
4533
+ const _resolveSharingRegistry = async (publicClient, chainId) => {
4534
+ const configured = opts.config.acp?.sharingRegistry?.[chainId];
4535
+ if (configured != null)
4536
+ return configured;
4537
+ const registry = (await acps.getAclServedAddresses(publicClient, chainId)).shareRegistry;
4538
+ if (registry == null) {
4539
+ throw new CofheError({
4540
+ code: "MISSING_CONFIG" /* MissingConfig */,
4541
+ message: `No ACP share registry available for chainId <${chainId}>`,
4542
+ hint: "The ACL on this chain does not serve a share registry address. Set `acp.sharingRegistry` in the cofhe config to use on-chain sharing.",
4543
+ context: { chainId }
4544
+ });
4545
+ }
4546
+ return registry;
4547
+ };
4241
4548
  const _requireConnected = () => {
4242
4549
  const state = connectStore.getState();
4243
4550
  const notConnected = !state.connected || !state.account || !state.chainId || !state.publicClient || !state.walletClient;
@@ -4360,74 +4667,147 @@ function createCofheClientBase(opts) {
4360
4667
  }
4361
4668
  return { chainId: _chainId, account: _account };
4362
4669
  };
4363
- const clientPermits = {
4670
+ const clientACPs = {
4364
4671
  // Pass through store access
4365
- getSnapshot: permits.getSnapshot,
4366
- subscribe: permits.subscribe,
4672
+ getSnapshot: acps.getSnapshot,
4673
+ subscribe: acps.subscribe,
4367
4674
  // Creation methods (require connection)
4368
4675
  createSelf: async (options, clients) => {
4369
4676
  _requireConnected();
4370
4677
  const { publicClient, walletClient } = clients ?? connectStore.getState();
4371
- return permits.createSelf(options, publicClient, walletClient);
4678
+ const chainId = await publicClient.getChainId();
4679
+ return acps.createSelf(
4680
+ await acps.applyACPDefaultsFromChain(options, opts.config.acp, publicClient, chainId),
4681
+ publicClient,
4682
+ walletClient
4683
+ );
4372
4684
  },
4373
4685
  createSharing: async (options, clients) => {
4374
4686
  _requireConnected();
4375
4687
  const { publicClient, walletClient } = clients ?? connectStore.getState();
4376
- return permits.createSharing(options, publicClient, walletClient);
4688
+ const chainId = await publicClient.getChainId();
4689
+ return acps.createSharing(
4690
+ await acps.applyACPDefaultsFromChain(options, opts.config.acp, publicClient, chainId),
4691
+ publicClient,
4692
+ walletClient
4693
+ );
4377
4694
  },
4378
4695
  importShared: async (options, clients) => {
4379
4696
  _requireConnected();
4380
4697
  const { publicClient, walletClient } = clients ?? connectStore.getState();
4381
- return permits.importShared(options, publicClient, walletClient);
4698
+ return acps.importShared(options, publicClient, walletClient);
4382
4699
  },
4383
4700
  // Get or create methods (require connection)
4384
- getOrCreateSelfPermit: async (chainId, account, options) => {
4701
+ getOrCreateSelfACP: async (chainId, account, options) => {
4385
4702
  _requireConnected();
4386
4703
  const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
4387
4704
  const { publicClient, walletClient } = connectStore.getState();
4388
- return permits.getOrCreateSelfPermit(publicClient, walletClient, _chainId, _account, options);
4705
+ const optionsWithDefaults = await acps.applyACPDefaultsFromChain(
4706
+ options ?? { issuer: _account, name: "Autogenerated Self ACP" },
4707
+ opts.config.acp,
4708
+ publicClient,
4709
+ _chainId
4710
+ );
4711
+ return acps.getOrCreateSelfACP(publicClient, walletClient, _chainId, _account, optionsWithDefaults);
4389
4712
  },
4390
- getOrCreateSharingPermit: async (options, chainId, account) => {
4713
+ getOrCreateSharingACP: async (options, chainId, account) => {
4391
4714
  _requireConnected();
4392
4715
  const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
4393
4716
  const { publicClient, walletClient } = connectStore.getState();
4394
- return permits.getOrCreateSharingPermit(publicClient, walletClient, options, _chainId, _account);
4717
+ return acps.getOrCreateSharingACP(
4718
+ publicClient,
4719
+ walletClient,
4720
+ await acps.applyACPDefaultsFromChain(options, opts.config.acp, publicClient, _chainId),
4721
+ _chainId,
4722
+ _account
4723
+ );
4724
+ },
4725
+ // Revocation (require connection)
4726
+ revokeACP: async (acp) => {
4727
+ _requireConnected();
4728
+ const { walletClient } = connectStore.getState();
4729
+ return acps.revokeACP(acp, walletClient);
4730
+ },
4731
+ revokeAllACPs: async (revokerContract) => {
4732
+ _requireConnected();
4733
+ const { publicClient, walletClient } = connectStore.getState();
4734
+ return acps.revokeAllACPs(walletClient, publicClient, revokerContract);
4735
+ },
4736
+ isACPRevoked: async (acp) => {
4737
+ _requireConnected();
4738
+ const { publicClient } = connectStore.getState();
4739
+ return acps.isACPRevoked(acp, publicClient);
4740
+ },
4741
+ // On-chain sharing (require connection + config.acp.sharingRegistry)
4742
+ shareOnChain: async (acp) => {
4743
+ _requireConnected();
4744
+ const { publicClient, walletClient } = connectStore.getState();
4745
+ const chainId = await publicClient.getChainId();
4746
+ const sharingRegistry = await _resolveSharingRegistry(publicClient, chainId);
4747
+ return acps.shareOnChain(acp, walletClient, sharingRegistry);
4748
+ },
4749
+ getIncomingShares: async () => {
4750
+ _requireConnected();
4751
+ const { publicClient, walletClient } = connectStore.getState();
4752
+ const chainId = await publicClient.getChainId();
4753
+ const account = walletClient.account.address;
4754
+ const sharingRegistry = await _resolveSharingRegistry(publicClient, chainId);
4755
+ return acps.getIncomingShares(publicClient, sharingRegistry, account);
4756
+ },
4757
+ importFromChain: async (share) => {
4758
+ _requireConnected();
4759
+ const { publicClient, walletClient } = connectStore.getState();
4760
+ return acps.importFromChain(share, publicClient, walletClient);
4761
+ },
4762
+ dismissShare: async (shareId) => {
4763
+ _requireConnected();
4764
+ const { publicClient, walletClient } = connectStore.getState();
4765
+ const chainId = await publicClient.getChainId();
4766
+ const sharingRegistry = await _resolveSharingRegistry(publicClient, chainId);
4767
+ return acps.removeShareOnChain(shareId, walletClient, sharingRegistry);
4768
+ },
4769
+ cancelShare: async (shareId) => {
4770
+ _requireConnected();
4771
+ const { publicClient, walletClient } = connectStore.getState();
4772
+ const chainId = await publicClient.getChainId();
4773
+ const sharingRegistry = await _resolveSharingRegistry(publicClient, chainId);
4774
+ return acps.removeShareOnChain(shareId, walletClient, sharingRegistry);
4395
4775
  },
4396
4776
  // Retrieval methods (auto-fill chainId/account)
4397
- getPermit: (hash, chainId, account) => {
4777
+ getACP: (hash, chainId, account) => {
4398
4778
  const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
4399
- return permits.getPermit(_chainId, _account, hash);
4779
+ return acps.getACP(_chainId, _account, hash);
4400
4780
  },
4401
- getPermits: (chainId, account) => {
4781
+ getACPs: (chainId, account) => {
4402
4782
  const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
4403
- return permits.getPermits(_chainId, _account);
4783
+ return acps.getACPs(_chainId, _account);
4404
4784
  },
4405
- getActivePermit: (chainId, account) => {
4785
+ getActiveACP: (chainId, account) => {
4406
4786
  const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
4407
- return permits.getActivePermit(_chainId, _account);
4787
+ return acps.getActiveACP(_chainId, _account);
4408
4788
  },
4409
- getActivePermitHash: (chainId, account) => {
4789
+ getActiveACPHash: (chainId, account) => {
4410
4790
  const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
4411
- return permits.getActivePermitHash(_chainId, _account);
4791
+ return acps.getActiveACPHash(_chainId, _account);
4412
4792
  },
4413
4793
  // Mutation methods (auto-fill chainId/account)
4414
- selectActivePermit: (hash, chainId, account) => {
4794
+ selectActiveACP: (hash, chainId, account) => {
4415
4795
  const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
4416
- return permits.selectActivePermit(_chainId, _account, hash);
4796
+ return acps.selectActiveACP(_chainId, _account, hash);
4417
4797
  },
4418
- removePermit: async (hash, chainId, account) => {
4798
+ removeACP: async (hash, chainId, account) => {
4419
4799
  const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
4420
- return permits.removePermit(_chainId, _account, hash);
4800
+ return acps.removeACP(_chainId, _account, hash);
4421
4801
  },
4422
- removeActivePermit: async (chainId, account) => {
4802
+ removeActiveACP: async (chainId, account) => {
4423
4803
  const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
4424
- return permits.removeActivePermit(_chainId, _account);
4804
+ return acps.removeActiveACP(_chainId, _account);
4425
4805
  },
4426
4806
  // Utils (no context needed)
4427
- getHash: permits.getHash,
4428
- export: permits.export,
4429
- serialize: permits.serialize,
4430
- deserialize: permits.deserialize
4807
+ getHash: acps.getHash,
4808
+ export: acps.export,
4809
+ serialize: acps.serialize,
4810
+ deserialize: acps.deserialize
4431
4811
  };
4432
4812
  return {
4433
4813
  // Zustand reactive accessors (don't export store directly to prevent mutation)
@@ -4455,7 +4835,7 @@ function createCofheClientBase(opts) {
4455
4835
  decryptHandle: decryptForView,
4456
4836
  decryptForTx,
4457
4837
  verifyDecryptResult: verifyDecryptResult2,
4458
- permits: clientPermits
4838
+ acp: clientACPs
4459
4839
  // Add SDK-specific methods below that require connection
4460
4840
  // Example:
4461
4841
  // async encryptData(data: unknown) {