@cofhe/sdk 0.1.1 → 0.2.1

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 (107) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/adapters/ethers6.ts +28 -28
  3. package/adapters/hardhat.ts +0 -1
  4. package/adapters/index.test.ts +14 -19
  5. package/adapters/smartWallet.ts +81 -73
  6. package/adapters/test-utils.ts +45 -45
  7. package/adapters/types.ts +3 -3
  8. package/chains/chains/localcofhe.ts +14 -0
  9. package/chains/chains.test.ts +2 -1
  10. package/chains/defineChain.ts +2 -2
  11. package/chains/index.ts +3 -1
  12. package/chains/types.ts +3 -3
  13. package/core/baseBuilder.ts +30 -49
  14. package/core/client.test.ts +200 -72
  15. package/core/client.ts +152 -148
  16. package/core/clientTypes.ts +114 -0
  17. package/core/config.test.ts +30 -11
  18. package/core/config.ts +26 -13
  19. package/core/consts.ts +18 -0
  20. package/core/decrypt/cofheMocksSealOutput.ts +2 -4
  21. package/core/decrypt/decryptHandleBuilder.ts +51 -45
  22. package/core/decrypt/{tnSealOutput.ts → tnSealOutputV1.ts} +1 -1
  23. package/core/decrypt/tnSealOutputV2.ts +298 -0
  24. package/core/encrypt/cofheMocksZkVerifySign.ts +15 -16
  25. package/core/encrypt/encryptInputsBuilder.test.ts +132 -116
  26. package/core/encrypt/encryptInputsBuilder.ts +159 -111
  27. package/core/encrypt/encryptUtils.ts +6 -3
  28. package/core/encrypt/zkPackProveVerify.ts +70 -8
  29. package/core/error.ts +0 -2
  30. package/core/fetchKeys.test.ts +1 -18
  31. package/core/fetchKeys.ts +0 -26
  32. package/core/index.ts +37 -17
  33. package/core/keyStore.ts +65 -38
  34. package/core/permits.test.ts +255 -4
  35. package/core/permits.ts +83 -18
  36. package/core/types.ts +198 -152
  37. package/core/utils.ts +43 -1
  38. package/dist/adapters.d.cts +38 -20
  39. package/dist/adapters.d.ts +38 -20
  40. package/dist/chains.cjs +18 -8
  41. package/dist/chains.d.cts +31 -9
  42. package/dist/chains.d.ts +31 -9
  43. package/dist/chains.js +1 -1
  44. package/dist/{chunk-KFGPTJ6X.js → chunk-I5WFEYXX.js} +1768 -1526
  45. package/dist/{chunk-LU7BMUUT.js → chunk-R3B5TMVX.js} +330 -197
  46. package/dist/{chunk-GZCQQYVI.js → chunk-TBLR7NNE.js} +18 -9
  47. package/dist/{types-PhwGgQvs.d.ts → clientTypes-RqkgkV2i.d.ts} +331 -429
  48. package/dist/{types-bB7wLj0q.d.cts → clientTypes-e4filDzK.d.cts} +331 -429
  49. package/dist/core.cjs +3000 -2625
  50. package/dist/core.d.cts +113 -7
  51. package/dist/core.d.ts +113 -7
  52. package/dist/core.js +3 -3
  53. package/dist/node.cjs +2851 -2526
  54. package/dist/node.d.cts +4 -4
  55. package/dist/node.d.ts +4 -4
  56. package/dist/node.js +4 -3
  57. package/dist/{permit-S9CnI6MF.d.cts → permit-MZ502UBl.d.cts} +54 -41
  58. package/dist/{permit-S9CnI6MF.d.ts → permit-MZ502UBl.d.ts} +54 -41
  59. package/dist/permits.cjs +328 -195
  60. package/dist/permits.d.cts +113 -825
  61. package/dist/permits.d.ts +113 -825
  62. package/dist/permits.js +1 -1
  63. package/dist/types-YiAC4gig.d.cts +33 -0
  64. package/dist/types-YiAC4gig.d.ts +33 -0
  65. package/dist/web.cjs +3067 -2527
  66. package/dist/web.d.cts +22 -6
  67. package/dist/web.d.ts +22 -6
  68. package/dist/web.js +185 -9
  69. package/dist/zkProve.worker.cjs +93 -0
  70. package/dist/zkProve.worker.d.cts +2 -0
  71. package/dist/zkProve.worker.d.ts +2 -0
  72. package/dist/zkProve.worker.js +91 -0
  73. package/node/client.test.ts +20 -25
  74. package/node/encryptInputs.test.ts +18 -38
  75. package/node/index.ts +1 -0
  76. package/package.json +15 -15
  77. package/permits/index.ts +1 -0
  78. package/permits/localstorage.test.ts +9 -14
  79. package/permits/onchain-utils.ts +221 -0
  80. package/permits/permit.test.ts +76 -27
  81. package/permits/permit.ts +58 -95
  82. package/permits/sealing.test.ts +3 -3
  83. package/permits/sealing.ts +2 -2
  84. package/permits/store.test.ts +10 -50
  85. package/permits/store.ts +9 -21
  86. package/permits/test-utils.ts +11 -3
  87. package/permits/types.ts +39 -9
  88. package/permits/utils.ts +0 -5
  89. package/permits/validation.test.ts +29 -32
  90. package/permits/validation.ts +114 -176
  91. package/web/client.web.test.ts +20 -25
  92. package/web/config.web.test.ts +0 -2
  93. package/web/encryptInputs.web.test.ts +31 -54
  94. package/web/index.ts +65 -1
  95. package/web/storage.ts +19 -5
  96. package/web/worker.builder.web.test.ts +148 -0
  97. package/web/worker.config.web.test.ts +329 -0
  98. package/web/worker.output.web.test.ts +84 -0
  99. package/web/workerManager.test.ts +80 -0
  100. package/web/workerManager.ts +214 -0
  101. package/web/workerManager.web.test.ts +114 -0
  102. package/web/zkProve.worker.ts +133 -0
  103. package/core/result.test.ts +0 -180
  104. package/core/result.ts +0 -67
  105. package/core/test-utils.ts +0 -45
  106. package/dist/types-KImPrEIe.d.cts +0 -48
  107. package/dist/types-KImPrEIe.d.ts +0 -48
@@ -1,8 +1,8 @@
1
1
  import { describe, it, expect, vi, beforeEach } from 'vitest';
2
2
  import { createCofhesdkClientBase } from './client.js';
3
- import { type CofhesdkClient, type CofhesdkClientConnectionState } from './types.js';
4
- import { createCofhesdkConfigBase } from './config.js';
5
- import { CofhesdkErrorCode } from './error.js';
3
+ import { type CofhesdkClient, type CofhesdkClientConnectionState } from './clientTypes.js';
4
+ import { createCofhesdkConfigBase, type CofhesdkEnvironment } from './config.js';
5
+ import { CofhesdkError, CofhesdkErrorCode } from './error.js';
6
6
  import { type PublicClient, type WalletClient } from 'viem';
7
7
  import { EncryptInputsBuilder } from './encrypt/encryptInputsBuilder.js';
8
8
  import { Encryptable } from './types.js';
@@ -20,10 +20,6 @@ vi.mock('./keyStore', () => ({
20
20
  })),
21
21
  }));
22
22
 
23
- vi.mock('./fetchKeys', () => ({
24
- fetchMultichainKeys: vi.fn().mockResolvedValue(undefined),
25
- }));
26
-
27
23
  // Test helpers
28
24
  const createMockPublicClient = (chainId = 11155111): PublicClient =>
29
25
  ({
@@ -61,6 +57,8 @@ describe('createCofhesdkClientBase', () => {
61
57
  expect(snapshot.connectError).toBe(undefined);
62
58
  expect(snapshot.chainId).toBe(undefined);
63
59
  expect(snapshot.account).toBe(undefined);
60
+ expect(snapshot.publicClient).toBe(undefined);
61
+ expect(snapshot.walletClient).toBe(undefined);
64
62
  });
65
63
 
66
64
  it('should expose convenience flags', () => {
@@ -74,6 +72,24 @@ describe('createCofhesdkClientBase', () => {
74
72
  });
75
73
  });
76
74
 
75
+ describe('environment', () => {
76
+ it('should create a client with the correct environment', async () => {
77
+ const environments: CofhesdkEnvironment[] = ['node', 'hardhat', 'web', 'react'];
78
+ for (const environment of environments) {
79
+ const config = createCofhesdkConfigBase({ environment, supportedChains: [] });
80
+ const client = createCofhesdkClientBase({
81
+ config,
82
+ zkBuilderAndCrsGenerator: {} as any,
83
+ tfhePublicKeyDeserializer: {} as any,
84
+ compactPkeCrsDeserializer: {} as any,
85
+ initTfhe: () => Promise.resolve(false),
86
+ });
87
+
88
+ expect(client.config.environment).toBe(environment);
89
+ }
90
+ });
91
+ });
92
+
77
93
  describe('reactive state', () => {
78
94
  it('should notify subscribers of state changes', async () => {
79
95
  const states: CofhesdkClientConnectionState[] = [];
@@ -88,12 +104,16 @@ describe('createCofhesdkClientBase', () => {
88
104
  expect(states[0].connected).toBe(false);
89
105
  expect(states[0].chainId).toBe(undefined);
90
106
  expect(states[0].account).toBe(undefined);
107
+ expect(states[0].publicClient).toBe(undefined);
108
+ expect(states[0].walletClient).toBe(undefined);
91
109
 
92
110
  // Expect states[1] to be the connected state
93
111
  expect(states[1].connected).toBe(true);
94
112
  expect(states[1].connecting).toBe(false);
95
113
  expect(states[1].chainId).toBe(11155111);
96
114
  expect(states[1].account).toBe('0x1234567890123456789012345678901234567890');
115
+ expect(states[1].publicClient).toBe(publicClient);
116
+ expect(states[1].walletClient).toBe(walletClient);
97
117
  });
98
118
 
99
119
  it('should stop notifications after unsubscribe', async () => {
@@ -116,10 +136,7 @@ describe('createCofhesdkClientBase', () => {
116
136
  const publicClient = createMockPublicClient(11155111);
117
137
  const walletClient = createMockWalletClient(['0xabcd']);
118
138
 
119
- const result = await client.connect(publicClient, walletClient);
120
-
121
- expect(result.success).toBe(true);
122
- expect(result.data).toBe(true);
139
+ await client.connect(publicClient, walletClient);
123
140
 
124
141
  expect(client.connected).toBe(true);
125
142
  expect(client.connecting).toBe(false);
@@ -127,6 +144,8 @@ describe('createCofhesdkClientBase', () => {
127
144
  const snapshot = client.getSnapshot();
128
145
  expect(snapshot.chainId).toBe(11155111);
129
146
  expect(snapshot.account).toBe('0xabcd');
147
+ expect(snapshot.publicClient).toBe(publicClient);
148
+ expect(snapshot.walletClient).toBe(walletClient);
130
149
  });
131
150
 
132
151
  it('should set connecting state during connection', async () => {
@@ -157,95 +176,215 @@ describe('createCofhesdkClientBase', () => {
157
176
  await promise1;
158
177
  });
159
178
 
160
- it('should return immediately if already connected with same clients', async () => {
161
- const publicClient = createMockPublicClient();
162
- const walletClient = createMockWalletClient();
179
+ it('should ensure the latest connection attempt wins when connecting twice', async () => {
180
+ let resolveChainId1: (value: number) => void;
181
+ let resolveAddresses1: (value: string[]) => void;
182
+ let resolveChainId2: (value: number) => void;
183
+ let resolveAddresses2: (value: string[]) => void;
184
+
185
+ const chainIdPromise1 = new Promise<number>((resolve) => {
186
+ resolveChainId1 = resolve;
187
+ });
188
+ const addressesPromise1 = new Promise<string[]>((resolve) => {
189
+ resolveAddresses1 = resolve;
190
+ });
191
+
192
+ const chainIdPromise2 = new Promise<number>((resolve) => {
193
+ resolveChainId2 = resolve;
194
+ });
195
+ const addressesPromise2 = new Promise<string[]>((resolve) => {
196
+ resolveAddresses2 = resolve;
197
+ });
198
+
199
+ const publicClient1 = createMockPublicClient() as any;
200
+ publicClient1.getChainId = vi.fn().mockReturnValue(chainIdPromise1);
201
+ const walletClient1 = createMockWalletClient() as any;
202
+ walletClient1.getAddresses = vi.fn().mockReturnValue(addressesPromise1);
203
+
204
+ const publicClient2 = createMockPublicClient() as any;
205
+ publicClient2.getChainId = vi.fn().mockReturnValue(chainIdPromise2);
206
+ const walletClient2 = createMockWalletClient() as any;
207
+ walletClient2.getAddresses = vi.fn().mockReturnValue(addressesPromise2);
208
+
209
+ const promise1 = client.connect(publicClient1, walletClient1);
210
+ expect(client.connecting).toBe(true);
163
211
 
164
- await client.connect(publicClient, walletClient);
165
- const result = await client.connect(publicClient, walletClient);
212
+ const promise2 = client.connect(publicClient2, walletClient2);
213
+
214
+ // Resolve the second connect first
215
+ resolveChainId2!(222);
216
+ resolveAddresses2!(['0x2222222222222222222222222222222222222222']);
217
+ await promise2;
218
+
219
+ expect(client.connected).toBe(true);
220
+ expect(client.connecting).toBe(false);
221
+ expect(client.getSnapshot().chainId).toBe(222);
222
+ expect(client.getSnapshot().account).toBe('0x2222222222222222222222222222222222222222');
223
+ expect(client.getSnapshot().publicClient).toBe(publicClient2);
224
+ expect(client.getSnapshot().walletClient).toBe(walletClient2);
225
+
226
+ // Now resolve the first connect; it must not overwrite the latest state.
227
+ resolveChainId1!(111);
228
+ resolveAddresses1!(['0x1111111111111111111111111111111111111111']);
229
+ await promise1;
166
230
 
167
- expect(result.success).toBe(true);
231
+ expect(client.getSnapshot().chainId).toBe(222);
232
+ expect(client.getSnapshot().account).toBe('0x2222222222222222222222222222222222222222');
233
+ expect(client.getSnapshot().publicClient).toBe(publicClient2);
234
+ expect(client.getSnapshot().walletClient).toBe(walletClient2);
168
235
  });
169
236
 
170
- it('should handle getChainId throwing an error', async () => {
171
- const publicClient = createMockPublicClient();
172
- const error = new Error('Network error');
173
- publicClient.getChainId = vi.fn().mockRejectedValue(error);
174
- const walletClient = createMockWalletClient();
237
+ it('should allow disconnect while connecting and never end up connected afterwards', async () => {
238
+ let resolveChainId: (value: number) => void;
239
+ let resolveAddresses: (value: string[]) => void;
240
+
241
+ const chainIdPromise = new Promise<number>((resolve) => {
242
+ resolveChainId = resolve;
243
+ });
244
+ const addressesPromise = new Promise<string[]>((resolve) => {
245
+ resolveAddresses = resolve;
246
+ });
247
+
248
+ const publicClient = createMockPublicClient() as any;
249
+ publicClient.getChainId = vi.fn().mockReturnValue(chainIdPromise);
250
+
251
+ const walletClient = createMockWalletClient() as any;
252
+ walletClient.getAddresses = vi.fn().mockReturnValue(addressesPromise);
253
+
254
+ const connectPromise = client.connect(publicClient, walletClient);
255
+ expect(client.connecting).toBe(true);
175
256
 
176
- const result = await client.connect(publicClient, walletClient);
257
+ client.disconnect();
258
+ expect(client.connected).toBe(false);
259
+ expect(client.connecting).toBe(false);
260
+
261
+ resolveChainId!(11155111);
262
+ resolveAddresses!(['0x1234567890123456789012345678901234567890']);
263
+
264
+ await connectPromise;
177
265
 
178
- expect(result.success).toBe(false);
179
- expect(result.error?.code).toBe(CofhesdkErrorCode.PublicWalletGetChainIdFailed);
180
- expect(result.error?.message).toBe('getting chain ID from public client failed | Caused by: Network error');
181
- expect(result.error?.cause).toBe(error);
182
266
  expect(client.connected).toBe(false);
267
+ expect(client.connecting).toBe(false);
183
268
  });
184
269
 
185
- it('should handle getChainId returning null', async () => {
270
+ it('should handle publicClient.getChainId throwing an error', async () => {
271
+ const publicClient = createMockPublicClient();
272
+ const getChainIdError = new Error('Network error');
273
+ publicClient.getChainId = vi.fn().mockRejectedValue(getChainIdError);
274
+ const walletClient = createMockWalletClient();
275
+
276
+ try {
277
+ await client.connect(publicClient, walletClient);
278
+ } catch (error) {
279
+ expect(error).toBeInstanceOf(CofhesdkError);
280
+ expect((error as CofhesdkError).code).toBe(CofhesdkErrorCode.PublicWalletGetChainIdFailed);
281
+ expect((error as CofhesdkError).message).toBe(
282
+ 'getting chain ID from public client failed | Caused by: Network error'
283
+ );
284
+ expect((error as CofhesdkError).cause).toBe(getChainIdError);
285
+ }
286
+ });
287
+
288
+ it('should handle publicClient.getChainId returning null', async () => {
186
289
  const publicClient = createMockPublicClient();
187
290
  publicClient.getChainId = vi.fn().mockResolvedValue(null);
188
291
  const walletClient = createMockWalletClient();
189
292
 
190
- const result = await client.connect(publicClient, walletClient);
293
+ const connectPromise = client.connect(publicClient, walletClient);
191
294
 
192
- expect(result.success).toBe(false);
193
- expect(result.error?.code).toBe(CofhesdkErrorCode.PublicWalletGetChainIdFailed);
194
- expect(result.error?.message).toBe('chain ID from public client is null');
195
- expect(result.error?.cause).toBe(undefined);
196
- expect(client.connected).toBe(false);
295
+ try {
296
+ await connectPromise;
297
+ } catch (error) {
298
+ expect(error).toBeInstanceOf(CofhesdkError);
299
+ expect((error as CofhesdkError).code).toBe(CofhesdkErrorCode.PublicWalletGetChainIdFailed);
300
+ expect((error as CofhesdkError).message).toBe('chain ID from public client is null');
301
+ }
197
302
  });
198
303
 
199
- it('should handle getAddresses throwing an error', async () => {
304
+ it('should handle walletClient.getAddresses throwing an error', async () => {
200
305
  const publicClient = createMockPublicClient();
201
- const error = new Error('Network error');
306
+ const getAddressesError = new Error('Network error');
202
307
  const walletClient = createMockWalletClient();
203
- walletClient.getAddresses = vi.fn().mockRejectedValue(error);
308
+ walletClient.getAddresses = vi.fn().mockRejectedValue(getAddressesError);
204
309
 
205
- const result = await client.connect(publicClient, walletClient);
310
+ const connectPromise = client.connect(publicClient, walletClient);
206
311
 
207
- expect(result.success).toBe(false);
208
- expect(result.error?.code).toBe(CofhesdkErrorCode.PublicWalletGetAddressesFailed);
209
- expect(result.error?.message).toBe('getting address from wallet client failed | Caused by: Network error');
210
- expect(result.error?.cause).toBe(error);
211
- expect(client.connected).toBe(false);
312
+ try {
313
+ await connectPromise;
314
+ } catch (error) {
315
+ expect(error).toBeInstanceOf(CofhesdkError);
316
+ expect((error as CofhesdkError).code).toBe(CofhesdkErrorCode.PublicWalletGetAddressesFailed);
317
+ expect((error as CofhesdkError).message).toBe(
318
+ 'getting address from wallet client failed | Caused by: Network error'
319
+ );
320
+ expect((error as CofhesdkError).cause).toBe(getAddressesError);
321
+ }
212
322
  });
213
323
 
214
- it('should handle getAddresses returning an empty array', async () => {
324
+ it('should handle walletClient.getAddresses returning an empty array', async () => {
215
325
  const publicClient = createMockPublicClient();
216
326
  const walletClient = createMockWalletClient([]);
217
327
 
218
- const result = await client.connect(publicClient, walletClient);
328
+ const connectPromise = client.connect(publicClient, walletClient);
219
329
 
220
- expect(result.success).toBe(false);
221
- expect(result.error?.code).toBe(CofhesdkErrorCode.PublicWalletGetAddressesFailed);
222
- expect(result.error?.message).toBe('address from wallet client is null');
223
- expect(result.error?.cause).toBe(undefined);
224
- expect(client.connected).toBe(false);
330
+ try {
331
+ await connectPromise;
332
+ } catch (error) {
333
+ expect(error).toBeInstanceOf(CofhesdkError);
334
+ expect((error as CofhesdkError).code).toBe(CofhesdkErrorCode.PublicWalletGetAddressesFailed);
335
+ expect((error as CofhesdkError).message).toBe('address from wallet client is null');
336
+ }
225
337
  });
226
338
 
227
339
  it('should store error in state on failure', async () => {
228
340
  const publicClient = createMockPublicClient();
229
- const error = new Error('Network error');
230
- publicClient.getChainId = vi.fn().mockRejectedValue(error);
341
+ const getChainIdError = new Error('Network error');
342
+ publicClient.getChainId = vi.fn().mockRejectedValue(getChainIdError);
231
343
  const walletClient = createMockWalletClient();
232
344
 
233
- const result = await client.connect(publicClient, walletClient);
345
+ const connectPromise = client.connect(publicClient, walletClient);
346
+
347
+ try {
348
+ await connectPromise;
349
+ } catch (error) {
350
+ expect(error).toBeInstanceOf(CofhesdkError);
351
+ expect((error as CofhesdkError).code).toBe(CofhesdkErrorCode.PublicWalletGetChainIdFailed);
352
+ expect((error as CofhesdkError).message).toBe(
353
+ 'getting chain ID from public client failed | Caused by: Network error'
354
+ );
355
+ expect((error as CofhesdkError).cause).toBe(getChainIdError);
356
+ }
357
+ });
358
+
359
+ it('should disconnect and clear connection state', async () => {
360
+ const publicClient = createMockPublicClient(11155111);
361
+ const walletClient = createMockWalletClient(['0xabcd']);
362
+
363
+ await client.connect(publicClient, walletClient);
364
+ expect(client.connected).toBe(true);
365
+
366
+ client.disconnect();
367
+
368
+ expect(client.connected).toBe(false);
369
+ expect(client.connecting).toBe(false);
234
370
 
235
- expect(result.success).toBe(false);
236
371
  const snapshot = client.getSnapshot();
237
- expect(snapshot.connectError).toBeTruthy();
238
- expect(snapshot.connected).toBe(false);
372
+ expect(snapshot.chainId).toBe(undefined);
373
+ expect(snapshot.account).toBe(undefined);
374
+ expect(snapshot.publicClient).toBe(undefined);
375
+ expect(snapshot.walletClient).toBe(undefined);
376
+ expect(snapshot.connectError).toBe(undefined);
239
377
  });
240
378
  });
241
379
 
242
380
  describe('encryptInputs', () => {
243
381
  it('should throw if not connected', async () => {
244
- const result = await client
245
- .encryptInputs([Encryptable.uint8(1n), Encryptable.uint8(2n), Encryptable.uint8(3n)])
246
- .encrypt();
247
- expect(result.success).toBe(false);
248
- expect(result.error?.code).toBe(CofhesdkErrorCode.NotConnected);
382
+ try {
383
+ await client.encryptInputs([Encryptable.uint8(1n), Encryptable.uint8(2n), Encryptable.uint8(3n)]).encrypt();
384
+ } catch (error) {
385
+ expect(error).toBeInstanceOf(CofhesdkError);
386
+ expect((error as CofhesdkError).code).toBe(CofhesdkErrorCode.NotConnected);
387
+ }
249
388
  });
250
389
 
251
390
  it('should create EncryptInputsBuilder when connected', async () => {
@@ -264,17 +403,6 @@ describe('createCofhesdkClientBase', () => {
264
403
  });
265
404
  });
266
405
 
267
- describe('initializationResults', () => {
268
- it('should have keyFetchResult promise', () => {
269
- expect(client.initializationResults.keyFetchResult).toBeInstanceOf(Promise);
270
- });
271
-
272
- it('should resolve keyFetchResult', async () => {
273
- const result = await client.initializationResults.keyFetchResult;
274
- expect(result.success).toBe(true);
275
- });
276
- });
277
-
278
406
  describe('permits', () => {
279
407
  it('should expose permits', () => {
280
408
  expect(client.permits).toBeDefined();