@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.
Files changed (83) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/chains/defineChain.ts +2 -2
  3. package/chains/types.ts +3 -3
  4. package/core/baseBuilder.ts +18 -18
  5. package/core/client.test.ts +155 -41
  6. package/core/client.ts +72 -32
  7. package/core/clientTypes.ts +28 -18
  8. package/core/config.test.ts +40 -33
  9. package/core/config.ts +56 -51
  10. package/core/consts.ts +22 -0
  11. package/core/decrypt/{MockQueryDecrypterAbi.ts → MockThresholdNetworkAbi.ts} +71 -21
  12. package/core/decrypt/cofheMocksDecryptForTx.ts +142 -0
  13. package/core/decrypt/{cofheMocksSealOutput.ts → cofheMocksDecryptForView.ts} +12 -14
  14. package/core/decrypt/decryptForTxBuilder.ts +340 -0
  15. package/core/decrypt/{decryptHandleBuilder.ts → decryptForViewBuilder.ts} +75 -42
  16. package/core/decrypt/tnDecrypt.ts +232 -0
  17. package/core/decrypt/tnSealOutputV1.ts +5 -5
  18. package/core/decrypt/tnSealOutputV2.ts +27 -27
  19. package/core/encrypt/cofheMocksZkVerifySign.ts +19 -26
  20. package/core/encrypt/encryptInputsBuilder.test.ts +57 -61
  21. package/core/encrypt/encryptInputsBuilder.ts +65 -42
  22. package/core/encrypt/zkPackProveVerify.ts +11 -11
  23. package/core/error.ts +18 -18
  24. package/core/fetchKeys.test.ts +3 -3
  25. package/core/fetchKeys.ts +3 -3
  26. package/core/index.ts +22 -11
  27. package/core/permits.test.ts +5 -6
  28. package/core/permits.ts +5 -4
  29. package/core/utils.ts +10 -10
  30. package/dist/chains.cjs +4 -7
  31. package/dist/chains.d.cts +12 -12
  32. package/dist/chains.d.ts +12 -12
  33. package/dist/chains.js +1 -1
  34. package/dist/{chunk-WGCRJCBR.js → chunk-2TPSCOW3.js} +820 -224
  35. package/dist/{chunk-UGBVZNRT.js → chunk-NWDKXBIP.js} +309 -189
  36. package/dist/{chunk-WEAZ25JO.js → chunk-TBLR7NNE.js} +4 -7
  37. package/dist/{clientTypes-5_1nwtUe.d.cts → clientTypes-6aTZPQ_4.d.ts} +233 -173
  38. package/dist/{clientTypes-Es7fyi65.d.ts → clientTypes-Bhq7pCSA.d.cts} +233 -173
  39. package/dist/core.cjs +1138 -418
  40. package/dist/core.d.cts +37 -24
  41. package/dist/core.d.ts +37 -24
  42. package/dist/core.js +3 -3
  43. package/dist/node.cjs +1082 -370
  44. package/dist/node.d.cts +12 -12
  45. package/dist/node.d.ts +12 -12
  46. package/dist/node.js +8 -8
  47. package/dist/{permit-fUSe6KKq.d.cts → permit-MZ502UBl.d.cts} +30 -33
  48. package/dist/{permit-fUSe6KKq.d.ts → permit-MZ502UBl.d.ts} +30 -33
  49. package/dist/permits.cjs +305 -187
  50. package/dist/permits.d.cts +111 -812
  51. package/dist/permits.d.ts +111 -812
  52. package/dist/permits.js +1 -1
  53. package/dist/types-YiAC4gig.d.cts +33 -0
  54. package/dist/types-YiAC4gig.d.ts +33 -0
  55. package/dist/web.cjs +1085 -373
  56. package/dist/web.d.cts +13 -13
  57. package/dist/web.d.ts +13 -13
  58. package/dist/web.js +10 -10
  59. package/node/client.test.ts +34 -34
  60. package/node/config.test.ts +11 -11
  61. package/node/encryptInputs.test.ts +29 -29
  62. package/node/index.ts +15 -15
  63. package/package.json +3 -3
  64. package/permits/localstorage.test.ts +9 -13
  65. package/permits/onchain-utils.ts +221 -0
  66. package/permits/permit.test.ts +51 -5
  67. package/permits/permit.ts +28 -74
  68. package/permits/store.test.ts +10 -50
  69. package/permits/store.ts +4 -14
  70. package/permits/test-utils.ts +10 -2
  71. package/permits/types.ts +22 -9
  72. package/permits/utils.ts +0 -4
  73. package/permits/validation.test.ts +29 -32
  74. package/permits/validation.ts +112 -194
  75. package/web/client.web.test.ts +34 -34
  76. package/web/config.web.test.ts +11 -11
  77. package/web/encryptInputs.web.test.ts +29 -29
  78. package/web/index.ts +19 -19
  79. package/web/worker.builder.web.test.ts +28 -28
  80. package/web/worker.config.web.test.ts +47 -47
  81. package/web/worker.output.web.test.ts +10 -10
  82. package/dist/types-KImPrEIe.d.cts +0 -48
  83. 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 { CofhesdkError, CofhesdkErrorCode } from './error.js';
5
+ import { CofheError, CofheErrorCode } from './error.js';
6
6
  import { type IStorage } from './types.js';
7
7
 
8
- export type CofhesdkEnvironment = 'node' | 'hardhat' | 'web' | 'react';
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 CofhesdkConfig = {
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
- sealOutputDelay: number;
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?: CofhesdkInternalConfig;
48
+ _internal?: CofheInternalConfig;
49
49
  };
50
50
 
51
- export type CofhesdkInternalConfig = {
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 CofhesdkConfigSchema = z.object({
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.function().args(z.string()).returns(z.promise(z.any())),
74
- setItem: z.function().args(z.string(), z.any()).returns(z.promise(z.void())),
75
- removeItem: z.function().args(z.string()).returns(z.promise(z.void())),
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
- sealOutputDelay: z.number().optional().default(0),
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({ sealOutputDelay: 0 }),
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 CofhesdkInputConfig = z.input<typeof CofhesdkConfigSchema>;
107
+ export type CofheInputConfig = z.input<typeof CofheConfigSchema>;
100
108
 
101
109
  /**
102
- * Creates and validates a cofhesdk configuration (base implementation)
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 createCofhesdkConfigBase(config: CofhesdkInputConfig): CofhesdkConfig {
108
- const result = CofhesdkConfigSchema.safeParse(config);
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 cofhesdk configuration: ${result.error.message}`);
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 CofhesdkConfig object directly by providing the key.
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 getCofhesdkConfigItem = <K extends keyof CofhesdkConfig>(
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 cofhesdk configuration
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 {CofhesdkError} If the chain is not found in the config
138
+ * @throws {CofheError} If the chain is not found in the config
134
139
  */
135
- export function getSupportedChainOrThrow(config: CofhesdkConfig, chainId: number): CofheChain {
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 CofhesdkError({
140
- code: CofhesdkErrorCode.UnsupportedChain,
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 cofhesdk configuration
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 {CofhesdkError} If the chain or URL is not found
163
+ * @throws {CofheError} If the chain or URL is not found
159
164
  */
160
- export function getCoFheUrlOrThrow(config: CofhesdkConfig, chainId: number): string {
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 CofhesdkError({
166
- code: CofhesdkErrorCode.MissingConfig,
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 cofhesdk configuration
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 {CofhesdkError} If the chain or URL is not found
186
+ * @throws {CofheError} If the chain or URL is not found
182
187
  */
183
- export function getZkVerifierUrlOrThrow(config: CofhesdkConfig, chainId: number): string {
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 CofhesdkError({
189
- code: CofhesdkErrorCode.ZkVerifierUrlUninitialized,
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 cofhesdk configuration
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 {CofhesdkError} If the chain or URL is not found
209
+ * @throws {CofheError} If the chain or URL is not found
205
210
  */
206
- export function getThresholdNetworkUrlOrThrow(config: CofhesdkConfig, chainId: number): string {
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 CofhesdkError({
212
- code: CofhesdkErrorCode.ThresholdNetworkUrlUninitialized,
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 MockQueryDecrypterAbi = [
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
- { type: 'error', name: 'NotAllowed', inputs: [] },
127
- { type: 'error', name: 'SealingKeyInvalid', inputs: [] },
128
- { type: 'error', name: 'SealingKeyMissing', inputs: [] },
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 { MockQueryDecrypterAbi } from './MockQueryDecrypterAbi.js';
5
+ import { MockThresholdNetworkAbi } from './MockThresholdNetworkAbi.js';
6
6
  import { FheTypes } from '../types.js';
7
- import { CofhesdkError, CofhesdkErrorCode } from '../error.js';
7
+ import { CofheError, CofheErrorCode } from '../error.js';
8
+ import { MOCKS_THRESHOLD_NETWORK_ADDRESS } from '../consts.js';
8
9
 
9
- // Address the Mock Query Decrypter contract is deployed to on the Hardhat chain
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
- mocksSealOutputDelay: number
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 (mocksSealOutputDelay > 0) await sleep(mocksSealOutputDelay);
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: MockQueryDecrypterAddress,
33
- abi: MockQueryDecrypterAbi,
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 CofhesdkError({
40
- code: CofhesdkErrorCode.SealOutputFailed,
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 CofhesdkError({
47
- code: CofhesdkErrorCode.SealOutputFailed,
44
+ throw new CofheError({
45
+ code: CofheErrorCode.SealOutputFailed,
48
46
  message: `mocks querySealOutput call failed: ACL Access Denied (NotAllowed)`,
49
47
  });
50
48
  }