@cofhe/sdk 0.6.1 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/CHANGELOG.md +45 -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/decrypt/MockThresholdNetworkAbi.ts +20 -11
  27. package/core/decrypt/apiError.ts +104 -0
  28. package/core/decrypt/cofheMocksDecryptForTx.ts +11 -11
  29. package/core/decrypt/cofheMocksDecryptForView.ts +7 -7
  30. package/core/decrypt/decryptForTxBuilder.ts +102 -102
  31. package/core/decrypt/decryptForViewBuilder.ts +90 -90
  32. package/core/decrypt/submitRetry.ts +38 -30
  33. package/core/decrypt/tnDecryptV1.ts +5 -5
  34. package/core/decrypt/tnDecryptV2.ts +25 -21
  35. package/core/decrypt/tnSealOutputV1.ts +4 -3
  36. package/core/decrypt/tnSealOutputV2.ts +24 -18
  37. package/core/encrypt/cofheMocksZkVerifySign.ts +59 -74
  38. package/core/encrypt/encryptInputsBuilder.ts +86 -52
  39. package/core/encrypt/zkPackProveVerify.ts +25 -18
  40. package/core/error.ts +34 -6
  41. package/core/index.ts +4 -14
  42. package/core/test/acpDefaults.test.ts +52 -0
  43. package/core/test/acps.test.ts +596 -0
  44. package/core/test/apiError.test.ts +130 -0
  45. package/core/test/client.test.ts +22 -19
  46. package/core/test/config.test.ts +25 -5
  47. package/core/test/decrypt.test.ts +40 -35
  48. package/core/test/decryptBuilders.test.ts +68 -68
  49. package/core/test/decryptErrorCodes.test.ts +217 -0
  50. package/core/test/encryptInputsBuilder.test.ts +72 -41
  51. package/core/test/pollCallbacks.test.ts +89 -18
  52. package/core/test/stagingRedirect.ts +18 -0
  53. package/core/test/submitRetry.test.ts +182 -0
  54. package/core/types.ts +9 -69
  55. package/dist/acp-Wi6isVQI.d.cts +407 -0
  56. package/dist/acp-Wi6isVQI.d.ts +407 -0
  57. package/dist/acps.cjs +1081 -0
  58. package/dist/acps.d.cts +480 -0
  59. package/dist/acps.d.ts +480 -0
  60. package/dist/acps.js +2 -0
  61. package/dist/chains.cjs +14 -1
  62. package/dist/chains.d.cts +30 -1
  63. package/dist/chains.d.ts +30 -1
  64. package/dist/chains.js +1 -1
  65. package/dist/{chunk-NOC3PYB7.js → chunk-43USWPEH.js} +930 -580
  66. package/dist/{chunk-MTRAXQXC.js → chunk-N6IDQRRU.js} +14 -2
  67. package/dist/chunk-Q7CBWGQX.js +1029 -0
  68. package/dist/{clientTypes-CyUvRRzA.d.ts → clientTypes-BN3nbzYM.d.ts} +342 -165
  69. package/dist/{clientTypes-BDy1qIBu.d.cts → clientTypes-CYZjFznO.d.cts} +342 -165
  70. package/dist/core.cjs +1358 -1002
  71. package/dist/core.d.cts +31 -9
  72. package/dist/core.d.ts +31 -9
  73. package/dist/core.js +3 -3
  74. package/dist/node.cjs +1293 -952
  75. package/dist/node.d.cts +2 -2
  76. package/dist/node.d.ts +2 -2
  77. package/dist/node.js +3 -3
  78. package/dist/web.cjs +1293 -952
  79. package/dist/web.d.cts +2 -2
  80. package/dist/web.d.ts +2 -2
  81. package/dist/web.js +3 -3
  82. package/node/test/inherited.test.ts +75 -65
  83. package/node/test/tfheinit.test.ts +23 -8
  84. package/package.json +6 -6
  85. package/web/test/client.web.test.ts +5 -1
  86. package/web/test/inherited.web.test.ts +75 -65
  87. package/web/test/tfheinit.web.test.ts +14 -5
  88. package/web/test/worker.config.web.test.ts +38 -23
  89. package/web/test/worker.output.web.test.ts +25 -24
  90. package/core/encrypt/encryptUtils.ts +0 -67
  91. package/core/permits.ts +0 -216
  92. package/core/test/permits.test.ts +0 -596
  93. package/dist/chunk-VB62WYPL.js +0 -978
  94. package/dist/permit-DnVMDT5h.d.cts +0 -376
  95. package/dist/permit-DnVMDT5h.d.ts +0 -376
  96. package/dist/permits.cjs +0 -1026
  97. package/dist/permits.d.cts +0 -353
  98. package/dist/permits.d.ts +0 -353
  99. package/dist/permits.js +0 -2
  100. package/permits/index.ts +0 -68
  101. package/permits/permit.ts +0 -385
  102. package/permits/sealing.ts +0 -131
  103. package/permits/signature.ts +0 -79
  104. package/permits/store.ts +0 -157
  105. package/permits/test/localstorage.test.ts +0 -113
  106. package/permits/test/permit.test.ts +0 -557
  107. package/permits/test/sealing.test.ts +0 -84
  108. package/permits/test/store.test.ts +0 -88
  109. package/permits/test/validation.test.ts +0 -361
  110. package/permits/test-utils.ts +0 -28
  111. package/permits/types.ts +0 -204
  112. package/permits/validation.ts +0 -327
  113. /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) => {
2522
+ const chainId = await publicClient.getChainId();
2523
+ const account = walletClient.account.address;
2524
+ acpStore.setACP(chainId, account, acp);
2525
+ };
2526
+ var storeActiveACP = async (acp, publicClient, walletClient) => {
2527
+ await storeACP(acp, publicClient, walletClient);
2550
2528
  const chainId = await publicClient.getChainId();
2551
2529
  const account = walletClient.account.address;
2552
- permitStore.setPermit(chainId, account, permit);
2553
- permitStore.setActivePermitHash(chainId, account, permit.hash);
2530
+ acpStore.setActiveACPHash(chainId, account, acp.hash);
2554
2531
  };
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;
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" && PermitUtils.isValid(activePermit).valid) {
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" && PermitUtils.isValid(activePermit).valid) {
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,7 +3065,7 @@ 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
  }
@@ -2896,11 +3101,61 @@ function computeMinuteRampPollIntervalMs(elapsedMs, params) {
2896
3101
  return Math.min(params.maxIntervalMs, Math.max(params.minIntervalMs, intervalMs));
2897
3102
  }
2898
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
+
2899
3157
  // core/decrypt/submitRetry.ts
2900
3158
  var DEFAULT_404_RETRY_TIMEOUT_MS = 1e4;
2901
- function isRetryableSubmitStatus(status) {
2902
- return status === 204 || status === 404;
2903
- }
2904
3159
  function normalize404RetryTimeoutMs(params) {
2905
3160
  const { timeoutMs, operationLabel, errorCode } = params;
2906
3161
  if (timeoutMs === void 0)
@@ -2917,32 +3172,24 @@ function normalize404RetryTimeoutMs(params) {
2917
3172
  return timeoutMs;
2918
3173
  }
2919
3174
  async function classifySubmitResponse(params) {
2920
- const { response, extractErrorMessage } = params;
2921
- if (isRetryableSubmitStatus(response.status)) {
2922
- return { kind: "retryable", status: response.status };
3175
+ const { response, fallbackErrorCode } = params;
3176
+ if (response.status === 204) {
3177
+ return { kind: "retryable", status: 204 };
2923
3178
  }
2924
3179
  if (response.ok) {
2925
3180
  return { kind: "parse-json" };
2926
3181
  }
2927
- let errorMessage = `HTTP ${response.status}`;
2928
- try {
2929
- const errorBody = await response.json();
2930
- const maybeErrorMessage = extractErrorMessage?.(errorBody);
2931
- if (typeof maybeErrorMessage === "string" && maybeErrorMessage.length > 0) {
2932
- errorMessage = maybeErrorMessage;
2933
- } else if (errorBody && typeof errorBody === "object") {
2934
- const defaultMessage = errorBody.error_message;
2935
- const fallbackMessage = errorBody.message;
2936
- if (typeof defaultMessage === "string" && defaultMessage.length > 0) {
2937
- errorMessage = defaultMessage;
2938
- } else if (typeof fallbackMessage === "string" && fallbackMessage.length > 0) {
2939
- errorMessage = fallbackMessage;
2940
- }
2941
- }
2942
- } catch {
2943
- errorMessage = response.statusText || errorMessage;
3182
+ const { apiErrorCode, errorMessage } = await parseApiErrorResponseBody(response);
3183
+ if (response.status === 404) {
3184
+ return { kind: "retryable", status: 404, apiErrorMessage: errorMessage };
2944
3185
  }
2945
- 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
+ };
2946
3193
  }
2947
3194
  function throwIfSubmitRetryTimedOut(params) {
2948
3195
  const {
@@ -2954,12 +3201,14 @@ function throwIfSubmitRetryTimedOut(params) {
2954
3201
  overallTimeoutMs,
2955
3202
  thresholdNetworkUrl,
2956
3203
  body,
2957
- attemptIndex
3204
+ attemptIndex,
3205
+ lastKnownErrorMessage
2958
3206
  } = params;
2959
3207
  if (status === 404 && elapsedMs > retry404TimeoutMs) {
2960
3208
  throw new CofheError({
2961
- code: errorCode,
2962
- 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}` : ""),
2963
3212
  hint: "The ciphertext may not be indexed yet. Increase set404RetryTimeout(...) if the backend is slow to index ciphertexts.",
2964
3213
  context: {
2965
3214
  thresholdNetworkUrl,
@@ -2985,6 +3234,62 @@ function throwIfSubmitRetryTimedOut(params) {
2985
3234
  });
2986
3235
  }
2987
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
+ }
2988
3293
 
2989
3294
  // core/decrypt/tnSealOutputV2.ts
2990
3295
  var POLL_INTERVAL_MS = 1e3;
@@ -3047,13 +3352,14 @@ function parseCompletedSealOutputResponse(params) {
3047
3352
  }
3048
3353
  return convertSealedData(sealed);
3049
3354
  }
3050
- async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, permission, overallStartTime, retry404TimeoutMs, onPoll) {
3355
+ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, acp, overallStartTime, retry404TimeoutMs, onPoll) {
3051
3356
  const body = {
3052
3357
  ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
3053
3358
  host_chain_id: chainId,
3054
- permit: permission
3359
+ acp
3055
3360
  };
3056
3361
  let attemptIndex = 0;
3362
+ let last404ApiErrorMessage;
3057
3363
  for (; ; ) {
3058
3364
  let response;
3059
3365
  try {
@@ -3081,16 +3387,19 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, per
3081
3387
  }
3082
3388
  });
3083
3389
  }
3084
- const responseClassification = await classifySubmitResponse({ response });
3390
+ const responseClassification = await classifySubmitResponse({
3391
+ response,
3392
+ fallbackErrorCode: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */
3393
+ });
3085
3394
  if (responseClassification.kind === "fatal-http") {
3086
3395
  throw new CofheError({
3087
- code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
3396
+ code: responseClassification.cofheErrorCode,
3397
+ apiErrorCode: responseClassification.apiErrorCode,
3088
3398
  message: `sealOutput request failed: ${responseClassification.errorMessage}`,
3089
3399
  hint: "Check the threshold network URL and request parameters.",
3090
3400
  context: {
3091
3401
  thresholdNetworkUrl,
3092
- status: response.status,
3093
- statusText: response.statusText,
3402
+ status: responseClassification.status,
3094
3403
  body,
3095
3404
  attemptIndex
3096
3405
  }
@@ -3136,6 +3445,9 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, per
3136
3445
  }
3137
3446
  });
3138
3447
  }
3448
+ if (responseClassification.status === 404) {
3449
+ last404ApiErrorMessage = responseClassification.apiErrorMessage;
3450
+ }
3139
3451
  const elapsedMs = Date.now() - overallStartTime;
3140
3452
  throwIfSubmitRetryTimedOut({
3141
3453
  operationLabel: "sealOutput",
@@ -3146,7 +3458,8 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, per
3146
3458
  overallTimeoutMs: SEAL_OUTPUT_TIMEOUT_MS,
3147
3459
  thresholdNetworkUrl,
3148
3460
  body,
3149
- attemptIndex
3461
+ attemptIndex,
3462
+ lastKnownErrorMessage: last404ApiErrorMessage
3150
3463
  });
3151
3464
  onPoll?.({
3152
3465
  operation: "sealoutput",
@@ -3224,15 +3537,10 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStart
3224
3537
  });
3225
3538
  }
3226
3539
  if (!response.ok) {
3227
- let errorMessage = `HTTP ${response.status}`;
3228
- try {
3229
- const errorBody = await response.json();
3230
- errorMessage = errorBody.error_message || errorBody.message || errorMessage;
3231
- } catch {
3232
- errorMessage = response.statusText || errorMessage;
3233
- }
3540
+ const { apiErrorCode, errorMessage } = await parseApiErrorResponseBody(response);
3234
3541
  throw new CofheError({
3235
- code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
3542
+ code: mapApiErrorCodeToCofheErrorCode(apiErrorCode, "SEAL_OUTPUT_FAILED" /* SealOutputFailed */),
3543
+ apiErrorCode,
3236
3544
  message: `sealOutput status poll failed: ${errorMessage}`,
3237
3545
  context: {
3238
3546
  thresholdNetworkUrl,
@@ -3276,7 +3584,7 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStart
3276
3584
  });
3277
3585
  }
3278
3586
  async function tnSealOutputV2(params) {
3279
- const { thresholdNetworkUrl, ctHash, chainId, permission, retry404TimeoutMs, onPoll } = params;
3587
+ const { thresholdNetworkUrl, ctHash, chainId, acp, retry404TimeoutMs, onPoll } = params;
3280
3588
  const normalized404RetryTimeoutMs = normalize404RetryTimeoutMs({
3281
3589
  timeoutMs: retry404TimeoutMs,
3282
3590
  operationLabel: "sealOutput",
@@ -3287,7 +3595,7 @@ async function tnSealOutputV2(params) {
3287
3595
  thresholdNetworkUrl,
3288
3596
  ctHash,
3289
3597
  chainId,
3290
- permission,
3598
+ acp,
3291
3599
  overallStartTime,
3292
3600
  normalized404RetryTimeoutMs,
3293
3601
  onPoll
@@ -3303,8 +3611,8 @@ var DEFAULT_404_RETRY_TIMEOUT_MS2 = 1e4;
3303
3611
  var DecryptForViewBuilder = class extends BaseBuilder {
3304
3612
  ctHash;
3305
3613
  utype;
3306
- permitHash;
3307
- permit;
3614
+ acpHash;
3615
+ acp;
3308
3616
  pollCallback;
3309
3617
  retry404TimeoutMs = DEFAULT_404_RETRY_TIMEOUT_MS2;
3310
3618
  constructor(params) {
@@ -3318,11 +3626,11 @@ var DecryptForViewBuilder = class extends BaseBuilder {
3318
3626
  });
3319
3627
  this.ctHash = params.ctHash;
3320
3628
  this.utype = params.utype;
3321
- this.permitHash = params.permitHash;
3322
- this.permit = params.permit;
3629
+ this.acpHash = params.acpHash;
3630
+ this.acp = params.acp;
3323
3631
  }
3324
3632
  /**
3325
- * @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.
3326
3634
  *
3327
3635
  * If not provided, the chainId will be fetched from the connected publicClient.
3328
3636
  *
@@ -3343,7 +3651,7 @@ var DecryptForViewBuilder = class extends BaseBuilder {
3343
3651
  return this.chainId;
3344
3652
  }
3345
3653
  /**
3346
- * @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.
3347
3655
  *
3348
3656
  * If not provided, the account will be fetched from the connected walletClient.
3349
3657
  *
@@ -3380,61 +3688,61 @@ var DecryptForViewBuilder = class extends BaseBuilder {
3380
3688
  this.retry404TimeoutMs = timeoutMs;
3381
3689
  return this;
3382
3690
  }
3383
- withPermit(permitOrPermitHash) {
3384
- if (typeof permitOrPermitHash === "string") {
3385
- this.permitHash = permitOrPermitHash;
3386
- this.permit = void 0;
3387
- } else if (permitOrPermitHash === void 0) {
3388
- this.permitHash = void 0;
3389
- 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;
3390
3698
  } else {
3391
- this.permit = permitOrPermitHash;
3392
- this.permitHash = void 0;
3699
+ this.acp = acpOrACPHash;
3700
+ this.acpHash = void 0;
3393
3701
  }
3394
3702
  return this;
3395
3703
  }
3396
3704
  /**
3397
- * @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.
3398
3706
  *
3399
- * If not provided, the active permit for the chainId and account will be used.
3400
- * 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.
3401
3709
  *
3402
3710
  * Example:
3403
3711
  * ```typescript
3404
3712
  * const unsealed = await client.decryptForView(ctHash, utype)
3405
- * .setPermitHash('0x1234567890123456789012345678901234567890')
3713
+ * .setACPHash('0x1234567890123456789012345678901234567890')
3406
3714
  * .execute();
3407
3715
  * ```
3408
3716
  *
3409
3717
  * @returns The chainable DecryptForViewBuilder instance.
3410
3718
  */
3411
- /** @deprecated Use `withPermit(permitHash)` instead. */
3412
- setPermitHash(permitHash) {
3413
- return this.withPermit(permitHash);
3719
+ /** @deprecated Use `withACP(acpHash)` instead. */
3720
+ setACPHash(acpHash) {
3721
+ return this.withACP(acpHash);
3414
3722
  }
3415
- getPermitHash() {
3416
- return this.permitHash;
3723
+ getACPHash() {
3724
+ return this.acpHash;
3417
3725
  }
3418
3726
  /**
3419
- * @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.
3420
3728
  *
3421
- * 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.
3422
3730
  *
3423
3731
  * Example:
3424
3732
  * ```typescript
3425
3733
  * const unsealed = await client.decryptForView(ctHash, utype)
3426
- * .setPermit(permit)
3734
+ * .setACP(acp)
3427
3735
  * .execute();
3428
3736
  * ```
3429
3737
  *
3430
3738
  * @returns The chainable DecryptForViewBuilder instance.
3431
3739
  */
3432
- /** @deprecated Use `withPermit(permit)` instead. */
3433
- setPermit(permit) {
3434
- return this.withPermit(permit);
3740
+ /** @deprecated Use `withACP(acp)` instead. */
3741
+ setACP(acp) {
3742
+ return this.withACP(acp);
3435
3743
  }
3436
- getPermit() {
3437
- return this.permit;
3744
+ getACP() {
3745
+ return this.acp;
3438
3746
  }
3439
3747
  async getThresholdNetworkUrl() {
3440
3748
  this.assertChainId();
@@ -3450,77 +3758,77 @@ var DecryptForViewBuilder = class extends BaseBuilder {
3450
3758
  }
3451
3759
  });
3452
3760
  }
3453
- async getResolvedPermit() {
3454
- if (this.permit)
3455
- return this.permit;
3761
+ async getResolvedACP() {
3762
+ if (this.acp)
3763
+ return this.acp;
3456
3764
  this.assertChainId();
3457
3765
  this.assertAccount();
3458
- if (this.permitHash) {
3459
- const permit2 = await permits.getPermit(this.chainId, this.account, this.permitHash);
3460
- if (!permit2) {
3766
+ if (this.acpHash) {
3767
+ const acp2 = await acps.getACP(this.chainId, this.account, this.acpHash);
3768
+ if (!acp2) {
3461
3769
  throw new CofheError({
3462
- code: "PERMIT_NOT_FOUND" /* PermitNotFound */,
3463
- message: `Permit with hash <${this.permitHash}> not found for account <${this.account}> and chainId <${this.chainId}>`,
3464
- 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.",
3465
3773
  context: {
3466
3774
  chainId: this.chainId,
3467
3775
  account: this.account,
3468
- permitHash: this.permitHash
3776
+ acpHash: this.acpHash
3469
3777
  }
3470
3778
  });
3471
3779
  }
3472
- return permit2;
3780
+ return acp2;
3473
3781
  }
3474
- const permit = await permits.getActivePermit(this.chainId, this.account);
3475
- if (!permit) {
3782
+ const acp = await acps.getActiveACP(this.chainId, this.account);
3783
+ if (!acp) {
3476
3784
  throw new CofheError({
3477
- code: "PERMIT_NOT_FOUND" /* PermitNotFound */,
3478
- message: `Active permit not found for chainId <${this.chainId}> and account <${this.account}>`,
3479
- 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.",
3480
3788
  context: {
3481
3789
  chainId: this.chainId,
3482
3790
  account: this.account
3483
3791
  }
3484
3792
  });
3485
3793
  }
3486
- return permit;
3794
+ return acp;
3487
3795
  }
3488
3796
  /**
3489
3797
  * On hardhat, interact with MockZkVerifier contract instead of CoFHE
3490
3798
  */
3491
- async mocksSealOutput(permit) {
3799
+ async mocksSealOutput(acp) {
3492
3800
  this.assertPublicClient();
3493
3801
  const mocksDecryptDelay = this.config.mocks.decryptDelay;
3494
3802
  if (mocksDecryptDelay > 0)
3495
3803
  await sleep(mocksDecryptDelay);
3496
- return cofheMocksDecryptForView(this.ctHash, this.utype, permit, this.publicClient);
3804
+ return cofheMocksDecryptForView(this.ctHash, this.utype, acp, this.publicClient);
3497
3805
  }
3498
3806
  /**
3499
3807
  * In the production context, perform a true decryption with the CoFHE coprocessor.
3500
3808
  */
3501
- async productionSealOutput(permit) {
3809
+ async productionSealOutput(acp) {
3502
3810
  this.assertChainId();
3503
3811
  this.assertPublicClient();
3504
3812
  const thresholdNetworkUrl = await this.getThresholdNetworkUrl();
3505
- const permission = PermitUtils.getPermission(permit, true);
3813
+ const wireAcp = ACPUtils.getPublic(acp, true);
3506
3814
  const sealed = await tnSealOutputV2({
3507
3815
  ctHash: this.ctHash,
3508
3816
  chainId: this.chainId,
3509
- permission,
3817
+ acp: wireAcp,
3510
3818
  thresholdNetworkUrl,
3511
3819
  retry404TimeoutMs: this.retry404TimeoutMs,
3512
3820
  onPoll: this.pollCallback
3513
3821
  });
3514
- return PermitUtils.unseal(permit, sealed);
3822
+ return ACPUtils.unseal(acp, sealed);
3515
3823
  }
3516
3824
  /**
3517
3825
  * Final step of the decryption process. MUST BE CALLED LAST IN THE CHAIN.
3518
3826
  *
3519
3827
  * This will:
3520
- * - Use a permit based on provided permit OR chainId + account + permitHash
3521
- * - Check permit validity
3522
- * - Call CoFHE `/sealoutput` with the permit, which returns a sealed (encrypted) item
3523
- * - 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
3524
3832
  * - Return the unsealed item
3525
3833
  *
3526
3834
  * Example:
@@ -3528,7 +3836,7 @@ var DecryptForViewBuilder = class extends BaseBuilder {
3528
3836
  * const unsealed = await client.decryptForView(ctHash, utype)
3529
3837
  * .setChainId(11155111) // optional
3530
3838
  * .setAccount('0x123...890') // optional
3531
- * .withPermit() // optional
3839
+ * .withACP() // optional
3532
3840
  * .execute(); // execute
3533
3841
  * ```
3534
3842
  *
@@ -3536,14 +3844,14 @@ var DecryptForViewBuilder = class extends BaseBuilder {
3536
3844
  */
3537
3845
  async execute() {
3538
3846
  this.validateUtypeOrThrow();
3539
- const permit = await this.getResolvedPermit();
3540
- PermitUtils.validate(permit);
3541
- const chainId = permit._signedDomain.chainId;
3847
+ const acp = await this.getResolvedACP();
3848
+ ACPUtils.validate(acp);
3849
+ const chainId = acp._signedDomain.chainId;
3542
3850
  let unsealed;
3543
3851
  if (chainId === hardhat2.id) {
3544
- unsealed = await this.mocksSealOutput(permit);
3852
+ unsealed = await this.mocksSealOutput(acp);
3545
3853
  } else {
3546
- unsealed = await this.productionSealOutput(permit);
3854
+ unsealed = await this.productionSealOutput(acp);
3547
3855
  }
3548
3856
  return convertViaUtype(this.utype, unsealed);
3549
3857
  }
@@ -3551,28 +3859,28 @@ var DecryptForViewBuilder = class extends BaseBuilder {
3551
3859
  var UINT_TYPE_MASK = 0x7fn;
3552
3860
  var TYPE_BYTE_OFFSET = 8n;
3553
3861
  var getEncryptionTypeFromCtHash = (ctHash) => Number(ctHash >> TYPE_BYTE_OFFSET & UINT_TYPE_MASK);
3554
- async function cofheMocksDecryptForTx(ctHash, utype, permit, publicClient) {
3862
+ async function cofheMocksDecryptForTx(ctHash, utype, acp, publicClient) {
3555
3863
  let allowed;
3556
3864
  let error;
3557
3865
  let decryptedValue;
3558
- if (permit !== null) {
3559
- let permission = PermitUtils.getPermission(permit, true);
3866
+ if (acp !== null) {
3867
+ const wireAcp = ACPUtils.getPublic(acp, true);
3560
3868
  const permissionWithBigInts = {
3561
- ...permission,
3562
- expiration: BigInt(permission.expiration),
3563
- validatorId: BigInt(permission.validatorId)
3869
+ ...wireAcp,
3870
+ expiration: BigInt(wireAcp.expiration),
3871
+ revokerData: BigInt(wireAcp.revokerData)
3564
3872
  };
3565
3873
  [allowed, error, decryptedValue] = await publicClient.readContract({
3566
3874
  address: MOCKS_THRESHOLD_NETWORK_ADDRESS,
3567
3875
  abi: MockThresholdNetworkAbi,
3568
- functionName: "decryptForTxWithPermit",
3876
+ functionName: "decryptForTxWithACP",
3569
3877
  args: [BigInt(ctHash), permissionWithBigInts]
3570
3878
  });
3571
3879
  } else {
3572
3880
  [allowed, error, decryptedValue] = await publicClient.readContract({
3573
3881
  address: MOCKS_THRESHOLD_NETWORK_ADDRESS,
3574
3882
  abi: MockThresholdNetworkAbi,
3575
- functionName: "decryptForTxWithoutPermit",
3883
+ functionName: "decryptForTxWithoutACP",
3576
3884
  args: [BigInt(ctHash)]
3577
3885
  });
3578
3886
  }
@@ -3607,62 +3915,6 @@ async function cofheMocksDecryptForTx(ctHash, utype, permit, publicClient) {
3607
3915
  signature
3608
3916
  };
3609
3917
  }
3610
- function normalizeTnSignature(signature) {
3611
- if (typeof signature !== "string") {
3612
- throw new CofheError({
3613
- code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
3614
- message: "decrypt response missing signature",
3615
- context: {
3616
- signature
3617
- }
3618
- });
3619
- }
3620
- const trimmed = signature.trim();
3621
- if (trimmed.length === 0) {
3622
- throw new CofheError({
3623
- code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
3624
- message: "decrypt response returned empty signature"
3625
- });
3626
- }
3627
- const prefixed = trimmed.startsWith("0x") ? trimmed : `0x${trimmed}`;
3628
- const parsed = viem.parseSignature(prefixed);
3629
- return viem.serializeSignature(parsed);
3630
- }
3631
- function parseDecryptedBytesToBigInt(decrypted) {
3632
- if (!Array.isArray(decrypted)) {
3633
- throw new CofheError({
3634
- code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
3635
- message: "decrypt response field <decrypted> must be a byte array",
3636
- context: {
3637
- decrypted
3638
- }
3639
- });
3640
- }
3641
- if (decrypted.length === 0) {
3642
- throw new CofheError({
3643
- code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
3644
- message: "decrypt response field <decrypted> was an empty byte array",
3645
- context: {
3646
- decrypted
3647
- }
3648
- });
3649
- }
3650
- let hex = "";
3651
- for (const b of decrypted) {
3652
- if (typeof b !== "number" || !Number.isInteger(b) || b < 0 || b > 255) {
3653
- throw new CofheError({
3654
- code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
3655
- message: "decrypt response field <decrypted> contained a non-byte value",
3656
- context: {
3657
- badElement: b,
3658
- decrypted
3659
- }
3660
- });
3661
- }
3662
- hex += b.toString(16).padStart(2, "0");
3663
- }
3664
- return BigInt(`0x${hex}`);
3665
- }
3666
3918
 
3667
3919
  // core/decrypt/tnDecryptV2.ts
3668
3920
  var POLL_INTERVAL_MS2 = 1e3;
@@ -3784,15 +4036,16 @@ function assertDecryptStatusResponseV2(value) {
3784
4036
  }
3785
4037
  return value;
3786
4038
  }
3787
- async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, permission, overallStartTime, retry404TimeoutMs, onPoll) {
4039
+ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, acp, overallStartTime, retry404TimeoutMs, onPoll) {
3788
4040
  const body = {
3789
4041
  ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
3790
4042
  host_chain_id: chainId
3791
4043
  };
3792
- if (permission) {
3793
- body.permit = permission;
4044
+ if (acp) {
4045
+ body.acp = acp;
3794
4046
  }
3795
4047
  let attemptIndex = 0;
4048
+ let last404ApiErrorMessage;
3796
4049
  for (; ; ) {
3797
4050
  let response;
3798
4051
  try {
@@ -3820,16 +4073,19 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, perm
3820
4073
  }
3821
4074
  });
3822
4075
  }
3823
- const responseClassification = await classifySubmitResponse({ response });
4076
+ const responseClassification = await classifySubmitResponse({
4077
+ response,
4078
+ fallbackErrorCode: "DECRYPT_FAILED" /* DecryptFailed */
4079
+ });
3824
4080
  if (responseClassification.kind === "fatal-http") {
3825
4081
  throw new CofheError({
3826
- code: "DECRYPT_FAILED" /* DecryptFailed */,
4082
+ code: responseClassification.cofheErrorCode,
4083
+ apiErrorCode: responseClassification.apiErrorCode,
3827
4084
  message: `decrypt request failed: ${responseClassification.errorMessage}`,
3828
4085
  hint: "Check the threshold network URL and request parameters.",
3829
4086
  context: {
3830
4087
  thresholdNetworkUrl,
3831
- status: response.status,
3832
- statusText: response.statusText,
4088
+ status: responseClassification.status,
3833
4089
  body,
3834
4090
  attemptIndex
3835
4091
  }
@@ -3877,6 +4133,9 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, perm
3877
4133
  }
3878
4134
  });
3879
4135
  }
4136
+ if (responseClassification.status === 404) {
4137
+ last404ApiErrorMessage = responseClassification.apiErrorMessage;
4138
+ }
3880
4139
  const elapsedMs = Date.now() - overallStartTime;
3881
4140
  throwIfSubmitRetryTimedOut({
3882
4141
  operationLabel: "decrypt",
@@ -3887,7 +4146,8 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, perm
3887
4146
  overallTimeoutMs: DECRYPT_TIMEOUT_MS,
3888
4147
  thresholdNetworkUrl,
3889
4148
  body,
3890
- attemptIndex
4149
+ attemptIndex,
4150
+ lastKnownErrorMessage: last404ApiErrorMessage
3891
4151
  });
3892
4152
  onPoll?.({
3893
4153
  operation: "decrypt",
@@ -3965,17 +4225,10 @@ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartT
3965
4225
  });
3966
4226
  }
3967
4227
  if (!response.ok) {
3968
- let errorMessage = `HTTP ${response.status}`;
3969
- try {
3970
- const errorBody = await response.json();
3971
- const maybeMessage = errorBody.error_message || errorBody.message;
3972
- if (typeof maybeMessage === "string" && maybeMessage.length > 0)
3973
- errorMessage = maybeMessage;
3974
- } catch {
3975
- errorMessage = response.statusText || errorMessage;
3976
- }
4228
+ const { apiErrorCode, errorMessage } = await parseApiErrorResponseBody(response);
3977
4229
  throw new CofheError({
3978
- code: "DECRYPT_FAILED" /* DecryptFailed */,
4230
+ code: mapApiErrorCodeToCofheErrorCode(apiErrorCode, "DECRYPT_FAILED" /* DecryptFailed */),
4231
+ apiErrorCode,
3979
4232
  message: `decrypt status poll failed: ${errorMessage}`,
3980
4233
  context: {
3981
4234
  thresholdNetworkUrl,
@@ -4020,7 +4273,7 @@ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartT
4020
4273
  });
4021
4274
  }
4022
4275
  async function tnDecryptV2(params) {
4023
- const { thresholdNetworkUrl, ctHash, chainId, permission, retry404TimeoutMs, onPoll } = params;
4276
+ const { thresholdNetworkUrl, ctHash, chainId, acp, retry404TimeoutMs, onPoll } = params;
4024
4277
  const normalized404RetryTimeoutMs = normalize404RetryTimeoutMs({
4025
4278
  timeoutMs: retry404TimeoutMs,
4026
4279
  operationLabel: "decrypt",
@@ -4031,7 +4284,7 @@ async function tnDecryptV2(params) {
4031
4284
  thresholdNetworkUrl,
4032
4285
  ctHash,
4033
4286
  chainId,
4034
- permission,
4287
+ acp,
4035
4288
  overallStartTime,
4036
4289
  normalized404RetryTimeoutMs,
4037
4290
  onPoll
@@ -4046,9 +4299,9 @@ async function tnDecryptV2(params) {
4046
4299
  var DEFAULT_404_RETRY_TIMEOUT_MS3 = 1e4;
4047
4300
  var DecryptForTxBuilder = class extends BaseBuilder {
4048
4301
  ctHash;
4049
- permitHash;
4050
- permit;
4051
- permitSelection = "unset";
4302
+ acpHash;
4303
+ acp;
4304
+ acpSelection = "unset";
4052
4305
  pollCallback;
4053
4306
  retry404TimeoutMs = DEFAULT_404_RETRY_TIMEOUT_MS3;
4054
4307
  constructor(params) {
@@ -4093,137 +4346,137 @@ var DecryptForTxBuilder = class extends BaseBuilder {
4093
4346
  this.retry404TimeoutMs = timeoutMs;
4094
4347
  return this;
4095
4348
  }
4096
- withPermit(permitOrPermitHash) {
4097
- if (this.permitSelection === "with-permit") {
4349
+ withACP(acpOrACPHash) {
4350
+ if (this.acpSelection === "with-acp") {
4098
4351
  throw new CofheError({
4099
4352
  code: "INTERNAL_ERROR" /* InternalError */,
4100
- message: "decryptForTx: withPermit() can only be selected once.",
4101
- 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."
4102
4355
  });
4103
4356
  }
4104
- if (this.permitSelection === "without-permit") {
4357
+ if (this.acpSelection === "without-acp") {
4105
4358
  throw new CofheError({
4106
4359
  code: "INTERNAL_ERROR" /* InternalError */,
4107
- message: "decryptForTx: cannot call withPermit() after withoutPermit() has been selected.",
4108
- 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."
4109
4362
  });
4110
4363
  }
4111
- this.permitSelection = "with-permit";
4112
- if (typeof permitOrPermitHash === "string") {
4113
- this.permitHash = permitOrPermitHash;
4114
- this.permit = void 0;
4115
- } else if (permitOrPermitHash === void 0) {
4116
- this.permitHash = void 0;
4117
- 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;
4118
4371
  } else {
4119
- this.permit = permitOrPermitHash;
4120
- this.permitHash = void 0;
4372
+ this.acp = acpOrACPHash;
4373
+ this.acpHash = void 0;
4121
4374
  }
4122
4375
  return this;
4123
4376
  }
4124
4377
  /**
4125
- * Select "no permit" mode.
4378
+ * Select "no acp" mode.
4126
4379
  *
4127
- * 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`.
4128
4381
  */
4129
- withoutPermit() {
4130
- if (this.permitSelection === "without-permit") {
4382
+ withoutACP() {
4383
+ if (this.acpSelection === "without-acp") {
4131
4384
  throw new CofheError({
4132
4385
  code: "INTERNAL_ERROR" /* InternalError */,
4133
- message: "decryptForTx: withoutPermit() can only be selected once.",
4134
- 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."
4135
4388
  });
4136
4389
  }
4137
- if (this.permitSelection === "with-permit") {
4390
+ if (this.acpSelection === "with-acp") {
4138
4391
  throw new CofheError({
4139
4392
  code: "INTERNAL_ERROR" /* InternalError */,
4140
- message: "decryptForTx: cannot call withoutPermit() after withPermit() has been selected.",
4141
- 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."
4142
4395
  });
4143
4396
  }
4144
- this.permitSelection = "without-permit";
4145
- this.permitHash = void 0;
4146
- this.permit = void 0;
4397
+ this.acpSelection = "without-acp";
4398
+ this.acpHash = void 0;
4399
+ this.acp = void 0;
4147
4400
  return this;
4148
4401
  }
4149
- getPermit() {
4150
- return this.permit;
4402
+ getACP() {
4403
+ return this.acp;
4151
4404
  }
4152
- getPermitHash() {
4153
- return this.permitHash;
4405
+ getACPHash() {
4406
+ return this.acpHash;
4154
4407
  }
4155
4408
  async getThresholdNetworkUrl() {
4156
4409
  this.assertChainId();
4157
4410
  return getThresholdNetworkUrlOrThrow(this.config, this.chainId);
4158
4411
  }
4159
- async getResolvedPermit() {
4160
- if (this.permitSelection === "unset") {
4412
+ async getResolvedACP() {
4413
+ if (this.acpSelection === "unset") {
4161
4414
  throw new CofheError({
4162
4415
  code: "INTERNAL_ERROR" /* InternalError */,
4163
- message: "decryptForTx: missing permit selection; call withPermit(...) or withoutPermit() before execute().",
4164
- 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."
4165
4418
  });
4166
4419
  }
4167
- if (this.permitSelection === "without-permit") {
4420
+ if (this.acpSelection === "without-acp") {
4168
4421
  return null;
4169
4422
  }
4170
- if (this.permit)
4171
- return this.permit;
4423
+ if (this.acp)
4424
+ return this.acp;
4172
4425
  this.assertChainId();
4173
4426
  this.assertAccount();
4174
- if (this.permitHash) {
4175
- const permit2 = await permits.getPermit(this.chainId, this.account, this.permitHash);
4176
- if (!permit2) {
4427
+ if (this.acpHash) {
4428
+ const acp2 = await acps.getACP(this.chainId, this.account, this.acpHash);
4429
+ if (!acp2) {
4177
4430
  throw new CofheError({
4178
- code: "PERMIT_NOT_FOUND" /* PermitNotFound */,
4179
- message: `Permit with hash <${this.permitHash}> not found for account <${this.account}> and chainId <${this.chainId}>`,
4180
- 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.",
4181
4434
  context: {
4182
4435
  chainId: this.chainId,
4183
4436
  account: this.account,
4184
- permitHash: this.permitHash
4437
+ acpHash: this.acpHash
4185
4438
  }
4186
4439
  });
4187
4440
  }
4188
- return permit2;
4441
+ return acp2;
4189
4442
  }
4190
- const permit = await permits.getActivePermit(this.chainId, this.account);
4191
- if (!permit) {
4443
+ const acp = await acps.getActiveACP(this.chainId, this.account);
4444
+ if (!acp) {
4192
4445
  throw new CofheError({
4193
- code: "PERMIT_NOT_FOUND" /* PermitNotFound */,
4194
- message: `Active permit not found for chainId <${this.chainId}> and account <${this.account}>`,
4195
- 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)).",
4196
4449
  context: {
4197
4450
  chainId: this.chainId,
4198
4451
  account: this.account
4199
4452
  }
4200
4453
  });
4201
4454
  }
4202
- return permit;
4455
+ return acp;
4203
4456
  }
4204
4457
  /**
4205
4458
  * On hardhat, interact with MockThresholdNetwork contract
4206
4459
  */
4207
- async mocksDecryptForTx(permit) {
4460
+ async mocksDecryptForTx(acp) {
4208
4461
  this.assertPublicClient();
4209
4462
  const delay = this.config.mocks.decryptDelay;
4210
4463
  if (delay > 0)
4211
4464
  await sleep(delay);
4212
- const result = await cofheMocksDecryptForTx(this.ctHash, 0, permit, this.publicClient);
4465
+ const result = await cofheMocksDecryptForTx(this.ctHash, 0, acp, this.publicClient);
4213
4466
  return result;
4214
4467
  }
4215
4468
  /**
4216
4469
  * In the production context, perform a true decryption with the CoFHE coprocessor.
4217
4470
  */
4218
- async productionDecryptForTx(permit) {
4471
+ async productionDecryptForTx(acp) {
4219
4472
  this.assertChainId();
4220
4473
  this.assertPublicClient();
4221
4474
  const thresholdNetworkUrl = await this.getThresholdNetworkUrl();
4222
- const permission = permit ? PermitUtils.getPermission(permit, true) : null;
4475
+ const wireAcp = acp ? ACPUtils.getPublic(acp, true) : null;
4223
4476
  const { decryptedValue, signature } = await tnDecryptV2({
4224
4477
  ctHash: this.ctHash,
4225
4478
  chainId: this.chainId,
4226
- permission,
4479
+ acp: wireAcp,
4227
4480
  thresholdNetworkUrl,
4228
4481
  retry404TimeoutMs: this.retry404TimeoutMs,
4229
4482
  onPoll: this.pollCallback
@@ -4237,19 +4490,19 @@ var DecryptForTxBuilder = class extends BaseBuilder {
4237
4490
  /**
4238
4491
  * Final step of the decryptForTx process. MUST BE CALLED LAST IN THE CHAIN.
4239
4492
  *
4240
- * You must explicitly choose one permit mode before calling `execute()`:
4241
- * - `withPermit(permit)` / `withPermit(permitHash)` / `withPermit()` (active permit)
4242
- * - `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)
4243
4496
  */
4244
4497
  async execute() {
4245
- const permit = await this.getResolvedPermit();
4246
- if (permit !== null) {
4247
- PermitUtils.validate(permit);
4248
- 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;
4249
4502
  if (chainId === hardhat2.id) {
4250
- return await this.mocksDecryptForTx(permit);
4503
+ return await this.mocksDecryptForTx(acp);
4251
4504
  } else {
4252
- return await this.productionDecryptForTx(permit);
4505
+ return await this.productionDecryptForTx(acp);
4253
4506
  }
4254
4507
  } else {
4255
4508
  if (!this.chainId) {
@@ -4312,6 +4565,21 @@ function createCofheClientBase(opts) {
4312
4565
  const updateConnectState = (partial) => {
4313
4566
  connectStore.setState((state) => ({ ...state, ...partial }));
4314
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
+ };
4315
4583
  const _requireConnected = () => {
4316
4584
  const state = connectStore.getState();
4317
4585
  const notConnected = !state.connected || !state.account || !state.chainId || !state.publicClient || !state.walletClient;
@@ -4434,74 +4702,147 @@ function createCofheClientBase(opts) {
4434
4702
  }
4435
4703
  return { chainId: _chainId, account: _account };
4436
4704
  };
4437
- const clientPermits = {
4705
+ const clientACPs = {
4438
4706
  // Pass through store access
4439
- getSnapshot: permits.getSnapshot,
4440
- subscribe: permits.subscribe,
4707
+ getSnapshot: acps.getSnapshot,
4708
+ subscribe: acps.subscribe,
4441
4709
  // Creation methods (require connection)
4442
4710
  createSelf: async (options, clients) => {
4443
4711
  _requireConnected();
4444
4712
  const { publicClient, walletClient } = clients ?? connectStore.getState();
4445
- 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
+ );
4446
4719
  },
4447
4720
  createSharing: async (options, clients) => {
4448
4721
  _requireConnected();
4449
4722
  const { publicClient, walletClient } = clients ?? connectStore.getState();
4450
- 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
+ );
4451
4729
  },
4452
4730
  importShared: async (options, clients) => {
4453
4731
  _requireConnected();
4454
4732
  const { publicClient, walletClient } = clients ?? connectStore.getState();
4455
- return permits.importShared(options, publicClient, walletClient);
4733
+ return acps.importShared(options, publicClient, walletClient);
4456
4734
  },
4457
4735
  // Get or create methods (require connection)
4458
- getOrCreateSelfPermit: async (chainId, account, options) => {
4736
+ getOrCreateSelfACP: async (chainId, account, options) => {
4459
4737
  _requireConnected();
4460
4738
  const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
4461
4739
  const { publicClient, walletClient } = connectStore.getState();
4462
- 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);
4463
4747
  },
4464
- getOrCreateSharingPermit: async (options, chainId, account) => {
4748
+ getOrCreateSharingACP: async (options, chainId, account) => {
4465
4749
  _requireConnected();
4466
4750
  const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
4467
4751
  const { publicClient, walletClient } = connectStore.getState();
4468
- 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);
4469
4810
  },
4470
4811
  // Retrieval methods (auto-fill chainId/account)
4471
- getPermit: (hash, chainId, account) => {
4812
+ getACP: (hash, chainId, account) => {
4472
4813
  const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
4473
- return permits.getPermit(_chainId, _account, hash);
4814
+ return acps.getACP(_chainId, _account, hash);
4474
4815
  },
4475
- getPermits: (chainId, account) => {
4816
+ getACPs: (chainId, account) => {
4476
4817
  const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
4477
- return permits.getPermits(_chainId, _account);
4818
+ return acps.getACPs(_chainId, _account);
4478
4819
  },
4479
- getActivePermit: (chainId, account) => {
4820
+ getActiveACP: (chainId, account) => {
4480
4821
  const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
4481
- return permits.getActivePermit(_chainId, _account);
4822
+ return acps.getActiveACP(_chainId, _account);
4482
4823
  },
4483
- getActivePermitHash: (chainId, account) => {
4824
+ getActiveACPHash: (chainId, account) => {
4484
4825
  const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
4485
- return permits.getActivePermitHash(_chainId, _account);
4826
+ return acps.getActiveACPHash(_chainId, _account);
4486
4827
  },
4487
4828
  // Mutation methods (auto-fill chainId/account)
4488
- selectActivePermit: (hash, chainId, account) => {
4829
+ selectActiveACP: (hash, chainId, account) => {
4489
4830
  const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
4490
- return permits.selectActivePermit(_chainId, _account, hash);
4831
+ return acps.selectActiveACP(_chainId, _account, hash);
4491
4832
  },
4492
- removePermit: async (hash, chainId, account) => {
4833
+ removeACP: async (hash, chainId, account) => {
4493
4834
  const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
4494
- return permits.removePermit(_chainId, _account, hash);
4835
+ return acps.removeACP(_chainId, _account, hash);
4495
4836
  },
4496
- removeActivePermit: async (chainId, account) => {
4837
+ removeActiveACP: async (chainId, account) => {
4497
4838
  const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
4498
- return permits.removeActivePermit(_chainId, _account);
4839
+ return acps.removeActiveACP(_chainId, _account);
4499
4840
  },
4500
4841
  // Utils (no context needed)
4501
- getHash: permits.getHash,
4502
- export: permits.export,
4503
- serialize: permits.serialize,
4504
- deserialize: permits.deserialize
4842
+ getHash: acps.getHash,
4843
+ export: acps.export,
4844
+ serialize: acps.serialize,
4845
+ deserialize: acps.deserialize
4505
4846
  };
4506
4847
  return {
4507
4848
  // Zustand reactive accessors (don't export store directly to prevent mutation)
@@ -4529,7 +4870,7 @@ function createCofheClientBase(opts) {
4529
4870
  decryptHandle: decryptForView,
4530
4871
  decryptForTx,
4531
4872
  verifyDecryptResult: verifyDecryptResult2,
4532
- permits: clientPermits
4873
+ acp: clientACPs
4533
4874
  // Add SDK-specific methods below that require connection
4534
4875
  // Example:
4535
4876
  // async encryptData(data: unknown) {