@cofhe/sdk 0.2.0 → 0.3.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 +36 -0
- package/chains/defineChain.ts +2 -2
- package/chains/types.ts +3 -3
- package/core/baseBuilder.ts +18 -18
- package/core/client.test.ts +155 -41
- package/core/client.ts +72 -32
- package/core/clientTypes.ts +28 -18
- package/core/config.test.ts +40 -33
- package/core/config.ts +56 -51
- package/core/consts.ts +22 -0
- package/core/decrypt/{MockQueryDecrypterAbi.ts → MockThresholdNetworkAbi.ts} +71 -21
- package/core/decrypt/cofheMocksDecryptForTx.ts +142 -0
- package/core/decrypt/{cofheMocksSealOutput.ts → cofheMocksDecryptForView.ts} +12 -14
- package/core/decrypt/decryptForTxBuilder.ts +340 -0
- package/core/decrypt/{decryptHandleBuilder.ts → decryptForViewBuilder.ts} +75 -42
- package/core/decrypt/tnDecrypt.ts +232 -0
- package/core/decrypt/tnSealOutputV1.ts +5 -5
- package/core/decrypt/tnSealOutputV2.ts +27 -27
- package/core/encrypt/cofheMocksZkVerifySign.ts +19 -26
- package/core/encrypt/encryptInputsBuilder.test.ts +57 -61
- package/core/encrypt/encryptInputsBuilder.ts +65 -42
- package/core/encrypt/zkPackProveVerify.ts +11 -11
- package/core/error.ts +18 -18
- package/core/fetchKeys.test.ts +3 -3
- package/core/fetchKeys.ts +3 -3
- package/core/index.ts +22 -11
- package/core/permits.test.ts +5 -6
- package/core/permits.ts +5 -4
- package/core/utils.ts +10 -10
- package/dist/chains.cjs +4 -7
- package/dist/chains.d.cts +12 -12
- package/dist/chains.d.ts +12 -12
- package/dist/chains.js +1 -1
- package/dist/{chunk-WGCRJCBR.js → chunk-2TPSCOW3.js} +820 -224
- package/dist/{chunk-UGBVZNRT.js → chunk-NWDKXBIP.js} +309 -189
- package/dist/{chunk-WEAZ25JO.js → chunk-TBLR7NNE.js} +4 -7
- package/dist/{clientTypes-5_1nwtUe.d.cts → clientTypes-6aTZPQ_4.d.ts} +233 -173
- package/dist/{clientTypes-Es7fyi65.d.ts → clientTypes-Bhq7pCSA.d.cts} +233 -173
- package/dist/core.cjs +1138 -418
- package/dist/core.d.cts +37 -24
- package/dist/core.d.ts +37 -24
- package/dist/core.js +3 -3
- package/dist/node.cjs +1082 -370
- package/dist/node.d.cts +12 -12
- package/dist/node.d.ts +12 -12
- package/dist/node.js +8 -8
- package/dist/{permit-fUSe6KKq.d.cts → permit-MZ502UBl.d.cts} +30 -33
- package/dist/{permit-fUSe6KKq.d.ts → permit-MZ502UBl.d.ts} +30 -33
- package/dist/permits.cjs +305 -187
- package/dist/permits.d.cts +111 -812
- package/dist/permits.d.ts +111 -812
- 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 +1085 -373
- package/dist/web.d.cts +13 -13
- package/dist/web.d.ts +13 -13
- package/dist/web.js +10 -10
- package/node/client.test.ts +34 -34
- package/node/config.test.ts +11 -11
- package/node/encryptInputs.test.ts +29 -29
- package/node/index.ts +15 -15
- package/package.json +3 -3
- package/permits/localstorage.test.ts +9 -13
- package/permits/onchain-utils.ts +221 -0
- package/permits/permit.test.ts +51 -5
- package/permits/permit.ts +28 -74
- package/permits/store.test.ts +10 -50
- package/permits/store.ts +4 -14
- package/permits/test-utils.ts +10 -2
- package/permits/types.ts +22 -9
- package/permits/utils.ts +0 -4
- package/permits/validation.test.ts +29 -32
- package/permits/validation.ts +112 -194
- package/web/client.web.test.ts +34 -34
- package/web/config.web.test.ts +11 -11
- package/web/encryptInputs.web.test.ts +29 -29
- package/web/index.ts +19 -19
- package/web/worker.builder.web.test.ts +28 -28
- package/web/worker.config.web.test.ts +47 -47
- package/web/worker.output.web.test.ts +10 -10
- package/dist/types-KImPrEIe.d.cts +0 -48
- package/dist/types-KImPrEIe.d.ts +0 -48
package/permits/validation.ts
CHANGED
|
@@ -1,44 +1,48 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { isAddress, zeroAddress } from 'viem';
|
|
3
|
-
import {
|
|
4
|
-
import { is0xPrefixed } from './utils.js';
|
|
2
|
+
import { getAddress, isAddress, isHex, zeroAddress, type Hex } from 'viem';
|
|
3
|
+
import type { Permit, ValidationResult } from './types.js';
|
|
5
4
|
|
|
6
5
|
const SerializedSealingPair = z.object({
|
|
7
6
|
privateKey: z.string(),
|
|
8
7
|
publicKey: z.string(),
|
|
9
8
|
});
|
|
10
9
|
|
|
10
|
+
export const addressSchema = z
|
|
11
|
+
.string()
|
|
12
|
+
.refine((val) => isAddress(val), {
|
|
13
|
+
error: 'Invalid address',
|
|
14
|
+
})
|
|
15
|
+
.transform((val): Hex => getAddress(val));
|
|
16
|
+
|
|
17
|
+
export const addressNotZeroSchema = addressSchema.refine((val) => val !== zeroAddress, {
|
|
18
|
+
error: 'Must not be zeroAddress',
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
export const bytesSchema = z.custom<Hex>(
|
|
22
|
+
(val) => {
|
|
23
|
+
return typeof val === 'string' && isHex(val);
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
message: 'Invalid hex value',
|
|
27
|
+
}
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
export const bytesNotEmptySchema = bytesSchema.refine((val) => val !== '0x', {
|
|
31
|
+
error: 'Must not be empty',
|
|
32
|
+
});
|
|
33
|
+
|
|
11
34
|
const DEFAULT_EXPIRATION_FN = () => Math.round(Date.now() / 1000) + 7 * 24 * 60 * 60; // 7 days from now
|
|
12
35
|
|
|
13
36
|
const zPermitWithDefaults = z.object({
|
|
14
37
|
name: z.string().optional().default('Unnamed Permit'),
|
|
15
38
|
type: z.enum(['self', 'sharing', 'recipient']),
|
|
16
|
-
issuer:
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}),
|
|
24
|
-
expiration: z.number().optional().default(DEFAULT_EXPIRATION_FN),
|
|
25
|
-
recipient: z
|
|
26
|
-
.string()
|
|
27
|
-
.optional()
|
|
28
|
-
.default(zeroAddress)
|
|
29
|
-
.refine((val) => isAddress(val), {
|
|
30
|
-
message: 'Permit recipient :: invalid address',
|
|
31
|
-
}),
|
|
32
|
-
validatorId: z.number().optional().default(0),
|
|
33
|
-
validatorContract: z
|
|
34
|
-
.string()
|
|
35
|
-
.optional()
|
|
36
|
-
.default(zeroAddress)
|
|
37
|
-
.refine((val) => isAddress(val), {
|
|
38
|
-
message: 'Permit validatorContract :: invalid address',
|
|
39
|
-
}),
|
|
40
|
-
issuerSignature: z.string().optional().default('0x'),
|
|
41
|
-
recipientSignature: z.string().optional().default('0x'),
|
|
39
|
+
issuer: addressNotZeroSchema,
|
|
40
|
+
expiration: z.int().optional().default(DEFAULT_EXPIRATION_FN),
|
|
41
|
+
recipient: addressSchema.optional().default(zeroAddress),
|
|
42
|
+
validatorId: z.int().optional().default(0),
|
|
43
|
+
validatorContract: addressSchema.optional().default(zeroAddress),
|
|
44
|
+
issuerSignature: bytesSchema.optional().default('0x'),
|
|
45
|
+
recipientSignature: bytesSchema.optional().default('0x'),
|
|
42
46
|
});
|
|
43
47
|
|
|
44
48
|
const zPermitWithSealingPair = zPermitWithDefaults.extend({
|
|
@@ -52,16 +56,27 @@ type zPermitType = z.infer<typeof zPermitWithDefaults>;
|
|
|
52
56
|
* this check ensures that IF an external validator is applied, that both `validatorId` and `validatorContract` are populated,
|
|
53
57
|
* ELSE ensures that both `validatorId` and `validatorContract` are empty
|
|
54
58
|
*/
|
|
55
|
-
const
|
|
59
|
+
const ExternalValidatorRefinement = [
|
|
56
60
|
(data: zPermitType) =>
|
|
57
61
|
(data.validatorId !== 0 && data.validatorContract !== zeroAddress) ||
|
|
58
62
|
(data.validatorId === 0 && data.validatorContract === zeroAddress),
|
|
59
63
|
{
|
|
60
|
-
|
|
64
|
+
error: 'Permit external validator :: validatorId and validatorContract must either both be set or both be unset.',
|
|
61
65
|
path: ['validatorId', 'validatorContract'] as string[],
|
|
62
66
|
},
|
|
63
67
|
] as const;
|
|
64
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Prevents sharable permit from having the same issuer and recipient
|
|
71
|
+
*/
|
|
72
|
+
const RecipientRefinement = [
|
|
73
|
+
(data: zPermitType) => data.issuer !== data.recipient,
|
|
74
|
+
{
|
|
75
|
+
error: 'Sharing permit :: issuer and recipient must not be the same',
|
|
76
|
+
path: ['issuer', 'recipient'] as string[],
|
|
77
|
+
},
|
|
78
|
+
] as const;
|
|
79
|
+
|
|
65
80
|
// ============================================================================
|
|
66
81
|
// SELF PERMIT VALIDATORS
|
|
67
82
|
// ============================================================================
|
|
@@ -72,74 +87,34 @@ const ValidatorContractRefinement = [
|
|
|
72
87
|
export const SelfPermitOptionsValidator = z
|
|
73
88
|
.object({
|
|
74
89
|
type: z.literal('self').optional().default('self'),
|
|
75
|
-
issuer:
|
|
76
|
-
.string()
|
|
77
|
-
.refine((val) => isAddress(val), {
|
|
78
|
-
message: 'Self permit issuer :: invalid address',
|
|
79
|
-
})
|
|
80
|
-
.refine((val) => is0xPrefixed(val), {
|
|
81
|
-
message: 'Self permit issuer :: must be 0x prefixed',
|
|
82
|
-
})
|
|
83
|
-
.refine((val) => val !== zeroAddress, {
|
|
84
|
-
message: 'Self permit issuer :: must not be zeroAddress',
|
|
85
|
-
}),
|
|
90
|
+
issuer: addressNotZeroSchema,
|
|
86
91
|
name: z.string().optional().default('Unnamed Permit'),
|
|
87
|
-
expiration: z.
|
|
88
|
-
recipient:
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
message: 'Self permit recipient :: invalid address',
|
|
94
|
-
})
|
|
95
|
-
.refine((val) => is0xPrefixed(val), {
|
|
96
|
-
message: 'Self permit recipient :: must be 0x prefixed',
|
|
97
|
-
})
|
|
98
|
-
.refine((val) => val === zeroAddress, {
|
|
99
|
-
message: 'Self permit recipient :: must be zeroAddress',
|
|
100
|
-
}),
|
|
101
|
-
validatorId: z.number().optional().default(0),
|
|
102
|
-
validatorContract: z
|
|
103
|
-
.string()
|
|
104
|
-
.optional()
|
|
105
|
-
.default(zeroAddress)
|
|
106
|
-
.refine((val) => isAddress(val), {
|
|
107
|
-
message: 'Self permit validatorContract :: invalid address',
|
|
108
|
-
}),
|
|
109
|
-
issuerSignature: z
|
|
110
|
-
.string()
|
|
111
|
-
.optional()
|
|
112
|
-
.default('0x')
|
|
113
|
-
.refine((val) => is0xPrefixed(val), {
|
|
114
|
-
message: 'Self permit issuerSignature :: must be 0x prefixed',
|
|
115
|
-
}),
|
|
116
|
-
recipientSignature: z
|
|
117
|
-
.string()
|
|
118
|
-
.optional()
|
|
119
|
-
.default('0x')
|
|
120
|
-
.refine((val) => is0xPrefixed(val), {
|
|
121
|
-
message: 'Self permit recipientSignature :: must be 0x prefixed',
|
|
122
|
-
}),
|
|
92
|
+
expiration: z.int().optional().default(DEFAULT_EXPIRATION_FN),
|
|
93
|
+
recipient: addressSchema.optional().default(zeroAddress),
|
|
94
|
+
validatorId: z.int().optional().default(0),
|
|
95
|
+
validatorContract: addressSchema.optional().default(zeroAddress),
|
|
96
|
+
issuerSignature: bytesSchema.optional().default('0x'),
|
|
97
|
+
recipientSignature: bytesSchema.optional().default('0x'),
|
|
123
98
|
})
|
|
124
|
-
.refine(...
|
|
99
|
+
.refine(...ExternalValidatorRefinement);
|
|
125
100
|
|
|
126
101
|
/**
|
|
127
102
|
* Validator for fully formed self permits
|
|
128
103
|
*/
|
|
129
104
|
export const SelfPermitValidator = zPermitWithSealingPair
|
|
130
105
|
.refine((data) => data.type === 'self', {
|
|
131
|
-
|
|
106
|
+
error: "Type must be 'self'",
|
|
132
107
|
})
|
|
133
108
|
.refine((data) => data.recipient === zeroAddress, {
|
|
134
|
-
|
|
109
|
+
error: 'Recipient must be zeroAddress',
|
|
135
110
|
})
|
|
136
111
|
.refine((data) => data.issuerSignature !== '0x', {
|
|
137
|
-
|
|
112
|
+
error: 'IssuerSignature must be populated',
|
|
138
113
|
})
|
|
139
114
|
.refine((data) => data.recipientSignature === '0x', {
|
|
140
|
-
|
|
115
|
+
error: 'RecipientSignature must be empty',
|
|
141
116
|
})
|
|
142
|
-
.refine(...
|
|
117
|
+
.refine(...ExternalValidatorRefinement);
|
|
143
118
|
|
|
144
119
|
// ============================================================================
|
|
145
120
|
// SHARING PERMIT VALIDATORS
|
|
@@ -151,72 +126,35 @@ export const SelfPermitValidator = zPermitWithSealingPair
|
|
|
151
126
|
export const SharingPermitOptionsValidator = z
|
|
152
127
|
.object({
|
|
153
128
|
type: z.literal('sharing').optional().default('sharing'),
|
|
154
|
-
issuer:
|
|
155
|
-
|
|
156
|
-
.refine((val) => isAddress(val), {
|
|
157
|
-
message: 'Sharing permit issuer :: invalid address',
|
|
158
|
-
})
|
|
159
|
-
.refine((val) => is0xPrefixed(val), {
|
|
160
|
-
message: 'Sharing permit issuer :: must be 0x prefixed',
|
|
161
|
-
})
|
|
162
|
-
.refine((val) => val !== zeroAddress, {
|
|
163
|
-
message: 'Sharing permit issuer :: must not be zeroAddress',
|
|
164
|
-
}),
|
|
165
|
-
recipient: z
|
|
166
|
-
.string()
|
|
167
|
-
.refine((val) => isAddress(val), {
|
|
168
|
-
message: 'Sharing permit recipient :: invalid address',
|
|
169
|
-
})
|
|
170
|
-
.refine((val) => is0xPrefixed(val), {
|
|
171
|
-
message: 'Sharing permit recipient :: must be 0x prefixed',
|
|
172
|
-
})
|
|
173
|
-
.refine((val) => val !== zeroAddress, {
|
|
174
|
-
message: 'Sharing permit recipient :: must not be zeroAddress',
|
|
175
|
-
}),
|
|
129
|
+
issuer: addressNotZeroSchema,
|
|
130
|
+
recipient: addressNotZeroSchema,
|
|
176
131
|
name: z.string().optional().default('Unnamed Permit'),
|
|
177
|
-
expiration: z.
|
|
178
|
-
validatorId: z.
|
|
179
|
-
validatorContract:
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
.default(zeroAddress)
|
|
183
|
-
.refine((val) => isAddress(val), {
|
|
184
|
-
message: 'Sharing permit validatorContract :: invalid address',
|
|
185
|
-
}),
|
|
186
|
-
issuerSignature: z
|
|
187
|
-
.string()
|
|
188
|
-
.optional()
|
|
189
|
-
.default('0x')
|
|
190
|
-
.refine((val) => is0xPrefixed(val), {
|
|
191
|
-
message: 'Sharing permit issuerSignature :: must be 0x prefixed',
|
|
192
|
-
}),
|
|
193
|
-
recipientSignature: z
|
|
194
|
-
.string()
|
|
195
|
-
.optional()
|
|
196
|
-
.default('0x')
|
|
197
|
-
.refine((val) => is0xPrefixed(val), {
|
|
198
|
-
message: 'Sharing permit recipientSignature :: must be 0x prefixed',
|
|
199
|
-
}),
|
|
132
|
+
expiration: z.int().optional().default(DEFAULT_EXPIRATION_FN),
|
|
133
|
+
validatorId: z.int().optional().default(0),
|
|
134
|
+
validatorContract: addressSchema.optional().default(zeroAddress),
|
|
135
|
+
issuerSignature: bytesSchema.optional().default('0x'),
|
|
136
|
+
recipientSignature: bytesSchema.optional().default('0x'),
|
|
200
137
|
})
|
|
201
|
-
.refine(...
|
|
138
|
+
.refine(...RecipientRefinement)
|
|
139
|
+
.refine(...ExternalValidatorRefinement);
|
|
202
140
|
|
|
203
141
|
/**
|
|
204
142
|
* Validator for fully formed sharing permits
|
|
205
143
|
*/
|
|
206
144
|
export const SharingPermitValidator = zPermitWithSealingPair
|
|
207
145
|
.refine((data) => data.type === 'sharing', {
|
|
208
|
-
|
|
146
|
+
error: "Type must be 'sharing'",
|
|
209
147
|
})
|
|
210
148
|
.refine((data) => data.recipient !== zeroAddress, {
|
|
211
|
-
|
|
149
|
+
error: 'Recipient must not be zeroAddress',
|
|
212
150
|
})
|
|
213
151
|
.refine((data) => data.issuerSignature !== '0x', {
|
|
214
|
-
|
|
152
|
+
error: 'IssuerSignature must be populated',
|
|
215
153
|
})
|
|
216
154
|
.refine((data) => data.recipientSignature === '0x', {
|
|
217
|
-
|
|
155
|
+
error: 'RecipientSignature must be empty',
|
|
218
156
|
})
|
|
219
|
-
.refine(...
|
|
157
|
+
.refine(...ExternalValidatorRefinement);
|
|
220
158
|
|
|
221
159
|
// ============================================================================
|
|
222
160
|
// IMPORT/RECIPIENT PERMIT VALIDATORS
|
|
@@ -228,107 +166,87 @@ export const SharingPermitValidator = zPermitWithSealingPair
|
|
|
228
166
|
export const ImportPermitOptionsValidator = z
|
|
229
167
|
.object({
|
|
230
168
|
type: z.literal('recipient').optional().default('recipient'),
|
|
231
|
-
issuer:
|
|
232
|
-
|
|
233
|
-
.refine((val) => isAddress(val), {
|
|
234
|
-
message: 'Import permit issuer :: invalid address',
|
|
235
|
-
})
|
|
236
|
-
.refine((val) => is0xPrefixed(val), {
|
|
237
|
-
message: 'Import permit issuer :: must be 0x prefixed',
|
|
238
|
-
})
|
|
239
|
-
.refine((val) => val !== zeroAddress, {
|
|
240
|
-
message: 'Import permit issuer :: must not be zeroAddress',
|
|
241
|
-
}),
|
|
242
|
-
recipient: z
|
|
243
|
-
.string()
|
|
244
|
-
.refine((val) => isAddress(val), {
|
|
245
|
-
message: 'Import permit recipient :: invalid address',
|
|
246
|
-
})
|
|
247
|
-
.refine((val) => is0xPrefixed(val), {
|
|
248
|
-
message: 'Import permit recipient :: must be 0x prefixed',
|
|
249
|
-
})
|
|
250
|
-
.refine((val) => val !== zeroAddress, {
|
|
251
|
-
message: 'Import permit recipient :: must not be zeroAddress',
|
|
252
|
-
}),
|
|
253
|
-
issuerSignature: z
|
|
254
|
-
.string()
|
|
255
|
-
.refine((val) => is0xPrefixed(val), {
|
|
256
|
-
message: 'Import permit issuerSignature :: must be 0x prefixed',
|
|
257
|
-
})
|
|
258
|
-
.refine((val) => val !== '0x', {
|
|
259
|
-
message: 'Import permit :: issuerSignature must be provided',
|
|
260
|
-
}),
|
|
169
|
+
issuer: addressNotZeroSchema,
|
|
170
|
+
recipient: addressNotZeroSchema,
|
|
261
171
|
name: z.string().optional().default('Unnamed Permit'),
|
|
262
|
-
expiration: z.
|
|
263
|
-
validatorId: z.
|
|
264
|
-
validatorContract:
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
.default(zeroAddress)
|
|
268
|
-
.refine((val) => isAddress(val), {
|
|
269
|
-
message: 'Import permit validatorContract :: invalid address',
|
|
270
|
-
}),
|
|
271
|
-
recipientSignature: z
|
|
272
|
-
.string()
|
|
273
|
-
.optional()
|
|
274
|
-
.default('0x')
|
|
275
|
-
.refine((val) => is0xPrefixed(val), {
|
|
276
|
-
message: 'Import permit recipientSignature :: must be 0x prefixed',
|
|
277
|
-
}),
|
|
172
|
+
expiration: z.int(),
|
|
173
|
+
validatorId: z.int().optional().default(0),
|
|
174
|
+
validatorContract: addressSchema.optional().default(zeroAddress),
|
|
175
|
+
issuerSignature: bytesNotEmptySchema,
|
|
176
|
+
recipientSignature: bytesSchema.optional().default('0x'),
|
|
278
177
|
})
|
|
279
|
-
.refine(...
|
|
178
|
+
.refine(...ExternalValidatorRefinement);
|
|
280
179
|
|
|
281
180
|
/**
|
|
282
181
|
* Validator for fully formed import/recipient permits
|
|
283
182
|
*/
|
|
284
183
|
export const ImportPermitValidator = zPermitWithSealingPair
|
|
285
184
|
.refine((data) => data.type === 'recipient', {
|
|
286
|
-
|
|
185
|
+
error: "Type must be 'recipient'",
|
|
287
186
|
})
|
|
288
187
|
.refine((data) => data.recipient !== zeroAddress, {
|
|
289
|
-
|
|
188
|
+
error: 'Recipient must not be zeroAddress',
|
|
290
189
|
})
|
|
291
190
|
.refine((data) => data.issuerSignature !== '0x', {
|
|
292
|
-
|
|
191
|
+
error: 'IssuerSignature must be populated',
|
|
293
192
|
})
|
|
294
193
|
.refine((data) => data.recipientSignature !== '0x', {
|
|
295
|
-
|
|
194
|
+
error: 'RecipientSignature must be populated',
|
|
296
195
|
})
|
|
297
|
-
.refine(...
|
|
196
|
+
.refine(...ExternalValidatorRefinement);
|
|
298
197
|
|
|
299
198
|
// ============================================================================
|
|
300
199
|
// VALIDATION FUNCTIONS
|
|
301
200
|
// ============================================================================
|
|
302
201
|
|
|
202
|
+
const safeParseAndThrowFormatted = <T extends z.ZodTypeAny>(schema: T, data: unknown, message: string): z.output<T> => {
|
|
203
|
+
const result = schema.safeParse(data);
|
|
204
|
+
if (!result.success) {
|
|
205
|
+
throw new Error(`${message}: ${z.prettifyError(result.error)}`, { cause: result.error });
|
|
206
|
+
}
|
|
207
|
+
return result.data;
|
|
208
|
+
};
|
|
209
|
+
|
|
303
210
|
/**
|
|
304
211
|
* Validates self permit creation options
|
|
305
212
|
*/
|
|
306
|
-
export const validateSelfPermitOptions = (options: any) =>
|
|
307
|
-
|
|
213
|
+
export const validateSelfPermitOptions = (options: any) => {
|
|
214
|
+
return safeParseAndThrowFormatted(SelfPermitOptionsValidator, options, 'Invalid self permit options');
|
|
215
|
+
};
|
|
308
216
|
/**
|
|
309
217
|
* Validates sharing permit creation options
|
|
310
218
|
*/
|
|
311
|
-
export const validateSharingPermitOptions = (options: any) =>
|
|
219
|
+
export const validateSharingPermitOptions = (options: any) => {
|
|
220
|
+
return safeParseAndThrowFormatted(SharingPermitOptionsValidator, options, 'Invalid sharing permit options');
|
|
221
|
+
};
|
|
312
222
|
|
|
313
223
|
/**
|
|
314
224
|
* Validates import permit creation options
|
|
315
225
|
*/
|
|
316
|
-
export const validateImportPermitOptions = (options: any) =>
|
|
226
|
+
export const validateImportPermitOptions = (options: any) => {
|
|
227
|
+
return safeParseAndThrowFormatted(ImportPermitOptionsValidator, options, 'Invalid import permit options');
|
|
228
|
+
};
|
|
317
229
|
|
|
318
230
|
/**
|
|
319
231
|
* Validates a fully formed self permit
|
|
320
232
|
*/
|
|
321
|
-
export const validateSelfPermit = (permit: any) =>
|
|
233
|
+
export const validateSelfPermit = (permit: any) => {
|
|
234
|
+
return safeParseAndThrowFormatted(SelfPermitValidator, permit, 'Invalid self permit');
|
|
235
|
+
};
|
|
322
236
|
|
|
323
237
|
/**
|
|
324
238
|
* Validates a fully formed sharing permit
|
|
325
239
|
*/
|
|
326
|
-
export const validateSharingPermit = (permit: any) =>
|
|
240
|
+
export const validateSharingPermit = (permit: any) => {
|
|
241
|
+
return safeParseAndThrowFormatted(SharingPermitValidator, permit, 'Invalid sharing permit');
|
|
242
|
+
};
|
|
327
243
|
|
|
328
244
|
/**
|
|
329
245
|
* Validates a fully formed import/recipient permit
|
|
330
246
|
*/
|
|
331
|
-
export const validateImportPermit = (permit: any) =>
|
|
247
|
+
export const validateImportPermit = (permit: any) => {
|
|
248
|
+
return safeParseAndThrowFormatted(ImportPermitValidator, permit, 'Invalid import permit');
|
|
249
|
+
};
|
|
332
250
|
|
|
333
251
|
/**
|
|
334
252
|
* Simple validation functions for common checks
|
package/web/client.web.test.ts
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { arbSepolia as
|
|
1
|
+
import { CofheErrorCode, CofheError, type CofheClient } from '@/core';
|
|
2
|
+
import { arbSepolia as cofheArbSepolia } from '@/chains';
|
|
3
3
|
|
|
4
4
|
import { describe, it, expect, beforeAll, beforeEach, vi } from 'vitest';
|
|
5
5
|
import { arbitrumSepolia as viemArbitrumSepolia } from 'viem/chains';
|
|
6
6
|
import type { PublicClient, WalletClient } from 'viem';
|
|
7
7
|
import { createPublicClient, createWalletClient, http } from 'viem';
|
|
8
8
|
import { privateKeyToAccount } from 'viem/accounts';
|
|
9
|
-
import {
|
|
9
|
+
import { createCofheClient, createCofheConfig } from './index.js';
|
|
10
10
|
|
|
11
11
|
// Real test setup - runs in browser
|
|
12
12
|
const TEST_PRIVATE_KEY = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80';
|
|
13
13
|
const TEST_ACCOUNT = privateKeyToAccount(TEST_PRIVATE_KEY).address;
|
|
14
14
|
|
|
15
15
|
describe('@cofhe/web - Client', () => {
|
|
16
|
-
let
|
|
16
|
+
let cofheClient: CofheClient;
|
|
17
17
|
let publicClient: PublicClient;
|
|
18
18
|
let walletClient: WalletClient;
|
|
19
19
|
|
|
@@ -33,62 +33,62 @@ describe('@cofhe/web - Client', () => {
|
|
|
33
33
|
});
|
|
34
34
|
|
|
35
35
|
beforeEach(() => {
|
|
36
|
-
const config =
|
|
37
|
-
supportedChains: [
|
|
36
|
+
const config = createCofheConfig({
|
|
37
|
+
supportedChains: [cofheArbSepolia],
|
|
38
38
|
});
|
|
39
|
-
|
|
39
|
+
cofheClient = createCofheClient(config);
|
|
40
40
|
});
|
|
41
41
|
|
|
42
42
|
describe('Browser Client Initialization', () => {
|
|
43
43
|
it('should create a client with real tfhe for browser', () => {
|
|
44
|
-
expect(
|
|
45
|
-
expect(
|
|
46
|
-
expect(
|
|
44
|
+
expect(cofheClient).toBeDefined();
|
|
45
|
+
expect(cofheClient.config).toBeDefined();
|
|
46
|
+
expect(cofheClient.connected).toBe(false);
|
|
47
47
|
});
|
|
48
48
|
|
|
49
49
|
it('should automatically use IndexedDB storage as default', () => {
|
|
50
|
-
expect(
|
|
51
|
-
expect(
|
|
50
|
+
expect(cofheClient.config.fheKeyStorage).toBeDefined();
|
|
51
|
+
expect(cofheClient.config.fheKeyStorage).not.toBeNull();
|
|
52
52
|
});
|
|
53
53
|
|
|
54
54
|
it('should have all expected methods', () => {
|
|
55
|
-
expect(typeof
|
|
56
|
-
expect(typeof
|
|
57
|
-
expect(typeof
|
|
58
|
-
expect(typeof
|
|
59
|
-
expect(typeof
|
|
55
|
+
expect(typeof cofheClient.connect).toBe('function');
|
|
56
|
+
expect(typeof cofheClient.encryptInputs).toBe('function');
|
|
57
|
+
expect(typeof cofheClient.decryptForView).toBe('function');
|
|
58
|
+
expect(typeof cofheClient.getSnapshot).toBe('function');
|
|
59
|
+
expect(typeof cofheClient.subscribe).toBe('function');
|
|
60
60
|
});
|
|
61
61
|
});
|
|
62
62
|
|
|
63
63
|
describe('Environment', () => {
|
|
64
64
|
it('should have the correct environment', () => {
|
|
65
|
-
expect(
|
|
65
|
+
expect(cofheClient.config.environment).toBe('web');
|
|
66
66
|
});
|
|
67
67
|
});
|
|
68
68
|
|
|
69
69
|
describe('Connection', () => {
|
|
70
70
|
it('should connect to real chain', async () => {
|
|
71
|
-
await
|
|
71
|
+
await cofheClient.connect(publicClient, walletClient);
|
|
72
72
|
|
|
73
|
-
expect(
|
|
73
|
+
expect(cofheClient.connected).toBe(true);
|
|
74
74
|
|
|
75
|
-
const snapshot =
|
|
75
|
+
const snapshot = cofheClient.getSnapshot();
|
|
76
76
|
expect(snapshot.connected).toBe(true);
|
|
77
|
-
expect(snapshot.chainId).toBe(
|
|
77
|
+
expect(snapshot.chainId).toBe(cofheArbSepolia.id);
|
|
78
78
|
expect(snapshot.account).toBe(TEST_ACCOUNT);
|
|
79
79
|
}, 30000);
|
|
80
80
|
|
|
81
81
|
it('should handle network errors', async () => {
|
|
82
82
|
try {
|
|
83
|
-
await
|
|
83
|
+
await cofheClient.connect(
|
|
84
84
|
{
|
|
85
85
|
getChainId: vi.fn().mockRejectedValue(new Error('Network error')),
|
|
86
86
|
} as unknown as PublicClient,
|
|
87
87
|
walletClient
|
|
88
88
|
);
|
|
89
89
|
} catch (error) {
|
|
90
|
-
expect(error).toBeInstanceOf(
|
|
91
|
-
expect((error as
|
|
90
|
+
expect(error).toBeInstanceOf(CofheError);
|
|
91
|
+
expect((error as CofheError).code).toBe(CofheErrorCode.PublicWalletGetChainIdFailed);
|
|
92
92
|
}
|
|
93
93
|
}, 30000);
|
|
94
94
|
});
|
|
@@ -96,11 +96,11 @@ describe('@cofhe/web - Client', () => {
|
|
|
96
96
|
describe('State Management', () => {
|
|
97
97
|
it('should track connection state changes', async () => {
|
|
98
98
|
const states: any[] = [];
|
|
99
|
-
const unsubscribe =
|
|
99
|
+
const unsubscribe = cofheClient.subscribe((snapshot) => {
|
|
100
100
|
states.push({ ...snapshot });
|
|
101
101
|
});
|
|
102
102
|
|
|
103
|
-
await
|
|
103
|
+
await cofheClient.connect(publicClient, walletClient);
|
|
104
104
|
|
|
105
105
|
unsubscribe();
|
|
106
106
|
|
|
@@ -116,32 +116,32 @@ describe('@cofhe/web - Client', () => {
|
|
|
116
116
|
const lastState = states[states.length - 1];
|
|
117
117
|
expect(lastState.connected).toBe(true);
|
|
118
118
|
expect(lastState.connecting).toBe(false);
|
|
119
|
-
expect(lastState.chainId).toBe(
|
|
119
|
+
expect(lastState.chainId).toBe(cofheArbSepolia.id);
|
|
120
120
|
}, 30000);
|
|
121
121
|
});
|
|
122
122
|
|
|
123
123
|
describe('Builder Creation', () => {
|
|
124
124
|
it('should create encrypt builder after connection', async () => {
|
|
125
|
-
await
|
|
125
|
+
await cofheClient.connect(publicClient, walletClient);
|
|
126
126
|
|
|
127
|
-
const builder =
|
|
127
|
+
const builder = cofheClient.encryptInputs([{ data: 100n, utype: 2, securityZone: 0 }]);
|
|
128
128
|
|
|
129
129
|
expect(builder).toBeDefined();
|
|
130
130
|
expect(typeof builder.setChainId).toBe('function');
|
|
131
131
|
expect(typeof builder.setAccount).toBe('function');
|
|
132
132
|
expect(typeof builder.setSecurityZone).toBe('function');
|
|
133
|
-
expect(typeof builder.
|
|
133
|
+
expect(typeof builder.execute).toBe('function');
|
|
134
134
|
}, 30000);
|
|
135
135
|
|
|
136
136
|
it('should create decrypt builder after connection', async () => {
|
|
137
|
-
await
|
|
137
|
+
await cofheClient.connect(publicClient, walletClient);
|
|
138
138
|
|
|
139
|
-
const builder =
|
|
139
|
+
const builder = cofheClient.decryptForView(123n, 2);
|
|
140
140
|
|
|
141
141
|
expect(builder).toBeDefined();
|
|
142
142
|
expect(typeof builder.setChainId).toBe('function');
|
|
143
143
|
expect(typeof builder.setAccount).toBe('function');
|
|
144
|
-
expect(typeof builder.
|
|
144
|
+
expect(typeof builder.execute).toBe('function');
|
|
145
145
|
}, 30000);
|
|
146
146
|
});
|
|
147
147
|
});
|
package/web/config.web.test.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { arbSepolia } from '@/chains';
|
|
2
2
|
|
|
3
3
|
import { describe, it, expect } from 'vitest';
|
|
4
|
-
import {
|
|
4
|
+
import { createCofheConfig, createCofheClient } from './index.js';
|
|
5
5
|
|
|
6
6
|
describe('@cofhe/web - Config', () => {
|
|
7
|
-
describe('
|
|
7
|
+
describe('createCofheConfig', () => {
|
|
8
8
|
it('should automatically inject IndexedDB storage as default', () => {
|
|
9
|
-
const config =
|
|
9
|
+
const config = createCofheConfig({
|
|
10
10
|
supportedChains: [arbSepolia],
|
|
11
11
|
});
|
|
12
12
|
|
|
@@ -22,7 +22,7 @@ describe('@cofhe/web - Config', () => {
|
|
|
22
22
|
removeItem: () => Promise.resolve(),
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
-
const config =
|
|
25
|
+
const config = createCofheConfig({
|
|
26
26
|
supportedChains: [arbSepolia],
|
|
27
27
|
fheKeyStorage: customStorage,
|
|
28
28
|
});
|
|
@@ -31,7 +31,7 @@ describe('@cofhe/web - Config', () => {
|
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
it('should allow null storage', () => {
|
|
34
|
-
const config =
|
|
34
|
+
const config = createCofheConfig({
|
|
35
35
|
supportedChains: [arbSepolia],
|
|
36
36
|
fheKeyStorage: null,
|
|
37
37
|
});
|
|
@@ -40,26 +40,26 @@ describe('@cofhe/web - Config', () => {
|
|
|
40
40
|
});
|
|
41
41
|
|
|
42
42
|
it('should preserve all other config options', () => {
|
|
43
|
-
const config =
|
|
43
|
+
const config = createCofheConfig({
|
|
44
44
|
supportedChains: [arbSepolia],
|
|
45
45
|
mocks: {
|
|
46
|
-
|
|
46
|
+
decryptDelay: 500,
|
|
47
47
|
},
|
|
48
48
|
});
|
|
49
49
|
|
|
50
50
|
expect(config.supportedChains).toEqual([arbSepolia]);
|
|
51
|
-
expect(config.mocks.
|
|
51
|
+
expect(config.mocks.decryptDelay).toBe(500);
|
|
52
52
|
expect(config.fheKeyStorage).toBeDefined();
|
|
53
53
|
});
|
|
54
54
|
});
|
|
55
55
|
|
|
56
|
-
describe('
|
|
56
|
+
describe('createCofheClient with config', () => {
|
|
57
57
|
it('should create client with validated config', () => {
|
|
58
|
-
const config =
|
|
58
|
+
const config = createCofheConfig({
|
|
59
59
|
supportedChains: [arbSepolia],
|
|
60
60
|
});
|
|
61
61
|
|
|
62
|
-
const client =
|
|
62
|
+
const client = createCofheClient(config);
|
|
63
63
|
|
|
64
64
|
expect(client).toBeDefined();
|
|
65
65
|
expect(client.config).toBe(config);
|