@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.
- package/CHANGELOG.md +22 -0
- package/adapters/ethers6.ts +28 -28
- package/adapters/hardhat.ts +0 -1
- package/adapters/index.test.ts +14 -19
- package/adapters/smartWallet.ts +81 -73
- package/adapters/test-utils.ts +45 -45
- package/adapters/types.ts +3 -3
- package/chains/chains/localcofhe.ts +14 -0
- package/chains/chains.test.ts +2 -1
- package/chains/defineChain.ts +2 -2
- package/chains/index.ts +3 -1
- package/chains/types.ts +3 -3
- package/core/baseBuilder.ts +30 -49
- package/core/client.test.ts +200 -72
- package/core/client.ts +152 -148
- package/core/clientTypes.ts +114 -0
- package/core/config.test.ts +30 -11
- package/core/config.ts +26 -13
- package/core/consts.ts +18 -0
- package/core/decrypt/cofheMocksSealOutput.ts +2 -4
- package/core/decrypt/decryptHandleBuilder.ts +51 -45
- package/core/decrypt/{tnSealOutput.ts → tnSealOutputV1.ts} +1 -1
- package/core/decrypt/tnSealOutputV2.ts +298 -0
- package/core/encrypt/cofheMocksZkVerifySign.ts +15 -16
- package/core/encrypt/encryptInputsBuilder.test.ts +132 -116
- package/core/encrypt/encryptInputsBuilder.ts +159 -111
- package/core/encrypt/encryptUtils.ts +6 -3
- package/core/encrypt/zkPackProveVerify.ts +70 -8
- package/core/error.ts +0 -2
- package/core/fetchKeys.test.ts +1 -18
- package/core/fetchKeys.ts +0 -26
- package/core/index.ts +37 -17
- package/core/keyStore.ts +65 -38
- package/core/permits.test.ts +255 -4
- package/core/permits.ts +83 -18
- package/core/types.ts +198 -152
- package/core/utils.ts +43 -1
- package/dist/adapters.d.cts +38 -20
- package/dist/adapters.d.ts +38 -20
- package/dist/chains.cjs +18 -8
- package/dist/chains.d.cts +31 -9
- package/dist/chains.d.ts +31 -9
- package/dist/chains.js +1 -1
- package/dist/{chunk-KFGPTJ6X.js → chunk-I5WFEYXX.js} +1768 -1526
- package/dist/{chunk-LU7BMUUT.js → chunk-R3B5TMVX.js} +330 -197
- package/dist/{chunk-GZCQQYVI.js → chunk-TBLR7NNE.js} +18 -9
- package/dist/{types-PhwGgQvs.d.ts → clientTypes-RqkgkV2i.d.ts} +331 -429
- package/dist/{types-bB7wLj0q.d.cts → clientTypes-e4filDzK.d.cts} +331 -429
- package/dist/core.cjs +3000 -2625
- package/dist/core.d.cts +113 -7
- package/dist/core.d.ts +113 -7
- package/dist/core.js +3 -3
- package/dist/node.cjs +2851 -2526
- package/dist/node.d.cts +4 -4
- package/dist/node.d.ts +4 -4
- package/dist/node.js +4 -3
- package/dist/{permit-S9CnI6MF.d.cts → permit-MZ502UBl.d.cts} +54 -41
- package/dist/{permit-S9CnI6MF.d.ts → permit-MZ502UBl.d.ts} +54 -41
- package/dist/permits.cjs +328 -195
- package/dist/permits.d.cts +113 -825
- package/dist/permits.d.ts +113 -825
- package/dist/permits.js +1 -1
- package/dist/types-YiAC4gig.d.cts +33 -0
- package/dist/types-YiAC4gig.d.ts +33 -0
- package/dist/web.cjs +3067 -2527
- package/dist/web.d.cts +22 -6
- package/dist/web.d.ts +22 -6
- package/dist/web.js +185 -9
- package/dist/zkProve.worker.cjs +93 -0
- package/dist/zkProve.worker.d.cts +2 -0
- package/dist/zkProve.worker.d.ts +2 -0
- package/dist/zkProve.worker.js +91 -0
- package/node/client.test.ts +20 -25
- package/node/encryptInputs.test.ts +18 -38
- package/node/index.ts +1 -0
- package/package.json +15 -15
- package/permits/index.ts +1 -0
- package/permits/localstorage.test.ts +9 -14
- package/permits/onchain-utils.ts +221 -0
- package/permits/permit.test.ts +76 -27
- package/permits/permit.ts +58 -95
- package/permits/sealing.test.ts +3 -3
- package/permits/sealing.ts +2 -2
- package/permits/store.test.ts +10 -50
- package/permits/store.ts +9 -21
- package/permits/test-utils.ts +11 -3
- package/permits/types.ts +39 -9
- package/permits/utils.ts +0 -5
- package/permits/validation.test.ts +29 -32
- package/permits/validation.ts +114 -176
- package/web/client.web.test.ts +20 -25
- package/web/config.web.test.ts +0 -2
- package/web/encryptInputs.web.test.ts +31 -54
- package/web/index.ts +65 -1
- package/web/storage.ts +19 -5
- package/web/worker.builder.web.test.ts +148 -0
- package/web/worker.config.web.test.ts +329 -0
- package/web/worker.output.web.test.ts +84 -0
- package/web/workerManager.test.ts +80 -0
- package/web/workerManager.ts +214 -0
- package/web/workerManager.web.test.ts +114 -0
- package/web/zkProve.worker.ts +133 -0
- package/core/result.test.ts +0 -180
- package/core/result.ts +0 -67
- package/core/test-utils.ts +0 -45
- package/dist/types-KImPrEIe.d.cts +0 -48
- package/dist/types-KImPrEIe.d.ts +0 -48
package/permits/permit.test.ts
CHANGED
|
@@ -44,8 +44,9 @@ describe('PermitUtils Tests', () => {
|
|
|
44
44
|
name: 'Test Permit',
|
|
45
45
|
};
|
|
46
46
|
|
|
47
|
-
const permit =
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
301
|
+
const permit = PermitUtils.importShared({
|
|
284
302
|
issuer: bobAddress,
|
|
285
303
|
recipient: aliceAddress,
|
|
286
|
-
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
377
|
+
const permit2 = PermitUtils.createSelf({
|
|
378
|
+
expiration,
|
|
357
379
|
issuer: bobAddress,
|
|
358
380
|
name: 'Test Permit',
|
|
359
381
|
});
|
|
360
382
|
|
|
361
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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:
|
|
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 =
|
|
41
|
+
const sealingPair = GenerateSealingKey();
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
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:
|
|
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 =
|
|
60
|
+
const sealingPair = GenerateSealingKey();
|
|
65
61
|
|
|
66
|
-
|
|
67
|
-
|
|
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:
|
|
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(`
|
|
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(`
|
|
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 =
|
|
101
|
+
const sealingPair = GenerateSealingKey();
|
|
111
102
|
|
|
112
|
-
|
|
113
|
-
|
|
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:
|
|
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
|
-
'
|
|
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
|
|
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<
|
|
167
|
-
const permit =
|
|
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<
|
|
179
|
-
const permit =
|
|
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 |
|
|
181
|
+
options: ImportSharedPermitOptions | string,
|
|
188
182
|
publicClient: PublicClient,
|
|
189
183
|
walletClient: WalletClient
|
|
190
|
-
): Promise<
|
|
191
|
-
const permit =
|
|
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('
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
|
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
|
};
|
package/permits/sealing.test.ts
CHANGED
|
@@ -67,7 +67,7 @@ describe('SealingKey', () => {
|
|
|
67
67
|
|
|
68
68
|
describe('GenerateSealingKey', () => {
|
|
69
69
|
it('should generate a valid SealingKey', async () => {
|
|
70
|
-
const sealingKey =
|
|
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 =
|
|
79
|
-
const key2 =
|
|
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);
|
package/permits/sealing.ts
CHANGED
|
@@ -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 {
|
|
125
|
+
* @returns {SealingKey} - A new SealingKey object containing the hexadecimal strings of the public and private keys.
|
|
126
126
|
*/
|
|
127
|
-
export const GenerateSealingKey =
|
|
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));
|