@cofhe/sdk 0.6.1 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +45 -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/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 +25 -21
- package/core/decrypt/tnSealOutputV1.ts +4 -3
- package/core/decrypt/tnSealOutputV2.ts +24 -18
- 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 +4 -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-NOC3PYB7.js → chunk-43USWPEH.js} +930 -580
- 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 +1358 -1002
- package/dist/core.d.cts +31 -9
- package/dist/core.d.ts +31 -9
- package/dist/core.js +3 -3
- package/dist/node.cjs +1293 -952
- package/dist/node.d.cts +2 -2
- package/dist/node.d.ts +2 -2
- package/dist/node.js +3 -3
- package/dist/web.cjs +1293 -952
- 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 -216
- package/core/test/permits.test.ts +0 -596
- 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
package/dist/node.cjs
CHANGED
|
@@ -24,7 +24,8 @@ var CofheError = class _CofheError extends Error {
|
|
|
24
24
|
cause;
|
|
25
25
|
hint;
|
|
26
26
|
context;
|
|
27
|
-
|
|
27
|
+
apiErrorCode;
|
|
28
|
+
constructor({ code, message, cause, hint, context, apiErrorCode }) {
|
|
28
29
|
const fullMessage = cause ? `${message} | Caused by: ${cause.message}` : message;
|
|
29
30
|
super(fullMessage);
|
|
30
31
|
this.name = "CofheError";
|
|
@@ -32,6 +33,7 @@ var CofheError = class _CofheError extends Error {
|
|
|
32
33
|
this.cause = cause;
|
|
33
34
|
this.hint = hint;
|
|
34
35
|
this.context = context;
|
|
36
|
+
this.apiErrorCode = apiErrorCode;
|
|
35
37
|
if (Error.captureStackTrace) {
|
|
36
38
|
Error.captureStackTrace(this, _CofheError);
|
|
37
39
|
}
|
|
@@ -50,6 +52,7 @@ var CofheError = class _CofheError extends Error {
|
|
|
50
52
|
message: wrapperError?.message ?? "An internal error occurred",
|
|
51
53
|
hint: wrapperError?.hint,
|
|
52
54
|
context: wrapperError?.context,
|
|
55
|
+
apiErrorCode: wrapperError?.apiErrorCode,
|
|
53
56
|
cause
|
|
54
57
|
});
|
|
55
58
|
}
|
|
@@ -63,6 +66,7 @@ var CofheError = class _CofheError extends Error {
|
|
|
63
66
|
message: this.message,
|
|
64
67
|
hint: this.hint,
|
|
65
68
|
context: this.context,
|
|
69
|
+
apiErrorCode: this.apiErrorCode,
|
|
66
70
|
cause: this.cause ? {
|
|
67
71
|
name: this.cause.name,
|
|
68
72
|
message: this.cause.message,
|
|
@@ -75,7 +79,8 @@ var CofheError = class _CofheError extends Error {
|
|
|
75
79
|
* Returns a human-readable string representation of the error
|
|
76
80
|
*/
|
|
77
81
|
toString() {
|
|
78
|
-
const
|
|
82
|
+
const codeSuffix = this.apiErrorCode ? ` (api: ${this.apiErrorCode})` : "";
|
|
83
|
+
const parts = [`${this.name} [${this.code}]${codeSuffix}: ${this.message}`];
|
|
79
84
|
if (this.hint) {
|
|
80
85
|
parts.push(`Hint: ${this.hint}`);
|
|
81
86
|
}
|
|
@@ -311,18 +316,19 @@ var constructZkPoKMetadata = (accountAddr, securityZone, chainId) => {
|
|
|
311
316
|
metadata.set(chainIdBytes, 1 + accountBytes.length);
|
|
312
317
|
return metadata;
|
|
313
318
|
};
|
|
314
|
-
var
|
|
319
|
+
var zkVerifyBatch = async (verifierUrl, serializedBytes, address, securityZone, chainId, consumingContract) => {
|
|
315
320
|
const packed_list = toHexString(serializedBytes);
|
|
316
321
|
const sz_byte = new Uint8Array([securityZone]);
|
|
317
322
|
const payload = {
|
|
318
323
|
packed_list,
|
|
319
324
|
account_addr: address,
|
|
320
325
|
security_zone: sz_byte[0],
|
|
321
|
-
chain_id: chainId
|
|
326
|
+
chain_id: chainId,
|
|
327
|
+
contract_address: consumingContract
|
|
322
328
|
};
|
|
323
329
|
const body = JSON.stringify(payload);
|
|
324
330
|
try {
|
|
325
|
-
const response = await fetch(`${verifierUrl}/
|
|
331
|
+
const response = await fetch(`${verifierUrl}/verifyBatch`, {
|
|
326
332
|
method: "POST",
|
|
327
333
|
headers: {
|
|
328
334
|
"Content-Type": "application/json"
|
|
@@ -333,26 +339,25 @@ var zkVerify = async (verifierUrl, serializedBytes, address, securityZone, chain
|
|
|
333
339
|
const errorBody = await response.text();
|
|
334
340
|
throw new CofheError({
|
|
335
341
|
code: "ZK_VERIFY_FAILED" /* ZkVerifyFailed */,
|
|
336
|
-
message: `HTTP error! ZK proof verification failed - ${errorBody}`
|
|
342
|
+
message: `HTTP error! ZK batch proof verification failed - ${errorBody}`
|
|
337
343
|
});
|
|
338
344
|
}
|
|
339
345
|
const json = await response.json();
|
|
340
346
|
if (json.status !== "success") {
|
|
341
347
|
throw new CofheError({
|
|
342
348
|
code: "ZK_VERIFY_FAILED" /* ZkVerifyFailed */,
|
|
343
|
-
message: `ZK proof verification response malformed - ${json.error}`
|
|
349
|
+
message: `ZK batch proof verification response malformed - ${json.error}`
|
|
344
350
|
});
|
|
345
351
|
}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
});
|
|
352
|
+
const { ciphertexts, signature, recid } = json.data;
|
|
353
|
+
return {
|
|
354
|
+
outputs: ciphertexts,
|
|
355
|
+
signature: concatSigRecid(signature, recid)
|
|
356
|
+
};
|
|
352
357
|
} catch (e) {
|
|
353
358
|
throw new CofheError({
|
|
354
359
|
code: "ZK_VERIFY_FAILED" /* ZkVerifyFailed */,
|
|
355
|
-
message: `ZK proof verification failed`,
|
|
360
|
+
message: `ZK batch proof verification failed`,
|
|
356
361
|
cause: e instanceof Error ? e : void 0
|
|
357
362
|
});
|
|
358
363
|
}
|
|
@@ -597,67 +602,59 @@ async function insertCtHashes(items, walletClient) {
|
|
|
597
602
|
});
|
|
598
603
|
}
|
|
599
604
|
}
|
|
600
|
-
async function
|
|
601
|
-
let signatures = [];
|
|
602
|
-
let encInputSignerClient;
|
|
605
|
+
async function createBatchProofSignature(items, securityZone, account, consumingContract) {
|
|
603
606
|
try {
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
607
|
+
const itemHashes = items.map(
|
|
608
|
+
(item) => viem.keccak256(
|
|
609
|
+
viem.encodePacked(
|
|
610
|
+
["uint256", "uint8", "uint8", "address", "uint256", "address"],
|
|
611
|
+
[
|
|
612
|
+
BigInt(item.ctHash),
|
|
613
|
+
item.utype,
|
|
614
|
+
securityZone,
|
|
615
|
+
account,
|
|
616
|
+
BigInt(chains.hardhat.id),
|
|
617
|
+
consumingContract
|
|
618
|
+
]
|
|
619
|
+
)
|
|
620
|
+
)
|
|
621
|
+
);
|
|
622
|
+
const batchDigest = viem.keccak256(
|
|
623
|
+
viem.encodePacked(
|
|
624
|
+
itemHashes.map(() => "bytes32"),
|
|
625
|
+
itemHashes
|
|
626
|
+
)
|
|
627
|
+
);
|
|
628
|
+
return await accounts.sign({
|
|
629
|
+
hash: batchDigest,
|
|
630
|
+
privateKey: MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY,
|
|
631
|
+
to: "hex"
|
|
613
632
|
});
|
|
614
|
-
}
|
|
615
|
-
try {
|
|
616
|
-
for (const item of items) {
|
|
617
|
-
const packedData = viem.encodePacked(
|
|
618
|
-
["uint256", "uint8", "uint8", "address", "uint256"],
|
|
619
|
-
[BigInt(item.ctHash), item.utype, securityZone, account, BigInt(chains.hardhat.id)]
|
|
620
|
-
);
|
|
621
|
-
const messageHash = viem.keccak256(packedData);
|
|
622
|
-
const signature = await accounts.sign({
|
|
623
|
-
hash: messageHash,
|
|
624
|
-
privateKey: MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY,
|
|
625
|
-
to: "hex"
|
|
626
|
-
});
|
|
627
|
-
signatures.push(signature);
|
|
628
|
-
}
|
|
629
633
|
} catch (err) {
|
|
630
634
|
throw new CofheError({
|
|
631
635
|
code: "ZK_MOCKS_CREATE_PROOF_SIGNATURE_FAILED" /* ZkMocksCreateProofSignatureFailed */,
|
|
632
|
-
message: `mockZkVerifySign
|
|
636
|
+
message: `mockZkVerifySign createBatchProofSignature failed while signing the batch digest`,
|
|
633
637
|
cause: err instanceof Error ? err : void 0,
|
|
634
638
|
context: {
|
|
635
639
|
items,
|
|
636
|
-
securityZone
|
|
637
|
-
|
|
638
|
-
});
|
|
639
|
-
}
|
|
640
|
-
if (signatures.length !== items.length) {
|
|
641
|
-
throw new CofheError({
|
|
642
|
-
code: "ZK_MOCKS_CREATE_PROOF_SIGNATURE_FAILED" /* ZkMocksCreateProofSignatureFailed */,
|
|
643
|
-
message: `mockZkVerifySign createProofSignatures returned incorrect number of signatures`,
|
|
644
|
-
context: {
|
|
645
|
-
items,
|
|
646
|
-
securityZone
|
|
640
|
+
securityZone,
|
|
641
|
+
consumingContract
|
|
647
642
|
}
|
|
648
643
|
});
|
|
649
644
|
}
|
|
650
|
-
return signatures;
|
|
651
645
|
}
|
|
652
|
-
async function cofheMocksZkVerifySign(items, account, securityZone, publicClient, walletClient, zkvWalletClient) {
|
|
646
|
+
async function cofheMocksZkVerifySign(items, account, securityZone, consumingContract, publicClient, walletClient, zkvWalletClient) {
|
|
653
647
|
const _walletClient = zkvWalletClient ?? createMockZkVerifierSigner();
|
|
654
648
|
const encryptableItems = await calcCtHashes(items, account, securityZone, publicClient);
|
|
655
649
|
await insertCtHashes(encryptableItems, _walletClient);
|
|
656
|
-
const
|
|
657
|
-
return
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
650
|
+
const signature = await createBatchProofSignature(encryptableItems, securityZone, account, consumingContract);
|
|
651
|
+
return {
|
|
652
|
+
outputs: encryptableItems.map((item) => ({
|
|
653
|
+
ct_hash: item.ctHash.toString(),
|
|
654
|
+
ct_type: item.utype
|
|
655
|
+
})),
|
|
656
|
+
signature
|
|
657
|
+
};
|
|
661
658
|
}
|
|
662
659
|
var EnvironmentSchema = zod.z.enum(["MOCK", "TESTNET", "MAINNET"]);
|
|
663
660
|
var CofheChainSchema = zod.z.object({
|
|
@@ -700,8 +697,8 @@ var CofheConfigSchema = zod.z.object({
|
|
|
700
697
|
environment: zod.z.enum(["node", "hardhat", "web", "react"]).optional().default("node"),
|
|
701
698
|
/** List of supported chain configurations */
|
|
702
699
|
supportedChains: zod.z.array(zod.z.custom()),
|
|
703
|
-
/** Default
|
|
704
|
-
|
|
700
|
+
/** Default acp expiration in seconds, default is 30 days */
|
|
701
|
+
defaultACPExpiration: zod.z.number().optional().default(60 * 60 * 24 * 30),
|
|
705
702
|
/** Storage method for fhe keys (defaults to indexedDB on web, filesystem on node) */
|
|
706
703
|
fheKeyStorage: zod.z.object({
|
|
707
704
|
getItem: zod.z.custom((val) => typeof val === "function", {
|
|
@@ -716,6 +713,12 @@ var CofheConfigSchema = zod.z.object({
|
|
|
716
713
|
}).or(zod.z.null()).default(null),
|
|
717
714
|
/** Whether to use Web Workers for ZK proof generation (web platform only) */
|
|
718
715
|
useWorkers: zod.z.boolean().optional().default(true),
|
|
716
|
+
/** ACP acp defaults */
|
|
717
|
+
acp: zod.z.object({
|
|
718
|
+
defaultRevoker: zod.z.custom().optional(),
|
|
719
|
+
defaultContractScopes: zod.z.custom().optional(),
|
|
720
|
+
sharingRegistry: zod.z.custom().optional()
|
|
721
|
+
}).optional().default({}),
|
|
719
722
|
/** Mocks configs */
|
|
720
723
|
mocks: zod.z.object({
|
|
721
724
|
decryptDelay: zod.z.number().optional().default(0),
|
|
@@ -726,8 +729,19 @@ var CofheConfigSchema = zod.z.object({
|
|
|
726
729
|
zkvWalletClient: zod.z.any().optional()
|
|
727
730
|
}).optional()
|
|
728
731
|
});
|
|
732
|
+
var RENAMED_COFHE_CONFIG_KEYS = {
|
|
733
|
+
defaultPermitExpiration: "defaultACPExpiration"
|
|
734
|
+
};
|
|
735
|
+
function assertNoRenamedConfigKeys(config, renamedKeys, label) {
|
|
736
|
+
const stale = Object.keys(config).filter((key) => key in renamedKeys);
|
|
737
|
+
if (stale.length === 0)
|
|
738
|
+
return;
|
|
739
|
+
const renames = stale.map((key) => `\`${key}\` is now \`${renamedKeys[key]}\``).join("; ");
|
|
740
|
+
throw new Error(`Invalid ${label}: ${renames}. See the v0.7.0 migration guide.`);
|
|
741
|
+
}
|
|
729
742
|
function createCofheConfigBase(config) {
|
|
730
|
-
|
|
743
|
+
assertNoRenamedConfigKeys(config, RENAMED_COFHE_CONFIG_KEYS, "cofhe configuration");
|
|
744
|
+
const result = CofheConfigSchema.strict().safeParse(config);
|
|
731
745
|
if (!result.success) {
|
|
732
746
|
throw new Error(`Invalid cofhe configuration: ${zod.z.prettifyError(result.error)}`, { cause: result.error });
|
|
733
747
|
}
|
|
@@ -1076,9 +1090,9 @@ var BaseBuilder = class {
|
|
|
1076
1090
|
// core/encrypt/encryptInputsBuilder.ts
|
|
1077
1091
|
var EncryptInputsBuilder = class extends BaseBuilder {
|
|
1078
1092
|
securityZone;
|
|
1093
|
+
consumingContract;
|
|
1079
1094
|
stepCallback;
|
|
1080
1095
|
inputItems;
|
|
1081
|
-
hpp = false;
|
|
1082
1096
|
zkvWalletClient;
|
|
1083
1097
|
tfhePublicKeyDeserializer;
|
|
1084
1098
|
compactPkeCrsDeserializer;
|
|
@@ -1145,20 +1159,6 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1145
1159
|
this.keysStorage = params.keysStorage;
|
|
1146
1160
|
this.useWorker = params.config?.useWorkers ?? true;
|
|
1147
1161
|
}
|
|
1148
|
-
/**
|
|
1149
|
-
* @param account - Account that will create the tx using the encrypted inputs.
|
|
1150
|
-
*
|
|
1151
|
-
* If not provided, the account will be fetched from the connected walletClient.
|
|
1152
|
-
*
|
|
1153
|
-
* Example:
|
|
1154
|
-
* ```typescript
|
|
1155
|
-
* const encrypted = await encryptInputs([Encryptable.uint128(10n)])
|
|
1156
|
-
* .setAccount("0x123")
|
|
1157
|
-
* .execute();
|
|
1158
|
-
* ```
|
|
1159
|
-
*
|
|
1160
|
-
* @returns The chainable EncryptInputsBuilder instance.
|
|
1161
|
-
*/
|
|
1162
1162
|
setAccount(account) {
|
|
1163
1163
|
this.account = account;
|
|
1164
1164
|
return this;
|
|
@@ -1166,20 +1166,6 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1166
1166
|
getAccount() {
|
|
1167
1167
|
return this.account;
|
|
1168
1168
|
}
|
|
1169
|
-
/**
|
|
1170
|
-
* @param chainId - Chain that will consume the encrypted inputs.
|
|
1171
|
-
*
|
|
1172
|
-
* If not provided, the chainId will be fetched from the connected publicClient.
|
|
1173
|
-
*
|
|
1174
|
-
* Example:
|
|
1175
|
-
* ```typescript
|
|
1176
|
-
* const encrypted = await encryptInputs([Encryptable.uint128(10n)])
|
|
1177
|
-
* .setChainId(11155111)
|
|
1178
|
-
* .execute();
|
|
1179
|
-
* ```
|
|
1180
|
-
*
|
|
1181
|
-
* @returns The chainable EncryptInputsBuilder instance.
|
|
1182
|
-
*/
|
|
1183
1169
|
setChainId(chainId) {
|
|
1184
1170
|
this.chainId = chainId;
|
|
1185
1171
|
return this;
|
|
@@ -1187,20 +1173,6 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1187
1173
|
getChainId() {
|
|
1188
1174
|
return this.chainId;
|
|
1189
1175
|
}
|
|
1190
|
-
/**
|
|
1191
|
-
* @param securityZone - Security zone to encrypt the inputs for.
|
|
1192
|
-
*
|
|
1193
|
-
* If not provided, the default securityZone 0 will be used.
|
|
1194
|
-
*
|
|
1195
|
-
* Example:
|
|
1196
|
-
* ```typescript
|
|
1197
|
-
* const encrypted = await encryptInputs([Encryptable.uint128(10n)])
|
|
1198
|
-
* .setSecurityZone(1)
|
|
1199
|
-
* .execute();
|
|
1200
|
-
* ```
|
|
1201
|
-
*
|
|
1202
|
-
* @returns The chainable EncryptInputsBuilder instance.
|
|
1203
|
-
*/
|
|
1204
1176
|
setSecurityZone(securityZone) {
|
|
1205
1177
|
this.securityZone = securityZone;
|
|
1206
1178
|
return this;
|
|
@@ -1209,33 +1181,44 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1209
1181
|
return this.securityZone;
|
|
1210
1182
|
}
|
|
1211
1183
|
/**
|
|
1184
|
+
* @param address - The contract that will consume the resulting hashes+signature (i.e. the
|
|
1185
|
+
* contract that will call `FHE.asEuint*`/`FHE.asEuint*s` with them).
|
|
1186
|
+
*
|
|
1187
|
+
* Required before `execute()` - the verifier binds this address into the signed digest, so a
|
|
1188
|
+
* batch signed for one contract cannot be replayed into another.
|
|
1189
|
+
*
|
|
1212
1190
|
* Example:
|
|
1213
1191
|
* ```typescript
|
|
1214
1192
|
* const encrypted = await encryptInputs([Encryptable.uint128(10n)])
|
|
1215
|
-
* .
|
|
1193
|
+
* .setConsumingContract("0x123...890")
|
|
1216
1194
|
* .execute();
|
|
1217
1195
|
* ```
|
|
1218
1196
|
*
|
|
1219
|
-
* @returns
|
|
1197
|
+
* @returns The chainable EncryptInputsBuilder instance.
|
|
1220
1198
|
*/
|
|
1221
|
-
|
|
1222
|
-
this.
|
|
1199
|
+
setConsumingContract(address) {
|
|
1200
|
+
this.consumingContract = address;
|
|
1223
1201
|
return this;
|
|
1224
1202
|
}
|
|
1203
|
+
getConsumingContract() {
|
|
1204
|
+
return this.consumingContract;
|
|
1205
|
+
}
|
|
1225
1206
|
/**
|
|
1226
|
-
*
|
|
1227
|
-
*
|
|
1228
|
-
* Overrides the config-level useWorkers setting for this specific encryption.
|
|
1229
|
-
*
|
|
1230
|
-
* Example:
|
|
1231
|
-
* ```typescript
|
|
1232
|
-
* const encrypted = await encryptInputs([Encryptable.uint128(10n)])
|
|
1233
|
-
* .setUseWorker(false)
|
|
1234
|
-
* .execute();
|
|
1235
|
-
* ```
|
|
1236
|
-
*
|
|
1237
|
-
* @returns The chainable EncryptInputsBuilder instance.
|
|
1207
|
+
* Asserts that this.consumingContract is populated
|
|
1208
|
+
* @throws {CofheError} If consumingContract is not set
|
|
1238
1209
|
*/
|
|
1210
|
+
assertConsumingContract() {
|
|
1211
|
+
if (this.consumingContract)
|
|
1212
|
+
return;
|
|
1213
|
+
throw new CofheError({
|
|
1214
|
+
code: "CONSUMING_CONTRACT_UNINITIALIZED" /* ConsumingContractUninitialized */,
|
|
1215
|
+
message: "Consuming contract is not set",
|
|
1216
|
+
hint: "Use setConsumingContract(...) to set the contract that will consume the encrypted inputs.",
|
|
1217
|
+
context: {
|
|
1218
|
+
consumingContract: this.consumingContract
|
|
1219
|
+
}
|
|
1220
|
+
});
|
|
1221
|
+
}
|
|
1239
1222
|
setUseWorker(useWorker) {
|
|
1240
1223
|
this.useWorker = useWorker;
|
|
1241
1224
|
return this;
|
|
@@ -1256,21 +1239,6 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1256
1239
|
getUseWorker() {
|
|
1257
1240
|
return this.useWorker;
|
|
1258
1241
|
}
|
|
1259
|
-
/**
|
|
1260
|
-
* @param callback - Function to be called with the encryption step.
|
|
1261
|
-
*
|
|
1262
|
-
* Useful for debugging and tracking the progress of the encryption process.
|
|
1263
|
-
* Useful for a UI element that shows the progress of the encryption process.
|
|
1264
|
-
*
|
|
1265
|
-
* Example:
|
|
1266
|
-
* ```typescript
|
|
1267
|
-
* const encrypted = await encryptInputs([Encryptable.uint128(10n)])
|
|
1268
|
-
* .onStep((step: EncryptStep) => console.log(step))
|
|
1269
|
-
* .execute();
|
|
1270
|
-
* ```
|
|
1271
|
-
*
|
|
1272
|
-
* @returns The EncryptInputsBuilder instance.
|
|
1273
|
-
*/
|
|
1274
1242
|
onStep(callback) {
|
|
1275
1243
|
this.stepCallback = callback;
|
|
1276
1244
|
return this;
|
|
@@ -1409,6 +1377,7 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1409
1377
|
this.assertAccount();
|
|
1410
1378
|
this.assertPublicClient();
|
|
1411
1379
|
this.assertWalletClient();
|
|
1380
|
+
this.assertConsumingContract();
|
|
1412
1381
|
const [initTfheDelay, fetchKeysDelay, packDelay, proveDelay, verifyDelay] = this.resolveEncryptDelays();
|
|
1413
1382
|
this.fireStepStart("initTfhe" /* InitTfhe */);
|
|
1414
1383
|
await sleep(initTfheDelay);
|
|
@@ -1434,22 +1403,17 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1434
1403
|
this.fireStepEnd("prove" /* Prove */, { isMocks: true, mockSleep: proveDelay });
|
|
1435
1404
|
this.fireStepStart("verify" /* Verify */);
|
|
1436
1405
|
await sleep(verifyDelay);
|
|
1437
|
-
const
|
|
1406
|
+
const result = await cofheMocksZkVerifySign(
|
|
1438
1407
|
this.inputItems,
|
|
1439
1408
|
this.account,
|
|
1440
1409
|
this.securityZone,
|
|
1410
|
+
this.consumingContract,
|
|
1441
1411
|
this.publicClient,
|
|
1442
1412
|
this.walletClient,
|
|
1443
1413
|
this.zkvWalletClient
|
|
1444
1414
|
);
|
|
1445
|
-
const encryptedInputs = signedResults.map(({ ct_hash, signature }, index) => ({
|
|
1446
|
-
ctHash: BigInt(ct_hash),
|
|
1447
|
-
securityZone: this.securityZone,
|
|
1448
|
-
utype: this.inputItems[index].utype,
|
|
1449
|
-
signature
|
|
1450
|
-
}));
|
|
1451
1415
|
this.fireStepEnd("verify" /* Verify */, { isMocks: true, mockSleep: verifyDelay });
|
|
1452
|
-
return
|
|
1416
|
+
return result;
|
|
1453
1417
|
}
|
|
1454
1418
|
/**
|
|
1455
1419
|
* In the production context, perform a true encryption with the CoFHE coprocessor.
|
|
@@ -1457,6 +1421,7 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1457
1421
|
async productionExecute() {
|
|
1458
1422
|
this.assertAccount();
|
|
1459
1423
|
this.assertChainId();
|
|
1424
|
+
this.assertConsumingContract();
|
|
1460
1425
|
this.fireStepStart("initTfhe" /* InitTfhe */);
|
|
1461
1426
|
const tfheInitializationExecuted = await this.initTfheOrThrow();
|
|
1462
1427
|
this.fireStepEnd("initTfhe" /* InitTfhe */, { tfheInitializationExecuted });
|
|
@@ -1491,26 +1456,24 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1491
1456
|
});
|
|
1492
1457
|
this.fireStepStart("verify" /* Verify */);
|
|
1493
1458
|
const zkVerifierUrl = await this.getZkVerifierUrl();
|
|
1494
|
-
const
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
})
|
|
1459
|
+
const result = await zkVerifyBatch(
|
|
1460
|
+
zkVerifierUrl,
|
|
1461
|
+
proof,
|
|
1462
|
+
this.account,
|
|
1463
|
+
this.securityZone,
|
|
1464
|
+
this.chainId,
|
|
1465
|
+
this.consumingContract
|
|
1502
1466
|
);
|
|
1503
1467
|
this.fireStepEnd("verify" /* Verify */);
|
|
1504
|
-
return
|
|
1505
|
-
}
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
return [...hashes, proof];
|
|
1468
|
+
return result;
|
|
1469
|
+
}
|
|
1470
|
+
/**
|
|
1471
|
+
* Converts a batch-verified result (per-item ctHash/ctType + one shared signature) into the
|
|
1472
|
+
* tuple returned by `execute()`: per-item hashes in input order, followed by the single signature.
|
|
1473
|
+
*/
|
|
1474
|
+
buildBatchResult(result) {
|
|
1475
|
+
const hashes = result.outputs.map((output) => "0x" + BigInt(output.ct_hash).toString(16).padStart(64, "0"));
|
|
1476
|
+
return [...hashes, result.signature];
|
|
1514
1477
|
}
|
|
1515
1478
|
/**
|
|
1516
1479
|
* Final step of the encryption process. MUST BE CALLED LAST IN THE CHAIN.
|
|
@@ -1532,18 +1495,16 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1532
1495
|
* @returns The encrypted inputs.
|
|
1533
1496
|
*/
|
|
1534
1497
|
async execute() {
|
|
1535
|
-
let
|
|
1498
|
+
let result;
|
|
1536
1499
|
if (this.chainId === chains.hardhat.id)
|
|
1537
|
-
|
|
1500
|
+
result = await this.mocksExecute();
|
|
1538
1501
|
else
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
return this.structsToHashPlusProof(items);
|
|
1542
|
-
return items;
|
|
1502
|
+
result = await this.productionExecute();
|
|
1503
|
+
return this.buildBatchResult(result);
|
|
1543
1504
|
}
|
|
1544
1505
|
};
|
|
1545
1506
|
|
|
1546
|
-
//
|
|
1507
|
+
// acps/utils.ts
|
|
1547
1508
|
var fromHexString = (hexString) => {
|
|
1548
1509
|
const cleanString = hexString.length % 2 === 1 ? `0${hexString}` : hexString;
|
|
1549
1510
|
const arr = cleanString.replace(/^0x/, "").match(/.{1,2}/g);
|
|
@@ -1563,120 +1524,33 @@ function toBigInt(value) {
|
|
|
1563
1524
|
return value;
|
|
1564
1525
|
}
|
|
1565
1526
|
}
|
|
1566
|
-
function toBeArray(value) {
|
|
1567
|
-
const bigIntValue = typeof value === "number" ? BigInt(value) : value;
|
|
1568
|
-
const hex = bigIntValue.toString(16);
|
|
1569
|
-
const paddedHex = hex.length % 2 === 0 ? hex : "0" + hex;
|
|
1570
|
-
return fromHexString(paddedHex);
|
|
1571
|
-
}
|
|
1572
|
-
function isString(value) {
|
|
1573
|
-
if (typeof value !== "string") {
|
|
1574
|
-
throw new Error(`Expected value which is \`string\`, received value of type \`${typeof value}\`.`);
|
|
1575
|
-
}
|
|
1576
|
-
}
|
|
1577
|
-
function isNumber(value) {
|
|
1578
|
-
const is = typeof value === "number" && !Number.isNaN(value);
|
|
1579
|
-
if (!is) {
|
|
1580
|
-
throw new Error(`Expected value which is \`number\`, received value of type \`${typeof value}\`.`);
|
|
1581
|
-
}
|
|
1582
|
-
}
|
|
1583
|
-
function isBigIntOrNumber(value) {
|
|
1584
|
-
const is = typeof value === "bigint";
|
|
1585
|
-
if (!is) {
|
|
1586
|
-
try {
|
|
1587
|
-
isNumber(value);
|
|
1588
|
-
} catch (e) {
|
|
1589
|
-
throw new Error(`Value ${value} is not a number or bigint: ${typeof value}`);
|
|
1590
|
-
}
|
|
1591
|
-
}
|
|
1592
|
-
}
|
|
1593
1527
|
|
|
1594
|
-
//
|
|
1595
|
-
var
|
|
1596
|
-
var PUBLIC_KEY_LENGTH = 64;
|
|
1597
|
-
var SealingKey = class _SealingKey {
|
|
1598
|
-
/**
|
|
1599
|
-
* The private key used for decryption.
|
|
1600
|
-
*/
|
|
1601
|
-
privateKey;
|
|
1602
|
-
/**
|
|
1603
|
-
* The public key used for encryption.
|
|
1604
|
-
*/
|
|
1605
|
-
publicKey;
|
|
1606
|
-
/**
|
|
1607
|
-
* Constructs a SealingKey instance with the given private and public keys.
|
|
1608
|
-
*
|
|
1609
|
-
* @param {string} privateKey - The private key used for decryption.
|
|
1610
|
-
* @param {string} publicKey - The public key used for encryption.
|
|
1611
|
-
* @throws Will throw an error if the provided keys lengths do not match
|
|
1612
|
-
* the required lengths for private and public keys.
|
|
1613
|
-
*/
|
|
1614
|
-
constructor(privateKey, publicKey) {
|
|
1615
|
-
if (privateKey.length !== PRIVATE_KEY_LENGTH) {
|
|
1616
|
-
throw new Error(`Private key must be of length ${PRIVATE_KEY_LENGTH}`);
|
|
1617
|
-
}
|
|
1618
|
-
if (publicKey.length !== PUBLIC_KEY_LENGTH) {
|
|
1619
|
-
throw new Error(`Public key must be of length ${PUBLIC_KEY_LENGTH}`);
|
|
1620
|
-
}
|
|
1621
|
-
this.privateKey = privateKey;
|
|
1622
|
-
this.publicKey = publicKey;
|
|
1623
|
-
}
|
|
1624
|
-
unseal = (parsedData) => {
|
|
1625
|
-
const nonce = parsedData.nonce instanceof Uint8Array ? parsedData.nonce : new Uint8Array(parsedData.nonce);
|
|
1626
|
-
const ephemPublicKey = parsedData.public_key instanceof Uint8Array ? parsedData.public_key : new Uint8Array(parsedData.public_key);
|
|
1627
|
-
const dataToDecrypt = parsedData.data instanceof Uint8Array ? parsedData.data : new Uint8Array(parsedData.data);
|
|
1628
|
-
const privateKeyBytes = fromHexString(this.privateKey);
|
|
1629
|
-
const decryptedMessage = nacl__default.default.box.open(dataToDecrypt, nonce, ephemPublicKey, privateKeyBytes);
|
|
1630
|
-
if (!decryptedMessage) {
|
|
1631
|
-
throw new Error("Failed to decrypt message");
|
|
1632
|
-
}
|
|
1633
|
-
return toBigInt(decryptedMessage);
|
|
1634
|
-
};
|
|
1635
|
-
/**
|
|
1636
|
-
* Serializes the SealingKey to a JSON object.
|
|
1637
|
-
*/
|
|
1638
|
-
serialize = () => {
|
|
1639
|
-
return {
|
|
1640
|
-
privateKey: this.privateKey,
|
|
1641
|
-
publicKey: this.publicKey
|
|
1642
|
-
};
|
|
1643
|
-
};
|
|
1644
|
-
/**
|
|
1645
|
-
* Deserializes the SealingKey from a JSON object.
|
|
1646
|
-
*/
|
|
1647
|
-
static deserialize = (privateKey, publicKey) => {
|
|
1648
|
-
return new _SealingKey(privateKey, publicKey);
|
|
1649
|
-
};
|
|
1650
|
-
/**
|
|
1651
|
-
* Seals (encrypts) the provided message for a receiver with the specified public key.
|
|
1652
|
-
*
|
|
1653
|
-
* @param {bigint | number} value - The message to be encrypted.
|
|
1654
|
-
* @param {string} publicKey - The public key of the intended recipient.
|
|
1655
|
-
* @returns string - The encrypted message in hexadecimal format.
|
|
1656
|
-
* @static
|
|
1657
|
-
* @throws Will throw if the provided publicKey or value do not meet defined preconditions.
|
|
1658
|
-
*/
|
|
1659
|
-
static seal = (value, publicKey) => {
|
|
1660
|
-
isString(publicKey);
|
|
1661
|
-
isBigIntOrNumber(value);
|
|
1662
|
-
const ephemeralKeyPair = nacl__default.default.box.keyPair();
|
|
1663
|
-
const nonce = nacl__default.default.randomBytes(nacl__default.default.box.nonceLength);
|
|
1664
|
-
const encryptedMessage = nacl__default.default.box(toBeArray(value), nonce, fromHexString(publicKey), ephemeralKeyPair.secretKey);
|
|
1665
|
-
return {
|
|
1666
|
-
data: encryptedMessage,
|
|
1667
|
-
public_key: ephemeralKeyPair.publicKey,
|
|
1668
|
-
nonce
|
|
1669
|
-
};
|
|
1670
|
-
};
|
|
1671
|
-
};
|
|
1528
|
+
// acps/sealing.ts
|
|
1529
|
+
var KEY_HEX_LENGTH = 64;
|
|
1672
1530
|
var GenerateSealingKey = () => {
|
|
1673
1531
|
const sodiumKeypair = nacl__default.default.box.keyPair();
|
|
1674
|
-
return
|
|
1532
|
+
return {
|
|
1533
|
+
privateKey: `0x${toHexString2(sodiumKeypair.secretKey)}`,
|
|
1534
|
+
publicKey: `0x${toHexString2(sodiumKeypair.publicKey)}`
|
|
1535
|
+
};
|
|
1536
|
+
};
|
|
1537
|
+
var unsealWithPrivateKey = (privateKey, parsedData) => {
|
|
1538
|
+
assertKeyLength(privateKey, "Private");
|
|
1539
|
+
const nonce = parsedData.nonce instanceof Uint8Array ? parsedData.nonce : new Uint8Array(parsedData.nonce);
|
|
1540
|
+
const ephemPublicKey = parsedData.public_key instanceof Uint8Array ? parsedData.public_key : new Uint8Array(parsedData.public_key);
|
|
1541
|
+
const dataToDecrypt = parsedData.data instanceof Uint8Array ? parsedData.data : new Uint8Array(parsedData.data);
|
|
1542
|
+
const decryptedMessage = nacl__default.default.box.open(dataToDecrypt, nonce, ephemPublicKey, fromHexString(privateKey));
|
|
1543
|
+
if (!decryptedMessage) {
|
|
1544
|
+
throw new Error("Failed to decrypt message");
|
|
1545
|
+
}
|
|
1546
|
+
return toBigInt(decryptedMessage);
|
|
1547
|
+
};
|
|
1548
|
+
var assertKeyLength = (key, kind) => {
|
|
1549
|
+
const bare = key.startsWith("0x") ? key.slice(2) : key;
|
|
1550
|
+
if (bare.length !== KEY_HEX_LENGTH) {
|
|
1551
|
+
throw new Error(`${kind} key must be of length ${KEY_HEX_LENGTH}`);
|
|
1552
|
+
}
|
|
1675
1553
|
};
|
|
1676
|
-
var SerializedSealingPair = zod.z.object({
|
|
1677
|
-
privateKey: zod.z.string(),
|
|
1678
|
-
publicKey: zod.z.string()
|
|
1679
|
-
});
|
|
1680
1554
|
var addressSchema = zod.z.string().refine((val) => viem.isAddress(val), {
|
|
1681
1555
|
error: "Invalid address"
|
|
1682
1556
|
}).transform((val) => viem.getAddress(val));
|
|
@@ -1695,46 +1569,70 @@ var bytesNotEmptySchema = bytesSchema.refine((val) => val !== "0x", {
|
|
|
1695
1569
|
error: "Must not be empty"
|
|
1696
1570
|
});
|
|
1697
1571
|
var DEFAULT_EXPIRATION_FN = () => Math.round(Date.now() / 1e3) + 7 * 24 * 60 * 60;
|
|
1698
|
-
var
|
|
1699
|
-
|
|
1572
|
+
var handlesSchema = zod.z.array(zod.z.string().regex(/^0x[0-9a-fA-F]{64}$/, "Invalid handle: expected 32-byte hex")).optional().default([]);
|
|
1573
|
+
var contractsSchema = zod.z.array(addressSchema).optional().default([]);
|
|
1574
|
+
var SCOPE_GLOBAL = 0;
|
|
1575
|
+
var SCOPE_CONTRACT = 1;
|
|
1576
|
+
var SCOPE_HANDLES = 2;
|
|
1577
|
+
var ScopeConsistencyRefinement = [
|
|
1578
|
+
(data) => data.scope === SCOPE_GLOBAL && data.contracts.length === 0 && data.handles.length === 0 || data.scope === SCOPE_CONTRACT && data.contracts.length > 0 && data.handles.length === 0 || data.scope === SCOPE_HANDLES && data.handles.length > 0 && data.contracts.length === 0,
|
|
1579
|
+
{
|
|
1580
|
+
error: "ACP scope :: arrays must match the scope mode (Global: both empty; Contract: contracts only; Handles: handles only)",
|
|
1581
|
+
path: ["scope"]
|
|
1582
|
+
}
|
|
1583
|
+
];
|
|
1584
|
+
var withDerivedScope = (data) => ({
|
|
1585
|
+
...data,
|
|
1586
|
+
scope: data.scope ?? (data.contracts.length > 0 ? SCOPE_CONTRACT : data.handles.length > 0 ? SCOPE_HANDLES : SCOPE_GLOBAL)
|
|
1587
|
+
});
|
|
1588
|
+
var zACPWithDefaults = zod.z.object({
|
|
1589
|
+
name: zod.z.string().optional().default("Unnamed ACP"),
|
|
1700
1590
|
type: zod.z.enum(["self", "sharing", "recipient"]),
|
|
1701
1591
|
issuer: addressNotZeroSchema,
|
|
1702
1592
|
expiration: zod.z.int().optional().default(DEFAULT_EXPIRATION_FN),
|
|
1703
1593
|
recipient: addressSchema.optional().default(viem.zeroAddress),
|
|
1704
|
-
|
|
1705
|
-
|
|
1594
|
+
revokerData: zod.z.int().optional().default(0),
|
|
1595
|
+
revokerContract: addressSchema.optional().default(viem.zeroAddress),
|
|
1596
|
+
scope: zod.z.int().min(0).max(2).optional().default(0),
|
|
1597
|
+
contracts: contractsSchema,
|
|
1598
|
+
handles: handlesSchema,
|
|
1706
1599
|
issuerSignature: bytesSchema.optional().default("0x"),
|
|
1707
1600
|
recipientSignature: bytesSchema.optional().default("0x")
|
|
1708
1601
|
});
|
|
1709
|
-
var
|
|
1710
|
-
|
|
1602
|
+
var zACPWithSealingKeys = zACPWithDefaults.extend({
|
|
1603
|
+
/** X25519 private key, 0x-prefixed 32-byte hex; never leaves the client */
|
|
1604
|
+
sealingPrivateKey: zod.z.string().regex(/^0x[0-9a-fA-F]{64}$/, "Invalid sealing private key").optional(),
|
|
1605
|
+
sealingKey: zod.z.string().regex(/^0x[0-9a-fA-F]{64}$/, "Invalid sealing key").optional()
|
|
1711
1606
|
});
|
|
1712
1607
|
var ExternalValidatorRefinement = [
|
|
1713
|
-
(data) => data.
|
|
1608
|
+
(data) => data.revokerData !== 0 && data.revokerContract !== viem.zeroAddress || data.revokerData === 0 && data.revokerContract === viem.zeroAddress,
|
|
1714
1609
|
{
|
|
1715
|
-
error: "
|
|
1716
|
-
path: ["
|
|
1610
|
+
error: "ACP external revoker :: revokerData and revokerContract must either both be set or both be unset.",
|
|
1611
|
+
path: ["revokerData", "revokerContract"]
|
|
1717
1612
|
}
|
|
1718
1613
|
];
|
|
1719
1614
|
var RecipientRefinement = [
|
|
1720
1615
|
(data) => data.issuer !== data.recipient,
|
|
1721
1616
|
{
|
|
1722
|
-
error: "Sharing
|
|
1617
|
+
error: "Sharing acp :: issuer and recipient must not be the same",
|
|
1723
1618
|
path: ["issuer", "recipient"]
|
|
1724
1619
|
}
|
|
1725
1620
|
];
|
|
1726
|
-
var
|
|
1621
|
+
var SelfACPOptionsValidator = zod.z.object({
|
|
1727
1622
|
type: zod.z.literal("self").optional().default("self"),
|
|
1728
1623
|
issuer: addressNotZeroSchema,
|
|
1729
|
-
name: zod.z.string().optional().default("Unnamed
|
|
1624
|
+
name: zod.z.string().optional().default("Unnamed ACP"),
|
|
1730
1625
|
expiration: zod.z.int().optional().default(DEFAULT_EXPIRATION_FN),
|
|
1731
1626
|
recipient: addressSchema.optional().default(viem.zeroAddress),
|
|
1732
|
-
|
|
1733
|
-
|
|
1627
|
+
revokerData: zod.z.int().optional().default(0),
|
|
1628
|
+
revokerContract: addressSchema.optional().default(viem.zeroAddress),
|
|
1629
|
+
scope: zod.z.int().min(0).max(2).optional(),
|
|
1630
|
+
contracts: contractsSchema,
|
|
1631
|
+
handles: handlesSchema,
|
|
1734
1632
|
issuerSignature: bytesSchema.optional().default("0x"),
|
|
1735
1633
|
recipientSignature: bytesSchema.optional().default("0x")
|
|
1736
|
-
}).refine(...ExternalValidatorRefinement);
|
|
1737
|
-
var
|
|
1634
|
+
}).refine(...ExternalValidatorRefinement).transform(withDerivedScope).refine(...ScopeConsistencyRefinement);
|
|
1635
|
+
var SelfACPValidator = zACPWithSealingKeys.refine((data) => data.type === "self", {
|
|
1738
1636
|
error: "Type must be 'self'"
|
|
1739
1637
|
}).refine((data) => data.recipient === viem.zeroAddress, {
|
|
1740
1638
|
error: "Recipient must be zeroAddress"
|
|
@@ -1743,18 +1641,21 @@ var SelfPermitValidator = zPermitWithSealingPair.refine((data) => data.type ===
|
|
|
1743
1641
|
}).refine((data) => data.recipientSignature === "0x", {
|
|
1744
1642
|
error: "RecipientSignature must be empty"
|
|
1745
1643
|
}).refine(...ExternalValidatorRefinement);
|
|
1746
|
-
var
|
|
1644
|
+
var SharingACPOptionsValidator = zod.z.object({
|
|
1747
1645
|
type: zod.z.literal("sharing").optional().default("sharing"),
|
|
1748
1646
|
issuer: addressNotZeroSchema,
|
|
1749
1647
|
recipient: addressNotZeroSchema,
|
|
1750
|
-
name: zod.z.string().optional().default("Unnamed
|
|
1648
|
+
name: zod.z.string().optional().default("Unnamed ACP"),
|
|
1751
1649
|
expiration: zod.z.int().optional().default(DEFAULT_EXPIRATION_FN),
|
|
1752
|
-
|
|
1753
|
-
|
|
1650
|
+
revokerData: zod.z.int().optional().default(0),
|
|
1651
|
+
revokerContract: addressSchema.optional().default(viem.zeroAddress),
|
|
1652
|
+
scope: zod.z.int().min(0).max(2).optional(),
|
|
1653
|
+
contracts: contractsSchema,
|
|
1654
|
+
handles: handlesSchema,
|
|
1754
1655
|
issuerSignature: bytesSchema.optional().default("0x"),
|
|
1755
1656
|
recipientSignature: bytesSchema.optional().default("0x")
|
|
1756
|
-
}).refine(...RecipientRefinement).refine(...ExternalValidatorRefinement);
|
|
1757
|
-
var
|
|
1657
|
+
}).refine(...RecipientRefinement).refine(...ExternalValidatorRefinement).transform(withDerivedScope).refine(...ScopeConsistencyRefinement);
|
|
1658
|
+
var SharingACPValidator = zACPWithSealingKeys.refine((data) => data.type === "sharing", {
|
|
1758
1659
|
error: "Type must be 'sharing'"
|
|
1759
1660
|
}).refine((data) => data.recipient !== viem.zeroAddress, {
|
|
1760
1661
|
error: "Recipient must not be zeroAddress"
|
|
@@ -1763,18 +1664,21 @@ var SharingPermitValidator = zPermitWithSealingPair.refine((data) => data.type =
|
|
|
1763
1664
|
}).refine((data) => data.recipientSignature === "0x", {
|
|
1764
1665
|
error: "RecipientSignature must be empty"
|
|
1765
1666
|
}).refine(...ExternalValidatorRefinement);
|
|
1766
|
-
var
|
|
1667
|
+
var ImportACPOptionsValidator = zod.z.object({
|
|
1767
1668
|
type: zod.z.literal("recipient").optional().default("recipient"),
|
|
1768
1669
|
issuer: addressNotZeroSchema,
|
|
1769
1670
|
recipient: addressNotZeroSchema,
|
|
1770
|
-
name: zod.z.string().optional().default("Unnamed
|
|
1671
|
+
name: zod.z.string().optional().default("Unnamed ACP"),
|
|
1771
1672
|
expiration: zod.z.int(),
|
|
1772
|
-
|
|
1773
|
-
|
|
1673
|
+
revokerData: zod.z.int().optional().default(0),
|
|
1674
|
+
revokerContract: addressSchema.optional().default(viem.zeroAddress),
|
|
1675
|
+
scope: zod.z.int().min(0).max(2).optional(),
|
|
1676
|
+
contracts: contractsSchema,
|
|
1677
|
+
handles: handlesSchema,
|
|
1774
1678
|
issuerSignature: bytesNotEmptySchema,
|
|
1775
1679
|
recipientSignature: bytesSchema.optional().default("0x")
|
|
1776
|
-
}).refine(...ExternalValidatorRefinement);
|
|
1777
|
-
var
|
|
1680
|
+
}).refine(...ExternalValidatorRefinement).transform(withDerivedScope).refine(...ScopeConsistencyRefinement);
|
|
1681
|
+
var ImportACPValidator = zACPWithSealingKeys.refine((data) => data.type === "recipient", {
|
|
1778
1682
|
error: "Type must be 'recipient'"
|
|
1779
1683
|
}).refine((data) => data.recipient !== viem.zeroAddress, {
|
|
1780
1684
|
error: "Recipient must not be zeroAddress"
|
|
@@ -1790,116 +1694,125 @@ var safeParseAndThrowFormatted = (schema, data, message) => {
|
|
|
1790
1694
|
}
|
|
1791
1695
|
return result.data;
|
|
1792
1696
|
};
|
|
1793
|
-
var
|
|
1794
|
-
return safeParseAndThrowFormatted(
|
|
1697
|
+
var validateSelfACPOptions = (options) => {
|
|
1698
|
+
return safeParseAndThrowFormatted(SelfACPOptionsValidator, options, "Invalid self acp options");
|
|
1795
1699
|
};
|
|
1796
|
-
var
|
|
1797
|
-
return safeParseAndThrowFormatted(
|
|
1700
|
+
var validateSharingACPOptions = (options) => {
|
|
1701
|
+
return safeParseAndThrowFormatted(SharingACPOptionsValidator, options, "Invalid sharing acp options");
|
|
1798
1702
|
};
|
|
1799
|
-
var
|
|
1800
|
-
return safeParseAndThrowFormatted(
|
|
1703
|
+
var validateImportACPOptions = (options) => {
|
|
1704
|
+
return safeParseAndThrowFormatted(ImportACPOptionsValidator, options, "Invalid import acp options");
|
|
1801
1705
|
};
|
|
1802
|
-
var
|
|
1803
|
-
return safeParseAndThrowFormatted(
|
|
1706
|
+
var validateSelfACP = (acp) => {
|
|
1707
|
+
return safeParseAndThrowFormatted(SelfACPValidator, acp, "Invalid self acp");
|
|
1804
1708
|
};
|
|
1805
|
-
var
|
|
1806
|
-
return safeParseAndThrowFormatted(
|
|
1709
|
+
var validateSharingACP = (acp) => {
|
|
1710
|
+
return safeParseAndThrowFormatted(SharingACPValidator, acp, "Invalid sharing acp");
|
|
1807
1711
|
};
|
|
1808
|
-
var
|
|
1809
|
-
return safeParseAndThrowFormatted(
|
|
1712
|
+
var validateImportACP = (acp) => {
|
|
1713
|
+
return safeParseAndThrowFormatted(ImportACPValidator, acp, "Invalid import acp");
|
|
1810
1714
|
};
|
|
1811
1715
|
var ValidationUtils = {
|
|
1812
1716
|
/**
|
|
1813
|
-
* Check if
|
|
1717
|
+
* Check if acp is expired
|
|
1814
1718
|
*/
|
|
1815
|
-
isExpired: (
|
|
1816
|
-
return
|
|
1719
|
+
isExpired: (acp) => {
|
|
1720
|
+
return acp.expiration < Math.floor(Date.now() / 1e3);
|
|
1817
1721
|
},
|
|
1818
1722
|
/**
|
|
1819
|
-
* Check if
|
|
1723
|
+
* Check if acp is signed by the active party
|
|
1820
1724
|
*/
|
|
1821
|
-
isSigned: (
|
|
1822
|
-
if (
|
|
1823
|
-
return
|
|
1725
|
+
isSigned: (acp) => {
|
|
1726
|
+
if (acp.type === "self" || acp.type === "sharing") {
|
|
1727
|
+
return acp.issuerSignature !== "0x";
|
|
1824
1728
|
}
|
|
1825
|
-
if (
|
|
1826
|
-
return
|
|
1729
|
+
if (acp.type === "recipient") {
|
|
1730
|
+
return acp.recipientSignature !== "0x";
|
|
1827
1731
|
}
|
|
1828
1732
|
return false;
|
|
1829
1733
|
},
|
|
1830
1734
|
/**
|
|
1831
|
-
* Checks that
|
|
1735
|
+
* Checks that an ACP is signed and not expired.
|
|
1832
1736
|
*/
|
|
1833
|
-
isSignedAndNotExpired: (
|
|
1834
|
-
if (ValidationUtils.isExpired(
|
|
1737
|
+
isSignedAndNotExpired: (acp) => {
|
|
1738
|
+
if (ValidationUtils.isExpired(acp)) {
|
|
1835
1739
|
return { valid: false, error: "expired" };
|
|
1836
1740
|
}
|
|
1837
|
-
if (!ValidationUtils.isSigned(
|
|
1741
|
+
if (!ValidationUtils.isSigned(acp)) {
|
|
1838
1742
|
return { valid: false, error: "not-signed" };
|
|
1839
1743
|
}
|
|
1840
1744
|
return { valid: true, error: null };
|
|
1841
1745
|
},
|
|
1842
1746
|
/**
|
|
1843
|
-
* Asserts that
|
|
1747
|
+
* Asserts that an ACP is signed and not expired.
|
|
1844
1748
|
*
|
|
1845
1749
|
* Throws `Error` with message:
|
|
1846
|
-
* - `
|
|
1847
|
-
* - `
|
|
1750
|
+
* - `ACP is expired`
|
|
1751
|
+
* - `ACP is not signed`
|
|
1848
1752
|
*/
|
|
1849
|
-
assertSignedAndNotExpired: (
|
|
1850
|
-
const result = ValidationUtils.isSignedAndNotExpired(
|
|
1753
|
+
assertSignedAndNotExpired: (acp) => {
|
|
1754
|
+
const result = ValidationUtils.isSignedAndNotExpired(acp);
|
|
1851
1755
|
if (result.valid)
|
|
1852
1756
|
return;
|
|
1853
1757
|
if (result.error === "expired") {
|
|
1854
|
-
throw new Error("
|
|
1758
|
+
throw new Error("ACP is expired");
|
|
1855
1759
|
}
|
|
1856
1760
|
if (result.error === "not-signed") {
|
|
1857
|
-
throw new Error("
|
|
1761
|
+
throw new Error("ACP is not signed");
|
|
1858
1762
|
}
|
|
1859
|
-
throw new Error("
|
|
1763
|
+
throw new Error("ACP is invalid");
|
|
1860
1764
|
},
|
|
1861
|
-
isValid: (
|
|
1862
|
-
const schema =
|
|
1765
|
+
isValid: (acp) => {
|
|
1766
|
+
const schema = acp.type === "self" ? SelfACPValidator : acp.type === "sharing" ? SharingACPValidator : acp.type === "recipient" ? ImportACPValidator : null;
|
|
1863
1767
|
if (schema == null)
|
|
1864
1768
|
return { valid: false, error: "invalid-schema" };
|
|
1865
|
-
const schemaResult = schema.safeParse(
|
|
1769
|
+
const schemaResult = schema.safeParse(acp);
|
|
1866
1770
|
if (!schemaResult.success)
|
|
1867
1771
|
return { valid: false, error: "invalid-schema" };
|
|
1868
|
-
return ValidationUtils.isSignedAndNotExpired(
|
|
1772
|
+
return ValidationUtils.isSignedAndNotExpired(acp);
|
|
1869
1773
|
}
|
|
1870
1774
|
};
|
|
1871
1775
|
|
|
1872
|
-
//
|
|
1873
|
-
var
|
|
1776
|
+
// acps/signature.ts
|
|
1777
|
+
var ACPSignatureAllFields = [
|
|
1874
1778
|
{ name: "issuer", type: "address" },
|
|
1875
1779
|
{ name: "expiration", type: "uint64" },
|
|
1876
1780
|
{ name: "recipient", type: "address" },
|
|
1877
|
-
{ name: "
|
|
1878
|
-
{ name: "
|
|
1781
|
+
{ name: "revokerData", type: "uint256" },
|
|
1782
|
+
{ name: "revokerContract", type: "address" },
|
|
1783
|
+
{ name: "scope", type: "uint8" },
|
|
1784
|
+
{ name: "contracts", type: "address[]" },
|
|
1785
|
+
{ name: "handles", type: "bytes32[]" },
|
|
1879
1786
|
{ name: "sealingKey", type: "bytes32" },
|
|
1880
1787
|
{ name: "issuerSignature", type: "bytes" }
|
|
1881
1788
|
];
|
|
1882
1789
|
var SignatureTypes = {
|
|
1883
|
-
|
|
1790
|
+
ACPIssuerSelf: [
|
|
1884
1791
|
"issuer",
|
|
1885
1792
|
"expiration",
|
|
1886
1793
|
"recipient",
|
|
1887
|
-
"
|
|
1888
|
-
"
|
|
1794
|
+
"revokerData",
|
|
1795
|
+
"revokerContract",
|
|
1796
|
+
"scope",
|
|
1797
|
+
"contracts",
|
|
1798
|
+
"handles",
|
|
1889
1799
|
"sealingKey"
|
|
1890
1800
|
],
|
|
1891
|
-
|
|
1801
|
+
ACPIssuerShared: [
|
|
1892
1802
|
"issuer",
|
|
1893
1803
|
"expiration",
|
|
1894
1804
|
"recipient",
|
|
1895
|
-
"
|
|
1896
|
-
"
|
|
1805
|
+
"revokerData",
|
|
1806
|
+
"revokerContract",
|
|
1807
|
+
"scope",
|
|
1808
|
+
"contracts",
|
|
1809
|
+
"handles"
|
|
1897
1810
|
],
|
|
1898
|
-
|
|
1811
|
+
ACPRecipient: ["sealingKey", "issuerSignature"]
|
|
1899
1812
|
};
|
|
1900
1813
|
var getSignatureTypesAndMessage = (primaryType, fields, values) => {
|
|
1901
1814
|
const types = {
|
|
1902
|
-
[primaryType]:
|
|
1815
|
+
[primaryType]: ACPSignatureAllFields.filter((fieldType) => fields.includes(fieldType.name))
|
|
1903
1816
|
};
|
|
1904
1817
|
const message = {};
|
|
1905
1818
|
fields.forEach((field) => {
|
|
@@ -1911,22 +1824,22 @@ var getSignatureTypesAndMessage = (primaryType, fields, values) => {
|
|
|
1911
1824
|
};
|
|
1912
1825
|
var SignatureUtils = {
|
|
1913
1826
|
/**
|
|
1914
|
-
* Get signature parameters for
|
|
1827
|
+
* Get signature parameters for an ACP
|
|
1915
1828
|
*/
|
|
1916
|
-
getSignatureParams: (
|
|
1917
|
-
return getSignatureTypesAndMessage(primaryType, SignatureTypes[primaryType],
|
|
1829
|
+
getSignatureParams: (acp, primaryType) => {
|
|
1830
|
+
return getSignatureTypesAndMessage(primaryType, SignatureTypes[primaryType], acp);
|
|
1918
1831
|
},
|
|
1919
1832
|
/**
|
|
1920
|
-
* Determine the required signature type based on
|
|
1833
|
+
* Determine the required signature type based on acp type
|
|
1921
1834
|
*/
|
|
1922
|
-
getPrimaryType: (
|
|
1923
|
-
if (
|
|
1924
|
-
return "
|
|
1925
|
-
if (
|
|
1926
|
-
return "
|
|
1927
|
-
if (
|
|
1928
|
-
return "
|
|
1929
|
-
throw new Error(`Unknown
|
|
1835
|
+
getPrimaryType: (acpType) => {
|
|
1836
|
+
if (acpType === "self")
|
|
1837
|
+
return "ACPIssuerSelf";
|
|
1838
|
+
if (acpType === "sharing")
|
|
1839
|
+
return "ACPIssuerShared";
|
|
1840
|
+
if (acpType === "recipient")
|
|
1841
|
+
return "ACPRecipient";
|
|
1842
|
+
throw new Error(`Unknown acp type: ${acpType}`);
|
|
1930
1843
|
}
|
|
1931
1844
|
};
|
|
1932
1845
|
var getAclAddress = async (publicClient) => {
|
|
@@ -1948,6 +1861,11 @@ var getAclEIP712Domain = async (publicClient) => {
|
|
|
1948
1861
|
functionName: "eip712Domain"
|
|
1949
1862
|
});
|
|
1950
1863
|
const [_fields, name, version, chainId, verifyingContract, _salt, _extensions] = domain;
|
|
1864
|
+
if (version !== "2") {
|
|
1865
|
+
throw new Error(
|
|
1866
|
+
`Chain ${chainId}'s ACL serves EIP-712 domain version "${version}" \u2014 this SDK requires the upgraded (ACP-era) ACL, which signs as version "2". Pre-upgrade (V2 Permission) chains are not supported.`
|
|
1867
|
+
);
|
|
1868
|
+
}
|
|
1951
1869
|
return {
|
|
1952
1870
|
name,
|
|
1953
1871
|
version,
|
|
@@ -1955,23 +1873,26 @@ var getAclEIP712Domain = async (publicClient) => {
|
|
|
1955
1873
|
verifyingContract
|
|
1956
1874
|
};
|
|
1957
1875
|
};
|
|
1958
|
-
var
|
|
1876
|
+
var checkACPValidityOnChain = async (acp, publicClient) => {
|
|
1959
1877
|
const aclAddress = await getAclAddress(publicClient);
|
|
1960
1878
|
try {
|
|
1961
1879
|
await publicClient.simulateContract({
|
|
1962
1880
|
address: aclAddress,
|
|
1963
|
-
abi:
|
|
1964
|
-
functionName: "
|
|
1881
|
+
abi: checkACPValidityAbi,
|
|
1882
|
+
functionName: "checkPermissionValidity",
|
|
1965
1883
|
args: [
|
|
1966
1884
|
{
|
|
1967
|
-
issuer:
|
|
1968
|
-
expiration: BigInt(
|
|
1969
|
-
recipient:
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1885
|
+
issuer: acp.issuer,
|
|
1886
|
+
expiration: BigInt(acp.expiration),
|
|
1887
|
+
recipient: acp.recipient,
|
|
1888
|
+
revokerData: BigInt(acp.revokerData),
|
|
1889
|
+
revokerContract: acp.revokerContract,
|
|
1890
|
+
scope: acp.scope,
|
|
1891
|
+
contracts: acp.contracts,
|
|
1892
|
+
handles: acp.handles,
|
|
1893
|
+
sealingKey: acp.sealingKey,
|
|
1894
|
+
issuerSignature: acp.issuerSignature,
|
|
1895
|
+
recipientSignature: acp.recipientSignature
|
|
1975
1896
|
}
|
|
1976
1897
|
]
|
|
1977
1898
|
});
|
|
@@ -1984,14 +1905,14 @@ var checkPermitValidityOnChain = async (permission, publicClient) => {
|
|
|
1984
1905
|
throw new Error(errorName);
|
|
1985
1906
|
}
|
|
1986
1907
|
}
|
|
1987
|
-
const customErrorName = extractCustomErrorFromDetails(err,
|
|
1908
|
+
const customErrorName = extractCustomErrorFromDetails(err, checkACPValidityAbi);
|
|
1988
1909
|
if (customErrorName) {
|
|
1989
1910
|
throw new Error(customErrorName);
|
|
1990
1911
|
}
|
|
1991
1912
|
const hhDetailsData = extractReturnData(err);
|
|
1992
1913
|
if (hhDetailsData != null) {
|
|
1993
1914
|
const decoded = viem.decodeErrorResult({
|
|
1994
|
-
abi:
|
|
1915
|
+
abi: checkACPValidityAbi,
|
|
1995
1916
|
data: hhDetailsData
|
|
1996
1917
|
});
|
|
1997
1918
|
throw new Error(decoded.errorName);
|
|
@@ -2019,15 +1940,15 @@ function extractReturnData(err) {
|
|
|
2019
1940
|
const s = anyErr?.details ?? anyErr?.cause?.details ?? anyErr?.shortMessage ?? anyErr?.message ?? String(err);
|
|
2020
1941
|
return s.match(/return data:\s*(0x[a-fA-F0-9]+)/)?.[1];
|
|
2021
1942
|
}
|
|
2022
|
-
var
|
|
1943
|
+
var checkACPValidityAbi = [
|
|
2023
1944
|
{
|
|
2024
1945
|
type: "function",
|
|
2025
|
-
name: "
|
|
1946
|
+
name: "checkPermissionValidity",
|
|
2026
1947
|
inputs: [
|
|
2027
1948
|
{
|
|
2028
|
-
name: "
|
|
1949
|
+
name: "acp",
|
|
2029
1950
|
type: "tuple",
|
|
2030
|
-
internalType: "struct
|
|
1951
|
+
internalType: "struct ACP",
|
|
2031
1952
|
components: [
|
|
2032
1953
|
{
|
|
2033
1954
|
name: "issuer",
|
|
@@ -2045,15 +1966,30 @@ var checkPermitValidityAbi = [
|
|
|
2045
1966
|
internalType: "address"
|
|
2046
1967
|
},
|
|
2047
1968
|
{
|
|
2048
|
-
name: "
|
|
1969
|
+
name: "revokerData",
|
|
2049
1970
|
type: "uint256",
|
|
2050
1971
|
internalType: "uint256"
|
|
2051
1972
|
},
|
|
2052
1973
|
{
|
|
2053
|
-
name: "
|
|
1974
|
+
name: "revokerContract",
|
|
2054
1975
|
type: "address",
|
|
2055
1976
|
internalType: "address"
|
|
2056
1977
|
},
|
|
1978
|
+
{
|
|
1979
|
+
name: "scope",
|
|
1980
|
+
type: "uint8",
|
|
1981
|
+
internalType: "uint8"
|
|
1982
|
+
},
|
|
1983
|
+
{
|
|
1984
|
+
name: "contracts",
|
|
1985
|
+
type: "address[]",
|
|
1986
|
+
internalType: "address[]"
|
|
1987
|
+
},
|
|
1988
|
+
{
|
|
1989
|
+
name: "handles",
|
|
1990
|
+
type: "bytes32[]",
|
|
1991
|
+
internalType: "bytes32[]"
|
|
1992
|
+
},
|
|
2057
1993
|
{
|
|
2058
1994
|
name: "sealingKey",
|
|
2059
1995
|
type: "bytes32",
|
|
@@ -2103,38 +2039,40 @@ var checkPermitValidityAbi = [
|
|
|
2103
2039
|
}
|
|
2104
2040
|
];
|
|
2105
2041
|
|
|
2106
|
-
//
|
|
2107
|
-
var
|
|
2042
|
+
// acps/acp.ts
|
|
2043
|
+
var ACPUtils = {
|
|
2108
2044
|
/**
|
|
2109
|
-
* Create a self
|
|
2045
|
+
* Create a self acp for personal use
|
|
2110
2046
|
*/
|
|
2111
2047
|
createSelf: (options) => {
|
|
2112
|
-
const validation =
|
|
2048
|
+
const validation = validateSelfACPOptions(options);
|
|
2113
2049
|
const sealingPair = GenerateSealingKey();
|
|
2114
|
-
const
|
|
2115
|
-
hash:
|
|
2050
|
+
const acp = {
|
|
2051
|
+
hash: ACPUtils.getHash(validation),
|
|
2116
2052
|
...validation,
|
|
2117
|
-
sealingPair,
|
|
2053
|
+
sealingPrivateKey: sealingPair.privateKey,
|
|
2054
|
+
sealingKey: sealingPair.publicKey,
|
|
2118
2055
|
_signedDomain: void 0
|
|
2119
2056
|
};
|
|
2120
|
-
return
|
|
2057
|
+
return acp;
|
|
2121
2058
|
},
|
|
2122
2059
|
/**
|
|
2123
|
-
* Create a sharing
|
|
2060
|
+
* Create a sharing acp to be shared with another user
|
|
2124
2061
|
*/
|
|
2125
2062
|
createSharing: (options) => {
|
|
2126
|
-
const validation =
|
|
2063
|
+
const validation = validateSharingACPOptions(options);
|
|
2127
2064
|
const sealingPair = GenerateSealingKey();
|
|
2128
|
-
const
|
|
2129
|
-
hash:
|
|
2065
|
+
const acp = {
|
|
2066
|
+
hash: ACPUtils.getHash(validation),
|
|
2130
2067
|
...validation,
|
|
2131
|
-
sealingPair,
|
|
2068
|
+
sealingPrivateKey: sealingPair.privateKey,
|
|
2069
|
+
sealingKey: sealingPair.publicKey,
|
|
2132
2070
|
_signedDomain: void 0
|
|
2133
2071
|
};
|
|
2134
|
-
return
|
|
2072
|
+
return acp;
|
|
2135
2073
|
},
|
|
2136
2074
|
/**
|
|
2137
|
-
* Import a shared
|
|
2075
|
+
* Import a shared acp from various input formats
|
|
2138
2076
|
*/
|
|
2139
2077
|
importShared: (options) => {
|
|
2140
2078
|
let parsedOptions;
|
|
@@ -2147,33 +2085,34 @@ var PermitUtils = {
|
|
|
2147
2085
|
} else if (typeof options === "object" && options !== null) {
|
|
2148
2086
|
parsedOptions = options;
|
|
2149
2087
|
} else {
|
|
2150
|
-
throw new Error("Invalid input type, expected
|
|
2088
|
+
throw new Error("Invalid input type, expected ImportSharedACPOptions, object, or string");
|
|
2151
2089
|
}
|
|
2152
2090
|
if (parsedOptions.type != null && parsedOptions.type !== "sharing") {
|
|
2153
|
-
throw new Error(`Invalid
|
|
2091
|
+
throw new Error(`Invalid acp type <${parsedOptions.type}>, must be "sharing"`);
|
|
2154
2092
|
}
|
|
2155
|
-
const validation =
|
|
2093
|
+
const validation = validateImportACPOptions({ ...parsedOptions, type: "recipient" });
|
|
2156
2094
|
const sealingPair = GenerateSealingKey();
|
|
2157
|
-
const
|
|
2158
|
-
hash:
|
|
2095
|
+
const acp = {
|
|
2096
|
+
hash: ACPUtils.getHash(validation),
|
|
2159
2097
|
...validation,
|
|
2160
|
-
sealingPair,
|
|
2098
|
+
sealingPrivateKey: sealingPair.privateKey,
|
|
2099
|
+
sealingKey: sealingPair.publicKey,
|
|
2161
2100
|
_signedDomain: void 0
|
|
2162
2101
|
};
|
|
2163
|
-
return
|
|
2102
|
+
return acp;
|
|
2164
2103
|
},
|
|
2165
2104
|
/**
|
|
2166
|
-
* Sign
|
|
2105
|
+
* Sign an ACP with the provided wallet client
|
|
2167
2106
|
*/
|
|
2168
|
-
sign: async (
|
|
2107
|
+
sign: async (acp, publicClient, walletClient) => {
|
|
2169
2108
|
if (walletClient == null || walletClient.account == null) {
|
|
2170
2109
|
throw new Error(
|
|
2171
|
-
"Missing walletClient, you must pass in a `walletClient` for the connected user to create
|
|
2110
|
+
"Missing walletClient, you must pass in a `walletClient` for the connected user to create an ACP signature"
|
|
2172
2111
|
);
|
|
2173
2112
|
}
|
|
2174
|
-
const primaryType = SignatureUtils.getPrimaryType(
|
|
2113
|
+
const primaryType = SignatureUtils.getPrimaryType(acp.type);
|
|
2175
2114
|
const domain = await getAclEIP712Domain(publicClient);
|
|
2176
|
-
const { types, message } = SignatureUtils.getSignatureParams(
|
|
2115
|
+
const { types, message } = SignatureUtils.getSignatureParams(ACPUtils.getPublic(acp, true), primaryType);
|
|
2177
2116
|
const signature = await walletClient.signTypedData({
|
|
2178
2117
|
domain,
|
|
2179
2118
|
types,
|
|
@@ -2181,190 +2120,209 @@ var PermitUtils = {
|
|
|
2181
2120
|
message,
|
|
2182
2121
|
account: walletClient.account
|
|
2183
2122
|
});
|
|
2184
|
-
let
|
|
2185
|
-
if (
|
|
2186
|
-
|
|
2187
|
-
...
|
|
2123
|
+
let updatedACP;
|
|
2124
|
+
if (acp.type === "self" || acp.type === "sharing") {
|
|
2125
|
+
updatedACP = {
|
|
2126
|
+
...acp,
|
|
2188
2127
|
issuerSignature: signature,
|
|
2189
2128
|
_signedDomain: domain
|
|
2190
2129
|
};
|
|
2191
2130
|
} else {
|
|
2192
|
-
|
|
2193
|
-
...
|
|
2131
|
+
updatedACP = {
|
|
2132
|
+
...acp,
|
|
2194
2133
|
recipientSignature: signature,
|
|
2195
2134
|
_signedDomain: domain
|
|
2196
2135
|
};
|
|
2197
2136
|
}
|
|
2198
|
-
return
|
|
2137
|
+
return updatedACP;
|
|
2199
2138
|
},
|
|
2200
2139
|
/**
|
|
2201
|
-
* Create and sign a self
|
|
2140
|
+
* Create and sign a self acp in one operation
|
|
2202
2141
|
*/
|
|
2203
2142
|
createSelfAndSign: async (options, publicClient, walletClient) => {
|
|
2204
|
-
const
|
|
2205
|
-
return
|
|
2143
|
+
const acp = ACPUtils.createSelf(options);
|
|
2144
|
+
return ACPUtils.sign(acp, publicClient, walletClient);
|
|
2206
2145
|
},
|
|
2207
2146
|
/**
|
|
2208
|
-
* Create and sign a sharing
|
|
2147
|
+
* Create and sign a sharing acp in one operation
|
|
2209
2148
|
*/
|
|
2210
2149
|
createSharingAndSign: async (options, publicClient, walletClient) => {
|
|
2211
|
-
const
|
|
2212
|
-
return
|
|
2150
|
+
const acp = ACPUtils.createSharing(options);
|
|
2151
|
+
return ACPUtils.sign(acp, publicClient, walletClient);
|
|
2213
2152
|
},
|
|
2214
2153
|
/**
|
|
2215
|
-
* Import and sign a shared
|
|
2154
|
+
* Import and sign a shared acp in one operation from various input formats
|
|
2216
2155
|
*/
|
|
2217
2156
|
importSharedAndSign: async (options, publicClient, walletClient) => {
|
|
2218
|
-
const
|
|
2219
|
-
return
|
|
2157
|
+
const acp = ACPUtils.importShared(options);
|
|
2158
|
+
return ACPUtils.sign(acp, publicClient, walletClient);
|
|
2220
2159
|
},
|
|
2221
2160
|
/**
|
|
2222
|
-
* Deserialize
|
|
2161
|
+
* Deserialize an ACP from serialized data
|
|
2223
2162
|
*/
|
|
2224
2163
|
deserialize: (data) => {
|
|
2225
|
-
return {
|
|
2226
|
-
...data,
|
|
2227
|
-
sealingPair: SealingKey.deserialize(data.sealingPair.privateKey, data.sealingPair.publicKey)
|
|
2228
|
-
};
|
|
2164
|
+
return { ...data };
|
|
2229
2165
|
},
|
|
2230
2166
|
/**
|
|
2231
|
-
* Serialize
|
|
2167
|
+
* Serialize an ACP for storage
|
|
2232
2168
|
*/
|
|
2233
|
-
serialize: (
|
|
2169
|
+
serialize: (acp) => {
|
|
2234
2170
|
return {
|
|
2235
|
-
hash:
|
|
2236
|
-
name:
|
|
2237
|
-
type:
|
|
2238
|
-
issuer:
|
|
2239
|
-
expiration:
|
|
2240
|
-
recipient:
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2171
|
+
hash: acp.hash,
|
|
2172
|
+
name: acp.name,
|
|
2173
|
+
type: acp.type,
|
|
2174
|
+
issuer: acp.issuer,
|
|
2175
|
+
expiration: acp.expiration,
|
|
2176
|
+
recipient: acp.recipient,
|
|
2177
|
+
revokerData: acp.revokerData,
|
|
2178
|
+
revokerContract: acp.revokerContract,
|
|
2179
|
+
scope: acp.scope,
|
|
2180
|
+
contracts: acp.contracts,
|
|
2181
|
+
handles: acp.handles,
|
|
2182
|
+
sealingKey: acp.sealingKey,
|
|
2183
|
+
issuerSignature: acp.issuerSignature,
|
|
2184
|
+
recipientSignature: acp.recipientSignature,
|
|
2185
|
+
_signedDomain: acp._signedDomain,
|
|
2186
|
+
sealingPrivateKey: acp.sealingPrivateKey
|
|
2247
2187
|
};
|
|
2248
2188
|
},
|
|
2249
2189
|
/**
|
|
2250
|
-
* Validate
|
|
2190
|
+
* Validate an ACP (schema-level validation)
|
|
2251
2191
|
*/
|
|
2252
|
-
validateSchema: (
|
|
2253
|
-
if (
|
|
2254
|
-
return
|
|
2255
|
-
} else if (
|
|
2256
|
-
return
|
|
2257
|
-
} else if (
|
|
2258
|
-
return
|
|
2192
|
+
validateSchema: (acp) => {
|
|
2193
|
+
if (acp.type === "self") {
|
|
2194
|
+
return validateSelfACP(acp);
|
|
2195
|
+
} else if (acp.type === "sharing") {
|
|
2196
|
+
return validateSharingACP(acp);
|
|
2197
|
+
} else if (acp.type === "recipient") {
|
|
2198
|
+
return validateImportACP(acp);
|
|
2259
2199
|
} else {
|
|
2260
|
-
throw new Error("Invalid
|
|
2200
|
+
throw new Error("Invalid ACP type");
|
|
2261
2201
|
}
|
|
2262
2202
|
},
|
|
2263
2203
|
/**
|
|
2264
|
-
* Validate
|
|
2204
|
+
* Validate an ACP (holistic validation).
|
|
2265
2205
|
*
|
|
2266
2206
|
* This validates:
|
|
2267
|
-
* -
|
|
2268
|
-
* -
|
|
2269
|
-
* -
|
|
2207
|
+
* - ACP schema (shape + invariants)
|
|
2208
|
+
* - ACP is signed
|
|
2209
|
+
* - ACP is not expired
|
|
2270
2210
|
*
|
|
2271
|
-
* For schema-only validation, use `validateSchema(
|
|
2211
|
+
* For schema-only validation, use `validateSchema(acp)`.
|
|
2272
2212
|
*/
|
|
2273
|
-
validate: (
|
|
2274
|
-
const validated =
|
|
2213
|
+
validate: (acp) => {
|
|
2214
|
+
const validated = ACPUtils.validateSchema(acp);
|
|
2275
2215
|
ValidationUtils.assertSignedAndNotExpired(validated);
|
|
2276
2216
|
return validated;
|
|
2277
2217
|
},
|
|
2278
2218
|
/**
|
|
2279
|
-
* Get the
|
|
2219
|
+
* Get the public component of an ACP — the signed struct sent on-chain / to the decryption backend.
|
|
2220
|
+
* Strips the private component (hash, name, type, sealing pair).
|
|
2280
2221
|
*/
|
|
2281
|
-
|
|
2222
|
+
getPublic: (acp, skipValidation = false) => {
|
|
2282
2223
|
if (!skipValidation) {
|
|
2283
|
-
|
|
2224
|
+
ACPUtils.validateSchema(acp);
|
|
2284
2225
|
}
|
|
2285
2226
|
return {
|
|
2286
|
-
issuer:
|
|
2287
|
-
expiration:
|
|
2288
|
-
recipient:
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2227
|
+
issuer: acp.issuer,
|
|
2228
|
+
expiration: acp.expiration,
|
|
2229
|
+
recipient: acp.recipient,
|
|
2230
|
+
revokerData: acp.revokerData,
|
|
2231
|
+
revokerContract: acp.revokerContract,
|
|
2232
|
+
scope: acp.scope,
|
|
2233
|
+
contracts: acp.contracts,
|
|
2234
|
+
handles: acp.handles,
|
|
2235
|
+
sealingKey: acp.sealingKey,
|
|
2236
|
+
issuerSignature: acp.issuerSignature,
|
|
2237
|
+
recipientSignature: acp.recipientSignature
|
|
2294
2238
|
};
|
|
2295
2239
|
},
|
|
2296
2240
|
/**
|
|
2297
|
-
* Get a stable hash for the
|
|
2241
|
+
* Get a stable hash for the acp (used as key in storage)
|
|
2298
2242
|
*/
|
|
2299
|
-
getHash: (
|
|
2243
|
+
getHash: (acp) => {
|
|
2300
2244
|
const data = JSON.stringify({
|
|
2301
|
-
type:
|
|
2302
|
-
issuer:
|
|
2303
|
-
expiration:
|
|
2304
|
-
recipient:
|
|
2305
|
-
|
|
2306
|
-
|
|
2245
|
+
type: acp.type,
|
|
2246
|
+
issuer: acp.issuer,
|
|
2247
|
+
expiration: acp.expiration,
|
|
2248
|
+
recipient: acp.recipient,
|
|
2249
|
+
revokerData: acp.revokerData,
|
|
2250
|
+
revokerContract: acp.revokerContract,
|
|
2251
|
+
scope: acp.scope,
|
|
2252
|
+
contracts: acp.contracts,
|
|
2253
|
+
handles: acp.handles
|
|
2307
2254
|
});
|
|
2308
2255
|
return viem.keccak256(viem.toHex(data));
|
|
2309
2256
|
},
|
|
2310
2257
|
/**
|
|
2311
|
-
* Export
|
|
2258
|
+
* Export acp data for sharing (strips the private component).
|
|
2259
|
+
* Fixed `SharedACP` shape — every field always present, aligned with
|
|
2260
|
+
* `ACPPublic` and the on-chain sharing payload.
|
|
2312
2261
|
*/
|
|
2313
|
-
export: (
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2262
|
+
export: (acp) => {
|
|
2263
|
+
if (acp.type !== "sharing") {
|
|
2264
|
+
throw new Error(
|
|
2265
|
+
`Cannot export a '${acp.type}' ACP \u2014 only 'sharing' ACPs are exportable. The export includes the issuer signature.`
|
|
2266
|
+
);
|
|
2267
|
+
}
|
|
2268
|
+
if (acp.issuerSignature === "0x") {
|
|
2269
|
+
throw new Error(
|
|
2270
|
+
"Cannot export an unsigned sharing ACP \u2014 sign it first (the recipient needs the issuer signature)."
|
|
2271
|
+
);
|
|
2272
|
+
}
|
|
2273
|
+
const shared = {
|
|
2274
|
+
name: acp.name,
|
|
2275
|
+
type: acp.type,
|
|
2276
|
+
issuer: acp.issuer,
|
|
2277
|
+
expiration: acp.expiration,
|
|
2278
|
+
recipient: acp.recipient,
|
|
2279
|
+
revokerData: acp.revokerData,
|
|
2280
|
+
revokerContract: acp.revokerContract,
|
|
2281
|
+
scope: acp.scope,
|
|
2282
|
+
contracts: acp.contracts,
|
|
2283
|
+
handles: acp.handles,
|
|
2284
|
+
issuerSignature: acp.issuerSignature
|
|
2319
2285
|
};
|
|
2320
|
-
|
|
2321
|
-
cleanedPermit.recipient = permit.recipient;
|
|
2322
|
-
if (permit.validatorId !== 0)
|
|
2323
|
-
cleanedPermit.validatorId = permit.validatorId;
|
|
2324
|
-
if (permit.validatorContract !== viem.zeroAddress)
|
|
2325
|
-
cleanedPermit.validatorContract = permit.validatorContract;
|
|
2326
|
-
if (permit.type === "sharing" && permit.issuerSignature !== "0x")
|
|
2327
|
-
cleanedPermit.issuerSignature = permit.issuerSignature;
|
|
2328
|
-
return JSON.stringify(cleanedPermit, void 0, 2);
|
|
2286
|
+
return JSON.stringify(shared, void 0, 2);
|
|
2329
2287
|
},
|
|
2330
2288
|
/**
|
|
2331
|
-
* Unseal encrypted data using the
|
|
2289
|
+
* Unseal encrypted data using the acp's sealing key
|
|
2332
2290
|
*/
|
|
2333
|
-
unseal: (
|
|
2334
|
-
return
|
|
2291
|
+
unseal: (acp, ciphertext) => {
|
|
2292
|
+
return unsealWithPrivateKey(acp.sealingPrivateKey, ciphertext);
|
|
2335
2293
|
},
|
|
2336
2294
|
/**
|
|
2337
|
-
* Check if
|
|
2295
|
+
* Check if acp is expired
|
|
2338
2296
|
*/
|
|
2339
|
-
isExpired: (
|
|
2340
|
-
return ValidationUtils.isExpired(
|
|
2297
|
+
isExpired: (acp) => {
|
|
2298
|
+
return ValidationUtils.isExpired(acp);
|
|
2341
2299
|
},
|
|
2342
2300
|
/**
|
|
2343
|
-
* Check if
|
|
2301
|
+
* Check if acp is signed
|
|
2344
2302
|
*/
|
|
2345
|
-
isSigned: (
|
|
2346
|
-
return ValidationUtils.isSigned(
|
|
2303
|
+
isSigned: (acp) => {
|
|
2304
|
+
return ValidationUtils.isSigned(acp);
|
|
2347
2305
|
},
|
|
2348
2306
|
/**
|
|
2349
|
-
* Check if
|
|
2307
|
+
* Check if acp is signed and not expired
|
|
2350
2308
|
*/
|
|
2351
|
-
isSignedAndNotExpired: (
|
|
2352
|
-
return ValidationUtils.isSignedAndNotExpired(
|
|
2309
|
+
isSignedAndNotExpired: (acp) => {
|
|
2310
|
+
return ValidationUtils.isSignedAndNotExpired(acp);
|
|
2353
2311
|
},
|
|
2354
2312
|
/**
|
|
2355
|
-
* Assert that
|
|
2313
|
+
* Assert that acp is signed and not expired
|
|
2356
2314
|
*/
|
|
2357
|
-
assertSignedAndNotExpired: (
|
|
2358
|
-
return ValidationUtils.assertSignedAndNotExpired(
|
|
2315
|
+
assertSignedAndNotExpired: (acp) => {
|
|
2316
|
+
return ValidationUtils.assertSignedAndNotExpired(acp);
|
|
2359
2317
|
},
|
|
2360
|
-
isValid: (
|
|
2361
|
-
return ValidationUtils.isValid(
|
|
2318
|
+
isValid: (acp) => {
|
|
2319
|
+
return ValidationUtils.isValid(acp);
|
|
2362
2320
|
},
|
|
2363
2321
|
/**
|
|
2364
|
-
* Update
|
|
2322
|
+
* Update acp name (returns new acp instance)
|
|
2365
2323
|
*/
|
|
2366
|
-
updateName: (
|
|
2367
|
-
return { ...
|
|
2324
|
+
updateName: (acp, name) => {
|
|
2325
|
+
return { ...acp, name };
|
|
2368
2326
|
},
|
|
2369
2327
|
/**
|
|
2370
2328
|
* Fetch EIP712 domain from the blockchain
|
|
@@ -2373,230 +2331,468 @@ var PermitUtils = {
|
|
|
2373
2331
|
return getAclEIP712Domain(publicClient);
|
|
2374
2332
|
},
|
|
2375
2333
|
/**
|
|
2376
|
-
* Check if
|
|
2334
|
+
* Check if acp's signed domain matches the provided domain
|
|
2377
2335
|
*/
|
|
2378
|
-
matchesDomain: (
|
|
2379
|
-
return
|
|
2336
|
+
matchesDomain: (acp, domain) => {
|
|
2337
|
+
return acp._signedDomain?.name === domain.name && acp._signedDomain?.version === domain.version && acp._signedDomain?.verifyingContract === domain.verifyingContract && acp._signedDomain?.chainId === domain.chainId;
|
|
2380
2338
|
},
|
|
2381
2339
|
/**
|
|
2382
|
-
* Check if
|
|
2340
|
+
* Check if acp's signed domain is valid for the current chain
|
|
2383
2341
|
*/
|
|
2384
|
-
checkSignedDomainValid: async (
|
|
2385
|
-
if (
|
|
2342
|
+
checkSignedDomainValid: async (acp, publicClient) => {
|
|
2343
|
+
if (acp._signedDomain == null)
|
|
2386
2344
|
return false;
|
|
2387
2345
|
const domain = await getAclEIP712Domain(publicClient);
|
|
2388
|
-
return
|
|
2346
|
+
return ACPUtils.matchesDomain(acp, domain);
|
|
2389
2347
|
},
|
|
2390
2348
|
/**
|
|
2391
|
-
* Check if
|
|
2349
|
+
* Check if acp passes the on-chain validation
|
|
2392
2350
|
*/
|
|
2393
|
-
checkValidityOnChain: async (
|
|
2394
|
-
const
|
|
2395
|
-
return
|
|
2351
|
+
checkValidityOnChain: async (acp, publicClient) => {
|
|
2352
|
+
const publicAcp = ACPUtils.getPublic(acp);
|
|
2353
|
+
return checkACPValidityOnChain(publicAcp, publicClient);
|
|
2396
2354
|
}
|
|
2397
2355
|
};
|
|
2398
|
-
var
|
|
2399
|
-
|
|
2400
|
-
|
|
2356
|
+
var ACP_STORE_DEFAULTS = {
|
|
2357
|
+
acps: {},
|
|
2358
|
+
activeACPHash: {}
|
|
2401
2359
|
};
|
|
2402
|
-
var
|
|
2403
|
-
|
|
2360
|
+
var ACP_STORE_VERSION = 3;
|
|
2361
|
+
var _acpStore = vanilla.createStore()(
|
|
2362
|
+
middleware.persist(() => ACP_STORE_DEFAULTS, {
|
|
2363
|
+
name: "cofhesdk-acps",
|
|
2364
|
+
version: ACP_STORE_VERSION,
|
|
2365
|
+
migrate: (persistedState, version) => {
|
|
2366
|
+
if (version < ACP_STORE_VERSION)
|
|
2367
|
+
return ACP_STORE_DEFAULTS;
|
|
2368
|
+
return persistedState;
|
|
2369
|
+
}
|
|
2370
|
+
})
|
|
2404
2371
|
);
|
|
2405
2372
|
var clearStaleStore = () => {
|
|
2406
|
-
const state =
|
|
2407
|
-
const hasExpectedStructure = state && typeof state === "object" && "
|
|
2373
|
+
const state = _acpStore.getState();
|
|
2374
|
+
const hasExpectedStructure = state && typeof state === "object" && "acps" in state && "activeACPHash" in state && typeof state.acps === "object" && typeof state.activeACPHash === "object";
|
|
2408
2375
|
if (hasExpectedStructure)
|
|
2409
2376
|
return;
|
|
2410
|
-
|
|
2377
|
+
_acpStore.setState({ acps: {}, activeACPHash: {} });
|
|
2411
2378
|
};
|
|
2412
|
-
var
|
|
2379
|
+
var getACP = (chainId, account, hash) => {
|
|
2413
2380
|
clearStaleStore();
|
|
2414
2381
|
if (chainId == null || account == null || hash == null)
|
|
2415
2382
|
return;
|
|
2416
|
-
const
|
|
2417
|
-
if (
|
|
2383
|
+
const savedACP = _acpStore.getState().acps[chainId]?.[account]?.[hash];
|
|
2384
|
+
if (savedACP == null)
|
|
2418
2385
|
return;
|
|
2419
|
-
return
|
|
2386
|
+
return ACPUtils.deserialize(savedACP);
|
|
2420
2387
|
};
|
|
2421
|
-
var
|
|
2388
|
+
var getActiveACP = (chainId, account) => {
|
|
2422
2389
|
clearStaleStore();
|
|
2423
2390
|
if (chainId == null || account == null)
|
|
2424
2391
|
return;
|
|
2425
|
-
const
|
|
2426
|
-
return
|
|
2392
|
+
const activeACPHash = _acpStore.getState().activeACPHash[chainId]?.[account];
|
|
2393
|
+
return getACP(chainId, account, activeACPHash);
|
|
2427
2394
|
};
|
|
2428
|
-
var
|
|
2395
|
+
var getACPs = (chainId, account) => {
|
|
2429
2396
|
clearStaleStore();
|
|
2430
2397
|
if (chainId == null || account == null)
|
|
2431
2398
|
return {};
|
|
2432
|
-
return Object.entries(
|
|
2433
|
-
(acc, [hash,
|
|
2434
|
-
if (
|
|
2399
|
+
return Object.entries(_acpStore.getState().acps[chainId]?.[account] ?? {}).reduce(
|
|
2400
|
+
(acc, [hash, acp]) => {
|
|
2401
|
+
if (acp == void 0)
|
|
2435
2402
|
return acc;
|
|
2436
|
-
return { ...acc, [hash]:
|
|
2403
|
+
return { ...acc, [hash]: ACPUtils.deserialize(acp) };
|
|
2437
2404
|
},
|
|
2438
2405
|
{}
|
|
2439
2406
|
);
|
|
2440
2407
|
};
|
|
2441
|
-
var
|
|
2408
|
+
var setACP = (chainId, account, acp) => {
|
|
2442
2409
|
clearStaleStore();
|
|
2443
|
-
|
|
2410
|
+
_acpStore.setState(
|
|
2444
2411
|
immer.produce((state) => {
|
|
2445
|
-
if (state.
|
|
2446
|
-
state.
|
|
2447
|
-
if (state.
|
|
2448
|
-
state.
|
|
2449
|
-
state.
|
|
2412
|
+
if (state.acps[chainId] == null)
|
|
2413
|
+
state.acps[chainId] = {};
|
|
2414
|
+
if (state.acps[chainId][account] == null)
|
|
2415
|
+
state.acps[chainId][account] = {};
|
|
2416
|
+
state.acps[chainId][account][acp.hash] = ACPUtils.serialize(acp);
|
|
2450
2417
|
})
|
|
2451
2418
|
);
|
|
2452
2419
|
};
|
|
2453
|
-
var
|
|
2420
|
+
var removeACP = (chainId, account, hash) => {
|
|
2454
2421
|
clearStaleStore();
|
|
2455
|
-
|
|
2422
|
+
_acpStore.setState(
|
|
2456
2423
|
immer.produce((state) => {
|
|
2457
|
-
if (state.
|
|
2458
|
-
state.
|
|
2459
|
-
if (state.
|
|
2460
|
-
state.
|
|
2461
|
-
const
|
|
2462
|
-
if (
|
|
2424
|
+
if (state.acps[chainId] == null)
|
|
2425
|
+
state.acps[chainId] = {};
|
|
2426
|
+
if (state.activeACPHash[chainId] == null)
|
|
2427
|
+
state.activeACPHash[chainId] = {};
|
|
2428
|
+
const accountACPs = state.acps[chainId][account];
|
|
2429
|
+
if (accountACPs == null)
|
|
2463
2430
|
return;
|
|
2464
|
-
if (
|
|
2431
|
+
if (accountACPs[hash] == null)
|
|
2465
2432
|
return;
|
|
2466
|
-
if (state.
|
|
2467
|
-
state.
|
|
2433
|
+
if (state.activeACPHash[chainId][account] === hash) {
|
|
2434
|
+
state.activeACPHash[chainId][account] = void 0;
|
|
2468
2435
|
}
|
|
2469
|
-
|
|
2436
|
+
accountACPs[hash] = void 0;
|
|
2470
2437
|
})
|
|
2471
2438
|
);
|
|
2472
2439
|
};
|
|
2473
|
-
var
|
|
2440
|
+
var getActiveACPHash = (chainId, account) => {
|
|
2474
2441
|
clearStaleStore();
|
|
2475
2442
|
if (chainId == null || account == null)
|
|
2476
2443
|
return void 0;
|
|
2477
|
-
return
|
|
2444
|
+
return _acpStore.getState().activeACPHash[chainId]?.[account];
|
|
2478
2445
|
};
|
|
2479
|
-
var
|
|
2446
|
+
var setActiveACPHash = (chainId, account, hash) => {
|
|
2480
2447
|
clearStaleStore();
|
|
2481
|
-
|
|
2448
|
+
_acpStore.setState(
|
|
2482
2449
|
immer.produce((state) => {
|
|
2483
|
-
if (state.
|
|
2484
|
-
state.
|
|
2485
|
-
state.
|
|
2450
|
+
if (state.activeACPHash[chainId] == null)
|
|
2451
|
+
state.activeACPHash[chainId] = {};
|
|
2452
|
+
state.activeACPHash[chainId][account] = hash;
|
|
2486
2453
|
})
|
|
2487
2454
|
);
|
|
2488
2455
|
};
|
|
2489
|
-
var
|
|
2456
|
+
var removeActiveACPHash = (chainId, account) => {
|
|
2490
2457
|
clearStaleStore();
|
|
2491
|
-
|
|
2458
|
+
_acpStore.setState(
|
|
2492
2459
|
immer.produce((state) => {
|
|
2493
|
-
if (state.
|
|
2494
|
-
state.
|
|
2460
|
+
if (state.activeACPHash[chainId])
|
|
2461
|
+
state.activeACPHash[chainId][account] = void 0;
|
|
2495
2462
|
})
|
|
2496
2463
|
);
|
|
2497
2464
|
};
|
|
2498
2465
|
var resetStore = () => {
|
|
2499
2466
|
clearStaleStore();
|
|
2500
|
-
|
|
2467
|
+
_acpStore.setState({ acps: {}, activeACPHash: {} });
|
|
2501
2468
|
};
|
|
2502
|
-
var
|
|
2503
|
-
store:
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2469
|
+
var acpStore = {
|
|
2470
|
+
store: _acpStore,
|
|
2471
|
+
getACP,
|
|
2472
|
+
getActiveACP,
|
|
2473
|
+
getACPs,
|
|
2474
|
+
setACP,
|
|
2475
|
+
removeACP,
|
|
2476
|
+
getActiveACPHash,
|
|
2477
|
+
setActiveACPHash,
|
|
2478
|
+
removeActiveACPHash,
|
|
2512
2479
|
resetStore
|
|
2513
2480
|
};
|
|
2514
|
-
var
|
|
2481
|
+
var ACP_VALIDATOR_ABI = viem.parseAbi([
|
|
2482
|
+
"function revokeSingle(uint256 id)",
|
|
2483
|
+
"function revokeAllExisting()",
|
|
2484
|
+
"function disabled(address issuer, uint256 id) view returns (bool)"
|
|
2485
|
+
]);
|
|
2486
|
+
var storeACP = async (acp, publicClient, walletClient) => {
|
|
2487
|
+
const chainId = await publicClient.getChainId();
|
|
2488
|
+
const account = walletClient.account.address;
|
|
2489
|
+
acpStore.setACP(chainId, account, acp);
|
|
2490
|
+
};
|
|
2491
|
+
var storeActiveACP = async (acp, publicClient, walletClient) => {
|
|
2492
|
+
await storeACP(acp, publicClient, walletClient);
|
|
2515
2493
|
const chainId = await publicClient.getChainId();
|
|
2516
2494
|
const account = walletClient.account.address;
|
|
2517
|
-
|
|
2518
|
-
permitStore.setActivePermitHash(chainId, account, permit.hash);
|
|
2495
|
+
acpStore.setActiveACPHash(chainId, account, acp.hash);
|
|
2519
2496
|
};
|
|
2520
|
-
var
|
|
2521
|
-
const
|
|
2522
|
-
|
|
2523
|
-
|
|
2497
|
+
var createACPWithSign = async (options, publicClient, walletClient, acpMethod, activate = true) => {
|
|
2498
|
+
const acp = await acpMethod(options, publicClient, walletClient);
|
|
2499
|
+
if (activate) {
|
|
2500
|
+
await storeActiveACP(acp, publicClient, walletClient);
|
|
2501
|
+
} else {
|
|
2502
|
+
await storeACP(acp, publicClient, walletClient);
|
|
2503
|
+
}
|
|
2504
|
+
return acp;
|
|
2524
2505
|
};
|
|
2525
2506
|
var createSelf = async (options, publicClient, walletClient) => {
|
|
2526
|
-
return
|
|
2507
|
+
return createACPWithSign(options, publicClient, walletClient, ACPUtils.createSelfAndSign);
|
|
2527
2508
|
};
|
|
2528
2509
|
var createSharing = async (options, publicClient, walletClient) => {
|
|
2529
|
-
return
|
|
2510
|
+
return createACPWithSign(options, publicClient, walletClient, ACPUtils.createSharingAndSign, false);
|
|
2530
2511
|
};
|
|
2531
2512
|
var importShared = async (options, publicClient, walletClient) => {
|
|
2532
|
-
return
|
|
2513
|
+
return createACPWithSign(options, publicClient, walletClient, ACPUtils.importSharedAndSign);
|
|
2533
2514
|
};
|
|
2534
|
-
var getHash = (
|
|
2535
|
-
return
|
|
2515
|
+
var getHash = (acp) => {
|
|
2516
|
+
return ACPUtils.getHash(acp);
|
|
2536
2517
|
};
|
|
2537
|
-
var exportShared = (
|
|
2538
|
-
return
|
|
2518
|
+
var exportShared = (acp) => {
|
|
2519
|
+
return ACPUtils.export(acp);
|
|
2539
2520
|
};
|
|
2540
|
-
var serialize = (
|
|
2541
|
-
return
|
|
2521
|
+
var serialize = (acp) => {
|
|
2522
|
+
return ACPUtils.serialize(acp);
|
|
2542
2523
|
};
|
|
2543
2524
|
var deserialize = (serialized) => {
|
|
2544
|
-
return
|
|
2525
|
+
return ACPUtils.deserialize(serialized);
|
|
2545
2526
|
};
|
|
2546
|
-
var
|
|
2547
|
-
return
|
|
2527
|
+
var getACP2 = (chainId, account, hash) => {
|
|
2528
|
+
return acpStore.getACP(chainId, account, hash);
|
|
2548
2529
|
};
|
|
2549
|
-
var
|
|
2550
|
-
return
|
|
2530
|
+
var getACPs2 = (chainId, account) => {
|
|
2531
|
+
return acpStore.getACPs(chainId, account);
|
|
2551
2532
|
};
|
|
2552
|
-
var
|
|
2553
|
-
return
|
|
2533
|
+
var getActiveACP2 = (chainId, account) => {
|
|
2534
|
+
return acpStore.getActiveACP(chainId, account);
|
|
2554
2535
|
};
|
|
2555
|
-
var
|
|
2556
|
-
return
|
|
2536
|
+
var getActiveACPHash2 = (chainId, account) => {
|
|
2537
|
+
return acpStore.getActiveACPHash(chainId, account);
|
|
2557
2538
|
};
|
|
2558
|
-
var
|
|
2559
|
-
|
|
2539
|
+
var selectActiveACP = (chainId, account, hash) => {
|
|
2540
|
+
acpStore.setActiveACPHash(chainId, account, hash);
|
|
2560
2541
|
};
|
|
2561
|
-
var
|
|
2542
|
+
var getOrCreateSelfACP = async (publicClient, walletClient, chainId, account, options) => {
|
|
2562
2543
|
const _chainId = chainId ?? await publicClient.getChainId();
|
|
2563
2544
|
const _account = account ?? walletClient.account.address;
|
|
2564
|
-
const
|
|
2565
|
-
if (
|
|
2566
|
-
return
|
|
2545
|
+
const activeACP = await getActiveACP2(_chainId, _account);
|
|
2546
|
+
if (activeACP && activeACP.type === "self" && ACPUtils.isValid(activeACP).valid) {
|
|
2547
|
+
return activeACP;
|
|
2567
2548
|
}
|
|
2568
|
-
return createSelf(options ?? { issuer: _account, name: "Autogenerated Self
|
|
2549
|
+
return createSelf(options ?? { issuer: _account, name: "Autogenerated Self ACP" }, publicClient, walletClient);
|
|
2569
2550
|
};
|
|
2570
|
-
var
|
|
2551
|
+
var getOrCreateSharingACP = async (publicClient, walletClient, options, chainId, account) => {
|
|
2571
2552
|
const _chainId = chainId ?? await publicClient.getChainId();
|
|
2572
2553
|
const _account = account ?? walletClient.account.address;
|
|
2573
|
-
const
|
|
2574
|
-
if (
|
|
2575
|
-
return
|
|
2554
|
+
const activeACP = await getActiveACP2(_chainId, _account);
|
|
2555
|
+
if (activeACP && activeACP.type === "sharing" && ACPUtils.isValid(activeACP).valid) {
|
|
2556
|
+
return activeACP;
|
|
2576
2557
|
}
|
|
2577
2558
|
return createSharing(options, publicClient, walletClient);
|
|
2578
2559
|
};
|
|
2579
|
-
var
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2560
|
+
var applyACPDefaults = (options, acpConfig, chainId) => {
|
|
2561
|
+
const result = { ...options };
|
|
2562
|
+
const defaultRevoker = acpConfig?.defaultRevoker?.[chainId];
|
|
2563
|
+
const hasValidatorOptions = options.revokerData != null || options.revokerContract != null;
|
|
2564
|
+
if (defaultRevoker != null && !hasValidatorOptions) {
|
|
2565
|
+
result.revokerContract = defaultRevoker;
|
|
2566
|
+
result.revokerData = Math.round(Date.now() / 1e3) - 60;
|
|
2567
|
+
}
|
|
2568
|
+
const defaultContracts = acpConfig?.defaultContractScopes?.[chainId];
|
|
2569
|
+
const hasScopeOptions = options.scope != null || options.contracts != null || options.handles != null;
|
|
2570
|
+
if (defaultContracts != null && defaultContracts.length > 0 && !hasScopeOptions) {
|
|
2571
|
+
result.contracts = defaultContracts;
|
|
2572
|
+
}
|
|
2573
|
+
return result;
|
|
2574
|
+
};
|
|
2575
|
+
var ACL_SERVED_ADDRESSES_ABI = viem.parseAbi([
|
|
2576
|
+
"function acl() view returns (address)",
|
|
2577
|
+
"function defaultRevokerContract() view returns (address)",
|
|
2578
|
+
"function shareRegistry() view returns (address)"
|
|
2579
|
+
]);
|
|
2580
|
+
var aclServedAddressesCache = /* @__PURE__ */ new Map();
|
|
2581
|
+
var clearAclServedAddresses = () => aclServedAddressesCache.clear();
|
|
2582
|
+
var getAclServedAddresses = async (publicClient, chainId) => {
|
|
2583
|
+
const cached = aclServedAddressesCache.get(chainId);
|
|
2584
|
+
if (cached != null)
|
|
2585
|
+
return cached;
|
|
2586
|
+
let aclAddress;
|
|
2587
|
+
try {
|
|
2588
|
+
aclAddress = await publicClient.readContract({
|
|
2589
|
+
address: TASK_MANAGER_ADDRESS,
|
|
2590
|
+
abi: ACL_SERVED_ADDRESSES_ABI,
|
|
2591
|
+
functionName: "acl"
|
|
2592
|
+
});
|
|
2593
|
+
} catch {
|
|
2594
|
+
return {};
|
|
2595
|
+
}
|
|
2596
|
+
const [defaultRevoker, shareRegistry] = await Promise.all([
|
|
2597
|
+
publicClient.readContract({ address: aclAddress, abi: ACL_SERVED_ADDRESSES_ABI, functionName: "defaultRevokerContract" }).catch(() => void 0),
|
|
2598
|
+
publicClient.readContract({ address: aclAddress, abi: ACL_SERVED_ADDRESSES_ABI, functionName: "shareRegistry" }).catch(() => void 0)
|
|
2599
|
+
]);
|
|
2600
|
+
const resolved = {
|
|
2601
|
+
defaultRevoker: defaultRevoker != null && defaultRevoker !== viem.zeroAddress ? defaultRevoker : void 0,
|
|
2602
|
+
shareRegistry: shareRegistry != null && shareRegistry !== viem.zeroAddress ? shareRegistry : void 0
|
|
2603
|
+
};
|
|
2604
|
+
aclServedAddressesCache.set(chainId, resolved);
|
|
2605
|
+
return resolved;
|
|
2606
|
+
};
|
|
2607
|
+
var applyACPDefaultsFromChain = async (options, acpConfig, publicClient, chainId) => {
|
|
2608
|
+
const hasExplicitRevoker = acpConfig?.defaultRevoker?.[chainId] != null || options.revokerData != null || options.revokerContract != null;
|
|
2609
|
+
if (hasExplicitRevoker)
|
|
2610
|
+
return applyACPDefaults(options, acpConfig, chainId);
|
|
2611
|
+
const served = await getAclServedAddresses(publicClient, chainId);
|
|
2612
|
+
const effectiveConfig = served.defaultRevoker != null ? { ...acpConfig, defaultRevoker: { ...acpConfig?.defaultRevoker, [chainId]: served.defaultRevoker } } : acpConfig;
|
|
2613
|
+
return applyACPDefaults(options, effectiveConfig, chainId);
|
|
2614
|
+
};
|
|
2615
|
+
var revokeACP = async (acp, walletClient) => {
|
|
2616
|
+
if (acp.revokerContract === viem.zeroAddress || acp.revokerData === 0) {
|
|
2617
|
+
throw new Error("ACP is not revocable: it has no revoker (revokerContract/revokerData unset)");
|
|
2618
|
+
}
|
|
2619
|
+
if (walletClient.account == null)
|
|
2620
|
+
throw new Error("Missing walletClient account");
|
|
2621
|
+
if (walletClient.account.address.toLowerCase() !== acp.issuer.toLowerCase()) {
|
|
2622
|
+
throw new Error("Only the acp issuer can revoke it");
|
|
2623
|
+
}
|
|
2624
|
+
return walletClient.writeContract({
|
|
2625
|
+
address: acp.revokerContract,
|
|
2626
|
+
abi: ACP_VALIDATOR_ABI,
|
|
2627
|
+
functionName: "revokeSingle",
|
|
2628
|
+
args: [BigInt(acp.revokerData)],
|
|
2629
|
+
account: walletClient.account,
|
|
2630
|
+
chain: walletClient.chain
|
|
2631
|
+
});
|
|
2632
|
+
};
|
|
2633
|
+
var revokeAllACPs = async (walletClient, publicClient, revokerContract) => {
|
|
2634
|
+
if (walletClient.account == null)
|
|
2635
|
+
throw new Error("Missing walletClient account");
|
|
2636
|
+
let revoker = revokerContract;
|
|
2637
|
+
if (revoker == null) {
|
|
2638
|
+
const chainId = await publicClient.getChainId();
|
|
2639
|
+
const active = getActiveACP2(chainId, walletClient.account.address);
|
|
2640
|
+
revoker = active?.revokerContract;
|
|
2641
|
+
}
|
|
2642
|
+
if (revoker == null || revoker === viem.zeroAddress) {
|
|
2643
|
+
throw new Error("No revoker contract: pass `revokerContract` or activate a revocable acp first");
|
|
2644
|
+
}
|
|
2645
|
+
return walletClient.writeContract({
|
|
2646
|
+
address: revoker,
|
|
2647
|
+
abi: ACP_VALIDATOR_ABI,
|
|
2648
|
+
functionName: "revokeAllExisting",
|
|
2649
|
+
args: [],
|
|
2650
|
+
account: walletClient.account,
|
|
2651
|
+
chain: walletClient.chain
|
|
2652
|
+
});
|
|
2653
|
+
};
|
|
2654
|
+
var isACPRevoked = async (acp, publicClient) => {
|
|
2655
|
+
if (acp.revokerContract === viem.zeroAddress || acp.revokerData === 0)
|
|
2656
|
+
return false;
|
|
2657
|
+
return publicClient.readContract({
|
|
2658
|
+
address: acp.revokerContract,
|
|
2659
|
+
abi: ACP_VALIDATOR_ABI,
|
|
2660
|
+
functionName: "disabled",
|
|
2661
|
+
args: [acp.issuer, BigInt(acp.revokerData)]
|
|
2662
|
+
});
|
|
2663
|
+
};
|
|
2664
|
+
var ACP_SHARE_REGISTRY_ABI = viem.parseAbi([
|
|
2665
|
+
"struct ACP { address issuer; uint64 expiration; address recipient; uint256 revokerData; address revokerContract; uint8 scope; address[] contracts; bytes32[] handles; bytes32 sealingKey; bytes issuerSignature; bytes recipientSignature; }",
|
|
2666
|
+
"function share(ACP calldata acp) external returns (bytes32)",
|
|
2667
|
+
"function removeShare(bytes32 shareId) external",
|
|
2668
|
+
"function sharesFor(address recipient) external view returns (ACP[] memory)",
|
|
2669
|
+
"function getShare(bytes32 shareId) external view returns (ACP memory)",
|
|
2670
|
+
"function isShareValid(bytes32 shareId) external view returns (bool)"
|
|
2671
|
+
]);
|
|
2672
|
+
var ACP_TUPLE = [
|
|
2673
|
+
{
|
|
2674
|
+
type: "tuple",
|
|
2675
|
+
components: [
|
|
2676
|
+
{ name: "issuer", type: "address" },
|
|
2677
|
+
{ name: "expiration", type: "uint64" },
|
|
2678
|
+
{ name: "recipient", type: "address" },
|
|
2679
|
+
{ name: "revokerData", type: "uint256" },
|
|
2680
|
+
{ name: "revokerContract", type: "address" },
|
|
2681
|
+
{ name: "scope", type: "uint8" },
|
|
2682
|
+
{ name: "contracts", type: "address[]" },
|
|
2683
|
+
{ name: "handles", type: "bytes32[]" },
|
|
2684
|
+
{ name: "sealingKey", type: "bytes32" },
|
|
2685
|
+
{ name: "issuerSignature", type: "bytes" },
|
|
2686
|
+
{ name: "recipientSignature", type: "bytes" }
|
|
2687
|
+
]
|
|
2688
|
+
}
|
|
2689
|
+
];
|
|
2690
|
+
var ZERO_BYTES32 = `0x${"0".repeat(64)}`;
|
|
2691
|
+
var toChainShare = (acp) => {
|
|
2692
|
+
const pub = ACPUtils.getPublic(acp, true);
|
|
2693
|
+
return {
|
|
2694
|
+
...pub,
|
|
2695
|
+
expiration: BigInt(pub.expiration),
|
|
2696
|
+
revokerData: BigInt(pub.revokerData),
|
|
2697
|
+
sealingKey: ZERO_BYTES32,
|
|
2698
|
+
recipientSignature: "0x"
|
|
2699
|
+
};
|
|
2700
|
+
};
|
|
2701
|
+
var computeShareId = (acp) => {
|
|
2702
|
+
const p = toChainShare(acp);
|
|
2703
|
+
return viem.keccak256(viem.encodeAbiParameters(ACP_TUPLE, [p]));
|
|
2704
|
+
};
|
|
2705
|
+
var shareOnChain = async (acp, walletClient, registry) => {
|
|
2706
|
+
if (acp.type !== "sharing") {
|
|
2707
|
+
throw new Error(`Cannot share a '${acp.type}' ACP on-chain \u2014 only 'sharing' ACPs are shareable.`);
|
|
2708
|
+
}
|
|
2709
|
+
if (acp.issuerSignature === "0x") {
|
|
2710
|
+
throw new Error("Cannot share an unsigned sharing ACP \u2014 sign it first.");
|
|
2711
|
+
}
|
|
2712
|
+
if (walletClient.account == null)
|
|
2713
|
+
throw new Error("Missing walletClient account");
|
|
2714
|
+
if (walletClient.account.address.toLowerCase() !== acp.issuer.toLowerCase()) {
|
|
2715
|
+
throw new Error("Only the ACP issuer can share it on-chain");
|
|
2716
|
+
}
|
|
2717
|
+
const txHash = await walletClient.writeContract({
|
|
2718
|
+
address: registry,
|
|
2719
|
+
abi: ACP_SHARE_REGISTRY_ABI,
|
|
2720
|
+
functionName: "share",
|
|
2721
|
+
args: [toChainShare(acp)],
|
|
2722
|
+
account: walletClient.account,
|
|
2723
|
+
chain: walletClient.chain ?? null
|
|
2724
|
+
});
|
|
2725
|
+
return { txHash, shareId: computeShareId(acp) };
|
|
2726
|
+
};
|
|
2727
|
+
var getIncomingShares = async (publicClient, registry, recipient) => {
|
|
2728
|
+
const raw = await publicClient.readContract({
|
|
2729
|
+
address: registry,
|
|
2730
|
+
abi: ACP_SHARE_REGISTRY_ABI,
|
|
2731
|
+
functionName: "sharesFor",
|
|
2732
|
+
args: [recipient]
|
|
2733
|
+
});
|
|
2734
|
+
return raw.map((s) => ({
|
|
2735
|
+
shareId: viem.keccak256(viem.encodeAbiParameters(ACP_TUPLE, [s])),
|
|
2736
|
+
issuer: s.issuer,
|
|
2737
|
+
expiration: Number(s.expiration),
|
|
2738
|
+
recipient: s.recipient,
|
|
2739
|
+
revokerData: Number(s.revokerData),
|
|
2740
|
+
revokerContract: s.revokerContract,
|
|
2741
|
+
scope: Number(s.scope),
|
|
2742
|
+
contracts: [...s.contracts],
|
|
2743
|
+
handles: [...s.handles],
|
|
2744
|
+
issuerSignature: s.issuerSignature
|
|
2745
|
+
}));
|
|
2746
|
+
};
|
|
2747
|
+
var importFromChain = async (share, publicClient, walletClient) => {
|
|
2748
|
+
const { shareId: _shareId, ...options } = share;
|
|
2749
|
+
return importShared({ ...options, type: "sharing" }, publicClient, walletClient);
|
|
2750
|
+
};
|
|
2751
|
+
var removeShareOnChain = async (shareId, walletClient, registry) => {
|
|
2752
|
+
if (walletClient.account == null)
|
|
2753
|
+
throw new Error("Missing walletClient account");
|
|
2754
|
+
return walletClient.writeContract({
|
|
2755
|
+
address: registry,
|
|
2756
|
+
abi: ACP_SHARE_REGISTRY_ABI,
|
|
2757
|
+
functionName: "removeShare",
|
|
2758
|
+
args: [shareId],
|
|
2759
|
+
account: walletClient.account,
|
|
2760
|
+
chain: walletClient.chain ?? null
|
|
2761
|
+
});
|
|
2762
|
+
};
|
|
2763
|
+
var removeACP2 = async (chainId, account, hash) => acpStore.removeACP(chainId, account, hash);
|
|
2764
|
+
var removeActiveACP = async (chainId, account) => acpStore.removeActiveACPHash(chainId, account);
|
|
2765
|
+
var acps = {
|
|
2766
|
+
getSnapshot: acpStore.store.getState,
|
|
2767
|
+
subscribe: acpStore.store.subscribe,
|
|
2584
2768
|
createSelf,
|
|
2585
2769
|
createSharing,
|
|
2586
2770
|
importShared,
|
|
2587
|
-
|
|
2588
|
-
|
|
2771
|
+
getOrCreateSelfACP,
|
|
2772
|
+
getOrCreateSharingACP,
|
|
2589
2773
|
getHash,
|
|
2590
2774
|
export: exportShared,
|
|
2591
2775
|
serialize,
|
|
2592
2776
|
deserialize,
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2777
|
+
getACP: getACP2,
|
|
2778
|
+
getACPs: getACPs2,
|
|
2779
|
+
getActiveACP: getActiveACP2,
|
|
2780
|
+
getActiveACPHash: getActiveACPHash2,
|
|
2781
|
+
removeACP: removeACP2,
|
|
2782
|
+
selectActiveACP,
|
|
2783
|
+
removeActiveACP,
|
|
2784
|
+
revokeACP,
|
|
2785
|
+
revokeAllACPs,
|
|
2786
|
+
isACPRevoked,
|
|
2787
|
+
shareOnChain,
|
|
2788
|
+
getIncomingShares,
|
|
2789
|
+
importFromChain,
|
|
2790
|
+
removeShareOnChain,
|
|
2791
|
+
computeShareId,
|
|
2792
|
+
applyACPDefaults,
|
|
2793
|
+
applyACPDefaultsFromChain,
|
|
2794
|
+
getAclServedAddresses,
|
|
2795
|
+
clearAclServedAddresses
|
|
2600
2796
|
};
|
|
2601
2797
|
function uint160ToAddress(uint160) {
|
|
2602
2798
|
const hexStr = uint160.toString(16).padStart(40, "0");
|
|
@@ -2659,13 +2855,16 @@ var MockThresholdNetworkAbi = [
|
|
|
2659
2855
|
{
|
|
2660
2856
|
name: "permission",
|
|
2661
2857
|
type: "tuple",
|
|
2662
|
-
internalType: "struct
|
|
2858
|
+
internalType: "struct ACPermission",
|
|
2663
2859
|
components: [
|
|
2664
2860
|
{ name: "issuer", type: "address", internalType: "address" },
|
|
2665
2861
|
{ name: "expiration", type: "uint64", internalType: "uint64" },
|
|
2666
2862
|
{ name: "recipient", type: "address", internalType: "address" },
|
|
2667
|
-
{ name: "
|
|
2668
|
-
{ name: "
|
|
2863
|
+
{ name: "revokerData", type: "uint256", internalType: "uint256" },
|
|
2864
|
+
{ name: "revokerContract", type: "address", internalType: "address" },
|
|
2865
|
+
{ name: "scope", type: "uint8", internalType: "uint8" },
|
|
2866
|
+
{ name: "contracts", type: "address[]", internalType: "address[]" },
|
|
2867
|
+
{ name: "handles", type: "bytes32[]", internalType: "bytes32[]" },
|
|
2669
2868
|
{ name: "sealingKey", type: "bytes32", internalType: "bytes32" },
|
|
2670
2869
|
{ name: "issuerSignature", type: "bytes", internalType: "bytes" },
|
|
2671
2870
|
{ name: "recipientSignature", type: "bytes", internalType: "bytes" }
|
|
@@ -2688,13 +2887,16 @@ var MockThresholdNetworkAbi = [
|
|
|
2688
2887
|
{
|
|
2689
2888
|
name: "permission",
|
|
2690
2889
|
type: "tuple",
|
|
2691
|
-
internalType: "struct
|
|
2890
|
+
internalType: "struct ACPermission",
|
|
2692
2891
|
components: [
|
|
2693
2892
|
{ name: "issuer", type: "address", internalType: "address" },
|
|
2694
2893
|
{ name: "expiration", type: "uint64", internalType: "uint64" },
|
|
2695
2894
|
{ name: "recipient", type: "address", internalType: "address" },
|
|
2696
|
-
{ name: "
|
|
2697
|
-
{ name: "
|
|
2895
|
+
{ name: "revokerData", type: "uint256", internalType: "uint256" },
|
|
2896
|
+
{ name: "revokerContract", type: "address", internalType: "address" },
|
|
2897
|
+
{ name: "scope", type: "uint8", internalType: "uint8" },
|
|
2898
|
+
{ name: "contracts", type: "address[]", internalType: "address[]" },
|
|
2899
|
+
{ name: "handles", type: "bytes32[]", internalType: "bytes32[]" },
|
|
2698
2900
|
{ name: "sealingKey", type: "bytes32", internalType: "bytes32" },
|
|
2699
2901
|
{ name: "issuerSignature", type: "bytes", internalType: "bytes" },
|
|
2700
2902
|
{ name: "recipientSignature", type: "bytes", internalType: "bytes" }
|
|
@@ -2759,19 +2961,22 @@ var MockThresholdNetworkAbi = [
|
|
|
2759
2961
|
},
|
|
2760
2962
|
{
|
|
2761
2963
|
type: "function",
|
|
2762
|
-
name: "
|
|
2964
|
+
name: "decryptForTxWithACP",
|
|
2763
2965
|
inputs: [
|
|
2764
2966
|
{ name: "ctHash", type: "uint256", internalType: "uint256" },
|
|
2765
2967
|
{
|
|
2766
2968
|
name: "permission",
|
|
2767
2969
|
type: "tuple",
|
|
2768
|
-
internalType: "struct
|
|
2970
|
+
internalType: "struct ACPermission",
|
|
2769
2971
|
components: [
|
|
2770
2972
|
{ name: "issuer", type: "address", internalType: "address" },
|
|
2771
2973
|
{ name: "expiration", type: "uint64", internalType: "uint64" },
|
|
2772
2974
|
{ name: "recipient", type: "address", internalType: "address" },
|
|
2773
|
-
{ name: "
|
|
2774
|
-
{ name: "
|
|
2975
|
+
{ name: "revokerData", type: "uint256", internalType: "uint256" },
|
|
2976
|
+
{ name: "revokerContract", type: "address", internalType: "address" },
|
|
2977
|
+
{ name: "scope", type: "uint8", internalType: "uint8" },
|
|
2978
|
+
{ name: "contracts", type: "address[]", internalType: "address[]" },
|
|
2979
|
+
{ name: "handles", type: "bytes32[]", internalType: "bytes32[]" },
|
|
2775
2980
|
{ name: "sealingKey", type: "bytes32", internalType: "bytes32" },
|
|
2776
2981
|
{ name: "issuerSignature", type: "bytes", internalType: "bytes" },
|
|
2777
2982
|
{ name: "recipientSignature", type: "bytes", internalType: "bytes" }
|
|
@@ -2787,7 +2992,7 @@ var MockThresholdNetworkAbi = [
|
|
|
2787
2992
|
},
|
|
2788
2993
|
{
|
|
2789
2994
|
type: "function",
|
|
2790
|
-
name: "
|
|
2995
|
+
name: "decryptForTxWithoutACP",
|
|
2791
2996
|
inputs: [{ name: "ctHash", type: "uint256", internalType: "uint256" }],
|
|
2792
2997
|
outputs: [
|
|
2793
2998
|
{ name: "allowed", type: "bool", internalType: "bool" },
|
|
@@ -2799,12 +3004,12 @@ var MockThresholdNetworkAbi = [
|
|
|
2799
3004
|
];
|
|
2800
3005
|
|
|
2801
3006
|
// core/decrypt/cofheMocksDecryptForView.ts
|
|
2802
|
-
async function cofheMocksDecryptForView(ctHash, utype,
|
|
2803
|
-
const
|
|
3007
|
+
async function cofheMocksDecryptForView(ctHash, utype, acp, publicClient) {
|
|
3008
|
+
const wireAcp = ACPUtils.getPublic(acp, true);
|
|
2804
3009
|
const permissionWithBigInts = {
|
|
2805
|
-
...
|
|
2806
|
-
expiration: BigInt(
|
|
2807
|
-
|
|
3010
|
+
...wireAcp,
|
|
3011
|
+
expiration: BigInt(wireAcp.expiration),
|
|
3012
|
+
revokerData: BigInt(wireAcp.revokerData)
|
|
2808
3013
|
};
|
|
2809
3014
|
const [allowed, error, result] = await publicClient.readContract({
|
|
2810
3015
|
address: MOCKS_THRESHOLD_NETWORK_ADDRESS,
|
|
@@ -2825,7 +3030,7 @@ async function cofheMocksDecryptForView(ctHash, utype, permit, publicClient) {
|
|
|
2825
3030
|
});
|
|
2826
3031
|
}
|
|
2827
3032
|
const sealedBigInt = BigInt(result);
|
|
2828
|
-
const sealingKeyBigInt = BigInt(
|
|
3033
|
+
const sealingKeyBigInt = BigInt(acp.sealingKey);
|
|
2829
3034
|
const unsealed = sealedBigInt ^ sealingKeyBigInt;
|
|
2830
3035
|
return unsealed;
|
|
2831
3036
|
}
|
|
@@ -2861,11 +3066,61 @@ function computeMinuteRampPollIntervalMs(elapsedMs, params) {
|
|
|
2861
3066
|
return Math.min(params.maxIntervalMs, Math.max(params.minIntervalMs, intervalMs));
|
|
2862
3067
|
}
|
|
2863
3068
|
|
|
3069
|
+
// core/decrypt/apiError.ts
|
|
3070
|
+
var BACKEND_ERROR_CODE_TO_COFHE_ERROR_CODE = {
|
|
3071
|
+
bad_request: "BAD_REQUEST" /* BadRequest */,
|
|
3072
|
+
unknown_chain: "UNKNOWN_CHAIN" /* UnknownChain */,
|
|
3073
|
+
acp_malformed: "ACP_MALFORMED" /* ACPMalformed */,
|
|
3074
|
+
acp_denied: "ACP_DENIED" /* ACPDenied */,
|
|
3075
|
+
// ACP-era backends fold revoked into denied
|
|
3076
|
+
acp_expired: "ACP_EXPIRED" /* ACPExpired */,
|
|
3077
|
+
acp_invalid: "ACP_INVALID" /* ACPInvalid */,
|
|
3078
|
+
acp_required: "ACP_REQUIRED" /* ACPRequired */,
|
|
3079
|
+
acp_verifier_error: "ACP_VERIFIER_ERROR" /* ACPVerifierError */,
|
|
3080
|
+
acp_verifier_timeout: "ACP_VERIFIER_TIMEOUT" /* ACPVerifierTimeout */,
|
|
3081
|
+
not_publicly_allowed: "NOT_PUBLICLY_ALLOWED" /* NotPubliclyAllowed */,
|
|
3082
|
+
ct_not_found: "CT_NOT_FOUND" /* CtNotFound */,
|
|
3083
|
+
unsupported_security_zone: "UNSUPPORTED_SECURITY_ZONE" /* UnsupportedSecurityZone */,
|
|
3084
|
+
unsupported_type: "UNSUPPORTED_TYPE" /* UnsupportedType */,
|
|
3085
|
+
internal_error: "INTERNAL_ERROR" /* InternalError */,
|
|
3086
|
+
signing_failed: "SIGNING_FAILED" /* SigningFailed */,
|
|
3087
|
+
ct_source_error: "CT_SOURCE_ERROR" /* CtSourceError */,
|
|
3088
|
+
ct_source_timeout: "CT_SOURCE_TIMEOUT" /* CtSourceTimeout */,
|
|
3089
|
+
seal_failed: "SEAL_FAILED" /* SealFailed */
|
|
3090
|
+
};
|
|
3091
|
+
function isBackendApiErrorCode(value) {
|
|
3092
|
+
return value in BACKEND_ERROR_CODE_TO_COFHE_ERROR_CODE;
|
|
3093
|
+
}
|
|
3094
|
+
async function parseApiErrorResponseBody(response) {
|
|
3095
|
+
let errorMessage = `HTTP ${response.status}`;
|
|
3096
|
+
let apiErrorCode;
|
|
3097
|
+
try {
|
|
3098
|
+
const body = await response.json();
|
|
3099
|
+
if (body && typeof body === "object") {
|
|
3100
|
+
const record = body;
|
|
3101
|
+
if (typeof record.error === "string" && record.error.length > 0) {
|
|
3102
|
+
apiErrorCode = record.error;
|
|
3103
|
+
}
|
|
3104
|
+
if (typeof record.error_message === "string" && record.error_message.length > 0) {
|
|
3105
|
+
errorMessage = record.error_message;
|
|
3106
|
+
} else if (typeof record.message === "string" && record.message.length > 0) {
|
|
3107
|
+
errorMessage = record.message;
|
|
3108
|
+
}
|
|
3109
|
+
}
|
|
3110
|
+
} catch {
|
|
3111
|
+
errorMessage = response.statusText || errorMessage;
|
|
3112
|
+
}
|
|
3113
|
+
return { apiErrorCode, errorMessage };
|
|
3114
|
+
}
|
|
3115
|
+
function mapApiErrorCodeToCofheErrorCode(apiErrorCode, fallback) {
|
|
3116
|
+
if (apiErrorCode && isBackendApiErrorCode(apiErrorCode)) {
|
|
3117
|
+
return BACKEND_ERROR_CODE_TO_COFHE_ERROR_CODE[apiErrorCode];
|
|
3118
|
+
}
|
|
3119
|
+
return fallback;
|
|
3120
|
+
}
|
|
3121
|
+
|
|
2864
3122
|
// core/decrypt/submitRetry.ts
|
|
2865
3123
|
var DEFAULT_404_RETRY_TIMEOUT_MS = 1e4;
|
|
2866
|
-
function isRetryableSubmitStatus(status) {
|
|
2867
|
-
return status === 204 || status === 404;
|
|
2868
|
-
}
|
|
2869
3124
|
function normalize404RetryTimeoutMs(params) {
|
|
2870
3125
|
const { timeoutMs, operationLabel, errorCode } = params;
|
|
2871
3126
|
if (timeoutMs === void 0)
|
|
@@ -2882,32 +3137,24 @@ function normalize404RetryTimeoutMs(params) {
|
|
|
2882
3137
|
return timeoutMs;
|
|
2883
3138
|
}
|
|
2884
3139
|
async function classifySubmitResponse(params) {
|
|
2885
|
-
const { response,
|
|
2886
|
-
if (
|
|
2887
|
-
return { kind: "retryable", status:
|
|
3140
|
+
const { response, fallbackErrorCode } = params;
|
|
3141
|
+
if (response.status === 204) {
|
|
3142
|
+
return { kind: "retryable", status: 204 };
|
|
2888
3143
|
}
|
|
2889
3144
|
if (response.ok) {
|
|
2890
3145
|
return { kind: "parse-json" };
|
|
2891
3146
|
}
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
const maybeErrorMessage = extractErrorMessage?.(errorBody);
|
|
2896
|
-
if (typeof maybeErrorMessage === "string" && maybeErrorMessage.length > 0) {
|
|
2897
|
-
errorMessage = maybeErrorMessage;
|
|
2898
|
-
} else if (errorBody && typeof errorBody === "object") {
|
|
2899
|
-
const defaultMessage = errorBody.error_message;
|
|
2900
|
-
const fallbackMessage = errorBody.message;
|
|
2901
|
-
if (typeof defaultMessage === "string" && defaultMessage.length > 0) {
|
|
2902
|
-
errorMessage = defaultMessage;
|
|
2903
|
-
} else if (typeof fallbackMessage === "string" && fallbackMessage.length > 0) {
|
|
2904
|
-
errorMessage = fallbackMessage;
|
|
2905
|
-
}
|
|
2906
|
-
}
|
|
2907
|
-
} catch {
|
|
2908
|
-
errorMessage = response.statusText || errorMessage;
|
|
3147
|
+
const { apiErrorCode, errorMessage } = await parseApiErrorResponseBody(response);
|
|
3148
|
+
if (response.status === 404) {
|
|
3149
|
+
return { kind: "retryable", status: 404, apiErrorMessage: errorMessage };
|
|
2909
3150
|
}
|
|
2910
|
-
return {
|
|
3151
|
+
return {
|
|
3152
|
+
kind: "fatal-http",
|
|
3153
|
+
status: response.status,
|
|
3154
|
+
cofheErrorCode: mapApiErrorCodeToCofheErrorCode(apiErrorCode, fallbackErrorCode),
|
|
3155
|
+
apiErrorCode,
|
|
3156
|
+
errorMessage
|
|
3157
|
+
};
|
|
2911
3158
|
}
|
|
2912
3159
|
function throwIfSubmitRetryTimedOut(params) {
|
|
2913
3160
|
const {
|
|
@@ -2919,12 +3166,14 @@ function throwIfSubmitRetryTimedOut(params) {
|
|
|
2919
3166
|
overallTimeoutMs,
|
|
2920
3167
|
thresholdNetworkUrl,
|
|
2921
3168
|
body,
|
|
2922
|
-
attemptIndex
|
|
3169
|
+
attemptIndex,
|
|
3170
|
+
lastKnownErrorMessage
|
|
2923
3171
|
} = params;
|
|
2924
3172
|
if (status === 404 && elapsedMs > retry404TimeoutMs) {
|
|
2925
3173
|
throw new CofheError({
|
|
2926
|
-
code:
|
|
2927
|
-
|
|
3174
|
+
code: "CT_NOT_FOUND" /* CtNotFound */,
|
|
3175
|
+
apiErrorCode: "ct_not_found",
|
|
3176
|
+
message: `${operationLabel} ciphertext not found after retrying for ${retry404TimeoutMs}ms` + (lastKnownErrorMessage ? `: ${lastKnownErrorMessage}` : ""),
|
|
2928
3177
|
hint: "The ciphertext may not be indexed yet. Increase set404RetryTimeout(...) if the backend is slow to index ciphertexts.",
|
|
2929
3178
|
context: {
|
|
2930
3179
|
thresholdNetworkUrl,
|
|
@@ -2950,6 +3199,62 @@ function throwIfSubmitRetryTimedOut(params) {
|
|
|
2950
3199
|
});
|
|
2951
3200
|
}
|
|
2952
3201
|
}
|
|
3202
|
+
function normalizeTnSignature(signature) {
|
|
3203
|
+
if (typeof signature !== "string") {
|
|
3204
|
+
throw new CofheError({
|
|
3205
|
+
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3206
|
+
message: "decrypt response missing signature",
|
|
3207
|
+
context: {
|
|
3208
|
+
signature
|
|
3209
|
+
}
|
|
3210
|
+
});
|
|
3211
|
+
}
|
|
3212
|
+
const trimmed = signature.trim();
|
|
3213
|
+
if (trimmed.length === 0) {
|
|
3214
|
+
throw new CofheError({
|
|
3215
|
+
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3216
|
+
message: "decrypt response returned empty signature"
|
|
3217
|
+
});
|
|
3218
|
+
}
|
|
3219
|
+
const prefixed = trimmed.startsWith("0x") ? trimmed : `0x${trimmed}`;
|
|
3220
|
+
const parsed = viem.parseSignature(prefixed);
|
|
3221
|
+
return viem.serializeSignature(parsed);
|
|
3222
|
+
}
|
|
3223
|
+
function parseDecryptedBytesToBigInt(decrypted) {
|
|
3224
|
+
if (!Array.isArray(decrypted)) {
|
|
3225
|
+
throw new CofheError({
|
|
3226
|
+
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3227
|
+
message: "decrypt response field <decrypted> must be a byte array",
|
|
3228
|
+
context: {
|
|
3229
|
+
decrypted
|
|
3230
|
+
}
|
|
3231
|
+
});
|
|
3232
|
+
}
|
|
3233
|
+
if (decrypted.length === 0) {
|
|
3234
|
+
throw new CofheError({
|
|
3235
|
+
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3236
|
+
message: "decrypt response field <decrypted> was an empty byte array",
|
|
3237
|
+
context: {
|
|
3238
|
+
decrypted
|
|
3239
|
+
}
|
|
3240
|
+
});
|
|
3241
|
+
}
|
|
3242
|
+
let hex = "";
|
|
3243
|
+
for (const b of decrypted) {
|
|
3244
|
+
if (typeof b !== "number" || !Number.isInteger(b) || b < 0 || b > 255) {
|
|
3245
|
+
throw new CofheError({
|
|
3246
|
+
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3247
|
+
message: "decrypt response field <decrypted> contained a non-byte value",
|
|
3248
|
+
context: {
|
|
3249
|
+
badElement: b,
|
|
3250
|
+
decrypted
|
|
3251
|
+
}
|
|
3252
|
+
});
|
|
3253
|
+
}
|
|
3254
|
+
hex += b.toString(16).padStart(2, "0");
|
|
3255
|
+
}
|
|
3256
|
+
return BigInt(`0x${hex}`);
|
|
3257
|
+
}
|
|
2953
3258
|
|
|
2954
3259
|
// core/decrypt/tnSealOutputV2.ts
|
|
2955
3260
|
var POLL_INTERVAL_MS = 1e3;
|
|
@@ -3012,13 +3317,14 @@ function parseCompletedSealOutputResponse(params) {
|
|
|
3012
3317
|
}
|
|
3013
3318
|
return convertSealedData(sealed);
|
|
3014
3319
|
}
|
|
3015
|
-
async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId,
|
|
3320
|
+
async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, acp, overallStartTime, retry404TimeoutMs, onPoll) {
|
|
3016
3321
|
const body = {
|
|
3017
3322
|
ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
|
|
3018
3323
|
host_chain_id: chainId,
|
|
3019
|
-
|
|
3324
|
+
acp
|
|
3020
3325
|
};
|
|
3021
3326
|
let attemptIndex = 0;
|
|
3327
|
+
let last404ApiErrorMessage;
|
|
3022
3328
|
for (; ; ) {
|
|
3023
3329
|
let response;
|
|
3024
3330
|
try {
|
|
@@ -3046,16 +3352,19 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, per
|
|
|
3046
3352
|
}
|
|
3047
3353
|
});
|
|
3048
3354
|
}
|
|
3049
|
-
const responseClassification = await classifySubmitResponse({
|
|
3355
|
+
const responseClassification = await classifySubmitResponse({
|
|
3356
|
+
response,
|
|
3357
|
+
fallbackErrorCode: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */
|
|
3358
|
+
});
|
|
3050
3359
|
if (responseClassification.kind === "fatal-http") {
|
|
3051
3360
|
throw new CofheError({
|
|
3052
|
-
code:
|
|
3361
|
+
code: responseClassification.cofheErrorCode,
|
|
3362
|
+
apiErrorCode: responseClassification.apiErrorCode,
|
|
3053
3363
|
message: `sealOutput request failed: ${responseClassification.errorMessage}`,
|
|
3054
3364
|
hint: "Check the threshold network URL and request parameters.",
|
|
3055
3365
|
context: {
|
|
3056
3366
|
thresholdNetworkUrl,
|
|
3057
|
-
status:
|
|
3058
|
-
statusText: response.statusText,
|
|
3367
|
+
status: responseClassification.status,
|
|
3059
3368
|
body,
|
|
3060
3369
|
attemptIndex
|
|
3061
3370
|
}
|
|
@@ -3101,6 +3410,9 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, per
|
|
|
3101
3410
|
}
|
|
3102
3411
|
});
|
|
3103
3412
|
}
|
|
3413
|
+
if (responseClassification.status === 404) {
|
|
3414
|
+
last404ApiErrorMessage = responseClassification.apiErrorMessage;
|
|
3415
|
+
}
|
|
3104
3416
|
const elapsedMs = Date.now() - overallStartTime;
|
|
3105
3417
|
throwIfSubmitRetryTimedOut({
|
|
3106
3418
|
operationLabel: "sealOutput",
|
|
@@ -3111,7 +3423,8 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, per
|
|
|
3111
3423
|
overallTimeoutMs: SEAL_OUTPUT_TIMEOUT_MS,
|
|
3112
3424
|
thresholdNetworkUrl,
|
|
3113
3425
|
body,
|
|
3114
|
-
attemptIndex
|
|
3426
|
+
attemptIndex,
|
|
3427
|
+
lastKnownErrorMessage: last404ApiErrorMessage
|
|
3115
3428
|
});
|
|
3116
3429
|
onPoll?.({
|
|
3117
3430
|
operation: "sealoutput",
|
|
@@ -3189,15 +3502,10 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStart
|
|
|
3189
3502
|
});
|
|
3190
3503
|
}
|
|
3191
3504
|
if (!response.ok) {
|
|
3192
|
-
|
|
3193
|
-
try {
|
|
3194
|
-
const errorBody = await response.json();
|
|
3195
|
-
errorMessage = errorBody.error_message || errorBody.message || errorMessage;
|
|
3196
|
-
} catch {
|
|
3197
|
-
errorMessage = response.statusText || errorMessage;
|
|
3198
|
-
}
|
|
3505
|
+
const { apiErrorCode, errorMessage } = await parseApiErrorResponseBody(response);
|
|
3199
3506
|
throw new CofheError({
|
|
3200
|
-
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed
|
|
3507
|
+
code: mapApiErrorCodeToCofheErrorCode(apiErrorCode, "SEAL_OUTPUT_FAILED" /* SealOutputFailed */),
|
|
3508
|
+
apiErrorCode,
|
|
3201
3509
|
message: `sealOutput status poll failed: ${errorMessage}`,
|
|
3202
3510
|
context: {
|
|
3203
3511
|
thresholdNetworkUrl,
|
|
@@ -3241,7 +3549,7 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStart
|
|
|
3241
3549
|
});
|
|
3242
3550
|
}
|
|
3243
3551
|
async function tnSealOutputV2(params) {
|
|
3244
|
-
const { thresholdNetworkUrl, ctHash, chainId,
|
|
3552
|
+
const { thresholdNetworkUrl, ctHash, chainId, acp, retry404TimeoutMs, onPoll } = params;
|
|
3245
3553
|
const normalized404RetryTimeoutMs = normalize404RetryTimeoutMs({
|
|
3246
3554
|
timeoutMs: retry404TimeoutMs,
|
|
3247
3555
|
operationLabel: "sealOutput",
|
|
@@ -3252,7 +3560,7 @@ async function tnSealOutputV2(params) {
|
|
|
3252
3560
|
thresholdNetworkUrl,
|
|
3253
3561
|
ctHash,
|
|
3254
3562
|
chainId,
|
|
3255
|
-
|
|
3563
|
+
acp,
|
|
3256
3564
|
overallStartTime,
|
|
3257
3565
|
normalized404RetryTimeoutMs,
|
|
3258
3566
|
onPoll
|
|
@@ -3268,8 +3576,8 @@ var DEFAULT_404_RETRY_TIMEOUT_MS2 = 1e4;
|
|
|
3268
3576
|
var DecryptForViewBuilder = class extends BaseBuilder {
|
|
3269
3577
|
ctHash;
|
|
3270
3578
|
utype;
|
|
3271
|
-
|
|
3272
|
-
|
|
3579
|
+
acpHash;
|
|
3580
|
+
acp;
|
|
3273
3581
|
pollCallback;
|
|
3274
3582
|
retry404TimeoutMs = DEFAULT_404_RETRY_TIMEOUT_MS2;
|
|
3275
3583
|
constructor(params) {
|
|
@@ -3283,11 +3591,11 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3283
3591
|
});
|
|
3284
3592
|
this.ctHash = params.ctHash;
|
|
3285
3593
|
this.utype = params.utype;
|
|
3286
|
-
this.
|
|
3287
|
-
this.
|
|
3594
|
+
this.acpHash = params.acpHash;
|
|
3595
|
+
this.acp = params.acp;
|
|
3288
3596
|
}
|
|
3289
3597
|
/**
|
|
3290
|
-
* @param chainId - Chain to decrypt values from. Used to fetch the threshold network URL and use the correct
|
|
3598
|
+
* @param chainId - Chain to decrypt values from. Used to fetch the threshold network URL and use the correct acp.
|
|
3291
3599
|
*
|
|
3292
3600
|
* If not provided, the chainId will be fetched from the connected publicClient.
|
|
3293
3601
|
*
|
|
@@ -3308,7 +3616,7 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3308
3616
|
return this.chainId;
|
|
3309
3617
|
}
|
|
3310
3618
|
/**
|
|
3311
|
-
* @param account - Account to decrypt values from. Used to fetch the correct
|
|
3619
|
+
* @param account - Account to decrypt values from. Used to fetch the correct acp.
|
|
3312
3620
|
*
|
|
3313
3621
|
* If not provided, the account will be fetched from the connected walletClient.
|
|
3314
3622
|
*
|
|
@@ -3345,61 +3653,61 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3345
3653
|
this.retry404TimeoutMs = timeoutMs;
|
|
3346
3654
|
return this;
|
|
3347
3655
|
}
|
|
3348
|
-
|
|
3349
|
-
if (typeof
|
|
3350
|
-
this.
|
|
3351
|
-
this.
|
|
3352
|
-
} else if (
|
|
3353
|
-
this.
|
|
3354
|
-
this.
|
|
3656
|
+
withACP(acpOrACPHash) {
|
|
3657
|
+
if (typeof acpOrACPHash === "string") {
|
|
3658
|
+
this.acpHash = acpOrACPHash;
|
|
3659
|
+
this.acp = void 0;
|
|
3660
|
+
} else if (acpOrACPHash === void 0) {
|
|
3661
|
+
this.acpHash = void 0;
|
|
3662
|
+
this.acp = void 0;
|
|
3355
3663
|
} else {
|
|
3356
|
-
this.
|
|
3357
|
-
this.
|
|
3664
|
+
this.acp = acpOrACPHash;
|
|
3665
|
+
this.acpHash = void 0;
|
|
3358
3666
|
}
|
|
3359
3667
|
return this;
|
|
3360
3668
|
}
|
|
3361
3669
|
/**
|
|
3362
|
-
* @param
|
|
3670
|
+
* @param acpHash - ACP hash to decrypt values from. Used to fetch the correct acp.
|
|
3363
3671
|
*
|
|
3364
|
-
* If not provided, the active
|
|
3365
|
-
* If `
|
|
3672
|
+
* If not provided, the active acp for the chainId and account will be used.
|
|
3673
|
+
* If `setACP()` is called, it will be used regardless of chainId, account, or acpHash.
|
|
3366
3674
|
*
|
|
3367
3675
|
* Example:
|
|
3368
3676
|
* ```typescript
|
|
3369
3677
|
* const unsealed = await client.decryptForView(ctHash, utype)
|
|
3370
|
-
* .
|
|
3678
|
+
* .setACPHash('0x1234567890123456789012345678901234567890')
|
|
3371
3679
|
* .execute();
|
|
3372
3680
|
* ```
|
|
3373
3681
|
*
|
|
3374
3682
|
* @returns The chainable DecryptForViewBuilder instance.
|
|
3375
3683
|
*/
|
|
3376
|
-
/** @deprecated Use `
|
|
3377
|
-
|
|
3378
|
-
return this.
|
|
3684
|
+
/** @deprecated Use `withACP(acpHash)` instead. */
|
|
3685
|
+
setACPHash(acpHash) {
|
|
3686
|
+
return this.withACP(acpHash);
|
|
3379
3687
|
}
|
|
3380
|
-
|
|
3381
|
-
return this.
|
|
3688
|
+
getACPHash() {
|
|
3689
|
+
return this.acpHash;
|
|
3382
3690
|
}
|
|
3383
3691
|
/**
|
|
3384
|
-
* @param
|
|
3692
|
+
* @param acp - ACP to decrypt values with. If provided, it will be used regardless of chainId, account, or acpHash.
|
|
3385
3693
|
*
|
|
3386
|
-
* If not provided, the
|
|
3694
|
+
* If not provided, the acp will be determined by chainId, account, and acpHash.
|
|
3387
3695
|
*
|
|
3388
3696
|
* Example:
|
|
3389
3697
|
* ```typescript
|
|
3390
3698
|
* const unsealed = await client.decryptForView(ctHash, utype)
|
|
3391
|
-
* .
|
|
3699
|
+
* .setACP(acp)
|
|
3392
3700
|
* .execute();
|
|
3393
3701
|
* ```
|
|
3394
3702
|
*
|
|
3395
3703
|
* @returns The chainable DecryptForViewBuilder instance.
|
|
3396
3704
|
*/
|
|
3397
|
-
/** @deprecated Use `
|
|
3398
|
-
|
|
3399
|
-
return this.
|
|
3705
|
+
/** @deprecated Use `withACP(acp)` instead. */
|
|
3706
|
+
setACP(acp) {
|
|
3707
|
+
return this.withACP(acp);
|
|
3400
3708
|
}
|
|
3401
|
-
|
|
3402
|
-
return this.
|
|
3709
|
+
getACP() {
|
|
3710
|
+
return this.acp;
|
|
3403
3711
|
}
|
|
3404
3712
|
async getThresholdNetworkUrl() {
|
|
3405
3713
|
this.assertChainId();
|
|
@@ -3415,77 +3723,77 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3415
3723
|
}
|
|
3416
3724
|
});
|
|
3417
3725
|
}
|
|
3418
|
-
async
|
|
3419
|
-
if (this.
|
|
3420
|
-
return this.
|
|
3726
|
+
async getResolvedACP() {
|
|
3727
|
+
if (this.acp)
|
|
3728
|
+
return this.acp;
|
|
3421
3729
|
this.assertChainId();
|
|
3422
3730
|
this.assertAccount();
|
|
3423
|
-
if (this.
|
|
3424
|
-
const
|
|
3425
|
-
if (!
|
|
3731
|
+
if (this.acpHash) {
|
|
3732
|
+
const acp2 = await acps.getACP(this.chainId, this.account, this.acpHash);
|
|
3733
|
+
if (!acp2) {
|
|
3426
3734
|
throw new CofheError({
|
|
3427
|
-
code: "
|
|
3428
|
-
message: `
|
|
3429
|
-
hint: "Ensure the
|
|
3735
|
+
code: "ACP_NOT_FOUND" /* ACPNotFound */,
|
|
3736
|
+
message: `ACP with hash <${this.acpHash}> not found for account <${this.account}> and chainId <${this.chainId}>`,
|
|
3737
|
+
hint: "Ensure the acp exists and is valid.",
|
|
3430
3738
|
context: {
|
|
3431
3739
|
chainId: this.chainId,
|
|
3432
3740
|
account: this.account,
|
|
3433
|
-
|
|
3741
|
+
acpHash: this.acpHash
|
|
3434
3742
|
}
|
|
3435
3743
|
});
|
|
3436
3744
|
}
|
|
3437
|
-
return
|
|
3745
|
+
return acp2;
|
|
3438
3746
|
}
|
|
3439
|
-
const
|
|
3440
|
-
if (!
|
|
3747
|
+
const acp = await acps.getActiveACP(this.chainId, this.account);
|
|
3748
|
+
if (!acp) {
|
|
3441
3749
|
throw new CofheError({
|
|
3442
|
-
code: "
|
|
3443
|
-
message: `Active
|
|
3444
|
-
hint: "Ensure
|
|
3750
|
+
code: "ACP_NOT_FOUND" /* ACPNotFound */,
|
|
3751
|
+
message: `Active acp not found for chainId <${this.chainId}> and account <${this.account}>`,
|
|
3752
|
+
hint: "Ensure an ACP exists for this account on this chain.",
|
|
3445
3753
|
context: {
|
|
3446
3754
|
chainId: this.chainId,
|
|
3447
3755
|
account: this.account
|
|
3448
3756
|
}
|
|
3449
3757
|
});
|
|
3450
3758
|
}
|
|
3451
|
-
return
|
|
3759
|
+
return acp;
|
|
3452
3760
|
}
|
|
3453
3761
|
/**
|
|
3454
3762
|
* On hardhat, interact with MockZkVerifier contract instead of CoFHE
|
|
3455
3763
|
*/
|
|
3456
|
-
async mocksSealOutput(
|
|
3764
|
+
async mocksSealOutput(acp) {
|
|
3457
3765
|
this.assertPublicClient();
|
|
3458
3766
|
const mocksDecryptDelay = this.config.mocks.decryptDelay;
|
|
3459
3767
|
if (mocksDecryptDelay > 0)
|
|
3460
3768
|
await sleep(mocksDecryptDelay);
|
|
3461
|
-
return cofheMocksDecryptForView(this.ctHash, this.utype,
|
|
3769
|
+
return cofheMocksDecryptForView(this.ctHash, this.utype, acp, this.publicClient);
|
|
3462
3770
|
}
|
|
3463
3771
|
/**
|
|
3464
3772
|
* In the production context, perform a true decryption with the CoFHE coprocessor.
|
|
3465
3773
|
*/
|
|
3466
|
-
async productionSealOutput(
|
|
3774
|
+
async productionSealOutput(acp) {
|
|
3467
3775
|
this.assertChainId();
|
|
3468
3776
|
this.assertPublicClient();
|
|
3469
3777
|
const thresholdNetworkUrl = await this.getThresholdNetworkUrl();
|
|
3470
|
-
const
|
|
3778
|
+
const wireAcp = ACPUtils.getPublic(acp, true);
|
|
3471
3779
|
const sealed = await tnSealOutputV2({
|
|
3472
3780
|
ctHash: this.ctHash,
|
|
3473
3781
|
chainId: this.chainId,
|
|
3474
|
-
|
|
3782
|
+
acp: wireAcp,
|
|
3475
3783
|
thresholdNetworkUrl,
|
|
3476
3784
|
retry404TimeoutMs: this.retry404TimeoutMs,
|
|
3477
3785
|
onPoll: this.pollCallback
|
|
3478
3786
|
});
|
|
3479
|
-
return
|
|
3787
|
+
return ACPUtils.unseal(acp, sealed);
|
|
3480
3788
|
}
|
|
3481
3789
|
/**
|
|
3482
3790
|
* Final step of the decryption process. MUST BE CALLED LAST IN THE CHAIN.
|
|
3483
3791
|
*
|
|
3484
3792
|
* This will:
|
|
3485
|
-
* - Use
|
|
3486
|
-
* - Check
|
|
3487
|
-
* - Call CoFHE `/sealoutput` with the
|
|
3488
|
-
* - Unseal the sealed item with the
|
|
3793
|
+
* - Use an ACP based on provided acp OR chainId + account + acpHash
|
|
3794
|
+
* - Check acp validity
|
|
3795
|
+
* - Call CoFHE `/sealoutput` with the acp, which returns a sealed (encrypted) item
|
|
3796
|
+
* - Unseal the sealed item with the acp
|
|
3489
3797
|
* - Return the unsealed item
|
|
3490
3798
|
*
|
|
3491
3799
|
* Example:
|
|
@@ -3493,7 +3801,7 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3493
3801
|
* const unsealed = await client.decryptForView(ctHash, utype)
|
|
3494
3802
|
* .setChainId(11155111) // optional
|
|
3495
3803
|
* .setAccount('0x123...890') // optional
|
|
3496
|
-
* .
|
|
3804
|
+
* .withACP() // optional
|
|
3497
3805
|
* .execute(); // execute
|
|
3498
3806
|
* ```
|
|
3499
3807
|
*
|
|
@@ -3501,14 +3809,14 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3501
3809
|
*/
|
|
3502
3810
|
async execute() {
|
|
3503
3811
|
this.validateUtypeOrThrow();
|
|
3504
|
-
const
|
|
3505
|
-
|
|
3506
|
-
const chainId =
|
|
3812
|
+
const acp = await this.getResolvedACP();
|
|
3813
|
+
ACPUtils.validate(acp);
|
|
3814
|
+
const chainId = acp._signedDomain.chainId;
|
|
3507
3815
|
let unsealed;
|
|
3508
3816
|
if (chainId === hardhat2.id) {
|
|
3509
|
-
unsealed = await this.mocksSealOutput(
|
|
3817
|
+
unsealed = await this.mocksSealOutput(acp);
|
|
3510
3818
|
} else {
|
|
3511
|
-
unsealed = await this.productionSealOutput(
|
|
3819
|
+
unsealed = await this.productionSealOutput(acp);
|
|
3512
3820
|
}
|
|
3513
3821
|
return convertViaUtype(this.utype, unsealed);
|
|
3514
3822
|
}
|
|
@@ -3516,28 +3824,28 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3516
3824
|
var UINT_TYPE_MASK = 0x7fn;
|
|
3517
3825
|
var TYPE_BYTE_OFFSET = 8n;
|
|
3518
3826
|
var getEncryptionTypeFromCtHash = (ctHash) => Number(ctHash >> TYPE_BYTE_OFFSET & UINT_TYPE_MASK);
|
|
3519
|
-
async function cofheMocksDecryptForTx(ctHash, utype,
|
|
3827
|
+
async function cofheMocksDecryptForTx(ctHash, utype, acp, publicClient) {
|
|
3520
3828
|
let allowed;
|
|
3521
3829
|
let error;
|
|
3522
3830
|
let decryptedValue;
|
|
3523
|
-
if (
|
|
3524
|
-
|
|
3831
|
+
if (acp !== null) {
|
|
3832
|
+
const wireAcp = ACPUtils.getPublic(acp, true);
|
|
3525
3833
|
const permissionWithBigInts = {
|
|
3526
|
-
...
|
|
3527
|
-
expiration: BigInt(
|
|
3528
|
-
|
|
3834
|
+
...wireAcp,
|
|
3835
|
+
expiration: BigInt(wireAcp.expiration),
|
|
3836
|
+
revokerData: BigInt(wireAcp.revokerData)
|
|
3529
3837
|
};
|
|
3530
3838
|
[allowed, error, decryptedValue] = await publicClient.readContract({
|
|
3531
3839
|
address: MOCKS_THRESHOLD_NETWORK_ADDRESS,
|
|
3532
3840
|
abi: MockThresholdNetworkAbi,
|
|
3533
|
-
functionName: "
|
|
3841
|
+
functionName: "decryptForTxWithACP",
|
|
3534
3842
|
args: [BigInt(ctHash), permissionWithBigInts]
|
|
3535
3843
|
});
|
|
3536
3844
|
} else {
|
|
3537
3845
|
[allowed, error, decryptedValue] = await publicClient.readContract({
|
|
3538
3846
|
address: MOCKS_THRESHOLD_NETWORK_ADDRESS,
|
|
3539
3847
|
abi: MockThresholdNetworkAbi,
|
|
3540
|
-
functionName: "
|
|
3848
|
+
functionName: "decryptForTxWithoutACP",
|
|
3541
3849
|
args: [BigInt(ctHash)]
|
|
3542
3850
|
});
|
|
3543
3851
|
}
|
|
@@ -3572,62 +3880,6 @@ async function cofheMocksDecryptForTx(ctHash, utype, permit, publicClient) {
|
|
|
3572
3880
|
signature
|
|
3573
3881
|
};
|
|
3574
3882
|
}
|
|
3575
|
-
function normalizeTnSignature(signature) {
|
|
3576
|
-
if (typeof signature !== "string") {
|
|
3577
|
-
throw new CofheError({
|
|
3578
|
-
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3579
|
-
message: "decrypt response missing signature",
|
|
3580
|
-
context: {
|
|
3581
|
-
signature
|
|
3582
|
-
}
|
|
3583
|
-
});
|
|
3584
|
-
}
|
|
3585
|
-
const trimmed = signature.trim();
|
|
3586
|
-
if (trimmed.length === 0) {
|
|
3587
|
-
throw new CofheError({
|
|
3588
|
-
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3589
|
-
message: "decrypt response returned empty signature"
|
|
3590
|
-
});
|
|
3591
|
-
}
|
|
3592
|
-
const prefixed = trimmed.startsWith("0x") ? trimmed : `0x${trimmed}`;
|
|
3593
|
-
const parsed = viem.parseSignature(prefixed);
|
|
3594
|
-
return viem.serializeSignature(parsed);
|
|
3595
|
-
}
|
|
3596
|
-
function parseDecryptedBytesToBigInt(decrypted) {
|
|
3597
|
-
if (!Array.isArray(decrypted)) {
|
|
3598
|
-
throw new CofheError({
|
|
3599
|
-
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3600
|
-
message: "decrypt response field <decrypted> must be a byte array",
|
|
3601
|
-
context: {
|
|
3602
|
-
decrypted
|
|
3603
|
-
}
|
|
3604
|
-
});
|
|
3605
|
-
}
|
|
3606
|
-
if (decrypted.length === 0) {
|
|
3607
|
-
throw new CofheError({
|
|
3608
|
-
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3609
|
-
message: "decrypt response field <decrypted> was an empty byte array",
|
|
3610
|
-
context: {
|
|
3611
|
-
decrypted
|
|
3612
|
-
}
|
|
3613
|
-
});
|
|
3614
|
-
}
|
|
3615
|
-
let hex = "";
|
|
3616
|
-
for (const b of decrypted) {
|
|
3617
|
-
if (typeof b !== "number" || !Number.isInteger(b) || b < 0 || b > 255) {
|
|
3618
|
-
throw new CofheError({
|
|
3619
|
-
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3620
|
-
message: "decrypt response field <decrypted> contained a non-byte value",
|
|
3621
|
-
context: {
|
|
3622
|
-
badElement: b,
|
|
3623
|
-
decrypted
|
|
3624
|
-
}
|
|
3625
|
-
});
|
|
3626
|
-
}
|
|
3627
|
-
hex += b.toString(16).padStart(2, "0");
|
|
3628
|
-
}
|
|
3629
|
-
return BigInt(`0x${hex}`);
|
|
3630
|
-
}
|
|
3631
3883
|
|
|
3632
3884
|
// core/decrypt/tnDecryptV2.ts
|
|
3633
3885
|
var POLL_INTERVAL_MS2 = 1e3;
|
|
@@ -3749,15 +4001,16 @@ function assertDecryptStatusResponseV2(value) {
|
|
|
3749
4001
|
}
|
|
3750
4002
|
return value;
|
|
3751
4003
|
}
|
|
3752
|
-
async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId,
|
|
4004
|
+
async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, acp, overallStartTime, retry404TimeoutMs, onPoll) {
|
|
3753
4005
|
const body = {
|
|
3754
4006
|
ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
|
|
3755
4007
|
host_chain_id: chainId
|
|
3756
4008
|
};
|
|
3757
|
-
if (
|
|
3758
|
-
body.
|
|
4009
|
+
if (acp) {
|
|
4010
|
+
body.acp = acp;
|
|
3759
4011
|
}
|
|
3760
4012
|
let attemptIndex = 0;
|
|
4013
|
+
let last404ApiErrorMessage;
|
|
3761
4014
|
for (; ; ) {
|
|
3762
4015
|
let response;
|
|
3763
4016
|
try {
|
|
@@ -3785,16 +4038,19 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, perm
|
|
|
3785
4038
|
}
|
|
3786
4039
|
});
|
|
3787
4040
|
}
|
|
3788
|
-
const responseClassification = await classifySubmitResponse({
|
|
4041
|
+
const responseClassification = await classifySubmitResponse({
|
|
4042
|
+
response,
|
|
4043
|
+
fallbackErrorCode: "DECRYPT_FAILED" /* DecryptFailed */
|
|
4044
|
+
});
|
|
3789
4045
|
if (responseClassification.kind === "fatal-http") {
|
|
3790
4046
|
throw new CofheError({
|
|
3791
|
-
code:
|
|
4047
|
+
code: responseClassification.cofheErrorCode,
|
|
4048
|
+
apiErrorCode: responseClassification.apiErrorCode,
|
|
3792
4049
|
message: `decrypt request failed: ${responseClassification.errorMessage}`,
|
|
3793
4050
|
hint: "Check the threshold network URL and request parameters.",
|
|
3794
4051
|
context: {
|
|
3795
4052
|
thresholdNetworkUrl,
|
|
3796
|
-
status:
|
|
3797
|
-
statusText: response.statusText,
|
|
4053
|
+
status: responseClassification.status,
|
|
3798
4054
|
body,
|
|
3799
4055
|
attemptIndex
|
|
3800
4056
|
}
|
|
@@ -3842,6 +4098,9 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, perm
|
|
|
3842
4098
|
}
|
|
3843
4099
|
});
|
|
3844
4100
|
}
|
|
4101
|
+
if (responseClassification.status === 404) {
|
|
4102
|
+
last404ApiErrorMessage = responseClassification.apiErrorMessage;
|
|
4103
|
+
}
|
|
3845
4104
|
const elapsedMs = Date.now() - overallStartTime;
|
|
3846
4105
|
throwIfSubmitRetryTimedOut({
|
|
3847
4106
|
operationLabel: "decrypt",
|
|
@@ -3852,7 +4111,8 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, perm
|
|
|
3852
4111
|
overallTimeoutMs: DECRYPT_TIMEOUT_MS,
|
|
3853
4112
|
thresholdNetworkUrl,
|
|
3854
4113
|
body,
|
|
3855
|
-
attemptIndex
|
|
4114
|
+
attemptIndex,
|
|
4115
|
+
lastKnownErrorMessage: last404ApiErrorMessage
|
|
3856
4116
|
});
|
|
3857
4117
|
onPoll?.({
|
|
3858
4118
|
operation: "decrypt",
|
|
@@ -3930,17 +4190,10 @@ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartT
|
|
|
3930
4190
|
});
|
|
3931
4191
|
}
|
|
3932
4192
|
if (!response.ok) {
|
|
3933
|
-
|
|
3934
|
-
try {
|
|
3935
|
-
const errorBody = await response.json();
|
|
3936
|
-
const maybeMessage = errorBody.error_message || errorBody.message;
|
|
3937
|
-
if (typeof maybeMessage === "string" && maybeMessage.length > 0)
|
|
3938
|
-
errorMessage = maybeMessage;
|
|
3939
|
-
} catch {
|
|
3940
|
-
errorMessage = response.statusText || errorMessage;
|
|
3941
|
-
}
|
|
4193
|
+
const { apiErrorCode, errorMessage } = await parseApiErrorResponseBody(response);
|
|
3942
4194
|
throw new CofheError({
|
|
3943
|
-
code: "DECRYPT_FAILED" /* DecryptFailed
|
|
4195
|
+
code: mapApiErrorCodeToCofheErrorCode(apiErrorCode, "DECRYPT_FAILED" /* DecryptFailed */),
|
|
4196
|
+
apiErrorCode,
|
|
3944
4197
|
message: `decrypt status poll failed: ${errorMessage}`,
|
|
3945
4198
|
context: {
|
|
3946
4199
|
thresholdNetworkUrl,
|
|
@@ -3985,7 +4238,7 @@ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartT
|
|
|
3985
4238
|
});
|
|
3986
4239
|
}
|
|
3987
4240
|
async function tnDecryptV2(params) {
|
|
3988
|
-
const { thresholdNetworkUrl, ctHash, chainId,
|
|
4241
|
+
const { thresholdNetworkUrl, ctHash, chainId, acp, retry404TimeoutMs, onPoll } = params;
|
|
3989
4242
|
const normalized404RetryTimeoutMs = normalize404RetryTimeoutMs({
|
|
3990
4243
|
timeoutMs: retry404TimeoutMs,
|
|
3991
4244
|
operationLabel: "decrypt",
|
|
@@ -3996,7 +4249,7 @@ async function tnDecryptV2(params) {
|
|
|
3996
4249
|
thresholdNetworkUrl,
|
|
3997
4250
|
ctHash,
|
|
3998
4251
|
chainId,
|
|
3999
|
-
|
|
4252
|
+
acp,
|
|
4000
4253
|
overallStartTime,
|
|
4001
4254
|
normalized404RetryTimeoutMs,
|
|
4002
4255
|
onPoll
|
|
@@ -4011,9 +4264,9 @@ async function tnDecryptV2(params) {
|
|
|
4011
4264
|
var DEFAULT_404_RETRY_TIMEOUT_MS3 = 1e4;
|
|
4012
4265
|
var DecryptForTxBuilder = class extends BaseBuilder {
|
|
4013
4266
|
ctHash;
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4267
|
+
acpHash;
|
|
4268
|
+
acp;
|
|
4269
|
+
acpSelection = "unset";
|
|
4017
4270
|
pollCallback;
|
|
4018
4271
|
retry404TimeoutMs = DEFAULT_404_RETRY_TIMEOUT_MS3;
|
|
4019
4272
|
constructor(params) {
|
|
@@ -4058,137 +4311,137 @@ var DecryptForTxBuilder = class extends BaseBuilder {
|
|
|
4058
4311
|
this.retry404TimeoutMs = timeoutMs;
|
|
4059
4312
|
return this;
|
|
4060
4313
|
}
|
|
4061
|
-
|
|
4062
|
-
if (this.
|
|
4314
|
+
withACP(acpOrACPHash) {
|
|
4315
|
+
if (this.acpSelection === "with-acp") {
|
|
4063
4316
|
throw new CofheError({
|
|
4064
4317
|
code: "INTERNAL_ERROR" /* InternalError */,
|
|
4065
|
-
message: "decryptForTx:
|
|
4066
|
-
hint: "Choose the
|
|
4318
|
+
message: "decryptForTx: withACP() can only be selected once.",
|
|
4319
|
+
hint: "Choose the acp mode once. If you need a different acp, start a new decryptForTx() builder chain."
|
|
4067
4320
|
});
|
|
4068
4321
|
}
|
|
4069
|
-
if (this.
|
|
4322
|
+
if (this.acpSelection === "without-acp") {
|
|
4070
4323
|
throw new CofheError({
|
|
4071
4324
|
code: "INTERNAL_ERROR" /* InternalError */,
|
|
4072
|
-
message: "decryptForTx: cannot call
|
|
4073
|
-
hint: "Choose exactly one
|
|
4325
|
+
message: "decryptForTx: cannot call withACP() after withoutACP() has been selected.",
|
|
4326
|
+
hint: "Choose exactly one acp mode: either call .withACP(...) or .withoutACP(), but not both."
|
|
4074
4327
|
});
|
|
4075
4328
|
}
|
|
4076
|
-
this.
|
|
4077
|
-
if (typeof
|
|
4078
|
-
this.
|
|
4079
|
-
this.
|
|
4080
|
-
} else if (
|
|
4081
|
-
this.
|
|
4082
|
-
this.
|
|
4329
|
+
this.acpSelection = "with-acp";
|
|
4330
|
+
if (typeof acpOrACPHash === "string") {
|
|
4331
|
+
this.acpHash = acpOrACPHash;
|
|
4332
|
+
this.acp = void 0;
|
|
4333
|
+
} else if (acpOrACPHash === void 0) {
|
|
4334
|
+
this.acpHash = void 0;
|
|
4335
|
+
this.acp = void 0;
|
|
4083
4336
|
} else {
|
|
4084
|
-
this.
|
|
4085
|
-
this.
|
|
4337
|
+
this.acp = acpOrACPHash;
|
|
4338
|
+
this.acpHash = void 0;
|
|
4086
4339
|
}
|
|
4087
4340
|
return this;
|
|
4088
4341
|
}
|
|
4089
4342
|
/**
|
|
4090
|
-
* Select "no
|
|
4343
|
+
* Select "no acp" mode.
|
|
4091
4344
|
*
|
|
4092
|
-
* This uses global allowance (no
|
|
4345
|
+
* This uses global allowance (no acp required) and sends an empty permission payload to `/decrypt`.
|
|
4093
4346
|
*/
|
|
4094
|
-
|
|
4095
|
-
if (this.
|
|
4347
|
+
withoutACP() {
|
|
4348
|
+
if (this.acpSelection === "without-acp") {
|
|
4096
4349
|
throw new CofheError({
|
|
4097
4350
|
code: "INTERNAL_ERROR" /* InternalError */,
|
|
4098
|
-
message: "decryptForTx:
|
|
4099
|
-
hint: "Choose the
|
|
4351
|
+
message: "decryptForTx: withoutACP() can only be selected once.",
|
|
4352
|
+
hint: "Choose the acp mode once. If you need a different mode, start a new decryptForTx() builder chain."
|
|
4100
4353
|
});
|
|
4101
4354
|
}
|
|
4102
|
-
if (this.
|
|
4355
|
+
if (this.acpSelection === "with-acp") {
|
|
4103
4356
|
throw new CofheError({
|
|
4104
4357
|
code: "INTERNAL_ERROR" /* InternalError */,
|
|
4105
|
-
message: "decryptForTx: cannot call
|
|
4106
|
-
hint: "Choose exactly one
|
|
4358
|
+
message: "decryptForTx: cannot call withoutACP() after withACP() has been selected.",
|
|
4359
|
+
hint: "Choose exactly one acp mode: either call .withACP(...) or .withoutACP(), but not both."
|
|
4107
4360
|
});
|
|
4108
4361
|
}
|
|
4109
|
-
this.
|
|
4110
|
-
this.
|
|
4111
|
-
this.
|
|
4362
|
+
this.acpSelection = "without-acp";
|
|
4363
|
+
this.acpHash = void 0;
|
|
4364
|
+
this.acp = void 0;
|
|
4112
4365
|
return this;
|
|
4113
4366
|
}
|
|
4114
|
-
|
|
4115
|
-
return this.
|
|
4367
|
+
getACP() {
|
|
4368
|
+
return this.acp;
|
|
4116
4369
|
}
|
|
4117
|
-
|
|
4118
|
-
return this.
|
|
4370
|
+
getACPHash() {
|
|
4371
|
+
return this.acpHash;
|
|
4119
4372
|
}
|
|
4120
4373
|
async getThresholdNetworkUrl() {
|
|
4121
4374
|
this.assertChainId();
|
|
4122
4375
|
return getThresholdNetworkUrlOrThrow(this.config, this.chainId);
|
|
4123
4376
|
}
|
|
4124
|
-
async
|
|
4125
|
-
if (this.
|
|
4377
|
+
async getResolvedACP() {
|
|
4378
|
+
if (this.acpSelection === "unset") {
|
|
4126
4379
|
throw new CofheError({
|
|
4127
4380
|
code: "INTERNAL_ERROR" /* InternalError */,
|
|
4128
|
-
message: "decryptForTx: missing
|
|
4129
|
-
hint: "Call .
|
|
4381
|
+
message: "decryptForTx: missing acp selection; call withACP(...) or withoutACP() before execute().",
|
|
4382
|
+
hint: "Call .withACP() to use the active acp, or .withoutACP() for global allowance."
|
|
4130
4383
|
});
|
|
4131
4384
|
}
|
|
4132
|
-
if (this.
|
|
4385
|
+
if (this.acpSelection === "without-acp") {
|
|
4133
4386
|
return null;
|
|
4134
4387
|
}
|
|
4135
|
-
if (this.
|
|
4136
|
-
return this.
|
|
4388
|
+
if (this.acp)
|
|
4389
|
+
return this.acp;
|
|
4137
4390
|
this.assertChainId();
|
|
4138
4391
|
this.assertAccount();
|
|
4139
|
-
if (this.
|
|
4140
|
-
const
|
|
4141
|
-
if (!
|
|
4392
|
+
if (this.acpHash) {
|
|
4393
|
+
const acp2 = await acps.getACP(this.chainId, this.account, this.acpHash);
|
|
4394
|
+
if (!acp2) {
|
|
4142
4395
|
throw new CofheError({
|
|
4143
|
-
code: "
|
|
4144
|
-
message: `
|
|
4145
|
-
hint: "Ensure the
|
|
4396
|
+
code: "ACP_NOT_FOUND" /* ACPNotFound */,
|
|
4397
|
+
message: `ACP with hash <${this.acpHash}> not found for account <${this.account}> and chainId <${this.chainId}>`,
|
|
4398
|
+
hint: "Ensure the acp exists and is valid.",
|
|
4146
4399
|
context: {
|
|
4147
4400
|
chainId: this.chainId,
|
|
4148
4401
|
account: this.account,
|
|
4149
|
-
|
|
4402
|
+
acpHash: this.acpHash
|
|
4150
4403
|
}
|
|
4151
4404
|
});
|
|
4152
4405
|
}
|
|
4153
|
-
return
|
|
4406
|
+
return acp2;
|
|
4154
4407
|
}
|
|
4155
|
-
const
|
|
4156
|
-
if (!
|
|
4408
|
+
const acp = await acps.getActiveACP(this.chainId, this.account);
|
|
4409
|
+
if (!acp) {
|
|
4157
4410
|
throw new CofheError({
|
|
4158
|
-
code: "
|
|
4159
|
-
message: `Active
|
|
4160
|
-
hint: "Create
|
|
4411
|
+
code: "ACP_NOT_FOUND" /* ACPNotFound */,
|
|
4412
|
+
message: `Active acp not found for chainId <${this.chainId}> and account <${this.account}>`,
|
|
4413
|
+
hint: "Create an ACP (e.g. client.acp.createSelf(...)) and/or set it active (client.acp.selectActiveACP(hash)).",
|
|
4161
4414
|
context: {
|
|
4162
4415
|
chainId: this.chainId,
|
|
4163
4416
|
account: this.account
|
|
4164
4417
|
}
|
|
4165
4418
|
});
|
|
4166
4419
|
}
|
|
4167
|
-
return
|
|
4420
|
+
return acp;
|
|
4168
4421
|
}
|
|
4169
4422
|
/**
|
|
4170
4423
|
* On hardhat, interact with MockThresholdNetwork contract
|
|
4171
4424
|
*/
|
|
4172
|
-
async mocksDecryptForTx(
|
|
4425
|
+
async mocksDecryptForTx(acp) {
|
|
4173
4426
|
this.assertPublicClient();
|
|
4174
4427
|
const delay = this.config.mocks.decryptDelay;
|
|
4175
4428
|
if (delay > 0)
|
|
4176
4429
|
await sleep(delay);
|
|
4177
|
-
const result = await cofheMocksDecryptForTx(this.ctHash, 0,
|
|
4430
|
+
const result = await cofheMocksDecryptForTx(this.ctHash, 0, acp, this.publicClient);
|
|
4178
4431
|
return result;
|
|
4179
4432
|
}
|
|
4180
4433
|
/**
|
|
4181
4434
|
* In the production context, perform a true decryption with the CoFHE coprocessor.
|
|
4182
4435
|
*/
|
|
4183
|
-
async productionDecryptForTx(
|
|
4436
|
+
async productionDecryptForTx(acp) {
|
|
4184
4437
|
this.assertChainId();
|
|
4185
4438
|
this.assertPublicClient();
|
|
4186
4439
|
const thresholdNetworkUrl = await this.getThresholdNetworkUrl();
|
|
4187
|
-
const
|
|
4440
|
+
const wireAcp = acp ? ACPUtils.getPublic(acp, true) : null;
|
|
4188
4441
|
const { decryptedValue, signature } = await tnDecryptV2({
|
|
4189
4442
|
ctHash: this.ctHash,
|
|
4190
4443
|
chainId: this.chainId,
|
|
4191
|
-
|
|
4444
|
+
acp: wireAcp,
|
|
4192
4445
|
thresholdNetworkUrl,
|
|
4193
4446
|
retry404TimeoutMs: this.retry404TimeoutMs,
|
|
4194
4447
|
onPoll: this.pollCallback
|
|
@@ -4202,19 +4455,19 @@ var DecryptForTxBuilder = class extends BaseBuilder {
|
|
|
4202
4455
|
/**
|
|
4203
4456
|
* Final step of the decryptForTx process. MUST BE CALLED LAST IN THE CHAIN.
|
|
4204
4457
|
*
|
|
4205
|
-
* You must explicitly choose one
|
|
4206
|
-
* - `
|
|
4207
|
-
* - `
|
|
4458
|
+
* You must explicitly choose one acp mode before calling `execute()`:
|
|
4459
|
+
* - `withACP(acp)` / `withACP(acpHash)` / `withACP()` (active acp)
|
|
4460
|
+
* - `withoutACP()` (global allowance)
|
|
4208
4461
|
*/
|
|
4209
4462
|
async execute() {
|
|
4210
|
-
const
|
|
4211
|
-
if (
|
|
4212
|
-
|
|
4213
|
-
const chainId =
|
|
4463
|
+
const acp = await this.getResolvedACP();
|
|
4464
|
+
if (acp !== null) {
|
|
4465
|
+
ACPUtils.validate(acp);
|
|
4466
|
+
const chainId = acp._signedDomain.chainId;
|
|
4214
4467
|
if (chainId === hardhat2.id) {
|
|
4215
|
-
return await this.mocksDecryptForTx(
|
|
4468
|
+
return await this.mocksDecryptForTx(acp);
|
|
4216
4469
|
} else {
|
|
4217
|
-
return await this.productionDecryptForTx(
|
|
4470
|
+
return await this.productionDecryptForTx(acp);
|
|
4218
4471
|
}
|
|
4219
4472
|
} else {
|
|
4220
4473
|
if (!this.chainId) {
|
|
@@ -4277,6 +4530,21 @@ function createCofheClientBase(opts) {
|
|
|
4277
4530
|
const updateConnectState = (partial) => {
|
|
4278
4531
|
connectStore.setState((state) => ({ ...state, ...partial }));
|
|
4279
4532
|
};
|
|
4533
|
+
const _resolveSharingRegistry = async (publicClient, chainId) => {
|
|
4534
|
+
const configured = opts.config.acp?.sharingRegistry?.[chainId];
|
|
4535
|
+
if (configured != null)
|
|
4536
|
+
return configured;
|
|
4537
|
+
const registry = (await acps.getAclServedAddresses(publicClient, chainId)).shareRegistry;
|
|
4538
|
+
if (registry == null) {
|
|
4539
|
+
throw new CofheError({
|
|
4540
|
+
code: "MISSING_CONFIG" /* MissingConfig */,
|
|
4541
|
+
message: `No ACP share registry available for chainId <${chainId}>`,
|
|
4542
|
+
hint: "The ACL on this chain does not serve a share registry address. Set `acp.sharingRegistry` in the cofhe config to use on-chain sharing.",
|
|
4543
|
+
context: { chainId }
|
|
4544
|
+
});
|
|
4545
|
+
}
|
|
4546
|
+
return registry;
|
|
4547
|
+
};
|
|
4280
4548
|
const _requireConnected = () => {
|
|
4281
4549
|
const state = connectStore.getState();
|
|
4282
4550
|
const notConnected = !state.connected || !state.account || !state.chainId || !state.publicClient || !state.walletClient;
|
|
@@ -4399,74 +4667,147 @@ function createCofheClientBase(opts) {
|
|
|
4399
4667
|
}
|
|
4400
4668
|
return { chainId: _chainId, account: _account };
|
|
4401
4669
|
};
|
|
4402
|
-
const
|
|
4670
|
+
const clientACPs = {
|
|
4403
4671
|
// Pass through store access
|
|
4404
|
-
getSnapshot:
|
|
4405
|
-
subscribe:
|
|
4672
|
+
getSnapshot: acps.getSnapshot,
|
|
4673
|
+
subscribe: acps.subscribe,
|
|
4406
4674
|
// Creation methods (require connection)
|
|
4407
4675
|
createSelf: async (options, clients) => {
|
|
4408
4676
|
_requireConnected();
|
|
4409
4677
|
const { publicClient, walletClient } = clients ?? connectStore.getState();
|
|
4410
|
-
|
|
4678
|
+
const chainId = await publicClient.getChainId();
|
|
4679
|
+
return acps.createSelf(
|
|
4680
|
+
await acps.applyACPDefaultsFromChain(options, opts.config.acp, publicClient, chainId),
|
|
4681
|
+
publicClient,
|
|
4682
|
+
walletClient
|
|
4683
|
+
);
|
|
4411
4684
|
},
|
|
4412
4685
|
createSharing: async (options, clients) => {
|
|
4413
4686
|
_requireConnected();
|
|
4414
4687
|
const { publicClient, walletClient } = clients ?? connectStore.getState();
|
|
4415
|
-
|
|
4688
|
+
const chainId = await publicClient.getChainId();
|
|
4689
|
+
return acps.createSharing(
|
|
4690
|
+
await acps.applyACPDefaultsFromChain(options, opts.config.acp, publicClient, chainId),
|
|
4691
|
+
publicClient,
|
|
4692
|
+
walletClient
|
|
4693
|
+
);
|
|
4416
4694
|
},
|
|
4417
4695
|
importShared: async (options, clients) => {
|
|
4418
4696
|
_requireConnected();
|
|
4419
4697
|
const { publicClient, walletClient } = clients ?? connectStore.getState();
|
|
4420
|
-
return
|
|
4698
|
+
return acps.importShared(options, publicClient, walletClient);
|
|
4421
4699
|
},
|
|
4422
4700
|
// Get or create methods (require connection)
|
|
4423
|
-
|
|
4701
|
+
getOrCreateSelfACP: async (chainId, account, options) => {
|
|
4424
4702
|
_requireConnected();
|
|
4425
4703
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
4426
4704
|
const { publicClient, walletClient } = connectStore.getState();
|
|
4427
|
-
|
|
4705
|
+
const optionsWithDefaults = await acps.applyACPDefaultsFromChain(
|
|
4706
|
+
options ?? { issuer: _account, name: "Autogenerated Self ACP" },
|
|
4707
|
+
opts.config.acp,
|
|
4708
|
+
publicClient,
|
|
4709
|
+
_chainId
|
|
4710
|
+
);
|
|
4711
|
+
return acps.getOrCreateSelfACP(publicClient, walletClient, _chainId, _account, optionsWithDefaults);
|
|
4428
4712
|
},
|
|
4429
|
-
|
|
4713
|
+
getOrCreateSharingACP: async (options, chainId, account) => {
|
|
4430
4714
|
_requireConnected();
|
|
4431
4715
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
4432
4716
|
const { publicClient, walletClient } = connectStore.getState();
|
|
4433
|
-
return
|
|
4717
|
+
return acps.getOrCreateSharingACP(
|
|
4718
|
+
publicClient,
|
|
4719
|
+
walletClient,
|
|
4720
|
+
await acps.applyACPDefaultsFromChain(options, opts.config.acp, publicClient, _chainId),
|
|
4721
|
+
_chainId,
|
|
4722
|
+
_account
|
|
4723
|
+
);
|
|
4724
|
+
},
|
|
4725
|
+
// Revocation (require connection)
|
|
4726
|
+
revokeACP: async (acp) => {
|
|
4727
|
+
_requireConnected();
|
|
4728
|
+
const { walletClient } = connectStore.getState();
|
|
4729
|
+
return acps.revokeACP(acp, walletClient);
|
|
4730
|
+
},
|
|
4731
|
+
revokeAllACPs: async (revokerContract) => {
|
|
4732
|
+
_requireConnected();
|
|
4733
|
+
const { publicClient, walletClient } = connectStore.getState();
|
|
4734
|
+
return acps.revokeAllACPs(walletClient, publicClient, revokerContract);
|
|
4735
|
+
},
|
|
4736
|
+
isACPRevoked: async (acp) => {
|
|
4737
|
+
_requireConnected();
|
|
4738
|
+
const { publicClient } = connectStore.getState();
|
|
4739
|
+
return acps.isACPRevoked(acp, publicClient);
|
|
4740
|
+
},
|
|
4741
|
+
// On-chain sharing (require connection + config.acp.sharingRegistry)
|
|
4742
|
+
shareOnChain: async (acp) => {
|
|
4743
|
+
_requireConnected();
|
|
4744
|
+
const { publicClient, walletClient } = connectStore.getState();
|
|
4745
|
+
const chainId = await publicClient.getChainId();
|
|
4746
|
+
const sharingRegistry = await _resolveSharingRegistry(publicClient, chainId);
|
|
4747
|
+
return acps.shareOnChain(acp, walletClient, sharingRegistry);
|
|
4748
|
+
},
|
|
4749
|
+
getIncomingShares: async () => {
|
|
4750
|
+
_requireConnected();
|
|
4751
|
+
const { publicClient, walletClient } = connectStore.getState();
|
|
4752
|
+
const chainId = await publicClient.getChainId();
|
|
4753
|
+
const account = walletClient.account.address;
|
|
4754
|
+
const sharingRegistry = await _resolveSharingRegistry(publicClient, chainId);
|
|
4755
|
+
return acps.getIncomingShares(publicClient, sharingRegistry, account);
|
|
4756
|
+
},
|
|
4757
|
+
importFromChain: async (share) => {
|
|
4758
|
+
_requireConnected();
|
|
4759
|
+
const { publicClient, walletClient } = connectStore.getState();
|
|
4760
|
+
return acps.importFromChain(share, publicClient, walletClient);
|
|
4761
|
+
},
|
|
4762
|
+
dismissShare: async (shareId) => {
|
|
4763
|
+
_requireConnected();
|
|
4764
|
+
const { publicClient, walletClient } = connectStore.getState();
|
|
4765
|
+
const chainId = await publicClient.getChainId();
|
|
4766
|
+
const sharingRegistry = await _resolveSharingRegistry(publicClient, chainId);
|
|
4767
|
+
return acps.removeShareOnChain(shareId, walletClient, sharingRegistry);
|
|
4768
|
+
},
|
|
4769
|
+
cancelShare: async (shareId) => {
|
|
4770
|
+
_requireConnected();
|
|
4771
|
+
const { publicClient, walletClient } = connectStore.getState();
|
|
4772
|
+
const chainId = await publicClient.getChainId();
|
|
4773
|
+
const sharingRegistry = await _resolveSharingRegistry(publicClient, chainId);
|
|
4774
|
+
return acps.removeShareOnChain(shareId, walletClient, sharingRegistry);
|
|
4434
4775
|
},
|
|
4435
4776
|
// Retrieval methods (auto-fill chainId/account)
|
|
4436
|
-
|
|
4777
|
+
getACP: (hash, chainId, account) => {
|
|
4437
4778
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
4438
|
-
return
|
|
4779
|
+
return acps.getACP(_chainId, _account, hash);
|
|
4439
4780
|
},
|
|
4440
|
-
|
|
4781
|
+
getACPs: (chainId, account) => {
|
|
4441
4782
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
4442
|
-
return
|
|
4783
|
+
return acps.getACPs(_chainId, _account);
|
|
4443
4784
|
},
|
|
4444
|
-
|
|
4785
|
+
getActiveACP: (chainId, account) => {
|
|
4445
4786
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
4446
|
-
return
|
|
4787
|
+
return acps.getActiveACP(_chainId, _account);
|
|
4447
4788
|
},
|
|
4448
|
-
|
|
4789
|
+
getActiveACPHash: (chainId, account) => {
|
|
4449
4790
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
4450
|
-
return
|
|
4791
|
+
return acps.getActiveACPHash(_chainId, _account);
|
|
4451
4792
|
},
|
|
4452
4793
|
// Mutation methods (auto-fill chainId/account)
|
|
4453
|
-
|
|
4794
|
+
selectActiveACP: (hash, chainId, account) => {
|
|
4454
4795
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
4455
|
-
return
|
|
4796
|
+
return acps.selectActiveACP(_chainId, _account, hash);
|
|
4456
4797
|
},
|
|
4457
|
-
|
|
4798
|
+
removeACP: async (hash, chainId, account) => {
|
|
4458
4799
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
4459
|
-
return
|
|
4800
|
+
return acps.removeACP(_chainId, _account, hash);
|
|
4460
4801
|
},
|
|
4461
|
-
|
|
4802
|
+
removeActiveACP: async (chainId, account) => {
|
|
4462
4803
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
4463
|
-
return
|
|
4804
|
+
return acps.removeActiveACP(_chainId, _account);
|
|
4464
4805
|
},
|
|
4465
4806
|
// Utils (no context needed)
|
|
4466
|
-
getHash:
|
|
4467
|
-
export:
|
|
4468
|
-
serialize:
|
|
4469
|
-
deserialize:
|
|
4807
|
+
getHash: acps.getHash,
|
|
4808
|
+
export: acps.export,
|
|
4809
|
+
serialize: acps.serialize,
|
|
4810
|
+
deserialize: acps.deserialize
|
|
4470
4811
|
};
|
|
4471
4812
|
return {
|
|
4472
4813
|
// Zustand reactive accessors (don't export store directly to prevent mutation)
|
|
@@ -4494,7 +4835,7 @@ function createCofheClientBase(opts) {
|
|
|
4494
4835
|
decryptHandle: decryptForView,
|
|
4495
4836
|
decryptForTx,
|
|
4496
4837
|
verifyDecryptResult: verifyDecryptResult2,
|
|
4497
|
-
|
|
4838
|
+
acp: clientACPs
|
|
4498
4839
|
// Add SDK-specific methods below that require connection
|
|
4499
4840
|
// Example:
|
|
4500
4841
|
// async encryptData(data: unknown) {
|