@cofhe/sdk 0.2.0 → 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 +36 -0
- package/chains/defineChain.ts +2 -2
- package/chains/types.ts +3 -3
- package/core/baseBuilder.ts +18 -18
- package/core/client.test.ts +155 -41
- package/core/client.ts +72 -32
- package/core/clientTypes.ts +28 -18
- package/core/config.test.ts +40 -33
- package/core/config.ts +56 -51
- package/core/consts.ts +22 -0
- package/core/decrypt/{MockQueryDecrypterAbi.ts → MockThresholdNetworkAbi.ts} +71 -21
- package/core/decrypt/cofheMocksDecryptForTx.ts +142 -0
- package/core/decrypt/{cofheMocksSealOutput.ts → cofheMocksDecryptForView.ts} +12 -14
- 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 +19 -26
- 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 +22 -11
- package/core/permits.test.ts +5 -6
- package/core/permits.ts +5 -4
- package/core/utils.ts +10 -10
- package/dist/chains.cjs +4 -7
- package/dist/chains.d.cts +12 -12
- package/dist/chains.d.ts +12 -12
- package/dist/chains.js +1 -1
- package/dist/{chunk-WGCRJCBR.js → chunk-2TPSCOW3.js} +820 -224
- package/dist/{chunk-UGBVZNRT.js → chunk-NWDKXBIP.js} +309 -189
- package/dist/{chunk-WEAZ25JO.js → chunk-TBLR7NNE.js} +4 -7
- package/dist/{clientTypes-5_1nwtUe.d.cts → clientTypes-6aTZPQ_4.d.ts} +233 -173
- package/dist/{clientTypes-Es7fyi65.d.ts → clientTypes-Bhq7pCSA.d.cts} +233 -173
- package/dist/core.cjs +1138 -418
- package/dist/core.d.cts +37 -24
- package/dist/core.d.ts +37 -24
- package/dist/core.js +3 -3
- package/dist/node.cjs +1082 -370
- package/dist/node.d.cts +12 -12
- package/dist/node.d.ts +12 -12
- package/dist/node.js +8 -8
- package/dist/{permit-fUSe6KKq.d.cts → permit-MZ502UBl.d.cts} +30 -33
- package/dist/{permit-fUSe6KKq.d.ts → permit-MZ502UBl.d.ts} +30 -33
- package/dist/permits.cjs +305 -187
- package/dist/permits.d.cts +111 -812
- package/dist/permits.d.ts +111 -812
- package/dist/permits.js +1 -1
- package/dist/types-YiAC4gig.d.cts +33 -0
- package/dist/types-YiAC4gig.d.ts +33 -0
- package/dist/web.cjs +1085 -373
- package/dist/web.d.cts +13 -13
- package/dist/web.d.ts +13 -13
- package/dist/web.js +10 -10
- 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 +3 -3
- package/permits/localstorage.test.ts +9 -13
- package/permits/onchain-utils.ts +221 -0
- package/permits/permit.test.ts +51 -5
- package/permits/permit.ts +28 -74
- package/permits/store.test.ts +10 -50
- package/permits/store.ts +4 -14
- package/permits/test-utils.ts +10 -2
- package/permits/types.ts +22 -9
- package/permits/utils.ts +0 -4
- package/permits/validation.test.ts +29 -32
- package/permits/validation.ts +112 -194
- 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
- package/dist/types-KImPrEIe.d.cts +0 -48
- package/dist/types-KImPrEIe.d.ts +0 -48
package/core/config.ts
CHANGED
|
@@ -2,26 +2,19 @@ import { type CofheChain } from '@/chains';
|
|
|
2
2
|
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { type WalletClient } from 'viem';
|
|
5
|
-
import {
|
|
5
|
+
import { CofheError, CofheErrorCode } from './error.js';
|
|
6
6
|
import { type IStorage } from './types.js';
|
|
7
7
|
|
|
8
|
-
export type
|
|
8
|
+
export type CofheEnvironment = 'node' | 'hardhat' | 'web' | 'react';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Usable config type inferred from the schema
|
|
12
12
|
*/
|
|
13
|
-
export type
|
|
13
|
+
export type CofheConfig = {
|
|
14
14
|
/** Environment that the SDK is running in */
|
|
15
15
|
environment: 'node' | 'hardhat' | 'web' | 'react';
|
|
16
16
|
/** List of supported chains */
|
|
17
17
|
supportedChains: CofheChain[];
|
|
18
|
-
/**
|
|
19
|
-
* How permits are generated
|
|
20
|
-
* - ON_CONNECT: Generate a permit when client.connect() is called
|
|
21
|
-
* - ON_DECRYPT_HANDLES: Generate a permit when client.decryptHandles() is called
|
|
22
|
-
* - MANUAL: Generate a permit manually using client.generatePermit()
|
|
23
|
-
*/
|
|
24
|
-
permitGeneration: 'ON_CONNECT' | 'ON_DECRYPT_HANDLES' | 'MANUAL';
|
|
25
18
|
/** Default permit expiration in seconds, default is 30 days */
|
|
26
19
|
defaultPermitExpiration: number;
|
|
27
20
|
/**
|
|
@@ -43,25 +36,30 @@ export type CofhesdkConfig = {
|
|
|
43
36
|
* Default 1000ms on web
|
|
44
37
|
* Default 0ms on hardhat (will be called during tests no need for fake delay)
|
|
45
38
|
*/
|
|
46
|
-
|
|
39
|
+
decryptDelay: number;
|
|
40
|
+
/**
|
|
41
|
+
* Simulated delay(s) in milliseconds for each step of encryptInputs in mock mode.
|
|
42
|
+
* A single number applies the same delay to all five steps (InitTfhe, FetchKeys, Pack, Prove, Verify).
|
|
43
|
+
* A tuple of five numbers applies a per-step delay: [InitTfhe, FetchKeys, Pack, Prove, Verify].
|
|
44
|
+
* Default: [100, 100, 100, 500, 500]
|
|
45
|
+
*/
|
|
46
|
+
encryptDelay: number | [number, number, number, number, number];
|
|
47
47
|
};
|
|
48
|
-
_internal?:
|
|
48
|
+
_internal?: CofheInternalConfig;
|
|
49
49
|
};
|
|
50
50
|
|
|
51
|
-
export type
|
|
51
|
+
export type CofheInternalConfig = {
|
|
52
52
|
zkvWalletClient?: WalletClient;
|
|
53
53
|
};
|
|
54
54
|
|
|
55
55
|
/**
|
|
56
56
|
* Zod schema for configuration validation
|
|
57
57
|
*/
|
|
58
|
-
export const
|
|
58
|
+
export const CofheConfigSchema = z.object({
|
|
59
59
|
/** Environment that the SDK is running in */
|
|
60
60
|
environment: z.enum(['node', 'hardhat', 'web', 'react']).optional().default('node'),
|
|
61
61
|
/** List of supported chain configurations */
|
|
62
62
|
supportedChains: z.array(z.custom<CofheChain>()),
|
|
63
|
-
/** How permits are generated */
|
|
64
|
-
permitGeneration: z.enum(['ON_CONNECT', 'ON_DECRYPT_HANDLES', 'MANUAL']).optional().default('ON_CONNECT'),
|
|
65
63
|
/** Default permit expiration in seconds, default is 30 days */
|
|
66
64
|
defaultPermitExpiration: z
|
|
67
65
|
.number()
|
|
@@ -70,9 +68,15 @@ export const CofhesdkConfigSchema = z.object({
|
|
|
70
68
|
/** Storage method for fhe keys (defaults to indexedDB on web, filesystem on node) */
|
|
71
69
|
fheKeyStorage: z
|
|
72
70
|
.object({
|
|
73
|
-
getItem: z.
|
|
74
|
-
|
|
75
|
-
|
|
71
|
+
getItem: z.custom<IStorage['getItem']>((val) => typeof val === 'function', {
|
|
72
|
+
message: 'getItem must be a function',
|
|
73
|
+
}),
|
|
74
|
+
setItem: z.custom<IStorage['setItem']>((val) => typeof val === 'function', {
|
|
75
|
+
message: 'setItem must be a function',
|
|
76
|
+
}),
|
|
77
|
+
removeItem: z.custom<IStorage['removeItem']>((val) => typeof val === 'function', {
|
|
78
|
+
message: 'removeItem must be a function',
|
|
79
|
+
}),
|
|
76
80
|
})
|
|
77
81
|
.or(z.null())
|
|
78
82
|
.default(null),
|
|
@@ -81,10 +85,14 @@ export const CofhesdkConfigSchema = z.object({
|
|
|
81
85
|
/** Mocks configs */
|
|
82
86
|
mocks: z
|
|
83
87
|
.object({
|
|
84
|
-
|
|
88
|
+
decryptDelay: z.number().optional().default(0),
|
|
89
|
+
encryptDelay: z
|
|
90
|
+
.union([z.number(), z.tuple([z.number(), z.number(), z.number(), z.number(), z.number()])])
|
|
91
|
+
.optional()
|
|
92
|
+
.default([100, 100, 100, 500, 500]),
|
|
85
93
|
})
|
|
86
94
|
.optional()
|
|
87
|
-
.default({
|
|
95
|
+
.default({ decryptDelay: 0, encryptDelay: [100, 100, 100, 500, 500] }),
|
|
88
96
|
/** Internal configuration */
|
|
89
97
|
_internal: z
|
|
90
98
|
.object({
|
|
@@ -96,48 +104,45 @@ export const CofhesdkConfigSchema = z.object({
|
|
|
96
104
|
/**
|
|
97
105
|
* Input config type inferred from the schema
|
|
98
106
|
*/
|
|
99
|
-
export type
|
|
107
|
+
export type CofheInputConfig = z.input<typeof CofheConfigSchema>;
|
|
100
108
|
|
|
101
109
|
/**
|
|
102
|
-
* Creates and validates a
|
|
110
|
+
* Creates and validates a cofhe configuration (base implementation)
|
|
103
111
|
* @param config - The configuration object to validate
|
|
104
112
|
* @returns The validated configuration
|
|
105
113
|
* @throws {Error} If the configuration is invalid
|
|
106
114
|
*/
|
|
107
|
-
export function
|
|
108
|
-
const result =
|
|
115
|
+
export function createCofheConfigBase(config: CofheInputConfig): CofheConfig {
|
|
116
|
+
const result = CofheConfigSchema.safeParse(config);
|
|
109
117
|
|
|
110
118
|
if (!result.success) {
|
|
111
|
-
throw new Error(`Invalid
|
|
119
|
+
throw new Error(`Invalid cofhe configuration: ${z.prettifyError(result.error)}`, { cause: result.error });
|
|
112
120
|
}
|
|
113
121
|
|
|
114
122
|
return result.data;
|
|
115
123
|
}
|
|
116
124
|
|
|
117
125
|
/**
|
|
118
|
-
* Access the
|
|
126
|
+
* Access the CofheConfig object directly by providing the key.
|
|
119
127
|
* This is powerful when you use OnchainKit utilities outside of the React context.
|
|
120
128
|
*/
|
|
121
|
-
export const
|
|
122
|
-
config: CofhesdkConfig,
|
|
123
|
-
key: K
|
|
124
|
-
): CofhesdkConfig[K] => {
|
|
129
|
+
export const getCofheConfigItem = <K extends keyof CofheConfig>(config: CofheConfig, key: K): CofheConfig[K] => {
|
|
125
130
|
return config[key];
|
|
126
131
|
};
|
|
127
132
|
|
|
128
133
|
/**
|
|
129
134
|
* Gets a supported chain from config by chainId, throws if not found
|
|
130
|
-
* @param config - The
|
|
135
|
+
* @param config - The cofhe configuration
|
|
131
136
|
* @param chainId - The chain ID to look up
|
|
132
137
|
* @returns The supported chain configuration
|
|
133
|
-
* @throws {
|
|
138
|
+
* @throws {CofheError} If the chain is not found in the config
|
|
134
139
|
*/
|
|
135
|
-
export function getSupportedChainOrThrow(config:
|
|
140
|
+
export function getSupportedChainOrThrow(config: CofheConfig, chainId: number): CofheChain {
|
|
136
141
|
const supportedChain = config.supportedChains.find((chain) => chain.id === chainId);
|
|
137
142
|
|
|
138
143
|
if (!supportedChain) {
|
|
139
|
-
throw new
|
|
140
|
-
code:
|
|
144
|
+
throw new CofheError({
|
|
145
|
+
code: CofheErrorCode.UnsupportedChain,
|
|
141
146
|
message: `Config does not support chain <${chainId}>`,
|
|
142
147
|
hint: 'Ensure config passed to client has been created with this chain in the config.supportedChains array.',
|
|
143
148
|
context: {
|
|
@@ -152,18 +157,18 @@ export function getSupportedChainOrThrow(config: CofhesdkConfig, chainId: number
|
|
|
152
157
|
|
|
153
158
|
/**
|
|
154
159
|
* Gets the CoFHE URL for a chain, throws if not found
|
|
155
|
-
* @param config - The
|
|
160
|
+
* @param config - The cofhe configuration
|
|
156
161
|
* @param chainId - The chain ID to look up
|
|
157
162
|
* @returns The CoFHE URL for the chain
|
|
158
|
-
* @throws {
|
|
163
|
+
* @throws {CofheError} If the chain or URL is not found
|
|
159
164
|
*/
|
|
160
|
-
export function getCoFheUrlOrThrow(config:
|
|
165
|
+
export function getCoFheUrlOrThrow(config: CofheConfig, chainId: number): string {
|
|
161
166
|
const supportedChain = getSupportedChainOrThrow(config, chainId);
|
|
162
167
|
const url = supportedChain.coFheUrl;
|
|
163
168
|
|
|
164
169
|
if (!url) {
|
|
165
|
-
throw new
|
|
166
|
-
code:
|
|
170
|
+
throw new CofheError({
|
|
171
|
+
code: CofheErrorCode.MissingConfig,
|
|
167
172
|
message: `CoFHE URL is not configured for chain <${chainId}>`,
|
|
168
173
|
hint: 'Ensure this chain config includes a coFheUrl property.',
|
|
169
174
|
context: { chainId },
|
|
@@ -175,18 +180,18 @@ export function getCoFheUrlOrThrow(config: CofhesdkConfig, chainId: number): str
|
|
|
175
180
|
|
|
176
181
|
/**
|
|
177
182
|
* Gets the ZK verifier URL for a chain, throws if not found
|
|
178
|
-
* @param config - The
|
|
183
|
+
* @param config - The cofhe configuration
|
|
179
184
|
* @param chainId - The chain ID to look up
|
|
180
185
|
* @returns The ZK verifier URL for the chain
|
|
181
|
-
* @throws {
|
|
186
|
+
* @throws {CofheError} If the chain or URL is not found
|
|
182
187
|
*/
|
|
183
|
-
export function getZkVerifierUrlOrThrow(config:
|
|
188
|
+
export function getZkVerifierUrlOrThrow(config: CofheConfig, chainId: number): string {
|
|
184
189
|
const supportedChain = getSupportedChainOrThrow(config, chainId);
|
|
185
190
|
const url = supportedChain.verifierUrl;
|
|
186
191
|
|
|
187
192
|
if (!url) {
|
|
188
|
-
throw new
|
|
189
|
-
code:
|
|
193
|
+
throw new CofheError({
|
|
194
|
+
code: CofheErrorCode.ZkVerifierUrlUninitialized,
|
|
190
195
|
message: `ZK verifier URL is not configured for chain <${chainId}>`,
|
|
191
196
|
hint: 'Ensure this chain config includes a verifierUrl property.',
|
|
192
197
|
context: { chainId },
|
|
@@ -198,18 +203,18 @@ export function getZkVerifierUrlOrThrow(config: CofhesdkConfig, chainId: number)
|
|
|
198
203
|
|
|
199
204
|
/**
|
|
200
205
|
* Gets the threshold network URL for a chain, throws if not found
|
|
201
|
-
* @param config - The
|
|
206
|
+
* @param config - The cofhe configuration
|
|
202
207
|
* @param chainId - The chain ID to look up
|
|
203
208
|
* @returns The threshold network URL for the chain
|
|
204
|
-
* @throws {
|
|
209
|
+
* @throws {CofheError} If the chain or URL is not found
|
|
205
210
|
*/
|
|
206
|
-
export function getThresholdNetworkUrlOrThrow(config:
|
|
211
|
+
export function getThresholdNetworkUrlOrThrow(config: CofheConfig, chainId: number): string {
|
|
207
212
|
const supportedChain = getSupportedChainOrThrow(config, chainId);
|
|
208
213
|
const url = supportedChain.thresholdNetworkUrl;
|
|
209
214
|
|
|
210
215
|
if (!url) {
|
|
211
|
-
throw new
|
|
212
|
-
code:
|
|
216
|
+
throw new CofheError({
|
|
217
|
+
code: CofheErrorCode.ThresholdNetworkUrlUninitialized,
|
|
213
218
|
message: `Threshold network URL is not configured for chain <${chainId}>`,
|
|
214
219
|
hint: 'Ensure this chain config includes a thresholdNetworkUrl property.',
|
|
215
220
|
context: { chainId },
|
package/core/consts.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** Main Task Manager contract address */
|
|
2
|
+
export const TASK_MANAGER_ADDRESS = '0xeA30c4B8b44078Bbf8a6ef5b9f1eC1626C7848D9' as const;
|
|
3
|
+
|
|
4
|
+
/** Mock ZK Verifier contract address (used for testing) */
|
|
5
|
+
export const MOCKS_ZK_VERIFIER_ADDRESS = '0x0000000000000000000000000000000000005001' as const;
|
|
6
|
+
|
|
7
|
+
/** Mock Threshold Network contract address (used for testing) */
|
|
8
|
+
export const MOCKS_THRESHOLD_NETWORK_ADDRESS = '0x0000000000000000000000000000000000005002' as const;
|
|
9
|
+
|
|
10
|
+
/** Test Bed contract address (used for testing) */
|
|
11
|
+
export const TEST_BED_ADDRESS = '0x0000000000000000000000000000000000005003' as const;
|
|
12
|
+
|
|
13
|
+
/** Private key for the Mock ZK Verifier signer account */
|
|
14
|
+
export const MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY =
|
|
15
|
+
'0x6C8D7F768A6BB4AAFE85E8A2F5A9680355239C7E14646ED62B044E39DE154512' as const;
|
|
16
|
+
|
|
17
|
+
/** Address for the Mock ZK Verifier signer account */
|
|
18
|
+
export const MOCKS_ZK_VERIFIER_SIGNER_ADDRESS = '0x6E12D8C87503D4287c294f2Fdef96ACd9DFf6bd2' as const;
|
|
19
|
+
|
|
20
|
+
/** Private key for the Mock decrypt result signer account */
|
|
21
|
+
export const MOCKS_DECRYPT_RESULT_SIGNER_PRIVATE_KEY =
|
|
22
|
+
'0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d' as const;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const
|
|
1
|
+
export const MockThresholdNetworkAbi = [
|
|
2
2
|
{
|
|
3
3
|
type: 'function',
|
|
4
4
|
name: 'acl',
|
|
@@ -45,11 +45,7 @@ export const MockQueryDecrypterAbi = [
|
|
|
45
45
|
{ name: 'expiration', type: 'uint64', internalType: 'uint64' },
|
|
46
46
|
{ name: 'recipient', type: 'address', internalType: 'address' },
|
|
47
47
|
{ name: 'validatorId', type: 'uint256', internalType: 'uint256' },
|
|
48
|
-
{
|
|
49
|
-
name: 'validatorContract',
|
|
50
|
-
type: 'address',
|
|
51
|
-
internalType: 'address',
|
|
52
|
-
},
|
|
48
|
+
{ name: 'validatorContract', type: 'address', internalType: 'address' },
|
|
53
49
|
{ name: 'sealingKey', type: 'bytes32', internalType: 'bytes32' },
|
|
54
50
|
{ name: 'issuerSignature', type: 'bytes', internalType: 'bytes' },
|
|
55
51
|
{ name: 'recipientSignature', type: 'bytes', internalType: 'bytes' },
|
|
@@ -78,11 +74,7 @@ export const MockQueryDecrypterAbi = [
|
|
|
78
74
|
{ name: 'expiration', type: 'uint64', internalType: 'uint64' },
|
|
79
75
|
{ name: 'recipient', type: 'address', internalType: 'address' },
|
|
80
76
|
{ name: 'validatorId', type: 'uint256', internalType: 'uint256' },
|
|
81
|
-
{
|
|
82
|
-
name: 'validatorContract',
|
|
83
|
-
type: 'address',
|
|
84
|
-
internalType: 'address',
|
|
85
|
-
},
|
|
77
|
+
{ name: 'validatorContract', type: 'address', internalType: 'address' },
|
|
86
78
|
{ name: 'sealingKey', type: 'bytes32', internalType: 'bytes32' },
|
|
87
79
|
{ name: 'issuerSignature', type: 'bytes', internalType: 'bytes' },
|
|
88
80
|
{ name: 'recipientSignature', type: 'bytes', internalType: 'bytes' },
|
|
@@ -106,13 +98,6 @@ export const MockQueryDecrypterAbi = [
|
|
|
106
98
|
outputs: [{ name: '', type: 'bytes32', internalType: 'bytes32' }],
|
|
107
99
|
stateMutability: 'pure',
|
|
108
100
|
},
|
|
109
|
-
{
|
|
110
|
-
type: 'function',
|
|
111
|
-
name: 'taskManager',
|
|
112
|
-
inputs: [],
|
|
113
|
-
outputs: [{ name: '', type: 'address', internalType: 'contract TaskManager' }],
|
|
114
|
-
stateMutability: 'view',
|
|
115
|
-
},
|
|
116
101
|
{
|
|
117
102
|
type: 'function',
|
|
118
103
|
name: 'unseal',
|
|
@@ -123,7 +108,72 @@ export const MockQueryDecrypterAbi = [
|
|
|
123
108
|
outputs: [{ name: '', type: 'uint256', internalType: 'uint256' }],
|
|
124
109
|
stateMutability: 'pure',
|
|
125
110
|
},
|
|
126
|
-
{
|
|
127
|
-
|
|
128
|
-
|
|
111
|
+
{
|
|
112
|
+
type: 'function',
|
|
113
|
+
name: 'mockAcl',
|
|
114
|
+
inputs: [],
|
|
115
|
+
outputs: [{ name: '', type: 'address', internalType: 'contract MockACL' }],
|
|
116
|
+
stateMutability: 'view',
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
type: 'function',
|
|
120
|
+
name: 'mockTaskManager',
|
|
121
|
+
inputs: [],
|
|
122
|
+
outputs: [{ name: '', type: 'address', internalType: 'contract MockTaskManager' }],
|
|
123
|
+
stateMutability: 'view',
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
type: 'function',
|
|
127
|
+
name: 'mockQueryDecrypt',
|
|
128
|
+
inputs: [
|
|
129
|
+
{ name: 'ctHash', type: 'uint256', internalType: 'uint256' },
|
|
130
|
+
{ name: '', type: 'uint256', internalType: 'uint256' },
|
|
131
|
+
{ name: 'issuer', type: 'address', internalType: 'address' },
|
|
132
|
+
],
|
|
133
|
+
outputs: [
|
|
134
|
+
{ name: 'allowed', type: 'bool', internalType: 'bool' },
|
|
135
|
+
{ name: 'error', type: 'string', internalType: 'string' },
|
|
136
|
+
{ name: '', type: 'uint256', internalType: 'uint256' },
|
|
137
|
+
],
|
|
138
|
+
stateMutability: 'view',
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
type: 'function',
|
|
142
|
+
name: 'decryptForTxWithPermit',
|
|
143
|
+
inputs: [
|
|
144
|
+
{ name: 'ctHash', type: 'uint256', internalType: 'uint256' },
|
|
145
|
+
{
|
|
146
|
+
name: 'permission',
|
|
147
|
+
type: 'tuple',
|
|
148
|
+
internalType: 'struct Permission',
|
|
149
|
+
components: [
|
|
150
|
+
{ name: 'issuer', type: 'address', internalType: 'address' },
|
|
151
|
+
{ name: 'expiration', type: 'uint64', internalType: 'uint64' },
|
|
152
|
+
{ name: 'recipient', type: 'address', internalType: 'address' },
|
|
153
|
+
{ name: 'validatorId', type: 'uint256', internalType: 'uint256' },
|
|
154
|
+
{ name: 'validatorContract', type: 'address', internalType: 'address' },
|
|
155
|
+
{ name: 'sealingKey', type: 'bytes32', internalType: 'bytes32' },
|
|
156
|
+
{ name: 'issuerSignature', type: 'bytes', internalType: 'bytes' },
|
|
157
|
+
{ name: 'recipientSignature', type: 'bytes', internalType: 'bytes' },
|
|
158
|
+
],
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
outputs: [
|
|
162
|
+
{ name: 'allowed', type: 'bool', internalType: 'bool' },
|
|
163
|
+
{ name: 'error', type: 'string', internalType: 'string' },
|
|
164
|
+
{ name: 'decryptedValue', type: 'uint256', internalType: 'uint256' },
|
|
165
|
+
],
|
|
166
|
+
stateMutability: 'view',
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
type: 'function',
|
|
170
|
+
name: 'decryptForTxWithoutPermit',
|
|
171
|
+
inputs: [{ name: 'ctHash', type: 'uint256', internalType: 'uint256' }],
|
|
172
|
+
outputs: [
|
|
173
|
+
{ name: 'allowed', type: 'bool', internalType: 'bool' },
|
|
174
|
+
{ name: 'error', type: 'string', internalType: 'string' },
|
|
175
|
+
{ name: 'decryptedValue', type: 'uint256', internalType: 'uint256' },
|
|
176
|
+
],
|
|
177
|
+
stateMutability: 'view',
|
|
178
|
+
},
|
|
129
179
|
] as const;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { type Permit, PermitUtils } from '@/permits';
|
|
2
|
+
|
|
3
|
+
import { encodePacked, keccak256, pad, toHex, type Hex, type PublicClient } from 'viem';
|
|
4
|
+
import { sign } from 'viem/accounts';
|
|
5
|
+
import { sleep } from '../utils.js';
|
|
6
|
+
import { MockThresholdNetworkAbi } from './MockThresholdNetworkAbi.js';
|
|
7
|
+
import { FheTypes } from '../types.js';
|
|
8
|
+
import { CofheError, CofheErrorCode } from '../error.js';
|
|
9
|
+
import { MOCKS_DECRYPT_RESULT_SIGNER_PRIVATE_KEY } from '../consts.js';
|
|
10
|
+
import { MOCKS_THRESHOLD_NETWORK_ADDRESS } from '../consts.js';
|
|
11
|
+
|
|
12
|
+
export type DecryptForTxMocksResult = {
|
|
13
|
+
ctHash: bigint;
|
|
14
|
+
decryptedValue: bigint;
|
|
15
|
+
signature: string;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export async function cofheMocksDecryptForTx(
|
|
19
|
+
ctHash: bigint,
|
|
20
|
+
utype: FheTypes,
|
|
21
|
+
permit: Permit | null,
|
|
22
|
+
publicClient: PublicClient,
|
|
23
|
+
mocksDecryptForTxDelay: number
|
|
24
|
+
): Promise<DecryptForTxMocksResult> {
|
|
25
|
+
// Configurable delay before decrypting to simulate the CoFHE decrypt processing time
|
|
26
|
+
// Recommended 1000ms on web
|
|
27
|
+
// Recommended 0ms on hardhat (will be called during tests no need for fake delay)
|
|
28
|
+
if (mocksDecryptForTxDelay > 0) await sleep(mocksDecryptForTxDelay);
|
|
29
|
+
|
|
30
|
+
if (permit !== null) {
|
|
31
|
+
// With permit
|
|
32
|
+
let permission = PermitUtils.getPermission(permit, true);
|
|
33
|
+
const permissionWithBigInts = {
|
|
34
|
+
...permission,
|
|
35
|
+
expiration: BigInt(permission.expiration),
|
|
36
|
+
validatorId: BigInt(permission.validatorId),
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const [allowed, error, result] = await publicClient.readContract({
|
|
40
|
+
address: MOCKS_THRESHOLD_NETWORK_ADDRESS,
|
|
41
|
+
abi: MockThresholdNetworkAbi,
|
|
42
|
+
functionName: 'decryptForTxWithPermit',
|
|
43
|
+
args: [ctHash, permissionWithBigInts],
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
if (error != '') {
|
|
47
|
+
throw new CofheError({
|
|
48
|
+
code: CofheErrorCode.DecryptFailed,
|
|
49
|
+
message: `mocks decryptForTx call failed: ${error}`,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (allowed == false) {
|
|
54
|
+
throw new CofheError({
|
|
55
|
+
code: CofheErrorCode.DecryptFailed,
|
|
56
|
+
message: `mocks decryptForTx call failed: ACL Access Denied (NotAllowed)`,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// decryptForTx returns plaintext directly (no sealing/unsealing needed)
|
|
61
|
+
// Generate a mock threshold network signature (in production, this would be the actual signature)
|
|
62
|
+
// The signature must be valid for MockTaskManager verification.
|
|
63
|
+
const chainId = await publicClient.getChainId();
|
|
64
|
+
const ctHashBigInt = BigInt(ctHash);
|
|
65
|
+
const resultBigInt = BigInt(result);
|
|
66
|
+
const encryptionType = Number((ctHashBigInt & (0x7fn << 8n)) >> 8n);
|
|
67
|
+
|
|
68
|
+
// Matches Solidity: keccak256(abi.encodePacked(result, uint32(enc_type), uint64(chainId), bytes32(ctHash)))
|
|
69
|
+
const ctHashBytes32 = pad(toHex(ctHashBigInt), { size: 32 }) as Hex;
|
|
70
|
+
const packed = encodePacked(
|
|
71
|
+
['uint256', 'uint32', 'uint64', 'bytes32'],
|
|
72
|
+
[resultBigInt, encryptionType, BigInt(chainId), ctHashBytes32]
|
|
73
|
+
);
|
|
74
|
+
const messageHash = keccak256(packed);
|
|
75
|
+
|
|
76
|
+
// Raw digest signature (no EIP-191 prefix). Must verify against OpenZeppelin ECDSA.recover(messageHash, signature).
|
|
77
|
+
const signatureHex = await sign({
|
|
78
|
+
hash: messageHash,
|
|
79
|
+
privateKey: MOCKS_DECRYPT_RESULT_SIGNER_PRIVATE_KEY,
|
|
80
|
+
to: 'hex',
|
|
81
|
+
});
|
|
82
|
+
const signature = signatureHex.slice(2); // no 0x prefix
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
ctHash,
|
|
86
|
+
decryptedValue: BigInt(result),
|
|
87
|
+
signature,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Without permit (global allowance)
|
|
92
|
+
const [allowed, error, result] = await publicClient.readContract({
|
|
93
|
+
address: MOCKS_THRESHOLD_NETWORK_ADDRESS,
|
|
94
|
+
abi: MockThresholdNetworkAbi,
|
|
95
|
+
functionName: 'decryptForTxWithoutPermit',
|
|
96
|
+
args: [ctHash],
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
if (error != '') {
|
|
100
|
+
throw new CofheError({
|
|
101
|
+
code: CofheErrorCode.DecryptFailed,
|
|
102
|
+
message: `mocks decryptForTx call failed: ${error}`,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (allowed == false) {
|
|
107
|
+
throw new CofheError({
|
|
108
|
+
code: CofheErrorCode.DecryptFailed,
|
|
109
|
+
message: `mocks decryptForTx call failed: ACL Access Denied (NotAllowed)`,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// decryptForTx returns plaintext directly (no sealing/unsealing needed)
|
|
114
|
+
// Generate a mock threshold network signature (in production, this would be the actual signature)
|
|
115
|
+
// The signature must be valid for MockTaskManager verification.
|
|
116
|
+
const chainId = await publicClient.getChainId();
|
|
117
|
+
const ctHashBigInt = BigInt(ctHash);
|
|
118
|
+
const resultBigInt = BigInt(result);
|
|
119
|
+
const encryptionType = Number((ctHashBigInt & (0x7fn << 8n)) >> 8n);
|
|
120
|
+
|
|
121
|
+
// Matches Solidity: keccak256(abi.encodePacked(result, uint32(enc_type), uint64(chainId), bytes32(ctHash)))
|
|
122
|
+
const ctHashBytes32 = pad(toHex(ctHashBigInt), { size: 32 }) as Hex;
|
|
123
|
+
const packed = encodePacked(
|
|
124
|
+
['uint256', 'uint32', 'uint64', 'bytes32'],
|
|
125
|
+
[resultBigInt, encryptionType, BigInt(chainId), ctHashBytes32]
|
|
126
|
+
);
|
|
127
|
+
const messageHash = keccak256(packed);
|
|
128
|
+
|
|
129
|
+
// Raw digest signature (no EIP-191 prefix). Must verify against OpenZeppelin ECDSA.recover(messageHash, signature).
|
|
130
|
+
const signatureHex = await sign({
|
|
131
|
+
hash: messageHash,
|
|
132
|
+
privateKey: MOCKS_DECRYPT_RESULT_SIGNER_PRIVATE_KEY,
|
|
133
|
+
to: 'hex',
|
|
134
|
+
});
|
|
135
|
+
const signature = signatureHex.slice(2); // no 0x prefix
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
ctHash,
|
|
139
|
+
decryptedValue: BigInt(result),
|
|
140
|
+
signature,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
@@ -2,24 +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 {
|
|
7
|
+
import { CofheError, CofheErrorCode } from '../error.js';
|
|
8
|
+
import { MOCKS_THRESHOLD_NETWORK_ADDRESS } from '../consts.js';
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
export const MockQueryDecrypterAddress = '0x0000000000000000000000000000000000000200';
|
|
11
|
-
|
|
12
|
-
export async function cofheMocksSealOutput(
|
|
10
|
+
export async function cofheMocksDecryptForView(
|
|
13
11
|
ctHash: bigint,
|
|
14
12
|
utype: FheTypes,
|
|
15
13
|
permit: Permit,
|
|
16
14
|
publicClient: PublicClient,
|
|
17
|
-
|
|
15
|
+
mocksDecryptDelay: number
|
|
18
16
|
): Promise<bigint> {
|
|
19
17
|
// Configurable delay before decrypting the output to simulate the CoFHE decrypt processing time
|
|
20
18
|
// Recommended 1000ms on web
|
|
21
19
|
// Recommended 0ms on hardhat (will be called during tests no need for fake delay)
|
|
22
|
-
if (
|
|
20
|
+
if (mocksDecryptDelay > 0) await sleep(mocksDecryptDelay);
|
|
23
21
|
|
|
24
22
|
const permission = PermitUtils.getPermission(permit, true);
|
|
25
23
|
const permissionWithBigInts = {
|
|
@@ -29,22 +27,22 @@ export async function cofheMocksSealOutput(
|
|
|
29
27
|
};
|
|
30
28
|
|
|
31
29
|
const [allowed, error, result] = await publicClient.readContract({
|
|
32
|
-
address:
|
|
33
|
-
abi:
|
|
30
|
+
address: MOCKS_THRESHOLD_NETWORK_ADDRESS,
|
|
31
|
+
abi: MockThresholdNetworkAbi,
|
|
34
32
|
functionName: 'querySealOutput',
|
|
35
33
|
args: [ctHash, BigInt(utype), permissionWithBigInts],
|
|
36
34
|
});
|
|
37
35
|
|
|
38
36
|
if (error != '') {
|
|
39
|
-
throw new
|
|
40
|
-
code:
|
|
37
|
+
throw new CofheError({
|
|
38
|
+
code: CofheErrorCode.SealOutputFailed,
|
|
41
39
|
message: `mocks querySealOutput call failed: ${error}`,
|
|
42
40
|
});
|
|
43
41
|
}
|
|
44
42
|
|
|
45
43
|
if (allowed == false) {
|
|
46
|
-
throw new
|
|
47
|
-
code:
|
|
44
|
+
throw new CofheError({
|
|
45
|
+
code: CofheErrorCode.SealOutputFailed,
|
|
48
46
|
message: `mocks querySealOutput call failed: ACL Access Denied (NotAllowed)`,
|
|
49
47
|
});
|
|
50
48
|
}
|