@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/web.cjs CHANGED
@@ -23,7 +23,8 @@ var CofheError = class _CofheError extends Error {
23
23
  cause;
24
24
  hint;
25
25
  context;
26
- constructor({ code, message, cause, hint, context }) {
26
+ apiErrorCode;
27
+ constructor({ code, message, cause, hint, context, apiErrorCode }) {
27
28
  const fullMessage = cause ? `${message} | Caused by: ${cause.message}` : message;
28
29
  super(fullMessage);
29
30
  this.name = "CofheError";
@@ -31,6 +32,7 @@ var CofheError = class _CofheError extends Error {
31
32
  this.cause = cause;
32
33
  this.hint = hint;
33
34
  this.context = context;
35
+ this.apiErrorCode = apiErrorCode;
34
36
  if (Error.captureStackTrace) {
35
37
  Error.captureStackTrace(this, _CofheError);
36
38
  }
@@ -49,6 +51,7 @@ var CofheError = class _CofheError extends Error {
49
51
  message: wrapperError?.message ?? "An internal error occurred",
50
52
  hint: wrapperError?.hint,
51
53
  context: wrapperError?.context,
54
+ apiErrorCode: wrapperError?.apiErrorCode,
52
55
  cause
53
56
  });
54
57
  }
@@ -62,6 +65,7 @@ var CofheError = class _CofheError extends Error {
62
65
  message: this.message,
63
66
  hint: this.hint,
64
67
  context: this.context,
68
+ apiErrorCode: this.apiErrorCode,
65
69
  cause: this.cause ? {
66
70
  name: this.cause.name,
67
71
  message: this.cause.message,
@@ -74,7 +78,8 @@ var CofheError = class _CofheError extends Error {
74
78
  * Returns a human-readable string representation of the error
75
79
  */
76
80
  toString() {
77
- const parts = [`${this.name} [${this.code}]: ${this.message}`];
81
+ const codeSuffix = this.apiErrorCode ? ` (api: ${this.apiErrorCode})` : "";
82
+ const parts = [`${this.name} [${this.code}]${codeSuffix}: ${this.message}`];
78
83
  if (this.hint) {
79
84
  parts.push(`Hint: ${this.hint}`);
80
85
  }
@@ -346,18 +351,19 @@ var constructZkPoKMetadata = (accountAddr, securityZone, chainId) => {
346
351
  metadata.set(chainIdBytes, 1 + accountBytes.length);
347
352
  return metadata;
348
353
  };
349
- var zkVerify = async (verifierUrl, serializedBytes, address, securityZone, chainId) => {
354
+ var zkVerifyBatch = async (verifierUrl, serializedBytes, address, securityZone, chainId, consumingContract) => {
350
355
  const packed_list = toHexString(serializedBytes);
351
356
  const sz_byte = new Uint8Array([securityZone]);
352
357
  const payload = {
353
358
  packed_list,
354
359
  account_addr: address,
355
360
  security_zone: sz_byte[0],
356
- chain_id: chainId
361
+ chain_id: chainId,
362
+ contract_address: consumingContract
357
363
  };
358
364
  const body = JSON.stringify(payload);
359
365
  try {
360
- const response = await fetch(`${verifierUrl}/verify`, {
366
+ const response = await fetch(`${verifierUrl}/verifyBatch`, {
361
367
  method: "POST",
362
368
  headers: {
363
369
  "Content-Type": "application/json"
@@ -368,26 +374,25 @@ var zkVerify = async (verifierUrl, serializedBytes, address, securityZone, chain
368
374
  const errorBody = await response.text();
369
375
  throw new CofheError({
370
376
  code: "ZK_VERIFY_FAILED" /* ZkVerifyFailed */,
371
- message: `HTTP error! ZK proof verification failed - ${errorBody}`
377
+ message: `HTTP error! ZK batch proof verification failed - ${errorBody}`
372
378
  });
373
379
  }
374
380
  const json = await response.json();
375
381
  if (json.status !== "success") {
376
382
  throw new CofheError({
377
383
  code: "ZK_VERIFY_FAILED" /* ZkVerifyFailed */,
378
- message: `ZK proof verification response malformed - ${json.error}`
384
+ message: `ZK batch proof verification response malformed - ${json.error}`
379
385
  });
380
386
  }
381
- return json.data.map(({ ct_hash, signature, recid }) => {
382
- return {
383
- ct_hash,
384
- signature: concatSigRecid(signature, recid)
385
- };
386
- });
387
+ const { ciphertexts, signature, recid } = json.data;
388
+ return {
389
+ outputs: ciphertexts,
390
+ signature: concatSigRecid(signature, recid)
391
+ };
387
392
  } catch (e) {
388
393
  throw new CofheError({
389
394
  code: "ZK_VERIFY_FAILED" /* ZkVerifyFailed */,
390
- message: `ZK proof verification failed`,
395
+ message: `ZK batch proof verification failed`,
391
396
  cause: e instanceof Error ? e : void 0
392
397
  });
393
398
  }
@@ -632,67 +637,59 @@ async function insertCtHashes(items, walletClient) {
632
637
  });
633
638
  }
634
639
  }
635
- async function createProofSignatures(items, securityZone, account) {
636
- let signatures = [];
637
- let encInputSignerClient;
640
+ async function createBatchProofSignature(items, securityZone, account, consumingContract) {
638
641
  try {
639
- encInputSignerClient = createMockZkVerifierSigner();
640
- } catch (err) {
641
- throw new CofheError({
642
- code: "ZK_MOCKS_CREATE_PROOF_SIGNATURE_FAILED" /* ZkMocksCreateProofSignatureFailed */,
643
- message: `mockZkVerifySign createProofSignatures failed while creating wallet client`,
644
- cause: err instanceof Error ? err : void 0,
645
- context: {
646
- MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY
647
- }
642
+ const itemHashes = items.map(
643
+ (item) => viem.keccak256(
644
+ viem.encodePacked(
645
+ ["uint256", "uint8", "uint8", "address", "uint256", "address"],
646
+ [
647
+ BigInt(item.ctHash),
648
+ item.utype,
649
+ securityZone,
650
+ account,
651
+ BigInt(chains.hardhat.id),
652
+ consumingContract
653
+ ]
654
+ )
655
+ )
656
+ );
657
+ const batchDigest = viem.keccak256(
658
+ viem.encodePacked(
659
+ itemHashes.map(() => "bytes32"),
660
+ itemHashes
661
+ )
662
+ );
663
+ return await accounts.sign({
664
+ hash: batchDigest,
665
+ privateKey: MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY,
666
+ to: "hex"
648
667
  });
649
- }
650
- try {
651
- for (const item of items) {
652
- const packedData = viem.encodePacked(
653
- ["uint256", "uint8", "uint8", "address", "uint256"],
654
- [BigInt(item.ctHash), item.utype, securityZone, account, BigInt(chains.hardhat.id)]
655
- );
656
- const messageHash = viem.keccak256(packedData);
657
- const signature = await accounts.sign({
658
- hash: messageHash,
659
- privateKey: MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY,
660
- to: "hex"
661
- });
662
- signatures.push(signature);
663
- }
664
668
  } catch (err) {
665
669
  throw new CofheError({
666
670
  code: "ZK_MOCKS_CREATE_PROOF_SIGNATURE_FAILED" /* ZkMocksCreateProofSignatureFailed */,
667
- message: `mockZkVerifySign createProofSignatures failed while calling signMessage`,
671
+ message: `mockZkVerifySign createBatchProofSignature failed while signing the batch digest`,
668
672
  cause: err instanceof Error ? err : void 0,
669
673
  context: {
670
674
  items,
671
- securityZone
672
- }
673
- });
674
- }
675
- if (signatures.length !== items.length) {
676
- throw new CofheError({
677
- code: "ZK_MOCKS_CREATE_PROOF_SIGNATURE_FAILED" /* ZkMocksCreateProofSignatureFailed */,
678
- message: `mockZkVerifySign createProofSignatures returned incorrect number of signatures`,
679
- context: {
680
- items,
681
- securityZone
675
+ securityZone,
676
+ consumingContract
682
677
  }
683
678
  });
684
679
  }
685
- return signatures;
686
680
  }
687
- async function cofheMocksZkVerifySign(items, account, securityZone, publicClient, walletClient, zkvWalletClient) {
681
+ async function cofheMocksZkVerifySign(items, account, securityZone, consumingContract, publicClient, walletClient, zkvWalletClient) {
688
682
  const _walletClient = zkvWalletClient ?? createMockZkVerifierSigner();
689
683
  const encryptableItems = await calcCtHashes(items, account, securityZone, publicClient);
690
684
  await insertCtHashes(encryptableItems, _walletClient);
691
- const signatures = await createProofSignatures(encryptableItems, securityZone, account);
692
- return encryptableItems.map((item, index) => ({
693
- ct_hash: item.ctHash.toString(),
694
- signature: signatures[index]
695
- }));
685
+ const signature = await createBatchProofSignature(encryptableItems, securityZone, account, consumingContract);
686
+ return {
687
+ outputs: encryptableItems.map((item) => ({
688
+ ct_hash: item.ctHash.toString(),
689
+ ct_type: item.utype
690
+ })),
691
+ signature
692
+ };
696
693
  }
697
694
  var EnvironmentSchema = zod.z.enum(["MOCK", "TESTNET", "MAINNET"]);
698
695
  var CofheChainSchema = zod.z.object({
@@ -735,8 +732,8 @@ var CofheConfigSchema = zod.z.object({
735
732
  environment: zod.z.enum(["node", "hardhat", "web", "react"]).optional().default("node"),
736
733
  /** List of supported chain configurations */
737
734
  supportedChains: zod.z.array(zod.z.custom()),
738
- /** Default permit expiration in seconds, default is 30 days */
739
- defaultPermitExpiration: zod.z.number().optional().default(60 * 60 * 24 * 30),
735
+ /** Default acp expiration in seconds, default is 30 days */
736
+ defaultACPExpiration: zod.z.number().optional().default(60 * 60 * 24 * 30),
740
737
  /** Storage method for fhe keys (defaults to indexedDB on web, filesystem on node) */
741
738
  fheKeyStorage: zod.z.object({
742
739
  getItem: zod.z.custom((val) => typeof val === "function", {
@@ -751,6 +748,12 @@ var CofheConfigSchema = zod.z.object({
751
748
  }).or(zod.z.null()).default(null),
752
749
  /** Whether to use Web Workers for ZK proof generation (web platform only) */
753
750
  useWorkers: zod.z.boolean().optional().default(true),
751
+ /** ACP acp defaults */
752
+ acp: zod.z.object({
753
+ defaultRevoker: zod.z.custom().optional(),
754
+ defaultContractScopes: zod.z.custom().optional(),
755
+ sharingRegistry: zod.z.custom().optional()
756
+ }).optional().default({}),
754
757
  /** Mocks configs */
755
758
  mocks: zod.z.object({
756
759
  decryptDelay: zod.z.number().optional().default(0),
@@ -761,8 +764,19 @@ var CofheConfigSchema = zod.z.object({
761
764
  zkvWalletClient: zod.z.any().optional()
762
765
  }).optional()
763
766
  });
767
+ var RENAMED_COFHE_CONFIG_KEYS = {
768
+ defaultPermitExpiration: "defaultACPExpiration"
769
+ };
770
+ function assertNoRenamedConfigKeys(config, renamedKeys, label) {
771
+ const stale = Object.keys(config).filter((key) => key in renamedKeys);
772
+ if (stale.length === 0)
773
+ return;
774
+ const renames = stale.map((key) => `\`${key}\` is now \`${renamedKeys[key]}\``).join("; ");
775
+ throw new Error(`Invalid ${label}: ${renames}. See the v0.7.0 migration guide.`);
776
+ }
764
777
  function createCofheConfigBase(config) {
765
- const result = CofheConfigSchema.safeParse(config);
778
+ assertNoRenamedConfigKeys(config, RENAMED_COFHE_CONFIG_KEYS, "cofhe configuration");
779
+ const result = CofheConfigSchema.strict().safeParse(config);
766
780
  if (!result.success) {
767
781
  throw new Error(`Invalid cofhe configuration: ${zod.z.prettifyError(result.error)}`, { cause: result.error });
768
782
  }
@@ -1111,9 +1125,9 @@ var BaseBuilder = class {
1111
1125
  // core/encrypt/encryptInputsBuilder.ts
1112
1126
  var EncryptInputsBuilder = class extends BaseBuilder {
1113
1127
  securityZone;
1128
+ consumingContract;
1114
1129
  stepCallback;
1115
1130
  inputItems;
1116
- hpp = false;
1117
1131
  zkvWalletClient;
1118
1132
  tfhePublicKeyDeserializer;
1119
1133
  compactPkeCrsDeserializer;
@@ -1180,20 +1194,6 @@ var EncryptInputsBuilder = class extends BaseBuilder {
1180
1194
  this.keysStorage = params.keysStorage;
1181
1195
  this.useWorker = params.config?.useWorkers ?? true;
1182
1196
  }
1183
- /**
1184
- * @param account - Account that will create the tx using the encrypted inputs.
1185
- *
1186
- * If not provided, the account will be fetched from the connected walletClient.
1187
- *
1188
- * Example:
1189
- * ```typescript
1190
- * const encrypted = await encryptInputs([Encryptable.uint128(10n)])
1191
- * .setAccount("0x123")
1192
- * .execute();
1193
- * ```
1194
- *
1195
- * @returns The chainable EncryptInputsBuilder instance.
1196
- */
1197
1197
  setAccount(account) {
1198
1198
  this.account = account;
1199
1199
  return this;
@@ -1201,20 +1201,6 @@ var EncryptInputsBuilder = class extends BaseBuilder {
1201
1201
  getAccount() {
1202
1202
  return this.account;
1203
1203
  }
1204
- /**
1205
- * @param chainId - Chain that will consume the encrypted inputs.
1206
- *
1207
- * If not provided, the chainId will be fetched from the connected publicClient.
1208
- *
1209
- * Example:
1210
- * ```typescript
1211
- * const encrypted = await encryptInputs([Encryptable.uint128(10n)])
1212
- * .setChainId(11155111)
1213
- * .execute();
1214
- * ```
1215
- *
1216
- * @returns The chainable EncryptInputsBuilder instance.
1217
- */
1218
1204
  setChainId(chainId) {
1219
1205
  this.chainId = chainId;
1220
1206
  return this;
@@ -1222,20 +1208,6 @@ var EncryptInputsBuilder = class extends BaseBuilder {
1222
1208
  getChainId() {
1223
1209
  return this.chainId;
1224
1210
  }
1225
- /**
1226
- * @param securityZone - Security zone to encrypt the inputs for.
1227
- *
1228
- * If not provided, the default securityZone 0 will be used.
1229
- *
1230
- * Example:
1231
- * ```typescript
1232
- * const encrypted = await encryptInputs([Encryptable.uint128(10n)])
1233
- * .setSecurityZone(1)
1234
- * .execute();
1235
- * ```
1236
- *
1237
- * @returns The chainable EncryptInputsBuilder instance.
1238
- */
1239
1211
  setSecurityZone(securityZone) {
1240
1212
  this.securityZone = securityZone;
1241
1213
  return this;
@@ -1244,33 +1216,44 @@ var EncryptInputsBuilder = class extends BaseBuilder {
1244
1216
  return this.securityZone;
1245
1217
  }
1246
1218
  /**
1219
+ * @param address - The contract that will consume the resulting hashes+signature (i.e. the
1220
+ * contract that will call `FHE.asEuint*`/`FHE.asEuint*s` with them).
1221
+ *
1222
+ * Required before `execute()` - the verifier binds this address into the signed digest, so a
1223
+ * batch signed for one contract cannot be replayed into another.
1224
+ *
1247
1225
  * Example:
1248
1226
  * ```typescript
1249
1227
  * const encrypted = await encryptInputs([Encryptable.uint128(10n)])
1250
- * .asHashPlusProof()
1228
+ * .setConsumingContract("0x123...890")
1251
1229
  * .execute();
1252
1230
  * ```
1253
1231
  *
1254
- * @returns Chainable EncryptInputsBuilder instance that will return a HashPlusProofResult instead of an array of EncryptedItemInputs.
1232
+ * @returns The chainable EncryptInputsBuilder instance.
1255
1233
  */
1256
- asHashPlusProof() {
1257
- this.hpp = true;
1234
+ setConsumingContract(address) {
1235
+ this.consumingContract = address;
1258
1236
  return this;
1259
1237
  }
1238
+ getConsumingContract() {
1239
+ return this.consumingContract;
1240
+ }
1260
1241
  /**
1261
- * @param useWorker - Whether to use Web Workers for ZK proof generation.
1262
- *
1263
- * Overrides the config-level useWorkers setting for this specific encryption.
1264
- *
1265
- * Example:
1266
- * ```typescript
1267
- * const encrypted = await encryptInputs([Encryptable.uint128(10n)])
1268
- * .setUseWorker(false)
1269
- * .execute();
1270
- * ```
1271
- *
1272
- * @returns The chainable EncryptInputsBuilder instance.
1242
+ * Asserts that this.consumingContract is populated
1243
+ * @throws {CofheError} If consumingContract is not set
1273
1244
  */
1245
+ assertConsumingContract() {
1246
+ if (this.consumingContract)
1247
+ return;
1248
+ throw new CofheError({
1249
+ code: "CONSUMING_CONTRACT_UNINITIALIZED" /* ConsumingContractUninitialized */,
1250
+ message: "Consuming contract is not set",
1251
+ hint: "Use setConsumingContract(...) to set the contract that will consume the encrypted inputs.",
1252
+ context: {
1253
+ consumingContract: this.consumingContract
1254
+ }
1255
+ });
1256
+ }
1274
1257
  setUseWorker(useWorker) {
1275
1258
  this.useWorker = useWorker;
1276
1259
  return this;
@@ -1291,21 +1274,6 @@ var EncryptInputsBuilder = class extends BaseBuilder {
1291
1274
  getUseWorker() {
1292
1275
  return this.useWorker;
1293
1276
  }
1294
- /**
1295
- * @param callback - Function to be called with the encryption step.
1296
- *
1297
- * Useful for debugging and tracking the progress of the encryption process.
1298
- * Useful for a UI element that shows the progress of the encryption process.
1299
- *
1300
- * Example:
1301
- * ```typescript
1302
- * const encrypted = await encryptInputs([Encryptable.uint128(10n)])
1303
- * .onStep((step: EncryptStep) => console.log(step))
1304
- * .execute();
1305
- * ```
1306
- *
1307
- * @returns The EncryptInputsBuilder instance.
1308
- */
1309
1277
  onStep(callback) {
1310
1278
  this.stepCallback = callback;
1311
1279
  return this;
@@ -1444,6 +1412,7 @@ var EncryptInputsBuilder = class extends BaseBuilder {
1444
1412
  this.assertAccount();
1445
1413
  this.assertPublicClient();
1446
1414
  this.assertWalletClient();
1415
+ this.assertConsumingContract();
1447
1416
  const [initTfheDelay, fetchKeysDelay, packDelay, proveDelay, verifyDelay] = this.resolveEncryptDelays();
1448
1417
  this.fireStepStart("initTfhe" /* InitTfhe */);
1449
1418
  await sleep(initTfheDelay);
@@ -1469,22 +1438,17 @@ var EncryptInputsBuilder = class extends BaseBuilder {
1469
1438
  this.fireStepEnd("prove" /* Prove */, { isMocks: true, mockSleep: proveDelay });
1470
1439
  this.fireStepStart("verify" /* Verify */);
1471
1440
  await sleep(verifyDelay);
1472
- const signedResults = await cofheMocksZkVerifySign(
1441
+ const result = await cofheMocksZkVerifySign(
1473
1442
  this.inputItems,
1474
1443
  this.account,
1475
1444
  this.securityZone,
1445
+ this.consumingContract,
1476
1446
  this.publicClient,
1477
1447
  this.walletClient,
1478
1448
  this.zkvWalletClient
1479
1449
  );
1480
- const encryptedInputs = signedResults.map(({ ct_hash, signature }, index) => ({
1481
- ctHash: BigInt(ct_hash),
1482
- securityZone: this.securityZone,
1483
- utype: this.inputItems[index].utype,
1484
- signature
1485
- }));
1486
1450
  this.fireStepEnd("verify" /* Verify */, { isMocks: true, mockSleep: verifyDelay });
1487
- return encryptedInputs;
1451
+ return result;
1488
1452
  }
1489
1453
  /**
1490
1454
  * In the production context, perform a true encryption with the CoFHE coprocessor.
@@ -1492,6 +1456,7 @@ var EncryptInputsBuilder = class extends BaseBuilder {
1492
1456
  async productionExecute() {
1493
1457
  this.assertAccount();
1494
1458
  this.assertChainId();
1459
+ this.assertConsumingContract();
1495
1460
  this.fireStepStart("initTfhe" /* InitTfhe */);
1496
1461
  const tfheInitializationExecuted = await this.initTfheOrThrow();
1497
1462
  this.fireStepEnd("initTfhe" /* InitTfhe */, { tfheInitializationExecuted });
@@ -1526,26 +1491,24 @@ var EncryptInputsBuilder = class extends BaseBuilder {
1526
1491
  });
1527
1492
  this.fireStepStart("verify" /* Verify */);
1528
1493
  const zkVerifierUrl = await this.getZkVerifierUrl();
1529
- const verifyResults = await zkVerify(zkVerifierUrl, proof, this.account, this.securityZone, this.chainId);
1530
- const encryptedInputs = verifyResults.map(
1531
- ({ ct_hash, signature }, index) => ({
1532
- ctHash: BigInt(ct_hash),
1533
- securityZone: this.securityZone,
1534
- utype: this.inputItems[index].utype,
1535
- signature
1536
- })
1494
+ const result = await zkVerifyBatch(
1495
+ zkVerifierUrl,
1496
+ proof,
1497
+ this.account,
1498
+ this.securityZone,
1499
+ this.chainId,
1500
+ this.consumingContract
1537
1501
  );
1538
1502
  this.fireStepEnd("verify" /* Verify */);
1539
- return encryptedInputs;
1540
- }
1541
- structsToHashPlusProof(inItems) {
1542
- let hashes = [];
1543
- let proof = "";
1544
- for (const item of inItems) {
1545
- hashes.push("0x" + item.ctHash.toString(16).padStart(64, "0"));
1546
- proof += item.signature;
1547
- }
1548
- return [...hashes, proof];
1503
+ return result;
1504
+ }
1505
+ /**
1506
+ * Converts a batch-verified result (per-item ctHash/ctType + one shared signature) into the
1507
+ * tuple returned by `execute()`: per-item hashes in input order, followed by the single signature.
1508
+ */
1509
+ buildBatchResult(result) {
1510
+ const hashes = result.outputs.map((output) => "0x" + BigInt(output.ct_hash).toString(16).padStart(64, "0"));
1511
+ return [...hashes, result.signature];
1549
1512
  }
1550
1513
  /**
1551
1514
  * Final step of the encryption process. MUST BE CALLED LAST IN THE CHAIN.
@@ -1567,18 +1530,16 @@ var EncryptInputsBuilder = class extends BaseBuilder {
1567
1530
  * @returns The encrypted inputs.
1568
1531
  */
1569
1532
  async execute() {
1570
- let items;
1533
+ let result;
1571
1534
  if (this.chainId === chains.hardhat.id)
1572
- items = await this.mocksExecute();
1535
+ result = await this.mocksExecute();
1573
1536
  else
1574
- items = await this.productionExecute();
1575
- if (this.hpp)
1576
- return this.structsToHashPlusProof(items);
1577
- return items;
1537
+ result = await this.productionExecute();
1538
+ return this.buildBatchResult(result);
1578
1539
  }
1579
1540
  };
1580
1541
 
1581
- // permits/utils.ts
1542
+ // acps/utils.ts
1582
1543
  var fromHexString = (hexString) => {
1583
1544
  const cleanString = hexString.length % 2 === 1 ? `0${hexString}` : hexString;
1584
1545
  const arr = cleanString.replace(/^0x/, "").match(/.{1,2}/g);
@@ -1598,120 +1559,33 @@ function toBigInt(value) {
1598
1559
  return value;
1599
1560
  }
1600
1561
  }
1601
- function toBeArray(value) {
1602
- const bigIntValue = typeof value === "number" ? BigInt(value) : value;
1603
- const hex = bigIntValue.toString(16);
1604
- const paddedHex = hex.length % 2 === 0 ? hex : "0" + hex;
1605
- return fromHexString(paddedHex);
1606
- }
1607
- function isString(value) {
1608
- if (typeof value !== "string") {
1609
- throw new Error(`Expected value which is \`string\`, received value of type \`${typeof value}\`.`);
1610
- }
1611
- }
1612
- function isNumber(value) {
1613
- const is = typeof value === "number" && !Number.isNaN(value);
1614
- if (!is) {
1615
- throw new Error(`Expected value which is \`number\`, received value of type \`${typeof value}\`.`);
1616
- }
1617
- }
1618
- function isBigIntOrNumber(value) {
1619
- const is = typeof value === "bigint";
1620
- if (!is) {
1621
- try {
1622
- isNumber(value);
1623
- } catch (e) {
1624
- throw new Error(`Value ${value} is not a number or bigint: ${typeof value}`);
1625
- }
1626
- }
1627
- }
1628
1562
 
1629
- // permits/sealing.ts
1630
- var PRIVATE_KEY_LENGTH = 64;
1631
- var PUBLIC_KEY_LENGTH = 64;
1632
- var SealingKey = class _SealingKey {
1633
- /**
1634
- * The private key used for decryption.
1635
- */
1636
- privateKey;
1637
- /**
1638
- * The public key used for encryption.
1639
- */
1640
- publicKey;
1641
- /**
1642
- * Constructs a SealingKey instance with the given private and public keys.
1643
- *
1644
- * @param {string} privateKey - The private key used for decryption.
1645
- * @param {string} publicKey - The public key used for encryption.
1646
- * @throws Will throw an error if the provided keys lengths do not match
1647
- * the required lengths for private and public keys.
1648
- */
1649
- constructor(privateKey, publicKey) {
1650
- if (privateKey.length !== PRIVATE_KEY_LENGTH) {
1651
- throw new Error(`Private key must be of length ${PRIVATE_KEY_LENGTH}`);
1652
- }
1653
- if (publicKey.length !== PUBLIC_KEY_LENGTH) {
1654
- throw new Error(`Public key must be of length ${PUBLIC_KEY_LENGTH}`);
1655
- }
1656
- this.privateKey = privateKey;
1657
- this.publicKey = publicKey;
1658
- }
1659
- unseal = (parsedData) => {
1660
- const nonce = parsedData.nonce instanceof Uint8Array ? parsedData.nonce : new Uint8Array(parsedData.nonce);
1661
- const ephemPublicKey = parsedData.public_key instanceof Uint8Array ? parsedData.public_key : new Uint8Array(parsedData.public_key);
1662
- const dataToDecrypt = parsedData.data instanceof Uint8Array ? parsedData.data : new Uint8Array(parsedData.data);
1663
- const privateKeyBytes = fromHexString(this.privateKey);
1664
- const decryptedMessage = nacl__default.default.box.open(dataToDecrypt, nonce, ephemPublicKey, privateKeyBytes);
1665
- if (!decryptedMessage) {
1666
- throw new Error("Failed to decrypt message");
1667
- }
1668
- return toBigInt(decryptedMessage);
1669
- };
1670
- /**
1671
- * Serializes the SealingKey to a JSON object.
1672
- */
1673
- serialize = () => {
1674
- return {
1675
- privateKey: this.privateKey,
1676
- publicKey: this.publicKey
1677
- };
1678
- };
1679
- /**
1680
- * Deserializes the SealingKey from a JSON object.
1681
- */
1682
- static deserialize = (privateKey, publicKey) => {
1683
- return new _SealingKey(privateKey, publicKey);
1684
- };
1685
- /**
1686
- * Seals (encrypts) the provided message for a receiver with the specified public key.
1687
- *
1688
- * @param {bigint | number} value - The message to be encrypted.
1689
- * @param {string} publicKey - The public key of the intended recipient.
1690
- * @returns string - The encrypted message in hexadecimal format.
1691
- * @static
1692
- * @throws Will throw if the provided publicKey or value do not meet defined preconditions.
1693
- */
1694
- static seal = (value, publicKey) => {
1695
- isString(publicKey);
1696
- isBigIntOrNumber(value);
1697
- const ephemeralKeyPair = nacl__default.default.box.keyPair();
1698
- const nonce = nacl__default.default.randomBytes(nacl__default.default.box.nonceLength);
1699
- const encryptedMessage = nacl__default.default.box(toBeArray(value), nonce, fromHexString(publicKey), ephemeralKeyPair.secretKey);
1700
- return {
1701
- data: encryptedMessage,
1702
- public_key: ephemeralKeyPair.publicKey,
1703
- nonce
1704
- };
1705
- };
1706
- };
1563
+ // acps/sealing.ts
1564
+ var KEY_HEX_LENGTH = 64;
1707
1565
  var GenerateSealingKey = () => {
1708
1566
  const sodiumKeypair = nacl__default.default.box.keyPair();
1709
- return new SealingKey(toHexString2(sodiumKeypair.secretKey), toHexString2(sodiumKeypair.publicKey));
1567
+ return {
1568
+ privateKey: `0x${toHexString2(sodiumKeypair.secretKey)}`,
1569
+ publicKey: `0x${toHexString2(sodiumKeypair.publicKey)}`
1570
+ };
1571
+ };
1572
+ var unsealWithPrivateKey = (privateKey, parsedData) => {
1573
+ assertKeyLength(privateKey, "Private");
1574
+ const nonce = parsedData.nonce instanceof Uint8Array ? parsedData.nonce : new Uint8Array(parsedData.nonce);
1575
+ const ephemPublicKey = parsedData.public_key instanceof Uint8Array ? parsedData.public_key : new Uint8Array(parsedData.public_key);
1576
+ const dataToDecrypt = parsedData.data instanceof Uint8Array ? parsedData.data : new Uint8Array(parsedData.data);
1577
+ const decryptedMessage = nacl__default.default.box.open(dataToDecrypt, nonce, ephemPublicKey, fromHexString(privateKey));
1578
+ if (!decryptedMessage) {
1579
+ throw new Error("Failed to decrypt message");
1580
+ }
1581
+ return toBigInt(decryptedMessage);
1582
+ };
1583
+ var assertKeyLength = (key, kind) => {
1584
+ const bare = key.startsWith("0x") ? key.slice(2) : key;
1585
+ if (bare.length !== KEY_HEX_LENGTH) {
1586
+ throw new Error(`${kind} key must be of length ${KEY_HEX_LENGTH}`);
1587
+ }
1710
1588
  };
1711
- var SerializedSealingPair = zod.z.object({
1712
- privateKey: zod.z.string(),
1713
- publicKey: zod.z.string()
1714
- });
1715
1589
  var addressSchema = zod.z.string().refine((val) => viem.isAddress(val), {
1716
1590
  error: "Invalid address"
1717
1591
  }).transform((val) => viem.getAddress(val));
@@ -1730,46 +1604,70 @@ var bytesNotEmptySchema = bytesSchema.refine((val) => val !== "0x", {
1730
1604
  error: "Must not be empty"
1731
1605
  });
1732
1606
  var DEFAULT_EXPIRATION_FN = () => Math.round(Date.now() / 1e3) + 7 * 24 * 60 * 60;
1733
- var zPermitWithDefaults = zod.z.object({
1734
- name: zod.z.string().optional().default("Unnamed Permit"),
1607
+ var handlesSchema = zod.z.array(zod.z.string().regex(/^0x[0-9a-fA-F]{64}$/, "Invalid handle: expected 32-byte hex")).optional().default([]);
1608
+ var contractsSchema = zod.z.array(addressSchema).optional().default([]);
1609
+ var SCOPE_GLOBAL = 0;
1610
+ var SCOPE_CONTRACT = 1;
1611
+ var SCOPE_HANDLES = 2;
1612
+ var ScopeConsistencyRefinement = [
1613
+ (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,
1614
+ {
1615
+ error: "ACP scope :: arrays must match the scope mode (Global: both empty; Contract: contracts only; Handles: handles only)",
1616
+ path: ["scope"]
1617
+ }
1618
+ ];
1619
+ var withDerivedScope = (data) => ({
1620
+ ...data,
1621
+ scope: data.scope ?? (data.contracts.length > 0 ? SCOPE_CONTRACT : data.handles.length > 0 ? SCOPE_HANDLES : SCOPE_GLOBAL)
1622
+ });
1623
+ var zACPWithDefaults = zod.z.object({
1624
+ name: zod.z.string().optional().default("Unnamed ACP"),
1735
1625
  type: zod.z.enum(["self", "sharing", "recipient"]),
1736
1626
  issuer: addressNotZeroSchema,
1737
1627
  expiration: zod.z.int().optional().default(DEFAULT_EXPIRATION_FN),
1738
1628
  recipient: addressSchema.optional().default(viem.zeroAddress),
1739
- validatorId: zod.z.int().optional().default(0),
1740
- validatorContract: addressSchema.optional().default(viem.zeroAddress),
1629
+ revokerData: zod.z.int().optional().default(0),
1630
+ revokerContract: addressSchema.optional().default(viem.zeroAddress),
1631
+ scope: zod.z.int().min(0).max(2).optional().default(0),
1632
+ contracts: contractsSchema,
1633
+ handles: handlesSchema,
1741
1634
  issuerSignature: bytesSchema.optional().default("0x"),
1742
1635
  recipientSignature: bytesSchema.optional().default("0x")
1743
1636
  });
1744
- var zPermitWithSealingPair = zPermitWithDefaults.extend({
1745
- sealingPair: SerializedSealingPair.optional()
1637
+ var zACPWithSealingKeys = zACPWithDefaults.extend({
1638
+ /** X25519 private key, 0x-prefixed 32-byte hex; never leaves the client */
1639
+ sealingPrivateKey: zod.z.string().regex(/^0x[0-9a-fA-F]{64}$/, "Invalid sealing private key").optional(),
1640
+ sealingKey: zod.z.string().regex(/^0x[0-9a-fA-F]{64}$/, "Invalid sealing key").optional()
1746
1641
  });
1747
1642
  var ExternalValidatorRefinement = [
1748
- (data) => data.validatorId !== 0 && data.validatorContract !== viem.zeroAddress || data.validatorId === 0 && data.validatorContract === viem.zeroAddress,
1643
+ (data) => data.revokerData !== 0 && data.revokerContract !== viem.zeroAddress || data.revokerData === 0 && data.revokerContract === viem.zeroAddress,
1749
1644
  {
1750
- error: "Permit external validator :: validatorId and validatorContract must either both be set or both be unset.",
1751
- path: ["validatorId", "validatorContract"]
1645
+ error: "ACP external revoker :: revokerData and revokerContract must either both be set or both be unset.",
1646
+ path: ["revokerData", "revokerContract"]
1752
1647
  }
1753
1648
  ];
1754
1649
  var RecipientRefinement = [
1755
1650
  (data) => data.issuer !== data.recipient,
1756
1651
  {
1757
- error: "Sharing permit :: issuer and recipient must not be the same",
1652
+ error: "Sharing acp :: issuer and recipient must not be the same",
1758
1653
  path: ["issuer", "recipient"]
1759
1654
  }
1760
1655
  ];
1761
- var SelfPermitOptionsValidator = zod.z.object({
1656
+ var SelfACPOptionsValidator = zod.z.object({
1762
1657
  type: zod.z.literal("self").optional().default("self"),
1763
1658
  issuer: addressNotZeroSchema,
1764
- name: zod.z.string().optional().default("Unnamed Permit"),
1659
+ name: zod.z.string().optional().default("Unnamed ACP"),
1765
1660
  expiration: zod.z.int().optional().default(DEFAULT_EXPIRATION_FN),
1766
1661
  recipient: addressSchema.optional().default(viem.zeroAddress),
1767
- validatorId: zod.z.int().optional().default(0),
1768
- validatorContract: addressSchema.optional().default(viem.zeroAddress),
1662
+ revokerData: zod.z.int().optional().default(0),
1663
+ revokerContract: addressSchema.optional().default(viem.zeroAddress),
1664
+ scope: zod.z.int().min(0).max(2).optional(),
1665
+ contracts: contractsSchema,
1666
+ handles: handlesSchema,
1769
1667
  issuerSignature: bytesSchema.optional().default("0x"),
1770
1668
  recipientSignature: bytesSchema.optional().default("0x")
1771
- }).refine(...ExternalValidatorRefinement);
1772
- var SelfPermitValidator = zPermitWithSealingPair.refine((data) => data.type === "self", {
1669
+ }).refine(...ExternalValidatorRefinement).transform(withDerivedScope).refine(...ScopeConsistencyRefinement);
1670
+ var SelfACPValidator = zACPWithSealingKeys.refine((data) => data.type === "self", {
1773
1671
  error: "Type must be 'self'"
1774
1672
  }).refine((data) => data.recipient === viem.zeroAddress, {
1775
1673
  error: "Recipient must be zeroAddress"
@@ -1778,18 +1676,21 @@ var SelfPermitValidator = zPermitWithSealingPair.refine((data) => data.type ===
1778
1676
  }).refine((data) => data.recipientSignature === "0x", {
1779
1677
  error: "RecipientSignature must be empty"
1780
1678
  }).refine(...ExternalValidatorRefinement);
1781
- var SharingPermitOptionsValidator = zod.z.object({
1679
+ var SharingACPOptionsValidator = zod.z.object({
1782
1680
  type: zod.z.literal("sharing").optional().default("sharing"),
1783
1681
  issuer: addressNotZeroSchema,
1784
1682
  recipient: addressNotZeroSchema,
1785
- name: zod.z.string().optional().default("Unnamed Permit"),
1683
+ name: zod.z.string().optional().default("Unnamed ACP"),
1786
1684
  expiration: zod.z.int().optional().default(DEFAULT_EXPIRATION_FN),
1787
- validatorId: zod.z.int().optional().default(0),
1788
- validatorContract: addressSchema.optional().default(viem.zeroAddress),
1685
+ revokerData: zod.z.int().optional().default(0),
1686
+ revokerContract: addressSchema.optional().default(viem.zeroAddress),
1687
+ scope: zod.z.int().min(0).max(2).optional(),
1688
+ contracts: contractsSchema,
1689
+ handles: handlesSchema,
1789
1690
  issuerSignature: bytesSchema.optional().default("0x"),
1790
1691
  recipientSignature: bytesSchema.optional().default("0x")
1791
- }).refine(...RecipientRefinement).refine(...ExternalValidatorRefinement);
1792
- var SharingPermitValidator = zPermitWithSealingPair.refine((data) => data.type === "sharing", {
1692
+ }).refine(...RecipientRefinement).refine(...ExternalValidatorRefinement).transform(withDerivedScope).refine(...ScopeConsistencyRefinement);
1693
+ var SharingACPValidator = zACPWithSealingKeys.refine((data) => data.type === "sharing", {
1793
1694
  error: "Type must be 'sharing'"
1794
1695
  }).refine((data) => data.recipient !== viem.zeroAddress, {
1795
1696
  error: "Recipient must not be zeroAddress"
@@ -1798,18 +1699,21 @@ var SharingPermitValidator = zPermitWithSealingPair.refine((data) => data.type =
1798
1699
  }).refine((data) => data.recipientSignature === "0x", {
1799
1700
  error: "RecipientSignature must be empty"
1800
1701
  }).refine(...ExternalValidatorRefinement);
1801
- var ImportPermitOptionsValidator = zod.z.object({
1702
+ var ImportACPOptionsValidator = zod.z.object({
1802
1703
  type: zod.z.literal("recipient").optional().default("recipient"),
1803
1704
  issuer: addressNotZeroSchema,
1804
1705
  recipient: addressNotZeroSchema,
1805
- name: zod.z.string().optional().default("Unnamed Permit"),
1706
+ name: zod.z.string().optional().default("Unnamed ACP"),
1806
1707
  expiration: zod.z.int(),
1807
- validatorId: zod.z.int().optional().default(0),
1808
- validatorContract: addressSchema.optional().default(viem.zeroAddress),
1708
+ revokerData: zod.z.int().optional().default(0),
1709
+ revokerContract: addressSchema.optional().default(viem.zeroAddress),
1710
+ scope: zod.z.int().min(0).max(2).optional(),
1711
+ contracts: contractsSchema,
1712
+ handles: handlesSchema,
1809
1713
  issuerSignature: bytesNotEmptySchema,
1810
1714
  recipientSignature: bytesSchema.optional().default("0x")
1811
- }).refine(...ExternalValidatorRefinement);
1812
- var ImportPermitValidator = zPermitWithSealingPair.refine((data) => data.type === "recipient", {
1715
+ }).refine(...ExternalValidatorRefinement).transform(withDerivedScope).refine(...ScopeConsistencyRefinement);
1716
+ var ImportACPValidator = zACPWithSealingKeys.refine((data) => data.type === "recipient", {
1813
1717
  error: "Type must be 'recipient'"
1814
1718
  }).refine((data) => data.recipient !== viem.zeroAddress, {
1815
1719
  error: "Recipient must not be zeroAddress"
@@ -1825,116 +1729,125 @@ var safeParseAndThrowFormatted = (schema, data, message) => {
1825
1729
  }
1826
1730
  return result.data;
1827
1731
  };
1828
- var validateSelfPermitOptions = (options) => {
1829
- return safeParseAndThrowFormatted(SelfPermitOptionsValidator, options, "Invalid self permit options");
1732
+ var validateSelfACPOptions = (options) => {
1733
+ return safeParseAndThrowFormatted(SelfACPOptionsValidator, options, "Invalid self acp options");
1830
1734
  };
1831
- var validateSharingPermitOptions = (options) => {
1832
- return safeParseAndThrowFormatted(SharingPermitOptionsValidator, options, "Invalid sharing permit options");
1735
+ var validateSharingACPOptions = (options) => {
1736
+ return safeParseAndThrowFormatted(SharingACPOptionsValidator, options, "Invalid sharing acp options");
1833
1737
  };
1834
- var validateImportPermitOptions = (options) => {
1835
- return safeParseAndThrowFormatted(ImportPermitOptionsValidator, options, "Invalid import permit options");
1738
+ var validateImportACPOptions = (options) => {
1739
+ return safeParseAndThrowFormatted(ImportACPOptionsValidator, options, "Invalid import acp options");
1836
1740
  };
1837
- var validateSelfPermit = (permit) => {
1838
- return safeParseAndThrowFormatted(SelfPermitValidator, permit, "Invalid self permit");
1741
+ var validateSelfACP = (acp) => {
1742
+ return safeParseAndThrowFormatted(SelfACPValidator, acp, "Invalid self acp");
1839
1743
  };
1840
- var validateSharingPermit = (permit) => {
1841
- return safeParseAndThrowFormatted(SharingPermitValidator, permit, "Invalid sharing permit");
1744
+ var validateSharingACP = (acp) => {
1745
+ return safeParseAndThrowFormatted(SharingACPValidator, acp, "Invalid sharing acp");
1842
1746
  };
1843
- var validateImportPermit = (permit) => {
1844
- return safeParseAndThrowFormatted(ImportPermitValidator, permit, "Invalid import permit");
1747
+ var validateImportACP = (acp) => {
1748
+ return safeParseAndThrowFormatted(ImportACPValidator, acp, "Invalid import acp");
1845
1749
  };
1846
1750
  var ValidationUtils = {
1847
1751
  /**
1848
- * Check if permit is expired
1752
+ * Check if acp is expired
1849
1753
  */
1850
- isExpired: (permit) => {
1851
- return permit.expiration < Math.floor(Date.now() / 1e3);
1754
+ isExpired: (acp) => {
1755
+ return acp.expiration < Math.floor(Date.now() / 1e3);
1852
1756
  },
1853
1757
  /**
1854
- * Check if permit is signed by the active party
1758
+ * Check if acp is signed by the active party
1855
1759
  */
1856
- isSigned: (permit) => {
1857
- if (permit.type === "self" || permit.type === "sharing") {
1858
- return permit.issuerSignature !== "0x";
1760
+ isSigned: (acp) => {
1761
+ if (acp.type === "self" || acp.type === "sharing") {
1762
+ return acp.issuerSignature !== "0x";
1859
1763
  }
1860
- if (permit.type === "recipient") {
1861
- return permit.recipientSignature !== "0x";
1764
+ if (acp.type === "recipient") {
1765
+ return acp.recipientSignature !== "0x";
1862
1766
  }
1863
1767
  return false;
1864
1768
  },
1865
1769
  /**
1866
- * Checks that a permit is signed and not expired.
1770
+ * Checks that an ACP is signed and not expired.
1867
1771
  */
1868
- isSignedAndNotExpired: (permit) => {
1869
- if (ValidationUtils.isExpired(permit)) {
1772
+ isSignedAndNotExpired: (acp) => {
1773
+ if (ValidationUtils.isExpired(acp)) {
1870
1774
  return { valid: false, error: "expired" };
1871
1775
  }
1872
- if (!ValidationUtils.isSigned(permit)) {
1776
+ if (!ValidationUtils.isSigned(acp)) {
1873
1777
  return { valid: false, error: "not-signed" };
1874
1778
  }
1875
1779
  return { valid: true, error: null };
1876
1780
  },
1877
1781
  /**
1878
- * Asserts that a permit is signed and not expired.
1782
+ * Asserts that an ACP is signed and not expired.
1879
1783
  *
1880
1784
  * Throws `Error` with message:
1881
- * - `Permit is expired`
1882
- * - `Permit is not signed`
1785
+ * - `ACP is expired`
1786
+ * - `ACP is not signed`
1883
1787
  */
1884
- assertSignedAndNotExpired: (permit) => {
1885
- const result = ValidationUtils.isSignedAndNotExpired(permit);
1788
+ assertSignedAndNotExpired: (acp) => {
1789
+ const result = ValidationUtils.isSignedAndNotExpired(acp);
1886
1790
  if (result.valid)
1887
1791
  return;
1888
1792
  if (result.error === "expired") {
1889
- throw new Error("Permit is expired");
1793
+ throw new Error("ACP is expired");
1890
1794
  }
1891
1795
  if (result.error === "not-signed") {
1892
- throw new Error("Permit is not signed");
1796
+ throw new Error("ACP is not signed");
1893
1797
  }
1894
- throw new Error("Permit is invalid");
1798
+ throw new Error("ACP is invalid");
1895
1799
  },
1896
- isValid: (permit) => {
1897
- const schema = permit.type === "self" ? SelfPermitValidator : permit.type === "sharing" ? SharingPermitValidator : permit.type === "recipient" ? ImportPermitValidator : null;
1800
+ isValid: (acp) => {
1801
+ const schema = acp.type === "self" ? SelfACPValidator : acp.type === "sharing" ? SharingACPValidator : acp.type === "recipient" ? ImportACPValidator : null;
1898
1802
  if (schema == null)
1899
1803
  return { valid: false, error: "invalid-schema" };
1900
- const schemaResult = schema.safeParse(permit);
1804
+ const schemaResult = schema.safeParse(acp);
1901
1805
  if (!schemaResult.success)
1902
1806
  return { valid: false, error: "invalid-schema" };
1903
- return ValidationUtils.isSignedAndNotExpired(permit);
1807
+ return ValidationUtils.isSignedAndNotExpired(acp);
1904
1808
  }
1905
1809
  };
1906
1810
 
1907
- // permits/signature.ts
1908
- var PermitSignatureAllFields = [
1811
+ // acps/signature.ts
1812
+ var ACPSignatureAllFields = [
1909
1813
  { name: "issuer", type: "address" },
1910
1814
  { name: "expiration", type: "uint64" },
1911
1815
  { name: "recipient", type: "address" },
1912
- { name: "validatorId", type: "uint256" },
1913
- { name: "validatorContract", type: "address" },
1816
+ { name: "revokerData", type: "uint256" },
1817
+ { name: "revokerContract", type: "address" },
1818
+ { name: "scope", type: "uint8" },
1819
+ { name: "contracts", type: "address[]" },
1820
+ { name: "handles", type: "bytes32[]" },
1914
1821
  { name: "sealingKey", type: "bytes32" },
1915
1822
  { name: "issuerSignature", type: "bytes" }
1916
1823
  ];
1917
1824
  var SignatureTypes = {
1918
- PermissionedV2IssuerSelf: [
1825
+ ACPIssuerSelf: [
1919
1826
  "issuer",
1920
1827
  "expiration",
1921
1828
  "recipient",
1922
- "validatorId",
1923
- "validatorContract",
1829
+ "revokerData",
1830
+ "revokerContract",
1831
+ "scope",
1832
+ "contracts",
1833
+ "handles",
1924
1834
  "sealingKey"
1925
1835
  ],
1926
- PermissionedV2IssuerShared: [
1836
+ ACPIssuerShared: [
1927
1837
  "issuer",
1928
1838
  "expiration",
1929
1839
  "recipient",
1930
- "validatorId",
1931
- "validatorContract"
1840
+ "revokerData",
1841
+ "revokerContract",
1842
+ "scope",
1843
+ "contracts",
1844
+ "handles"
1932
1845
  ],
1933
- PermissionedV2Recipient: ["sealingKey", "issuerSignature"]
1846
+ ACPRecipient: ["sealingKey", "issuerSignature"]
1934
1847
  };
1935
1848
  var getSignatureTypesAndMessage = (primaryType, fields, values) => {
1936
1849
  const types = {
1937
- [primaryType]: PermitSignatureAllFields.filter((fieldType) => fields.includes(fieldType.name))
1850
+ [primaryType]: ACPSignatureAllFields.filter((fieldType) => fields.includes(fieldType.name))
1938
1851
  };
1939
1852
  const message = {};
1940
1853
  fields.forEach((field) => {
@@ -1946,22 +1859,22 @@ var getSignatureTypesAndMessage = (primaryType, fields, values) => {
1946
1859
  };
1947
1860
  var SignatureUtils = {
1948
1861
  /**
1949
- * Get signature parameters for a permit
1862
+ * Get signature parameters for an ACP
1950
1863
  */
1951
- getSignatureParams: (permit, primaryType) => {
1952
- return getSignatureTypesAndMessage(primaryType, SignatureTypes[primaryType], permit);
1864
+ getSignatureParams: (acp, primaryType) => {
1865
+ return getSignatureTypesAndMessage(primaryType, SignatureTypes[primaryType], acp);
1953
1866
  },
1954
1867
  /**
1955
- * Determine the required signature type based on permit type
1868
+ * Determine the required signature type based on acp type
1956
1869
  */
1957
- getPrimaryType: (permitType) => {
1958
- if (permitType === "self")
1959
- return "PermissionedV2IssuerSelf";
1960
- if (permitType === "sharing")
1961
- return "PermissionedV2IssuerShared";
1962
- if (permitType === "recipient")
1963
- return "PermissionedV2Recipient";
1964
- throw new Error(`Unknown permit type: ${permitType}`);
1870
+ getPrimaryType: (acpType) => {
1871
+ if (acpType === "self")
1872
+ return "ACPIssuerSelf";
1873
+ if (acpType === "sharing")
1874
+ return "ACPIssuerShared";
1875
+ if (acpType === "recipient")
1876
+ return "ACPRecipient";
1877
+ throw new Error(`Unknown acp type: ${acpType}`);
1965
1878
  }
1966
1879
  };
1967
1880
  var getAclAddress = async (publicClient) => {
@@ -1983,6 +1896,11 @@ var getAclEIP712Domain = async (publicClient) => {
1983
1896
  functionName: "eip712Domain"
1984
1897
  });
1985
1898
  const [_fields, name, version, chainId, verifyingContract, _salt, _extensions] = domain;
1899
+ if (version !== "2") {
1900
+ throw new Error(
1901
+ `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.`
1902
+ );
1903
+ }
1986
1904
  return {
1987
1905
  name,
1988
1906
  version,
@@ -1990,23 +1908,26 @@ var getAclEIP712Domain = async (publicClient) => {
1990
1908
  verifyingContract
1991
1909
  };
1992
1910
  };
1993
- var checkPermitValidityOnChain = async (permission, publicClient) => {
1911
+ var checkACPValidityOnChain = async (acp, publicClient) => {
1994
1912
  const aclAddress = await getAclAddress(publicClient);
1995
1913
  try {
1996
1914
  await publicClient.simulateContract({
1997
1915
  address: aclAddress,
1998
- abi: checkPermitValidityAbi,
1999
- functionName: "checkPermitValidity",
1916
+ abi: checkACPValidityAbi,
1917
+ functionName: "checkPermissionValidity",
2000
1918
  args: [
2001
1919
  {
2002
- issuer: permission.issuer,
2003
- expiration: BigInt(permission.expiration),
2004
- recipient: permission.recipient,
2005
- validatorId: BigInt(permission.validatorId),
2006
- validatorContract: permission.validatorContract,
2007
- sealingKey: permission.sealingKey,
2008
- issuerSignature: permission.issuerSignature,
2009
- recipientSignature: permission.recipientSignature
1920
+ issuer: acp.issuer,
1921
+ expiration: BigInt(acp.expiration),
1922
+ recipient: acp.recipient,
1923
+ revokerData: BigInt(acp.revokerData),
1924
+ revokerContract: acp.revokerContract,
1925
+ scope: acp.scope,
1926
+ contracts: acp.contracts,
1927
+ handles: acp.handles,
1928
+ sealingKey: acp.sealingKey,
1929
+ issuerSignature: acp.issuerSignature,
1930
+ recipientSignature: acp.recipientSignature
2010
1931
  }
2011
1932
  ]
2012
1933
  });
@@ -2019,14 +1940,14 @@ var checkPermitValidityOnChain = async (permission, publicClient) => {
2019
1940
  throw new Error(errorName);
2020
1941
  }
2021
1942
  }
2022
- const customErrorName = extractCustomErrorFromDetails(err, checkPermitValidityAbi);
1943
+ const customErrorName = extractCustomErrorFromDetails(err, checkACPValidityAbi);
2023
1944
  if (customErrorName) {
2024
1945
  throw new Error(customErrorName);
2025
1946
  }
2026
1947
  const hhDetailsData = extractReturnData(err);
2027
1948
  if (hhDetailsData != null) {
2028
1949
  const decoded = viem.decodeErrorResult({
2029
- abi: checkPermitValidityAbi,
1950
+ abi: checkACPValidityAbi,
2030
1951
  data: hhDetailsData
2031
1952
  });
2032
1953
  throw new Error(decoded.errorName);
@@ -2054,15 +1975,15 @@ function extractReturnData(err) {
2054
1975
  const s = anyErr?.details ?? anyErr?.cause?.details ?? anyErr?.shortMessage ?? anyErr?.message ?? String(err);
2055
1976
  return s.match(/return data:\s*(0x[a-fA-F0-9]+)/)?.[1];
2056
1977
  }
2057
- var checkPermitValidityAbi = [
1978
+ var checkACPValidityAbi = [
2058
1979
  {
2059
1980
  type: "function",
2060
- name: "checkPermitValidity",
1981
+ name: "checkPermissionValidity",
2061
1982
  inputs: [
2062
1983
  {
2063
- name: "permission",
1984
+ name: "acp",
2064
1985
  type: "tuple",
2065
- internalType: "struct Permission",
1986
+ internalType: "struct ACP",
2066
1987
  components: [
2067
1988
  {
2068
1989
  name: "issuer",
@@ -2080,15 +2001,30 @@ var checkPermitValidityAbi = [
2080
2001
  internalType: "address"
2081
2002
  },
2082
2003
  {
2083
- name: "validatorId",
2004
+ name: "revokerData",
2084
2005
  type: "uint256",
2085
2006
  internalType: "uint256"
2086
2007
  },
2087
2008
  {
2088
- name: "validatorContract",
2009
+ name: "revokerContract",
2089
2010
  type: "address",
2090
2011
  internalType: "address"
2091
2012
  },
2013
+ {
2014
+ name: "scope",
2015
+ type: "uint8",
2016
+ internalType: "uint8"
2017
+ },
2018
+ {
2019
+ name: "contracts",
2020
+ type: "address[]",
2021
+ internalType: "address[]"
2022
+ },
2023
+ {
2024
+ name: "handles",
2025
+ type: "bytes32[]",
2026
+ internalType: "bytes32[]"
2027
+ },
2092
2028
  {
2093
2029
  name: "sealingKey",
2094
2030
  type: "bytes32",
@@ -2138,38 +2074,40 @@ var checkPermitValidityAbi = [
2138
2074
  }
2139
2075
  ];
2140
2076
 
2141
- // permits/permit.ts
2142
- var PermitUtils = {
2077
+ // acps/acp.ts
2078
+ var ACPUtils = {
2143
2079
  /**
2144
- * Create a self permit for personal use
2080
+ * Create a self acp for personal use
2145
2081
  */
2146
2082
  createSelf: (options) => {
2147
- const validation = validateSelfPermitOptions(options);
2083
+ const validation = validateSelfACPOptions(options);
2148
2084
  const sealingPair = GenerateSealingKey();
2149
- const permit = {
2150
- hash: PermitUtils.getHash(validation),
2085
+ const acp = {
2086
+ hash: ACPUtils.getHash(validation),
2151
2087
  ...validation,
2152
- sealingPair,
2088
+ sealingPrivateKey: sealingPair.privateKey,
2089
+ sealingKey: sealingPair.publicKey,
2153
2090
  _signedDomain: void 0
2154
2091
  };
2155
- return permit;
2092
+ return acp;
2156
2093
  },
2157
2094
  /**
2158
- * Create a sharing permit to be shared with another user
2095
+ * Create a sharing acp to be shared with another user
2159
2096
  */
2160
2097
  createSharing: (options) => {
2161
- const validation = validateSharingPermitOptions(options);
2098
+ const validation = validateSharingACPOptions(options);
2162
2099
  const sealingPair = GenerateSealingKey();
2163
- const permit = {
2164
- hash: PermitUtils.getHash(validation),
2100
+ const acp = {
2101
+ hash: ACPUtils.getHash(validation),
2165
2102
  ...validation,
2166
- sealingPair,
2103
+ sealingPrivateKey: sealingPair.privateKey,
2104
+ sealingKey: sealingPair.publicKey,
2167
2105
  _signedDomain: void 0
2168
2106
  };
2169
- return permit;
2107
+ return acp;
2170
2108
  },
2171
2109
  /**
2172
- * Import a shared permit from various input formats
2110
+ * Import a shared acp from various input formats
2173
2111
  */
2174
2112
  importShared: (options) => {
2175
2113
  let parsedOptions;
@@ -2182,33 +2120,34 @@ var PermitUtils = {
2182
2120
  } else if (typeof options === "object" && options !== null) {
2183
2121
  parsedOptions = options;
2184
2122
  } else {
2185
- throw new Error("Invalid input type, expected ImportSharedPermitOptions, object, or string");
2123
+ throw new Error("Invalid input type, expected ImportSharedACPOptions, object, or string");
2186
2124
  }
2187
2125
  if (parsedOptions.type != null && parsedOptions.type !== "sharing") {
2188
- throw new Error(`Invalid permit type <${parsedOptions.type}>, must be "sharing"`);
2126
+ throw new Error(`Invalid acp type <${parsedOptions.type}>, must be "sharing"`);
2189
2127
  }
2190
- const validation = validateImportPermitOptions({ ...parsedOptions, type: "recipient" });
2128
+ const validation = validateImportACPOptions({ ...parsedOptions, type: "recipient" });
2191
2129
  const sealingPair = GenerateSealingKey();
2192
- const permit = {
2193
- hash: PermitUtils.getHash(validation),
2130
+ const acp = {
2131
+ hash: ACPUtils.getHash(validation),
2194
2132
  ...validation,
2195
- sealingPair,
2133
+ sealingPrivateKey: sealingPair.privateKey,
2134
+ sealingKey: sealingPair.publicKey,
2196
2135
  _signedDomain: void 0
2197
2136
  };
2198
- return permit;
2137
+ return acp;
2199
2138
  },
2200
2139
  /**
2201
- * Sign a permit with the provided wallet client
2140
+ * Sign an ACP with the provided wallet client
2202
2141
  */
2203
- sign: async (permit, publicClient, walletClient) => {
2142
+ sign: async (acp, publicClient, walletClient) => {
2204
2143
  if (walletClient == null || walletClient.account == null) {
2205
2144
  throw new Error(
2206
- "Missing walletClient, you must pass in a `walletClient` for the connected user to create a permit signature"
2145
+ "Missing walletClient, you must pass in a `walletClient` for the connected user to create an ACP signature"
2207
2146
  );
2208
2147
  }
2209
- const primaryType = SignatureUtils.getPrimaryType(permit.type);
2148
+ const primaryType = SignatureUtils.getPrimaryType(acp.type);
2210
2149
  const domain = await getAclEIP712Domain(publicClient);
2211
- const { types, message } = SignatureUtils.getSignatureParams(PermitUtils.getPermission(permit, true), primaryType);
2150
+ const { types, message } = SignatureUtils.getSignatureParams(ACPUtils.getPublic(acp, true), primaryType);
2212
2151
  const signature = await walletClient.signTypedData({
2213
2152
  domain,
2214
2153
  types,
@@ -2216,190 +2155,209 @@ var PermitUtils = {
2216
2155
  message,
2217
2156
  account: walletClient.account
2218
2157
  });
2219
- let updatedPermit;
2220
- if (permit.type === "self" || permit.type === "sharing") {
2221
- updatedPermit = {
2222
- ...permit,
2158
+ let updatedACP;
2159
+ if (acp.type === "self" || acp.type === "sharing") {
2160
+ updatedACP = {
2161
+ ...acp,
2223
2162
  issuerSignature: signature,
2224
2163
  _signedDomain: domain
2225
2164
  };
2226
2165
  } else {
2227
- updatedPermit = {
2228
- ...permit,
2166
+ updatedACP = {
2167
+ ...acp,
2229
2168
  recipientSignature: signature,
2230
2169
  _signedDomain: domain
2231
2170
  };
2232
2171
  }
2233
- return updatedPermit;
2172
+ return updatedACP;
2234
2173
  },
2235
2174
  /**
2236
- * Create and sign a self permit in one operation
2175
+ * Create and sign a self acp in one operation
2237
2176
  */
2238
2177
  createSelfAndSign: async (options, publicClient, walletClient) => {
2239
- const permit = PermitUtils.createSelf(options);
2240
- return PermitUtils.sign(permit, publicClient, walletClient);
2178
+ const acp = ACPUtils.createSelf(options);
2179
+ return ACPUtils.sign(acp, publicClient, walletClient);
2241
2180
  },
2242
2181
  /**
2243
- * Create and sign a sharing permit in one operation
2182
+ * Create and sign a sharing acp in one operation
2244
2183
  */
2245
2184
  createSharingAndSign: async (options, publicClient, walletClient) => {
2246
- const permit = PermitUtils.createSharing(options);
2247
- return PermitUtils.sign(permit, publicClient, walletClient);
2185
+ const acp = ACPUtils.createSharing(options);
2186
+ return ACPUtils.sign(acp, publicClient, walletClient);
2248
2187
  },
2249
2188
  /**
2250
- * Import and sign a shared permit in one operation from various input formats
2189
+ * Import and sign a shared acp in one operation from various input formats
2251
2190
  */
2252
2191
  importSharedAndSign: async (options, publicClient, walletClient) => {
2253
- const permit = PermitUtils.importShared(options);
2254
- return PermitUtils.sign(permit, publicClient, walletClient);
2192
+ const acp = ACPUtils.importShared(options);
2193
+ return ACPUtils.sign(acp, publicClient, walletClient);
2255
2194
  },
2256
2195
  /**
2257
- * Deserialize a permit from serialized data
2196
+ * Deserialize an ACP from serialized data
2258
2197
  */
2259
2198
  deserialize: (data) => {
2260
- return {
2261
- ...data,
2262
- sealingPair: SealingKey.deserialize(data.sealingPair.privateKey, data.sealingPair.publicKey)
2263
- };
2199
+ return { ...data };
2264
2200
  },
2265
2201
  /**
2266
- * Serialize a permit for storage
2202
+ * Serialize an ACP for storage
2267
2203
  */
2268
- serialize: (permit) => {
2204
+ serialize: (acp) => {
2269
2205
  return {
2270
- hash: permit.hash,
2271
- name: permit.name,
2272
- type: permit.type,
2273
- issuer: permit.issuer,
2274
- expiration: permit.expiration,
2275
- recipient: permit.recipient,
2276
- validatorId: permit.validatorId,
2277
- validatorContract: permit.validatorContract,
2278
- issuerSignature: permit.issuerSignature,
2279
- recipientSignature: permit.recipientSignature,
2280
- _signedDomain: permit._signedDomain,
2281
- sealingPair: permit.sealingPair.serialize()
2206
+ hash: acp.hash,
2207
+ name: acp.name,
2208
+ type: acp.type,
2209
+ issuer: acp.issuer,
2210
+ expiration: acp.expiration,
2211
+ recipient: acp.recipient,
2212
+ revokerData: acp.revokerData,
2213
+ revokerContract: acp.revokerContract,
2214
+ scope: acp.scope,
2215
+ contracts: acp.contracts,
2216
+ handles: acp.handles,
2217
+ sealingKey: acp.sealingKey,
2218
+ issuerSignature: acp.issuerSignature,
2219
+ recipientSignature: acp.recipientSignature,
2220
+ _signedDomain: acp._signedDomain,
2221
+ sealingPrivateKey: acp.sealingPrivateKey
2282
2222
  };
2283
2223
  },
2284
2224
  /**
2285
- * Validate a permit (schema-level validation)
2225
+ * Validate an ACP (schema-level validation)
2286
2226
  */
2287
- validateSchema: (permit) => {
2288
- if (permit.type === "self") {
2289
- return validateSelfPermit(permit);
2290
- } else if (permit.type === "sharing") {
2291
- return validateSharingPermit(permit);
2292
- } else if (permit.type === "recipient") {
2293
- return validateImportPermit(permit);
2227
+ validateSchema: (acp) => {
2228
+ if (acp.type === "self") {
2229
+ return validateSelfACP(acp);
2230
+ } else if (acp.type === "sharing") {
2231
+ return validateSharingACP(acp);
2232
+ } else if (acp.type === "recipient") {
2233
+ return validateImportACP(acp);
2294
2234
  } else {
2295
- throw new Error("Invalid permit type");
2235
+ throw new Error("Invalid ACP type");
2296
2236
  }
2297
2237
  },
2298
2238
  /**
2299
- * Validate a permit (holistic validation).
2239
+ * Validate an ACP (holistic validation).
2300
2240
  *
2301
2241
  * This validates:
2302
- * - Permit schema (shape + invariants)
2303
- * - Permit is signed
2304
- * - Permit is not expired
2242
+ * - ACP schema (shape + invariants)
2243
+ * - ACP is signed
2244
+ * - ACP is not expired
2305
2245
  *
2306
- * For schema-only validation, use `validateSchema(permit)`.
2246
+ * For schema-only validation, use `validateSchema(acp)`.
2307
2247
  */
2308
- validate: (permit) => {
2309
- const validated = PermitUtils.validateSchema(permit);
2248
+ validate: (acp) => {
2249
+ const validated = ACPUtils.validateSchema(acp);
2310
2250
  ValidationUtils.assertSignedAndNotExpired(validated);
2311
2251
  return validated;
2312
2252
  },
2313
2253
  /**
2314
- * Get the permission object from a permit (for use in contracts)
2254
+ * Get the public component of an ACP the signed struct sent on-chain / to the decryption backend.
2255
+ * Strips the private component (hash, name, type, sealing pair).
2315
2256
  */
2316
- getPermission: (permit, skipValidation = false) => {
2257
+ getPublic: (acp, skipValidation = false) => {
2317
2258
  if (!skipValidation) {
2318
- PermitUtils.validateSchema(permit);
2259
+ ACPUtils.validateSchema(acp);
2319
2260
  }
2320
2261
  return {
2321
- issuer: permit.issuer,
2322
- expiration: permit.expiration,
2323
- recipient: permit.recipient,
2324
- validatorId: permit.validatorId,
2325
- validatorContract: permit.validatorContract,
2326
- sealingKey: `0x${permit.sealingPair.publicKey}`,
2327
- issuerSignature: permit.issuerSignature,
2328
- recipientSignature: permit.recipientSignature
2262
+ issuer: acp.issuer,
2263
+ expiration: acp.expiration,
2264
+ recipient: acp.recipient,
2265
+ revokerData: acp.revokerData,
2266
+ revokerContract: acp.revokerContract,
2267
+ scope: acp.scope,
2268
+ contracts: acp.contracts,
2269
+ handles: acp.handles,
2270
+ sealingKey: acp.sealingKey,
2271
+ issuerSignature: acp.issuerSignature,
2272
+ recipientSignature: acp.recipientSignature
2329
2273
  };
2330
2274
  },
2331
2275
  /**
2332
- * Get a stable hash for the permit (used as key in storage)
2276
+ * Get a stable hash for the acp (used as key in storage)
2333
2277
  */
2334
- getHash: (permit) => {
2278
+ getHash: (acp) => {
2335
2279
  const data = JSON.stringify({
2336
- type: permit.type,
2337
- issuer: permit.issuer,
2338
- expiration: permit.expiration,
2339
- recipient: permit.recipient,
2340
- validatorId: permit.validatorId,
2341
- validatorContract: permit.validatorContract
2280
+ type: acp.type,
2281
+ issuer: acp.issuer,
2282
+ expiration: acp.expiration,
2283
+ recipient: acp.recipient,
2284
+ revokerData: acp.revokerData,
2285
+ revokerContract: acp.revokerContract,
2286
+ scope: acp.scope,
2287
+ contracts: acp.contracts,
2288
+ handles: acp.handles
2342
2289
  });
2343
2290
  return viem.keccak256(viem.toHex(data));
2344
2291
  },
2345
2292
  /**
2346
- * Export permit data for sharing (removes sensitive fields)
2293
+ * Export acp data for sharing (strips the private component).
2294
+ * Fixed `SharedACP` shape — every field always present, aligned with
2295
+ * `ACPPublic` and the on-chain sharing payload.
2347
2296
  */
2348
- export: (permit) => {
2349
- const cleanedPermit = {
2350
- name: permit.name,
2351
- type: permit.type,
2352
- issuer: permit.issuer,
2353
- expiration: permit.expiration
2297
+ export: (acp) => {
2298
+ if (acp.type !== "sharing") {
2299
+ throw new Error(
2300
+ `Cannot export a '${acp.type}' ACP \u2014 only 'sharing' ACPs are exportable. The export includes the issuer signature.`
2301
+ );
2302
+ }
2303
+ if (acp.issuerSignature === "0x") {
2304
+ throw new Error(
2305
+ "Cannot export an unsigned sharing ACP \u2014 sign it first (the recipient needs the issuer signature)."
2306
+ );
2307
+ }
2308
+ const shared = {
2309
+ name: acp.name,
2310
+ type: acp.type,
2311
+ issuer: acp.issuer,
2312
+ expiration: acp.expiration,
2313
+ recipient: acp.recipient,
2314
+ revokerData: acp.revokerData,
2315
+ revokerContract: acp.revokerContract,
2316
+ scope: acp.scope,
2317
+ contracts: acp.contracts,
2318
+ handles: acp.handles,
2319
+ issuerSignature: acp.issuerSignature
2354
2320
  };
2355
- if (permit.recipient !== viem.zeroAddress)
2356
- cleanedPermit.recipient = permit.recipient;
2357
- if (permit.validatorId !== 0)
2358
- cleanedPermit.validatorId = permit.validatorId;
2359
- if (permit.validatorContract !== viem.zeroAddress)
2360
- cleanedPermit.validatorContract = permit.validatorContract;
2361
- if (permit.type === "sharing" && permit.issuerSignature !== "0x")
2362
- cleanedPermit.issuerSignature = permit.issuerSignature;
2363
- return JSON.stringify(cleanedPermit, void 0, 2);
2321
+ return JSON.stringify(shared, void 0, 2);
2364
2322
  },
2365
2323
  /**
2366
- * Unseal encrypted data using the permit's sealing key
2324
+ * Unseal encrypted data using the acp's sealing key
2367
2325
  */
2368
- unseal: (permit, ciphertext) => {
2369
- return permit.sealingPair.unseal(ciphertext);
2326
+ unseal: (acp, ciphertext) => {
2327
+ return unsealWithPrivateKey(acp.sealingPrivateKey, ciphertext);
2370
2328
  },
2371
2329
  /**
2372
- * Check if permit is expired
2330
+ * Check if acp is expired
2373
2331
  */
2374
- isExpired: (permit) => {
2375
- return ValidationUtils.isExpired(permit);
2332
+ isExpired: (acp) => {
2333
+ return ValidationUtils.isExpired(acp);
2376
2334
  },
2377
2335
  /**
2378
- * Check if permit is signed
2336
+ * Check if acp is signed
2379
2337
  */
2380
- isSigned: (permit) => {
2381
- return ValidationUtils.isSigned(permit);
2338
+ isSigned: (acp) => {
2339
+ return ValidationUtils.isSigned(acp);
2382
2340
  },
2383
2341
  /**
2384
- * Check if permit is signed and not expired
2342
+ * Check if acp is signed and not expired
2385
2343
  */
2386
- isSignedAndNotExpired: (permit) => {
2387
- return ValidationUtils.isSignedAndNotExpired(permit);
2344
+ isSignedAndNotExpired: (acp) => {
2345
+ return ValidationUtils.isSignedAndNotExpired(acp);
2388
2346
  },
2389
2347
  /**
2390
- * Assert that permit is signed and not expired
2348
+ * Assert that acp is signed and not expired
2391
2349
  */
2392
- assertSignedAndNotExpired: (permit) => {
2393
- return ValidationUtils.assertSignedAndNotExpired(permit);
2350
+ assertSignedAndNotExpired: (acp) => {
2351
+ return ValidationUtils.assertSignedAndNotExpired(acp);
2394
2352
  },
2395
- isValid: (permit) => {
2396
- return ValidationUtils.isValid(permit);
2353
+ isValid: (acp) => {
2354
+ return ValidationUtils.isValid(acp);
2397
2355
  },
2398
2356
  /**
2399
- * Update permit name (returns new permit instance)
2357
+ * Update acp name (returns new acp instance)
2400
2358
  */
2401
- updateName: (permit, name) => {
2402
- return { ...permit, name };
2359
+ updateName: (acp, name) => {
2360
+ return { ...acp, name };
2403
2361
  },
2404
2362
  /**
2405
2363
  * Fetch EIP712 domain from the blockchain
@@ -2408,230 +2366,468 @@ var PermitUtils = {
2408
2366
  return getAclEIP712Domain(publicClient);
2409
2367
  },
2410
2368
  /**
2411
- * Check if permit's signed domain matches the provided domain
2369
+ * Check if acp's signed domain matches the provided domain
2412
2370
  */
2413
- matchesDomain: (permit, domain) => {
2414
- return permit._signedDomain?.name === domain.name && permit._signedDomain?.version === domain.version && permit._signedDomain?.verifyingContract === domain.verifyingContract && permit._signedDomain?.chainId === domain.chainId;
2371
+ matchesDomain: (acp, domain) => {
2372
+ return acp._signedDomain?.name === domain.name && acp._signedDomain?.version === domain.version && acp._signedDomain?.verifyingContract === domain.verifyingContract && acp._signedDomain?.chainId === domain.chainId;
2415
2373
  },
2416
2374
  /**
2417
- * Check if permit's signed domain is valid for the current chain
2375
+ * Check if acp's signed domain is valid for the current chain
2418
2376
  */
2419
- checkSignedDomainValid: async (permit, publicClient) => {
2420
- if (permit._signedDomain == null)
2377
+ checkSignedDomainValid: async (acp, publicClient) => {
2378
+ if (acp._signedDomain == null)
2421
2379
  return false;
2422
2380
  const domain = await getAclEIP712Domain(publicClient);
2423
- return PermitUtils.matchesDomain(permit, domain);
2381
+ return ACPUtils.matchesDomain(acp, domain);
2424
2382
  },
2425
2383
  /**
2426
- * Check if permit passes the on-chain validation
2384
+ * Check if acp passes the on-chain validation
2427
2385
  */
2428
- checkValidityOnChain: async (permit, publicClient) => {
2429
- const permission = PermitUtils.getPermission(permit);
2430
- return checkPermitValidityOnChain(permission, publicClient);
2386
+ checkValidityOnChain: async (acp, publicClient) => {
2387
+ const publicAcp = ACPUtils.getPublic(acp);
2388
+ return checkACPValidityOnChain(publicAcp, publicClient);
2431
2389
  }
2432
2390
  };
2433
- var PERMIT_STORE_DEFAULTS = {
2434
- permits: {},
2435
- activePermitHash: {}
2391
+ var ACP_STORE_DEFAULTS = {
2392
+ acps: {},
2393
+ activeACPHash: {}
2436
2394
  };
2437
- var _permitStore = vanilla.createStore()(
2438
- middleware.persist(() => PERMIT_STORE_DEFAULTS, { name: "cofhesdk-permits" })
2395
+ var ACP_STORE_VERSION = 3;
2396
+ var _acpStore = vanilla.createStore()(
2397
+ middleware.persist(() => ACP_STORE_DEFAULTS, {
2398
+ name: "cofhesdk-acps",
2399
+ version: ACP_STORE_VERSION,
2400
+ migrate: (persistedState, version) => {
2401
+ if (version < ACP_STORE_VERSION)
2402
+ return ACP_STORE_DEFAULTS;
2403
+ return persistedState;
2404
+ }
2405
+ })
2439
2406
  );
2440
2407
  var clearStaleStore = () => {
2441
- const state = _permitStore.getState();
2442
- const hasExpectedStructure = state && typeof state === "object" && "permits" in state && "activePermitHash" in state && typeof state.permits === "object" && typeof state.activePermitHash === "object";
2408
+ const state = _acpStore.getState();
2409
+ const hasExpectedStructure = state && typeof state === "object" && "acps" in state && "activeACPHash" in state && typeof state.acps === "object" && typeof state.activeACPHash === "object";
2443
2410
  if (hasExpectedStructure)
2444
2411
  return;
2445
- _permitStore.setState({ permits: {}, activePermitHash: {} });
2412
+ _acpStore.setState({ acps: {}, activeACPHash: {} });
2446
2413
  };
2447
- var getPermit = (chainId, account, hash) => {
2414
+ var getACP = (chainId, account, hash) => {
2448
2415
  clearStaleStore();
2449
2416
  if (chainId == null || account == null || hash == null)
2450
2417
  return;
2451
- const savedPermit = _permitStore.getState().permits[chainId]?.[account]?.[hash];
2452
- if (savedPermit == null)
2418
+ const savedACP = _acpStore.getState().acps[chainId]?.[account]?.[hash];
2419
+ if (savedACP == null)
2453
2420
  return;
2454
- return PermitUtils.deserialize(savedPermit);
2421
+ return ACPUtils.deserialize(savedACP);
2455
2422
  };
2456
- var getActivePermit = (chainId, account) => {
2423
+ var getActiveACP = (chainId, account) => {
2457
2424
  clearStaleStore();
2458
2425
  if (chainId == null || account == null)
2459
2426
  return;
2460
- const activePermitHash = _permitStore.getState().activePermitHash[chainId]?.[account];
2461
- return getPermit(chainId, account, activePermitHash);
2427
+ const activeACPHash = _acpStore.getState().activeACPHash[chainId]?.[account];
2428
+ return getACP(chainId, account, activeACPHash);
2462
2429
  };
2463
- var getPermits = (chainId, account) => {
2430
+ var getACPs = (chainId, account) => {
2464
2431
  clearStaleStore();
2465
2432
  if (chainId == null || account == null)
2466
2433
  return {};
2467
- return Object.entries(_permitStore.getState().permits[chainId]?.[account] ?? {}).reduce(
2468
- (acc, [hash, permit]) => {
2469
- if (permit == void 0)
2434
+ return Object.entries(_acpStore.getState().acps[chainId]?.[account] ?? {}).reduce(
2435
+ (acc, [hash, acp]) => {
2436
+ if (acp == void 0)
2470
2437
  return acc;
2471
- return { ...acc, [hash]: PermitUtils.deserialize(permit) };
2438
+ return { ...acc, [hash]: ACPUtils.deserialize(acp) };
2472
2439
  },
2473
2440
  {}
2474
2441
  );
2475
2442
  };
2476
- var setPermit = (chainId, account, permit) => {
2443
+ var setACP = (chainId, account, acp) => {
2477
2444
  clearStaleStore();
2478
- _permitStore.setState(
2445
+ _acpStore.setState(
2479
2446
  immer.produce((state) => {
2480
- if (state.permits[chainId] == null)
2481
- state.permits[chainId] = {};
2482
- if (state.permits[chainId][account] == null)
2483
- state.permits[chainId][account] = {};
2484
- state.permits[chainId][account][permit.hash] = PermitUtils.serialize(permit);
2447
+ if (state.acps[chainId] == null)
2448
+ state.acps[chainId] = {};
2449
+ if (state.acps[chainId][account] == null)
2450
+ state.acps[chainId][account] = {};
2451
+ state.acps[chainId][account][acp.hash] = ACPUtils.serialize(acp);
2485
2452
  })
2486
2453
  );
2487
2454
  };
2488
- var removePermit = (chainId, account, hash) => {
2455
+ var removeACP = (chainId, account, hash) => {
2489
2456
  clearStaleStore();
2490
- _permitStore.setState(
2457
+ _acpStore.setState(
2491
2458
  immer.produce((state) => {
2492
- if (state.permits[chainId] == null)
2493
- state.permits[chainId] = {};
2494
- if (state.activePermitHash[chainId] == null)
2495
- state.activePermitHash[chainId] = {};
2496
- const accountPermits = state.permits[chainId][account];
2497
- if (accountPermits == null)
2459
+ if (state.acps[chainId] == null)
2460
+ state.acps[chainId] = {};
2461
+ if (state.activeACPHash[chainId] == null)
2462
+ state.activeACPHash[chainId] = {};
2463
+ const accountACPs = state.acps[chainId][account];
2464
+ if (accountACPs == null)
2498
2465
  return;
2499
- if (accountPermits[hash] == null)
2466
+ if (accountACPs[hash] == null)
2500
2467
  return;
2501
- if (state.activePermitHash[chainId][account] === hash) {
2502
- state.activePermitHash[chainId][account] = void 0;
2468
+ if (state.activeACPHash[chainId][account] === hash) {
2469
+ state.activeACPHash[chainId][account] = void 0;
2503
2470
  }
2504
- accountPermits[hash] = void 0;
2471
+ accountACPs[hash] = void 0;
2505
2472
  })
2506
2473
  );
2507
2474
  };
2508
- var getActivePermitHash = (chainId, account) => {
2475
+ var getActiveACPHash = (chainId, account) => {
2509
2476
  clearStaleStore();
2510
2477
  if (chainId == null || account == null)
2511
2478
  return void 0;
2512
- return _permitStore.getState().activePermitHash[chainId]?.[account];
2479
+ return _acpStore.getState().activeACPHash[chainId]?.[account];
2513
2480
  };
2514
- var setActivePermitHash = (chainId, account, hash) => {
2481
+ var setActiveACPHash = (chainId, account, hash) => {
2515
2482
  clearStaleStore();
2516
- _permitStore.setState(
2483
+ _acpStore.setState(
2517
2484
  immer.produce((state) => {
2518
- if (state.activePermitHash[chainId] == null)
2519
- state.activePermitHash[chainId] = {};
2520
- state.activePermitHash[chainId][account] = hash;
2485
+ if (state.activeACPHash[chainId] == null)
2486
+ state.activeACPHash[chainId] = {};
2487
+ state.activeACPHash[chainId][account] = hash;
2521
2488
  })
2522
2489
  );
2523
2490
  };
2524
- var removeActivePermitHash = (chainId, account) => {
2491
+ var removeActiveACPHash = (chainId, account) => {
2525
2492
  clearStaleStore();
2526
- _permitStore.setState(
2493
+ _acpStore.setState(
2527
2494
  immer.produce((state) => {
2528
- if (state.activePermitHash[chainId])
2529
- state.activePermitHash[chainId][account] = void 0;
2495
+ if (state.activeACPHash[chainId])
2496
+ state.activeACPHash[chainId][account] = void 0;
2530
2497
  })
2531
2498
  );
2532
2499
  };
2533
2500
  var resetStore = () => {
2534
2501
  clearStaleStore();
2535
- _permitStore.setState({ permits: {}, activePermitHash: {} });
2502
+ _acpStore.setState({ acps: {}, activeACPHash: {} });
2536
2503
  };
2537
- var permitStore = {
2538
- store: _permitStore,
2539
- getPermit,
2540
- getActivePermit,
2541
- getPermits,
2542
- setPermit,
2543
- removePermit,
2544
- getActivePermitHash,
2545
- setActivePermitHash,
2546
- removeActivePermitHash,
2504
+ var acpStore = {
2505
+ store: _acpStore,
2506
+ getACP,
2507
+ getActiveACP,
2508
+ getACPs,
2509
+ setACP,
2510
+ removeACP,
2511
+ getActiveACPHash,
2512
+ setActiveACPHash,
2513
+ removeActiveACPHash,
2547
2514
  resetStore
2548
2515
  };
2549
- var storeActivePermit = async (permit, publicClient, walletClient) => {
2516
+ var ACP_VALIDATOR_ABI = viem.parseAbi([
2517
+ "function revokeSingle(uint256 id)",
2518
+ "function revokeAllExisting()",
2519
+ "function disabled(address issuer, uint256 id) view returns (bool)"
2520
+ ]);
2521
+ var storeACP = async (acp, publicClient, walletClient) => {
2550
2522
  const chainId = await publicClient.getChainId();
2551
2523
  const account = walletClient.account.address;
2552
- permitStore.setPermit(chainId, account, permit);
2553
- permitStore.setActivePermitHash(chainId, account, permit.hash);
2524
+ acpStore.setACP(chainId, account, acp);
2554
2525
  };
2555
- var createPermitWithSign = async (options, publicClient, walletClient, permitMethod) => {
2556
- const permit = await permitMethod(options, publicClient, walletClient);
2557
- await storeActivePermit(permit, publicClient, walletClient);
2558
- return permit;
2526
+ var storeActiveACP = async (acp, publicClient, walletClient) => {
2527
+ await storeACP(acp, publicClient, walletClient);
2528
+ const chainId = await publicClient.getChainId();
2529
+ const account = walletClient.account.address;
2530
+ acpStore.setActiveACPHash(chainId, account, acp.hash);
2531
+ };
2532
+ var createACPWithSign = async (options, publicClient, walletClient, acpMethod, activate = true) => {
2533
+ const acp = await acpMethod(options, publicClient, walletClient);
2534
+ if (activate) {
2535
+ await storeActiveACP(acp, publicClient, walletClient);
2536
+ } else {
2537
+ await storeACP(acp, publicClient, walletClient);
2538
+ }
2539
+ return acp;
2559
2540
  };
2560
2541
  var createSelf = async (options, publicClient, walletClient) => {
2561
- return createPermitWithSign(options, publicClient, walletClient, PermitUtils.createSelfAndSign);
2542
+ return createACPWithSign(options, publicClient, walletClient, ACPUtils.createSelfAndSign);
2562
2543
  };
2563
2544
  var createSharing = async (options, publicClient, walletClient) => {
2564
- return createPermitWithSign(options, publicClient, walletClient, PermitUtils.createSharingAndSign);
2545
+ return createACPWithSign(options, publicClient, walletClient, ACPUtils.createSharingAndSign, false);
2565
2546
  };
2566
2547
  var importShared = async (options, publicClient, walletClient) => {
2567
- return createPermitWithSign(options, publicClient, walletClient, PermitUtils.importSharedAndSign);
2548
+ return createACPWithSign(options, publicClient, walletClient, ACPUtils.importSharedAndSign);
2568
2549
  };
2569
- var getHash = (permit) => {
2570
- return PermitUtils.getHash(permit);
2550
+ var getHash = (acp) => {
2551
+ return ACPUtils.getHash(acp);
2571
2552
  };
2572
- var exportShared = (permit) => {
2573
- return PermitUtils.export(permit);
2553
+ var exportShared = (acp) => {
2554
+ return ACPUtils.export(acp);
2574
2555
  };
2575
- var serialize = (permit) => {
2576
- return PermitUtils.serialize(permit);
2556
+ var serialize = (acp) => {
2557
+ return ACPUtils.serialize(acp);
2577
2558
  };
2578
2559
  var deserialize = (serialized) => {
2579
- return PermitUtils.deserialize(serialized);
2560
+ return ACPUtils.deserialize(serialized);
2580
2561
  };
2581
- var getPermit2 = (chainId, account, hash) => {
2582
- return permitStore.getPermit(chainId, account, hash);
2562
+ var getACP2 = (chainId, account, hash) => {
2563
+ return acpStore.getACP(chainId, account, hash);
2583
2564
  };
2584
- var getPermits2 = (chainId, account) => {
2585
- return permitStore.getPermits(chainId, account);
2565
+ var getACPs2 = (chainId, account) => {
2566
+ return acpStore.getACPs(chainId, account);
2586
2567
  };
2587
- var getActivePermit2 = (chainId, account) => {
2588
- return permitStore.getActivePermit(chainId, account);
2568
+ var getActiveACP2 = (chainId, account) => {
2569
+ return acpStore.getActiveACP(chainId, account);
2589
2570
  };
2590
- var getActivePermitHash2 = (chainId, account) => {
2591
- return permitStore.getActivePermitHash(chainId, account);
2571
+ var getActiveACPHash2 = (chainId, account) => {
2572
+ return acpStore.getActiveACPHash(chainId, account);
2592
2573
  };
2593
- var selectActivePermit = (chainId, account, hash) => {
2594
- permitStore.setActivePermitHash(chainId, account, hash);
2574
+ var selectActiveACP = (chainId, account, hash) => {
2575
+ acpStore.setActiveACPHash(chainId, account, hash);
2595
2576
  };
2596
- var getOrCreateSelfPermit = async (publicClient, walletClient, chainId, account, options) => {
2577
+ var getOrCreateSelfACP = async (publicClient, walletClient, chainId, account, options) => {
2597
2578
  const _chainId = chainId ?? await publicClient.getChainId();
2598
2579
  const _account = account ?? walletClient.account.address;
2599
- const activePermit = await getActivePermit2(_chainId, _account);
2600
- if (activePermit && activePermit.type === "self") {
2601
- return activePermit;
2580
+ const activeACP = await getActiveACP2(_chainId, _account);
2581
+ if (activeACP && activeACP.type === "self" && ACPUtils.isValid(activeACP).valid) {
2582
+ return activeACP;
2602
2583
  }
2603
- return createSelf(options ?? { issuer: _account, name: "Autogenerated Self Permit" }, publicClient, walletClient);
2584
+ return createSelf(options ?? { issuer: _account, name: "Autogenerated Self ACP" }, publicClient, walletClient);
2604
2585
  };
2605
- var getOrCreateSharingPermit = async (publicClient, walletClient, options, chainId, account) => {
2586
+ var getOrCreateSharingACP = async (publicClient, walletClient, options, chainId, account) => {
2606
2587
  const _chainId = chainId ?? await publicClient.getChainId();
2607
2588
  const _account = account ?? walletClient.account.address;
2608
- const activePermit = await getActivePermit2(_chainId, _account);
2609
- if (activePermit && activePermit.type === "sharing") {
2610
- return activePermit;
2589
+ const activeACP = await getActiveACP2(_chainId, _account);
2590
+ if (activeACP && activeACP.type === "sharing" && ACPUtils.isValid(activeACP).valid) {
2591
+ return activeACP;
2611
2592
  }
2612
2593
  return createSharing(options, publicClient, walletClient);
2613
2594
  };
2614
- var removePermit2 = async (chainId, account, hash) => permitStore.removePermit(chainId, account, hash);
2615
- var removeActivePermit = async (chainId, account) => permitStore.removeActivePermitHash(chainId, account);
2616
- var permits = {
2617
- getSnapshot: permitStore.store.getState,
2618
- subscribe: permitStore.store.subscribe,
2595
+ var applyACPDefaults = (options, acpConfig, chainId) => {
2596
+ const result = { ...options };
2597
+ const defaultRevoker = acpConfig?.defaultRevoker?.[chainId];
2598
+ const hasValidatorOptions = options.revokerData != null || options.revokerContract != null;
2599
+ if (defaultRevoker != null && !hasValidatorOptions) {
2600
+ result.revokerContract = defaultRevoker;
2601
+ result.revokerData = Math.round(Date.now() / 1e3) - 60;
2602
+ }
2603
+ const defaultContracts = acpConfig?.defaultContractScopes?.[chainId];
2604
+ const hasScopeOptions = options.scope != null || options.contracts != null || options.handles != null;
2605
+ if (defaultContracts != null && defaultContracts.length > 0 && !hasScopeOptions) {
2606
+ result.contracts = defaultContracts;
2607
+ }
2608
+ return result;
2609
+ };
2610
+ var ACL_SERVED_ADDRESSES_ABI = viem.parseAbi([
2611
+ "function acl() view returns (address)",
2612
+ "function defaultRevokerContract() view returns (address)",
2613
+ "function shareRegistry() view returns (address)"
2614
+ ]);
2615
+ var aclServedAddressesCache = /* @__PURE__ */ new Map();
2616
+ var clearAclServedAddresses = () => aclServedAddressesCache.clear();
2617
+ var getAclServedAddresses = async (publicClient, chainId) => {
2618
+ const cached = aclServedAddressesCache.get(chainId);
2619
+ if (cached != null)
2620
+ return cached;
2621
+ let aclAddress;
2622
+ try {
2623
+ aclAddress = await publicClient.readContract({
2624
+ address: TASK_MANAGER_ADDRESS,
2625
+ abi: ACL_SERVED_ADDRESSES_ABI,
2626
+ functionName: "acl"
2627
+ });
2628
+ } catch {
2629
+ return {};
2630
+ }
2631
+ const [defaultRevoker, shareRegistry] = await Promise.all([
2632
+ publicClient.readContract({ address: aclAddress, abi: ACL_SERVED_ADDRESSES_ABI, functionName: "defaultRevokerContract" }).catch(() => void 0),
2633
+ publicClient.readContract({ address: aclAddress, abi: ACL_SERVED_ADDRESSES_ABI, functionName: "shareRegistry" }).catch(() => void 0)
2634
+ ]);
2635
+ const resolved = {
2636
+ defaultRevoker: defaultRevoker != null && defaultRevoker !== viem.zeroAddress ? defaultRevoker : void 0,
2637
+ shareRegistry: shareRegistry != null && shareRegistry !== viem.zeroAddress ? shareRegistry : void 0
2638
+ };
2639
+ aclServedAddressesCache.set(chainId, resolved);
2640
+ return resolved;
2641
+ };
2642
+ var applyACPDefaultsFromChain = async (options, acpConfig, publicClient, chainId) => {
2643
+ const hasExplicitRevoker = acpConfig?.defaultRevoker?.[chainId] != null || options.revokerData != null || options.revokerContract != null;
2644
+ if (hasExplicitRevoker)
2645
+ return applyACPDefaults(options, acpConfig, chainId);
2646
+ const served = await getAclServedAddresses(publicClient, chainId);
2647
+ const effectiveConfig = served.defaultRevoker != null ? { ...acpConfig, defaultRevoker: { ...acpConfig?.defaultRevoker, [chainId]: served.defaultRevoker } } : acpConfig;
2648
+ return applyACPDefaults(options, effectiveConfig, chainId);
2649
+ };
2650
+ var revokeACP = async (acp, walletClient) => {
2651
+ if (acp.revokerContract === viem.zeroAddress || acp.revokerData === 0) {
2652
+ throw new Error("ACP is not revocable: it has no revoker (revokerContract/revokerData unset)");
2653
+ }
2654
+ if (walletClient.account == null)
2655
+ throw new Error("Missing walletClient account");
2656
+ if (walletClient.account.address.toLowerCase() !== acp.issuer.toLowerCase()) {
2657
+ throw new Error("Only the acp issuer can revoke it");
2658
+ }
2659
+ return walletClient.writeContract({
2660
+ address: acp.revokerContract,
2661
+ abi: ACP_VALIDATOR_ABI,
2662
+ functionName: "revokeSingle",
2663
+ args: [BigInt(acp.revokerData)],
2664
+ account: walletClient.account,
2665
+ chain: walletClient.chain
2666
+ });
2667
+ };
2668
+ var revokeAllACPs = async (walletClient, publicClient, revokerContract) => {
2669
+ if (walletClient.account == null)
2670
+ throw new Error("Missing walletClient account");
2671
+ let revoker = revokerContract;
2672
+ if (revoker == null) {
2673
+ const chainId = await publicClient.getChainId();
2674
+ const active = getActiveACP2(chainId, walletClient.account.address);
2675
+ revoker = active?.revokerContract;
2676
+ }
2677
+ if (revoker == null || revoker === viem.zeroAddress) {
2678
+ throw new Error("No revoker contract: pass `revokerContract` or activate a revocable acp first");
2679
+ }
2680
+ return walletClient.writeContract({
2681
+ address: revoker,
2682
+ abi: ACP_VALIDATOR_ABI,
2683
+ functionName: "revokeAllExisting",
2684
+ args: [],
2685
+ account: walletClient.account,
2686
+ chain: walletClient.chain
2687
+ });
2688
+ };
2689
+ var isACPRevoked = async (acp, publicClient) => {
2690
+ if (acp.revokerContract === viem.zeroAddress || acp.revokerData === 0)
2691
+ return false;
2692
+ return publicClient.readContract({
2693
+ address: acp.revokerContract,
2694
+ abi: ACP_VALIDATOR_ABI,
2695
+ functionName: "disabled",
2696
+ args: [acp.issuer, BigInt(acp.revokerData)]
2697
+ });
2698
+ };
2699
+ var ACP_SHARE_REGISTRY_ABI = viem.parseAbi([
2700
+ "struct ACP { address issuer; uint64 expiration; address recipient; uint256 revokerData; address revokerContract; uint8 scope; address[] contracts; bytes32[] handles; bytes32 sealingKey; bytes issuerSignature; bytes recipientSignature; }",
2701
+ "function share(ACP calldata acp) external returns (bytes32)",
2702
+ "function removeShare(bytes32 shareId) external",
2703
+ "function sharesFor(address recipient) external view returns (ACP[] memory)",
2704
+ "function getShare(bytes32 shareId) external view returns (ACP memory)",
2705
+ "function isShareValid(bytes32 shareId) external view returns (bool)"
2706
+ ]);
2707
+ var ACP_TUPLE = [
2708
+ {
2709
+ type: "tuple",
2710
+ components: [
2711
+ { name: "issuer", type: "address" },
2712
+ { name: "expiration", type: "uint64" },
2713
+ { name: "recipient", type: "address" },
2714
+ { name: "revokerData", type: "uint256" },
2715
+ { name: "revokerContract", type: "address" },
2716
+ { name: "scope", type: "uint8" },
2717
+ { name: "contracts", type: "address[]" },
2718
+ { name: "handles", type: "bytes32[]" },
2719
+ { name: "sealingKey", type: "bytes32" },
2720
+ { name: "issuerSignature", type: "bytes" },
2721
+ { name: "recipientSignature", type: "bytes" }
2722
+ ]
2723
+ }
2724
+ ];
2725
+ var ZERO_BYTES32 = `0x${"0".repeat(64)}`;
2726
+ var toChainShare = (acp) => {
2727
+ const pub = ACPUtils.getPublic(acp, true);
2728
+ return {
2729
+ ...pub,
2730
+ expiration: BigInt(pub.expiration),
2731
+ revokerData: BigInt(pub.revokerData),
2732
+ sealingKey: ZERO_BYTES32,
2733
+ recipientSignature: "0x"
2734
+ };
2735
+ };
2736
+ var computeShareId = (acp) => {
2737
+ const p = toChainShare(acp);
2738
+ return viem.keccak256(viem.encodeAbiParameters(ACP_TUPLE, [p]));
2739
+ };
2740
+ var shareOnChain = async (acp, walletClient, registry) => {
2741
+ if (acp.type !== "sharing") {
2742
+ throw new Error(`Cannot share a '${acp.type}' ACP on-chain \u2014 only 'sharing' ACPs are shareable.`);
2743
+ }
2744
+ if (acp.issuerSignature === "0x") {
2745
+ throw new Error("Cannot share an unsigned sharing ACP \u2014 sign it first.");
2746
+ }
2747
+ if (walletClient.account == null)
2748
+ throw new Error("Missing walletClient account");
2749
+ if (walletClient.account.address.toLowerCase() !== acp.issuer.toLowerCase()) {
2750
+ throw new Error("Only the ACP issuer can share it on-chain");
2751
+ }
2752
+ const txHash = await walletClient.writeContract({
2753
+ address: registry,
2754
+ abi: ACP_SHARE_REGISTRY_ABI,
2755
+ functionName: "share",
2756
+ args: [toChainShare(acp)],
2757
+ account: walletClient.account,
2758
+ chain: walletClient.chain ?? null
2759
+ });
2760
+ return { txHash, shareId: computeShareId(acp) };
2761
+ };
2762
+ var getIncomingShares = async (publicClient, registry, recipient) => {
2763
+ const raw = await publicClient.readContract({
2764
+ address: registry,
2765
+ abi: ACP_SHARE_REGISTRY_ABI,
2766
+ functionName: "sharesFor",
2767
+ args: [recipient]
2768
+ });
2769
+ return raw.map((s) => ({
2770
+ shareId: viem.keccak256(viem.encodeAbiParameters(ACP_TUPLE, [s])),
2771
+ issuer: s.issuer,
2772
+ expiration: Number(s.expiration),
2773
+ recipient: s.recipient,
2774
+ revokerData: Number(s.revokerData),
2775
+ revokerContract: s.revokerContract,
2776
+ scope: Number(s.scope),
2777
+ contracts: [...s.contracts],
2778
+ handles: [...s.handles],
2779
+ issuerSignature: s.issuerSignature
2780
+ }));
2781
+ };
2782
+ var importFromChain = async (share, publicClient, walletClient) => {
2783
+ const { shareId: _shareId, ...options } = share;
2784
+ return importShared({ ...options, type: "sharing" }, publicClient, walletClient);
2785
+ };
2786
+ var removeShareOnChain = async (shareId, walletClient, registry) => {
2787
+ if (walletClient.account == null)
2788
+ throw new Error("Missing walletClient account");
2789
+ return walletClient.writeContract({
2790
+ address: registry,
2791
+ abi: ACP_SHARE_REGISTRY_ABI,
2792
+ functionName: "removeShare",
2793
+ args: [shareId],
2794
+ account: walletClient.account,
2795
+ chain: walletClient.chain ?? null
2796
+ });
2797
+ };
2798
+ var removeACP2 = async (chainId, account, hash) => acpStore.removeACP(chainId, account, hash);
2799
+ var removeActiveACP = async (chainId, account) => acpStore.removeActiveACPHash(chainId, account);
2800
+ var acps = {
2801
+ getSnapshot: acpStore.store.getState,
2802
+ subscribe: acpStore.store.subscribe,
2619
2803
  createSelf,
2620
2804
  createSharing,
2621
2805
  importShared,
2622
- getOrCreateSelfPermit,
2623
- getOrCreateSharingPermit,
2806
+ getOrCreateSelfACP,
2807
+ getOrCreateSharingACP,
2624
2808
  getHash,
2625
2809
  export: exportShared,
2626
2810
  serialize,
2627
2811
  deserialize,
2628
- getPermit: getPermit2,
2629
- getPermits: getPermits2,
2630
- getActivePermit: getActivePermit2,
2631
- getActivePermitHash: getActivePermitHash2,
2632
- removePermit: removePermit2,
2633
- selectActivePermit,
2634
- removeActivePermit
2812
+ getACP: getACP2,
2813
+ getACPs: getACPs2,
2814
+ getActiveACP: getActiveACP2,
2815
+ getActiveACPHash: getActiveACPHash2,
2816
+ removeACP: removeACP2,
2817
+ selectActiveACP,
2818
+ removeActiveACP,
2819
+ revokeACP,
2820
+ revokeAllACPs,
2821
+ isACPRevoked,
2822
+ shareOnChain,
2823
+ getIncomingShares,
2824
+ importFromChain,
2825
+ removeShareOnChain,
2826
+ computeShareId,
2827
+ applyACPDefaults,
2828
+ applyACPDefaultsFromChain,
2829
+ getAclServedAddresses,
2830
+ clearAclServedAddresses
2635
2831
  };
2636
2832
  function uint160ToAddress(uint160) {
2637
2833
  const hexStr = uint160.toString(16).padStart(40, "0");
@@ -2694,13 +2890,16 @@ var MockThresholdNetworkAbi = [
2694
2890
  {
2695
2891
  name: "permission",
2696
2892
  type: "tuple",
2697
- internalType: "struct Permission",
2893
+ internalType: "struct ACPermission",
2698
2894
  components: [
2699
2895
  { name: "issuer", type: "address", internalType: "address" },
2700
2896
  { name: "expiration", type: "uint64", internalType: "uint64" },
2701
2897
  { name: "recipient", type: "address", internalType: "address" },
2702
- { name: "validatorId", type: "uint256", internalType: "uint256" },
2703
- { name: "validatorContract", type: "address", internalType: "address" },
2898
+ { name: "revokerData", type: "uint256", internalType: "uint256" },
2899
+ { name: "revokerContract", type: "address", internalType: "address" },
2900
+ { name: "scope", type: "uint8", internalType: "uint8" },
2901
+ { name: "contracts", type: "address[]", internalType: "address[]" },
2902
+ { name: "handles", type: "bytes32[]", internalType: "bytes32[]" },
2704
2903
  { name: "sealingKey", type: "bytes32", internalType: "bytes32" },
2705
2904
  { name: "issuerSignature", type: "bytes", internalType: "bytes" },
2706
2905
  { name: "recipientSignature", type: "bytes", internalType: "bytes" }
@@ -2723,13 +2922,16 @@ var MockThresholdNetworkAbi = [
2723
2922
  {
2724
2923
  name: "permission",
2725
2924
  type: "tuple",
2726
- internalType: "struct Permission",
2925
+ internalType: "struct ACPermission",
2727
2926
  components: [
2728
2927
  { name: "issuer", type: "address", internalType: "address" },
2729
2928
  { name: "expiration", type: "uint64", internalType: "uint64" },
2730
2929
  { name: "recipient", type: "address", internalType: "address" },
2731
- { name: "validatorId", type: "uint256", internalType: "uint256" },
2732
- { name: "validatorContract", type: "address", internalType: "address" },
2930
+ { name: "revokerData", type: "uint256", internalType: "uint256" },
2931
+ { name: "revokerContract", type: "address", internalType: "address" },
2932
+ { name: "scope", type: "uint8", internalType: "uint8" },
2933
+ { name: "contracts", type: "address[]", internalType: "address[]" },
2934
+ { name: "handles", type: "bytes32[]", internalType: "bytes32[]" },
2733
2935
  { name: "sealingKey", type: "bytes32", internalType: "bytes32" },
2734
2936
  { name: "issuerSignature", type: "bytes", internalType: "bytes" },
2735
2937
  { name: "recipientSignature", type: "bytes", internalType: "bytes" }
@@ -2794,19 +2996,22 @@ var MockThresholdNetworkAbi = [
2794
2996
  },
2795
2997
  {
2796
2998
  type: "function",
2797
- name: "decryptForTxWithPermit",
2999
+ name: "decryptForTxWithACP",
2798
3000
  inputs: [
2799
3001
  { name: "ctHash", type: "uint256", internalType: "uint256" },
2800
3002
  {
2801
3003
  name: "permission",
2802
3004
  type: "tuple",
2803
- internalType: "struct Permission",
3005
+ internalType: "struct ACPermission",
2804
3006
  components: [
2805
3007
  { name: "issuer", type: "address", internalType: "address" },
2806
3008
  { name: "expiration", type: "uint64", internalType: "uint64" },
2807
3009
  { name: "recipient", type: "address", internalType: "address" },
2808
- { name: "validatorId", type: "uint256", internalType: "uint256" },
2809
- { name: "validatorContract", type: "address", internalType: "address" },
3010
+ { name: "revokerData", type: "uint256", internalType: "uint256" },
3011
+ { name: "revokerContract", type: "address", internalType: "address" },
3012
+ { name: "scope", type: "uint8", internalType: "uint8" },
3013
+ { name: "contracts", type: "address[]", internalType: "address[]" },
3014
+ { name: "handles", type: "bytes32[]", internalType: "bytes32[]" },
2810
3015
  { name: "sealingKey", type: "bytes32", internalType: "bytes32" },
2811
3016
  { name: "issuerSignature", type: "bytes", internalType: "bytes" },
2812
3017
  { name: "recipientSignature", type: "bytes", internalType: "bytes" }
@@ -2822,7 +3027,7 @@ var MockThresholdNetworkAbi = [
2822
3027
  },
2823
3028
  {
2824
3029
  type: "function",
2825
- name: "decryptForTxWithoutPermit",
3030
+ name: "decryptForTxWithoutACP",
2826
3031
  inputs: [{ name: "ctHash", type: "uint256", internalType: "uint256" }],
2827
3032
  outputs: [
2828
3033
  { name: "allowed", type: "bool", internalType: "bool" },
@@ -2834,12 +3039,12 @@ var MockThresholdNetworkAbi = [
2834
3039
  ];
2835
3040
 
2836
3041
  // core/decrypt/cofheMocksDecryptForView.ts
2837
- async function cofheMocksDecryptForView(ctHash, utype, permit, publicClient) {
2838
- const permission = PermitUtils.getPermission(permit, true);
3042
+ async function cofheMocksDecryptForView(ctHash, utype, acp, publicClient) {
3043
+ const wireAcp = ACPUtils.getPublic(acp, true);
2839
3044
  const permissionWithBigInts = {
2840
- ...permission,
2841
- expiration: BigInt(permission.expiration),
2842
- validatorId: BigInt(permission.validatorId)
3045
+ ...wireAcp,
3046
+ expiration: BigInt(wireAcp.expiration),
3047
+ revokerData: BigInt(wireAcp.revokerData)
2843
3048
  };
2844
3049
  const [allowed, error, result] = await publicClient.readContract({
2845
3050
  address: MOCKS_THRESHOLD_NETWORK_ADDRESS,
@@ -2860,11 +3065,34 @@ async function cofheMocksDecryptForView(ctHash, utype, permit, publicClient) {
2860
3065
  });
2861
3066
  }
2862
3067
  const sealedBigInt = BigInt(result);
2863
- const sealingKeyBigInt = BigInt(permission.sealingKey);
3068
+ const sealingKeyBigInt = BigInt(acp.sealingKey);
2864
3069
  const unsealed = sealedBigInt ^ sealingKeyBigInt;
2865
3070
  return unsealed;
2866
3071
  }
2867
3072
 
3073
+ // core/debug.ts
3074
+ var interceptors = {};
3075
+ async function cofheFetch(url, init, ctx = { op: "request" }) {
3076
+ let finalUrl = url;
3077
+ let finalInit = init;
3078
+ if (interceptors.onRequest) {
3079
+ const override = await interceptors.onRequest(finalUrl, finalInit, ctx);
3080
+ if (override) {
3081
+ if (override.url !== void 0)
3082
+ finalUrl = override.url;
3083
+ if (override.init !== void 0)
3084
+ finalInit = override.init;
3085
+ }
3086
+ }
3087
+ let response = await fetch(finalUrl, finalInit);
3088
+ if (interceptors.onResponse) {
3089
+ const replaced = await interceptors.onResponse(response, ctx);
3090
+ if (replaced)
3091
+ response = replaced;
3092
+ }
3093
+ return response;
3094
+ }
3095
+
2868
3096
  // core/decrypt/polling.ts
2869
3097
  function computeMinuteRampPollIntervalMs(elapsedMs, params) {
2870
3098
  const elapsedSeconds = Math.floor(elapsedMs / 1e3);
@@ -2873,11 +3101,61 @@ function computeMinuteRampPollIntervalMs(elapsedMs, params) {
2873
3101
  return Math.min(params.maxIntervalMs, Math.max(params.minIntervalMs, intervalMs));
2874
3102
  }
2875
3103
 
3104
+ // core/decrypt/apiError.ts
3105
+ var BACKEND_ERROR_CODE_TO_COFHE_ERROR_CODE = {
3106
+ bad_request: "BAD_REQUEST" /* BadRequest */,
3107
+ unknown_chain: "UNKNOWN_CHAIN" /* UnknownChain */,
3108
+ acp_malformed: "ACP_MALFORMED" /* ACPMalformed */,
3109
+ acp_denied: "ACP_DENIED" /* ACPDenied */,
3110
+ // ACP-era backends fold revoked into denied
3111
+ acp_expired: "ACP_EXPIRED" /* ACPExpired */,
3112
+ acp_invalid: "ACP_INVALID" /* ACPInvalid */,
3113
+ acp_required: "ACP_REQUIRED" /* ACPRequired */,
3114
+ acp_verifier_error: "ACP_VERIFIER_ERROR" /* ACPVerifierError */,
3115
+ acp_verifier_timeout: "ACP_VERIFIER_TIMEOUT" /* ACPVerifierTimeout */,
3116
+ not_publicly_allowed: "NOT_PUBLICLY_ALLOWED" /* NotPubliclyAllowed */,
3117
+ ct_not_found: "CT_NOT_FOUND" /* CtNotFound */,
3118
+ unsupported_security_zone: "UNSUPPORTED_SECURITY_ZONE" /* UnsupportedSecurityZone */,
3119
+ unsupported_type: "UNSUPPORTED_TYPE" /* UnsupportedType */,
3120
+ internal_error: "INTERNAL_ERROR" /* InternalError */,
3121
+ signing_failed: "SIGNING_FAILED" /* SigningFailed */,
3122
+ ct_source_error: "CT_SOURCE_ERROR" /* CtSourceError */,
3123
+ ct_source_timeout: "CT_SOURCE_TIMEOUT" /* CtSourceTimeout */,
3124
+ seal_failed: "SEAL_FAILED" /* SealFailed */
3125
+ };
3126
+ function isBackendApiErrorCode(value) {
3127
+ return value in BACKEND_ERROR_CODE_TO_COFHE_ERROR_CODE;
3128
+ }
3129
+ async function parseApiErrorResponseBody(response) {
3130
+ let errorMessage = `HTTP ${response.status}`;
3131
+ let apiErrorCode;
3132
+ try {
3133
+ const body = await response.json();
3134
+ if (body && typeof body === "object") {
3135
+ const record = body;
3136
+ if (typeof record.error === "string" && record.error.length > 0) {
3137
+ apiErrorCode = record.error;
3138
+ }
3139
+ if (typeof record.error_message === "string" && record.error_message.length > 0) {
3140
+ errorMessage = record.error_message;
3141
+ } else if (typeof record.message === "string" && record.message.length > 0) {
3142
+ errorMessage = record.message;
3143
+ }
3144
+ }
3145
+ } catch {
3146
+ errorMessage = response.statusText || errorMessage;
3147
+ }
3148
+ return { apiErrorCode, errorMessage };
3149
+ }
3150
+ function mapApiErrorCodeToCofheErrorCode(apiErrorCode, fallback) {
3151
+ if (apiErrorCode && isBackendApiErrorCode(apiErrorCode)) {
3152
+ return BACKEND_ERROR_CODE_TO_COFHE_ERROR_CODE[apiErrorCode];
3153
+ }
3154
+ return fallback;
3155
+ }
3156
+
2876
3157
  // core/decrypt/submitRetry.ts
2877
3158
  var DEFAULT_404_RETRY_TIMEOUT_MS = 1e4;
2878
- function isRetryableSubmitStatus(status) {
2879
- return status === 204 || status === 404;
2880
- }
2881
3159
  function normalize404RetryTimeoutMs(params) {
2882
3160
  const { timeoutMs, operationLabel, errorCode } = params;
2883
3161
  if (timeoutMs === void 0)
@@ -2894,32 +3172,24 @@ function normalize404RetryTimeoutMs(params) {
2894
3172
  return timeoutMs;
2895
3173
  }
2896
3174
  async function classifySubmitResponse(params) {
2897
- const { response, extractErrorMessage } = params;
2898
- if (isRetryableSubmitStatus(response.status)) {
2899
- return { kind: "retryable", status: response.status };
3175
+ const { response, fallbackErrorCode } = params;
3176
+ if (response.status === 204) {
3177
+ return { kind: "retryable", status: 204 };
2900
3178
  }
2901
3179
  if (response.ok) {
2902
3180
  return { kind: "parse-json" };
2903
3181
  }
2904
- let errorMessage = `HTTP ${response.status}`;
2905
- try {
2906
- const errorBody = await response.json();
2907
- const maybeErrorMessage = extractErrorMessage?.(errorBody);
2908
- if (typeof maybeErrorMessage === "string" && maybeErrorMessage.length > 0) {
2909
- errorMessage = maybeErrorMessage;
2910
- } else if (errorBody && typeof errorBody === "object") {
2911
- const defaultMessage = errorBody.error_message;
2912
- const fallbackMessage = errorBody.message;
2913
- if (typeof defaultMessage === "string" && defaultMessage.length > 0) {
2914
- errorMessage = defaultMessage;
2915
- } else if (typeof fallbackMessage === "string" && fallbackMessage.length > 0) {
2916
- errorMessage = fallbackMessage;
2917
- }
2918
- }
2919
- } catch {
2920
- errorMessage = response.statusText || errorMessage;
3182
+ const { apiErrorCode, errorMessage } = await parseApiErrorResponseBody(response);
3183
+ if (response.status === 404) {
3184
+ return { kind: "retryable", status: 404, apiErrorMessage: errorMessage };
2921
3185
  }
2922
- return { kind: "fatal-http", errorMessage };
3186
+ return {
3187
+ kind: "fatal-http",
3188
+ status: response.status,
3189
+ cofheErrorCode: mapApiErrorCodeToCofheErrorCode(apiErrorCode, fallbackErrorCode),
3190
+ apiErrorCode,
3191
+ errorMessage
3192
+ };
2923
3193
  }
2924
3194
  function throwIfSubmitRetryTimedOut(params) {
2925
3195
  const {
@@ -2931,12 +3201,14 @@ function throwIfSubmitRetryTimedOut(params) {
2931
3201
  overallTimeoutMs,
2932
3202
  thresholdNetworkUrl,
2933
3203
  body,
2934
- attemptIndex
3204
+ attemptIndex,
3205
+ lastKnownErrorMessage
2935
3206
  } = params;
2936
3207
  if (status === 404 && elapsedMs > retry404TimeoutMs) {
2937
3208
  throw new CofheError({
2938
- code: errorCode,
2939
- message: `${operationLabel} submit retried 404 responses without receiving request_id for ${retry404TimeoutMs}ms`,
3209
+ code: "CT_NOT_FOUND" /* CtNotFound */,
3210
+ apiErrorCode: "ct_not_found",
3211
+ message: `${operationLabel} ciphertext not found after retrying for ${retry404TimeoutMs}ms` + (lastKnownErrorMessage ? `: ${lastKnownErrorMessage}` : ""),
2940
3212
  hint: "The ciphertext may not be indexed yet. Increase set404RetryTimeout(...) if the backend is slow to index ciphertexts.",
2941
3213
  context: {
2942
3214
  thresholdNetworkUrl,
@@ -2962,6 +3234,62 @@ function throwIfSubmitRetryTimedOut(params) {
2962
3234
  });
2963
3235
  }
2964
3236
  }
3237
+ function normalizeTnSignature(signature) {
3238
+ if (typeof signature !== "string") {
3239
+ throw new CofheError({
3240
+ code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
3241
+ message: "decrypt response missing signature",
3242
+ context: {
3243
+ signature
3244
+ }
3245
+ });
3246
+ }
3247
+ const trimmed = signature.trim();
3248
+ if (trimmed.length === 0) {
3249
+ throw new CofheError({
3250
+ code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
3251
+ message: "decrypt response returned empty signature"
3252
+ });
3253
+ }
3254
+ const prefixed = trimmed.startsWith("0x") ? trimmed : `0x${trimmed}`;
3255
+ const parsed = viem.parseSignature(prefixed);
3256
+ return viem.serializeSignature(parsed);
3257
+ }
3258
+ function parseDecryptedBytesToBigInt(decrypted) {
3259
+ if (!Array.isArray(decrypted)) {
3260
+ throw new CofheError({
3261
+ code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
3262
+ message: "decrypt response field <decrypted> must be a byte array",
3263
+ context: {
3264
+ decrypted
3265
+ }
3266
+ });
3267
+ }
3268
+ if (decrypted.length === 0) {
3269
+ throw new CofheError({
3270
+ code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
3271
+ message: "decrypt response field <decrypted> was an empty byte array",
3272
+ context: {
3273
+ decrypted
3274
+ }
3275
+ });
3276
+ }
3277
+ let hex = "";
3278
+ for (const b of decrypted) {
3279
+ if (typeof b !== "number" || !Number.isInteger(b) || b < 0 || b > 255) {
3280
+ throw new CofheError({
3281
+ code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
3282
+ message: "decrypt response field <decrypted> contained a non-byte value",
3283
+ context: {
3284
+ badElement: b,
3285
+ decrypted
3286
+ }
3287
+ });
3288
+ }
3289
+ hex += b.toString(16).padStart(2, "0");
3290
+ }
3291
+ return BigInt(`0x${hex}`);
3292
+ }
2965
3293
 
2966
3294
  // core/decrypt/tnSealOutputV2.ts
2967
3295
  var POLL_INTERVAL_MS = 1e3;
@@ -3024,23 +3352,28 @@ function parseCompletedSealOutputResponse(params) {
3024
3352
  }
3025
3353
  return convertSealedData(sealed);
3026
3354
  }
3027
- async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, permission, overallStartTime, retry404TimeoutMs, onPoll) {
3355
+ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, acp, overallStartTime, retry404TimeoutMs, onPoll) {
3028
3356
  const body = {
3029
3357
  ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
3030
3358
  host_chain_id: chainId,
3031
- permit: permission
3359
+ acp
3032
3360
  };
3033
3361
  let attemptIndex = 0;
3362
+ let last404ApiErrorMessage;
3034
3363
  for (; ; ) {
3035
3364
  let response;
3036
3365
  try {
3037
- response = await fetch(`${thresholdNetworkUrl}/v2/sealoutput`, {
3038
- method: "POST",
3039
- headers: {
3040
- "Content-Type": "application/json"
3041
- },
3042
- body: JSON.stringify(body)
3043
- });
3366
+ response = await cofheFetch(
3367
+ `${thresholdNetworkUrl}/v2/sealoutput`,
3368
+ /*op:sealoutput*/
3369
+ {
3370
+ method: "POST",
3371
+ headers: {
3372
+ "Content-Type": "application/json"
3373
+ },
3374
+ body: JSON.stringify(body)
3375
+ }
3376
+ );
3044
3377
  } catch (e) {
3045
3378
  throw new CofheError({
3046
3379
  code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
@@ -3054,16 +3387,19 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, per
3054
3387
  }
3055
3388
  });
3056
3389
  }
3057
- const responseClassification = await classifySubmitResponse({ response });
3390
+ const responseClassification = await classifySubmitResponse({
3391
+ response,
3392
+ fallbackErrorCode: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */
3393
+ });
3058
3394
  if (responseClassification.kind === "fatal-http") {
3059
3395
  throw new CofheError({
3060
- code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
3396
+ code: responseClassification.cofheErrorCode,
3397
+ apiErrorCode: responseClassification.apiErrorCode,
3061
3398
  message: `sealOutput request failed: ${responseClassification.errorMessage}`,
3062
3399
  hint: "Check the threshold network URL and request parameters.",
3063
3400
  context: {
3064
3401
  thresholdNetworkUrl,
3065
- status: response.status,
3066
- statusText: response.statusText,
3402
+ status: responseClassification.status,
3067
3403
  body,
3068
3404
  attemptIndex
3069
3405
  }
@@ -3109,6 +3445,9 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, per
3109
3445
  }
3110
3446
  });
3111
3447
  }
3448
+ if (responseClassification.status === 404) {
3449
+ last404ApiErrorMessage = responseClassification.apiErrorMessage;
3450
+ }
3112
3451
  const elapsedMs = Date.now() - overallStartTime;
3113
3452
  throwIfSubmitRetryTimedOut({
3114
3453
  operationLabel: "sealOutput",
@@ -3119,7 +3458,8 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, per
3119
3458
  overallTimeoutMs: SEAL_OUTPUT_TIMEOUT_MS,
3120
3459
  thresholdNetworkUrl,
3121
3460
  body,
3122
- attemptIndex
3461
+ attemptIndex,
3462
+ lastKnownErrorMessage: last404ApiErrorMessage
3123
3463
  });
3124
3464
  onPoll?.({
3125
3465
  operation: "sealoutput",
@@ -3163,12 +3503,16 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStart
3163
3503
  }
3164
3504
  let response;
3165
3505
  try {
3166
- response = await fetch(`${thresholdNetworkUrl}/v2/sealoutput/${requestId}`, {
3167
- method: "GET",
3168
- headers: {
3169
- "Content-Type": "application/json"
3506
+ response = await cofheFetch(
3507
+ `${thresholdNetworkUrl}/v2/sealoutput/${requestId}`,
3508
+ /*op:sealoutput-poll*/
3509
+ {
3510
+ method: "GET",
3511
+ headers: {
3512
+ "Content-Type": "application/json"
3513
+ }
3170
3514
  }
3171
- });
3515
+ );
3172
3516
  } catch (e) {
3173
3517
  throw new CofheError({
3174
3518
  code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
@@ -3193,15 +3537,10 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStart
3193
3537
  });
3194
3538
  }
3195
3539
  if (!response.ok) {
3196
- let errorMessage = `HTTP ${response.status}`;
3197
- try {
3198
- const errorBody = await response.json();
3199
- errorMessage = errorBody.error_message || errorBody.message || errorMessage;
3200
- } catch {
3201
- errorMessage = response.statusText || errorMessage;
3202
- }
3540
+ const { apiErrorCode, errorMessage } = await parseApiErrorResponseBody(response);
3203
3541
  throw new CofheError({
3204
- code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
3542
+ code: mapApiErrorCodeToCofheErrorCode(apiErrorCode, "SEAL_OUTPUT_FAILED" /* SealOutputFailed */),
3543
+ apiErrorCode,
3205
3544
  message: `sealOutput status poll failed: ${errorMessage}`,
3206
3545
  context: {
3207
3546
  thresholdNetworkUrl,
@@ -3245,7 +3584,7 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStart
3245
3584
  });
3246
3585
  }
3247
3586
  async function tnSealOutputV2(params) {
3248
- const { thresholdNetworkUrl, ctHash, chainId, permission, retry404TimeoutMs, onPoll } = params;
3587
+ const { thresholdNetworkUrl, ctHash, chainId, acp, retry404TimeoutMs, onPoll } = params;
3249
3588
  const normalized404RetryTimeoutMs = normalize404RetryTimeoutMs({
3250
3589
  timeoutMs: retry404TimeoutMs,
3251
3590
  operationLabel: "sealOutput",
@@ -3256,7 +3595,7 @@ async function tnSealOutputV2(params) {
3256
3595
  thresholdNetworkUrl,
3257
3596
  ctHash,
3258
3597
  chainId,
3259
- permission,
3598
+ acp,
3260
3599
  overallStartTime,
3261
3600
  normalized404RetryTimeoutMs,
3262
3601
  onPoll
@@ -3272,8 +3611,8 @@ var DEFAULT_404_RETRY_TIMEOUT_MS2 = 1e4;
3272
3611
  var DecryptForViewBuilder = class extends BaseBuilder {
3273
3612
  ctHash;
3274
3613
  utype;
3275
- permitHash;
3276
- permit;
3614
+ acpHash;
3615
+ acp;
3277
3616
  pollCallback;
3278
3617
  retry404TimeoutMs = DEFAULT_404_RETRY_TIMEOUT_MS2;
3279
3618
  constructor(params) {
@@ -3287,11 +3626,11 @@ var DecryptForViewBuilder = class extends BaseBuilder {
3287
3626
  });
3288
3627
  this.ctHash = params.ctHash;
3289
3628
  this.utype = params.utype;
3290
- this.permitHash = params.permitHash;
3291
- this.permit = params.permit;
3629
+ this.acpHash = params.acpHash;
3630
+ this.acp = params.acp;
3292
3631
  }
3293
3632
  /**
3294
- * @param chainId - Chain to decrypt values from. Used to fetch the threshold network URL and use the correct permit.
3633
+ * @param chainId - Chain to decrypt values from. Used to fetch the threshold network URL and use the correct acp.
3295
3634
  *
3296
3635
  * If not provided, the chainId will be fetched from the connected publicClient.
3297
3636
  *
@@ -3312,7 +3651,7 @@ var DecryptForViewBuilder = class extends BaseBuilder {
3312
3651
  return this.chainId;
3313
3652
  }
3314
3653
  /**
3315
- * @param account - Account to decrypt values from. Used to fetch the correct permit.
3654
+ * @param account - Account to decrypt values from. Used to fetch the correct acp.
3316
3655
  *
3317
3656
  * If not provided, the account will be fetched from the connected walletClient.
3318
3657
  *
@@ -3349,61 +3688,61 @@ var DecryptForViewBuilder = class extends BaseBuilder {
3349
3688
  this.retry404TimeoutMs = timeoutMs;
3350
3689
  return this;
3351
3690
  }
3352
- withPermit(permitOrPermitHash) {
3353
- if (typeof permitOrPermitHash === "string") {
3354
- this.permitHash = permitOrPermitHash;
3355
- this.permit = void 0;
3356
- } else if (permitOrPermitHash === void 0) {
3357
- this.permitHash = void 0;
3358
- this.permit = void 0;
3691
+ withACP(acpOrACPHash) {
3692
+ if (typeof acpOrACPHash === "string") {
3693
+ this.acpHash = acpOrACPHash;
3694
+ this.acp = void 0;
3695
+ } else if (acpOrACPHash === void 0) {
3696
+ this.acpHash = void 0;
3697
+ this.acp = void 0;
3359
3698
  } else {
3360
- this.permit = permitOrPermitHash;
3361
- this.permitHash = void 0;
3699
+ this.acp = acpOrACPHash;
3700
+ this.acpHash = void 0;
3362
3701
  }
3363
3702
  return this;
3364
3703
  }
3365
3704
  /**
3366
- * @param permitHash - Permit hash to decrypt values from. Used to fetch the correct permit.
3705
+ * @param acpHash - ACP hash to decrypt values from. Used to fetch the correct acp.
3367
3706
  *
3368
- * If not provided, the active permit for the chainId and account will be used.
3369
- * If `setPermit()` is called, it will be used regardless of chainId, account, or permitHash.
3707
+ * If not provided, the active acp for the chainId and account will be used.
3708
+ * If `setACP()` is called, it will be used regardless of chainId, account, or acpHash.
3370
3709
  *
3371
3710
  * Example:
3372
3711
  * ```typescript
3373
3712
  * const unsealed = await client.decryptForView(ctHash, utype)
3374
- * .setPermitHash('0x1234567890123456789012345678901234567890')
3713
+ * .setACPHash('0x1234567890123456789012345678901234567890')
3375
3714
  * .execute();
3376
3715
  * ```
3377
3716
  *
3378
3717
  * @returns The chainable DecryptForViewBuilder instance.
3379
3718
  */
3380
- /** @deprecated Use `withPermit(permitHash)` instead. */
3381
- setPermitHash(permitHash) {
3382
- return this.withPermit(permitHash);
3719
+ /** @deprecated Use `withACP(acpHash)` instead. */
3720
+ setACPHash(acpHash) {
3721
+ return this.withACP(acpHash);
3383
3722
  }
3384
- getPermitHash() {
3385
- return this.permitHash;
3723
+ getACPHash() {
3724
+ return this.acpHash;
3386
3725
  }
3387
3726
  /**
3388
- * @param permit - Permit to decrypt values with. If provided, it will be used regardless of chainId, account, or permitHash.
3727
+ * @param acp - ACP to decrypt values with. If provided, it will be used regardless of chainId, account, or acpHash.
3389
3728
  *
3390
- * If not provided, the permit will be determined by chainId, account, and permitHash.
3729
+ * If not provided, the acp will be determined by chainId, account, and acpHash.
3391
3730
  *
3392
3731
  * Example:
3393
3732
  * ```typescript
3394
3733
  * const unsealed = await client.decryptForView(ctHash, utype)
3395
- * .setPermit(permit)
3734
+ * .setACP(acp)
3396
3735
  * .execute();
3397
3736
  * ```
3398
3737
  *
3399
3738
  * @returns The chainable DecryptForViewBuilder instance.
3400
3739
  */
3401
- /** @deprecated Use `withPermit(permit)` instead. */
3402
- setPermit(permit) {
3403
- return this.withPermit(permit);
3740
+ /** @deprecated Use `withACP(acp)` instead. */
3741
+ setACP(acp) {
3742
+ return this.withACP(acp);
3404
3743
  }
3405
- getPermit() {
3406
- return this.permit;
3744
+ getACP() {
3745
+ return this.acp;
3407
3746
  }
3408
3747
  async getThresholdNetworkUrl() {
3409
3748
  this.assertChainId();
@@ -3419,77 +3758,77 @@ var DecryptForViewBuilder = class extends BaseBuilder {
3419
3758
  }
3420
3759
  });
3421
3760
  }
3422
- async getResolvedPermit() {
3423
- if (this.permit)
3424
- return this.permit;
3761
+ async getResolvedACP() {
3762
+ if (this.acp)
3763
+ return this.acp;
3425
3764
  this.assertChainId();
3426
3765
  this.assertAccount();
3427
- if (this.permitHash) {
3428
- const permit2 = await permits.getPermit(this.chainId, this.account, this.permitHash);
3429
- if (!permit2) {
3766
+ if (this.acpHash) {
3767
+ const acp2 = await acps.getACP(this.chainId, this.account, this.acpHash);
3768
+ if (!acp2) {
3430
3769
  throw new CofheError({
3431
- code: "PERMIT_NOT_FOUND" /* PermitNotFound */,
3432
- message: `Permit with hash <${this.permitHash}> not found for account <${this.account}> and chainId <${this.chainId}>`,
3433
- hint: "Ensure the permit exists and is valid.",
3770
+ code: "ACP_NOT_FOUND" /* ACPNotFound */,
3771
+ message: `ACP with hash <${this.acpHash}> not found for account <${this.account}> and chainId <${this.chainId}>`,
3772
+ hint: "Ensure the acp exists and is valid.",
3434
3773
  context: {
3435
3774
  chainId: this.chainId,
3436
3775
  account: this.account,
3437
- permitHash: this.permitHash
3776
+ acpHash: this.acpHash
3438
3777
  }
3439
3778
  });
3440
3779
  }
3441
- return permit2;
3780
+ return acp2;
3442
3781
  }
3443
- const permit = await permits.getActivePermit(this.chainId, this.account);
3444
- if (!permit) {
3782
+ const acp = await acps.getActiveACP(this.chainId, this.account);
3783
+ if (!acp) {
3445
3784
  throw new CofheError({
3446
- code: "PERMIT_NOT_FOUND" /* PermitNotFound */,
3447
- message: `Active permit not found for chainId <${this.chainId}> and account <${this.account}>`,
3448
- hint: "Ensure a permit exists for this account on this chain.",
3785
+ code: "ACP_NOT_FOUND" /* ACPNotFound */,
3786
+ message: `Active acp not found for chainId <${this.chainId}> and account <${this.account}>`,
3787
+ hint: "Ensure an ACP exists for this account on this chain.",
3449
3788
  context: {
3450
3789
  chainId: this.chainId,
3451
3790
  account: this.account
3452
3791
  }
3453
3792
  });
3454
3793
  }
3455
- return permit;
3794
+ return acp;
3456
3795
  }
3457
3796
  /**
3458
3797
  * On hardhat, interact with MockZkVerifier contract instead of CoFHE
3459
3798
  */
3460
- async mocksSealOutput(permit) {
3799
+ async mocksSealOutput(acp) {
3461
3800
  this.assertPublicClient();
3462
3801
  const mocksDecryptDelay = this.config.mocks.decryptDelay;
3463
3802
  if (mocksDecryptDelay > 0)
3464
3803
  await sleep(mocksDecryptDelay);
3465
- return cofheMocksDecryptForView(this.ctHash, this.utype, permit, this.publicClient);
3804
+ return cofheMocksDecryptForView(this.ctHash, this.utype, acp, this.publicClient);
3466
3805
  }
3467
3806
  /**
3468
3807
  * In the production context, perform a true decryption with the CoFHE coprocessor.
3469
3808
  */
3470
- async productionSealOutput(permit) {
3809
+ async productionSealOutput(acp) {
3471
3810
  this.assertChainId();
3472
3811
  this.assertPublicClient();
3473
3812
  const thresholdNetworkUrl = await this.getThresholdNetworkUrl();
3474
- const permission = PermitUtils.getPermission(permit, true);
3813
+ const wireAcp = ACPUtils.getPublic(acp, true);
3475
3814
  const sealed = await tnSealOutputV2({
3476
3815
  ctHash: this.ctHash,
3477
3816
  chainId: this.chainId,
3478
- permission,
3817
+ acp: wireAcp,
3479
3818
  thresholdNetworkUrl,
3480
3819
  retry404TimeoutMs: this.retry404TimeoutMs,
3481
3820
  onPoll: this.pollCallback
3482
3821
  });
3483
- return PermitUtils.unseal(permit, sealed);
3822
+ return ACPUtils.unseal(acp, sealed);
3484
3823
  }
3485
3824
  /**
3486
3825
  * Final step of the decryption process. MUST BE CALLED LAST IN THE CHAIN.
3487
3826
  *
3488
3827
  * This will:
3489
- * - Use a permit based on provided permit OR chainId + account + permitHash
3490
- * - Check permit validity
3491
- * - Call CoFHE `/sealoutput` with the permit, which returns a sealed (encrypted) item
3492
- * - Unseal the sealed item with the permit
3828
+ * - Use an ACP based on provided acp OR chainId + account + acpHash
3829
+ * - Check acp validity
3830
+ * - Call CoFHE `/sealoutput` with the acp, which returns a sealed (encrypted) item
3831
+ * - Unseal the sealed item with the acp
3493
3832
  * - Return the unsealed item
3494
3833
  *
3495
3834
  * Example:
@@ -3497,7 +3836,7 @@ var DecryptForViewBuilder = class extends BaseBuilder {
3497
3836
  * const unsealed = await client.decryptForView(ctHash, utype)
3498
3837
  * .setChainId(11155111) // optional
3499
3838
  * .setAccount('0x123...890') // optional
3500
- * .withPermit() // optional
3839
+ * .withACP() // optional
3501
3840
  * .execute(); // execute
3502
3841
  * ```
3503
3842
  *
@@ -3505,14 +3844,14 @@ var DecryptForViewBuilder = class extends BaseBuilder {
3505
3844
  */
3506
3845
  async execute() {
3507
3846
  this.validateUtypeOrThrow();
3508
- const permit = await this.getResolvedPermit();
3509
- PermitUtils.validate(permit);
3510
- const chainId = permit._signedDomain.chainId;
3847
+ const acp = await this.getResolvedACP();
3848
+ ACPUtils.validate(acp);
3849
+ const chainId = acp._signedDomain.chainId;
3511
3850
  let unsealed;
3512
3851
  if (chainId === hardhat2.id) {
3513
- unsealed = await this.mocksSealOutput(permit);
3852
+ unsealed = await this.mocksSealOutput(acp);
3514
3853
  } else {
3515
- unsealed = await this.productionSealOutput(permit);
3854
+ unsealed = await this.productionSealOutput(acp);
3516
3855
  }
3517
3856
  return convertViaUtype(this.utype, unsealed);
3518
3857
  }
@@ -3520,28 +3859,28 @@ var DecryptForViewBuilder = class extends BaseBuilder {
3520
3859
  var UINT_TYPE_MASK = 0x7fn;
3521
3860
  var TYPE_BYTE_OFFSET = 8n;
3522
3861
  var getEncryptionTypeFromCtHash = (ctHash) => Number(ctHash >> TYPE_BYTE_OFFSET & UINT_TYPE_MASK);
3523
- async function cofheMocksDecryptForTx(ctHash, utype, permit, publicClient) {
3862
+ async function cofheMocksDecryptForTx(ctHash, utype, acp, publicClient) {
3524
3863
  let allowed;
3525
3864
  let error;
3526
3865
  let decryptedValue;
3527
- if (permit !== null) {
3528
- let permission = PermitUtils.getPermission(permit, true);
3866
+ if (acp !== null) {
3867
+ const wireAcp = ACPUtils.getPublic(acp, true);
3529
3868
  const permissionWithBigInts = {
3530
- ...permission,
3531
- expiration: BigInt(permission.expiration),
3532
- validatorId: BigInt(permission.validatorId)
3869
+ ...wireAcp,
3870
+ expiration: BigInt(wireAcp.expiration),
3871
+ revokerData: BigInt(wireAcp.revokerData)
3533
3872
  };
3534
3873
  [allowed, error, decryptedValue] = await publicClient.readContract({
3535
3874
  address: MOCKS_THRESHOLD_NETWORK_ADDRESS,
3536
3875
  abi: MockThresholdNetworkAbi,
3537
- functionName: "decryptForTxWithPermit",
3876
+ functionName: "decryptForTxWithACP",
3538
3877
  args: [BigInt(ctHash), permissionWithBigInts]
3539
3878
  });
3540
3879
  } else {
3541
3880
  [allowed, error, decryptedValue] = await publicClient.readContract({
3542
3881
  address: MOCKS_THRESHOLD_NETWORK_ADDRESS,
3543
3882
  abi: MockThresholdNetworkAbi,
3544
- functionName: "decryptForTxWithoutPermit",
3883
+ functionName: "decryptForTxWithoutACP",
3545
3884
  args: [BigInt(ctHash)]
3546
3885
  });
3547
3886
  }
@@ -3576,62 +3915,6 @@ async function cofheMocksDecryptForTx(ctHash, utype, permit, publicClient) {
3576
3915
  signature
3577
3916
  };
3578
3917
  }
3579
- function normalizeTnSignature(signature) {
3580
- if (typeof signature !== "string") {
3581
- throw new CofheError({
3582
- code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
3583
- message: "decrypt response missing signature",
3584
- context: {
3585
- signature
3586
- }
3587
- });
3588
- }
3589
- const trimmed = signature.trim();
3590
- if (trimmed.length === 0) {
3591
- throw new CofheError({
3592
- code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
3593
- message: "decrypt response returned empty signature"
3594
- });
3595
- }
3596
- const prefixed = trimmed.startsWith("0x") ? trimmed : `0x${trimmed}`;
3597
- const parsed = viem.parseSignature(prefixed);
3598
- return viem.serializeSignature(parsed);
3599
- }
3600
- function parseDecryptedBytesToBigInt(decrypted) {
3601
- if (!Array.isArray(decrypted)) {
3602
- throw new CofheError({
3603
- code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
3604
- message: "decrypt response field <decrypted> must be a byte array",
3605
- context: {
3606
- decrypted
3607
- }
3608
- });
3609
- }
3610
- if (decrypted.length === 0) {
3611
- throw new CofheError({
3612
- code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
3613
- message: "decrypt response field <decrypted> was an empty byte array",
3614
- context: {
3615
- decrypted
3616
- }
3617
- });
3618
- }
3619
- let hex = "";
3620
- for (const b of decrypted) {
3621
- if (typeof b !== "number" || !Number.isInteger(b) || b < 0 || b > 255) {
3622
- throw new CofheError({
3623
- code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
3624
- message: "decrypt response field <decrypted> contained a non-byte value",
3625
- context: {
3626
- badElement: b,
3627
- decrypted
3628
- }
3629
- });
3630
- }
3631
- hex += b.toString(16).padStart(2, "0");
3632
- }
3633
- return BigInt(`0x${hex}`);
3634
- }
3635
3918
 
3636
3919
  // core/decrypt/tnDecryptV2.ts
3637
3920
  var POLL_INTERVAL_MS2 = 1e3;
@@ -3753,25 +4036,30 @@ function assertDecryptStatusResponseV2(value) {
3753
4036
  }
3754
4037
  return value;
3755
4038
  }
3756
- async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, permission, overallStartTime, retry404TimeoutMs, onPoll) {
4039
+ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, acp, overallStartTime, retry404TimeoutMs, onPoll) {
3757
4040
  const body = {
3758
4041
  ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
3759
4042
  host_chain_id: chainId
3760
4043
  };
3761
- if (permission) {
3762
- body.permit = permission;
4044
+ if (acp) {
4045
+ body.acp = acp;
3763
4046
  }
3764
4047
  let attemptIndex = 0;
4048
+ let last404ApiErrorMessage;
3765
4049
  for (; ; ) {
3766
4050
  let response;
3767
4051
  try {
3768
- response = await fetch(`${thresholdNetworkUrl}/v2/decrypt`, {
3769
- method: "POST",
3770
- headers: {
3771
- "Content-Type": "application/json"
3772
- },
3773
- body: JSON.stringify(body)
3774
- });
4052
+ response = await cofheFetch(
4053
+ `${thresholdNetworkUrl}/v2/decrypt`,
4054
+ /*op:decrypt*/
4055
+ {
4056
+ method: "POST",
4057
+ headers: {
4058
+ "Content-Type": "application/json"
4059
+ },
4060
+ body: JSON.stringify(body)
4061
+ }
4062
+ );
3775
4063
  } catch (e) {
3776
4064
  throw new CofheError({
3777
4065
  code: "DECRYPT_FAILED" /* DecryptFailed */,
@@ -3785,16 +4073,19 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, perm
3785
4073
  }
3786
4074
  });
3787
4075
  }
3788
- const responseClassification = await classifySubmitResponse({ response });
4076
+ const responseClassification = await classifySubmitResponse({
4077
+ response,
4078
+ fallbackErrorCode: "DECRYPT_FAILED" /* DecryptFailed */
4079
+ });
3789
4080
  if (responseClassification.kind === "fatal-http") {
3790
4081
  throw new CofheError({
3791
- code: "DECRYPT_FAILED" /* DecryptFailed */,
4082
+ code: responseClassification.cofheErrorCode,
4083
+ apiErrorCode: responseClassification.apiErrorCode,
3792
4084
  message: `decrypt request failed: ${responseClassification.errorMessage}`,
3793
4085
  hint: "Check the threshold network URL and request parameters.",
3794
4086
  context: {
3795
4087
  thresholdNetworkUrl,
3796
- status: response.status,
3797
- statusText: response.statusText,
4088
+ status: responseClassification.status,
3798
4089
  body,
3799
4090
  attemptIndex
3800
4091
  }
@@ -3842,6 +4133,9 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, perm
3842
4133
  }
3843
4134
  });
3844
4135
  }
4136
+ if (responseClassification.status === 404) {
4137
+ last404ApiErrorMessage = responseClassification.apiErrorMessage;
4138
+ }
3845
4139
  const elapsedMs = Date.now() - overallStartTime;
3846
4140
  throwIfSubmitRetryTimedOut({
3847
4141
  operationLabel: "decrypt",
@@ -3852,7 +4146,8 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, perm
3852
4146
  overallTimeoutMs: DECRYPT_TIMEOUT_MS,
3853
4147
  thresholdNetworkUrl,
3854
4148
  body,
3855
- attemptIndex
4149
+ attemptIndex,
4150
+ lastKnownErrorMessage: last404ApiErrorMessage
3856
4151
  });
3857
4152
  onPoll?.({
3858
4153
  operation: "decrypt",
@@ -3896,12 +4191,16 @@ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartT
3896
4191
  }
3897
4192
  let response;
3898
4193
  try {
3899
- response = await fetch(`${thresholdNetworkUrl}/v2/decrypt/${requestId}`, {
3900
- method: "GET",
3901
- headers: {
3902
- "Content-Type": "application/json"
4194
+ response = await cofheFetch(
4195
+ `${thresholdNetworkUrl}/v2/decrypt/${requestId}`,
4196
+ /*op:decrypt-poll*/
4197
+ {
4198
+ method: "GET",
4199
+ headers: {
4200
+ "Content-Type": "application/json"
4201
+ }
3903
4202
  }
3904
- });
4203
+ );
3905
4204
  } catch (e) {
3906
4205
  throw new CofheError({
3907
4206
  code: "DECRYPT_FAILED" /* DecryptFailed */,
@@ -3926,17 +4225,10 @@ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartT
3926
4225
  });
3927
4226
  }
3928
4227
  if (!response.ok) {
3929
- let errorMessage = `HTTP ${response.status}`;
3930
- try {
3931
- const errorBody = await response.json();
3932
- const maybeMessage = errorBody.error_message || errorBody.message;
3933
- if (typeof maybeMessage === "string" && maybeMessage.length > 0)
3934
- errorMessage = maybeMessage;
3935
- } catch {
3936
- errorMessage = response.statusText || errorMessage;
3937
- }
4228
+ const { apiErrorCode, errorMessage } = await parseApiErrorResponseBody(response);
3938
4229
  throw new CofheError({
3939
- code: "DECRYPT_FAILED" /* DecryptFailed */,
4230
+ code: mapApiErrorCodeToCofheErrorCode(apiErrorCode, "DECRYPT_FAILED" /* DecryptFailed */),
4231
+ apiErrorCode,
3940
4232
  message: `decrypt status poll failed: ${errorMessage}`,
3941
4233
  context: {
3942
4234
  thresholdNetworkUrl,
@@ -3981,7 +4273,7 @@ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartT
3981
4273
  });
3982
4274
  }
3983
4275
  async function tnDecryptV2(params) {
3984
- const { thresholdNetworkUrl, ctHash, chainId, permission, retry404TimeoutMs, onPoll } = params;
4276
+ const { thresholdNetworkUrl, ctHash, chainId, acp, retry404TimeoutMs, onPoll } = params;
3985
4277
  const normalized404RetryTimeoutMs = normalize404RetryTimeoutMs({
3986
4278
  timeoutMs: retry404TimeoutMs,
3987
4279
  operationLabel: "decrypt",
@@ -3992,7 +4284,7 @@ async function tnDecryptV2(params) {
3992
4284
  thresholdNetworkUrl,
3993
4285
  ctHash,
3994
4286
  chainId,
3995
- permission,
4287
+ acp,
3996
4288
  overallStartTime,
3997
4289
  normalized404RetryTimeoutMs,
3998
4290
  onPoll
@@ -4007,9 +4299,9 @@ async function tnDecryptV2(params) {
4007
4299
  var DEFAULT_404_RETRY_TIMEOUT_MS3 = 1e4;
4008
4300
  var DecryptForTxBuilder = class extends BaseBuilder {
4009
4301
  ctHash;
4010
- permitHash;
4011
- permit;
4012
- permitSelection = "unset";
4302
+ acpHash;
4303
+ acp;
4304
+ acpSelection = "unset";
4013
4305
  pollCallback;
4014
4306
  retry404TimeoutMs = DEFAULT_404_RETRY_TIMEOUT_MS3;
4015
4307
  constructor(params) {
@@ -4054,137 +4346,137 @@ var DecryptForTxBuilder = class extends BaseBuilder {
4054
4346
  this.retry404TimeoutMs = timeoutMs;
4055
4347
  return this;
4056
4348
  }
4057
- withPermit(permitOrPermitHash) {
4058
- if (this.permitSelection === "with-permit") {
4349
+ withACP(acpOrACPHash) {
4350
+ if (this.acpSelection === "with-acp") {
4059
4351
  throw new CofheError({
4060
4352
  code: "INTERNAL_ERROR" /* InternalError */,
4061
- message: "decryptForTx: withPermit() can only be selected once.",
4062
- hint: "Choose the permit mode once. If you need a different permit, start a new decryptForTx() builder chain."
4353
+ message: "decryptForTx: withACP() can only be selected once.",
4354
+ hint: "Choose the acp mode once. If you need a different acp, start a new decryptForTx() builder chain."
4063
4355
  });
4064
4356
  }
4065
- if (this.permitSelection === "without-permit") {
4357
+ if (this.acpSelection === "without-acp") {
4066
4358
  throw new CofheError({
4067
4359
  code: "INTERNAL_ERROR" /* InternalError */,
4068
- message: "decryptForTx: cannot call withPermit() after withoutPermit() has been selected.",
4069
- hint: "Choose exactly one permit mode: either call .withPermit(...) or .withoutPermit(), but not both."
4360
+ message: "decryptForTx: cannot call withACP() after withoutACP() has been selected.",
4361
+ hint: "Choose exactly one acp mode: either call .withACP(...) or .withoutACP(), but not both."
4070
4362
  });
4071
4363
  }
4072
- this.permitSelection = "with-permit";
4073
- if (typeof permitOrPermitHash === "string") {
4074
- this.permitHash = permitOrPermitHash;
4075
- this.permit = void 0;
4076
- } else if (permitOrPermitHash === void 0) {
4077
- this.permitHash = void 0;
4078
- this.permit = void 0;
4364
+ this.acpSelection = "with-acp";
4365
+ if (typeof acpOrACPHash === "string") {
4366
+ this.acpHash = acpOrACPHash;
4367
+ this.acp = void 0;
4368
+ } else if (acpOrACPHash === void 0) {
4369
+ this.acpHash = void 0;
4370
+ this.acp = void 0;
4079
4371
  } else {
4080
- this.permit = permitOrPermitHash;
4081
- this.permitHash = void 0;
4372
+ this.acp = acpOrACPHash;
4373
+ this.acpHash = void 0;
4082
4374
  }
4083
4375
  return this;
4084
4376
  }
4085
4377
  /**
4086
- * Select "no permit" mode.
4378
+ * Select "no acp" mode.
4087
4379
  *
4088
- * This uses global allowance (no permit required) and sends an empty permission payload to `/decrypt`.
4380
+ * This uses global allowance (no acp required) and sends an empty permission payload to `/decrypt`.
4089
4381
  */
4090
- withoutPermit() {
4091
- if (this.permitSelection === "without-permit") {
4382
+ withoutACP() {
4383
+ if (this.acpSelection === "without-acp") {
4092
4384
  throw new CofheError({
4093
4385
  code: "INTERNAL_ERROR" /* InternalError */,
4094
- message: "decryptForTx: withoutPermit() can only be selected once.",
4095
- hint: "Choose the permit mode once. If you need a different mode, start a new decryptForTx() builder chain."
4386
+ message: "decryptForTx: withoutACP() can only be selected once.",
4387
+ hint: "Choose the acp mode once. If you need a different mode, start a new decryptForTx() builder chain."
4096
4388
  });
4097
4389
  }
4098
- if (this.permitSelection === "with-permit") {
4390
+ if (this.acpSelection === "with-acp") {
4099
4391
  throw new CofheError({
4100
4392
  code: "INTERNAL_ERROR" /* InternalError */,
4101
- message: "decryptForTx: cannot call withoutPermit() after withPermit() has been selected.",
4102
- hint: "Choose exactly one permit mode: either call .withPermit(...) or .withoutPermit(), but not both."
4393
+ message: "decryptForTx: cannot call withoutACP() after withACP() has been selected.",
4394
+ hint: "Choose exactly one acp mode: either call .withACP(...) or .withoutACP(), but not both."
4103
4395
  });
4104
4396
  }
4105
- this.permitSelection = "without-permit";
4106
- this.permitHash = void 0;
4107
- this.permit = void 0;
4397
+ this.acpSelection = "without-acp";
4398
+ this.acpHash = void 0;
4399
+ this.acp = void 0;
4108
4400
  return this;
4109
4401
  }
4110
- getPermit() {
4111
- return this.permit;
4402
+ getACP() {
4403
+ return this.acp;
4112
4404
  }
4113
- getPermitHash() {
4114
- return this.permitHash;
4405
+ getACPHash() {
4406
+ return this.acpHash;
4115
4407
  }
4116
4408
  async getThresholdNetworkUrl() {
4117
4409
  this.assertChainId();
4118
4410
  return getThresholdNetworkUrlOrThrow(this.config, this.chainId);
4119
4411
  }
4120
- async getResolvedPermit() {
4121
- if (this.permitSelection === "unset") {
4412
+ async getResolvedACP() {
4413
+ if (this.acpSelection === "unset") {
4122
4414
  throw new CofheError({
4123
4415
  code: "INTERNAL_ERROR" /* InternalError */,
4124
- message: "decryptForTx: missing permit selection; call withPermit(...) or withoutPermit() before execute().",
4125
- hint: "Call .withPermit() to use the active permit, or .withoutPermit() for global allowance."
4416
+ message: "decryptForTx: missing acp selection; call withACP(...) or withoutACP() before execute().",
4417
+ hint: "Call .withACP() to use the active acp, or .withoutACP() for global allowance."
4126
4418
  });
4127
4419
  }
4128
- if (this.permitSelection === "without-permit") {
4420
+ if (this.acpSelection === "without-acp") {
4129
4421
  return null;
4130
4422
  }
4131
- if (this.permit)
4132
- return this.permit;
4423
+ if (this.acp)
4424
+ return this.acp;
4133
4425
  this.assertChainId();
4134
4426
  this.assertAccount();
4135
- if (this.permitHash) {
4136
- const permit2 = await permits.getPermit(this.chainId, this.account, this.permitHash);
4137
- if (!permit2) {
4427
+ if (this.acpHash) {
4428
+ const acp2 = await acps.getACP(this.chainId, this.account, this.acpHash);
4429
+ if (!acp2) {
4138
4430
  throw new CofheError({
4139
- code: "PERMIT_NOT_FOUND" /* PermitNotFound */,
4140
- message: `Permit with hash <${this.permitHash}> not found for account <${this.account}> and chainId <${this.chainId}>`,
4141
- hint: "Ensure the permit exists and is valid.",
4431
+ code: "ACP_NOT_FOUND" /* ACPNotFound */,
4432
+ message: `ACP with hash <${this.acpHash}> not found for account <${this.account}> and chainId <${this.chainId}>`,
4433
+ hint: "Ensure the acp exists and is valid.",
4142
4434
  context: {
4143
4435
  chainId: this.chainId,
4144
4436
  account: this.account,
4145
- permitHash: this.permitHash
4437
+ acpHash: this.acpHash
4146
4438
  }
4147
4439
  });
4148
4440
  }
4149
- return permit2;
4441
+ return acp2;
4150
4442
  }
4151
- const permit = await permits.getActivePermit(this.chainId, this.account);
4152
- if (!permit) {
4443
+ const acp = await acps.getActiveACP(this.chainId, this.account);
4444
+ if (!acp) {
4153
4445
  throw new CofheError({
4154
- code: "PERMIT_NOT_FOUND" /* PermitNotFound */,
4155
- message: `Active permit not found for chainId <${this.chainId}> and account <${this.account}>`,
4156
- hint: "Create a permit (e.g. client.permits.createSelf(...)) and/or set it active (client.permits.selectActivePermit(hash)).",
4446
+ code: "ACP_NOT_FOUND" /* ACPNotFound */,
4447
+ message: `Active acp not found for chainId <${this.chainId}> and account <${this.account}>`,
4448
+ hint: "Create an ACP (e.g. client.acp.createSelf(...)) and/or set it active (client.acp.selectActiveACP(hash)).",
4157
4449
  context: {
4158
4450
  chainId: this.chainId,
4159
4451
  account: this.account
4160
4452
  }
4161
4453
  });
4162
4454
  }
4163
- return permit;
4455
+ return acp;
4164
4456
  }
4165
4457
  /**
4166
4458
  * On hardhat, interact with MockThresholdNetwork contract
4167
4459
  */
4168
- async mocksDecryptForTx(permit) {
4460
+ async mocksDecryptForTx(acp) {
4169
4461
  this.assertPublicClient();
4170
4462
  const delay = this.config.mocks.decryptDelay;
4171
4463
  if (delay > 0)
4172
4464
  await sleep(delay);
4173
- const result = await cofheMocksDecryptForTx(this.ctHash, 0, permit, this.publicClient);
4465
+ const result = await cofheMocksDecryptForTx(this.ctHash, 0, acp, this.publicClient);
4174
4466
  return result;
4175
4467
  }
4176
4468
  /**
4177
4469
  * In the production context, perform a true decryption with the CoFHE coprocessor.
4178
4470
  */
4179
- async productionDecryptForTx(permit) {
4471
+ async productionDecryptForTx(acp) {
4180
4472
  this.assertChainId();
4181
4473
  this.assertPublicClient();
4182
4474
  const thresholdNetworkUrl = await this.getThresholdNetworkUrl();
4183
- const permission = permit ? PermitUtils.getPermission(permit, true) : null;
4475
+ const wireAcp = acp ? ACPUtils.getPublic(acp, true) : null;
4184
4476
  const { decryptedValue, signature } = await tnDecryptV2({
4185
4477
  ctHash: this.ctHash,
4186
4478
  chainId: this.chainId,
4187
- permission,
4479
+ acp: wireAcp,
4188
4480
  thresholdNetworkUrl,
4189
4481
  retry404TimeoutMs: this.retry404TimeoutMs,
4190
4482
  onPoll: this.pollCallback
@@ -4198,19 +4490,19 @@ var DecryptForTxBuilder = class extends BaseBuilder {
4198
4490
  /**
4199
4491
  * Final step of the decryptForTx process. MUST BE CALLED LAST IN THE CHAIN.
4200
4492
  *
4201
- * You must explicitly choose one permit mode before calling `execute()`:
4202
- * - `withPermit(permit)` / `withPermit(permitHash)` / `withPermit()` (active permit)
4203
- * - `withoutPermit()` (global allowance)
4493
+ * You must explicitly choose one acp mode before calling `execute()`:
4494
+ * - `withACP(acp)` / `withACP(acpHash)` / `withACP()` (active acp)
4495
+ * - `withoutACP()` (global allowance)
4204
4496
  */
4205
4497
  async execute() {
4206
- const permit = await this.getResolvedPermit();
4207
- if (permit !== null) {
4208
- PermitUtils.validate(permit);
4209
- const chainId = permit._signedDomain.chainId;
4498
+ const acp = await this.getResolvedACP();
4499
+ if (acp !== null) {
4500
+ ACPUtils.validate(acp);
4501
+ const chainId = acp._signedDomain.chainId;
4210
4502
  if (chainId === hardhat2.id) {
4211
- return await this.mocksDecryptForTx(permit);
4503
+ return await this.mocksDecryptForTx(acp);
4212
4504
  } else {
4213
- return await this.productionDecryptForTx(permit);
4505
+ return await this.productionDecryptForTx(acp);
4214
4506
  }
4215
4507
  } else {
4216
4508
  if (!this.chainId) {
@@ -4273,6 +4565,21 @@ function createCofheClientBase(opts) {
4273
4565
  const updateConnectState = (partial) => {
4274
4566
  connectStore.setState((state) => ({ ...state, ...partial }));
4275
4567
  };
4568
+ const _resolveSharingRegistry = async (publicClient, chainId) => {
4569
+ const configured = opts.config.acp?.sharingRegistry?.[chainId];
4570
+ if (configured != null)
4571
+ return configured;
4572
+ const registry = (await acps.getAclServedAddresses(publicClient, chainId)).shareRegistry;
4573
+ if (registry == null) {
4574
+ throw new CofheError({
4575
+ code: "MISSING_CONFIG" /* MissingConfig */,
4576
+ message: `No ACP share registry available for chainId <${chainId}>`,
4577
+ 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.",
4578
+ context: { chainId }
4579
+ });
4580
+ }
4581
+ return registry;
4582
+ };
4276
4583
  const _requireConnected = () => {
4277
4584
  const state = connectStore.getState();
4278
4585
  const notConnected = !state.connected || !state.account || !state.chainId || !state.publicClient || !state.walletClient;
@@ -4395,74 +4702,147 @@ function createCofheClientBase(opts) {
4395
4702
  }
4396
4703
  return { chainId: _chainId, account: _account };
4397
4704
  };
4398
- const clientPermits = {
4705
+ const clientACPs = {
4399
4706
  // Pass through store access
4400
- getSnapshot: permits.getSnapshot,
4401
- subscribe: permits.subscribe,
4707
+ getSnapshot: acps.getSnapshot,
4708
+ subscribe: acps.subscribe,
4402
4709
  // Creation methods (require connection)
4403
4710
  createSelf: async (options, clients) => {
4404
4711
  _requireConnected();
4405
4712
  const { publicClient, walletClient } = clients ?? connectStore.getState();
4406
- return permits.createSelf(options, publicClient, walletClient);
4713
+ const chainId = await publicClient.getChainId();
4714
+ return acps.createSelf(
4715
+ await acps.applyACPDefaultsFromChain(options, opts.config.acp, publicClient, chainId),
4716
+ publicClient,
4717
+ walletClient
4718
+ );
4407
4719
  },
4408
4720
  createSharing: async (options, clients) => {
4409
4721
  _requireConnected();
4410
4722
  const { publicClient, walletClient } = clients ?? connectStore.getState();
4411
- return permits.createSharing(options, publicClient, walletClient);
4723
+ const chainId = await publicClient.getChainId();
4724
+ return acps.createSharing(
4725
+ await acps.applyACPDefaultsFromChain(options, opts.config.acp, publicClient, chainId),
4726
+ publicClient,
4727
+ walletClient
4728
+ );
4412
4729
  },
4413
4730
  importShared: async (options, clients) => {
4414
4731
  _requireConnected();
4415
4732
  const { publicClient, walletClient } = clients ?? connectStore.getState();
4416
- return permits.importShared(options, publicClient, walletClient);
4733
+ return acps.importShared(options, publicClient, walletClient);
4417
4734
  },
4418
4735
  // Get or create methods (require connection)
4419
- getOrCreateSelfPermit: async (chainId, account, options) => {
4736
+ getOrCreateSelfACP: async (chainId, account, options) => {
4420
4737
  _requireConnected();
4421
4738
  const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
4422
4739
  const { publicClient, walletClient } = connectStore.getState();
4423
- return permits.getOrCreateSelfPermit(publicClient, walletClient, _chainId, _account, options);
4740
+ const optionsWithDefaults = await acps.applyACPDefaultsFromChain(
4741
+ options ?? { issuer: _account, name: "Autogenerated Self ACP" },
4742
+ opts.config.acp,
4743
+ publicClient,
4744
+ _chainId
4745
+ );
4746
+ return acps.getOrCreateSelfACP(publicClient, walletClient, _chainId, _account, optionsWithDefaults);
4424
4747
  },
4425
- getOrCreateSharingPermit: async (options, chainId, account) => {
4748
+ getOrCreateSharingACP: async (options, chainId, account) => {
4426
4749
  _requireConnected();
4427
4750
  const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
4428
4751
  const { publicClient, walletClient } = connectStore.getState();
4429
- return permits.getOrCreateSharingPermit(publicClient, walletClient, options, _chainId, _account);
4752
+ return acps.getOrCreateSharingACP(
4753
+ publicClient,
4754
+ walletClient,
4755
+ await acps.applyACPDefaultsFromChain(options, opts.config.acp, publicClient, _chainId),
4756
+ _chainId,
4757
+ _account
4758
+ );
4759
+ },
4760
+ // Revocation (require connection)
4761
+ revokeACP: async (acp) => {
4762
+ _requireConnected();
4763
+ const { walletClient } = connectStore.getState();
4764
+ return acps.revokeACP(acp, walletClient);
4765
+ },
4766
+ revokeAllACPs: async (revokerContract) => {
4767
+ _requireConnected();
4768
+ const { publicClient, walletClient } = connectStore.getState();
4769
+ return acps.revokeAllACPs(walletClient, publicClient, revokerContract);
4770
+ },
4771
+ isACPRevoked: async (acp) => {
4772
+ _requireConnected();
4773
+ const { publicClient } = connectStore.getState();
4774
+ return acps.isACPRevoked(acp, publicClient);
4775
+ },
4776
+ // On-chain sharing (require connection + config.acp.sharingRegistry)
4777
+ shareOnChain: async (acp) => {
4778
+ _requireConnected();
4779
+ const { publicClient, walletClient } = connectStore.getState();
4780
+ const chainId = await publicClient.getChainId();
4781
+ const sharingRegistry = await _resolveSharingRegistry(publicClient, chainId);
4782
+ return acps.shareOnChain(acp, walletClient, sharingRegistry);
4783
+ },
4784
+ getIncomingShares: async () => {
4785
+ _requireConnected();
4786
+ const { publicClient, walletClient } = connectStore.getState();
4787
+ const chainId = await publicClient.getChainId();
4788
+ const account = walletClient.account.address;
4789
+ const sharingRegistry = await _resolveSharingRegistry(publicClient, chainId);
4790
+ return acps.getIncomingShares(publicClient, sharingRegistry, account);
4791
+ },
4792
+ importFromChain: async (share) => {
4793
+ _requireConnected();
4794
+ const { publicClient, walletClient } = connectStore.getState();
4795
+ return acps.importFromChain(share, publicClient, walletClient);
4796
+ },
4797
+ dismissShare: async (shareId) => {
4798
+ _requireConnected();
4799
+ const { publicClient, walletClient } = connectStore.getState();
4800
+ const chainId = await publicClient.getChainId();
4801
+ const sharingRegistry = await _resolveSharingRegistry(publicClient, chainId);
4802
+ return acps.removeShareOnChain(shareId, walletClient, sharingRegistry);
4803
+ },
4804
+ cancelShare: async (shareId) => {
4805
+ _requireConnected();
4806
+ const { publicClient, walletClient } = connectStore.getState();
4807
+ const chainId = await publicClient.getChainId();
4808
+ const sharingRegistry = await _resolveSharingRegistry(publicClient, chainId);
4809
+ return acps.removeShareOnChain(shareId, walletClient, sharingRegistry);
4430
4810
  },
4431
4811
  // Retrieval methods (auto-fill chainId/account)
4432
- getPermit: (hash, chainId, account) => {
4812
+ getACP: (hash, chainId, account) => {
4433
4813
  const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
4434
- return permits.getPermit(_chainId, _account, hash);
4814
+ return acps.getACP(_chainId, _account, hash);
4435
4815
  },
4436
- getPermits: (chainId, account) => {
4816
+ getACPs: (chainId, account) => {
4437
4817
  const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
4438
- return permits.getPermits(_chainId, _account);
4818
+ return acps.getACPs(_chainId, _account);
4439
4819
  },
4440
- getActivePermit: (chainId, account) => {
4820
+ getActiveACP: (chainId, account) => {
4441
4821
  const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
4442
- return permits.getActivePermit(_chainId, _account);
4822
+ return acps.getActiveACP(_chainId, _account);
4443
4823
  },
4444
- getActivePermitHash: (chainId, account) => {
4824
+ getActiveACPHash: (chainId, account) => {
4445
4825
  const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
4446
- return permits.getActivePermitHash(_chainId, _account);
4826
+ return acps.getActiveACPHash(_chainId, _account);
4447
4827
  },
4448
4828
  // Mutation methods (auto-fill chainId/account)
4449
- selectActivePermit: (hash, chainId, account) => {
4829
+ selectActiveACP: (hash, chainId, account) => {
4450
4830
  const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
4451
- return permits.selectActivePermit(_chainId, _account, hash);
4831
+ return acps.selectActiveACP(_chainId, _account, hash);
4452
4832
  },
4453
- removePermit: async (hash, chainId, account) => {
4833
+ removeACP: async (hash, chainId, account) => {
4454
4834
  const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
4455
- return permits.removePermit(_chainId, _account, hash);
4835
+ return acps.removeACP(_chainId, _account, hash);
4456
4836
  },
4457
- removeActivePermit: async (chainId, account) => {
4837
+ removeActiveACP: async (chainId, account) => {
4458
4838
  const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
4459
- return permits.removeActivePermit(_chainId, _account);
4839
+ return acps.removeActiveACP(_chainId, _account);
4460
4840
  },
4461
4841
  // Utils (no context needed)
4462
- getHash: permits.getHash,
4463
- export: permits.export,
4464
- serialize: permits.serialize,
4465
- deserialize: permits.deserialize
4842
+ getHash: acps.getHash,
4843
+ export: acps.export,
4844
+ serialize: acps.serialize,
4845
+ deserialize: acps.deserialize
4466
4846
  };
4467
4847
  return {
4468
4848
  // Zustand reactive accessors (don't export store directly to prevent mutation)
@@ -4490,7 +4870,7 @@ function createCofheClientBase(opts) {
4490
4870
  decryptHandle: decryptForView,
4491
4871
  decryptForTx,
4492
4872
  verifyDecryptResult: verifyDecryptResult2,
4493
- permits: clientPermits
4873
+ acp: clientACPs
4494
4874
  // Add SDK-specific methods below that require connection
4495
4875
  // Example:
4496
4876
  // async encryptData(data: unknown) {