@cofhe/sdk 0.0.0-alpha-20260409113701
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 +146 -0
- package/adapters/ethers5.test.ts +174 -0
- package/adapters/ethers5.ts +36 -0
- package/adapters/ethers6.test.ts +169 -0
- package/adapters/ethers6.ts +36 -0
- package/adapters/hardhat-node.ts +167 -0
- package/adapters/hardhat.hh2.test.ts +159 -0
- package/adapters/hardhat.ts +36 -0
- package/adapters/index.test.ts +20 -0
- package/adapters/index.ts +5 -0
- package/adapters/smartWallet.ts +99 -0
- package/adapters/test-utils.ts +53 -0
- package/adapters/types.ts +6 -0
- package/adapters/wagmi.test.ts +156 -0
- package/adapters/wagmi.ts +17 -0
- package/chains/chains/arbSepolia.ts +14 -0
- package/chains/chains/baseSepolia.ts +14 -0
- package/chains/chains/hardhat.ts +15 -0
- package/chains/chains/localcofhe.ts +14 -0
- package/chains/chains/sepolia.ts +14 -0
- package/chains/chains.test.ts +50 -0
- package/chains/defineChain.ts +18 -0
- package/chains/index.ts +35 -0
- package/chains/types.ts +32 -0
- package/core/baseBuilder.ts +119 -0
- package/core/client.test.ts +429 -0
- package/core/client.ts +341 -0
- package/core/clientTypes.ts +119 -0
- package/core/config.test.ts +242 -0
- package/core/config.ts +225 -0
- package/core/consts.ts +22 -0
- package/core/decrypt/MockThresholdNetworkAbi.ts +179 -0
- package/core/decrypt/cofheMocksDecryptForTx.ts +84 -0
- package/core/decrypt/cofheMocksDecryptForView.ts +48 -0
- package/core/decrypt/decryptForTxBuilder.ts +359 -0
- package/core/decrypt/decryptForViewBuilder.ts +332 -0
- package/core/decrypt/decryptUtils.ts +28 -0
- package/core/decrypt/pollCallbacks.test.ts +194 -0
- package/core/decrypt/polling.ts +14 -0
- package/core/decrypt/tnDecryptUtils.ts +65 -0
- package/core/decrypt/tnDecryptV1.ts +171 -0
- package/core/decrypt/tnDecryptV2.ts +365 -0
- package/core/decrypt/tnSealOutputV1.ts +59 -0
- package/core/decrypt/tnSealOutputV2.ts +324 -0
- package/core/decrypt/verifyDecryptResult.ts +52 -0
- package/core/encrypt/MockZkVerifierAbi.ts +106 -0
- package/core/encrypt/cofheMocksZkVerifySign.ts +281 -0
- package/core/encrypt/encryptInputsBuilder.test.ts +747 -0
- package/core/encrypt/encryptInputsBuilder.ts +583 -0
- package/core/encrypt/encryptUtils.ts +67 -0
- package/core/encrypt/zkPackProveVerify.ts +335 -0
- package/core/error.ts +168 -0
- package/core/fetchKeys.test.ts +195 -0
- package/core/fetchKeys.ts +144 -0
- package/core/index.ts +106 -0
- package/core/keyStore.test.ts +226 -0
- package/core/keyStore.ts +154 -0
- package/core/permits.test.ts +493 -0
- package/core/permits.ts +201 -0
- package/core/types.ts +419 -0
- package/core/utils.ts +130 -0
- package/dist/adapters.cjs +88 -0
- package/dist/adapters.d.cts +14576 -0
- package/dist/adapters.d.ts +14576 -0
- package/dist/adapters.js +83 -0
- package/dist/chains.cjs +111 -0
- package/dist/chains.d.cts +121 -0
- package/dist/chains.d.ts +121 -0
- package/dist/chains.js +1 -0
- package/dist/chunk-36FBWLUS.js +3310 -0
- package/dist/chunk-7HLGHV67.js +990 -0
- package/dist/chunk-TBLR7NNE.js +102 -0
- package/dist/clientTypes-AVSCBet7.d.cts +998 -0
- package/dist/clientTypes-flH1ju82.d.ts +998 -0
- package/dist/core.cjs +4362 -0
- package/dist/core.d.cts +138 -0
- package/dist/core.d.ts +138 -0
- package/dist/core.js +3 -0
- package/dist/node.cjs +4225 -0
- package/dist/node.d.cts +22 -0
- package/dist/node.d.ts +22 -0
- package/dist/node.js +91 -0
- package/dist/permit-jRirYqFt.d.cts +376 -0
- package/dist/permit-jRirYqFt.d.ts +376 -0
- package/dist/permits.cjs +1025 -0
- package/dist/permits.d.cts +353 -0
- package/dist/permits.d.ts +353 -0
- package/dist/permits.js +1 -0
- package/dist/types-YiAC4gig.d.cts +33 -0
- package/dist/types-YiAC4gig.d.ts +33 -0
- package/dist/web.cjs +4434 -0
- package/dist/web.d.cts +42 -0
- package/dist/web.d.ts +42 -0
- package/dist/web.js +256 -0
- 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 +159 -0
- package/node/config.test.ts +68 -0
- package/node/encryptInputs.test.ts +155 -0
- package/node/index.ts +97 -0
- package/node/storage.ts +51 -0
- package/package.json +121 -0
- package/permits/index.ts +68 -0
- package/permits/localstorage.test.ts +113 -0
- package/permits/onchain-utils.ts +221 -0
- package/permits/permit.test.ts +534 -0
- package/permits/permit.ts +386 -0
- package/permits/sealing.test.ts +84 -0
- package/permits/sealing.ts +131 -0
- package/permits/signature.ts +79 -0
- package/permits/store.test.ts +88 -0
- package/permits/store.ts +156 -0
- package/permits/test-utils.ts +28 -0
- package/permits/types.ts +204 -0
- package/permits/utils.ts +58 -0
- package/permits/validation.test.ts +361 -0
- package/permits/validation.ts +327 -0
- package/web/client.web.test.ts +159 -0
- package/web/config.web.test.ts +69 -0
- package/web/const.ts +2 -0
- package/web/encryptInputs.web.test.ts +172 -0
- package/web/index.ts +166 -0
- package/web/storage.ts +49 -0
- 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
|
@@ -0,0 +1,990 @@
|
|
|
1
|
+
import { isAddress, getAddress, zeroAddress, isHex, keccak256, toHex, parseAbi, BaseError, ContractFunctionRevertedError, decodeErrorResult } from 'viem';
|
|
2
|
+
import nacl from 'tweetnacl';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { createStore } from 'zustand/vanilla';
|
|
5
|
+
import { persist } from 'zustand/middleware';
|
|
6
|
+
import { produce } from 'immer';
|
|
7
|
+
|
|
8
|
+
// permits/permit.ts
|
|
9
|
+
|
|
10
|
+
// permits/utils.ts
|
|
11
|
+
var fromHexString = (hexString) => {
|
|
12
|
+
const cleanString = hexString.length % 2 === 1 ? `0${hexString}` : hexString;
|
|
13
|
+
const arr = cleanString.replace(/^0x/, "").match(/.{1,2}/g);
|
|
14
|
+
if (!arr)
|
|
15
|
+
return new Uint8Array();
|
|
16
|
+
return new Uint8Array(arr.map((byte) => parseInt(byte, 16)));
|
|
17
|
+
};
|
|
18
|
+
var toHexString = (bytes) => bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, "0"), "");
|
|
19
|
+
function toBigInt(value) {
|
|
20
|
+
if (typeof value === "string") {
|
|
21
|
+
return BigInt(value);
|
|
22
|
+
} else if (typeof value === "number") {
|
|
23
|
+
return BigInt(value);
|
|
24
|
+
} else if (typeof value === "object") {
|
|
25
|
+
return BigInt("0x" + toHexString(value));
|
|
26
|
+
} else {
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function toBeArray(value) {
|
|
31
|
+
const bigIntValue = typeof value === "number" ? BigInt(value) : value;
|
|
32
|
+
const hex = bigIntValue.toString(16);
|
|
33
|
+
const paddedHex = hex.length % 2 === 0 ? hex : "0" + hex;
|
|
34
|
+
return fromHexString(paddedHex);
|
|
35
|
+
}
|
|
36
|
+
function isString(value) {
|
|
37
|
+
if (typeof value !== "string") {
|
|
38
|
+
throw new Error(`Expected value which is \`string\`, received value of type \`${typeof value}\`.`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function isNumber(value) {
|
|
42
|
+
const is = typeof value === "number" && !Number.isNaN(value);
|
|
43
|
+
if (!is) {
|
|
44
|
+
throw new Error(`Expected value which is \`number\`, received value of type \`${typeof value}\`.`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function isBigIntOrNumber(value) {
|
|
48
|
+
const is = typeof value === "bigint";
|
|
49
|
+
if (!is) {
|
|
50
|
+
try {
|
|
51
|
+
isNumber(value);
|
|
52
|
+
} catch (e) {
|
|
53
|
+
throw new Error(`Value ${value} is not a number or bigint: ${typeof value}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// permits/sealing.ts
|
|
59
|
+
var PRIVATE_KEY_LENGTH = 64;
|
|
60
|
+
var PUBLIC_KEY_LENGTH = 64;
|
|
61
|
+
var SealingKey = class _SealingKey {
|
|
62
|
+
/**
|
|
63
|
+
* The private key used for decryption.
|
|
64
|
+
*/
|
|
65
|
+
privateKey;
|
|
66
|
+
/**
|
|
67
|
+
* The public key used for encryption.
|
|
68
|
+
*/
|
|
69
|
+
publicKey;
|
|
70
|
+
/**
|
|
71
|
+
* Constructs a SealingKey instance with the given private and public keys.
|
|
72
|
+
*
|
|
73
|
+
* @param {string} privateKey - The private key used for decryption.
|
|
74
|
+
* @param {string} publicKey - The public key used for encryption.
|
|
75
|
+
* @throws Will throw an error if the provided keys lengths do not match
|
|
76
|
+
* the required lengths for private and public keys.
|
|
77
|
+
*/
|
|
78
|
+
constructor(privateKey, publicKey) {
|
|
79
|
+
if (privateKey.length !== PRIVATE_KEY_LENGTH) {
|
|
80
|
+
throw new Error(`Private key must be of length ${PRIVATE_KEY_LENGTH}`);
|
|
81
|
+
}
|
|
82
|
+
if (publicKey.length !== PUBLIC_KEY_LENGTH) {
|
|
83
|
+
throw new Error(`Public key must be of length ${PUBLIC_KEY_LENGTH}`);
|
|
84
|
+
}
|
|
85
|
+
this.privateKey = privateKey;
|
|
86
|
+
this.publicKey = publicKey;
|
|
87
|
+
}
|
|
88
|
+
unseal = (parsedData) => {
|
|
89
|
+
const nonce = parsedData.nonce instanceof Uint8Array ? parsedData.nonce : new Uint8Array(parsedData.nonce);
|
|
90
|
+
const ephemPublicKey = parsedData.public_key instanceof Uint8Array ? parsedData.public_key : new Uint8Array(parsedData.public_key);
|
|
91
|
+
const dataToDecrypt = parsedData.data instanceof Uint8Array ? parsedData.data : new Uint8Array(parsedData.data);
|
|
92
|
+
const privateKeyBytes = fromHexString(this.privateKey);
|
|
93
|
+
const decryptedMessage = nacl.box.open(dataToDecrypt, nonce, ephemPublicKey, privateKeyBytes);
|
|
94
|
+
if (!decryptedMessage) {
|
|
95
|
+
throw new Error("Failed to decrypt message");
|
|
96
|
+
}
|
|
97
|
+
return toBigInt(decryptedMessage);
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Serializes the SealingKey to a JSON object.
|
|
101
|
+
*/
|
|
102
|
+
serialize = () => {
|
|
103
|
+
return {
|
|
104
|
+
privateKey: this.privateKey,
|
|
105
|
+
publicKey: this.publicKey
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Deserializes the SealingKey from a JSON object.
|
|
110
|
+
*/
|
|
111
|
+
static deserialize = (privateKey, publicKey) => {
|
|
112
|
+
return new _SealingKey(privateKey, publicKey);
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* Seals (encrypts) the provided message for a receiver with the specified public key.
|
|
116
|
+
*
|
|
117
|
+
* @param {bigint | number} value - The message to be encrypted.
|
|
118
|
+
* @param {string} publicKey - The public key of the intended recipient.
|
|
119
|
+
* @returns string - The encrypted message in hexadecimal format.
|
|
120
|
+
* @static
|
|
121
|
+
* @throws Will throw if the provided publicKey or value do not meet defined preconditions.
|
|
122
|
+
*/
|
|
123
|
+
static seal = (value, publicKey) => {
|
|
124
|
+
isString(publicKey);
|
|
125
|
+
isBigIntOrNumber(value);
|
|
126
|
+
const ephemeralKeyPair = nacl.box.keyPair();
|
|
127
|
+
const nonce = nacl.randomBytes(nacl.box.nonceLength);
|
|
128
|
+
const encryptedMessage = nacl.box(toBeArray(value), nonce, fromHexString(publicKey), ephemeralKeyPair.secretKey);
|
|
129
|
+
return {
|
|
130
|
+
data: encryptedMessage,
|
|
131
|
+
public_key: ephemeralKeyPair.publicKey,
|
|
132
|
+
nonce
|
|
133
|
+
};
|
|
134
|
+
};
|
|
135
|
+
};
|
|
136
|
+
var GenerateSealingKey = () => {
|
|
137
|
+
const sodiumKeypair = nacl.box.keyPair();
|
|
138
|
+
return new SealingKey(toHexString(sodiumKeypair.secretKey), toHexString(sodiumKeypair.publicKey));
|
|
139
|
+
};
|
|
140
|
+
var SerializedSealingPair = z.object({
|
|
141
|
+
privateKey: z.string(),
|
|
142
|
+
publicKey: z.string()
|
|
143
|
+
});
|
|
144
|
+
var addressSchema = z.string().refine((val) => isAddress(val), {
|
|
145
|
+
error: "Invalid address"
|
|
146
|
+
}).transform((val) => getAddress(val));
|
|
147
|
+
var addressNotZeroSchema = addressSchema.refine((val) => val !== zeroAddress, {
|
|
148
|
+
error: "Must not be zeroAddress"
|
|
149
|
+
});
|
|
150
|
+
var bytesSchema = z.custom(
|
|
151
|
+
(val) => {
|
|
152
|
+
return typeof val === "string" && isHex(val);
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
message: "Invalid hex value"
|
|
156
|
+
}
|
|
157
|
+
);
|
|
158
|
+
var bytesNotEmptySchema = bytesSchema.refine((val) => val !== "0x", {
|
|
159
|
+
error: "Must not be empty"
|
|
160
|
+
});
|
|
161
|
+
var DEFAULT_EXPIRATION_FN = () => Math.round(Date.now() / 1e3) + 7 * 24 * 60 * 60;
|
|
162
|
+
var zPermitWithDefaults = z.object({
|
|
163
|
+
name: z.string().optional().default("Unnamed Permit"),
|
|
164
|
+
type: z.enum(["self", "sharing", "recipient"]),
|
|
165
|
+
issuer: addressNotZeroSchema,
|
|
166
|
+
expiration: z.int().optional().default(DEFAULT_EXPIRATION_FN),
|
|
167
|
+
recipient: addressSchema.optional().default(zeroAddress),
|
|
168
|
+
validatorId: z.int().optional().default(0),
|
|
169
|
+
validatorContract: addressSchema.optional().default(zeroAddress),
|
|
170
|
+
issuerSignature: bytesSchema.optional().default("0x"),
|
|
171
|
+
recipientSignature: bytesSchema.optional().default("0x")
|
|
172
|
+
});
|
|
173
|
+
var zPermitWithSealingPair = zPermitWithDefaults.extend({
|
|
174
|
+
sealingPair: SerializedSealingPair.optional()
|
|
175
|
+
});
|
|
176
|
+
var ExternalValidatorRefinement = [
|
|
177
|
+
(data) => data.validatorId !== 0 && data.validatorContract !== zeroAddress || data.validatorId === 0 && data.validatorContract === zeroAddress,
|
|
178
|
+
{
|
|
179
|
+
error: "Permit external validator :: validatorId and validatorContract must either both be set or both be unset.",
|
|
180
|
+
path: ["validatorId", "validatorContract"]
|
|
181
|
+
}
|
|
182
|
+
];
|
|
183
|
+
var RecipientRefinement = [
|
|
184
|
+
(data) => data.issuer !== data.recipient,
|
|
185
|
+
{
|
|
186
|
+
error: "Sharing permit :: issuer and recipient must not be the same",
|
|
187
|
+
path: ["issuer", "recipient"]
|
|
188
|
+
}
|
|
189
|
+
];
|
|
190
|
+
var SelfPermitOptionsValidator = z.object({
|
|
191
|
+
type: z.literal("self").optional().default("self"),
|
|
192
|
+
issuer: addressNotZeroSchema,
|
|
193
|
+
name: z.string().optional().default("Unnamed Permit"),
|
|
194
|
+
expiration: z.int().optional().default(DEFAULT_EXPIRATION_FN),
|
|
195
|
+
recipient: addressSchema.optional().default(zeroAddress),
|
|
196
|
+
validatorId: z.int().optional().default(0),
|
|
197
|
+
validatorContract: addressSchema.optional().default(zeroAddress),
|
|
198
|
+
issuerSignature: bytesSchema.optional().default("0x"),
|
|
199
|
+
recipientSignature: bytesSchema.optional().default("0x")
|
|
200
|
+
}).refine(...ExternalValidatorRefinement);
|
|
201
|
+
var SelfPermitValidator = zPermitWithSealingPair.refine((data) => data.type === "self", {
|
|
202
|
+
error: "Type must be 'self'"
|
|
203
|
+
}).refine((data) => data.recipient === zeroAddress, {
|
|
204
|
+
error: "Recipient must be zeroAddress"
|
|
205
|
+
}).refine((data) => data.issuerSignature !== "0x", {
|
|
206
|
+
error: "IssuerSignature must be populated"
|
|
207
|
+
}).refine((data) => data.recipientSignature === "0x", {
|
|
208
|
+
error: "RecipientSignature must be empty"
|
|
209
|
+
}).refine(...ExternalValidatorRefinement);
|
|
210
|
+
var SharingPermitOptionsValidator = z.object({
|
|
211
|
+
type: z.literal("sharing").optional().default("sharing"),
|
|
212
|
+
issuer: addressNotZeroSchema,
|
|
213
|
+
recipient: addressNotZeroSchema,
|
|
214
|
+
name: z.string().optional().default("Unnamed Permit"),
|
|
215
|
+
expiration: z.int().optional().default(DEFAULT_EXPIRATION_FN),
|
|
216
|
+
validatorId: z.int().optional().default(0),
|
|
217
|
+
validatorContract: addressSchema.optional().default(zeroAddress),
|
|
218
|
+
issuerSignature: bytesSchema.optional().default("0x"),
|
|
219
|
+
recipientSignature: bytesSchema.optional().default("0x")
|
|
220
|
+
}).refine(...RecipientRefinement).refine(...ExternalValidatorRefinement);
|
|
221
|
+
var SharingPermitValidator = zPermitWithSealingPair.refine((data) => data.type === "sharing", {
|
|
222
|
+
error: "Type must be 'sharing'"
|
|
223
|
+
}).refine((data) => data.recipient !== zeroAddress, {
|
|
224
|
+
error: "Recipient must not be zeroAddress"
|
|
225
|
+
}).refine((data) => data.issuerSignature !== "0x", {
|
|
226
|
+
error: "IssuerSignature must be populated"
|
|
227
|
+
}).refine((data) => data.recipientSignature === "0x", {
|
|
228
|
+
error: "RecipientSignature must be empty"
|
|
229
|
+
}).refine(...ExternalValidatorRefinement);
|
|
230
|
+
var ImportPermitOptionsValidator = z.object({
|
|
231
|
+
type: z.literal("recipient").optional().default("recipient"),
|
|
232
|
+
issuer: addressNotZeroSchema,
|
|
233
|
+
recipient: addressNotZeroSchema,
|
|
234
|
+
name: z.string().optional().default("Unnamed Permit"),
|
|
235
|
+
expiration: z.int(),
|
|
236
|
+
validatorId: z.int().optional().default(0),
|
|
237
|
+
validatorContract: addressSchema.optional().default(zeroAddress),
|
|
238
|
+
issuerSignature: bytesNotEmptySchema,
|
|
239
|
+
recipientSignature: bytesSchema.optional().default("0x")
|
|
240
|
+
}).refine(...ExternalValidatorRefinement);
|
|
241
|
+
var ImportPermitValidator = zPermitWithSealingPair.refine((data) => data.type === "recipient", {
|
|
242
|
+
error: "Type must be 'recipient'"
|
|
243
|
+
}).refine((data) => data.recipient !== zeroAddress, {
|
|
244
|
+
error: "Recipient must not be zeroAddress"
|
|
245
|
+
}).refine((data) => data.issuerSignature !== "0x", {
|
|
246
|
+
error: "IssuerSignature must be populated"
|
|
247
|
+
}).refine((data) => data.recipientSignature !== "0x", {
|
|
248
|
+
error: "RecipientSignature must be populated"
|
|
249
|
+
}).refine(...ExternalValidatorRefinement);
|
|
250
|
+
var safeParseAndThrowFormatted = (schema, data, message) => {
|
|
251
|
+
const result = schema.safeParse(data);
|
|
252
|
+
if (!result.success) {
|
|
253
|
+
throw new Error(`${message}: ${z.prettifyError(result.error)}`, { cause: result.error });
|
|
254
|
+
}
|
|
255
|
+
return result.data;
|
|
256
|
+
};
|
|
257
|
+
var validateSelfPermitOptions = (options) => {
|
|
258
|
+
return safeParseAndThrowFormatted(SelfPermitOptionsValidator, options, "Invalid self permit options");
|
|
259
|
+
};
|
|
260
|
+
var validateSharingPermitOptions = (options) => {
|
|
261
|
+
return safeParseAndThrowFormatted(SharingPermitOptionsValidator, options, "Invalid sharing permit options");
|
|
262
|
+
};
|
|
263
|
+
var validateImportPermitOptions = (options) => {
|
|
264
|
+
return safeParseAndThrowFormatted(ImportPermitOptionsValidator, options, "Invalid import permit options");
|
|
265
|
+
};
|
|
266
|
+
var validateSelfPermit = (permit) => {
|
|
267
|
+
return safeParseAndThrowFormatted(SelfPermitValidator, permit, "Invalid self permit");
|
|
268
|
+
};
|
|
269
|
+
var validateSharingPermit = (permit) => {
|
|
270
|
+
return safeParseAndThrowFormatted(SharingPermitValidator, permit, "Invalid sharing permit");
|
|
271
|
+
};
|
|
272
|
+
var validateImportPermit = (permit) => {
|
|
273
|
+
return safeParseAndThrowFormatted(ImportPermitValidator, permit, "Invalid import permit");
|
|
274
|
+
};
|
|
275
|
+
var ValidationUtils = {
|
|
276
|
+
/**
|
|
277
|
+
* Check if permit is expired
|
|
278
|
+
*/
|
|
279
|
+
isExpired: (permit) => {
|
|
280
|
+
return permit.expiration < Math.floor(Date.now() / 1e3);
|
|
281
|
+
},
|
|
282
|
+
/**
|
|
283
|
+
* Check if permit is signed by the active party
|
|
284
|
+
*/
|
|
285
|
+
isSigned: (permit) => {
|
|
286
|
+
if (permit.type === "self" || permit.type === "sharing") {
|
|
287
|
+
return permit.issuerSignature !== "0x";
|
|
288
|
+
}
|
|
289
|
+
if (permit.type === "recipient") {
|
|
290
|
+
return permit.recipientSignature !== "0x";
|
|
291
|
+
}
|
|
292
|
+
return false;
|
|
293
|
+
},
|
|
294
|
+
/**
|
|
295
|
+
* Checks that a permit is signed and not expired.
|
|
296
|
+
*/
|
|
297
|
+
isSignedAndNotExpired: (permit) => {
|
|
298
|
+
if (ValidationUtils.isExpired(permit)) {
|
|
299
|
+
return { valid: false, error: "expired" };
|
|
300
|
+
}
|
|
301
|
+
if (!ValidationUtils.isSigned(permit)) {
|
|
302
|
+
return { valid: false, error: "not-signed" };
|
|
303
|
+
}
|
|
304
|
+
return { valid: true, error: null };
|
|
305
|
+
},
|
|
306
|
+
/**
|
|
307
|
+
* Asserts that a permit is signed and not expired.
|
|
308
|
+
*
|
|
309
|
+
* Throws `Error` with message:
|
|
310
|
+
* - `Permit is expired`
|
|
311
|
+
* - `Permit is not signed`
|
|
312
|
+
*/
|
|
313
|
+
assertSignedAndNotExpired: (permit) => {
|
|
314
|
+
const result = ValidationUtils.isSignedAndNotExpired(permit);
|
|
315
|
+
if (result.valid)
|
|
316
|
+
return;
|
|
317
|
+
if (result.error === "expired") {
|
|
318
|
+
throw new Error("Permit is expired");
|
|
319
|
+
}
|
|
320
|
+
if (result.error === "not-signed") {
|
|
321
|
+
throw new Error("Permit is not signed");
|
|
322
|
+
}
|
|
323
|
+
throw new Error("Permit is invalid");
|
|
324
|
+
},
|
|
325
|
+
isValid: (permit) => {
|
|
326
|
+
const schema = permit.type === "self" ? SelfPermitValidator : permit.type === "sharing" ? SharingPermitValidator : permit.type === "recipient" ? ImportPermitValidator : null;
|
|
327
|
+
if (schema == null)
|
|
328
|
+
return { valid: false, error: "invalid-schema" };
|
|
329
|
+
const schemaResult = schema.safeParse(permit);
|
|
330
|
+
if (!schemaResult.success)
|
|
331
|
+
return { valid: false, error: "invalid-schema" };
|
|
332
|
+
return ValidationUtils.isSignedAndNotExpired(permit);
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
// permits/signature.ts
|
|
337
|
+
var PermitSignatureAllFields = [
|
|
338
|
+
{ name: "issuer", type: "address" },
|
|
339
|
+
{ name: "expiration", type: "uint64" },
|
|
340
|
+
{ name: "recipient", type: "address" },
|
|
341
|
+
{ name: "validatorId", type: "uint256" },
|
|
342
|
+
{ name: "validatorContract", type: "address" },
|
|
343
|
+
{ name: "sealingKey", type: "bytes32" },
|
|
344
|
+
{ name: "issuerSignature", type: "bytes" }
|
|
345
|
+
];
|
|
346
|
+
var SignatureTypes = {
|
|
347
|
+
PermissionedV2IssuerSelf: [
|
|
348
|
+
"issuer",
|
|
349
|
+
"expiration",
|
|
350
|
+
"recipient",
|
|
351
|
+
"validatorId",
|
|
352
|
+
"validatorContract",
|
|
353
|
+
"sealingKey"
|
|
354
|
+
],
|
|
355
|
+
PermissionedV2IssuerShared: [
|
|
356
|
+
"issuer",
|
|
357
|
+
"expiration",
|
|
358
|
+
"recipient",
|
|
359
|
+
"validatorId",
|
|
360
|
+
"validatorContract"
|
|
361
|
+
],
|
|
362
|
+
PermissionedV2Recipient: ["sealingKey", "issuerSignature"]
|
|
363
|
+
};
|
|
364
|
+
var getSignatureTypesAndMessage = (primaryType, fields, values) => {
|
|
365
|
+
const types = {
|
|
366
|
+
[primaryType]: PermitSignatureAllFields.filter((fieldType) => fields.includes(fieldType.name))
|
|
367
|
+
};
|
|
368
|
+
const message = {};
|
|
369
|
+
fields.forEach((field) => {
|
|
370
|
+
if (field in values) {
|
|
371
|
+
message[field] = values[field];
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
return { types, primaryType, message };
|
|
375
|
+
};
|
|
376
|
+
var SignatureUtils = {
|
|
377
|
+
/**
|
|
378
|
+
* Get signature parameters for a permit
|
|
379
|
+
*/
|
|
380
|
+
getSignatureParams: (permit, primaryType) => {
|
|
381
|
+
return getSignatureTypesAndMessage(primaryType, SignatureTypes[primaryType], permit);
|
|
382
|
+
},
|
|
383
|
+
/**
|
|
384
|
+
* Determine the required signature type based on permit type
|
|
385
|
+
*/
|
|
386
|
+
getPrimaryType: (permitType) => {
|
|
387
|
+
if (permitType === "self")
|
|
388
|
+
return "PermissionedV2IssuerSelf";
|
|
389
|
+
if (permitType === "sharing")
|
|
390
|
+
return "PermissionedV2IssuerShared";
|
|
391
|
+
if (permitType === "recipient")
|
|
392
|
+
return "PermissionedV2Recipient";
|
|
393
|
+
throw new Error(`Unknown permit type: ${permitType}`);
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
|
|
397
|
+
// core/consts.ts
|
|
398
|
+
var TASK_MANAGER_ADDRESS = "0xeA30c4B8b44078Bbf8a6ef5b9f1eC1626C7848D9";
|
|
399
|
+
var MOCKS_ZK_VERIFIER_ADDRESS = "0x0000000000000000000000000000000000005001";
|
|
400
|
+
var MOCKS_THRESHOLD_NETWORK_ADDRESS = "0x0000000000000000000000000000000000005002";
|
|
401
|
+
var TEST_BED_ADDRESS = "0x0000000000000000000000000000000000005003";
|
|
402
|
+
var MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY = "0x6C8D7F768A6BB4AAFE85E8A2F5A9680355239C7E14646ED62B044E39DE154512";
|
|
403
|
+
var MOCKS_ZK_VERIFIER_SIGNER_ADDRESS = "0x6E12D8C87503D4287c294f2Fdef96ACd9DFf6bd2";
|
|
404
|
+
var MOCKS_DECRYPT_RESULT_SIGNER_PRIVATE_KEY = "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d";
|
|
405
|
+
|
|
406
|
+
// permits/onchain-utils.ts
|
|
407
|
+
var getAclAddress = async (publicClient) => {
|
|
408
|
+
const ACL_IFACE = "function acl() view returns (address)";
|
|
409
|
+
const aclAbi = parseAbi([ACL_IFACE]);
|
|
410
|
+
return await publicClient.readContract({
|
|
411
|
+
address: TASK_MANAGER_ADDRESS,
|
|
412
|
+
abi: aclAbi,
|
|
413
|
+
functionName: "acl"
|
|
414
|
+
});
|
|
415
|
+
};
|
|
416
|
+
var getAclEIP712Domain = async (publicClient) => {
|
|
417
|
+
const aclAddress = await getAclAddress(publicClient);
|
|
418
|
+
const EIP712_DOMAIN_IFACE = "function eip712Domain() public view returns (bytes1 fields, string name, string version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] extensions)";
|
|
419
|
+
const domainAbi = parseAbi([EIP712_DOMAIN_IFACE]);
|
|
420
|
+
const domain = await publicClient.readContract({
|
|
421
|
+
address: aclAddress,
|
|
422
|
+
abi: domainAbi,
|
|
423
|
+
functionName: "eip712Domain"
|
|
424
|
+
});
|
|
425
|
+
const [_fields, name, version, chainId, verifyingContract, _salt, _extensions] = domain;
|
|
426
|
+
return {
|
|
427
|
+
name,
|
|
428
|
+
version,
|
|
429
|
+
chainId: Number(chainId),
|
|
430
|
+
verifyingContract
|
|
431
|
+
};
|
|
432
|
+
};
|
|
433
|
+
var checkPermitValidityOnChain = async (permission, publicClient) => {
|
|
434
|
+
const aclAddress = await getAclAddress(publicClient);
|
|
435
|
+
try {
|
|
436
|
+
await publicClient.simulateContract({
|
|
437
|
+
address: aclAddress,
|
|
438
|
+
abi: checkPermitValidityAbi,
|
|
439
|
+
functionName: "checkPermitValidity",
|
|
440
|
+
args: [
|
|
441
|
+
{
|
|
442
|
+
issuer: permission.issuer,
|
|
443
|
+
expiration: BigInt(permission.expiration),
|
|
444
|
+
recipient: permission.recipient,
|
|
445
|
+
validatorId: BigInt(permission.validatorId),
|
|
446
|
+
validatorContract: permission.validatorContract,
|
|
447
|
+
sealingKey: permission.sealingKey,
|
|
448
|
+
issuerSignature: permission.issuerSignature,
|
|
449
|
+
recipientSignature: permission.recipientSignature
|
|
450
|
+
}
|
|
451
|
+
]
|
|
452
|
+
});
|
|
453
|
+
return true;
|
|
454
|
+
} catch (err) {
|
|
455
|
+
if (err instanceof BaseError) {
|
|
456
|
+
const revertError = err.walk((err2) => err2 instanceof ContractFunctionRevertedError);
|
|
457
|
+
if (revertError instanceof ContractFunctionRevertedError) {
|
|
458
|
+
const errorName = revertError.data?.errorName ?? "";
|
|
459
|
+
throw new Error(errorName);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
const customErrorName = extractCustomErrorFromDetails(err, checkPermitValidityAbi);
|
|
463
|
+
if (customErrorName) {
|
|
464
|
+
throw new Error(customErrorName);
|
|
465
|
+
}
|
|
466
|
+
const hhDetailsData = extractReturnData(err);
|
|
467
|
+
if (hhDetailsData != null) {
|
|
468
|
+
const decoded = decodeErrorResult({
|
|
469
|
+
abi: checkPermitValidityAbi,
|
|
470
|
+
data: hhDetailsData
|
|
471
|
+
});
|
|
472
|
+
throw new Error(decoded.errorName);
|
|
473
|
+
}
|
|
474
|
+
throw err;
|
|
475
|
+
}
|
|
476
|
+
};
|
|
477
|
+
function extractCustomErrorFromDetails(err, abi) {
|
|
478
|
+
const anyErr = err;
|
|
479
|
+
const details = anyErr?.details ?? anyErr?.cause?.details;
|
|
480
|
+
if (typeof details === "string") {
|
|
481
|
+
const customErrorMatch = details.match(/reverted with custom error '(\w+)\(\)'/);
|
|
482
|
+
if (customErrorMatch) {
|
|
483
|
+
const errorName = customErrorMatch[1];
|
|
484
|
+
const errorExists = abi.some((item) => item.type === "error" && item.name === errorName);
|
|
485
|
+
if (errorExists) {
|
|
486
|
+
return errorName;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
return void 0;
|
|
491
|
+
}
|
|
492
|
+
function extractReturnData(err) {
|
|
493
|
+
const anyErr = err;
|
|
494
|
+
const s = anyErr?.details ?? anyErr?.cause?.details ?? anyErr?.shortMessage ?? anyErr?.message ?? String(err);
|
|
495
|
+
return s.match(/return data:\s*(0x[a-fA-F0-9]+)/)?.[1];
|
|
496
|
+
}
|
|
497
|
+
var checkPermitValidityAbi = [
|
|
498
|
+
{
|
|
499
|
+
type: "function",
|
|
500
|
+
name: "checkPermitValidity",
|
|
501
|
+
inputs: [
|
|
502
|
+
{
|
|
503
|
+
name: "permission",
|
|
504
|
+
type: "tuple",
|
|
505
|
+
internalType: "struct Permission",
|
|
506
|
+
components: [
|
|
507
|
+
{
|
|
508
|
+
name: "issuer",
|
|
509
|
+
type: "address",
|
|
510
|
+
internalType: "address"
|
|
511
|
+
},
|
|
512
|
+
{
|
|
513
|
+
name: "expiration",
|
|
514
|
+
type: "uint64",
|
|
515
|
+
internalType: "uint64"
|
|
516
|
+
},
|
|
517
|
+
{
|
|
518
|
+
name: "recipient",
|
|
519
|
+
type: "address",
|
|
520
|
+
internalType: "address"
|
|
521
|
+
},
|
|
522
|
+
{
|
|
523
|
+
name: "validatorId",
|
|
524
|
+
type: "uint256",
|
|
525
|
+
internalType: "uint256"
|
|
526
|
+
},
|
|
527
|
+
{
|
|
528
|
+
name: "validatorContract",
|
|
529
|
+
type: "address",
|
|
530
|
+
internalType: "address"
|
|
531
|
+
},
|
|
532
|
+
{
|
|
533
|
+
name: "sealingKey",
|
|
534
|
+
type: "bytes32",
|
|
535
|
+
internalType: "bytes32"
|
|
536
|
+
},
|
|
537
|
+
{
|
|
538
|
+
name: "issuerSignature",
|
|
539
|
+
type: "bytes",
|
|
540
|
+
internalType: "bytes"
|
|
541
|
+
},
|
|
542
|
+
{
|
|
543
|
+
name: "recipientSignature",
|
|
544
|
+
type: "bytes",
|
|
545
|
+
internalType: "bytes"
|
|
546
|
+
}
|
|
547
|
+
]
|
|
548
|
+
}
|
|
549
|
+
],
|
|
550
|
+
outputs: [
|
|
551
|
+
{
|
|
552
|
+
name: "",
|
|
553
|
+
type: "bool",
|
|
554
|
+
internalType: "bool"
|
|
555
|
+
}
|
|
556
|
+
],
|
|
557
|
+
stateMutability: "view"
|
|
558
|
+
},
|
|
559
|
+
{
|
|
560
|
+
type: "error",
|
|
561
|
+
name: "PermissionInvalid_Disabled",
|
|
562
|
+
inputs: []
|
|
563
|
+
},
|
|
564
|
+
{
|
|
565
|
+
type: "error",
|
|
566
|
+
name: "PermissionInvalid_Expired",
|
|
567
|
+
inputs: []
|
|
568
|
+
},
|
|
569
|
+
{
|
|
570
|
+
type: "error",
|
|
571
|
+
name: "PermissionInvalid_IssuerSignature",
|
|
572
|
+
inputs: []
|
|
573
|
+
},
|
|
574
|
+
{
|
|
575
|
+
type: "error",
|
|
576
|
+
name: "PermissionInvalid_RecipientSignature",
|
|
577
|
+
inputs: []
|
|
578
|
+
}
|
|
579
|
+
];
|
|
580
|
+
|
|
581
|
+
// permits/permit.ts
|
|
582
|
+
var PermitUtils = {
|
|
583
|
+
/**
|
|
584
|
+
* Create a self permit for personal use
|
|
585
|
+
*/
|
|
586
|
+
createSelf: (options) => {
|
|
587
|
+
const validation = validateSelfPermitOptions(options);
|
|
588
|
+
const sealingPair = GenerateSealingKey();
|
|
589
|
+
const permit = {
|
|
590
|
+
hash: PermitUtils.getHash(validation),
|
|
591
|
+
...validation,
|
|
592
|
+
sealingPair,
|
|
593
|
+
_signedDomain: void 0
|
|
594
|
+
};
|
|
595
|
+
return permit;
|
|
596
|
+
},
|
|
597
|
+
/**
|
|
598
|
+
* Create a sharing permit to be shared with another user
|
|
599
|
+
*/
|
|
600
|
+
createSharing: (options) => {
|
|
601
|
+
const validation = validateSharingPermitOptions(options);
|
|
602
|
+
const sealingPair = GenerateSealingKey();
|
|
603
|
+
const permit = {
|
|
604
|
+
hash: PermitUtils.getHash(validation),
|
|
605
|
+
...validation,
|
|
606
|
+
sealingPair,
|
|
607
|
+
_signedDomain: void 0
|
|
608
|
+
};
|
|
609
|
+
return permit;
|
|
610
|
+
},
|
|
611
|
+
/**
|
|
612
|
+
* Import a shared permit from various input formats
|
|
613
|
+
*/
|
|
614
|
+
importShared: (options) => {
|
|
615
|
+
let parsedOptions;
|
|
616
|
+
if (typeof options === "string") {
|
|
617
|
+
try {
|
|
618
|
+
parsedOptions = JSON.parse(options);
|
|
619
|
+
} catch (error) {
|
|
620
|
+
throw new Error(`Failed to parse JSON string: ${error}`);
|
|
621
|
+
}
|
|
622
|
+
} else if (typeof options === "object" && options !== null) {
|
|
623
|
+
parsedOptions = options;
|
|
624
|
+
} else {
|
|
625
|
+
throw new Error("Invalid input type, expected ImportSharedPermitOptions, object, or string");
|
|
626
|
+
}
|
|
627
|
+
if (parsedOptions.type != null && parsedOptions.type !== "sharing") {
|
|
628
|
+
throw new Error(`Invalid permit type <${parsedOptions.type}>, must be "sharing"`);
|
|
629
|
+
}
|
|
630
|
+
const validation = validateImportPermitOptions({ ...parsedOptions, type: "recipient" });
|
|
631
|
+
const sealingPair = GenerateSealingKey();
|
|
632
|
+
const permit = {
|
|
633
|
+
hash: PermitUtils.getHash(validation),
|
|
634
|
+
...validation,
|
|
635
|
+
sealingPair,
|
|
636
|
+
_signedDomain: void 0
|
|
637
|
+
};
|
|
638
|
+
return permit;
|
|
639
|
+
},
|
|
640
|
+
/**
|
|
641
|
+
* Sign a permit with the provided wallet client
|
|
642
|
+
*/
|
|
643
|
+
sign: async (permit, publicClient, walletClient) => {
|
|
644
|
+
if (walletClient == null || walletClient.account == null) {
|
|
645
|
+
throw new Error(
|
|
646
|
+
"Missing walletClient, you must pass in a `walletClient` for the connected user to create a permit signature"
|
|
647
|
+
);
|
|
648
|
+
}
|
|
649
|
+
const primaryType = SignatureUtils.getPrimaryType(permit.type);
|
|
650
|
+
const domain = await getAclEIP712Domain(publicClient);
|
|
651
|
+
const { types, message } = SignatureUtils.getSignatureParams(PermitUtils.getPermission(permit, true), primaryType);
|
|
652
|
+
const signature = await walletClient.signTypedData({
|
|
653
|
+
domain,
|
|
654
|
+
types,
|
|
655
|
+
primaryType,
|
|
656
|
+
message,
|
|
657
|
+
account: walletClient.account
|
|
658
|
+
});
|
|
659
|
+
let updatedPermit;
|
|
660
|
+
if (permit.type === "self" || permit.type === "sharing") {
|
|
661
|
+
updatedPermit = {
|
|
662
|
+
...permit,
|
|
663
|
+
issuerSignature: signature,
|
|
664
|
+
_signedDomain: domain
|
|
665
|
+
};
|
|
666
|
+
} else {
|
|
667
|
+
updatedPermit = {
|
|
668
|
+
...permit,
|
|
669
|
+
recipientSignature: signature,
|
|
670
|
+
_signedDomain: domain
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
return updatedPermit;
|
|
674
|
+
},
|
|
675
|
+
/**
|
|
676
|
+
* Create and sign a self permit in one operation
|
|
677
|
+
*/
|
|
678
|
+
createSelfAndSign: async (options, publicClient, walletClient) => {
|
|
679
|
+
const permit = PermitUtils.createSelf(options);
|
|
680
|
+
return PermitUtils.sign(permit, publicClient, walletClient);
|
|
681
|
+
},
|
|
682
|
+
/**
|
|
683
|
+
* Create and sign a sharing permit in one operation
|
|
684
|
+
*/
|
|
685
|
+
createSharingAndSign: async (options, publicClient, walletClient) => {
|
|
686
|
+
const permit = PermitUtils.createSharing(options);
|
|
687
|
+
return PermitUtils.sign(permit, publicClient, walletClient);
|
|
688
|
+
},
|
|
689
|
+
/**
|
|
690
|
+
* Import and sign a shared permit in one operation from various input formats
|
|
691
|
+
*/
|
|
692
|
+
importSharedAndSign: async (options, publicClient, walletClient) => {
|
|
693
|
+
const permit = PermitUtils.importShared(options);
|
|
694
|
+
return PermitUtils.sign(permit, publicClient, walletClient);
|
|
695
|
+
},
|
|
696
|
+
/**
|
|
697
|
+
* Deserialize a permit from serialized data
|
|
698
|
+
*/
|
|
699
|
+
deserialize: (data) => {
|
|
700
|
+
return {
|
|
701
|
+
...data,
|
|
702
|
+
sealingPair: SealingKey.deserialize(data.sealingPair.privateKey, data.sealingPair.publicKey)
|
|
703
|
+
};
|
|
704
|
+
},
|
|
705
|
+
/**
|
|
706
|
+
* Serialize a permit for storage
|
|
707
|
+
*/
|
|
708
|
+
serialize: (permit) => {
|
|
709
|
+
return {
|
|
710
|
+
hash: permit.hash,
|
|
711
|
+
name: permit.name,
|
|
712
|
+
type: permit.type,
|
|
713
|
+
issuer: permit.issuer,
|
|
714
|
+
expiration: permit.expiration,
|
|
715
|
+
recipient: permit.recipient,
|
|
716
|
+
validatorId: permit.validatorId,
|
|
717
|
+
validatorContract: permit.validatorContract,
|
|
718
|
+
issuerSignature: permit.issuerSignature,
|
|
719
|
+
recipientSignature: permit.recipientSignature,
|
|
720
|
+
_signedDomain: permit._signedDomain,
|
|
721
|
+
sealingPair: permit.sealingPair.serialize()
|
|
722
|
+
};
|
|
723
|
+
},
|
|
724
|
+
/**
|
|
725
|
+
* Validate a permit (schema-level validation)
|
|
726
|
+
*/
|
|
727
|
+
validateSchema: (permit) => {
|
|
728
|
+
if (permit.type === "self") {
|
|
729
|
+
return validateSelfPermit(permit);
|
|
730
|
+
} else if (permit.type === "sharing") {
|
|
731
|
+
return validateSharingPermit(permit);
|
|
732
|
+
} else if (permit.type === "recipient") {
|
|
733
|
+
return validateImportPermit(permit);
|
|
734
|
+
} else {
|
|
735
|
+
throw new Error("Invalid permit type");
|
|
736
|
+
}
|
|
737
|
+
},
|
|
738
|
+
/**
|
|
739
|
+
* Validate a permit (holistic validation).
|
|
740
|
+
*
|
|
741
|
+
* This validates:
|
|
742
|
+
* - Permit schema (shape + invariants)
|
|
743
|
+
* - Permit is signed
|
|
744
|
+
* - Permit is not expired
|
|
745
|
+
*
|
|
746
|
+
* For schema-only validation, use `validateSchema(permit)`.
|
|
747
|
+
*/
|
|
748
|
+
validate: (permit) => {
|
|
749
|
+
const validated = PermitUtils.validateSchema(permit);
|
|
750
|
+
ValidationUtils.assertSignedAndNotExpired(validated);
|
|
751
|
+
return validated;
|
|
752
|
+
},
|
|
753
|
+
/**
|
|
754
|
+
* Get the permission object from a permit (for use in contracts)
|
|
755
|
+
*/
|
|
756
|
+
getPermission: (permit, skipValidation = false) => {
|
|
757
|
+
if (!skipValidation) {
|
|
758
|
+
PermitUtils.validateSchema(permit);
|
|
759
|
+
}
|
|
760
|
+
return {
|
|
761
|
+
issuer: permit.issuer,
|
|
762
|
+
expiration: permit.expiration,
|
|
763
|
+
recipient: permit.recipient,
|
|
764
|
+
validatorId: permit.validatorId,
|
|
765
|
+
validatorContract: permit.validatorContract,
|
|
766
|
+
sealingKey: `0x${permit.sealingPair.publicKey}`,
|
|
767
|
+
issuerSignature: permit.issuerSignature,
|
|
768
|
+
recipientSignature: permit.recipientSignature
|
|
769
|
+
};
|
|
770
|
+
},
|
|
771
|
+
/**
|
|
772
|
+
* Get a stable hash for the permit (used as key in storage)
|
|
773
|
+
*/
|
|
774
|
+
getHash: (permit) => {
|
|
775
|
+
const data = JSON.stringify({
|
|
776
|
+
type: permit.type,
|
|
777
|
+
issuer: permit.issuer,
|
|
778
|
+
expiration: permit.expiration,
|
|
779
|
+
recipient: permit.recipient,
|
|
780
|
+
validatorId: permit.validatorId,
|
|
781
|
+
validatorContract: permit.validatorContract
|
|
782
|
+
});
|
|
783
|
+
return keccak256(toHex(data));
|
|
784
|
+
},
|
|
785
|
+
/**
|
|
786
|
+
* Export permit data for sharing (removes sensitive fields)
|
|
787
|
+
*/
|
|
788
|
+
export: (permit) => {
|
|
789
|
+
const cleanedPermit = {
|
|
790
|
+
name: permit.name,
|
|
791
|
+
type: permit.type,
|
|
792
|
+
issuer: permit.issuer,
|
|
793
|
+
expiration: permit.expiration
|
|
794
|
+
};
|
|
795
|
+
if (permit.recipient !== zeroAddress)
|
|
796
|
+
cleanedPermit.recipient = permit.recipient;
|
|
797
|
+
if (permit.validatorId !== 0)
|
|
798
|
+
cleanedPermit.validatorId = permit.validatorId;
|
|
799
|
+
if (permit.validatorContract !== zeroAddress)
|
|
800
|
+
cleanedPermit.validatorContract = permit.validatorContract;
|
|
801
|
+
if (permit.type === "sharing" && permit.issuerSignature !== "0x")
|
|
802
|
+
cleanedPermit.issuerSignature = permit.issuerSignature;
|
|
803
|
+
return JSON.stringify(cleanedPermit, void 0, 2);
|
|
804
|
+
},
|
|
805
|
+
/**
|
|
806
|
+
* Unseal encrypted data using the permit's sealing key
|
|
807
|
+
*/
|
|
808
|
+
unseal: (permit, ciphertext) => {
|
|
809
|
+
return permit.sealingPair.unseal(ciphertext);
|
|
810
|
+
},
|
|
811
|
+
/**
|
|
812
|
+
* Check if permit is expired
|
|
813
|
+
*/
|
|
814
|
+
isExpired: (permit) => {
|
|
815
|
+
return ValidationUtils.isExpired(permit);
|
|
816
|
+
},
|
|
817
|
+
/**
|
|
818
|
+
* Check if permit is signed
|
|
819
|
+
*/
|
|
820
|
+
isSigned: (permit) => {
|
|
821
|
+
return ValidationUtils.isSigned(permit);
|
|
822
|
+
},
|
|
823
|
+
/**
|
|
824
|
+
* Check if permit is signed and not expired
|
|
825
|
+
*/
|
|
826
|
+
isSignedAndNotExpired: (permit) => {
|
|
827
|
+
return ValidationUtils.isSignedAndNotExpired(permit);
|
|
828
|
+
},
|
|
829
|
+
/**
|
|
830
|
+
* Assert that permit is signed and not expired
|
|
831
|
+
*/
|
|
832
|
+
assertSignedAndNotExpired: (permit) => {
|
|
833
|
+
return ValidationUtils.assertSignedAndNotExpired(permit);
|
|
834
|
+
},
|
|
835
|
+
isValid: (permit) => {
|
|
836
|
+
return ValidationUtils.isValid(permit);
|
|
837
|
+
},
|
|
838
|
+
/**
|
|
839
|
+
* Update permit name (returns new permit instance)
|
|
840
|
+
*/
|
|
841
|
+
updateName: (permit, name) => {
|
|
842
|
+
return { ...permit, name };
|
|
843
|
+
},
|
|
844
|
+
/**
|
|
845
|
+
* Fetch EIP712 domain from the blockchain
|
|
846
|
+
*/
|
|
847
|
+
fetchEIP712Domain: async (publicClient) => {
|
|
848
|
+
return getAclEIP712Domain(publicClient);
|
|
849
|
+
},
|
|
850
|
+
/**
|
|
851
|
+
* Check if permit's signed domain matches the provided domain
|
|
852
|
+
*/
|
|
853
|
+
matchesDomain: (permit, domain) => {
|
|
854
|
+
return permit._signedDomain?.name === domain.name && permit._signedDomain?.version === domain.version && permit._signedDomain?.verifyingContract === domain.verifyingContract && permit._signedDomain?.chainId === domain.chainId;
|
|
855
|
+
},
|
|
856
|
+
/**
|
|
857
|
+
* Check if permit's signed domain is valid for the current chain
|
|
858
|
+
*/
|
|
859
|
+
checkSignedDomainValid: async (permit, publicClient) => {
|
|
860
|
+
if (permit._signedDomain == null)
|
|
861
|
+
return false;
|
|
862
|
+
const domain = await getAclEIP712Domain(publicClient);
|
|
863
|
+
return PermitUtils.matchesDomain(permit, domain);
|
|
864
|
+
},
|
|
865
|
+
/**
|
|
866
|
+
* Check if permit passes the on-chain validation
|
|
867
|
+
*/
|
|
868
|
+
checkValidityOnChain: async (permit, publicClient) => {
|
|
869
|
+
const permission = PermitUtils.getPermission(permit);
|
|
870
|
+
return checkPermitValidityOnChain(permission, publicClient);
|
|
871
|
+
}
|
|
872
|
+
};
|
|
873
|
+
var PERMIT_STORE_DEFAULTS = {
|
|
874
|
+
permits: {},
|
|
875
|
+
activePermitHash: {}
|
|
876
|
+
};
|
|
877
|
+
var _permitStore = createStore()(
|
|
878
|
+
persist(() => PERMIT_STORE_DEFAULTS, { name: "cofhesdk-permits" })
|
|
879
|
+
);
|
|
880
|
+
var clearStaleStore = () => {
|
|
881
|
+
const state = _permitStore.getState();
|
|
882
|
+
const hasExpectedStructure = state && typeof state === "object" && "permits" in state && "activePermitHash" in state && typeof state.permits === "object" && typeof state.activePermitHash === "object";
|
|
883
|
+
if (hasExpectedStructure)
|
|
884
|
+
return;
|
|
885
|
+
_permitStore.setState({ permits: {}, activePermitHash: {} });
|
|
886
|
+
};
|
|
887
|
+
var getPermit = (chainId, account, hash) => {
|
|
888
|
+
clearStaleStore();
|
|
889
|
+
if (chainId == null || account == null || hash == null)
|
|
890
|
+
return;
|
|
891
|
+
const savedPermit = _permitStore.getState().permits[chainId]?.[account]?.[hash];
|
|
892
|
+
if (savedPermit == null)
|
|
893
|
+
return;
|
|
894
|
+
return PermitUtils.deserialize(savedPermit);
|
|
895
|
+
};
|
|
896
|
+
var getActivePermit = (chainId, account) => {
|
|
897
|
+
clearStaleStore();
|
|
898
|
+
if (chainId == null || account == null)
|
|
899
|
+
return;
|
|
900
|
+
const activePermitHash = _permitStore.getState().activePermitHash[chainId]?.[account];
|
|
901
|
+
return getPermit(chainId, account, activePermitHash);
|
|
902
|
+
};
|
|
903
|
+
var getPermits = (chainId, account) => {
|
|
904
|
+
clearStaleStore();
|
|
905
|
+
if (chainId == null || account == null)
|
|
906
|
+
return {};
|
|
907
|
+
return Object.entries(_permitStore.getState().permits[chainId]?.[account] ?? {}).reduce(
|
|
908
|
+
(acc, [hash, permit]) => {
|
|
909
|
+
if (permit == void 0)
|
|
910
|
+
return acc;
|
|
911
|
+
return { ...acc, [hash]: PermitUtils.deserialize(permit) };
|
|
912
|
+
},
|
|
913
|
+
{}
|
|
914
|
+
);
|
|
915
|
+
};
|
|
916
|
+
var setPermit = (chainId, account, permit) => {
|
|
917
|
+
clearStaleStore();
|
|
918
|
+
_permitStore.setState(
|
|
919
|
+
produce((state) => {
|
|
920
|
+
if (state.permits[chainId] == null)
|
|
921
|
+
state.permits[chainId] = {};
|
|
922
|
+
if (state.permits[chainId][account] == null)
|
|
923
|
+
state.permits[chainId][account] = {};
|
|
924
|
+
state.permits[chainId][account][permit.hash] = PermitUtils.serialize(permit);
|
|
925
|
+
})
|
|
926
|
+
);
|
|
927
|
+
};
|
|
928
|
+
var removePermit = (chainId, account, hash) => {
|
|
929
|
+
clearStaleStore();
|
|
930
|
+
_permitStore.setState(
|
|
931
|
+
produce((state) => {
|
|
932
|
+
if (state.permits[chainId] == null)
|
|
933
|
+
state.permits[chainId] = {};
|
|
934
|
+
if (state.activePermitHash[chainId] == null)
|
|
935
|
+
state.activePermitHash[chainId] = {};
|
|
936
|
+
const accountPermits = state.permits[chainId][account];
|
|
937
|
+
if (accountPermits == null)
|
|
938
|
+
return;
|
|
939
|
+
if (accountPermits[hash] == null)
|
|
940
|
+
return;
|
|
941
|
+
if (state.activePermitHash[chainId][account] === hash) {
|
|
942
|
+
state.activePermitHash[chainId][account] = void 0;
|
|
943
|
+
}
|
|
944
|
+
accountPermits[hash] = void 0;
|
|
945
|
+
})
|
|
946
|
+
);
|
|
947
|
+
};
|
|
948
|
+
var getActivePermitHash = (chainId, account) => {
|
|
949
|
+
clearStaleStore();
|
|
950
|
+
if (chainId == null || account == null)
|
|
951
|
+
return void 0;
|
|
952
|
+
return _permitStore.getState().activePermitHash[chainId]?.[account];
|
|
953
|
+
};
|
|
954
|
+
var setActivePermitHash = (chainId, account, hash) => {
|
|
955
|
+
clearStaleStore();
|
|
956
|
+
_permitStore.setState(
|
|
957
|
+
produce((state) => {
|
|
958
|
+
if (state.activePermitHash[chainId] == null)
|
|
959
|
+
state.activePermitHash[chainId] = {};
|
|
960
|
+
state.activePermitHash[chainId][account] = hash;
|
|
961
|
+
})
|
|
962
|
+
);
|
|
963
|
+
};
|
|
964
|
+
var removeActivePermitHash = (chainId, account) => {
|
|
965
|
+
clearStaleStore();
|
|
966
|
+
_permitStore.setState(
|
|
967
|
+
produce((state) => {
|
|
968
|
+
if (state.activePermitHash[chainId])
|
|
969
|
+
state.activePermitHash[chainId][account] = void 0;
|
|
970
|
+
})
|
|
971
|
+
);
|
|
972
|
+
};
|
|
973
|
+
var resetStore = () => {
|
|
974
|
+
clearStaleStore();
|
|
975
|
+
_permitStore.setState({ permits: {}, activePermitHash: {} });
|
|
976
|
+
};
|
|
977
|
+
var permitStore = {
|
|
978
|
+
store: _permitStore,
|
|
979
|
+
getPermit,
|
|
980
|
+
getActivePermit,
|
|
981
|
+
getPermits,
|
|
982
|
+
setPermit,
|
|
983
|
+
removePermit,
|
|
984
|
+
getActivePermitHash,
|
|
985
|
+
setActivePermitHash,
|
|
986
|
+
removeActivePermitHash,
|
|
987
|
+
resetStore
|
|
988
|
+
};
|
|
989
|
+
|
|
990
|
+
export { GenerateSealingKey, ImportPermitOptionsValidator, ImportPermitValidator, MOCKS_DECRYPT_RESULT_SIGNER_PRIVATE_KEY, MOCKS_THRESHOLD_NETWORK_ADDRESS, MOCKS_ZK_VERIFIER_ADDRESS, MOCKS_ZK_VERIFIER_SIGNER_ADDRESS, MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY, PERMIT_STORE_DEFAULTS, PermitUtils, SealingKey, SelfPermitOptionsValidator, SelfPermitValidator, SharingPermitOptionsValidator, SharingPermitValidator, SignatureTypes, SignatureUtils, TASK_MANAGER_ADDRESS, TEST_BED_ADDRESS, ValidationUtils, _permitStore, addressNotZeroSchema, addressSchema, bytesNotEmptySchema, bytesSchema, clearStaleStore, getActivePermit, getActivePermitHash, getPermit, getPermits, getSignatureTypesAndMessage, permitStore, removeActivePermitHash, removePermit, resetStore, setActivePermitHash, setPermit, validateImportPermit, validateImportPermitOptions, validateSelfPermit, validateSelfPermitOptions, validateSharingPermit, validateSharingPermitOptions };
|