@cofhe/sdk 0.2.1 → 0.3.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 (54) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/core/baseBuilder.ts +18 -18
  3. package/core/client.test.ts +58 -55
  4. package/core/client.ts +50 -30
  5. package/core/clientTypes.ts +21 -17
  6. package/core/config.test.ts +32 -33
  7. package/core/config.ts +47 -48
  8. package/core/consts.ts +6 -2
  9. package/core/decrypt/{MockQueryDecrypterAbi.ts → MockThresholdNetworkAbi.ts} +71 -21
  10. package/core/decrypt/cofheMocksDecryptForTx.ts +142 -0
  11. package/core/decrypt/{cofheMocksSealOutput.ts → cofheMocksDecryptForView.ts} +12 -12
  12. package/core/decrypt/decryptForTxBuilder.ts +340 -0
  13. package/core/decrypt/{decryptHandleBuilder.ts → decryptForViewBuilder.ts} +75 -42
  14. package/core/decrypt/tnDecrypt.ts +232 -0
  15. package/core/decrypt/tnSealOutputV1.ts +5 -5
  16. package/core/decrypt/tnSealOutputV2.ts +27 -27
  17. package/core/encrypt/cofheMocksZkVerifySign.ts +15 -15
  18. package/core/encrypt/encryptInputsBuilder.test.ts +57 -61
  19. package/core/encrypt/encryptInputsBuilder.ts +65 -42
  20. package/core/encrypt/zkPackProveVerify.ts +11 -11
  21. package/core/error.ts +18 -18
  22. package/core/fetchKeys.test.ts +3 -3
  23. package/core/fetchKeys.ts +3 -3
  24. package/core/index.ts +14 -11
  25. package/core/utils.ts +10 -10
  26. package/dist/{chunk-I5WFEYXX.js → chunk-2TPSCOW3.js} +791 -209
  27. package/dist/{chunk-R3B5TMVX.js → chunk-NWDKXBIP.js} +3 -2
  28. package/dist/{clientTypes-RqkgkV2i.d.ts → clientTypes-6aTZPQ_4.d.ts} +204 -85
  29. package/dist/{clientTypes-e4filDzK.d.cts → clientTypes-Bhq7pCSA.d.cts} +204 -85
  30. package/dist/core.cjs +799 -214
  31. package/dist/core.d.cts +25 -23
  32. package/dist/core.d.ts +25 -23
  33. package/dist/core.js +2 -2
  34. package/dist/node.cjs +748 -165
  35. package/dist/node.d.cts +10 -10
  36. package/dist/node.d.ts +10 -10
  37. package/dist/node.js +7 -7
  38. package/dist/permits.js +1 -1
  39. package/dist/web.cjs +751 -168
  40. package/dist/web.d.cts +11 -11
  41. package/dist/web.d.ts +11 -11
  42. package/dist/web.js +9 -9
  43. package/node/client.test.ts +34 -34
  44. package/node/config.test.ts +11 -11
  45. package/node/encryptInputs.test.ts +29 -29
  46. package/node/index.ts +15 -15
  47. package/package.json +1 -1
  48. package/web/client.web.test.ts +34 -34
  49. package/web/config.web.test.ts +11 -11
  50. package/web/encryptInputs.web.test.ts +29 -29
  51. package/web/index.ts +19 -19
  52. package/web/worker.builder.web.test.ts +28 -28
  53. package/web/worker.config.web.test.ts +47 -47
  54. package/web/worker.output.web.test.ts +10 -10
@@ -2,22 +2,22 @@ import { type Permit, PermitUtils } from '@/permits';
2
2
 
3
3
  import { type PublicClient } from 'viem';
4
4
  import { sleep } from '../utils.js';
5
- import { MockQueryDecrypterAbi } from './MockQueryDecrypterAbi.js';
5
+ import { MockThresholdNetworkAbi } from './MockThresholdNetworkAbi.js';
6
6
  import { FheTypes } from '../types.js';
7
- import { CofhesdkError, CofhesdkErrorCode } from '../error.js';
8
- import { MOCKS_QUERY_DECRYPTER_ADDRESS } from '../consts.js';
7
+ import { CofheError, CofheErrorCode } from '../error.js';
8
+ import { MOCKS_THRESHOLD_NETWORK_ADDRESS } from '../consts.js';
9
9
 
10
- export async function cofheMocksSealOutput(
10
+ export async function cofheMocksDecryptForView(
11
11
  ctHash: bigint,
12
12
  utype: FheTypes,
13
13
  permit: Permit,
14
14
  publicClient: PublicClient,
15
- mocksSealOutputDelay: number
15
+ mocksDecryptDelay: number
16
16
  ): Promise<bigint> {
17
17
  // Configurable delay before decrypting the output to simulate the CoFHE decrypt processing time
18
18
  // Recommended 1000ms on web
19
19
  // Recommended 0ms on hardhat (will be called during tests no need for fake delay)
20
- if (mocksSealOutputDelay > 0) await sleep(mocksSealOutputDelay);
20
+ if (mocksDecryptDelay > 0) await sleep(mocksDecryptDelay);
21
21
 
22
22
  const permission = PermitUtils.getPermission(permit, true);
23
23
  const permissionWithBigInts = {
@@ -27,22 +27,22 @@ export async function cofheMocksSealOutput(
27
27
  };
28
28
 
29
29
  const [allowed, error, result] = await publicClient.readContract({
30
- address: MOCKS_QUERY_DECRYPTER_ADDRESS,
31
- abi: MockQueryDecrypterAbi,
30
+ address: MOCKS_THRESHOLD_NETWORK_ADDRESS,
31
+ abi: MockThresholdNetworkAbi,
32
32
  functionName: 'querySealOutput',
33
33
  args: [ctHash, BigInt(utype), permissionWithBigInts],
34
34
  });
35
35
 
36
36
  if (error != '') {
37
- throw new CofhesdkError({
38
- code: CofhesdkErrorCode.SealOutputFailed,
37
+ throw new CofheError({
38
+ code: CofheErrorCode.SealOutputFailed,
39
39
  message: `mocks querySealOutput call failed: ${error}`,
40
40
  });
41
41
  }
42
42
 
43
43
  if (allowed == false) {
44
- throw new CofhesdkError({
45
- code: CofhesdkErrorCode.SealOutputFailed,
44
+ throw new CofheError({
45
+ code: CofheErrorCode.SealOutputFailed,
46
46
  message: `mocks querySealOutput call failed: ACL Access Denied (NotAllowed)`,
47
47
  });
48
48
  }
@@ -0,0 +1,340 @@
1
+ /* eslint-disable no-dupe-class-members */
2
+ import { hardhat } from '@/chains';
3
+ import { type Permit, type Permission, PermitUtils } from '@/permits';
4
+
5
+ import { FheTypes } from '../types.js';
6
+ import { getThresholdNetworkUrlOrThrow } from '../config.js';
7
+ import { CofheError, CofheErrorCode } from '../error.js';
8
+ import { permits } from '../permits.js';
9
+ import { BaseBuilder, type BaseBuilderParams } from '../baseBuilder.js';
10
+ import { cofheMocksDecryptForTx } from './cofheMocksDecryptForTx.js';
11
+ import { getPublicClientChainID } from '../utils.js';
12
+ import { tnDecrypt } from './tnDecrypt.js';
13
+
14
+ /**
15
+ * API
16
+ *
17
+ * await client.decryptForTx(ctHash)
18
+ * .setChainId(chainId)
19
+ * .setAccount(account)
20
+ * .withPermit(permit | permitHash | undefined)
21
+ * // or .withoutPermit()
22
+ * .execute()
23
+ *
24
+ * If chainId not set, uses client's chainId
25
+ * If account not set, uses client's account
26
+ * You MUST choose one permit mode before calling execute():
27
+ * - withPermit(...) to decrypt using a permit
28
+ * - withoutPermit() to decrypt via global allowance (no permit)
29
+ *
30
+ * withPermit() (no args / undefined) uses the active permit for chainId + account.
31
+ * withoutPermit() uses global allowance (no permit required).
32
+ *
33
+ * Returns the decrypted value + proof ready for tx.
34
+ */
35
+
36
+ type DecryptForTxPermitSelection = 'unset' | 'with-permit' | 'without-permit';
37
+
38
+ type DecryptForTxBuilderParams = BaseBuilderParams & {
39
+ ctHash: bigint;
40
+ };
41
+
42
+ export type DecryptForTxResult = {
43
+ ctHash: bigint;
44
+ decryptedValue: bigint;
45
+ signature: string; // Threshold network signature for publishDecryptResult
46
+ };
47
+
48
+ /**
49
+ * Type-level gating:
50
+ * - The initial builder returned from `client.decryptForTx(...)` intentionally does not expose `execute()`.
51
+ * - Calling `withPermit(...)` or `withoutPermit()` returns a builder that *does* expose `execute()`, but no longer
52
+ * exposes `withPermit/withoutPermit` (so you can't select twice, or switch modes).
53
+ */
54
+ export type DecryptForTxBuilderUnset = Omit<DecryptForTxBuilder, 'execute'>;
55
+
56
+ export type DecryptForTxBuilderSelected = Omit<DecryptForTxBuilder, 'withPermit' | 'withoutPermit'>;
57
+
58
+ export class DecryptForTxBuilder extends BaseBuilder {
59
+ private ctHash: bigint;
60
+ private permitHash?: string;
61
+ private permit?: Permit;
62
+ private permitSelection: DecryptForTxPermitSelection = 'unset';
63
+
64
+ constructor(params: DecryptForTxBuilderParams) {
65
+ super({
66
+ config: params.config,
67
+ publicClient: params.publicClient,
68
+ walletClient: params.walletClient,
69
+ chainId: params.chainId,
70
+ account: params.account,
71
+ requireConnected: params.requireConnected,
72
+ });
73
+
74
+ this.ctHash = params.ctHash;
75
+ }
76
+
77
+ /**
78
+ * @param chainId - Chain to decrypt values from. Used to fetch the threshold network URL and use the correct permit.
79
+ *
80
+ * If not provided, the chainId will be fetched from the connected publicClient.
81
+ *
82
+ * Example:
83
+ * ```typescript
84
+ * const result = await decryptForTx(ctHash)
85
+ * .setChainId(11155111)
86
+ * .execute();
87
+ * ```
88
+ *
89
+ * @returns The chainable DecryptForTxBuilder instance.
90
+ */
91
+ setChainId(this: DecryptForTxBuilderUnset, chainId: number): DecryptForTxBuilderUnset;
92
+ setChainId(this: DecryptForTxBuilderSelected, chainId: number): DecryptForTxBuilderSelected;
93
+ setChainId(chainId: number): DecryptForTxBuilder {
94
+ this.chainId = chainId;
95
+ return this;
96
+ }
97
+
98
+ getChainId(): number | undefined {
99
+ return this.chainId;
100
+ }
101
+
102
+ /**
103
+ * @param account - Account to decrypt values from. Used to fetch the correct permit.
104
+ *
105
+ * If not provided, the account will be fetched from the connected walletClient.
106
+ *
107
+ * Example:
108
+ * ```typescript
109
+ * const result = await decryptForTx(ctHash)
110
+ * .setAccount('0x1234567890123456789012345678901234567890')
111
+ * .execute();
112
+ * ```
113
+ *
114
+ * @returns The chainable DecryptForTxBuilder instance.
115
+ */
116
+ setAccount(this: DecryptForTxBuilderUnset, account: string): DecryptForTxBuilderUnset;
117
+ setAccount(this: DecryptForTxBuilderSelected, account: string): DecryptForTxBuilderSelected;
118
+ setAccount(account: string): DecryptForTxBuilder {
119
+ this.account = account;
120
+ return this;
121
+ }
122
+
123
+ getAccount(): string | undefined {
124
+ return this.account;
125
+ }
126
+
127
+ /**
128
+ * Select "use permit" mode.
129
+ *
130
+ * - `withPermit(permit)` uses the provided permit.
131
+ * - `withPermit(permitHash)` fetches that permit.
132
+ * - `withPermit()` uses the active permit for the resolved `chainId + account`.
133
+ *
134
+ * Note: "global allowance" (no permit) is ONLY available via `withoutPermit()`.
135
+ */
136
+ withPermit(): DecryptForTxBuilderSelected;
137
+ withPermit(permitHash: string): DecryptForTxBuilderSelected;
138
+ withPermit(permit: Permit): DecryptForTxBuilderSelected;
139
+ withPermit(permitOrPermitHash?: Permit | string): DecryptForTxBuilderSelected {
140
+ if (this.permitSelection === 'with-permit') {
141
+ throw new CofheError({
142
+ code: CofheErrorCode.InternalError,
143
+ message: 'decryptForTx: withPermit() can only be selected once.',
144
+ hint: 'Choose the permit mode once. If you need a different permit, start a new decryptForTx() builder chain.',
145
+ });
146
+ }
147
+
148
+ if (this.permitSelection === 'without-permit') {
149
+ throw new CofheError({
150
+ code: CofheErrorCode.InternalError,
151
+ message: 'decryptForTx: cannot call withPermit() after withoutPermit() has been selected.',
152
+ hint: 'Choose exactly one permit mode: either call .withPermit(...) or .withoutPermit(), but not both.',
153
+ });
154
+ }
155
+
156
+ this.permitSelection = 'with-permit';
157
+
158
+ if (typeof permitOrPermitHash === 'string') {
159
+ this.permitHash = permitOrPermitHash;
160
+ this.permit = undefined;
161
+ } else if (permitOrPermitHash === undefined) {
162
+ // Explicitly choose "active permit" resolution at execute()
163
+ this.permitHash = undefined;
164
+ this.permit = undefined;
165
+ } else {
166
+ // Permit object
167
+ this.permit = permitOrPermitHash;
168
+ this.permitHash = undefined;
169
+ }
170
+
171
+ return this as unknown as DecryptForTxBuilderSelected;
172
+ }
173
+
174
+ /**
175
+ * Select "no permit" mode.
176
+ *
177
+ * This uses global allowance (no permit required) and sends an empty permission payload to `/decrypt`.
178
+ */
179
+ withoutPermit(): DecryptForTxBuilderSelected {
180
+ if (this.permitSelection === 'without-permit') {
181
+ throw new CofheError({
182
+ code: CofheErrorCode.InternalError,
183
+ message: 'decryptForTx: withoutPermit() can only be selected once.',
184
+ hint: 'Choose the permit mode once. If you need a different mode, start a new decryptForTx() builder chain.',
185
+ });
186
+ }
187
+
188
+ if (this.permitSelection === 'with-permit') {
189
+ throw new CofheError({
190
+ code: CofheErrorCode.InternalError,
191
+ message: 'decryptForTx: cannot call withoutPermit() after withPermit() has been selected.',
192
+ hint: 'Choose exactly one permit mode: either call .withPermit(...) or .withoutPermit(), but not both.',
193
+ });
194
+ }
195
+
196
+ this.permitSelection = 'without-permit';
197
+ this.permitHash = undefined;
198
+ this.permit = undefined;
199
+ return this as unknown as DecryptForTxBuilderSelected;
200
+ }
201
+
202
+ getPermit(): Permit | undefined {
203
+ return this.permit;
204
+ }
205
+
206
+ getPermitHash(): string | undefined {
207
+ return this.permitHash;
208
+ }
209
+
210
+ private async getThresholdNetworkUrl(): Promise<string> {
211
+ this.assertChainId();
212
+ return getThresholdNetworkUrlOrThrow(this.config, this.chainId);
213
+ }
214
+
215
+ private async getResolvedPermit(): Promise<Permit | null> {
216
+ if (this.permitSelection === 'unset') {
217
+ throw new CofheError({
218
+ code: CofheErrorCode.InternalError,
219
+ message: 'decryptForTx: missing permit selection; call withPermit(...) or withoutPermit() before execute().',
220
+ hint: 'Call .withPermit() to use the active permit, or .withoutPermit() for global allowance.',
221
+ });
222
+ }
223
+
224
+ if (this.permitSelection === 'without-permit') {
225
+ return null;
226
+ }
227
+
228
+ // with-permit mode
229
+ if (this.permit) return this.permit;
230
+
231
+ this.assertChainId();
232
+ this.assertAccount();
233
+
234
+ // Fetch with permit hash
235
+ if (this.permitHash) {
236
+ const permit = await permits.getPermit(this.chainId, this.account, this.permitHash);
237
+ if (!permit) {
238
+ throw new CofheError({
239
+ code: CofheErrorCode.PermitNotFound,
240
+ message: `Permit with hash <${this.permitHash}> not found for account <${this.account}> and chainId <${this.chainId}>`,
241
+ hint: 'Ensure the permit exists and is valid.',
242
+ context: {
243
+ chainId: this.chainId,
244
+ account: this.account,
245
+ permitHash: this.permitHash,
246
+ },
247
+ });
248
+ }
249
+ return permit;
250
+ }
251
+
252
+ // Fetch active permit (default for withPermit() with no args)
253
+ const permit = await permits.getActivePermit(this.chainId, this.account);
254
+ if (!permit) {
255
+ throw new CofheError({
256
+ code: CofheErrorCode.PermitNotFound,
257
+ message: `Active permit not found for chainId <${this.chainId}> and account <${this.account}>`,
258
+ hint: 'Create a permit (e.g. client.permits.createSelf(...)) and/or set it active (client.permits.selectActivePermit(hash)).',
259
+ context: {
260
+ chainId: this.chainId,
261
+ account: this.account,
262
+ },
263
+ });
264
+ }
265
+ return permit;
266
+ }
267
+
268
+ /**
269
+ * On hardhat, interact with MockThresholdNetwork contract
270
+ */
271
+ private async mocksDecryptForTx(permit: Permit | null): Promise<DecryptForTxResult> {
272
+ this.assertPublicClient();
273
+
274
+ const delay = this.config.mocks.decryptDelay;
275
+ const result = await cofheMocksDecryptForTx(this.ctHash, 0 as FheTypes, permit, this.publicClient, delay);
276
+ return result;
277
+ }
278
+
279
+ /**
280
+ * In the production context, perform a true decryption with the CoFHE coprocessor.
281
+ */
282
+ private async productionDecryptForTx(permit: Permit | null): Promise<DecryptForTxResult> {
283
+ this.assertChainId();
284
+ this.assertPublicClient();
285
+
286
+ const thresholdNetworkUrl = await this.getThresholdNetworkUrl();
287
+
288
+ const permission = permit ? PermitUtils.getPermission(permit, true) : null;
289
+ const { decryptedValue, signature } = await tnDecrypt(this.ctHash, this.chainId, permission, thresholdNetworkUrl);
290
+
291
+ return {
292
+ ctHash: this.ctHash,
293
+ decryptedValue,
294
+ signature,
295
+ };
296
+ }
297
+
298
+ /**
299
+ * Final step of the decryptForTx process. MUST BE CALLED LAST IN THE CHAIN.
300
+ *
301
+ * You must explicitly choose one permit mode before calling `execute()`:
302
+ * - `withPermit(permit)` / `withPermit(permitHash)` / `withPermit()` (active permit)
303
+ * - `withoutPermit()` (global allowance)
304
+ */
305
+ async execute(): Promise<DecryptForTxResult> {
306
+ // Resolve permit (can be Permit object or null for global allowance)
307
+ const permit = await this.getResolvedPermit();
308
+
309
+ // If permit is provided, validate it
310
+ if (permit !== null) {
311
+ // Ensure permit validity
312
+ PermitUtils.validate(permit);
313
+ PermitUtils.isValid(permit);
314
+
315
+ // Extract chainId from signed permit
316
+ const chainId = permit._signedDomain!.chainId;
317
+
318
+ if (chainId === hardhat.id) {
319
+ return await this.mocksDecryptForTx(permit);
320
+ } else {
321
+ return await this.productionDecryptForTx(permit);
322
+ }
323
+ } else {
324
+ // Global allowance - no permit
325
+ // If chainId not set, try to get it from publicClient
326
+ if (!this.chainId) {
327
+ this.assertPublicClient();
328
+ this.chainId = await getPublicClientChainID(this.publicClient);
329
+ }
330
+
331
+ this.assertChainId();
332
+
333
+ if (this.chainId === hardhat.id) {
334
+ return await this.mocksDecryptForTx(null);
335
+ } else {
336
+ return await this.productionDecryptForTx(null);
337
+ }
338
+ }
339
+ }
340
+ }
@@ -1,48 +1,53 @@
1
+ /* eslint-disable no-dupe-class-members */
1
2
  import { hardhat } from '@/chains';
2
3
  import { type Permit, PermitUtils } from '@/permits';
3
4
 
4
5
  import { FheTypes, type UnsealedItem } from '../types.js';
5
6
  import { getThresholdNetworkUrlOrThrow } from '../config.js';
6
- import { CofhesdkError, CofhesdkErrorCode } from '../error.js';
7
+ import { CofheError, CofheErrorCode } from '../error.js';
7
8
  import { permits } from '../permits.js';
8
9
  import { isValidUtype, convertViaUtype } from './decryptUtils.js';
9
10
  import { BaseBuilder, type BaseBuilderParams } from '../baseBuilder.js';
10
- import { cofheMocksSealOutput } from './cofheMocksSealOutput.js';
11
+ import { cofheMocksDecryptForView } from './cofheMocksDecryptForView.js';
11
12
  // import { tnSealOutputV1 } from './tnSealOutputV1.js';
12
13
  import { tnSealOutputV2 } from './tnSealOutputV2.js';
14
+ import { cofheMocksDecryptForTx } from './cofheMocksDecryptForTx.js';
13
15
 
14
16
  /**
15
17
  * API
16
18
  *
17
- * await client.decryptHandle(ctHash, utype)
19
+ * await client.decryptForView(ctHash, utype)
18
20
  * .setChainId(chainId)
19
21
  * .setAccount(account)
20
- * .setPermitHash(permitHash)
21
- * .setPermit(permit)
22
- * .decrypt()
22
+ * .withPermit() // optional (active permit)
23
+ * // or .withPermit(permitHash) / .withPermit(permit)
24
+ * .execute()
23
25
  *
24
26
  * If chainId not set, uses client's chainId
25
27
  * If account not set, uses client's account
26
- * If permitHash not set, uses chainId and account to get active permit
27
- * If permit is set, uses permit to decrypt regardless of chainId, account, or permitHash
28
+ * withPermit() uses chainId + account to get the active permit.
29
+ * withPermit(permitHash) fetches that permit using chainId + account.
30
+ * withPermit(permit) uses the provided permit regardless of chainId/account.
31
+ *
32
+ * Note: decryptForView always requires a permit (no global-allowance mode).
28
33
  *
29
34
  * Returns the unsealed item.
30
35
  */
31
36
 
32
- type DecryptHandlesBuilderParams<U extends FheTypes> = BaseBuilderParams & {
37
+ type DecryptForViewBuilderParams<U extends FheTypes> = BaseBuilderParams & {
33
38
  ctHash: bigint;
34
39
  utype: U;
35
40
  permitHash?: string;
36
41
  permit?: Permit;
37
42
  };
38
43
 
39
- export class DecryptHandlesBuilder<U extends FheTypes> extends BaseBuilder {
44
+ export class DecryptForViewBuilder<U extends FheTypes> extends BaseBuilder {
40
45
  private ctHash: bigint;
41
46
  private utype: U;
42
47
  private permitHash?: string;
43
48
  private permit?: Permit;
44
49
 
45
- constructor(params: DecryptHandlesBuilderParams<U>) {
50
+ constructor(params: DecryptForViewBuilderParams<U>) {
46
51
  super({
47
52
  config: params.config,
48
53
  publicClient: params.publicClient,
@@ -65,14 +70,14 @@ export class DecryptHandlesBuilder<U extends FheTypes> extends BaseBuilder {
65
70
  *
66
71
  * Example:
67
72
  * ```typescript
68
- * const unsealed = await decryptHandle(ctHash, utype)
73
+ * const unsealed = await client.decryptForView(ctHash, utype)
69
74
  * .setChainId(11155111)
70
- * .decrypt();
75
+ * .execute();
71
76
  * ```
72
77
  *
73
- * @returns The chainable DecryptHandlesBuilder instance.
78
+ * @returns The chainable DecryptForViewBuilder instance.
74
79
  */
75
- setChainId(chainId: number): DecryptHandlesBuilder<U> {
80
+ setChainId(chainId: number): DecryptForViewBuilder<U> {
76
81
  this.chainId = chainId;
77
82
  return this;
78
83
  }
@@ -88,14 +93,14 @@ export class DecryptHandlesBuilder<U extends FheTypes> extends BaseBuilder {
88
93
  *
89
94
  * Example:
90
95
  * ```typescript
91
- * const unsealed = await decryptHandle(ctHash, utype)
96
+ * const unsealed = await client.decryptForView(ctHash, utype)
92
97
  * .setAccount('0x1234567890123456789012345678901234567890')
93
- * .decrypt();
98
+ * .execute();
94
99
  * ```
95
100
  *
96
- * @returns The chainable DecryptHandlesBuilder instance.
101
+ * @returns The chainable DecryptForViewBuilder instance.
97
102
  */
98
- setAccount(account: string): DecryptHandlesBuilder<U> {
103
+ setAccount(account: string): DecryptForViewBuilder<U> {
99
104
  this.account = account;
100
105
  return this;
101
106
  }
@@ -104,6 +109,33 @@ export class DecryptHandlesBuilder<U extends FheTypes> extends BaseBuilder {
104
109
  return this.account;
105
110
  }
106
111
 
112
+ /**
113
+ * Select "use permit" mode (optional).
114
+ *
115
+ * - `withPermit(permit)` uses the provided permit.
116
+ * - `withPermit(permitHash)` fetches that permit.
117
+ * - `withPermit()` uses the active permit for the resolved `chainId + account`.
118
+ */
119
+ withPermit(): DecryptForViewBuilder<U>;
120
+ withPermit(permitHash: string): DecryptForViewBuilder<U>;
121
+ withPermit(permit: Permit): DecryptForViewBuilder<U>;
122
+ withPermit(permitOrPermitHash?: Permit | string): DecryptForViewBuilder<U> {
123
+ if (typeof permitOrPermitHash === 'string') {
124
+ this.permitHash = permitOrPermitHash;
125
+ this.permit = undefined;
126
+ } else if (permitOrPermitHash === undefined) {
127
+ // Explicitly choose "active permit" resolution at execute()
128
+ this.permitHash = undefined;
129
+ this.permit = undefined;
130
+ } else {
131
+ // Permit object
132
+ this.permit = permitOrPermitHash;
133
+ this.permitHash = undefined;
134
+ }
135
+
136
+ return this;
137
+ }
138
+
107
139
  /**
108
140
  * @param permitHash - Permit hash to decrypt values from. Used to fetch the correct permit.
109
141
  *
@@ -112,16 +144,16 @@ export class DecryptHandlesBuilder<U extends FheTypes> extends BaseBuilder {
112
144
  *
113
145
  * Example:
114
146
  * ```typescript
115
- * const unsealed = await decryptHandle(ctHash, utype)
147
+ * const unsealed = await client.decryptForView(ctHash, utype)
116
148
  * .setPermitHash('0x1234567890123456789012345678901234567890')
117
- * .decrypt();
149
+ * .execute();
118
150
  * ```
119
151
  *
120
- * @returns The chainable DecryptHandlesBuilder instance.
152
+ * @returns The chainable DecryptForViewBuilder instance.
121
153
  */
122
- setPermitHash(permitHash: string): DecryptHandlesBuilder<U> {
123
- this.permitHash = permitHash;
124
- return this;
154
+ /** @deprecated Use `withPermit(permitHash)` instead. */
155
+ setPermitHash(permitHash: string): DecryptForViewBuilder<U> {
156
+ return this.withPermit(permitHash);
125
157
  }
126
158
 
127
159
  getPermitHash(): string | undefined {
@@ -135,16 +167,16 @@ export class DecryptHandlesBuilder<U extends FheTypes> extends BaseBuilder {
135
167
  *
136
168
  * Example:
137
169
  * ```typescript
138
- * const unsealed = await decryptHandle(ctHash, utype)
170
+ * const unsealed = await client.decryptForView(ctHash, utype)
139
171
  * .setPermit(permit)
140
- * .decrypt();
172
+ * .execute();
141
173
  * ```
142
174
  *
143
- * @returns The chainable DecryptHandlesBuilder instance.
175
+ * @returns The chainable DecryptForViewBuilder instance.
144
176
  */
145
- setPermit(permit: Permit): DecryptHandlesBuilder<U> {
146
- this.permit = permit;
147
- return this;
177
+ /** @deprecated Use `withPermit(permit)` instead. */
178
+ setPermit(permit: Permit): DecryptForViewBuilder<U> {
179
+ return this.withPermit(permit);
148
180
  }
149
181
 
150
182
  getPermit(): Permit | undefined {
@@ -158,8 +190,8 @@ export class DecryptHandlesBuilder<U extends FheTypes> extends BaseBuilder {
158
190
 
159
191
  private validateUtypeOrThrow(): void {
160
192
  if (!isValidUtype(this.utype))
161
- throw new CofhesdkError({
162
- code: CofhesdkErrorCode.InvalidUtype,
193
+ throw new CofheError({
194
+ code: CofheErrorCode.InvalidUtype,
163
195
  message: `Invalid utype to decrypt to`,
164
196
  context: {
165
197
  utype: this.utype,
@@ -177,8 +209,8 @@ export class DecryptHandlesBuilder<U extends FheTypes> extends BaseBuilder {
177
209
  if (this.permitHash) {
178
210
  const permit = await permits.getPermit(this.chainId, this.account, this.permitHash);
179
211
  if (!permit) {
180
- throw new CofhesdkError({
181
- code: CofhesdkErrorCode.PermitNotFound,
212
+ throw new CofheError({
213
+ code: CofheErrorCode.PermitNotFound,
182
214
  message: `Permit with hash <${this.permitHash}> not found for account <${this.account}> and chainId <${this.chainId}>`,
183
215
  hint: 'Ensure the permit exists and is valid.',
184
216
  context: {
@@ -194,8 +226,8 @@ export class DecryptHandlesBuilder<U extends FheTypes> extends BaseBuilder {
194
226
  // Fetch with active permit
195
227
  const permit = await permits.getActivePermit(this.chainId, this.account);
196
228
  if (!permit) {
197
- throw new CofhesdkError({
198
- code: CofhesdkErrorCode.PermitNotFound,
229
+ throw new CofheError({
230
+ code: CofheErrorCode.PermitNotFound,
199
231
  message: `Active permit not found for chainId <${this.chainId}> and account <${this.account}>`,
200
232
  hint: 'Ensure a permit exists for this account on this chain.',
201
233
  context: {
@@ -213,8 +245,8 @@ export class DecryptHandlesBuilder<U extends FheTypes> extends BaseBuilder {
213
245
  private async mocksSealOutput(permit: Permit): Promise<bigint> {
214
246
  this.assertPublicClient();
215
247
 
216
- const mocksSealOutputDelay = this.config.mocks.sealOutputDelay;
217
- return cofheMocksSealOutput(this.ctHash, this.utype, permit, this.publicClient, mocksSealOutputDelay);
248
+ const mocksDecryptDelay = this.config.mocks.decryptDelay;
249
+ return cofheMocksDecryptForView(this.ctHash, this.utype, permit, this.publicClient, mocksDecryptDelay);
218
250
  }
219
251
 
220
252
  /**
@@ -243,15 +275,16 @@ export class DecryptHandlesBuilder<U extends FheTypes> extends BaseBuilder {
243
275
  *
244
276
  * Example:
245
277
  * ```typescript
246
- * const unsealed = await decryptHandle(ctHash, utype)
278
+ * const unsealed = await client.decryptForView(ctHash, utype)
247
279
  * .setChainId(11155111) // optional
248
280
  * .setAccount('0x123...890') // optional
249
- * .decrypt(); // execute
281
+ * .withPermit() // optional
282
+ * .execute(); // execute
250
283
  * ```
251
284
  *
252
285
  * @returns The unsealed item.
253
286
  */
254
- async decrypt(): Promise<UnsealedItem<U>> {
287
+ async execute(): Promise<UnsealedItem<U>> {
255
288
  // Ensure utype is valid
256
289
  this.validateUtypeOrThrow();
257
290