@cofhe/sdk 0.0.0-beta-20251027110729

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 (110) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/adapters/ethers5.test.ts +174 -0
  3. package/adapters/ethers5.ts +36 -0
  4. package/adapters/ethers6.test.ts +169 -0
  5. package/adapters/ethers6.ts +36 -0
  6. package/adapters/hardhat-node.ts +167 -0
  7. package/adapters/hardhat.hh2.test.ts +159 -0
  8. package/adapters/hardhat.ts +37 -0
  9. package/adapters/index.test.ts +25 -0
  10. package/adapters/index.ts +5 -0
  11. package/adapters/smartWallet.ts +91 -0
  12. package/adapters/test-utils.ts +53 -0
  13. package/adapters/types.ts +6 -0
  14. package/adapters/wagmi.test.ts +156 -0
  15. package/adapters/wagmi.ts +17 -0
  16. package/chains/chains/arbSepolia.ts +14 -0
  17. package/chains/chains/baseSepolia.ts +14 -0
  18. package/chains/chains/hardhat.ts +15 -0
  19. package/chains/chains/sepolia.ts +14 -0
  20. package/chains/chains.test.ts +49 -0
  21. package/chains/defineChain.ts +18 -0
  22. package/chains/index.ts +33 -0
  23. package/chains/types.ts +32 -0
  24. package/core/baseBuilder.ts +138 -0
  25. package/core/client.test.ts +298 -0
  26. package/core/client.ts +308 -0
  27. package/core/config.test.ts +224 -0
  28. package/core/config.ts +213 -0
  29. package/core/decrypt/MockQueryDecrypterAbi.ts +129 -0
  30. package/core/decrypt/cofheMocksSealOutput.ts +57 -0
  31. package/core/decrypt/decryptHandleBuilder.ts +281 -0
  32. package/core/decrypt/decryptUtils.ts +28 -0
  33. package/core/decrypt/tnSealOutput.ts +59 -0
  34. package/core/encrypt/MockZkVerifierAbi.ts +106 -0
  35. package/core/encrypt/cofheMocksZkVerifySign.ts +278 -0
  36. package/core/encrypt/encryptInputsBuilder.test.ts +735 -0
  37. package/core/encrypt/encryptInputsBuilder.ts +512 -0
  38. package/core/encrypt/encryptUtils.ts +64 -0
  39. package/core/encrypt/zkPackProveVerify.ts +273 -0
  40. package/core/error.ts +170 -0
  41. package/core/fetchKeys.test.ts +212 -0
  42. package/core/fetchKeys.ts +170 -0
  43. package/core/index.ts +77 -0
  44. package/core/keyStore.test.ts +226 -0
  45. package/core/keyStore.ts +127 -0
  46. package/core/permits.test.ts +242 -0
  47. package/core/permits.ts +136 -0
  48. package/core/result.test.ts +180 -0
  49. package/core/result.ts +67 -0
  50. package/core/test-utils.ts +45 -0
  51. package/core/types.ts +352 -0
  52. package/core/utils.ts +88 -0
  53. package/dist/adapters.cjs +88 -0
  54. package/dist/adapters.d.cts +14558 -0
  55. package/dist/adapters.d.ts +14558 -0
  56. package/dist/adapters.js +83 -0
  57. package/dist/chains.cjs +101 -0
  58. package/dist/chains.d.cts +99 -0
  59. package/dist/chains.d.ts +99 -0
  60. package/dist/chains.js +1 -0
  61. package/dist/chunk-GZCQQYVI.js +93 -0
  62. package/dist/chunk-KFGPTJ6X.js +2295 -0
  63. package/dist/chunk-LU7BMUUT.js +804 -0
  64. package/dist/core.cjs +3174 -0
  65. package/dist/core.d.cts +16 -0
  66. package/dist/core.d.ts +16 -0
  67. package/dist/core.js +3 -0
  68. package/dist/node.cjs +3090 -0
  69. package/dist/node.d.cts +22 -0
  70. package/dist/node.d.ts +22 -0
  71. package/dist/node.js +90 -0
  72. package/dist/permit-S9CnI6MF.d.cts +333 -0
  73. package/dist/permit-S9CnI6MF.d.ts +333 -0
  74. package/dist/permits.cjs +856 -0
  75. package/dist/permits.d.cts +1056 -0
  76. package/dist/permits.d.ts +1056 -0
  77. package/dist/permits.js +1 -0
  78. package/dist/types-KImPrEIe.d.cts +48 -0
  79. package/dist/types-KImPrEIe.d.ts +48 -0
  80. package/dist/types-PhwGgQvs.d.ts +953 -0
  81. package/dist/types-bB7wLj0q.d.cts +953 -0
  82. package/dist/web.cjs +3067 -0
  83. package/dist/web.d.cts +22 -0
  84. package/dist/web.d.ts +22 -0
  85. package/dist/web.js +64 -0
  86. package/node/client.test.ts +152 -0
  87. package/node/config.test.ts +68 -0
  88. package/node/encryptInputs.test.ts +175 -0
  89. package/node/index.ts +96 -0
  90. package/node/storage.ts +51 -0
  91. package/package.json +120 -0
  92. package/permits/index.ts +67 -0
  93. package/permits/localstorage.test.ts +118 -0
  94. package/permits/permit.test.ts +474 -0
  95. package/permits/permit.ts +396 -0
  96. package/permits/sealing.test.ts +84 -0
  97. package/permits/sealing.ts +131 -0
  98. package/permits/signature.ts +79 -0
  99. package/permits/store.test.ts +128 -0
  100. package/permits/store.ts +168 -0
  101. package/permits/test-utils.ts +20 -0
  102. package/permits/types.ts +174 -0
  103. package/permits/utils.ts +63 -0
  104. package/permits/validation.test.ts +288 -0
  105. package/permits/validation.ts +349 -0
  106. package/web/client.web.test.ts +152 -0
  107. package/web/config.web.test.ts +71 -0
  108. package/web/encryptInputs.web.test.ts +195 -0
  109. package/web/index.ts +97 -0
  110. package/web/storage.ts +20 -0
package/core/client.ts ADDED
@@ -0,0 +1,308 @@
1
+ /* eslint-disable no-unused-vars */
2
+ import type { CreateSelfPermitOptions, CreateSharingPermitOptions, ImportSharedPermitOptions } from '@/permits';
3
+
4
+ import { createStore } from 'zustand/vanilla';
5
+ import { type PublicClient, type WalletClient } from 'viem';
6
+ import { fetchMultichainKeys } from './fetchKeys.js';
7
+ import { CofhesdkError, CofhesdkErrorCode } from './error.js';
8
+ import { EncryptInputsBuilder } from './encrypt/encryptInputsBuilder.js';
9
+ import { type Result, ResultOk, resultWrapper } from './result.js';
10
+ import { createKeysStore } from './keyStore.js';
11
+ import { permits } from './permits.js';
12
+ import { DecryptHandlesBuilder } from './decrypt/decryptHandleBuilder.js';
13
+ import {
14
+ type CofhesdkClient,
15
+ type CofhesdkClientParams,
16
+ type CofhesdkClientConnectionState,
17
+ type EncryptableItem,
18
+ type FheTypes,
19
+ type CofhesdkClientPermits,
20
+ } from './types.js';
21
+ import { getPublicClientChainID, getWalletClientAccount } from './utils.js';
22
+
23
+ /**
24
+ * Creates a CoFHE SDK client instance (base implementation)
25
+ * @param {CofhesdkClientParams} opts - Initialization options including config and platform-specific serializers
26
+ * @returns {CofhesdkClient} - The CoFHE SDK client instance
27
+ */
28
+ export function createCofhesdkClientBase(opts: CofhesdkClientParams): CofhesdkClient {
29
+ // Create keysStorage instance using configured storage
30
+ const keysStorage = createKeysStore(opts.config.fheKeyStorage);
31
+
32
+ // refs captured in closure
33
+ let _publicClient: PublicClient | undefined = undefined;
34
+ let _walletClient: WalletClient | undefined = undefined;
35
+
36
+ // Zustand store for reactive state management
37
+ const connectStore = createStore<CofhesdkClientConnectionState>(() => ({
38
+ connected: false,
39
+ connecting: false,
40
+ connectError: undefined,
41
+ chainId: undefined,
42
+ account: undefined,
43
+ }));
44
+
45
+ // Helper to update state
46
+ const updateConnectState = (partial: Partial<CofhesdkClientConnectionState>) => {
47
+ connectStore.setState((state) => ({ ...state, ...partial }));
48
+ };
49
+
50
+ // single-flight + abortable warmup
51
+ let _connectPromise: Promise<Result<boolean>> | undefined = undefined;
52
+
53
+ // Called before any operation, throws of connection not yet established
54
+ const _requireConnected = () => {
55
+ const state = connectStore.getState();
56
+ const notConnected = !state.connected || !_publicClient || !_walletClient || !state.account || !state.chainId;
57
+ if (notConnected) {
58
+ throw new CofhesdkError({
59
+ code: CofhesdkErrorCode.NotConnected,
60
+ message: 'Client must be connected, account and chainId must be initialized',
61
+ hint: 'Ensure client.connect() has been called and awaited.',
62
+ context: {
63
+ connected: state.connected,
64
+ account: state.account,
65
+ chainId: state.chainId,
66
+ publicClient: _publicClient,
67
+ walletClient: _walletClient,
68
+ },
69
+ });
70
+ }
71
+ };
72
+
73
+ // INITIALIZATION
74
+
75
+ const keyFetchResult = resultWrapper(async () => {
76
+ // If configured, fetch keys for all supported chains
77
+ if (opts.config.fheKeysPrefetching === 'SUPPORTED_CHAINS') {
78
+ await fetchMultichainKeys(
79
+ opts.config,
80
+ 0,
81
+ opts.tfhePublicKeyDeserializer,
82
+ opts.compactPkeCrsDeserializer,
83
+ keysStorage
84
+ );
85
+ return true;
86
+ }
87
+
88
+ return false;
89
+ });
90
+
91
+ // LIFECYCLE
92
+
93
+ async function connect(publicClient: PublicClient, walletClient: WalletClient) {
94
+ const state = connectStore.getState();
95
+
96
+ // Exit if already connected and clients are the same
97
+ if (state.connected && _publicClient === publicClient && _walletClient === walletClient) {
98
+ return Promise.resolve(ResultOk(true));
99
+ }
100
+
101
+ // Exit if already connecting
102
+ if (_connectPromise && _publicClient === publicClient && _walletClient === walletClient) {
103
+ return _connectPromise;
104
+ }
105
+
106
+ // Set connecting state
107
+ updateConnectState({ connecting: true, connectError: null, connected: false });
108
+
109
+ _connectPromise = resultWrapper(
110
+ // try
111
+ async () => {
112
+ _publicClient = publicClient;
113
+ _walletClient = walletClient;
114
+
115
+ const chainId = await getPublicClientChainID(publicClient);
116
+ const account = await getWalletClientAccount(walletClient);
117
+
118
+ updateConnectState({ connecting: false, connected: true, chainId, account });
119
+
120
+ return true;
121
+ },
122
+ // catch
123
+ (e) => {
124
+ updateConnectState({ connecting: false, connected: false, connectError: e });
125
+ return false;
126
+ },
127
+ // finally
128
+ () => {
129
+ _connectPromise = undefined;
130
+ }
131
+ );
132
+
133
+ return _connectPromise;
134
+ }
135
+
136
+ // CLIENT OPERATIONS
137
+
138
+ function encryptInputs<T extends EncryptableItem[]>(inputs: [...T]): EncryptInputsBuilder<[...T]> {
139
+ const state = connectStore.getState();
140
+
141
+ return new EncryptInputsBuilder({
142
+ inputs,
143
+ account: state.account ?? undefined,
144
+ chainId: state.chainId ?? undefined,
145
+
146
+ config: opts.config,
147
+ publicClient: _publicClient ?? undefined,
148
+ walletClient: _walletClient ?? undefined,
149
+ zkvWalletClient: opts.config._internal?.zkvWalletClient,
150
+
151
+ tfhePublicKeyDeserializer: opts.tfhePublicKeyDeserializer,
152
+ compactPkeCrsDeserializer: opts.compactPkeCrsDeserializer,
153
+ zkBuilderAndCrsGenerator: opts.zkBuilderAndCrsGenerator,
154
+ initTfhe: opts.initTfhe,
155
+
156
+ keysStorage,
157
+
158
+ requireConnected: _requireConnected,
159
+ });
160
+ }
161
+
162
+ function decryptHandle<U extends FheTypes>(ctHash: bigint, utype: U): DecryptHandlesBuilder<U> {
163
+ const state = connectStore.getState();
164
+
165
+ return new DecryptHandlesBuilder({
166
+ ctHash,
167
+ utype,
168
+ chainId: state.chainId ?? undefined,
169
+ account: state.account ?? undefined,
170
+
171
+ config: opts.config,
172
+ publicClient: _publicClient ?? undefined,
173
+ walletClient: _walletClient ?? undefined,
174
+
175
+ requireConnected: _requireConnected,
176
+ });
177
+ }
178
+
179
+ // PERMITS - Context-aware wrapper
180
+
181
+ const _getChainIdAndAccount = (chainId?: number, account?: string) => {
182
+ const state = connectStore.getState();
183
+ const _chainId = chainId ?? state.chainId;
184
+ const _account = account ?? state.account;
185
+
186
+ if (_chainId == null || _account == null) {
187
+ throw new CofhesdkError({
188
+ code: CofhesdkErrorCode.NotConnected,
189
+ message: 'ChainId or account not available.',
190
+ hint: 'Ensure client.connect() has been called, or provide chainId and account explicitly.',
191
+ context: {
192
+ chainId: _chainId,
193
+ account: _account,
194
+ },
195
+ });
196
+ }
197
+
198
+ return { chainId: _chainId, account: _account };
199
+ };
200
+
201
+ const clientPermits: CofhesdkClientPermits = {
202
+ // Pass through store access
203
+ getSnapshot: permits.getSnapshot,
204
+ subscribe: permits.subscribe,
205
+
206
+ // Creation methods (require connection)
207
+ createSelf: async (options: CreateSelfPermitOptions) =>
208
+ resultWrapper(async () => {
209
+ _requireConnected();
210
+ return permits.createSelf(options, _publicClient!, _walletClient!);
211
+ }),
212
+
213
+ createSharing: async (options: CreateSharingPermitOptions) =>
214
+ resultWrapper(async () => {
215
+ _requireConnected();
216
+ return permits.createSharing(options, _publicClient!, _walletClient!);
217
+ }),
218
+
219
+ importShared: async (options: ImportSharedPermitOptions | any | string) =>
220
+ resultWrapper(async () => {
221
+ _requireConnected();
222
+ return permits.importShared(options, _publicClient!, _walletClient!);
223
+ }),
224
+
225
+ // Retrieval methods (auto-fill chainId/account)
226
+ getPermit: async (hash: string, chainId?: number, account?: string) =>
227
+ resultWrapper(async () => {
228
+ const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
229
+ return permits.getPermit(_chainId, _account, hash);
230
+ }),
231
+
232
+ getPermits: async (chainId?: number, account?: string) =>
233
+ resultWrapper(async () => {
234
+ const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
235
+ return permits.getPermits(_chainId, _account);
236
+ }),
237
+
238
+ getActivePermit: async (chainId?: number, account?: string) =>
239
+ resultWrapper(async () => {
240
+ const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
241
+ return permits.getActivePermit(_chainId, _account);
242
+ }),
243
+
244
+ getActivePermitHash: async (chainId?: number, account?: string) =>
245
+ resultWrapper(async () => {
246
+ const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
247
+ return permits.getActivePermitHash(_chainId, _account);
248
+ }),
249
+
250
+ // Mutation methods (auto-fill chainId/account)
251
+ selectActivePermit: async (hash: string, chainId?: number, account?: string) =>
252
+ resultWrapper(async () => {
253
+ const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
254
+ return permits.selectActivePermit(_chainId, _account, hash);
255
+ }),
256
+
257
+ removePermit: async (hash: string, chainId?: number, account?: string) =>
258
+ resultWrapper(async () => {
259
+ const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
260
+ return permits.removePermit(_chainId, _account, hash);
261
+ }),
262
+
263
+ removeActivePermit: async (chainId?: number, account?: string) =>
264
+ resultWrapper(async () => {
265
+ const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
266
+ return permits.removeActivePermit(_chainId, _account);
267
+ }),
268
+
269
+ // Utils (no context needed)
270
+ getHash: permits.getHash,
271
+ serialize: permits.serialize,
272
+ deserialize: permits.deserialize,
273
+ };
274
+
275
+ return {
276
+ // Zustand reactive accessors (don't export store directly to prevent mutation)
277
+ getSnapshot: connectStore.getState,
278
+ subscribe: connectStore.subscribe,
279
+
280
+ // initialization results
281
+ initializationResults: {
282
+ keyFetchResult,
283
+ },
284
+
285
+ // flags (read-only: reflect snapshot)
286
+ get connected() {
287
+ return connectStore.getState().connected;
288
+ },
289
+ get connecting() {
290
+ return connectStore.getState().connecting;
291
+ },
292
+
293
+ // config & platform-specific (read-only)
294
+ config: opts.config,
295
+
296
+ connect,
297
+ encryptInputs,
298
+ decryptHandle,
299
+ permits: clientPermits,
300
+
301
+ // Add SDK-specific methods below that require connection
302
+ // Example:
303
+ // async encryptData(data: unknown) {
304
+ // requireConnected();
305
+ // // Use _publicClient and _walletClient for implementation
306
+ // },
307
+ };
308
+ }
@@ -0,0 +1,224 @@
1
+ /* eslint-disable no-unused-vars */
2
+ import { sepolia, hardhat } from '@/chains';
3
+
4
+ import { describe, it, expect, vi } from 'vitest';
5
+ import {
6
+ createCofhesdkConfigBase,
7
+ getCofhesdkConfigItem,
8
+ type CofhesdkInputConfig,
9
+ getSupportedChainOrThrow,
10
+ getCoFheUrlOrThrow,
11
+ getZkVerifierUrlOrThrow,
12
+ getThresholdNetworkUrlOrThrow,
13
+ } from './config.js';
14
+
15
+ describe('createCofhesdkConfigBase', () => {
16
+ const validBaseConfig: CofhesdkInputConfig = {
17
+ supportedChains: [],
18
+ };
19
+
20
+ const setNestedValue = (obj: any, path: string, value: any): void => {
21
+ const keys = path.split('.');
22
+ const lastKey = keys.pop()!;
23
+ const target = keys.reduce((acc, key) => {
24
+ if (!acc[key]) acc[key] = {};
25
+ return acc[key];
26
+ }, obj);
27
+ target[lastKey] = value;
28
+ };
29
+
30
+ const getNestedValue = (obj: any, path: string): any => {
31
+ return path.split('.').reduce((acc, key) => acc?.[key], obj);
32
+ };
33
+
34
+ const expectInvalidConfigItem = (path: string, value: any, log = false): void => {
35
+ const config = { ...validBaseConfig };
36
+ setNestedValue(config, path, value);
37
+ if (log) {
38
+ console.log('expect config invalid', path, value, config);
39
+ try {
40
+ createCofhesdkConfigBase(config as CofhesdkInputConfig);
41
+ } catch (e) {
42
+ console.log('expect config invalid', path, value, config, e);
43
+ }
44
+ }
45
+ expect(() => createCofhesdkConfigBase(config as CofhesdkInputConfig)).toThrow('Invalid cofhesdk configuration:');
46
+ };
47
+
48
+ const expectValidConfigItem = (path: string, value: any, expectedValue: any): void => {
49
+ const config = { ...validBaseConfig };
50
+ setNestedValue(config, path, value);
51
+ const result = createCofhesdkConfigBase(config);
52
+ expect(getNestedValue(result, path)).toEqual(expectedValue);
53
+ };
54
+
55
+ it('supportedChains', () => {
56
+ expectInvalidConfigItem('supportedChains', {});
57
+ expectInvalidConfigItem('supportedChains', 'not-an-array');
58
+ expectInvalidConfigItem('supportedChains', null);
59
+ expectInvalidConfigItem('supportedChains', undefined);
60
+
61
+ expectValidConfigItem('supportedChains', [sepolia], [sepolia]);
62
+ expectValidConfigItem('supportedChains', [sepolia, hardhat], [sepolia, hardhat]);
63
+ });
64
+
65
+ it('fheKeysPrefetching', () => {
66
+ expectInvalidConfigItem('fheKeysPrefetching', 'invalid-option');
67
+ expectInvalidConfigItem('fheKeysPrefetching', 5);
68
+
69
+ expectValidConfigItem('fheKeysPrefetching', 'CONNECTED_CHAIN', 'CONNECTED_CHAIN');
70
+ expectValidConfigItem('fheKeysPrefetching', 'SUPPORTED_CHAINS', 'SUPPORTED_CHAINS');
71
+ expectValidConfigItem('fheKeysPrefetching', 'OFF', 'OFF');
72
+ expectValidConfigItem('fheKeysPrefetching', undefined, 'OFF');
73
+ });
74
+
75
+ it('permitGeneration', () => {
76
+ expectInvalidConfigItem('permitGeneration', 'not-a-boolean');
77
+ expectInvalidConfigItem('permitGeneration', null);
78
+
79
+ expectValidConfigItem('permitGeneration', 'ON_CONNECT', 'ON_CONNECT');
80
+ expectValidConfigItem('permitGeneration', 'ON_DECRYPT_HANDLES', 'ON_DECRYPT_HANDLES');
81
+ expectValidConfigItem('permitGeneration', 'MANUAL', 'MANUAL');
82
+ expectValidConfigItem('permitGeneration', undefined, 'ON_CONNECT');
83
+ });
84
+
85
+ it('defaultPermitExpiration', () => {
86
+ expectInvalidConfigItem('defaultPermitExpiration', 'not-a-number');
87
+ expectInvalidConfigItem('defaultPermitExpiration', null);
88
+
89
+ expectValidConfigItem('defaultPermitExpiration', 5, 5);
90
+ expectValidConfigItem('defaultPermitExpiration', undefined, 60 * 60 * 24 * 30);
91
+ });
92
+
93
+ it('fheKeyStorage', async () => {
94
+ expectInvalidConfigItem('fheKeyStorage', 'not-an-object');
95
+
96
+ expectValidConfigItem('fheKeyStorage', undefined, null);
97
+ expectValidConfigItem('fheKeyStorage', null, null);
98
+
99
+ let getItemCalled = false;
100
+ let setItemCalled = false;
101
+ let removeItemCalled = false;
102
+
103
+ const fakeStorage = {
104
+ getItem: (name: string) => {
105
+ getItemCalled = true;
106
+ return Promise.resolve(null);
107
+ },
108
+ setItem: (name: string, value: any) => {
109
+ setItemCalled = true;
110
+ return Promise.resolve();
111
+ },
112
+ removeItem: (name: string) => {
113
+ removeItemCalled = true;
114
+ return Promise.resolve();
115
+ },
116
+ };
117
+
118
+ const config = { ...validBaseConfig, fheKeyStorage: fakeStorage };
119
+ const result = createCofhesdkConfigBase(config);
120
+
121
+ expect(result.fheKeyStorage).not.toBeNull();
122
+ await result.fheKeyStorage!.getItem('test');
123
+ await result.fheKeyStorage!.setItem('test', 'test');
124
+ await result.fheKeyStorage!.removeItem('test');
125
+
126
+ expect(getItemCalled).toBe(true);
127
+ expect(setItemCalled).toBe(true);
128
+ expect(removeItemCalled).toBe(true);
129
+ });
130
+
131
+ it('mocks', () => {
132
+ expectInvalidConfigItem('mocks', 'not-an-object');
133
+ expectInvalidConfigItem('mocks', null);
134
+
135
+ expectValidConfigItem('mocks', { sealOutputDelay: 1000 }, { sealOutputDelay: 1000 });
136
+ expectValidConfigItem('mocks', undefined, { sealOutputDelay: 0 });
137
+ });
138
+
139
+ it('mocks.sealOutputDelay', () => {
140
+ expectInvalidConfigItem('mocks.sealOutputDelay', 'not-a-number');
141
+ expectInvalidConfigItem('mocks.sealOutputDelay', null);
142
+
143
+ expectValidConfigItem('mocks.sealOutputDelay', undefined, 0);
144
+ expectValidConfigItem('mocks.sealOutputDelay', 1000, 1000);
145
+ });
146
+
147
+ it('should get config item', () => {
148
+ const config: CofhesdkInputConfig = {
149
+ supportedChains: [sepolia],
150
+ };
151
+
152
+ const result = createCofhesdkConfigBase(config);
153
+
154
+ const supportedChains = getCofhesdkConfigItem(result, 'supportedChains');
155
+ expect(supportedChains).toEqual(config.supportedChains);
156
+ });
157
+ });
158
+
159
+ describe('Config helper functions', () => {
160
+ const config = createCofhesdkConfigBase({
161
+ supportedChains: [sepolia, hardhat],
162
+ });
163
+
164
+ describe('getSupportedChainOrThrow', () => {
165
+ it('should return chain when found', () => {
166
+ expect(getSupportedChainOrThrow(config, sepolia.id)).toEqual(sepolia);
167
+ });
168
+
169
+ it('should throw UnsupportedChain error when not found', () => {
170
+ expect(() => getSupportedChainOrThrow(config, 999999)).toThrow();
171
+ });
172
+ });
173
+
174
+ describe('getCoFheUrlOrThrow', () => {
175
+ it('should return coFheUrl', () => {
176
+ expect(getCoFheUrlOrThrow(config, sepolia.id)).toBe(sepolia.coFheUrl);
177
+ });
178
+
179
+ it('should throw when chain not found', () => {
180
+ expect(() => getCoFheUrlOrThrow(config, 999999)).toThrow();
181
+ });
182
+
183
+ it('should throw MissingConfig when url not set', () => {
184
+ const configWithoutUrl = createCofhesdkConfigBase({
185
+ supportedChains: [{ ...sepolia, coFheUrl: undefined } as any],
186
+ });
187
+ expect(() => getCoFheUrlOrThrow(configWithoutUrl, sepolia.id)).toThrow();
188
+ });
189
+ });
190
+
191
+ describe('getZkVerifierUrlOrThrow', () => {
192
+ it('should return verifierUrl', () => {
193
+ expect(getZkVerifierUrlOrThrow(config, sepolia.id)).toBe(sepolia.verifierUrl);
194
+ });
195
+
196
+ it('should throw when chain not found', () => {
197
+ expect(() => getZkVerifierUrlOrThrow(config, 999999)).toThrow();
198
+ });
199
+
200
+ it('should throw ZkVerifierUrlUninitialized when url not set', () => {
201
+ const configWithoutUrl = createCofhesdkConfigBase({
202
+ supportedChains: [{ ...sepolia, verifierUrl: undefined } as any],
203
+ });
204
+ expect(() => getZkVerifierUrlOrThrow(configWithoutUrl, sepolia.id)).toThrow();
205
+ });
206
+ });
207
+
208
+ describe('getThresholdNetworkUrlOrThrow', () => {
209
+ it('should return thresholdNetworkUrl', () => {
210
+ expect(getThresholdNetworkUrlOrThrow(config, sepolia.id)).toBe(sepolia.thresholdNetworkUrl);
211
+ });
212
+
213
+ it('should throw when chain not found', () => {
214
+ expect(() => getThresholdNetworkUrlOrThrow(config, 999999)).toThrow();
215
+ });
216
+
217
+ it('should throw ThresholdNetworkUrlUninitialized when url not set', () => {
218
+ const configWithoutUrl = createCofhesdkConfigBase({
219
+ supportedChains: [{ ...sepolia, thresholdNetworkUrl: undefined } as any],
220
+ });
221
+ expect(() => getThresholdNetworkUrlOrThrow(configWithoutUrl, sepolia.id)).toThrow();
222
+ });
223
+ });
224
+ });