@cofhe/sdk 0.6.0 → 0.7.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.
- package/CHANGELOG.md +49 -0
- package/acps/acp.ts +411 -0
- package/acps/index.ts +70 -0
- package/{permits → acps}/onchain-utils.ts +49 -24
- package/acps/sealing.ts +90 -0
- package/acps/signature.ts +89 -0
- package/acps/store.ts +172 -0
- package/acps/test/acp.test.ts +615 -0
- package/acps/test/localstorage.test.ts +105 -0
- package/acps/test/sealing.test.ts +77 -0
- package/acps/test/store.test.ts +88 -0
- package/acps/test/validation.test.ts +361 -0
- package/acps/test-utils.ts +32 -0
- package/acps/types.ts +252 -0
- package/acps/validation.ts +392 -0
- package/adapters/test/ethers5.test.ts +4 -1
- package/adapters/test/ethers6.test.ts +4 -1
- package/adapters/test/wagmi.test.ts +5 -2
- package/chains/chains/stagingCofhe.ts +21 -0
- package/chains/index.ts +3 -1
- package/chains/test/chains.test.ts +2 -1
- package/core/acps.ts +625 -0
- package/core/client.ts +136 -39
- package/core/clientTypes.ts +52 -41
- package/core/config.ts +66 -5
- package/core/debug.ts +72 -0
- package/core/decrypt/MockThresholdNetworkAbi.ts +20 -11
- package/core/decrypt/apiError.ts +104 -0
- package/core/decrypt/cofheMocksDecryptForTx.ts +11 -11
- package/core/decrypt/cofheMocksDecryptForView.ts +7 -7
- package/core/decrypt/decryptForTxBuilder.ts +102 -102
- package/core/decrypt/decryptForViewBuilder.ts +90 -90
- package/core/decrypt/submitRetry.ts +38 -30
- package/core/decrypt/tnDecryptV1.ts +5 -5
- package/core/decrypt/tnDecryptV2.ts +45 -34
- package/core/decrypt/tnSealOutputV1.ts +4 -3
- package/core/decrypt/tnSealOutputV2.ts +44 -31
- package/core/encrypt/cofheMocksZkVerifySign.ts +59 -74
- package/core/encrypt/encryptInputsBuilder.ts +86 -52
- package/core/encrypt/zkPackProveVerify.ts +25 -18
- package/core/error.ts +34 -6
- package/core/index.ts +14 -14
- package/core/test/acpDefaults.test.ts +52 -0
- package/core/test/acps.test.ts +596 -0
- package/core/test/apiError.test.ts +130 -0
- package/core/test/client.test.ts +22 -19
- package/core/test/config.test.ts +25 -5
- package/core/test/decrypt.test.ts +40 -35
- package/core/test/decryptBuilders.test.ts +68 -68
- package/core/test/decryptErrorCodes.test.ts +217 -0
- package/core/test/encryptInputsBuilder.test.ts +72 -41
- package/core/test/pollCallbacks.test.ts +89 -18
- package/core/test/stagingRedirect.ts +18 -0
- package/core/test/submitRetry.test.ts +182 -0
- package/core/types.ts +9 -69
- package/dist/acp-Wi6isVQI.d.cts +407 -0
- package/dist/acp-Wi6isVQI.d.ts +407 -0
- package/dist/acps.cjs +1081 -0
- package/dist/acps.d.cts +480 -0
- package/dist/acps.d.ts +480 -0
- package/dist/acps.js +2 -0
- package/dist/chains.cjs +14 -1
- package/dist/chains.d.cts +30 -1
- package/dist/chains.d.ts +30 -1
- package/dist/chains.js +1 -1
- package/dist/{chunk-PE5V5CCV.js → chunk-43USWPEH.js} +1000 -604
- package/dist/{chunk-MTRAXQXC.js → chunk-N6IDQRRU.js} +14 -2
- package/dist/chunk-Q7CBWGQX.js +1029 -0
- package/dist/{clientTypes-CyUvRRzA.d.ts → clientTypes-BN3nbzYM.d.ts} +342 -165
- package/dist/{clientTypes-BDy1qIBu.d.cts → clientTypes-CYZjFznO.d.cts} +342 -165
- package/dist/core.cjs +1431 -1026
- package/dist/core.d.cts +55 -10
- package/dist/core.d.ts +55 -10
- package/dist/core.js +3 -3
- package/dist/node.cjs +1356 -976
- package/dist/node.d.cts +2 -2
- package/dist/node.d.ts +2 -2
- package/dist/node.js +3 -3
- package/dist/web.cjs +1356 -976
- package/dist/web.d.cts +2 -2
- package/dist/web.d.ts +2 -2
- package/dist/web.js +3 -3
- package/node/test/inherited.test.ts +75 -65
- package/node/test/tfheinit.test.ts +23 -8
- package/package.json +6 -6
- package/web/test/client.web.test.ts +5 -1
- package/web/test/inherited.web.test.ts +75 -65
- package/web/test/tfheinit.web.test.ts +14 -5
- package/web/test/worker.config.web.test.ts +38 -23
- package/web/test/worker.output.web.test.ts +25 -24
- package/core/encrypt/encryptUtils.ts +0 -67
- package/core/permits.ts +0 -206
- package/core/test/permits.test.ts +0 -534
- package/dist/chunk-VB62WYPL.js +0 -978
- package/dist/permit-DnVMDT5h.d.cts +0 -376
- package/dist/permit-DnVMDT5h.d.ts +0 -376
- package/dist/permits.cjs +0 -1026
- package/dist/permits.d.cts +0 -353
- package/dist/permits.d.ts +0 -353
- package/dist/permits.js +0 -2
- package/permits/index.ts +0 -68
- package/permits/permit.ts +0 -385
- package/permits/sealing.ts +0 -131
- package/permits/signature.ts +0 -79
- package/permits/store.ts +0 -157
- package/permits/test/localstorage.test.ts +0 -113
- package/permits/test/permit.test.ts +0 -557
- package/permits/test/sealing.test.ts +0 -84
- package/permits/test/store.test.ts +0 -88
- package/permits/test/validation.test.ts +0 -361
- package/permits/test-utils.ts +0 -28
- package/permits/types.ts +0 -204
- package/permits/validation.ts +0 -327
- /package/{permits → acps}/utils.ts +0 -0
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @vitest-environment node
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
6
|
-
import {
|
|
7
|
-
permitStore,
|
|
8
|
-
getPermit,
|
|
9
|
-
getActivePermit,
|
|
10
|
-
getPermits,
|
|
11
|
-
setPermit,
|
|
12
|
-
removePermit,
|
|
13
|
-
getActivePermitHash,
|
|
14
|
-
setActivePermitHash,
|
|
15
|
-
PermitUtils,
|
|
16
|
-
} from '../index.js';
|
|
17
|
-
|
|
18
|
-
import { createMockPermit } from '../test-utils.js';
|
|
19
|
-
|
|
20
|
-
describe('Storage Tests', () => {
|
|
21
|
-
const chainId = 1;
|
|
22
|
-
const account = '0x1234567890123456789012345678901234567890';
|
|
23
|
-
|
|
24
|
-
beforeEach(() => {
|
|
25
|
-
permitStore.resetStore();
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
afterEach(() => {
|
|
29
|
-
permitStore.resetStore();
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
describe('Permit Storage', () => {
|
|
33
|
-
it('should store and retrieve permits', async () => {
|
|
34
|
-
const permit = await createMockPermit();
|
|
35
|
-
|
|
36
|
-
setPermit(chainId, account, permit);
|
|
37
|
-
const retrieved = getPermit(chainId, account, permit.hash);
|
|
38
|
-
|
|
39
|
-
expect(retrieved).toBeDefined();
|
|
40
|
-
expect(PermitUtils.serialize(retrieved!)).toEqual(PermitUtils.serialize(permit));
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('should handle multiple permits per account', async () => {
|
|
44
|
-
const permit1 = await createMockPermit();
|
|
45
|
-
const permit2 = await createMockPermit({
|
|
46
|
-
issuer: '0x0987654321098765432109876543210987654321' as `0x${string}`,
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
setPermit(chainId, account, permit1);
|
|
50
|
-
setPermit(chainId, account, permit2);
|
|
51
|
-
|
|
52
|
-
const permits = getPermits(chainId, account);
|
|
53
|
-
expect(Object.keys(permits)).toHaveLength(2);
|
|
54
|
-
|
|
55
|
-
expect(PermitUtils.serialize(permits[permit1.hash])).toEqual(PermitUtils.serialize(permit1));
|
|
56
|
-
expect(PermitUtils.serialize(permits[permit2.hash])).toEqual(PermitUtils.serialize(permit2));
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('should handle active permit hash', async () => {
|
|
60
|
-
const permit = await createMockPermit();
|
|
61
|
-
|
|
62
|
-
setPermit(chainId, account, permit);
|
|
63
|
-
setActivePermitHash(chainId, account, permit.hash);
|
|
64
|
-
|
|
65
|
-
const activeHash = getActivePermitHash(chainId, account);
|
|
66
|
-
expect(activeHash).toBe(permit.hash);
|
|
67
|
-
|
|
68
|
-
const activePermit = getActivePermit(chainId, account);
|
|
69
|
-
expect(activePermit).toBeDefined();
|
|
70
|
-
expect(PermitUtils.serialize(activePermit!)).toEqual(PermitUtils.serialize(permit));
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it('should remove permits', async () => {
|
|
74
|
-
const permit = await createMockPermit();
|
|
75
|
-
|
|
76
|
-
setPermit(chainId, account, permit);
|
|
77
|
-
setActivePermitHash(chainId, account, permit.hash);
|
|
78
|
-
|
|
79
|
-
removePermit(chainId, account, permit.hash);
|
|
80
|
-
|
|
81
|
-
const retrieved = getPermit(chainId, account, permit.hash);
|
|
82
|
-
expect(retrieved).toBeUndefined();
|
|
83
|
-
|
|
84
|
-
const activeHash = getActivePermitHash(chainId, account);
|
|
85
|
-
expect(activeHash).toBeUndefined();
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
});
|
|
@@ -1,361 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import {
|
|
3
|
-
ValidationUtils,
|
|
4
|
-
validateSelfPermitOptions,
|
|
5
|
-
validateSharingPermitOptions,
|
|
6
|
-
validateImportPermitOptions,
|
|
7
|
-
validateSelfPermit,
|
|
8
|
-
validateSharingPermit,
|
|
9
|
-
validateImportPermit,
|
|
10
|
-
type Permit,
|
|
11
|
-
type CreateSelfPermitOptions,
|
|
12
|
-
type CreateSharingPermitOptions,
|
|
13
|
-
type ImportSharedPermitOptions,
|
|
14
|
-
} from '../index.js';
|
|
15
|
-
import { createMockPermit } from '../test-utils.js';
|
|
16
|
-
|
|
17
|
-
describe('Validation Tests', () => {
|
|
18
|
-
describe('validateSelfPermitOptions', () => {
|
|
19
|
-
it('should validate valid self permit options', () => {
|
|
20
|
-
const options: CreateSelfPermitOptions = {
|
|
21
|
-
type: 'self',
|
|
22
|
-
issuer: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', // Bob's address
|
|
23
|
-
name: 'Test Permit',
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
expect(() => validateSelfPermitOptions(options)).not.toThrow();
|
|
27
|
-
const result = validateSelfPermitOptions(options);
|
|
28
|
-
expect(result).toBeDefined();
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('should reject invalid address', () => {
|
|
32
|
-
const options: CreateSelfPermitOptions = {
|
|
33
|
-
type: 'self',
|
|
34
|
-
issuer: 'invalid-address',
|
|
35
|
-
name: 'Test Permit',
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
expect(() => validateSelfPermitOptions(options)).toThrow();
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('should reject zero address', () => {
|
|
42
|
-
const options: CreateSelfPermitOptions = {
|
|
43
|
-
type: 'self',
|
|
44
|
-
issuer: '0x0000000000000000000000000000000000000000',
|
|
45
|
-
name: 'Test Permit',
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
expect(() => validateSelfPermitOptions(options)).toThrow();
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
describe('validateSharingPermitOptions', () => {
|
|
53
|
-
it('should validate valid sharing permit options', () => {
|
|
54
|
-
const options: CreateSharingPermitOptions = {
|
|
55
|
-
type: 'sharing',
|
|
56
|
-
issuer: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', // Bob's address
|
|
57
|
-
recipient: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8', // Alice's address
|
|
58
|
-
name: 'Sharing Permit',
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
expect(() => validateSharingPermitOptions(options)).not.toThrow();
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
it('should reject sharing permit with zero recipient', () => {
|
|
65
|
-
const options: CreateSharingPermitOptions = {
|
|
66
|
-
type: 'sharing',
|
|
67
|
-
issuer: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', // Bob's address
|
|
68
|
-
recipient: '0x0000000000000000000000000000000000000000',
|
|
69
|
-
name: 'Sharing Permit',
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
expect(() => validateSharingPermitOptions(options)).toThrow();
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it('should reject sharing permit with invalid recipient', () => {
|
|
76
|
-
const options: CreateSharingPermitOptions = {
|
|
77
|
-
type: 'sharing',
|
|
78
|
-
issuer: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', // Bob's address
|
|
79
|
-
recipient: 'invalid-address',
|
|
80
|
-
name: 'Sharing Permit',
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
expect(() => validateSharingPermitOptions(options)).toThrow();
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
describe('validateImportPermitOptions', () => {
|
|
88
|
-
it('should validate valid import permit options', () => {
|
|
89
|
-
const options: ImportSharedPermitOptions = {
|
|
90
|
-
issuer: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', // Bob's address
|
|
91
|
-
expiration: Math.floor(Date.now() / 1000) + 3600, // 1 hour from now
|
|
92
|
-
recipient: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8', // Alice's address
|
|
93
|
-
issuerSignature: '0x1234567890abcdef',
|
|
94
|
-
name: 'Import Permit',
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
expect(() => validateImportPermitOptions(options)).not.toThrow();
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it('should reject import permit with missing expiration', () => {
|
|
101
|
-
const options = {
|
|
102
|
-
issuer: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', // Bob's address
|
|
103
|
-
recipient: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8', // Alice's address
|
|
104
|
-
issuerSignature: '0x1234567890abcdef',
|
|
105
|
-
name: 'Import Permit',
|
|
106
|
-
};
|
|
107
|
-
expect(() => validateImportPermitOptions(options)).toThrow();
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
it('should reject import permit with empty signature', () => {
|
|
111
|
-
const options: ImportSharedPermitOptions = {
|
|
112
|
-
issuer: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', // Bob's address
|
|
113
|
-
expiration: Math.floor(Date.now() / 1000) + 3600, // 1 hour from now
|
|
114
|
-
recipient: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8', // Alice's address
|
|
115
|
-
issuerSignature: '0x',
|
|
116
|
-
name: 'Import Permit',
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
expect(() => validateImportPermitOptions(options)).toThrow();
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it('should reject import permit with invalid signature', () => {
|
|
123
|
-
const options: ImportSharedPermitOptions = {
|
|
124
|
-
issuer: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', // Bob's address
|
|
125
|
-
expiration: Math.floor(Date.now() / 1000) + 3600, // 1 hour from now
|
|
126
|
-
recipient: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8', // Alice's address
|
|
127
|
-
issuerSignature: '0x',
|
|
128
|
-
name: 'Import Permit',
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
expect(() => validateImportPermitOptions(options)).toThrow();
|
|
132
|
-
});
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
describe('validateSelfPermit', () => {
|
|
136
|
-
it('should validate valid self permit', async () => {
|
|
137
|
-
const permit = await createMockPermit();
|
|
138
|
-
permit.type = 'self';
|
|
139
|
-
permit.issuerSignature = '0x1234567890abcdef';
|
|
140
|
-
|
|
141
|
-
expect(() => validateSelfPermit(permit)).not.toThrow();
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
it('should reject self permit with missing sealing pair', async () => {
|
|
145
|
-
const permit = { ...(await createMockPermit()), sealingPair: undefined };
|
|
146
|
-
permit.type = 'self';
|
|
147
|
-
expect(() => validateSelfPermit(permit as unknown as Permit)).toThrow();
|
|
148
|
-
});
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
describe('validateSharingPermit', () => {
|
|
152
|
-
it('should validate valid sharing permit', async () => {
|
|
153
|
-
const permit = await createMockPermit();
|
|
154
|
-
permit.type = 'sharing';
|
|
155
|
-
permit.issuerSignature = '0x1234567890abcdef';
|
|
156
|
-
permit.recipient = '0x70997970C51812dc3A010C7d01b50e0d17dc79C8'; // Alice's address
|
|
157
|
-
|
|
158
|
-
expect(() => validateSharingPermit(permit)).not.toThrow();
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
it('should reject sharing permit with zero recipient', async () => {
|
|
162
|
-
const permit = await createMockPermit();
|
|
163
|
-
permit.type = 'sharing';
|
|
164
|
-
permit.issuerSignature = '0x1234567890abcdef';
|
|
165
|
-
permit.recipient = '0x0000000000000000000000000000000000000000';
|
|
166
|
-
|
|
167
|
-
expect(() => validateSharingPermit(permit)).toThrow();
|
|
168
|
-
});
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
describe('validateImportPermit', () => {
|
|
172
|
-
it('should validate valid import permit', async () => {
|
|
173
|
-
const permit = await createMockPermit();
|
|
174
|
-
permit.type = 'recipient';
|
|
175
|
-
permit.issuerSignature = '0x1234567890abcdef';
|
|
176
|
-
permit.recipient = '0x70997970C51812dc3A010C7d01b50e0d17dc79C8'; // Alice's address
|
|
177
|
-
permit.recipientSignature = '0xabcdef1234567890';
|
|
178
|
-
|
|
179
|
-
expect(() => validateImportPermit(permit)).not.toThrow();
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
it('should reject import permit with empty recipient signature', async () => {
|
|
183
|
-
const permit = await createMockPermit();
|
|
184
|
-
permit.type = 'recipient';
|
|
185
|
-
permit.issuerSignature = '0x1234567890abcdef';
|
|
186
|
-
permit.recipient = '0x70997970C51812dc3A010C7d01b50e0d17dc79C8'; // Alice's address
|
|
187
|
-
permit.recipientSignature = '0x';
|
|
188
|
-
|
|
189
|
-
expect(() => validateImportPermit(permit)).toThrow();
|
|
190
|
-
});
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
describe('ValidationUtils', () => {
|
|
194
|
-
describe('isExpired', () => {
|
|
195
|
-
it('should return true for expired permit', async () => {
|
|
196
|
-
const permit = {
|
|
197
|
-
...(await createMockPermit()),
|
|
198
|
-
expiration: Math.floor(Date.now() / 1000) - 3600, // 1 hour ago
|
|
199
|
-
};
|
|
200
|
-
expect(ValidationUtils.isExpired(permit)).toBe(true);
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
it('should return false for non-expired permit', async () => {
|
|
204
|
-
const permit = {
|
|
205
|
-
...(await createMockPermit()),
|
|
206
|
-
expiration: Math.floor(Date.now() / 1000) + 3600, // 1 hour from now
|
|
207
|
-
};
|
|
208
|
-
expect(ValidationUtils.isExpired(permit)).toBe(false);
|
|
209
|
-
});
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
describe('isSigned', () => {
|
|
213
|
-
it('should return true for signed self permit', async () => {
|
|
214
|
-
const permit = {
|
|
215
|
-
...(await createMockPermit()),
|
|
216
|
-
type: 'self' as const,
|
|
217
|
-
issuerSignature: '0x1234567890abcdef' as `0x${string}`,
|
|
218
|
-
};
|
|
219
|
-
expect(ValidationUtils.isSigned(permit)).toBe(true);
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
it('should return false for unsigned self permit', async () => {
|
|
223
|
-
const permit = {
|
|
224
|
-
...(await createMockPermit()),
|
|
225
|
-
type: 'self' as const,
|
|
226
|
-
issuerSignature: '0x' as `0x${string}`,
|
|
227
|
-
};
|
|
228
|
-
expect(ValidationUtils.isSigned(permit)).toBe(false);
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
it('should return true for signed recipient permit', async () => {
|
|
232
|
-
const permit = {
|
|
233
|
-
...(await createMockPermit()),
|
|
234
|
-
type: 'recipient' as const,
|
|
235
|
-
recipientSignature: '0x1234567890abcdef' as `0x${string}`,
|
|
236
|
-
};
|
|
237
|
-
expect(ValidationUtils.isSigned(permit)).toBe(true);
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
it('should return false for unsigned recipient permit', async () => {
|
|
241
|
-
const permit = {
|
|
242
|
-
...(await createMockPermit()),
|
|
243
|
-
type: 'recipient' as const,
|
|
244
|
-
recipientSignature: '0x' as `0x${string}`,
|
|
245
|
-
};
|
|
246
|
-
expect(ValidationUtils.isSigned(permit)).toBe(false);
|
|
247
|
-
});
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
describe('isSignedAndNotExpired', () => {
|
|
251
|
-
it('should return valid for valid permit', async () => {
|
|
252
|
-
const permit = {
|
|
253
|
-
...(await createMockPermit()),
|
|
254
|
-
expiration: Math.floor(Date.now() / 1000) + 3600,
|
|
255
|
-
issuerSignature: '0x1234567890abcdef' as `0x${string}`,
|
|
256
|
-
};
|
|
257
|
-
const result = ValidationUtils.isSignedAndNotExpired(permit);
|
|
258
|
-
expect(result.valid).toBe(true);
|
|
259
|
-
expect(result.error).toBeNull();
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
it('should return invalid for expired permit', async () => {
|
|
263
|
-
const permit = {
|
|
264
|
-
...(await createMockPermit()),
|
|
265
|
-
expiration: Math.floor(Date.now() / 1000) - 3600,
|
|
266
|
-
issuerSignature: '0x1234567890abcdef' as `0x${string}`,
|
|
267
|
-
};
|
|
268
|
-
const result = ValidationUtils.isSignedAndNotExpired(permit);
|
|
269
|
-
expect(result.valid).toBe(false);
|
|
270
|
-
expect(result.error).toBe('expired');
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
it('should return invalid for unsigned permit', async () => {
|
|
274
|
-
const permit = {
|
|
275
|
-
...(await createMockPermit()),
|
|
276
|
-
expiration: Math.floor(Date.now() / 1000) + 3600,
|
|
277
|
-
issuerSignature: '0x' as `0x${string}`,
|
|
278
|
-
};
|
|
279
|
-
const result = ValidationUtils.isSignedAndNotExpired(permit);
|
|
280
|
-
expect(result.valid).toBe(false);
|
|
281
|
-
expect(result.error).toBe('not-signed');
|
|
282
|
-
});
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
describe('assertSignedAndNotExpired', () => {
|
|
286
|
-
it('should not throw for valid permit', async () => {
|
|
287
|
-
const permit = {
|
|
288
|
-
...(await createMockPermit()),
|
|
289
|
-
expiration: Math.floor(Date.now() / 1000) + 3600,
|
|
290
|
-
issuerSignature: '0x1234567890abcdef' as `0x${string}`,
|
|
291
|
-
};
|
|
292
|
-
expect(() => ValidationUtils.assertSignedAndNotExpired(permit)).not.toThrow();
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
it('should throw for expired permit', async () => {
|
|
296
|
-
const permit = {
|
|
297
|
-
...(await createMockPermit()),
|
|
298
|
-
expiration: Math.floor(Date.now() / 1000) - 3600,
|
|
299
|
-
issuerSignature: '0x1234567890abcdef' as `0x${string}`,
|
|
300
|
-
};
|
|
301
|
-
expect(() => ValidationUtils.assertSignedAndNotExpired(permit)).toThrow('Permit is expired');
|
|
302
|
-
});
|
|
303
|
-
|
|
304
|
-
it('should throw for unsigned permit', async () => {
|
|
305
|
-
const permit = {
|
|
306
|
-
...(await createMockPermit()),
|
|
307
|
-
expiration: Math.floor(Date.now() / 1000) + 3600,
|
|
308
|
-
issuerSignature: '0x' as `0x${string}`,
|
|
309
|
-
};
|
|
310
|
-
expect(() => ValidationUtils.assertSignedAndNotExpired(permit)).toThrow('Permit is not signed');
|
|
311
|
-
});
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
describe('isValid', () => {
|
|
315
|
-
it('should return invalid-schema for schema-invalid permit', async () => {
|
|
316
|
-
const permit = {
|
|
317
|
-
...(await createMockPermit()),
|
|
318
|
-
type: 'self' as const,
|
|
319
|
-
expiration: Math.floor(Date.now() / 1000) + 3600,
|
|
320
|
-
issuerSignature: '0x1234567890abcdef' as `0x${string}`,
|
|
321
|
-
// Self permits must have recipient == zeroAddress per schema.
|
|
322
|
-
recipient: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8' as `0x${string}`,
|
|
323
|
-
};
|
|
324
|
-
|
|
325
|
-
const result = ValidationUtils.isValid(permit as unknown as Permit);
|
|
326
|
-
expect(result.valid).toBe(false);
|
|
327
|
-
expect(result.error).toBe('invalid-schema');
|
|
328
|
-
});
|
|
329
|
-
|
|
330
|
-
it('should return expired for expired but otherwise schema-valid permit', async () => {
|
|
331
|
-
const permit = {
|
|
332
|
-
...(await createMockPermit()),
|
|
333
|
-
type: 'self' as const,
|
|
334
|
-
expiration: Math.floor(Date.now() / 1000) - 3600,
|
|
335
|
-
issuerSignature: '0x1234567890abcdef' as `0x${string}`,
|
|
336
|
-
recipient: '0x0000000000000000000000000000000000000000' as `0x${string}`,
|
|
337
|
-
recipientSignature: '0x' as `0x${string}`,
|
|
338
|
-
};
|
|
339
|
-
|
|
340
|
-
const result = ValidationUtils.isValid(permit as unknown as Permit);
|
|
341
|
-
expect(result.valid).toBe(false);
|
|
342
|
-
expect(result.error).toBe('expired');
|
|
343
|
-
});
|
|
344
|
-
|
|
345
|
-
it('should return valid for schema-valid, signed, non-expired permit', async () => {
|
|
346
|
-
const permit = {
|
|
347
|
-
...(await createMockPermit()),
|
|
348
|
-
type: 'self' as const,
|
|
349
|
-
expiration: Math.floor(Date.now() / 1000) + 3600,
|
|
350
|
-
issuerSignature: '0x1234567890abcdef' as `0x${string}`,
|
|
351
|
-
recipient: '0x0000000000000000000000000000000000000000' as `0x${string}`,
|
|
352
|
-
recipientSignature: '0x' as `0x${string}`,
|
|
353
|
-
};
|
|
354
|
-
|
|
355
|
-
const result = ValidationUtils.isValid(permit as unknown as Permit);
|
|
356
|
-
expect(result.valid).toBe(true);
|
|
357
|
-
expect(result.error).toBeNull();
|
|
358
|
-
});
|
|
359
|
-
});
|
|
360
|
-
});
|
|
361
|
-
});
|
package/permits/test-utils.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { type Permit, type SerializedPermit, GenerateSealingKey, PermitUtils } from './index.js';
|
|
2
|
-
|
|
3
|
-
// Mock permit for testing - using Bob's address as issuer
|
|
4
|
-
export const createMockPermit = async (overrides: Partial<Permit> = {}): Promise<Permit> => {
|
|
5
|
-
const sealingPair = GenerateSealingKey();
|
|
6
|
-
|
|
7
|
-
const fields = {
|
|
8
|
-
name: 'Test Permit',
|
|
9
|
-
type: 'self',
|
|
10
|
-
issuer: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', // Bob's address
|
|
11
|
-
expiration: 1000000000000,
|
|
12
|
-
recipient: '0x0000000000000000000000000000000000000000',
|
|
13
|
-
validatorId: 0,
|
|
14
|
-
validatorContract: '0x0000000000000000000000000000000000000000',
|
|
15
|
-
sealingPair: sealingPair.serialize(),
|
|
16
|
-
issuerSignature: '0x',
|
|
17
|
-
recipientSignature: '0x',
|
|
18
|
-
_signedDomain: undefined,
|
|
19
|
-
...overrides,
|
|
20
|
-
} as const;
|
|
21
|
-
|
|
22
|
-
const serializedPermit: SerializedPermit = {
|
|
23
|
-
hash: PermitUtils.getHash(fields),
|
|
24
|
-
...fields,
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
return PermitUtils.deserialize(serializedPermit);
|
|
28
|
-
};
|
package/permits/types.ts
DELETED
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
import { SealingKey as SealingKeyClass, type EthEncryptedData } from './sealing.js';
|
|
2
|
-
import { type Hex } from 'viem';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* EIP712 related types
|
|
6
|
-
*/
|
|
7
|
-
export type EIP712Type = { name: string; type: string };
|
|
8
|
-
export type EIP712Types = Record<string, EIP712Type[]>;
|
|
9
|
-
export type EIP712Message = Record<string, string>;
|
|
10
|
-
export type EIP712Domain = {
|
|
11
|
-
chainId: number;
|
|
12
|
-
name: string;
|
|
13
|
-
verifyingContract: Hex;
|
|
14
|
-
version: string;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Sealing key type - using the actual SealingKey class
|
|
19
|
-
*/
|
|
20
|
-
export type SealingKey = SealingKeyClass;
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Re-export EthEncryptedData from sealing module
|
|
24
|
-
*/
|
|
25
|
-
export type { EthEncryptedData };
|
|
26
|
-
|
|
27
|
-
// Viem client types will be imported from viem package
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Core Permit interface - immutable design for React compatibility
|
|
31
|
-
*/
|
|
32
|
-
export interface Permit {
|
|
33
|
-
/**
|
|
34
|
-
* Stable hash of relevant permit data, used as key in storage
|
|
35
|
-
*/
|
|
36
|
-
hash: string;
|
|
37
|
-
/**
|
|
38
|
-
* Name for this permit, for organization and UI usage, not included in signature.
|
|
39
|
-
*/
|
|
40
|
-
name: string;
|
|
41
|
-
/**
|
|
42
|
-
* The type of the Permit (self / sharing)
|
|
43
|
-
* (self) Permit that will be signed and used by the issuer
|
|
44
|
-
* (sharing) Permit that is signed by the issuer, but intended to be shared with recipient
|
|
45
|
-
* (recipient) Permit that has been received, and signed by the recipient
|
|
46
|
-
*/
|
|
47
|
-
type: 'self' | 'sharing' | 'recipient';
|
|
48
|
-
/**
|
|
49
|
-
* (base) User that initially created the permission, target of data fetching
|
|
50
|
-
*/
|
|
51
|
-
issuer: Hex;
|
|
52
|
-
/**
|
|
53
|
-
* (base) Expiration timestamp
|
|
54
|
-
*/
|
|
55
|
-
expiration: number;
|
|
56
|
-
/**
|
|
57
|
-
* (sharing) The user that this permission will be shared with
|
|
58
|
-
* ** optional, use `address(0)` to disable **
|
|
59
|
-
*/
|
|
60
|
-
recipient: Hex;
|
|
61
|
-
/**
|
|
62
|
-
* (issuer defined validation) An id used to query a contract to check this permissions validity
|
|
63
|
-
* ** optional, use `0` to disable **
|
|
64
|
-
*/
|
|
65
|
-
validatorId: number;
|
|
66
|
-
/**
|
|
67
|
-
* (issuer defined validation) The contract to query to determine permission validity
|
|
68
|
-
* ** optional, user `address(0)` to disable **
|
|
69
|
-
*/
|
|
70
|
-
validatorContract: Hex;
|
|
71
|
-
/**
|
|
72
|
-
* (base) The publicKey of a sealingPair used to re-encrypt `issuer`s confidential data
|
|
73
|
-
* (non-sharing) Populated by `issuer`
|
|
74
|
-
* (sharing) Populated by `recipient`
|
|
75
|
-
*/
|
|
76
|
-
sealingPair: SealingKey;
|
|
77
|
-
/**
|
|
78
|
-
* (base) `signTypedData` signature created by `issuer`.
|
|
79
|
-
* (base) Shared- and Self- permissions differ in signature format: (`sealingKey` absent in shared signature)
|
|
80
|
-
* (non-sharing) < issuer, expiration, recipient, validatorId, validatorContract, sealingKey >
|
|
81
|
-
* (sharing) < issuer, expiration, recipient, validatorId, validatorContract >
|
|
82
|
-
*/
|
|
83
|
-
issuerSignature: Hex;
|
|
84
|
-
/**
|
|
85
|
-
* (sharing) `signTypedData` signature created by `recipient` with format:
|
|
86
|
-
* (sharing) < sealingKey, issuerSignature>
|
|
87
|
-
* ** required for shared permits **
|
|
88
|
-
*/
|
|
89
|
-
recipientSignature: Hex;
|
|
90
|
-
/**
|
|
91
|
-
* EIP712 domain used to sign this permit.
|
|
92
|
-
* Should not be set manually, included in metadata as part of serialization flows.
|
|
93
|
-
*/
|
|
94
|
-
_signedDomain?: EIP712Domain;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Permit discriminant helpers
|
|
99
|
-
*/
|
|
100
|
-
export type PermitType = Permit['type'];
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Utility type to narrow a permit to a specific discriminant.
|
|
104
|
-
*
|
|
105
|
-
* Note: this only narrows the `type` field. Runtime/validation constraints
|
|
106
|
-
* (e.g. recipient == zeroAddress for self permits) are enforced elsewhere.
|
|
107
|
-
*/
|
|
108
|
-
export type PermitOf<T extends PermitType> = Expand<Omit<Permit, 'type'> & { type: T }>;
|
|
109
|
-
|
|
110
|
-
export type SelfPermit = PermitOf<'self'>;
|
|
111
|
-
export type SharingPermit = PermitOf<'sharing'>;
|
|
112
|
-
export type RecipientPermit = PermitOf<'recipient'>;
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Optional additional metadata of a Permit
|
|
116
|
-
* Can be passed into the constructor, but not necessary
|
|
117
|
-
* Useful for deserialization
|
|
118
|
-
*/
|
|
119
|
-
export interface PermitMetadata {
|
|
120
|
-
/**
|
|
121
|
-
* EIP712 domain used to sign this permit.
|
|
122
|
-
* Should not be set manually, included in metadata as part of serialization flows.
|
|
123
|
-
*/
|
|
124
|
-
_signedDomain?: EIP712Domain;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Utility types for permit creation
|
|
129
|
-
*/
|
|
130
|
-
|
|
131
|
-
// Specific option types for each permit creation method
|
|
132
|
-
export type CreateSelfPermitOptions = {
|
|
133
|
-
type?: 'self';
|
|
134
|
-
issuer: string;
|
|
135
|
-
name?: string;
|
|
136
|
-
expiration?: number;
|
|
137
|
-
validatorId?: number;
|
|
138
|
-
validatorContract?: string;
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
export type CreateSharingPermitOptions = {
|
|
142
|
-
type?: 'sharing';
|
|
143
|
-
issuer: string;
|
|
144
|
-
recipient: string;
|
|
145
|
-
name?: string;
|
|
146
|
-
expiration?: number;
|
|
147
|
-
validatorId?: number;
|
|
148
|
-
validatorContract?: string;
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
export type ImportSharedPermitOptions = {
|
|
152
|
-
type?: 'sharing';
|
|
153
|
-
issuer: string;
|
|
154
|
-
recipient: string;
|
|
155
|
-
issuerSignature: string;
|
|
156
|
-
name?: string;
|
|
157
|
-
expiration: number;
|
|
158
|
-
validatorId?: number;
|
|
159
|
-
validatorContract?: string;
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
export type SerializedPermit = Omit<Permit, 'sealingPair'> & {
|
|
163
|
-
_signedDomain?: EIP712Domain;
|
|
164
|
-
sealingPair: {
|
|
165
|
-
privateKey: string;
|
|
166
|
-
publicKey: string;
|
|
167
|
-
};
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* A type representing the Permission struct that is passed to Permissioned.sol to grant encrypted data access.
|
|
172
|
-
*/
|
|
173
|
-
export type Permission = Expand<
|
|
174
|
-
Omit<Permit, 'name' | 'type' | 'sealingPair' | 'hash'> & {
|
|
175
|
-
sealingKey: Hex;
|
|
176
|
-
}
|
|
177
|
-
>;
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* A type representing the permit fields that are used to generate the hash
|
|
181
|
-
*/
|
|
182
|
-
export type PermitHashFields = Pick<
|
|
183
|
-
Permit,
|
|
184
|
-
'type' | 'issuer' | 'expiration' | 'recipient' | 'validatorId' | 'validatorContract'
|
|
185
|
-
>;
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Validation result type
|
|
189
|
-
*/
|
|
190
|
-
export interface ValidationResult {
|
|
191
|
-
valid: boolean;
|
|
192
|
-
error: 'invalid-schema' | 'expired' | 'not-signed' | null;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* Signature types for EIP712 signing
|
|
197
|
-
*/
|
|
198
|
-
export type PermitSignaturePrimaryType =
|
|
199
|
-
| 'PermissionedV2IssuerSelf'
|
|
200
|
-
| 'PermissionedV2IssuerShared'
|
|
201
|
-
| 'PermissionedV2Recipient';
|
|
202
|
-
|
|
203
|
-
// Utils
|
|
204
|
-
export type Expand<T> = T extends infer O ? { [K in keyof O]: O[K] } : never;
|