@cofhe/sdk 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/acps/acp.ts +411 -0
  3. package/acps/index.ts +70 -0
  4. package/{permits → acps}/onchain-utils.ts +49 -24
  5. package/acps/sealing.ts +90 -0
  6. package/acps/signature.ts +89 -0
  7. package/acps/store.ts +172 -0
  8. package/acps/test/acp.test.ts +615 -0
  9. package/acps/test/localstorage.test.ts +105 -0
  10. package/acps/test/sealing.test.ts +77 -0
  11. package/acps/test/store.test.ts +88 -0
  12. package/acps/test/validation.test.ts +361 -0
  13. package/acps/test-utils.ts +32 -0
  14. package/acps/types.ts +252 -0
  15. package/acps/validation.ts +392 -0
  16. package/adapters/test/ethers5.test.ts +4 -1
  17. package/adapters/test/ethers6.test.ts +4 -1
  18. package/adapters/test/wagmi.test.ts +5 -2
  19. package/chains/chains/stagingCofhe.ts +21 -0
  20. package/chains/index.ts +3 -1
  21. package/chains/test/chains.test.ts +2 -1
  22. package/core/acps.ts +625 -0
  23. package/core/client.ts +136 -39
  24. package/core/clientTypes.ts +52 -41
  25. package/core/config.ts +66 -5
  26. package/core/debug.ts +72 -0
  27. package/core/decrypt/MockThresholdNetworkAbi.ts +20 -11
  28. package/core/decrypt/apiError.ts +104 -0
  29. package/core/decrypt/cofheMocksDecryptForTx.ts +11 -11
  30. package/core/decrypt/cofheMocksDecryptForView.ts +7 -7
  31. package/core/decrypt/decryptForTxBuilder.ts +102 -102
  32. package/core/decrypt/decryptForViewBuilder.ts +90 -90
  33. package/core/decrypt/submitRetry.ts +38 -30
  34. package/core/decrypt/tnDecryptV1.ts +5 -5
  35. package/core/decrypt/tnDecryptV2.ts +45 -34
  36. package/core/decrypt/tnSealOutputV1.ts +4 -3
  37. package/core/decrypt/tnSealOutputV2.ts +44 -31
  38. package/core/encrypt/cofheMocksZkVerifySign.ts +59 -74
  39. package/core/encrypt/encryptInputsBuilder.ts +86 -52
  40. package/core/encrypt/zkPackProveVerify.ts +25 -18
  41. package/core/error.ts +34 -6
  42. package/core/index.ts +14 -14
  43. package/core/test/acpDefaults.test.ts +52 -0
  44. package/core/test/acps.test.ts +596 -0
  45. package/core/test/apiError.test.ts +130 -0
  46. package/core/test/client.test.ts +22 -19
  47. package/core/test/config.test.ts +25 -5
  48. package/core/test/decrypt.test.ts +40 -35
  49. package/core/test/decryptBuilders.test.ts +68 -68
  50. package/core/test/decryptErrorCodes.test.ts +217 -0
  51. package/core/test/encryptInputsBuilder.test.ts +72 -41
  52. package/core/test/pollCallbacks.test.ts +89 -18
  53. package/core/test/stagingRedirect.ts +18 -0
  54. package/core/test/submitRetry.test.ts +182 -0
  55. package/core/types.ts +9 -69
  56. package/dist/acp-Wi6isVQI.d.cts +407 -0
  57. package/dist/acp-Wi6isVQI.d.ts +407 -0
  58. package/dist/acps.cjs +1081 -0
  59. package/dist/acps.d.cts +480 -0
  60. package/dist/acps.d.ts +480 -0
  61. package/dist/acps.js +2 -0
  62. package/dist/chains.cjs +14 -1
  63. package/dist/chains.d.cts +30 -1
  64. package/dist/chains.d.ts +30 -1
  65. package/dist/chains.js +1 -1
  66. package/dist/{chunk-PE5V5CCV.js → chunk-43USWPEH.js} +1000 -604
  67. package/dist/{chunk-MTRAXQXC.js → chunk-N6IDQRRU.js} +14 -2
  68. package/dist/chunk-Q7CBWGQX.js +1029 -0
  69. package/dist/{clientTypes-CyUvRRzA.d.ts → clientTypes-BN3nbzYM.d.ts} +342 -165
  70. package/dist/{clientTypes-BDy1qIBu.d.cts → clientTypes-CYZjFznO.d.cts} +342 -165
  71. package/dist/core.cjs +1431 -1026
  72. package/dist/core.d.cts +55 -10
  73. package/dist/core.d.ts +55 -10
  74. package/dist/core.js +3 -3
  75. package/dist/node.cjs +1356 -976
  76. package/dist/node.d.cts +2 -2
  77. package/dist/node.d.ts +2 -2
  78. package/dist/node.js +3 -3
  79. package/dist/web.cjs +1356 -976
  80. package/dist/web.d.cts +2 -2
  81. package/dist/web.d.ts +2 -2
  82. package/dist/web.js +3 -3
  83. package/node/test/inherited.test.ts +75 -65
  84. package/node/test/tfheinit.test.ts +23 -8
  85. package/package.json +6 -6
  86. package/web/test/client.web.test.ts +5 -1
  87. package/web/test/inherited.web.test.ts +75 -65
  88. package/web/test/tfheinit.web.test.ts +14 -5
  89. package/web/test/worker.config.web.test.ts +38 -23
  90. package/web/test/worker.output.web.test.ts +25 -24
  91. package/core/encrypt/encryptUtils.ts +0 -67
  92. package/core/permits.ts +0 -206
  93. package/core/test/permits.test.ts +0 -534
  94. package/dist/chunk-VB62WYPL.js +0 -978
  95. package/dist/permit-DnVMDT5h.d.cts +0 -376
  96. package/dist/permit-DnVMDT5h.d.ts +0 -376
  97. package/dist/permits.cjs +0 -1026
  98. package/dist/permits.d.cts +0 -353
  99. package/dist/permits.d.ts +0 -353
  100. package/dist/permits.js +0 -2
  101. package/permits/index.ts +0 -68
  102. package/permits/permit.ts +0 -385
  103. package/permits/sealing.ts +0 -131
  104. package/permits/signature.ts +0 -79
  105. package/permits/store.ts +0 -157
  106. package/permits/test/localstorage.test.ts +0 -113
  107. package/permits/test/permit.test.ts +0 -557
  108. package/permits/test/sealing.test.ts +0 -84
  109. package/permits/test/store.test.ts +0 -88
  110. package/permits/test/validation.test.ts +0 -361
  111. package/permits/test-utils.ts +0 -28
  112. package/permits/types.ts +0 -204
  113. package/permits/validation.ts +0 -327
  114. /package/{permits → acps}/utils.ts +0 -0
@@ -39,13 +39,16 @@ export const MockThresholdNetworkAbi = [
39
39
  {
40
40
  name: 'permission',
41
41
  type: 'tuple',
42
- internalType: 'struct Permission',
42
+ internalType: 'struct ACPermission',
43
43
  components: [
44
44
  { name: 'issuer', type: 'address', internalType: 'address' },
45
45
  { name: 'expiration', type: 'uint64', internalType: 'uint64' },
46
46
  { name: 'recipient', type: 'address', internalType: 'address' },
47
- { name: 'validatorId', type: 'uint256', internalType: 'uint256' },
48
- { name: 'validatorContract', type: 'address', internalType: 'address' },
47
+ { name: 'revokerData', type: 'uint256', internalType: 'uint256' },
48
+ { name: 'revokerContract', type: 'address', internalType: 'address' },
49
+ { name: 'scope', type: 'uint8', internalType: 'uint8' },
50
+ { name: 'contracts', type: 'address[]', internalType: 'address[]' },
51
+ { name: 'handles', type: 'bytes32[]', internalType: 'bytes32[]' },
49
52
  { name: 'sealingKey', type: 'bytes32', internalType: 'bytes32' },
50
53
  { name: 'issuerSignature', type: 'bytes', internalType: 'bytes' },
51
54
  { name: 'recipientSignature', type: 'bytes', internalType: 'bytes' },
@@ -68,13 +71,16 @@ export const MockThresholdNetworkAbi = [
68
71
  {
69
72
  name: 'permission',
70
73
  type: 'tuple',
71
- internalType: 'struct Permission',
74
+ internalType: 'struct ACPermission',
72
75
  components: [
73
76
  { name: 'issuer', type: 'address', internalType: 'address' },
74
77
  { name: 'expiration', type: 'uint64', internalType: 'uint64' },
75
78
  { name: 'recipient', type: 'address', internalType: 'address' },
76
- { name: 'validatorId', type: 'uint256', internalType: 'uint256' },
77
- { name: 'validatorContract', type: 'address', internalType: 'address' },
79
+ { name: 'revokerData', type: 'uint256', internalType: 'uint256' },
80
+ { name: 'revokerContract', type: 'address', internalType: 'address' },
81
+ { name: 'scope', type: 'uint8', internalType: 'uint8' },
82
+ { name: 'contracts', type: 'address[]', internalType: 'address[]' },
83
+ { name: 'handles', type: 'bytes32[]', internalType: 'bytes32[]' },
78
84
  { name: 'sealingKey', type: 'bytes32', internalType: 'bytes32' },
79
85
  { name: 'issuerSignature', type: 'bytes', internalType: 'bytes' },
80
86
  { name: 'recipientSignature', type: 'bytes', internalType: 'bytes' },
@@ -139,19 +145,22 @@ export const MockThresholdNetworkAbi = [
139
145
  },
140
146
  {
141
147
  type: 'function',
142
- name: 'decryptForTxWithPermit',
148
+ name: 'decryptForTxWithACP',
143
149
  inputs: [
144
150
  { name: 'ctHash', type: 'uint256', internalType: 'uint256' },
145
151
  {
146
152
  name: 'permission',
147
153
  type: 'tuple',
148
- internalType: 'struct Permission',
154
+ internalType: 'struct ACPermission',
149
155
  components: [
150
156
  { name: 'issuer', type: 'address', internalType: 'address' },
151
157
  { name: 'expiration', type: 'uint64', internalType: 'uint64' },
152
158
  { name: 'recipient', type: 'address', internalType: 'address' },
153
- { name: 'validatorId', type: 'uint256', internalType: 'uint256' },
154
- { name: 'validatorContract', type: 'address', internalType: 'address' },
159
+ { name: 'revokerData', type: 'uint256', internalType: 'uint256' },
160
+ { name: 'revokerContract', type: 'address', internalType: 'address' },
161
+ { name: 'scope', type: 'uint8', internalType: 'uint8' },
162
+ { name: 'contracts', type: 'address[]', internalType: 'address[]' },
163
+ { name: 'handles', type: 'bytes32[]', internalType: 'bytes32[]' },
155
164
  { name: 'sealingKey', type: 'bytes32', internalType: 'bytes32' },
156
165
  { name: 'issuerSignature', type: 'bytes', internalType: 'bytes' },
157
166
  { name: 'recipientSignature', type: 'bytes', internalType: 'bytes' },
@@ -167,7 +176,7 @@ export const MockThresholdNetworkAbi = [
167
176
  },
168
177
  {
169
178
  type: 'function',
170
- name: 'decryptForTxWithoutPermit',
179
+ name: 'decryptForTxWithoutACP',
171
180
  inputs: [{ name: 'ctHash', type: 'uint256', internalType: 'uint256' }],
172
181
  outputs: [
173
182
  { name: 'allowed', type: 'bool', internalType: 'bool' },
@@ -0,0 +1,104 @@
1
+ import { CofheErrorCode } from '../error.js';
2
+
3
+ /**
4
+ * Stable backend error codes returned by the threshold-network server's
5
+ * `{ "error": "<stable_code>", "error_message": "<detail>" }` payload, see API-RESPONSES.md.
6
+ * `ct_not_ready`/`overloaded` are excluded: v2 always represents those as a bodyless 204, so
7
+ * they never reach this type.
8
+ */
9
+ export type BackendApiErrorCode =
10
+ | 'bad_request'
11
+ | 'unknown_chain'
12
+ | 'acp_malformed'
13
+ | 'acp_denied'
14
+ | 'acp_expired'
15
+ | 'acp_invalid'
16
+ | 'acp_required'
17
+ | 'acp_verifier_error'
18
+ | 'acp_verifier_timeout'
19
+ | 'not_publicly_allowed'
20
+ | 'ct_not_found'
21
+ | 'unsupported_security_zone'
22
+ | 'unsupported_type'
23
+ | 'internal_error'
24
+ | 'signing_failed'
25
+ | 'ct_source_error'
26
+ | 'ct_source_timeout'
27
+ | 'seal_failed';
28
+
29
+ const BACKEND_ERROR_CODE_TO_COFHE_ERROR_CODE: Record<BackendApiErrorCode, CofheErrorCode> = {
30
+ bad_request: CofheErrorCode.BadRequest,
31
+ unknown_chain: CofheErrorCode.UnknownChain,
32
+ acp_malformed: CofheErrorCode.ACPMalformed,
33
+ acp_denied: CofheErrorCode.ACPDenied, // ACP-era backends fold revoked into denied
34
+ acp_expired: CofheErrorCode.ACPExpired,
35
+ acp_invalid: CofheErrorCode.ACPInvalid,
36
+ acp_required: CofheErrorCode.ACPRequired,
37
+ acp_verifier_error: CofheErrorCode.ACPVerifierError,
38
+ acp_verifier_timeout: CofheErrorCode.ACPVerifierTimeout,
39
+ not_publicly_allowed: CofheErrorCode.NotPubliclyAllowed,
40
+ ct_not_found: CofheErrorCode.CtNotFound,
41
+ unsupported_security_zone: CofheErrorCode.UnsupportedSecurityZone,
42
+ unsupported_type: CofheErrorCode.UnsupportedType,
43
+ internal_error: CofheErrorCode.InternalError,
44
+ signing_failed: CofheErrorCode.SigningFailed,
45
+ ct_source_error: CofheErrorCode.CtSourceError,
46
+ ct_source_timeout: CofheErrorCode.CtSourceTimeout,
47
+ seal_failed: CofheErrorCode.SealFailed,
48
+ };
49
+
50
+ function isBackendApiErrorCode(value: string): value is BackendApiErrorCode {
51
+ return value in BACKEND_ERROR_CODE_TO_COFHE_ERROR_CODE;
52
+ }
53
+
54
+ export type ParsedApiError = {
55
+ /** Raw `error` field from the backend body, verbatim, even if unrecognized. */
56
+ apiErrorCode?: string;
57
+ /** `error_message`, else `message`, else `HTTP <status>` / statusText. */
58
+ errorMessage: string;
59
+ };
60
+
61
+ /**
62
+ * Reads and parses a fetch Response's JSON error body per the shared `{ error, error_message }`
63
+ * contract. Never throws — falls back to a status/statusText-derived message if the body isn't
64
+ * JSON (e.g. axum framework rejections, which are plain text).
65
+ */
66
+ export async function parseApiErrorResponseBody(response: Response): Promise<ParsedApiError> {
67
+ let errorMessage = `HTTP ${response.status}`;
68
+ let apiErrorCode: string | undefined;
69
+
70
+ try {
71
+ const body = (await response.json()) as unknown;
72
+ if (body && typeof body === 'object') {
73
+ const record = body as Record<string, unknown>;
74
+ if (typeof record.error === 'string' && record.error.length > 0) {
75
+ apiErrorCode = record.error;
76
+ }
77
+ if (typeof record.error_message === 'string' && record.error_message.length > 0) {
78
+ errorMessage = record.error_message;
79
+ } else if (typeof record.message === 'string' && record.message.length > 0) {
80
+ errorMessage = record.message;
81
+ }
82
+ }
83
+ } catch {
84
+ errorMessage = response.statusText || errorMessage;
85
+ }
86
+
87
+ return { apiErrorCode, errorMessage };
88
+ }
89
+
90
+ /**
91
+ * Maps a raw backend `error` string to a CofheErrorCode. Unrecognized or undefined codes fall
92
+ * back to `fallback` so future/undocumented backend codes degrade gracefully instead of
93
+ * throwing — the raw string is still preserved via `CofheError.apiErrorCode` on the resulting
94
+ * error.
95
+ */
96
+ export function mapApiErrorCodeToCofheErrorCode(
97
+ apiErrorCode: string | undefined,
98
+ fallback: CofheErrorCode
99
+ ): CofheErrorCode {
100
+ if (apiErrorCode && isBackendApiErrorCode(apiErrorCode)) {
101
+ return BACKEND_ERROR_CODE_TO_COFHE_ERROR_CODE[apiErrorCode];
102
+ }
103
+ return fallback;
104
+ }
@@ -1,4 +1,4 @@
1
- import { type Permit, PermitUtils } from '@/permits';
1
+ import { type ACP, ACPUtils } from '@/acps';
2
2
 
3
3
  import { encodePacked, keccak256, type PublicClient } from 'viem';
4
4
  import { sign } from 'viem/accounts';
@@ -22,34 +22,34 @@ export type DecryptForTxMocksResult = {
22
22
  export async function cofheMocksDecryptForTx(
23
23
  ctHash: bigint | string,
24
24
  utype: FheTypes,
25
- permit: Permit | null,
25
+ acp: ACP | null,
26
26
  publicClient: PublicClient
27
27
  ): Promise<DecryptForTxMocksResult> {
28
28
  let allowed: boolean;
29
29
  let error: string;
30
30
  let decryptedValue: bigint;
31
31
 
32
- // With permit
33
- if (permit !== null) {
34
- let permission = PermitUtils.getPermission(permit, true);
32
+ // With acp
33
+ if (acp !== null) {
34
+ const wireAcp = ACPUtils.getPublic(acp, true);
35
35
  const permissionWithBigInts = {
36
- ...permission,
37
- expiration: BigInt(permission.expiration),
38
- validatorId: BigInt(permission.validatorId),
36
+ ...wireAcp,
37
+ expiration: BigInt(wireAcp.expiration),
38
+ revokerData: BigInt(wireAcp.revokerData),
39
39
  };
40
40
 
41
41
  [allowed, error, decryptedValue] = await publicClient.readContract({
42
42
  address: MOCKS_THRESHOLD_NETWORK_ADDRESS,
43
43
  abi: MockThresholdNetworkAbi,
44
- functionName: 'decryptForTxWithPermit',
44
+ functionName: 'decryptForTxWithACP',
45
45
  args: [BigInt(ctHash), permissionWithBigInts],
46
46
  });
47
47
  } else {
48
- // Without permit (global allowance)
48
+ // Without acp (global allowance)
49
49
  [allowed, error, decryptedValue] = await publicClient.readContract({
50
50
  address: MOCKS_THRESHOLD_NETWORK_ADDRESS,
51
51
  abi: MockThresholdNetworkAbi,
52
- functionName: 'decryptForTxWithoutPermit',
52
+ functionName: 'decryptForTxWithoutACP',
53
53
  args: [BigInt(ctHash)],
54
54
  });
55
55
  }
@@ -1,4 +1,4 @@
1
- import { type Permit, PermitUtils } from '@/permits';
1
+ import { type ACP, ACPUtils } from '@/acps';
2
2
 
3
3
  import { type PublicClient } from 'viem';
4
4
  import { MockThresholdNetworkAbi } from './MockThresholdNetworkAbi.js';
@@ -9,14 +9,14 @@ import { MOCKS_THRESHOLD_NETWORK_ADDRESS } from '../consts.js';
9
9
  export async function cofheMocksDecryptForView(
10
10
  ctHash: bigint | string,
11
11
  utype: FheTypes,
12
- permit: Permit,
12
+ acp: ACP,
13
13
  publicClient: PublicClient
14
14
  ): Promise<bigint> {
15
- const permission = PermitUtils.getPermission(permit, true);
15
+ const wireAcp = ACPUtils.getPublic(acp, true);
16
16
  const permissionWithBigInts = {
17
- ...permission,
18
- expiration: BigInt(permission.expiration),
19
- validatorId: BigInt(permission.validatorId),
17
+ ...wireAcp,
18
+ expiration: BigInt(wireAcp.expiration),
19
+ revokerData: BigInt(wireAcp.revokerData),
20
20
  };
21
21
 
22
22
  const [allowed, error, result] = await publicClient.readContract({
@@ -41,7 +41,7 @@ export async function cofheMocksDecryptForView(
41
41
  }
42
42
 
43
43
  const sealedBigInt = BigInt(result);
44
- const sealingKeyBigInt = BigInt(permission.sealingKey);
44
+ const sealingKeyBigInt = BigInt(acp.sealingKey);
45
45
  const unsealed = sealedBigInt ^ sealingKeyBigInt;
46
46
 
47
47
  return unsealed;
@@ -1,11 +1,11 @@
1
1
  /* eslint-disable no-dupe-class-members */
2
2
  import { hardhat } from '@/chains';
3
- import { type Permit, type Permission, PermitUtils } from '@/permits';
3
+ import { type ACP, type ACPPublic, ACPUtils } from '@/acps';
4
4
 
5
5
  import { FheTypes } from '../types';
6
6
  import { getThresholdNetworkUrlOrThrow } from '../config';
7
7
  import { CofheError, CofheErrorCode } from '../error';
8
- import { permits } from '../permits';
8
+ import { acps } from '../acps';
9
9
  import { BaseBuilder, type BaseBuilderParams } from '../baseBuilder';
10
10
  import { cofheMocksDecryptForTx } from './cofheMocksDecryptForTx';
11
11
  import { getPublicClientChainID, sleep } from '../utils';
@@ -20,23 +20,23 @@ const DEFAULT_404_RETRY_TIMEOUT_MS = 10_000;
20
20
  * await client.decryptForTx(ctHash)
21
21
  * .setChainId(chainId)
22
22
  * .setAccount(account)
23
- * .withPermit(permit | permitHash | undefined)
24
- * // or .withoutPermit()
23
+ * .withACP(acp | acpHash | undefined)
24
+ * // or .withoutACP()
25
25
  * .execute()
26
26
  *
27
27
  * If chainId not set, uses client's chainId
28
28
  * If account not set, uses client's account
29
- * You MUST choose one permit mode before calling execute():
30
- * - withPermit(...) to decrypt using a permit
31
- * - withoutPermit() to decrypt via global allowance (no permit)
29
+ * You MUST choose one acp mode before calling execute():
30
+ * - withACP(...) to decrypt using an ACP
31
+ * - withoutACP() to decrypt via global allowance (no acp)
32
32
  *
33
- * withPermit() (no args / undefined) uses the active permit for chainId + account.
34
- * withoutPermit() uses global allowance (no permit required).
33
+ * withACP() (no args / undefined) uses the active acp for chainId + account.
34
+ * withoutACP() uses global allowance (no acp required).
35
35
  *
36
36
  * Returns the decrypted value + proof ready for tx.
37
37
  */
38
38
 
39
- type DecryptForTxPermitSelection = 'unset' | 'with-permit' | 'without-permit';
39
+ type DecryptForTxACPSelection = 'unset' | 'with-acp' | 'without-acp';
40
40
 
41
41
  type DecryptForTxBuilderParams = BaseBuilderParams & {
42
42
  ctHash: bigint | string;
@@ -51,18 +51,18 @@ export type DecryptForTxResult = {
51
51
  /**
52
52
  * Type-level gating:
53
53
  * - The initial builder returned from `client.decryptForTx(...)` intentionally does not expose `execute()`.
54
- * - Calling `withPermit(...)` or `withoutPermit()` returns a builder that *does* expose `execute()`, but no longer
55
- * exposes `withPermit/withoutPermit` (so you can't select twice, or switch modes).
54
+ * - Calling `withACP(...)` or `withoutACP()` returns a builder that *does* expose `execute()`, but no longer
55
+ * exposes `withACP/withoutACP` (so you can't select twice, or switch modes).
56
56
  */
57
57
  export type DecryptForTxBuilderUnset = Omit<DecryptForTxBuilder, 'execute'>;
58
58
 
59
- export type DecryptForTxBuilderSelected = Omit<DecryptForTxBuilder, 'withPermit' | 'withoutPermit'>;
59
+ export type DecryptForTxBuilderSelected = Omit<DecryptForTxBuilder, 'withACP' | 'withoutACP'>;
60
60
 
61
61
  export class DecryptForTxBuilder extends BaseBuilder {
62
62
  private ctHash: bigint | string;
63
- private permitHash?: string;
64
- private permit?: Permit;
65
- private permitSelection: DecryptForTxPermitSelection = 'unset';
63
+ private acpHash?: string;
64
+ private acp?: ACP;
65
+ private acpSelection: DecryptForTxACPSelection = 'unset';
66
66
  private pollCallback?: DecryptPollCallbackFunction;
67
67
  private retry404TimeoutMs = DEFAULT_404_RETRY_TIMEOUT_MS;
68
68
 
@@ -80,7 +80,7 @@ export class DecryptForTxBuilder extends BaseBuilder {
80
80
  }
81
81
 
82
82
  /**
83
- * @param chainId - Chain to decrypt values from. Used to fetch the threshold network URL and use the correct permit.
83
+ * @param chainId - Chain to decrypt values from. Used to fetch the threshold network URL and use the correct acp.
84
84
  *
85
85
  * If not provided, the chainId will be fetched from the connected publicClient.
86
86
  *
@@ -105,7 +105,7 @@ export class DecryptForTxBuilder extends BaseBuilder {
105
105
  }
106
106
 
107
107
  /**
108
- * @param account - Account to decrypt values from. Used to fetch the correct permit.
108
+ * @param account - Account to decrypt values from. Used to fetch the correct acp.
109
109
  *
110
110
  * If not provided, the account will be fetched from the connected walletClient.
111
111
  *
@@ -154,86 +154,86 @@ export class DecryptForTxBuilder extends BaseBuilder {
154
154
  }
155
155
 
156
156
  /**
157
- * Select "use permit" mode.
157
+ * Select "use acp" mode.
158
158
  *
159
- * - `withPermit(permit)` uses the provided permit.
160
- * - `withPermit(permitHash)` fetches that permit.
161
- * - `withPermit()` uses the active permit for the resolved `chainId + account`.
159
+ * - `withACP(acp)` uses the provided acp.
160
+ * - `withACP(acpHash)` fetches that acp.
161
+ * - `withACP()` uses the active acp for the resolved `chainId + account`.
162
162
  *
163
- * Note: "global allowance" (no permit) is ONLY available via `withoutPermit()`.
163
+ * Note: "global allowance" (no acp) is ONLY available via `withoutACP()`.
164
164
  */
165
- withPermit(): DecryptForTxBuilderSelected;
166
- withPermit(permitHash: string): DecryptForTxBuilderSelected;
167
- withPermit(permit: Permit): DecryptForTxBuilderSelected;
168
- withPermit(permitOrPermitHash?: Permit | string): DecryptForTxBuilderSelected {
169
- if (this.permitSelection === 'with-permit') {
165
+ withACP(): DecryptForTxBuilderSelected;
166
+ withACP(acpHash: string): DecryptForTxBuilderSelected;
167
+ withACP(acp: ACP): DecryptForTxBuilderSelected;
168
+ withACP(acpOrACPHash?: ACP | string): DecryptForTxBuilderSelected {
169
+ if (this.acpSelection === 'with-acp') {
170
170
  throw new CofheError({
171
171
  code: CofheErrorCode.InternalError,
172
- message: 'decryptForTx: withPermit() can only be selected once.',
173
- hint: 'Choose the permit mode once. If you need a different permit, start a new decryptForTx() builder chain.',
172
+ message: 'decryptForTx: withACP() can only be selected once.',
173
+ hint: 'Choose the acp mode once. If you need a different acp, start a new decryptForTx() builder chain.',
174
174
  });
175
175
  }
176
176
 
177
- if (this.permitSelection === 'without-permit') {
177
+ if (this.acpSelection === 'without-acp') {
178
178
  throw new CofheError({
179
179
  code: CofheErrorCode.InternalError,
180
- message: 'decryptForTx: cannot call withPermit() after withoutPermit() has been selected.',
181
- hint: 'Choose exactly one permit mode: either call .withPermit(...) or .withoutPermit(), but not both.',
180
+ message: 'decryptForTx: cannot call withACP() after withoutACP() has been selected.',
181
+ hint: 'Choose exactly one acp mode: either call .withACP(...) or .withoutACP(), but not both.',
182
182
  });
183
183
  }
184
184
 
185
- this.permitSelection = 'with-permit';
185
+ this.acpSelection = 'with-acp';
186
186
 
187
- if (typeof permitOrPermitHash === 'string') {
188
- this.permitHash = permitOrPermitHash;
189
- this.permit = undefined;
190
- } else if (permitOrPermitHash === undefined) {
191
- // Explicitly choose "active permit" resolution at execute()
192
- this.permitHash = undefined;
193
- this.permit = undefined;
187
+ if (typeof acpOrACPHash === 'string') {
188
+ this.acpHash = acpOrACPHash;
189
+ this.acp = undefined;
190
+ } else if (acpOrACPHash === undefined) {
191
+ // Explicitly choose "active acp" resolution at execute()
192
+ this.acpHash = undefined;
193
+ this.acp = undefined;
194
194
  } else {
195
- // Permit object
196
- this.permit = permitOrPermitHash;
197
- this.permitHash = undefined;
195
+ // ACP object
196
+ this.acp = acpOrACPHash;
197
+ this.acpHash = undefined;
198
198
  }
199
199
 
200
200
  return this as unknown as DecryptForTxBuilderSelected;
201
201
  }
202
202
 
203
203
  /**
204
- * Select "no permit" mode.
204
+ * Select "no acp" mode.
205
205
  *
206
- * This uses global allowance (no permit required) and sends an empty permission payload to `/decrypt`.
206
+ * This uses global allowance (no acp required) and sends an empty permission payload to `/decrypt`.
207
207
  */
208
- withoutPermit(): DecryptForTxBuilderSelected {
209
- if (this.permitSelection === 'without-permit') {
208
+ withoutACP(): DecryptForTxBuilderSelected {
209
+ if (this.acpSelection === 'without-acp') {
210
210
  throw new CofheError({
211
211
  code: CofheErrorCode.InternalError,
212
- message: 'decryptForTx: withoutPermit() can only be selected once.',
213
- hint: 'Choose the permit mode once. If you need a different mode, start a new decryptForTx() builder chain.',
212
+ message: 'decryptForTx: withoutACP() can only be selected once.',
213
+ hint: 'Choose the acp mode once. If you need a different mode, start a new decryptForTx() builder chain.',
214
214
  });
215
215
  }
216
216
 
217
- if (this.permitSelection === 'with-permit') {
217
+ if (this.acpSelection === 'with-acp') {
218
218
  throw new CofheError({
219
219
  code: CofheErrorCode.InternalError,
220
- message: 'decryptForTx: cannot call withoutPermit() after withPermit() has been selected.',
221
- hint: 'Choose exactly one permit mode: either call .withPermit(...) or .withoutPermit(), but not both.',
220
+ message: 'decryptForTx: cannot call withoutACP() after withACP() has been selected.',
221
+ hint: 'Choose exactly one acp mode: either call .withACP(...) or .withoutACP(), but not both.',
222
222
  });
223
223
  }
224
224
 
225
- this.permitSelection = 'without-permit';
226
- this.permitHash = undefined;
227
- this.permit = undefined;
225
+ this.acpSelection = 'without-acp';
226
+ this.acpHash = undefined;
227
+ this.acp = undefined;
228
228
  return this as unknown as DecryptForTxBuilderSelected;
229
229
  }
230
230
 
231
- getPermit(): Permit | undefined {
232
- return this.permit;
231
+ getACP(): ACP | undefined {
232
+ return this.acp;
233
233
  }
234
234
 
235
- getPermitHash(): string | undefined {
236
- return this.permitHash;
235
+ getACPHash(): string | undefined {
236
+ return this.acpHash;
237
237
  }
238
238
 
239
239
  private async getThresholdNetworkUrl(): Promise<string> {
@@ -241,63 +241,63 @@ export class DecryptForTxBuilder extends BaseBuilder {
241
241
  return getThresholdNetworkUrlOrThrow(this.config, this.chainId);
242
242
  }
243
243
 
244
- private async getResolvedPermit(): Promise<Permit | null> {
245
- if (this.permitSelection === 'unset') {
244
+ private async getResolvedACP(): Promise<ACP | null> {
245
+ if (this.acpSelection === 'unset') {
246
246
  throw new CofheError({
247
247
  code: CofheErrorCode.InternalError,
248
- message: 'decryptForTx: missing permit selection; call withPermit(...) or withoutPermit() before execute().',
249
- hint: 'Call .withPermit() to use the active permit, or .withoutPermit() for global allowance.',
248
+ message: 'decryptForTx: missing acp selection; call withACP(...) or withoutACP() before execute().',
249
+ hint: 'Call .withACP() to use the active acp, or .withoutACP() for global allowance.',
250
250
  });
251
251
  }
252
252
 
253
- if (this.permitSelection === 'without-permit') {
253
+ if (this.acpSelection === 'without-acp') {
254
254
  return null;
255
255
  }
256
256
 
257
- // with-permit mode
258
- if (this.permit) return this.permit;
257
+ // with-acp mode
258
+ if (this.acp) return this.acp;
259
259
 
260
260
  this.assertChainId();
261
261
  this.assertAccount();
262
262
 
263
- // Fetch with permit hash
264
- if (this.permitHash) {
265
- const permit = await permits.getPermit(this.chainId, this.account, this.permitHash);
266
- if (!permit) {
263
+ // Fetch with acp hash
264
+ if (this.acpHash) {
265
+ const acp = await acps.getACP(this.chainId, this.account, this.acpHash);
266
+ if (!acp) {
267
267
  throw new CofheError({
268
- code: CofheErrorCode.PermitNotFound,
269
- message: `Permit with hash <${this.permitHash}> not found for account <${this.account}> and chainId <${this.chainId}>`,
270
- hint: 'Ensure the permit exists and is valid.',
268
+ code: CofheErrorCode.ACPNotFound,
269
+ message: `ACP with hash <${this.acpHash}> not found for account <${this.account}> and chainId <${this.chainId}>`,
270
+ hint: 'Ensure the acp exists and is valid.',
271
271
  context: {
272
272
  chainId: this.chainId,
273
273
  account: this.account,
274
- permitHash: this.permitHash,
274
+ acpHash: this.acpHash,
275
275
  },
276
276
  });
277
277
  }
278
- return permit;
278
+ return acp;
279
279
  }
280
280
 
281
- // Fetch active permit (default for withPermit() with no args)
282
- const permit = await permits.getActivePermit(this.chainId, this.account);
283
- if (!permit) {
281
+ // Fetch active acp (default for withACP() with no args)
282
+ const acp = await acps.getActiveACP(this.chainId, this.account);
283
+ if (!acp) {
284
284
  throw new CofheError({
285
- code: CofheErrorCode.PermitNotFound,
286
- message: `Active permit not found for chainId <${this.chainId}> and account <${this.account}>`,
287
- hint: 'Create a permit (e.g. client.permits.createSelf(...)) and/or set it active (client.permits.selectActivePermit(hash)).',
285
+ code: CofheErrorCode.ACPNotFound,
286
+ message: `Active acp not found for chainId <${this.chainId}> and account <${this.account}>`,
287
+ hint: 'Create an ACP (e.g. client.acp.createSelf(...)) and/or set it active (client.acp.selectActiveACP(hash)).',
288
288
  context: {
289
289
  chainId: this.chainId,
290
290
  account: this.account,
291
291
  },
292
292
  });
293
293
  }
294
- return permit;
294
+ return acp;
295
295
  }
296
296
 
297
297
  /**
298
298
  * On hardhat, interact with MockThresholdNetwork contract
299
299
  */
300
- private async mocksDecryptForTx(permit: Permit | null): Promise<DecryptForTxResult> {
300
+ private async mocksDecryptForTx(acp: ACP | null): Promise<DecryptForTxResult> {
301
301
  this.assertPublicClient();
302
302
 
303
303
  // Configurable delay before decrypting to simulate the CoFHE decrypt processing time
@@ -306,24 +306,24 @@ export class DecryptForTxBuilder extends BaseBuilder {
306
306
  const delay = this.config.mocks.decryptDelay;
307
307
  if (delay > 0) await sleep(delay);
308
308
 
309
- const result = await cofheMocksDecryptForTx(this.ctHash, 0 as FheTypes, permit, this.publicClient);
309
+ const result = await cofheMocksDecryptForTx(this.ctHash, 0 as FheTypes, acp, this.publicClient);
310
310
  return result;
311
311
  }
312
312
 
313
313
  /**
314
314
  * In the production context, perform a true decryption with the CoFHE coprocessor.
315
315
  */
316
- private async productionDecryptForTx(permit: Permit | null): Promise<DecryptForTxResult> {
316
+ private async productionDecryptForTx(acp: ACP | null): Promise<DecryptForTxResult> {
317
317
  this.assertChainId();
318
318
  this.assertPublicClient();
319
319
 
320
320
  const thresholdNetworkUrl = await this.getThresholdNetworkUrl();
321
321
 
322
- const permission = permit ? PermitUtils.getPermission(permit, true) : null;
322
+ const wireAcp = acp ? ACPUtils.getPublic(acp, true) : null;
323
323
  const { decryptedValue, signature } = await tnDecryptV2({
324
324
  ctHash: this.ctHash,
325
325
  chainId: this.chainId,
326
- permission,
326
+ acp: wireAcp,
327
327
  thresholdNetworkUrl,
328
328
  retry404TimeoutMs: this.retry404TimeoutMs,
329
329
  onPoll: this.pollCallback,
@@ -339,29 +339,29 @@ export class DecryptForTxBuilder extends BaseBuilder {
339
339
  /**
340
340
  * Final step of the decryptForTx process. MUST BE CALLED LAST IN THE CHAIN.
341
341
  *
342
- * You must explicitly choose one permit mode before calling `execute()`:
343
- * - `withPermit(permit)` / `withPermit(permitHash)` / `withPermit()` (active permit)
344
- * - `withoutPermit()` (global allowance)
342
+ * You must explicitly choose one acp mode before calling `execute()`:
343
+ * - `withACP(acp)` / `withACP(acpHash)` / `withACP()` (active acp)
344
+ * - `withoutACP()` (global allowance)
345
345
  */
346
346
  async execute(): Promise<DecryptForTxResult> {
347
- // Resolve permit (can be Permit object or null for global allowance)
348
- const permit = await this.getResolvedPermit();
347
+ // Resolve acp (can be ACP object or null for global allowance)
348
+ const acp = await this.getResolvedACP();
349
349
 
350
- // If permit is provided, validate it
351
- if (permit !== null) {
352
- // Ensure permit validity
353
- PermitUtils.validate(permit);
350
+ // If acp is provided, validate it
351
+ if (acp !== null) {
352
+ // Ensure acp validity
353
+ ACPUtils.validate(acp);
354
354
 
355
- // Extract chainId from signed permit
356
- const chainId = permit._signedDomain!.chainId;
355
+ // Extract chainId from signed acp
356
+ const chainId = acp._signedDomain!.chainId;
357
357
 
358
358
  if (chainId === hardhat.id) {
359
- return await this.mocksDecryptForTx(permit);
359
+ return await this.mocksDecryptForTx(acp);
360
360
  } else {
361
- return await this.productionDecryptForTx(permit);
361
+ return await this.productionDecryptForTx(acp);
362
362
  }
363
363
  } else {
364
- // Global allowance - no permit
364
+ // Global allowance - no acp
365
365
  // If chainId not set, try to get it from publicClient
366
366
  if (!this.chainId) {
367
367
  this.assertPublicClient();