@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.
- package/CHANGELOG.md +28 -0
- package/core/baseBuilder.ts +18 -18
- package/core/client.test.ts +58 -55
- package/core/client.ts +50 -30
- package/core/clientTypes.ts +21 -17
- package/core/config.test.ts +32 -33
- package/core/config.ts +47 -48
- package/core/consts.ts +6 -2
- package/core/decrypt/{MockQueryDecrypterAbi.ts → MockThresholdNetworkAbi.ts} +71 -21
- package/core/decrypt/cofheMocksDecryptForTx.ts +142 -0
- package/core/decrypt/{cofheMocksSealOutput.ts → cofheMocksDecryptForView.ts} +12 -12
- package/core/decrypt/decryptForTxBuilder.ts +340 -0
- package/core/decrypt/{decryptHandleBuilder.ts → decryptForViewBuilder.ts} +75 -42
- package/core/decrypt/tnDecrypt.ts +232 -0
- package/core/decrypt/tnSealOutputV1.ts +5 -5
- package/core/decrypt/tnSealOutputV2.ts +27 -27
- package/core/encrypt/cofheMocksZkVerifySign.ts +15 -15
- package/core/encrypt/encryptInputsBuilder.test.ts +57 -61
- package/core/encrypt/encryptInputsBuilder.ts +65 -42
- package/core/encrypt/zkPackProveVerify.ts +11 -11
- package/core/error.ts +18 -18
- package/core/fetchKeys.test.ts +3 -3
- package/core/fetchKeys.ts +3 -3
- package/core/index.ts +14 -11
- package/core/utils.ts +10 -10
- package/dist/{chunk-I5WFEYXX.js → chunk-2TPSCOW3.js} +791 -209
- package/dist/{chunk-R3B5TMVX.js → chunk-NWDKXBIP.js} +3 -2
- package/dist/{clientTypes-RqkgkV2i.d.ts → clientTypes-6aTZPQ_4.d.ts} +204 -85
- package/dist/{clientTypes-e4filDzK.d.cts → clientTypes-Bhq7pCSA.d.cts} +204 -85
- package/dist/core.cjs +799 -214
- package/dist/core.d.cts +25 -23
- package/dist/core.d.ts +25 -23
- package/dist/core.js +2 -2
- package/dist/node.cjs +748 -165
- package/dist/node.d.cts +10 -10
- package/dist/node.d.ts +10 -10
- package/dist/node.js +7 -7
- package/dist/permits.js +1 -1
- package/dist/web.cjs +751 -168
- package/dist/web.d.cts +11 -11
- package/dist/web.d.ts +11 -11
- package/dist/web.js +9 -9
- package/node/client.test.ts +34 -34
- package/node/config.test.ts +11 -11
- package/node/encryptInputs.test.ts +29 -29
- package/node/index.ts +15 -15
- package/package.json +1 -1
- package/web/client.web.test.ts +34 -34
- package/web/config.web.test.ts +11 -11
- package/web/encryptInputs.web.test.ts +29 -29
- package/web/index.ts +19 -19
- package/web/worker.builder.web.test.ts +28 -28
- package/web/worker.config.web.test.ts +47 -47
- 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 {
|
|
5
|
+
import { MockThresholdNetworkAbi } from './MockThresholdNetworkAbi.js';
|
|
6
6
|
import { FheTypes } from '../types.js';
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { CofheError, CofheErrorCode } from '../error.js';
|
|
8
|
+
import { MOCKS_THRESHOLD_NETWORK_ADDRESS } from '../consts.js';
|
|
9
9
|
|
|
10
|
-
export async function
|
|
10
|
+
export async function cofheMocksDecryptForView(
|
|
11
11
|
ctHash: bigint,
|
|
12
12
|
utype: FheTypes,
|
|
13
13
|
permit: Permit,
|
|
14
14
|
publicClient: PublicClient,
|
|
15
|
-
|
|
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 (
|
|
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:
|
|
31
|
-
abi:
|
|
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
|
|
38
|
-
code:
|
|
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
|
|
45
|
-
code:
|
|
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 {
|
|
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 {
|
|
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.
|
|
19
|
+
* await client.decryptForView(ctHash, utype)
|
|
18
20
|
* .setChainId(chainId)
|
|
19
21
|
* .setAccount(account)
|
|
20
|
-
* .
|
|
21
|
-
* .
|
|
22
|
-
* .
|
|
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
|
-
*
|
|
27
|
-
*
|
|
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
|
|
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
|
|
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:
|
|
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
|
|
73
|
+
* const unsealed = await client.decryptForView(ctHash, utype)
|
|
69
74
|
* .setChainId(11155111)
|
|
70
|
-
* .
|
|
75
|
+
* .execute();
|
|
71
76
|
* ```
|
|
72
77
|
*
|
|
73
|
-
* @returns The chainable
|
|
78
|
+
* @returns The chainable DecryptForViewBuilder instance.
|
|
74
79
|
*/
|
|
75
|
-
setChainId(chainId: number):
|
|
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
|
|
96
|
+
* const unsealed = await client.decryptForView(ctHash, utype)
|
|
92
97
|
* .setAccount('0x1234567890123456789012345678901234567890')
|
|
93
|
-
* .
|
|
98
|
+
* .execute();
|
|
94
99
|
* ```
|
|
95
100
|
*
|
|
96
|
-
* @returns The chainable
|
|
101
|
+
* @returns The chainable DecryptForViewBuilder instance.
|
|
97
102
|
*/
|
|
98
|
-
setAccount(account: string):
|
|
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
|
|
147
|
+
* const unsealed = await client.decryptForView(ctHash, utype)
|
|
116
148
|
* .setPermitHash('0x1234567890123456789012345678901234567890')
|
|
117
|
-
* .
|
|
149
|
+
* .execute();
|
|
118
150
|
* ```
|
|
119
151
|
*
|
|
120
|
-
* @returns The chainable
|
|
152
|
+
* @returns The chainable DecryptForViewBuilder instance.
|
|
121
153
|
*/
|
|
122
|
-
|
|
123
|
-
|
|
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
|
|
170
|
+
* const unsealed = await client.decryptForView(ctHash, utype)
|
|
139
171
|
* .setPermit(permit)
|
|
140
|
-
* .
|
|
172
|
+
* .execute();
|
|
141
173
|
* ```
|
|
142
174
|
*
|
|
143
|
-
* @returns The chainable
|
|
175
|
+
* @returns The chainable DecryptForViewBuilder instance.
|
|
144
176
|
*/
|
|
145
|
-
|
|
146
|
-
|
|
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
|
|
162
|
-
code:
|
|
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
|
|
181
|
-
code:
|
|
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
|
|
198
|
-
code:
|
|
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
|
|
217
|
-
return
|
|
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
|
|
278
|
+
* const unsealed = await client.decryptForView(ctHash, utype)
|
|
247
279
|
* .setChainId(11155111) // optional
|
|
248
280
|
* .setAccount('0x123...890') // optional
|
|
249
|
-
* .
|
|
281
|
+
* .withPermit() // optional
|
|
282
|
+
* .execute(); // execute
|
|
250
283
|
* ```
|
|
251
284
|
*
|
|
252
285
|
* @returns The unsealed item.
|
|
253
286
|
*/
|
|
254
|
-
async
|
|
287
|
+
async execute(): Promise<UnsealedItem<U>> {
|
|
255
288
|
// Ensure utype is valid
|
|
256
289
|
this.validateUtypeOrThrow();
|
|
257
290
|
|