@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
@@ -44,8 +44,9 @@ describe('PermitUtils Tests', () => {
44
44
  name: 'Test Permit',
45
45
  };
46
46
 
47
- const permit = await PermitUtils.createSelf(options);
47
+ const permit = PermitUtils.createSelf(options);
48
48
 
49
+ expect(permit.hash).toBe(PermitUtils.getHash(permit));
49
50
  expect(permit.type).toBe('self');
50
51
  expect(permit.name).toBe('Test Permit');
51
52
  expect(permit.type).toBe('self');
@@ -66,7 +67,7 @@ describe('PermitUtils Tests', () => {
66
67
  name: 'Test Permit',
67
68
  };
68
69
 
69
- await expect(PermitUtils.createSelf(options)).rejects.toThrow();
70
+ expect(() => PermitUtils.createSelf(options)).toThrowError();
70
71
  });
71
72
  });
72
73
 
@@ -79,8 +80,9 @@ describe('PermitUtils Tests', () => {
79
80
  name: 'Test Sharing Permit',
80
81
  };
81
82
 
82
- const permit = await PermitUtils.createSharing(options);
83
+ const permit = PermitUtils.createSharing(options);
83
84
 
85
+ expect(permit.hash).toBe(PermitUtils.getHash(permit));
84
86
  expect(permit.type).toBe('sharing');
85
87
  expect(permit.name).toBe('Test Sharing Permit');
86
88
  expect(permit.type).toBe('sharing');
@@ -103,7 +105,7 @@ describe('PermitUtils Tests', () => {
103
105
  name: 'Test Sharing Permit',
104
106
  };
105
107
 
106
- await expect(PermitUtils.createSharing(options)).rejects.toThrow();
108
+ expect(() => PermitUtils.createSharing(options)).toThrow();
107
109
  });
108
110
  });
109
111
 
@@ -111,13 +113,15 @@ describe('PermitUtils Tests', () => {
111
113
  it('should import a shared permit with valid options', async () => {
112
114
  const options: ImportSharedPermitOptions = {
113
115
  issuer: bobAddress,
116
+ expiration: Math.floor(Date.now() / 1000) + 3600, // 1 hour from now
114
117
  recipient: aliceAddress,
115
118
  issuerSignature: '0x1234567890abcdef',
116
119
  name: 'Test Import Permit',
117
120
  };
118
121
 
119
- const permit = await PermitUtils.importShared(options);
122
+ const permit = PermitUtils.importShared(options);
120
123
 
124
+ expect(permit.hash).toBe(PermitUtils.getHash(permit));
121
125
  expect(permit.type).toBe('recipient');
122
126
  expect(permit.name).toBe('Test Import Permit');
123
127
  expect(permit.issuer).toBe(bobAddress);
@@ -134,13 +138,14 @@ describe('PermitUtils Tests', () => {
134
138
  it('should import a shared permit with valid options as string', async () => {
135
139
  const options: ImportSharedPermitOptions = {
136
140
  issuer: bobAddress,
141
+ expiration: Math.floor(Date.now() / 1000) + 3600, // 1 hour from now
137
142
  recipient: aliceAddress,
138
143
  issuerSignature: '0x1234567890abcdef',
139
144
  };
140
145
 
141
146
  const stringOptions = JSON.stringify(options);
142
147
 
143
- const permit = await PermitUtils.importShared(stringOptions);
148
+ const permit = PermitUtils.importShared(stringOptions);
144
149
 
145
150
  expect(permit.type).toBe('recipient');
146
151
  });
@@ -153,7 +158,7 @@ describe('PermitUtils Tests', () => {
153
158
  issuerSignature: '0x1234567890abcdef',
154
159
  } as unknown as ImportSharedPermitOptions;
155
160
 
156
- await expect(PermitUtils.importShared(options)).rejects.toThrow();
161
+ expect(() => PermitUtils.importShared(options)).toThrow();
157
162
 
158
163
  const options2 = {
159
164
  type: 'recipient',
@@ -162,18 +167,28 @@ describe('PermitUtils Tests', () => {
162
167
  issuerSignature: '0x1234567890abcdef',
163
168
  } as unknown as ImportSharedPermitOptions;
164
169
 
165
- await expect(PermitUtils.importShared(options2)).rejects.toThrow();
170
+ expect(() => PermitUtils.importShared(options2)).toThrow();
166
171
  });
167
172
 
168
173
  it('should throw error for missing issuerSignature', async () => {
169
174
  const options: ImportSharedPermitOptions = {
170
175
  issuer: bobAddress,
176
+ expiration: Math.floor(Date.now() / 1000) + 3600, // 1 hour from now
171
177
  recipient: aliceAddress,
172
178
  issuerSignature: '0x', // Invalid empty signature
173
179
  name: 'Test Import Permit',
174
180
  };
175
181
 
176
- await expect(PermitUtils.importShared(options)).rejects.toThrow();
182
+ expect(() => PermitUtils.importShared(options)).toThrow();
183
+ });
184
+
185
+ it('should throw error for missing expiration', async () => {
186
+ const options = {
187
+ issuer: bobAddress,
188
+ recipient: aliceAddress,
189
+ issuerSignature: '0x1234567890abcdef',
190
+ } as unknown as ImportSharedPermitOptions;
191
+ expect(() => PermitUtils.importShared(options)).toThrow();
177
192
  });
178
193
  });
179
194
 
@@ -217,6 +232,7 @@ describe('PermitUtils Tests', () => {
217
232
  const options: ImportSharedPermitOptions = {
218
233
  issuer: bobAddress,
219
234
  recipient: aliceAddress,
235
+ expiration: Math.floor(Date.now() / 1000) + 3600, // 1 hour from now
220
236
  issuerSignature: '0x1234567890abcdef',
221
237
  name: 'Test Import Permit',
222
238
  };
@@ -233,6 +249,7 @@ describe('PermitUtils Tests', () => {
233
249
  const options: ImportSharedPermitOptions = {
234
250
  issuer: bobAddress,
235
251
  recipient: aliceAddress,
252
+ expiration: Math.floor(Date.now() / 1000) + 3600, // 1 hour from now
236
253
  issuerSignature: '0x1234567890abcdef',
237
254
  };
238
255
 
@@ -250,6 +267,7 @@ describe('PermitUtils Tests', () => {
250
267
  const options: ImportSharedPermitOptions = {
251
268
  issuer: bobAddress,
252
269
  recipient: aliceAddress,
270
+ expiration: Math.floor(Date.now() / 1000) + 3600, // 1 hour from now
253
271
  issuerSignature: '0x1234567890abcdef',
254
272
  };
255
273
 
@@ -266,7 +284,7 @@ describe('PermitUtils Tests', () => {
266
284
 
267
285
  describe('sign', () => {
268
286
  it('should sign a self permit', async () => {
269
- const permit = await PermitUtils.createSelf({
287
+ const permit = PermitUtils.createSelf({
270
288
  issuer: bobAddress,
271
289
  name: 'Test Permit',
272
290
  });
@@ -280,10 +298,11 @@ describe('PermitUtils Tests', () => {
280
298
  });
281
299
 
282
300
  it('should sign a recipient permit', async () => {
283
- const permit = await PermitUtils.importShared({
301
+ const permit = PermitUtils.importShared({
284
302
  issuer: bobAddress,
285
303
  recipient: aliceAddress,
286
- issuerSignature: '0xexisting-signature',
304
+ expiration: Math.floor(Date.now() / 1000) + 3600, // 1 hour from now
305
+ issuerSignature: '0x1111111111111111111111111111111111111111111111111111111111111111',
287
306
  name: 'Test Permit',
288
307
  });
289
308
 
@@ -295,7 +314,7 @@ describe('PermitUtils Tests', () => {
295
314
  });
296
315
 
297
316
  it('should throw error for undefined signer', async () => {
298
- const permit = await PermitUtils.createSelf({
317
+ const permit = PermitUtils.createSelf({
299
318
  issuer: bobAddress,
300
319
  name: 'Test Permit',
301
320
  });
@@ -309,7 +328,7 @@ describe('PermitUtils Tests', () => {
309
328
 
310
329
  describe('serialize/deserialize', () => {
311
330
  it('should serialize and deserialize a permit', async () => {
312
- const originalPermit = await PermitUtils.createSelf({
331
+ const originalPermit = PermitUtils.createSelf({
313
332
  issuer: bobAddress,
314
333
  name: 'Test Permit',
315
334
  });
@@ -348,26 +367,26 @@ describe('PermitUtils Tests', () => {
348
367
 
349
368
  describe('getHash', () => {
350
369
  it('should generate consistent hash for same permit data', async () => {
351
- const permit1 = await PermitUtils.createSelf({
370
+ const expiration = Math.floor(Date.now() / 1000) + 3600; // 1 hour from now
371
+ const permit1 = PermitUtils.createSelf({
372
+ expiration,
352
373
  issuer: bobAddress,
353
374
  name: 'Test Permit',
354
375
  });
355
376
 
356
- const permit2 = await PermitUtils.createSelf({
377
+ const permit2 = PermitUtils.createSelf({
378
+ expiration,
357
379
  issuer: bobAddress,
358
380
  name: 'Test Permit',
359
381
  });
360
382
 
361
- const hash1 = PermitUtils.getHash(permit1);
362
- const hash2 = PermitUtils.getHash(permit2);
363
-
364
- expect(hash1).toBe(hash2);
383
+ expect(permit1.hash).toBe(permit2.hash);
365
384
  });
366
385
  });
367
386
 
368
387
  describe('export', () => {
369
388
  it('should export permit data without sensitive fields', async () => {
370
- const permit = await PermitUtils.createSelf({
389
+ const permit = PermitUtils.createSelf({
371
390
  issuer: bobAddress,
372
391
  name: 'Test Permit',
373
392
  });
@@ -384,7 +403,7 @@ describe('PermitUtils Tests', () => {
384
403
 
385
404
  describe('updateName', () => {
386
405
  it('should update permit name immutably', async () => {
387
- const permit = await PermitUtils.createSelf({
406
+ const permit = PermitUtils.createSelf({
388
407
  issuer: bobAddress,
389
408
  name: 'Original Name',
390
409
  });
@@ -399,13 +418,13 @@ describe('PermitUtils Tests', () => {
399
418
 
400
419
  describe('validation helpers', () => {
401
420
  it('should check if permit is expired', async () => {
402
- const expiredPermit = await PermitUtils.createSelf({
421
+ const expiredPermit = PermitUtils.createSelf({
403
422
  issuer: bobAddress,
404
423
  name: 'Test Permit',
405
424
  expiration: Math.floor(Date.now() / 1000) - 3600, // 1 hour ago
406
425
  });
407
426
 
408
- const validPermit = await PermitUtils.createSelf({
427
+ const validPermit = PermitUtils.createSelf({
409
428
  issuer: bobAddress,
410
429
  name: 'Test Permit',
411
430
  expiration: Math.floor(Date.now() / 1000) + 3600, // 1 hour from now
@@ -416,7 +435,7 @@ describe('PermitUtils Tests', () => {
416
435
  });
417
436
 
418
437
  it('should check if permit is signed', async () => {
419
- const unsignedPermit = await PermitUtils.createSelf({
438
+ const unsignedPermit = PermitUtils.createSelf({
420
439
  issuer: bobAddress,
421
440
  name: 'Test Permit',
422
441
  });
@@ -428,7 +447,7 @@ describe('PermitUtils Tests', () => {
428
447
  });
429
448
 
430
449
  it('should check overall validity', async () => {
431
- const validPermit = await PermitUtils.createSelf({
450
+ const validPermit = PermitUtils.createSelf({
432
451
  issuer: bobAddress,
433
452
  name: 'Test Permit',
434
453
  expiration: Math.floor(Date.now() / 1000) + 3600,
@@ -456,7 +475,7 @@ describe('PermitUtils Tests', () => {
456
475
  }, 10000); // 10 second timeout for network call
457
476
 
458
477
  it('should check signed domain validity with real contract data', async () => {
459
- const permit = await PermitUtils.createSelf({
478
+ const permit = PermitUtils.createSelf({
460
479
  type: 'self',
461
480
  issuer: bobAddress,
462
481
  name: 'Test Permit',
@@ -470,5 +489,35 @@ describe('PermitUtils Tests', () => {
470
489
 
471
490
  expect(typeof isValid).toBe('boolean');
472
491
  }, 10000); // 10 second timeout for network call
492
+
493
+ // TODO: Uncomment when updated ACL with checkPermitValidity function is deployed
494
+
495
+ // it('should check permit validity on chain with real contract data', async () => {
496
+ // const permit = PermitUtils.createSelf({
497
+ // type: 'self',
498
+ // issuer: bobAddress,
499
+ // name: 'Test Permit',
500
+ // });
501
+
502
+ // const signedPermit = await PermitUtils.sign(permit, publicClient, bobWalletClient);
503
+
504
+ // const isValid = await PermitUtils.checkValidityOnChain(signedPermit, publicClient);
505
+
506
+ // expect(typeof isValid).toBe('boolean');
507
+ // expect(isValid).toBe(true);
508
+
509
+ // const permitInvalid = PermitUtils.createSelf({
510
+ // type: 'self',
511
+ // issuer: bobAddress,
512
+ // name: 'Test Permit',
513
+ // expiration: Math.floor(Date.now() / 1000) - 3600, // 1 hour ago
514
+ // });
515
+
516
+ // const signedPermitInvalid = await PermitUtils.sign(permitInvalid, publicClient, bobWalletClient);
517
+ // const isValidInvalid = await PermitUtils.checkValidityOnChain(signedPermitInvalid, publicClient);
518
+
519
+ // expect(typeof isValidInvalid).toBe('boolean');
520
+ // expect(isValidInvalid).toBe(false);
521
+ // });
473
522
  });
474
523
  });
package/permits/permit.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  import { keccak256, toHex, zeroAddress, parseAbi, type PublicClient, type WalletClient } from 'viem';
2
2
  import {
3
3
  type Permit,
4
+ type SelfPermit,
5
+ type SharingPermit,
6
+ type RecipientPermit,
4
7
  type CreateSelfPermitOptions,
5
8
  type CreateSharingPermitOptions,
6
9
  type ImportSharedPermitOptions,
@@ -8,6 +11,7 @@ import {
8
11
  type EIP712Domain,
9
12
  type Permission,
10
13
  type EthEncryptedData,
14
+ type PermitHashFields,
11
15
  } from './types.js';
12
16
  import {
13
17
  validateSelfPermitOptions,
@@ -18,8 +22,10 @@ import {
18
22
  validateImportPermit,
19
23
  ValidationUtils,
20
24
  } from './validation.js';
25
+ import * as z from 'zod';
21
26
  import { SignatureUtils } from './signature.js';
22
27
  import { GenerateSealingKey, SealingKey } from './sealing.js';
28
+ import { checkPermitValidityOnChain, getAclEIP712Domain } from './onchain-utils.js';
23
29
 
24
30
  /**
25
31
  * Main Permit utilities - functional approach for React compatibility
@@ -28,52 +34,45 @@ export const PermitUtils = {
28
34
  /**
29
35
  * Create a self permit for personal use
30
36
  */
31
- createSelf: async (options: CreateSelfPermitOptions): Promise<Permit> => {
37
+ createSelf: (options: CreateSelfPermitOptions): SelfPermit => {
32
38
  const validation = validateSelfPermitOptions(options);
33
39
 
34
- if (!validation.success) {
35
- throw new Error(
36
- 'PermitUtils :: createSelf :: Parsing SelfPermitOptions failed ' + JSON.stringify(validation.error, null, 2)
37
- );
38
- }
39
-
40
40
  // Always generate a new sealing key - users cannot provide their own
41
- const sealingPair = await GenerateSealingKey();
41
+ const sealingPair = GenerateSealingKey();
42
42
 
43
- return {
44
- ...validation.data,
43
+ const permit = {
44
+ hash: PermitUtils.getHash(validation),
45
+ ...validation,
45
46
  sealingPair,
46
47
  _signedDomain: undefined,
47
- };
48
+ } satisfies SelfPermit;
49
+
50
+ return permit;
48
51
  },
49
52
 
50
53
  /**
51
54
  * Create a sharing permit to be shared with another user
52
55
  */
53
- createSharing: async (options: CreateSharingPermitOptions): Promise<Permit> => {
56
+ createSharing: (options: CreateSharingPermitOptions): SharingPermit => {
54
57
  const validation = validateSharingPermitOptions(options);
55
58
 
56
- if (!validation.success) {
57
- throw new Error(
58
- 'PermitUtils :: createSharing :: Parsing SharingPermitOptions failed ' +
59
- JSON.stringify(validation.error, null, 2)
60
- );
61
- }
62
-
63
59
  // Always generate a new sealing key - users cannot provide their own
64
- const sealingPair = await GenerateSealingKey();
60
+ const sealingPair = GenerateSealingKey();
65
61
 
66
- return {
67
- ...validation.data,
62
+ const permit = {
63
+ hash: PermitUtils.getHash(validation),
64
+ ...validation,
68
65
  sealingPair,
69
66
  _signedDomain: undefined,
70
- };
67
+ } satisfies SharingPermit;
68
+
69
+ return permit;
71
70
  },
72
71
 
73
72
  /**
74
73
  * Import a shared permit from various input formats
75
74
  */
76
- importShared: async (options: ImportSharedPermitOptions | any | string): Promise<Permit> => {
75
+ importShared: (options: ImportSharedPermitOptions | string): RecipientPermit => {
77
76
  let parsedOptions: ImportSharedPermitOptions;
78
77
 
79
78
  // Handle different input types
@@ -82,52 +81,47 @@ export const PermitUtils = {
82
81
  try {
83
82
  parsedOptions = JSON.parse(options);
84
83
  } catch (error) {
85
- throw new Error(`PermitUtils :: importShared :: Failed to parse JSON string: ${error}`);
84
+ throw new Error(`Failed to parse JSON string: ${error}`);
86
85
  }
87
86
  } else if (typeof options === 'object' && options !== null) {
88
87
  // Handle both ImportSharedPermitOptions and any object
89
88
  parsedOptions = options;
90
89
  } else {
91
- throw new Error(
92
- 'PermitUtils :: importShared :: Invalid input type, expected ImportSharedPermitOptions, object, or string'
93
- );
90
+ throw new Error('Invalid input type, expected ImportSharedPermitOptions, object, or string');
94
91
  }
95
92
 
96
93
  // Validate type if provided
97
94
  if (parsedOptions.type != null && parsedOptions.type !== 'sharing') {
98
- throw new Error(`PermitUtils :: importShared :: Invalid permit type <${parsedOptions.type}>, must be "sharing"`);
95
+ throw new Error(`Invalid permit type <${parsedOptions.type}>, must be "sharing"`);
99
96
  }
100
97
 
101
98
  const validation = validateImportPermitOptions({ ...parsedOptions, type: 'recipient' });
102
99
 
103
- if (!validation.success) {
104
- throw new Error(
105
- 'PermitUtils :: importShared :: Parsing ImportPermitOptions failed ' + JSON.stringify(validation.error, null, 2)
106
- );
107
- }
108
-
109
100
  // Always generate a new sealing key - users cannot provide their own
110
- const sealingPair = await GenerateSealingKey();
101
+ const sealingPair = GenerateSealingKey();
111
102
 
112
- return {
113
- ...validation.data,
103
+ const permit = {
104
+ hash: PermitUtils.getHash(validation),
105
+ ...validation,
114
106
  sealingPair,
115
107
  _signedDomain: undefined,
116
- };
108
+ } satisfies RecipientPermit;
109
+
110
+ return permit;
117
111
  },
118
112
 
119
113
  /**
120
114
  * Sign a permit with the provided wallet client
121
115
  */
122
- sign: async (permit: Permit, publicClient: PublicClient, walletClient: WalletClient): Promise<Permit> => {
116
+ sign: async <T extends Permit>(permit: T, publicClient: PublicClient, walletClient: WalletClient): Promise<T> => {
123
117
  if (walletClient == null || walletClient.account == null) {
124
118
  throw new Error(
125
- 'PermitUtils :: sign - walletClient undefined, you must pass in a `walletClient` for the connected user to create a permit signature'
119
+ 'Missing walletClient, you must pass in a `walletClient` for the connected user to create a permit signature'
126
120
  );
127
121
  }
128
122
 
129
123
  const primaryType = SignatureUtils.getPrimaryType(permit.type);
130
- const domain = await PermitUtils.fetchEIP712Domain(publicClient);
124
+ const domain = await getAclEIP712Domain(publicClient);
131
125
  const { types, message } = SignatureUtils.getSignatureParams(PermitUtils.getPermission(permit, true), primaryType);
132
126
 
133
127
  const signature = await walletClient.signTypedData({
@@ -153,7 +147,7 @@ export const PermitUtils = {
153
147
  };
154
148
  }
155
149
 
156
- return updatedPermit;
150
+ return updatedPermit as T;
157
151
  },
158
152
 
159
153
  /**
@@ -163,8 +157,8 @@ export const PermitUtils = {
163
157
  options: CreateSelfPermitOptions,
164
158
  publicClient: PublicClient,
165
159
  walletClient: WalletClient
166
- ): Promise<Permit> => {
167
- const permit = await PermitUtils.createSelf(options);
160
+ ): Promise<SelfPermit> => {
161
+ const permit = PermitUtils.createSelf(options);
168
162
  return PermitUtils.sign(permit, publicClient, walletClient);
169
163
  },
170
164
 
@@ -175,8 +169,8 @@ export const PermitUtils = {
175
169
  options: CreateSharingPermitOptions,
176
170
  publicClient: PublicClient,
177
171
  walletClient: WalletClient
178
- ): Promise<Permit> => {
179
- const permit = await PermitUtils.createSharing(options);
172
+ ): Promise<SharingPermit> => {
173
+ const permit = PermitUtils.createSharing(options);
180
174
  return PermitUtils.sign(permit, publicClient, walletClient);
181
175
  },
182
176
 
@@ -184,11 +178,11 @@ export const PermitUtils = {
184
178
  * Import and sign a shared permit in one operation from various input formats
185
179
  */
186
180
  importSharedAndSign: async (
187
- options: ImportSharedPermitOptions | any | string,
181
+ options: ImportSharedPermitOptions | string,
188
182
  publicClient: PublicClient,
189
183
  walletClient: WalletClient
190
- ): Promise<Permit> => {
191
- const permit = await PermitUtils.importShared(options);
184
+ ): Promise<RecipientPermit> => {
185
+ const permit = PermitUtils.importShared(options);
192
186
  return PermitUtils.sign(permit, publicClient, walletClient);
193
187
  },
194
188
 
@@ -207,6 +201,7 @@ export const PermitUtils = {
207
201
  */
208
202
  serialize: (permit: Permit): SerializedPermit => {
209
203
  return {
204
+ hash: permit.hash,
210
205
  name: permit.name,
211
206
  type: permit.type,
212
207
  issuer: permit.issuer,
@@ -232,7 +227,7 @@ export const PermitUtils = {
232
227
  } else if (permit.type === 'recipient') {
233
228
  return validateImportPermit(permit);
234
229
  } else {
235
- throw new Error('PermitUtils :: validate :: Invalid permit type');
230
+ throw new Error('Invalid permit type');
236
231
  }
237
232
  },
238
233
 
@@ -241,13 +236,7 @@ export const PermitUtils = {
241
236
  */
242
237
  getPermission: (permit: Permit, skipValidation = false): Permission => {
243
238
  if (!skipValidation) {
244
- const validationResult = PermitUtils.validate(permit);
245
-
246
- if (!validationResult.success) {
247
- throw new Error(
248
- `PermitUtils :: getPermission :: permit validation failed - ${JSON.stringify(validationResult.error, null, 2)} ${JSON.stringify(permit, null, 2)}`
249
- );
250
- }
239
+ PermitUtils.validate(permit);
251
240
  }
252
241
 
253
242
  return {
@@ -265,7 +254,7 @@ export const PermitUtils = {
265
254
  /**
266
255
  * Get a stable hash for the permit (used as key in storage)
267
256
  */
268
- getHash: (permit: Permit): string => {
257
+ getHash: (permit: PermitHashFields): string => {
269
258
  const data = JSON.stringify({
270
259
  type: permit.type,
271
260
  issuer: permit.issuer,
@@ -336,41 +325,7 @@ export const PermitUtils = {
336
325
  * Fetch EIP712 domain from the blockchain
337
326
  */
338
327
  fetchEIP712Domain: async (publicClient: PublicClient): Promise<EIP712Domain> => {
339
- // Hardcoded constants from the original implementation
340
- const TASK_MANAGER_ADDRESS = '0xeA30c4B8b44078Bbf8a6ef5b9f1eC1626C7848D9';
341
- const ACL_IFACE = 'function acl() view returns (address)';
342
- const EIP712_DOMAIN_IFACE =
343
- 'function eip712Domain() public view returns (bytes1 fields, string name, string version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] extensions)';
344
-
345
- // Parse the ABI for the ACL function
346
- const aclAbi = parseAbi([ACL_IFACE]);
347
-
348
- // Get the ACL address
349
- const aclAddress = (await publicClient.readContract({
350
- address: TASK_MANAGER_ADDRESS as `0x${string}`,
351
- abi: aclAbi,
352
- functionName: 'acl',
353
- })) as `0x${string}`;
354
-
355
- // Parse the ABI for the EIP712 domain function
356
- const domainAbi = parseAbi([EIP712_DOMAIN_IFACE]);
357
-
358
- // Get the EIP712 domain
359
- const domain = await publicClient.readContract({
360
- address: aclAddress,
361
- abi: domainAbi,
362
- functionName: 'eip712Domain',
363
- });
364
-
365
- // eslint-disable-next-line no-unused-vars
366
- const [_fields, name, version, chainId, verifyingContract, _salt, _extensions] = domain;
367
-
368
- return {
369
- name,
370
- version,
371
- chainId: Number(chainId),
372
- verifyingContract,
373
- };
328
+ return getAclEIP712Domain(publicClient);
374
329
  },
375
330
 
376
331
  /**
@@ -390,7 +345,15 @@ export const PermitUtils = {
390
345
  */
391
346
  checkSignedDomainValid: async (permit: Permit, publicClient: PublicClient): Promise<boolean> => {
392
347
  if (permit._signedDomain == null) return false;
393
- const domain = await PermitUtils.fetchEIP712Domain(publicClient);
348
+ const domain = await getAclEIP712Domain(publicClient);
394
349
  return PermitUtils.matchesDomain(permit, domain);
395
350
  },
351
+
352
+ /**
353
+ * Check if permit passes the on-chain validation
354
+ */
355
+ checkValidityOnChain: async (permit: Permit, publicClient: PublicClient): Promise<boolean> => {
356
+ const permission = PermitUtils.getPermission(permit);
357
+ return checkPermitValidityOnChain(permission, publicClient);
358
+ },
396
359
  };
@@ -67,7 +67,7 @@ describe('SealingKey', () => {
67
67
 
68
68
  describe('GenerateSealingKey', () => {
69
69
  it('should generate a valid SealingKey', async () => {
70
- const sealingKey = await GenerateSealingKey();
70
+ const sealingKey = GenerateSealingKey();
71
71
 
72
72
  expect(sealingKey).toBeInstanceOf(SealingKey);
73
73
  expect(sealingKey.privateKey).toHaveLength(64);
@@ -75,8 +75,8 @@ describe('GenerateSealingKey', () => {
75
75
  });
76
76
 
77
77
  it('should generate different keys on each call', async () => {
78
- const key1 = await GenerateSealingKey();
79
- const key2 = await GenerateSealingKey();
78
+ const key1 = GenerateSealingKey();
79
+ const key2 = GenerateSealingKey();
80
80
 
81
81
  expect(key1.privateKey).not.toBe(key2.privateKey);
82
82
  expect(key1.publicKey).not.toBe(key2.publicKey);
@@ -122,9 +122,9 @@ export class SealingKey {
122
122
  * Asynchronously generates a new SealingKey.
123
123
  * This function uses the 'nacl' library to create a new public/private key pair for sealing purposes.
124
124
  * A sealing key is used to encrypt data such that it can only be unsealed (decrypted) by the owner of the corresponding private key.
125
- * @returns {Promise<SealingKey>} - A promise that resolves to a new SealingKey object containing the hexadecimal strings of the public and private keys.
125
+ * @returns {SealingKey} - A new SealingKey object containing the hexadecimal strings of the public and private keys.
126
126
  */
127
- export const GenerateSealingKey = async (): Promise<SealingKey> => {
127
+ export const GenerateSealingKey = (): SealingKey => {
128
128
  const sodiumKeypair = nacl.box.keyPair();
129
129
 
130
130
  return new SealingKey(toHexString(sodiumKeypair.secretKey), toHexString(sodiumKeypair.publicKey));