@cofhe/sdk 0.1.1 → 0.2.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 (96) hide show
  1. package/CHANGELOG.md +14 -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/index.ts +3 -1
  11. package/core/baseBuilder.ts +30 -49
  12. package/core/client.test.ts +94 -77
  13. package/core/client.ts +133 -149
  14. package/core/clientTypes.ts +108 -0
  15. package/core/config.test.ts +22 -11
  16. package/core/config.ts +16 -9
  17. package/core/decrypt/decryptHandleBuilder.ts +51 -45
  18. package/core/decrypt/{tnSealOutput.ts → tnSealOutputV1.ts} +1 -1
  19. package/core/decrypt/tnSealOutputV2.ts +298 -0
  20. package/core/encrypt/cofheMocksZkVerifySign.ts +16 -10
  21. package/core/encrypt/encryptInputsBuilder.test.ts +132 -116
  22. package/core/encrypt/encryptInputsBuilder.ts +159 -111
  23. package/core/encrypt/encryptUtils.ts +6 -3
  24. package/core/encrypt/zkPackProveVerify.ts +70 -8
  25. package/core/error.ts +0 -2
  26. package/core/fetchKeys.test.ts +1 -18
  27. package/core/fetchKeys.ts +0 -26
  28. package/core/index.ts +29 -17
  29. package/core/keyStore.ts +65 -38
  30. package/core/permits.test.ts +253 -1
  31. package/core/permits.ts +80 -16
  32. package/core/types.ts +198 -152
  33. package/core/utils.ts +43 -1
  34. package/dist/adapters.d.cts +38 -20
  35. package/dist/adapters.d.ts +38 -20
  36. package/dist/chains.cjs +14 -1
  37. package/dist/chains.d.cts +23 -1
  38. package/dist/chains.d.ts +23 -1
  39. package/dist/chains.js +1 -1
  40. package/dist/{chunk-LU7BMUUT.js → chunk-UGBVZNRT.js} +39 -25
  41. package/dist/{chunk-GZCQQYVI.js → chunk-WEAZ25JO.js} +14 -2
  42. package/dist/{chunk-KFGPTJ6X.js → chunk-WGCRJCBR.js} +1920 -1692
  43. package/dist/{types-bB7wLj0q.d.cts → clientTypes-5_1nwtUe.d.cts} +308 -347
  44. package/dist/{types-PhwGgQvs.d.ts → clientTypes-Es7fyi65.d.ts} +308 -347
  45. package/dist/core.cjs +2872 -2632
  46. package/dist/core.d.cts +101 -6
  47. package/dist/core.d.ts +101 -6
  48. package/dist/core.js +3 -3
  49. package/dist/node.cjs +2716 -2520
  50. package/dist/node.d.cts +3 -3
  51. package/dist/node.d.ts +3 -3
  52. package/dist/node.js +4 -3
  53. package/dist/{permit-S9CnI6MF.d.cts → permit-fUSe6KKq.d.cts} +31 -15
  54. package/dist/{permit-S9CnI6MF.d.ts → permit-fUSe6KKq.d.ts} +31 -15
  55. package/dist/permits.cjs +39 -24
  56. package/dist/permits.d.cts +137 -148
  57. package/dist/permits.d.ts +137 -148
  58. package/dist/permits.js +1 -1
  59. package/dist/web.cjs +2929 -2518
  60. package/dist/web.d.cts +21 -5
  61. package/dist/web.d.ts +21 -5
  62. package/dist/web.js +185 -9
  63. package/dist/zkProve.worker.cjs +93 -0
  64. package/dist/zkProve.worker.d.cts +2 -0
  65. package/dist/zkProve.worker.d.ts +2 -0
  66. package/dist/zkProve.worker.js +91 -0
  67. package/node/client.test.ts +20 -25
  68. package/node/encryptInputs.test.ts +18 -38
  69. package/node/index.ts +1 -0
  70. package/package.json +14 -14
  71. package/permits/index.ts +1 -0
  72. package/permits/localstorage.test.ts +0 -1
  73. package/permits/permit.test.ts +25 -22
  74. package/permits/permit.ts +30 -21
  75. package/permits/sealing.test.ts +3 -3
  76. package/permits/sealing.ts +2 -2
  77. package/permits/store.ts +5 -7
  78. package/permits/test-utils.ts +1 -1
  79. package/permits/types.ts +17 -0
  80. package/permits/utils.ts +0 -1
  81. package/permits/validation.ts +24 -4
  82. package/web/client.web.test.ts +20 -25
  83. package/web/config.web.test.ts +0 -2
  84. package/web/encryptInputs.web.test.ts +31 -54
  85. package/web/index.ts +65 -1
  86. package/web/storage.ts +19 -5
  87. package/web/worker.builder.web.test.ts +148 -0
  88. package/web/worker.config.web.test.ts +329 -0
  89. package/web/worker.output.web.test.ts +84 -0
  90. package/web/workerManager.test.ts +80 -0
  91. package/web/workerManager.ts +214 -0
  92. package/web/workerManager.web.test.ts +114 -0
  93. package/web/zkProve.worker.ts +133 -0
  94. package/core/result.test.ts +0 -180
  95. package/core/result.ts +0 -67
  96. package/core/test-utils.ts +0 -45
@@ -1,4 +1,4 @@
1
- import { Encryptable, FheTypes, type CofhesdkClient, type Result, CofhesdkErrorCode, CofhesdkError } from '@/core';
1
+ import { Encryptable, FheTypes, type CofhesdkClient, CofhesdkErrorCode, CofhesdkError } from '@/core';
2
2
  import { arbSepolia as cofhesdkArbSepolia } from '@/chains';
3
3
 
4
4
  import { describe, it, expect, beforeAll, beforeEach } from 'vitest';
@@ -11,22 +11,6 @@ import { createCofhesdkClient, createCofhesdkConfig } from './index.js';
11
11
  // Real test setup - using actual node-tfhe
12
12
  const TEST_PRIVATE_KEY = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80';
13
13
 
14
- const expectResultSuccess = <T>(result: Result<T>): T => {
15
- expect(result.success, `Result error: ${result.error?.toString()}`).toBe(true);
16
- return result.data!;
17
- };
18
-
19
- const expectResultError = <T>(result: Result<T>, errorCode?: CofhesdkErrorCode): void => {
20
- expect(result.success).toBe(false);
21
- expect(result.data).toBe(null);
22
- expect(result.error).not.toBe(null);
23
- const error = result.error as CofhesdkError;
24
- expect(error).toBeInstanceOf(CofhesdkError);
25
- if (errorCode) {
26
- expect(error.code, `Result error: ${result.error?.toString()}`).toBe(errorCode);
27
- }
28
- };
29
-
30
14
  describe('@cofhe/node - Encrypt Inputs', () => {
31
15
  let cofhesdkClient: CofhesdkClient;
32
16
  let publicClient: PublicClient;
@@ -59,8 +43,7 @@ describe('@cofhe/node - Encrypt Inputs', () => {
59
43
  await cofhesdkClient.connect(publicClient, walletClient);
60
44
 
61
45
  // This will trigger real TFHE initialization
62
- const result = await cofhesdkClient.encryptInputs([Encryptable.uint128(100n)]).encrypt();
63
- const encrypted = expectResultSuccess(result);
46
+ const encrypted = await cofhesdkClient.encryptInputs([Encryptable.uint128(100n)]).encrypt();
64
47
 
65
48
  // If we get here, TFHE was initialized successfully
66
49
  expect(encrypted).toBeDefined();
@@ -70,12 +53,10 @@ describe('@cofhe/node - Encrypt Inputs', () => {
70
53
  await cofhesdkClient.connect(publicClient, walletClient);
71
54
 
72
55
  // First encryption
73
- const result1 = await cofhesdkClient.encryptInputs([Encryptable.uint128(100n)]).encrypt();
74
- expectResultSuccess(result1);
56
+ await cofhesdkClient.encryptInputs([Encryptable.uint128(100n)]).encrypt();
75
57
 
76
58
  // Second encryption should reuse initialization
77
- const result2 = await cofhesdkClient.encryptInputs([Encryptable.uint64(50n)]).encrypt();
78
- expectResultSuccess(result2);
59
+ await cofhesdkClient.encryptInputs([Encryptable.uint64(50n)]).encrypt();
79
60
  }, 120000);
80
61
  });
81
62
 
@@ -83,8 +64,7 @@ describe('@cofhe/node - Encrypt Inputs', () => {
83
64
  it('should encrypt a bool with real TFHE', async () => {
84
65
  await cofhesdkClient.connect(publicClient, walletClient);
85
66
 
86
- const result = await cofhesdkClient.encryptInputs([Encryptable.bool(true)]).encrypt();
87
- const encrypted = expectResultSuccess(result);
67
+ const encrypted = await cofhesdkClient.encryptInputs([Encryptable.bool(true)]).encrypt();
88
68
 
89
69
  expect(encrypted.length).toBe(1);
90
70
  expect(encrypted[0].utype).toBe(FheTypes.Bool);
@@ -108,8 +88,7 @@ describe('@cofhe/node - Encrypt Inputs', () => {
108
88
  Encryptable.address('0x742d35Cc6634C0532925a3b844D16faC4c175E99'),
109
89
  ];
110
90
 
111
- const result = await cofhesdkClient.encryptInputs(inputs).encrypt();
112
- const encrypted = expectResultSuccess(result);
91
+ const encrypted = await cofhesdkClient.encryptInputs(inputs).encrypt();
113
92
 
114
93
  expect(encrypted.length).toBe(7);
115
94
  // Verify each type
@@ -128,14 +107,13 @@ describe('@cofhe/node - Encrypt Inputs', () => {
128
107
  await cofhesdkClient.connect(publicClient, walletClient);
129
108
 
130
109
  const snapshot = cofhesdkClient.getSnapshot();
131
- const result = await cofhesdkClient
110
+ const encrypted = await cofhesdkClient
132
111
  .encryptInputs([Encryptable.uint128(100n)])
133
112
  .setChainId(snapshot.chainId!)
134
113
  .setAccount(snapshot.account!)
135
114
  .setSecurityZone(0)
136
115
  .encrypt();
137
116
 
138
- const encrypted = expectResultSuccess(result);
139
117
  expect(encrypted.length).toBe(1);
140
118
  expect(encrypted[0].utype).toBe(FheTypes.Uint128);
141
119
  }, 60000);
@@ -144,9 +122,12 @@ describe('@cofhe/node - Encrypt Inputs', () => {
144
122
  describe('Real Error Handling', () => {
145
123
  it('should fail gracefully when not connected', async () => {
146
124
  // Don't connect the client
147
- const result = await cofhesdkClient.encryptInputs([Encryptable.uint128(100n)]).encrypt();
148
-
149
- expectResultError(result, CofhesdkErrorCode.NotConnected);
125
+ try {
126
+ await cofhesdkClient.encryptInputs([Encryptable.uint128(100n)]).encrypt();
127
+ } catch (error) {
128
+ expect(error).toBeInstanceOf(CofhesdkError);
129
+ expect((error as CofhesdkError).code).toBe(CofhesdkErrorCode.NotConnected);
130
+ }
150
131
  }, 30000);
151
132
 
152
133
  it('should handle invalid CoFHE URL', async () => {
@@ -158,17 +139,16 @@ describe('@cofhe/node - Encrypt Inputs', () => {
158
139
  verifierUrl: 'http://invalid-verifier-url.local',
159
140
  },
160
141
  ],
161
- fheKeysPrefetching: 'OFF',
162
142
  });
163
143
 
164
144
  const badClient = createCofhesdkClient(badConfig);
165
145
  await badClient.connect(publicClient, walletClient);
166
146
 
167
- const result = await badClient.encryptInputs([Encryptable.uint128(100n)]).encrypt();
168
-
169
- expect(result.success).toBe(false);
170
- if (!result.success) {
171
- expect(result.error).toBeDefined();
147
+ try {
148
+ await badClient.encryptInputs([Encryptable.uint128(100n)]).encrypt();
149
+ } catch (error) {
150
+ expect(error).toBeInstanceOf(CofhesdkError);
151
+ expect((error as CofhesdkError).code).toBe(CofhesdkErrorCode.ZkVerifyFailed);
172
152
  }
173
153
  }, 60000);
174
154
  });
package/node/index.ts CHANGED
@@ -74,6 +74,7 @@ const zkBuilderAndCrsGenerator: ZkBuilderAndCrsGenerator = (fhe: string, crs: st
74
74
  */
75
75
  export function createCofhesdkConfig(config: CofhesdkInputConfig): CofhesdkConfig {
76
76
  return createCofhesdkConfigBase({
77
+ environment: 'node',
77
78
  ...config,
78
79
  fheKeyStorage: config.fheKeyStorage === null ? null : config.fheKeyStorage ?? createNodeStorage(),
79
80
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cofhe/sdk",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "type": "module",
5
5
  "description": "SDK for Fhenix COFHE coprocessor interaction",
6
6
  "main": "./dist/core.cjs",
@@ -57,21 +57,21 @@
57
57
  "CHANGELOG.md"
58
58
  ],
59
59
  "dependencies": {
60
+ "iframe-shared-storage": "^1.0.34",
60
61
  "immer": "^10.1.1",
61
- "zustand": "^5.0.1",
62
- "zod": "^3.22.0",
63
- "viem": "^2.0.0",
64
62
  "node-tfhe": "0.11.1",
65
- "idb-keyval": "^6.2.1",
66
63
  "tfhe": "0.11.1",
67
- "tweetnacl": "^1.0.3"
64
+ "tweetnacl": "^1.0.3",
65
+ "viem": "^2.38.6",
66
+ "zod": "^3.22.0",
67
+ "zustand": "^5.0.1"
68
68
  },
69
69
  "peerDependencies": {
70
- "viem": "^2.0.0",
70
+ "@nomicfoundation/hardhat-ethers": "^3.0.0",
71
71
  "@wagmi/core": "^2.0.0",
72
72
  "ethers": "^5.0.0 || ^6.0.0",
73
73
  "hardhat": "^2.0.0",
74
- "@nomicfoundation/hardhat-ethers": "^3.0.0"
74
+ "viem": "^2.38.6"
75
75
  },
76
76
  "peerDependenciesMeta": {
77
77
  "@wagmi/core": {
@@ -88,21 +88,21 @@
88
88
  }
89
89
  },
90
90
  "devDependencies": {
91
+ "@nomicfoundation/hardhat-ethers": "^3.0.0",
91
92
  "@types/node": "^20.0.0",
92
93
  "@vitest/browser": "^3.0.0",
93
94
  "@vitest/coverage-v8": "^3.0.0",
94
95
  "eslint": "^8.57.0",
96
+ "ethers5": "npm:ethers@^5.7.2",
97
+ "ethers6": "npm:ethers@^6.13.0",
95
98
  "happy-dom": "^15.0.0",
99
+ "hardhat": "^2.19.0",
96
100
  "playwright": "^1.55.0",
97
101
  "tsup": "^8.0.2",
98
102
  "typescript": "5.5.4",
99
103
  "vitest": "^3.0.0",
100
- "ethers5": "npm:ethers@^5.7.2",
101
- "ethers6": "npm:ethers@^6.13.0",
102
- "hardhat": "^2.19.0",
103
- "@nomicfoundation/hardhat-ethers": "^3.0.0",
104
- "@cofhe/eslint-config": "0.1.1",
105
- "@cofhe/tsconfig": "0.1.0"
104
+ "@cofhe/eslint-config": "0.2.0",
105
+ "@cofhe/tsconfig": "0.1.1"
106
106
  },
107
107
  "publishConfig": {
108
108
  "access": "public"
package/permits/index.ts CHANGED
@@ -53,6 +53,7 @@ export {
53
53
  setActivePermitHash,
54
54
  removeActivePermitHash,
55
55
  clearStaleStore,
56
+ PERMIT_STORE_DEFAULTS,
56
57
  } from './store.js';
57
58
 
58
59
  // Sealing utilities
@@ -1,7 +1,6 @@
1
1
  /**
2
2
  * @vitest-environment happy-dom
3
3
  */
4
- /* eslint-disable no-unused-vars */
5
4
 
6
5
  import { describe, it, expect, beforeEach, afterEach } from 'vitest';
7
6
  import {
@@ -44,7 +44,7 @@ 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
49
  expect(permit.type).toBe('self');
50
50
  expect(permit.name).toBe('Test Permit');
@@ -66,7 +66,7 @@ describe('PermitUtils Tests', () => {
66
66
  name: 'Test Permit',
67
67
  };
68
68
 
69
- await expect(PermitUtils.createSelf(options)).rejects.toThrow();
69
+ expect(() => PermitUtils.createSelf(options)).toThrowError();
70
70
  });
71
71
  });
72
72
 
@@ -79,7 +79,7 @@ describe('PermitUtils Tests', () => {
79
79
  name: 'Test Sharing Permit',
80
80
  };
81
81
 
82
- const permit = await PermitUtils.createSharing(options);
82
+ const permit = PermitUtils.createSharing(options);
83
83
 
84
84
  expect(permit.type).toBe('sharing');
85
85
  expect(permit.name).toBe('Test Sharing Permit');
@@ -103,7 +103,7 @@ describe('PermitUtils Tests', () => {
103
103
  name: 'Test Sharing Permit',
104
104
  };
105
105
 
106
- await expect(PermitUtils.createSharing(options)).rejects.toThrow();
106
+ expect(() => PermitUtils.createSharing(options)).toThrow();
107
107
  });
108
108
  });
109
109
 
@@ -116,7 +116,7 @@ describe('PermitUtils Tests', () => {
116
116
  name: 'Test Import Permit',
117
117
  };
118
118
 
119
- const permit = await PermitUtils.importShared(options);
119
+ const permit = PermitUtils.importShared(options);
120
120
 
121
121
  expect(permit.type).toBe('recipient');
122
122
  expect(permit.name).toBe('Test Import Permit');
@@ -140,7 +140,7 @@ describe('PermitUtils Tests', () => {
140
140
 
141
141
  const stringOptions = JSON.stringify(options);
142
142
 
143
- const permit = await PermitUtils.importShared(stringOptions);
143
+ const permit = PermitUtils.importShared(stringOptions);
144
144
 
145
145
  expect(permit.type).toBe('recipient');
146
146
  });
@@ -153,7 +153,7 @@ describe('PermitUtils Tests', () => {
153
153
  issuerSignature: '0x1234567890abcdef',
154
154
  } as unknown as ImportSharedPermitOptions;
155
155
 
156
- await expect(PermitUtils.importShared(options)).rejects.toThrow();
156
+ expect(() => PermitUtils.importShared(options)).toThrow();
157
157
 
158
158
  const options2 = {
159
159
  type: 'recipient',
@@ -162,7 +162,7 @@ describe('PermitUtils Tests', () => {
162
162
  issuerSignature: '0x1234567890abcdef',
163
163
  } as unknown as ImportSharedPermitOptions;
164
164
 
165
- await expect(PermitUtils.importShared(options2)).rejects.toThrow();
165
+ expect(() => PermitUtils.importShared(options2)).toThrow();
166
166
  });
167
167
 
168
168
  it('should throw error for missing issuerSignature', async () => {
@@ -173,7 +173,7 @@ describe('PermitUtils Tests', () => {
173
173
  name: 'Test Import Permit',
174
174
  };
175
175
 
176
- await expect(PermitUtils.importShared(options)).rejects.toThrow();
176
+ expect(() => PermitUtils.importShared(options)).toThrow();
177
177
  });
178
178
  });
179
179
 
@@ -266,7 +266,7 @@ describe('PermitUtils Tests', () => {
266
266
 
267
267
  describe('sign', () => {
268
268
  it('should sign a self permit', async () => {
269
- const permit = await PermitUtils.createSelf({
269
+ const permit = PermitUtils.createSelf({
270
270
  issuer: bobAddress,
271
271
  name: 'Test Permit',
272
272
  });
@@ -280,7 +280,7 @@ describe('PermitUtils Tests', () => {
280
280
  });
281
281
 
282
282
  it('should sign a recipient permit', async () => {
283
- const permit = await PermitUtils.importShared({
283
+ const permit = PermitUtils.importShared({
284
284
  issuer: bobAddress,
285
285
  recipient: aliceAddress,
286
286
  issuerSignature: '0xexisting-signature',
@@ -295,7 +295,7 @@ describe('PermitUtils Tests', () => {
295
295
  });
296
296
 
297
297
  it('should throw error for undefined signer', async () => {
298
- const permit = await PermitUtils.createSelf({
298
+ const permit = PermitUtils.createSelf({
299
299
  issuer: bobAddress,
300
300
  name: 'Test Permit',
301
301
  });
@@ -309,7 +309,7 @@ describe('PermitUtils Tests', () => {
309
309
 
310
310
  describe('serialize/deserialize', () => {
311
311
  it('should serialize and deserialize a permit', async () => {
312
- const originalPermit = await PermitUtils.createSelf({
312
+ const originalPermit = PermitUtils.createSelf({
313
313
  issuer: bobAddress,
314
314
  name: 'Test Permit',
315
315
  });
@@ -348,12 +348,15 @@ describe('PermitUtils Tests', () => {
348
348
 
349
349
  describe('getHash', () => {
350
350
  it('should generate consistent hash for same permit data', async () => {
351
- const permit1 = await PermitUtils.createSelf({
351
+ const expiration = Math.floor(Date.now() / 1000) + 3600; // 1 hour from now
352
+ const permit1 = PermitUtils.createSelf({
353
+ expiration,
352
354
  issuer: bobAddress,
353
355
  name: 'Test Permit',
354
356
  });
355
357
 
356
- const permit2 = await PermitUtils.createSelf({
358
+ const permit2 = PermitUtils.createSelf({
359
+ expiration,
357
360
  issuer: bobAddress,
358
361
  name: 'Test Permit',
359
362
  });
@@ -367,7 +370,7 @@ describe('PermitUtils Tests', () => {
367
370
 
368
371
  describe('export', () => {
369
372
  it('should export permit data without sensitive fields', async () => {
370
- const permit = await PermitUtils.createSelf({
373
+ const permit = PermitUtils.createSelf({
371
374
  issuer: bobAddress,
372
375
  name: 'Test Permit',
373
376
  });
@@ -384,7 +387,7 @@ describe('PermitUtils Tests', () => {
384
387
 
385
388
  describe('updateName', () => {
386
389
  it('should update permit name immutably', async () => {
387
- const permit = await PermitUtils.createSelf({
390
+ const permit = PermitUtils.createSelf({
388
391
  issuer: bobAddress,
389
392
  name: 'Original Name',
390
393
  });
@@ -399,13 +402,13 @@ describe('PermitUtils Tests', () => {
399
402
 
400
403
  describe('validation helpers', () => {
401
404
  it('should check if permit is expired', async () => {
402
- const expiredPermit = await PermitUtils.createSelf({
405
+ const expiredPermit = PermitUtils.createSelf({
403
406
  issuer: bobAddress,
404
407
  name: 'Test Permit',
405
408
  expiration: Math.floor(Date.now() / 1000) - 3600, // 1 hour ago
406
409
  });
407
410
 
408
- const validPermit = await PermitUtils.createSelf({
411
+ const validPermit = PermitUtils.createSelf({
409
412
  issuer: bobAddress,
410
413
  name: 'Test Permit',
411
414
  expiration: Math.floor(Date.now() / 1000) + 3600, // 1 hour from now
@@ -416,7 +419,7 @@ describe('PermitUtils Tests', () => {
416
419
  });
417
420
 
418
421
  it('should check if permit is signed', async () => {
419
- const unsignedPermit = await PermitUtils.createSelf({
422
+ const unsignedPermit = PermitUtils.createSelf({
420
423
  issuer: bobAddress,
421
424
  name: 'Test Permit',
422
425
  });
@@ -428,7 +431,7 @@ describe('PermitUtils Tests', () => {
428
431
  });
429
432
 
430
433
  it('should check overall validity', async () => {
431
- const validPermit = await PermitUtils.createSelf({
434
+ const validPermit = PermitUtils.createSelf({
432
435
  issuer: bobAddress,
433
436
  name: 'Test Permit',
434
437
  expiration: Math.floor(Date.now() / 1000) + 3600,
@@ -456,7 +459,7 @@ describe('PermitUtils Tests', () => {
456
459
  }, 10000); // 10 second timeout for network call
457
460
 
458
461
  it('should check signed domain validity with real contract data', async () => {
459
- const permit = await PermitUtils.createSelf({
462
+ const permit = PermitUtils.createSelf({
460
463
  type: 'self',
461
464
  issuer: bobAddress,
462
465
  name: 'Test Permit',
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,
@@ -28,7 +31,7 @@ export const PermitUtils = {
28
31
  /**
29
32
  * Create a self permit for personal use
30
33
  */
31
- createSelf: async (options: CreateSelfPermitOptions): Promise<Permit> => {
34
+ createSelf: (options: CreateSelfPermitOptions): SelfPermit => {
32
35
  const validation = validateSelfPermitOptions(options);
33
36
 
34
37
  if (!validation.success) {
@@ -38,19 +41,21 @@ export const PermitUtils = {
38
41
  }
39
42
 
40
43
  // Always generate a new sealing key - users cannot provide their own
41
- const sealingPair = await GenerateSealingKey();
44
+ const sealingPair = GenerateSealingKey();
42
45
 
43
- return {
46
+ const permit = {
44
47
  ...validation.data,
45
48
  sealingPair,
46
49
  _signedDomain: undefined,
47
- };
50
+ } satisfies SelfPermit;
51
+
52
+ return permit;
48
53
  },
49
54
 
50
55
  /**
51
56
  * Create a sharing permit to be shared with another user
52
57
  */
53
- createSharing: async (options: CreateSharingPermitOptions): Promise<Permit> => {
58
+ createSharing: (options: CreateSharingPermitOptions): SharingPermit => {
54
59
  const validation = validateSharingPermitOptions(options);
55
60
 
56
61
  if (!validation.success) {
@@ -61,19 +66,21 @@ export const PermitUtils = {
61
66
  }
62
67
 
63
68
  // Always generate a new sealing key - users cannot provide their own
64
- const sealingPair = await GenerateSealingKey();
69
+ const sealingPair = GenerateSealingKey();
65
70
 
66
- return {
71
+ const permit = {
67
72
  ...validation.data,
68
73
  sealingPair,
69
74
  _signedDomain: undefined,
70
- };
75
+ } satisfies SharingPermit;
76
+
77
+ return permit;
71
78
  },
72
79
 
73
80
  /**
74
81
  * Import a shared permit from various input formats
75
82
  */
76
- importShared: async (options: ImportSharedPermitOptions | any | string): Promise<Permit> => {
83
+ importShared: (options: ImportSharedPermitOptions | string): RecipientPermit => {
77
84
  let parsedOptions: ImportSharedPermitOptions;
78
85
 
79
86
  // Handle different input types
@@ -107,19 +114,21 @@ export const PermitUtils = {
107
114
  }
108
115
 
109
116
  // Always generate a new sealing key - users cannot provide their own
110
- const sealingPair = await GenerateSealingKey();
117
+ const sealingPair = GenerateSealingKey();
111
118
 
112
- return {
119
+ const permit = {
113
120
  ...validation.data,
114
121
  sealingPair,
115
122
  _signedDomain: undefined,
116
- };
123
+ } satisfies RecipientPermit;
124
+
125
+ return permit;
117
126
  },
118
127
 
119
128
  /**
120
129
  * Sign a permit with the provided wallet client
121
130
  */
122
- sign: async (permit: Permit, publicClient: PublicClient, walletClient: WalletClient): Promise<Permit> => {
131
+ sign: async <T extends Permit>(permit: T, publicClient: PublicClient, walletClient: WalletClient): Promise<T> => {
123
132
  if (walletClient == null || walletClient.account == null) {
124
133
  throw new Error(
125
134
  'PermitUtils :: sign - walletClient undefined, you must pass in a `walletClient` for the connected user to create a permit signature'
@@ -153,7 +162,7 @@ export const PermitUtils = {
153
162
  };
154
163
  }
155
164
 
156
- return updatedPermit;
165
+ return updatedPermit as T;
157
166
  },
158
167
 
159
168
  /**
@@ -163,8 +172,8 @@ export const PermitUtils = {
163
172
  options: CreateSelfPermitOptions,
164
173
  publicClient: PublicClient,
165
174
  walletClient: WalletClient
166
- ): Promise<Permit> => {
167
- const permit = await PermitUtils.createSelf(options);
175
+ ): Promise<SelfPermit> => {
176
+ const permit = PermitUtils.createSelf(options);
168
177
  return PermitUtils.sign(permit, publicClient, walletClient);
169
178
  },
170
179
 
@@ -175,8 +184,8 @@ export const PermitUtils = {
175
184
  options: CreateSharingPermitOptions,
176
185
  publicClient: PublicClient,
177
186
  walletClient: WalletClient
178
- ): Promise<Permit> => {
179
- const permit = await PermitUtils.createSharing(options);
187
+ ): Promise<SharingPermit> => {
188
+ const permit = PermitUtils.createSharing(options);
180
189
  return PermitUtils.sign(permit, publicClient, walletClient);
181
190
  },
182
191
 
@@ -184,11 +193,11 @@ export const PermitUtils = {
184
193
  * Import and sign a shared permit in one operation from various input formats
185
194
  */
186
195
  importSharedAndSign: async (
187
- options: ImportSharedPermitOptions | any | string,
196
+ options: ImportSharedPermitOptions | string,
188
197
  publicClient: PublicClient,
189
198
  walletClient: WalletClient
190
- ): Promise<Permit> => {
191
- const permit = await PermitUtils.importShared(options);
199
+ ): Promise<RecipientPermit> => {
200
+ const permit = PermitUtils.importShared(options);
192
201
  return PermitUtils.sign(permit, publicClient, walletClient);
193
202
  },
194
203
 
@@ -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));
package/permits/store.ts CHANGED
@@ -15,14 +15,12 @@ type PermitsStore = {
15
15
 
16
16
  // Stores generated permits for each user, a hash indicating the active permit for each user
17
17
  // Can be used to create reactive hooks
18
+ export const PERMIT_STORE_DEFAULTS: PermitsStore = {
19
+ permits: {},
20
+ activePermitHash: {},
21
+ };
18
22
  export const _permitStore = createStore<PermitsStore>()(
19
- persist(
20
- () => ({
21
- permits: {},
22
- activePermitHash: {},
23
- }),
24
- { name: 'cofhesdk-permits' }
25
- )
23
+ persist(() => PERMIT_STORE_DEFAULTS, { name: 'cofhesdk-permits' })
26
24
  );
27
25
 
28
26
  export const clearStaleStore = () => {
@@ -2,7 +2,7 @@ import { type Permit, type SerializedPermit, GenerateSealingKey, PermitUtils } f
2
2
 
3
3
  // Mock permit for testing - using Bob's address as issuer
4
4
  export const createMockPermit = async (): Promise<Permit> => {
5
- const sealingPair = await GenerateSealingKey();
5
+ const sealingPair = GenerateSealingKey();
6
6
  const serializedPermit: SerializedPermit = {
7
7
  name: 'Test Permit',
8
8
  type: 'self',
package/permits/types.ts CHANGED
@@ -89,6 +89,23 @@ export interface Permit {
89
89
  _signedDomain?: EIP712Domain;
90
90
  }
91
91
 
92
+ /**
93
+ * Permit discriminant helpers
94
+ */
95
+ export type PermitType = Permit['type'];
96
+
97
+ /**
98
+ * Utility type to narrow a permit to a specific discriminant.
99
+ *
100
+ * Note: this only narrows the `type` field. Runtime/validation constraints
101
+ * (e.g. recipient == zeroAddress for self permits) are enforced elsewhere.
102
+ */
103
+ export type PermitOf<T extends PermitType> = Expand<Omit<Permit, 'type'> & { type: T }>;
104
+
105
+ export type SelfPermit = PermitOf<'self'>;
106
+ export type SharingPermit = PermitOf<'sharing'>;
107
+ export type RecipientPermit = PermitOf<'recipient'>;
108
+
92
109
  /**
93
110
  * Optional additional metadata of a Permit
94
111
  * Can be passed into the constructor, but not necessary
package/permits/utils.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  // Utility functions for sealing key operations
2
2
 
3
- // eslint-disable-next-line no-unused-vars
4
3
  declare const BigInt: (value: string | number | bigint) => bigint;
5
4
 
6
5
  export const fromHexString = (hexString: string): Uint8Array => {