@cofhe/sdk 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +43 -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
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { hardhat as hardhat$1 } from './chunk-
|
|
2
|
-
import {
|
|
1
|
+
import { hardhat as hardhat$1 } from './chunk-N6IDQRRU.js';
|
|
2
|
+
import { acpStore, ACPUtils } from './chunk-Q7CBWGQX.js';
|
|
3
3
|
import { TFHE_RS_KEY_VERSION, TASK_MANAGER_ADDRESS, TFHE_RS_ZK_MAX_BITS, TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT, MOCKS_THRESHOLD_NETWORK_ADDRESS, MOCKS_DECRYPT_RESULT_SIGNER_PRIVATE_KEY, MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY, MOCKS_ZK_VERIFIER_ADDRESS } from './chunk-ESMZCFJY.js';
|
|
4
4
|
import { createStore } from 'zustand/vanilla';
|
|
5
|
-
import { parseAbi, isAddressEqual, zeroAddress, recoverAddress,
|
|
5
|
+
import { parseAbi, isAddressEqual, zeroAddress, recoverAddress, keccak256, encodeAbiParameters, encodePacked, createWalletClient, http, getAddress, parseSignature, serializeSignature } from 'viem';
|
|
6
6
|
import { hardhat } from 'viem/chains';
|
|
7
7
|
import { sign, privateKeyToAccount } from 'viem/accounts';
|
|
8
8
|
import { z } from 'zod';
|
|
@@ -10,58 +10,78 @@ import { persist, createJSONStorage } from 'zustand/middleware';
|
|
|
10
10
|
import { produce } from 'immer';
|
|
11
11
|
|
|
12
12
|
// core/error.ts
|
|
13
|
-
var CofheErrorCode = /* @__PURE__ */ ((
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
13
|
+
var CofheErrorCode = /* @__PURE__ */ ((CofheErrorCode2) => {
|
|
14
|
+
CofheErrorCode2["InternalError"] = "INTERNAL_ERROR";
|
|
15
|
+
CofheErrorCode2["UnknownEnvironment"] = "UNKNOWN_ENVIRONMENT";
|
|
16
|
+
CofheErrorCode2["InitTfheFailed"] = "INIT_TFHE_FAILED";
|
|
17
|
+
CofheErrorCode2["InitViemFailed"] = "INIT_VIEM_FAILED";
|
|
18
|
+
CofheErrorCode2["InitEthersFailed"] = "INIT_ETHERS_FAILED";
|
|
19
|
+
CofheErrorCode2["NotConnected"] = "NOT_CONNECTED";
|
|
20
|
+
CofheErrorCode2["MissingPublicClient"] = "MISSING_PUBLIC_CLIENT";
|
|
21
|
+
CofheErrorCode2["MissingWalletClient"] = "MISSING_WALLET_CLIENT";
|
|
22
|
+
CofheErrorCode2["MissingProviderParam"] = "MISSING_PROVIDER_PARAM";
|
|
23
|
+
CofheErrorCode2["EmptySecurityZonesParam"] = "EMPTY_SECURITY_ZONES_PARAM";
|
|
24
|
+
CofheErrorCode2["InvalidACPData"] = "INVALID_ACP_DATA";
|
|
25
|
+
CofheErrorCode2["InvalidACPDomain"] = "INVALID_ACP_DOMAIN";
|
|
26
|
+
CofheErrorCode2["ACPNotFound"] = "ACP_NOT_FOUND";
|
|
27
|
+
CofheErrorCode2["CannotRemoveLastACP"] = "CANNOT_REMOVE_LAST_ACP";
|
|
28
|
+
CofheErrorCode2["AccountUninitialized"] = "ACCOUNT_UNINITIALIZED";
|
|
29
|
+
CofheErrorCode2["ChainIdUninitialized"] = "CHAIN_ID_UNINITIALIZED";
|
|
30
|
+
CofheErrorCode2["ConsumingContractUninitialized"] = "CONSUMING_CONTRACT_UNINITIALIZED";
|
|
31
|
+
CofheErrorCode2["SealOutputFailed"] = "SEAL_OUTPUT_FAILED";
|
|
32
|
+
CofheErrorCode2["SealOutputReturnedNull"] = "SEAL_OUTPUT_RETURNED_NULL";
|
|
33
|
+
CofheErrorCode2["InvalidUtype"] = "INVALID_UTYPE";
|
|
34
|
+
CofheErrorCode2["DecryptFailed"] = "DECRYPT_FAILED";
|
|
35
|
+
CofheErrorCode2["DecryptReturnedNull"] = "DECRYPT_RETURNED_NULL";
|
|
36
|
+
CofheErrorCode2["ZkMocksInsertCtHashesFailed"] = "ZK_MOCKS_INSERT_CT_HASHES_FAILED";
|
|
37
|
+
CofheErrorCode2["ZkMocksCalcCtHashesFailed"] = "ZK_MOCKS_CALC_CT_HASHES_FAILED";
|
|
38
|
+
CofheErrorCode2["ZkMocksVerifySignFailed"] = "ZK_MOCKS_VERIFY_SIGN_FAILED";
|
|
39
|
+
CofheErrorCode2["ZkMocksCreateProofSignatureFailed"] = "ZK_MOCKS_CREATE_PROOF_SIGNATURE_FAILED";
|
|
40
|
+
CofheErrorCode2["ZkVerifyFailed"] = "ZK_VERIFY_FAILED";
|
|
41
|
+
CofheErrorCode2["ZkPackFailed"] = "ZK_PACK_FAILED";
|
|
42
|
+
CofheErrorCode2["ZkProveFailed"] = "ZK_PROVE_FAILED";
|
|
43
|
+
CofheErrorCode2["EncryptRemainingInItems"] = "ENCRYPT_REMAINING_IN_ITEMS";
|
|
44
|
+
CofheErrorCode2["ZkUninitialized"] = "ZK_UNINITIALIZED";
|
|
45
|
+
CofheErrorCode2["ZkVerifierUrlUninitialized"] = "ZK_VERIFIER_URL_UNINITIALIZED";
|
|
46
|
+
CofheErrorCode2["ThresholdNetworkUrlUninitialized"] = "THRESHOLD_NETWORK_URL_UNINITIALIZED";
|
|
47
|
+
CofheErrorCode2["MissingConfig"] = "MISSING_CONFIG";
|
|
48
|
+
CofheErrorCode2["UnsupportedChain"] = "UNSUPPORTED_CHAIN";
|
|
49
|
+
CofheErrorCode2["MissingZkBuilderAndCrsGenerator"] = "MISSING_ZK_BUILDER_AND_CRS_GENERATOR";
|
|
50
|
+
CofheErrorCode2["MissingTfhePublicKeyDeserializer"] = "MISSING_TFHE_PUBLIC_KEY_DESERIALIZER";
|
|
51
|
+
CofheErrorCode2["MissingCompactPkeCrsDeserializer"] = "MISSING_COMPACT_PKE_CRS_DESERIALIZER";
|
|
52
|
+
CofheErrorCode2["MissingFheKey"] = "MISSING_FHE_KEY";
|
|
53
|
+
CofheErrorCode2["MissingCrs"] = "MISSING_CRS";
|
|
54
|
+
CofheErrorCode2["FetchKeysFailed"] = "FETCH_KEYS_FAILED";
|
|
55
|
+
CofheErrorCode2["PublicWalletGetChainIdFailed"] = "PUBLIC_WALLET_GET_CHAIN_ID_FAILED";
|
|
56
|
+
CofheErrorCode2["PublicWalletGetAddressesFailed"] = "PUBLIC_WALLET_GET_ADDRESSES_FAILED";
|
|
57
|
+
CofheErrorCode2["RehydrateKeysStoreFailed"] = "REHYDRATE_KEYS_STORE_FAILED";
|
|
58
|
+
CofheErrorCode2["BadRequest"] = "BAD_REQUEST";
|
|
59
|
+
CofheErrorCode2["UnknownChain"] = "UNKNOWN_CHAIN";
|
|
60
|
+
CofheErrorCode2["ACPMalformed"] = "ACP_MALFORMED";
|
|
61
|
+
CofheErrorCode2["ACPDenied"] = "ACP_DENIED";
|
|
62
|
+
CofheErrorCode2["ACPExpired"] = "ACP_EXPIRED";
|
|
63
|
+
CofheErrorCode2["ACPInvalid"] = "ACP_INVALID";
|
|
64
|
+
CofheErrorCode2["ACPRevoked"] = "ACP_REVOKED";
|
|
65
|
+
CofheErrorCode2["NotPubliclyAllowed"] = "NOT_PUBLICLY_ALLOWED";
|
|
66
|
+
CofheErrorCode2["CtNotFound"] = "CT_NOT_FOUND";
|
|
67
|
+
CofheErrorCode2["UnsupportedSecurityZone"] = "UNSUPPORTED_SECURITY_ZONE";
|
|
68
|
+
CofheErrorCode2["UnsupportedType"] = "UNSUPPORTED_TYPE";
|
|
69
|
+
CofheErrorCode2["SigningFailed"] = "SIGNING_FAILED";
|
|
70
|
+
CofheErrorCode2["CtSourceError"] = "CT_SOURCE_ERROR";
|
|
71
|
+
CofheErrorCode2["ACPVerifierError"] = "ACP_VERIFIER_ERROR";
|
|
72
|
+
CofheErrorCode2["CtSourceTimeout"] = "CT_SOURCE_TIMEOUT";
|
|
73
|
+
CofheErrorCode2["ACPVerifierTimeout"] = "ACP_VERIFIER_TIMEOUT";
|
|
74
|
+
CofheErrorCode2["ACPRequired"] = "ACP_REQUIRED";
|
|
75
|
+
CofheErrorCode2["SealFailed"] = "SEAL_FAILED";
|
|
76
|
+
return CofheErrorCode2;
|
|
58
77
|
})(CofheErrorCode || {});
|
|
59
78
|
var CofheError = class _CofheError extends Error {
|
|
60
79
|
code;
|
|
61
80
|
cause;
|
|
62
81
|
hint;
|
|
63
82
|
context;
|
|
64
|
-
|
|
83
|
+
apiErrorCode;
|
|
84
|
+
constructor({ code, message, cause, hint, context, apiErrorCode }) {
|
|
65
85
|
const fullMessage = cause ? `${message} | Caused by: ${cause.message}` : message;
|
|
66
86
|
super(fullMessage);
|
|
67
87
|
this.name = "CofheError";
|
|
@@ -69,6 +89,7 @@ var CofheError = class _CofheError extends Error {
|
|
|
69
89
|
this.cause = cause;
|
|
70
90
|
this.hint = hint;
|
|
71
91
|
this.context = context;
|
|
92
|
+
this.apiErrorCode = apiErrorCode;
|
|
72
93
|
if (Error.captureStackTrace) {
|
|
73
94
|
Error.captureStackTrace(this, _CofheError);
|
|
74
95
|
}
|
|
@@ -87,6 +108,7 @@ var CofheError = class _CofheError extends Error {
|
|
|
87
108
|
message: wrapperError?.message ?? "An internal error occurred",
|
|
88
109
|
hint: wrapperError?.hint,
|
|
89
110
|
context: wrapperError?.context,
|
|
111
|
+
apiErrorCode: wrapperError?.apiErrorCode,
|
|
90
112
|
cause
|
|
91
113
|
});
|
|
92
114
|
}
|
|
@@ -100,6 +122,7 @@ var CofheError = class _CofheError extends Error {
|
|
|
100
122
|
message: this.message,
|
|
101
123
|
hint: this.hint,
|
|
102
124
|
context: this.context,
|
|
125
|
+
apiErrorCode: this.apiErrorCode,
|
|
103
126
|
cause: this.cause ? {
|
|
104
127
|
name: this.cause.name,
|
|
105
128
|
message: this.cause.message,
|
|
@@ -112,7 +135,8 @@ var CofheError = class _CofheError extends Error {
|
|
|
112
135
|
* Returns a human-readable string representation of the error
|
|
113
136
|
*/
|
|
114
137
|
toString() {
|
|
115
|
-
const
|
|
138
|
+
const codeSuffix = this.apiErrorCode ? ` (api: ${this.apiErrorCode})` : "";
|
|
139
|
+
const parts = [`${this.name} [${this.code}]${codeSuffix}: ${this.message}`];
|
|
116
140
|
if (this.hint) {
|
|
117
141
|
parts.push(`Hint: ${this.hint}`);
|
|
118
142
|
}
|
|
@@ -198,10 +222,6 @@ var FheAllUTypes = [
|
|
|
198
222
|
// FheTypes.Uint256,
|
|
199
223
|
7 /* Uint160 */
|
|
200
224
|
];
|
|
201
|
-
function assertCorrectEncryptedItemInput(input) {
|
|
202
|
-
if (!input.signature.startsWith("0x"))
|
|
203
|
-
throw new Error("Signature must be a hex string starting with 0x");
|
|
204
|
-
}
|
|
205
225
|
var EncryptableFactoriesImpl = {
|
|
206
226
|
bool: (data, securityZone = 0) => ({ data, securityZone, utype: 0 /* Bool */ }),
|
|
207
227
|
address: (data, securityZone = 0) => ({ data, securityZone, utype: 7 /* Uint160 */ }),
|
|
@@ -481,18 +501,19 @@ var constructZkPoKMetadata = (accountAddr, securityZone, chainId) => {
|
|
|
481
501
|
metadata.set(chainIdBytes, 1 + accountBytes.length);
|
|
482
502
|
return metadata;
|
|
483
503
|
};
|
|
484
|
-
var
|
|
504
|
+
var zkVerifyBatch = async (verifierUrl, serializedBytes, address, securityZone, chainId, consumingContract) => {
|
|
485
505
|
const packed_list = toHexString(serializedBytes);
|
|
486
506
|
const sz_byte = new Uint8Array([securityZone]);
|
|
487
507
|
const payload = {
|
|
488
508
|
packed_list,
|
|
489
509
|
account_addr: address,
|
|
490
510
|
security_zone: sz_byte[0],
|
|
491
|
-
chain_id: chainId
|
|
511
|
+
chain_id: chainId,
|
|
512
|
+
contract_address: consumingContract
|
|
492
513
|
};
|
|
493
514
|
const body = JSON.stringify(payload);
|
|
494
515
|
try {
|
|
495
|
-
const response = await fetch(`${verifierUrl}/
|
|
516
|
+
const response = await fetch(`${verifierUrl}/verifyBatch`, {
|
|
496
517
|
method: "POST",
|
|
497
518
|
headers: {
|
|
498
519
|
"Content-Type": "application/json"
|
|
@@ -503,26 +524,25 @@ var zkVerify = async (verifierUrl, serializedBytes, address, securityZone, chain
|
|
|
503
524
|
const errorBody = await response.text();
|
|
504
525
|
throw new CofheError({
|
|
505
526
|
code: "ZK_VERIFY_FAILED" /* ZkVerifyFailed */,
|
|
506
|
-
message: `HTTP error! ZK proof verification failed - ${errorBody}`
|
|
527
|
+
message: `HTTP error! ZK batch proof verification failed - ${errorBody}`
|
|
507
528
|
});
|
|
508
529
|
}
|
|
509
530
|
const json = await response.json();
|
|
510
531
|
if (json.status !== "success") {
|
|
511
532
|
throw new CofheError({
|
|
512
533
|
code: "ZK_VERIFY_FAILED" /* ZkVerifyFailed */,
|
|
513
|
-
message: `ZK proof verification response malformed - ${json.error}`
|
|
534
|
+
message: `ZK batch proof verification response malformed - ${json.error}`
|
|
514
535
|
});
|
|
515
536
|
}
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
});
|
|
537
|
+
const { ciphertexts, signature, recid } = json.data;
|
|
538
|
+
return {
|
|
539
|
+
outputs: ciphertexts,
|
|
540
|
+
signature: concatSigRecid(signature, recid)
|
|
541
|
+
};
|
|
522
542
|
} catch (e) {
|
|
523
543
|
throw new CofheError({
|
|
524
544
|
code: "ZK_VERIFY_FAILED" /* ZkVerifyFailed */,
|
|
525
|
-
message: `ZK proof verification failed`,
|
|
545
|
+
message: `ZK batch proof verification failed`,
|
|
526
546
|
cause: e instanceof Error ? e : void 0
|
|
527
547
|
});
|
|
528
548
|
}
|
|
@@ -767,75 +787,67 @@ async function insertCtHashes(items, walletClient) {
|
|
|
767
787
|
});
|
|
768
788
|
}
|
|
769
789
|
}
|
|
770
|
-
async function
|
|
771
|
-
let signatures = [];
|
|
772
|
-
let encInputSignerClient;
|
|
790
|
+
async function createBatchProofSignature(items, securityZone, account, consumingContract) {
|
|
773
791
|
try {
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
792
|
+
const itemHashes = items.map(
|
|
793
|
+
(item) => keccak256(
|
|
794
|
+
encodePacked(
|
|
795
|
+
["uint256", "uint8", "uint8", "address", "uint256", "address"],
|
|
796
|
+
[
|
|
797
|
+
BigInt(item.ctHash),
|
|
798
|
+
item.utype,
|
|
799
|
+
securityZone,
|
|
800
|
+
account,
|
|
801
|
+
BigInt(hardhat.id),
|
|
802
|
+
consumingContract
|
|
803
|
+
]
|
|
804
|
+
)
|
|
805
|
+
)
|
|
806
|
+
);
|
|
807
|
+
const batchDigest = keccak256(
|
|
808
|
+
encodePacked(
|
|
809
|
+
itemHashes.map(() => "bytes32"),
|
|
810
|
+
itemHashes
|
|
811
|
+
)
|
|
812
|
+
);
|
|
813
|
+
return await sign({
|
|
814
|
+
hash: batchDigest,
|
|
815
|
+
privateKey: MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY,
|
|
816
|
+
to: "hex"
|
|
783
817
|
});
|
|
784
|
-
}
|
|
785
|
-
try {
|
|
786
|
-
for (const item of items) {
|
|
787
|
-
const packedData = encodePacked(
|
|
788
|
-
["uint256", "uint8", "uint8", "address", "uint256"],
|
|
789
|
-
[BigInt(item.ctHash), item.utype, securityZone, account, BigInt(hardhat.id)]
|
|
790
|
-
);
|
|
791
|
-
const messageHash = keccak256(packedData);
|
|
792
|
-
const signature = await sign({
|
|
793
|
-
hash: messageHash,
|
|
794
|
-
privateKey: MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY,
|
|
795
|
-
to: "hex"
|
|
796
|
-
});
|
|
797
|
-
signatures.push(signature);
|
|
798
|
-
}
|
|
799
818
|
} catch (err) {
|
|
800
819
|
throw new CofheError({
|
|
801
820
|
code: "ZK_MOCKS_CREATE_PROOF_SIGNATURE_FAILED" /* ZkMocksCreateProofSignatureFailed */,
|
|
802
|
-
message: `mockZkVerifySign
|
|
821
|
+
message: `mockZkVerifySign createBatchProofSignature failed while signing the batch digest`,
|
|
803
822
|
cause: err instanceof Error ? err : void 0,
|
|
804
823
|
context: {
|
|
805
824
|
items,
|
|
806
|
-
securityZone
|
|
807
|
-
|
|
808
|
-
});
|
|
809
|
-
}
|
|
810
|
-
if (signatures.length !== items.length) {
|
|
811
|
-
throw new CofheError({
|
|
812
|
-
code: "ZK_MOCKS_CREATE_PROOF_SIGNATURE_FAILED" /* ZkMocksCreateProofSignatureFailed */,
|
|
813
|
-
message: `mockZkVerifySign createProofSignatures returned incorrect number of signatures`,
|
|
814
|
-
context: {
|
|
815
|
-
items,
|
|
816
|
-
securityZone
|
|
825
|
+
securityZone,
|
|
826
|
+
consumingContract
|
|
817
827
|
}
|
|
818
828
|
});
|
|
819
829
|
}
|
|
820
|
-
return signatures;
|
|
821
830
|
}
|
|
822
|
-
async function cofheMocksZkVerifySign(items, account, securityZone, publicClient, walletClient, zkvWalletClient) {
|
|
831
|
+
async function cofheMocksZkVerifySign(items, account, securityZone, consumingContract, publicClient, walletClient, zkvWalletClient) {
|
|
823
832
|
const _walletClient = zkvWalletClient ?? createMockZkVerifierSigner();
|
|
824
833
|
const encryptableItems = await calcCtHashes(items, account, securityZone, publicClient);
|
|
825
834
|
await insertCtHashes(encryptableItems, _walletClient);
|
|
826
|
-
const
|
|
827
|
-
return
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
835
|
+
const signature = await createBatchProofSignature(encryptableItems, securityZone, account, consumingContract);
|
|
836
|
+
return {
|
|
837
|
+
outputs: encryptableItems.map((item) => ({
|
|
838
|
+
ct_hash: item.ctHash.toString(),
|
|
839
|
+
ct_type: item.utype
|
|
840
|
+
})),
|
|
841
|
+
signature
|
|
842
|
+
};
|
|
831
843
|
}
|
|
832
844
|
var CofheConfigSchema = z.object({
|
|
833
845
|
/** Environment that the SDK is running in */
|
|
834
846
|
environment: z.enum(["node", "hardhat", "web", "react"]).optional().default("node"),
|
|
835
847
|
/** List of supported chain configurations */
|
|
836
848
|
supportedChains: z.array(z.custom()),
|
|
837
|
-
/** Default
|
|
838
|
-
|
|
849
|
+
/** Default acp expiration in seconds, default is 30 days */
|
|
850
|
+
defaultACPExpiration: z.number().optional().default(60 * 60 * 24 * 30),
|
|
839
851
|
/** Storage method for fhe keys (defaults to indexedDB on web, filesystem on node) */
|
|
840
852
|
fheKeyStorage: z.object({
|
|
841
853
|
getItem: z.custom((val) => typeof val === "function", {
|
|
@@ -850,6 +862,12 @@ var CofheConfigSchema = z.object({
|
|
|
850
862
|
}).or(z.null()).default(null),
|
|
851
863
|
/** Whether to use Web Workers for ZK proof generation (web platform only) */
|
|
852
864
|
useWorkers: z.boolean().optional().default(true),
|
|
865
|
+
/** ACP acp defaults */
|
|
866
|
+
acp: z.object({
|
|
867
|
+
defaultRevoker: z.custom().optional(),
|
|
868
|
+
defaultContractScopes: z.custom().optional(),
|
|
869
|
+
sharingRegistry: z.custom().optional()
|
|
870
|
+
}).optional().default({}),
|
|
853
871
|
/** Mocks configs */
|
|
854
872
|
mocks: z.object({
|
|
855
873
|
decryptDelay: z.number().optional().default(0),
|
|
@@ -860,8 +878,19 @@ var CofheConfigSchema = z.object({
|
|
|
860
878
|
zkvWalletClient: z.any().optional()
|
|
861
879
|
}).optional()
|
|
862
880
|
});
|
|
881
|
+
var RENAMED_COFHE_CONFIG_KEYS = {
|
|
882
|
+
defaultPermitExpiration: "defaultACPExpiration"
|
|
883
|
+
};
|
|
884
|
+
function assertNoRenamedConfigKeys(config, renamedKeys, label) {
|
|
885
|
+
const stale = Object.keys(config).filter((key) => key in renamedKeys);
|
|
886
|
+
if (stale.length === 0)
|
|
887
|
+
return;
|
|
888
|
+
const renames = stale.map((key) => `\`${key}\` is now \`${renamedKeys[key]}\``).join("; ");
|
|
889
|
+
throw new Error(`Invalid ${label}: ${renames}. See the v0.7.0 migration guide.`);
|
|
890
|
+
}
|
|
863
891
|
function createCofheConfigBase(config) {
|
|
864
|
-
|
|
892
|
+
assertNoRenamedConfigKeys(config, RENAMED_COFHE_CONFIG_KEYS, "cofhe configuration");
|
|
893
|
+
const result = CofheConfigSchema.strict().safeParse(config);
|
|
865
894
|
if (!result.success) {
|
|
866
895
|
throw new Error(`Invalid cofhe configuration: ${z.prettifyError(result.error)}`, { cause: result.error });
|
|
867
896
|
}
|
|
@@ -1213,9 +1242,9 @@ var BaseBuilder = class {
|
|
|
1213
1242
|
// core/encrypt/encryptInputsBuilder.ts
|
|
1214
1243
|
var EncryptInputsBuilder = class extends BaseBuilder {
|
|
1215
1244
|
securityZone;
|
|
1245
|
+
consumingContract;
|
|
1216
1246
|
stepCallback;
|
|
1217
1247
|
inputItems;
|
|
1218
|
-
hpp = false;
|
|
1219
1248
|
zkvWalletClient;
|
|
1220
1249
|
tfhePublicKeyDeserializer;
|
|
1221
1250
|
compactPkeCrsDeserializer;
|
|
@@ -1282,20 +1311,6 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1282
1311
|
this.keysStorage = params.keysStorage;
|
|
1283
1312
|
this.useWorker = params.config?.useWorkers ?? true;
|
|
1284
1313
|
}
|
|
1285
|
-
/**
|
|
1286
|
-
* @param account - Account that will create the tx using the encrypted inputs.
|
|
1287
|
-
*
|
|
1288
|
-
* If not provided, the account will be fetched from the connected walletClient.
|
|
1289
|
-
*
|
|
1290
|
-
* Example:
|
|
1291
|
-
* ```typescript
|
|
1292
|
-
* const encrypted = await encryptInputs([Encryptable.uint128(10n)])
|
|
1293
|
-
* .setAccount("0x123")
|
|
1294
|
-
* .execute();
|
|
1295
|
-
* ```
|
|
1296
|
-
*
|
|
1297
|
-
* @returns The chainable EncryptInputsBuilder instance.
|
|
1298
|
-
*/
|
|
1299
1314
|
setAccount(account) {
|
|
1300
1315
|
this.account = account;
|
|
1301
1316
|
return this;
|
|
@@ -1303,20 +1318,6 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1303
1318
|
getAccount() {
|
|
1304
1319
|
return this.account;
|
|
1305
1320
|
}
|
|
1306
|
-
/**
|
|
1307
|
-
* @param chainId - Chain that will consume the encrypted inputs.
|
|
1308
|
-
*
|
|
1309
|
-
* If not provided, the chainId will be fetched from the connected publicClient.
|
|
1310
|
-
*
|
|
1311
|
-
* Example:
|
|
1312
|
-
* ```typescript
|
|
1313
|
-
* const encrypted = await encryptInputs([Encryptable.uint128(10n)])
|
|
1314
|
-
* .setChainId(11155111)
|
|
1315
|
-
* .execute();
|
|
1316
|
-
* ```
|
|
1317
|
-
*
|
|
1318
|
-
* @returns The chainable EncryptInputsBuilder instance.
|
|
1319
|
-
*/
|
|
1320
1321
|
setChainId(chainId) {
|
|
1321
1322
|
this.chainId = chainId;
|
|
1322
1323
|
return this;
|
|
@@ -1324,20 +1325,6 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1324
1325
|
getChainId() {
|
|
1325
1326
|
return this.chainId;
|
|
1326
1327
|
}
|
|
1327
|
-
/**
|
|
1328
|
-
* @param securityZone - Security zone to encrypt the inputs for.
|
|
1329
|
-
*
|
|
1330
|
-
* If not provided, the default securityZone 0 will be used.
|
|
1331
|
-
*
|
|
1332
|
-
* Example:
|
|
1333
|
-
* ```typescript
|
|
1334
|
-
* const encrypted = await encryptInputs([Encryptable.uint128(10n)])
|
|
1335
|
-
* .setSecurityZone(1)
|
|
1336
|
-
* .execute();
|
|
1337
|
-
* ```
|
|
1338
|
-
*
|
|
1339
|
-
* @returns The chainable EncryptInputsBuilder instance.
|
|
1340
|
-
*/
|
|
1341
1328
|
setSecurityZone(securityZone) {
|
|
1342
1329
|
this.securityZone = securityZone;
|
|
1343
1330
|
return this;
|
|
@@ -1346,33 +1333,44 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1346
1333
|
return this.securityZone;
|
|
1347
1334
|
}
|
|
1348
1335
|
/**
|
|
1336
|
+
* @param address - The contract that will consume the resulting hashes+signature (i.e. the
|
|
1337
|
+
* contract that will call `FHE.asEuint*`/`FHE.asEuint*s` with them).
|
|
1338
|
+
*
|
|
1339
|
+
* Required before `execute()` - the verifier binds this address into the signed digest, so a
|
|
1340
|
+
* batch signed for one contract cannot be replayed into another.
|
|
1341
|
+
*
|
|
1349
1342
|
* Example:
|
|
1350
1343
|
* ```typescript
|
|
1351
1344
|
* const encrypted = await encryptInputs([Encryptable.uint128(10n)])
|
|
1352
|
-
* .
|
|
1345
|
+
* .setConsumingContract("0x123...890")
|
|
1353
1346
|
* .execute();
|
|
1354
1347
|
* ```
|
|
1355
1348
|
*
|
|
1356
|
-
* @returns
|
|
1349
|
+
* @returns The chainable EncryptInputsBuilder instance.
|
|
1357
1350
|
*/
|
|
1358
|
-
|
|
1359
|
-
this.
|
|
1351
|
+
setConsumingContract(address) {
|
|
1352
|
+
this.consumingContract = address;
|
|
1360
1353
|
return this;
|
|
1361
1354
|
}
|
|
1355
|
+
getConsumingContract() {
|
|
1356
|
+
return this.consumingContract;
|
|
1357
|
+
}
|
|
1362
1358
|
/**
|
|
1363
|
-
*
|
|
1364
|
-
*
|
|
1365
|
-
* Overrides the config-level useWorkers setting for this specific encryption.
|
|
1366
|
-
*
|
|
1367
|
-
* Example:
|
|
1368
|
-
* ```typescript
|
|
1369
|
-
* const encrypted = await encryptInputs([Encryptable.uint128(10n)])
|
|
1370
|
-
* .setUseWorker(false)
|
|
1371
|
-
* .execute();
|
|
1372
|
-
* ```
|
|
1373
|
-
*
|
|
1374
|
-
* @returns The chainable EncryptInputsBuilder instance.
|
|
1359
|
+
* Asserts that this.consumingContract is populated
|
|
1360
|
+
* @throws {CofheError} If consumingContract is not set
|
|
1375
1361
|
*/
|
|
1362
|
+
assertConsumingContract() {
|
|
1363
|
+
if (this.consumingContract)
|
|
1364
|
+
return;
|
|
1365
|
+
throw new CofheError({
|
|
1366
|
+
code: "CONSUMING_CONTRACT_UNINITIALIZED" /* ConsumingContractUninitialized */,
|
|
1367
|
+
message: "Consuming contract is not set",
|
|
1368
|
+
hint: "Use setConsumingContract(...) to set the contract that will consume the encrypted inputs.",
|
|
1369
|
+
context: {
|
|
1370
|
+
consumingContract: this.consumingContract
|
|
1371
|
+
}
|
|
1372
|
+
});
|
|
1373
|
+
}
|
|
1376
1374
|
setUseWorker(useWorker) {
|
|
1377
1375
|
this.useWorker = useWorker;
|
|
1378
1376
|
return this;
|
|
@@ -1393,21 +1391,6 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1393
1391
|
getUseWorker() {
|
|
1394
1392
|
return this.useWorker;
|
|
1395
1393
|
}
|
|
1396
|
-
/**
|
|
1397
|
-
* @param callback - Function to be called with the encryption step.
|
|
1398
|
-
*
|
|
1399
|
-
* Useful for debugging and tracking the progress of the encryption process.
|
|
1400
|
-
* Useful for a UI element that shows the progress of the encryption process.
|
|
1401
|
-
*
|
|
1402
|
-
* Example:
|
|
1403
|
-
* ```typescript
|
|
1404
|
-
* const encrypted = await encryptInputs([Encryptable.uint128(10n)])
|
|
1405
|
-
* .onStep((step: EncryptStep) => console.log(step))
|
|
1406
|
-
* .execute();
|
|
1407
|
-
* ```
|
|
1408
|
-
*
|
|
1409
|
-
* @returns The EncryptInputsBuilder instance.
|
|
1410
|
-
*/
|
|
1411
1394
|
onStep(callback) {
|
|
1412
1395
|
this.stepCallback = callback;
|
|
1413
1396
|
return this;
|
|
@@ -1546,6 +1529,7 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1546
1529
|
this.assertAccount();
|
|
1547
1530
|
this.assertPublicClient();
|
|
1548
1531
|
this.assertWalletClient();
|
|
1532
|
+
this.assertConsumingContract();
|
|
1549
1533
|
const [initTfheDelay, fetchKeysDelay, packDelay, proveDelay, verifyDelay] = this.resolveEncryptDelays();
|
|
1550
1534
|
this.fireStepStart("initTfhe" /* InitTfhe */);
|
|
1551
1535
|
await sleep(initTfheDelay);
|
|
@@ -1571,22 +1555,17 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1571
1555
|
this.fireStepEnd("prove" /* Prove */, { isMocks: true, mockSleep: proveDelay });
|
|
1572
1556
|
this.fireStepStart("verify" /* Verify */);
|
|
1573
1557
|
await sleep(verifyDelay);
|
|
1574
|
-
const
|
|
1558
|
+
const result = await cofheMocksZkVerifySign(
|
|
1575
1559
|
this.inputItems,
|
|
1576
1560
|
this.account,
|
|
1577
1561
|
this.securityZone,
|
|
1562
|
+
this.consumingContract,
|
|
1578
1563
|
this.publicClient,
|
|
1579
1564
|
this.walletClient,
|
|
1580
1565
|
this.zkvWalletClient
|
|
1581
1566
|
);
|
|
1582
|
-
const encryptedInputs = signedResults.map(({ ct_hash, signature }, index) => ({
|
|
1583
|
-
ctHash: BigInt(ct_hash),
|
|
1584
|
-
securityZone: this.securityZone,
|
|
1585
|
-
utype: this.inputItems[index].utype,
|
|
1586
|
-
signature
|
|
1587
|
-
}));
|
|
1588
1567
|
this.fireStepEnd("verify" /* Verify */, { isMocks: true, mockSleep: verifyDelay });
|
|
1589
|
-
return
|
|
1568
|
+
return result;
|
|
1590
1569
|
}
|
|
1591
1570
|
/**
|
|
1592
1571
|
* In the production context, perform a true encryption with the CoFHE coprocessor.
|
|
@@ -1594,6 +1573,7 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1594
1573
|
async productionExecute() {
|
|
1595
1574
|
this.assertAccount();
|
|
1596
1575
|
this.assertChainId();
|
|
1576
|
+
this.assertConsumingContract();
|
|
1597
1577
|
this.fireStepStart("initTfhe" /* InitTfhe */);
|
|
1598
1578
|
const tfheInitializationExecuted = await this.initTfheOrThrow();
|
|
1599
1579
|
this.fireStepEnd("initTfhe" /* InitTfhe */, { tfheInitializationExecuted });
|
|
@@ -1628,26 +1608,24 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1628
1608
|
});
|
|
1629
1609
|
this.fireStepStart("verify" /* Verify */);
|
|
1630
1610
|
const zkVerifierUrl = await this.getZkVerifierUrl();
|
|
1631
|
-
const
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
})
|
|
1611
|
+
const result = await zkVerifyBatch(
|
|
1612
|
+
zkVerifierUrl,
|
|
1613
|
+
proof,
|
|
1614
|
+
this.account,
|
|
1615
|
+
this.securityZone,
|
|
1616
|
+
this.chainId,
|
|
1617
|
+
this.consumingContract
|
|
1639
1618
|
);
|
|
1640
1619
|
this.fireStepEnd("verify" /* Verify */);
|
|
1641
|
-
return
|
|
1620
|
+
return result;
|
|
1642
1621
|
}
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
return [...hashes, proof];
|
|
1622
|
+
/**
|
|
1623
|
+
* Converts a batch-verified result (per-item ctHash/ctType + one shared signature) into the
|
|
1624
|
+
* tuple returned by `execute()`: per-item hashes in input order, followed by the single signature.
|
|
1625
|
+
*/
|
|
1626
|
+
buildBatchResult(result) {
|
|
1627
|
+
const hashes = result.outputs.map((output) => "0x" + BigInt(output.ct_hash).toString(16).padStart(64, "0"));
|
|
1628
|
+
return [...hashes, result.signature];
|
|
1651
1629
|
}
|
|
1652
1630
|
/**
|
|
1653
1631
|
* Final step of the encryption process. MUST BE CALLED LAST IN THE CHAIN.
|
|
@@ -1669,102 +1647,329 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1669
1647
|
* @returns The encrypted inputs.
|
|
1670
1648
|
*/
|
|
1671
1649
|
async execute() {
|
|
1672
|
-
let
|
|
1650
|
+
let result;
|
|
1673
1651
|
if (this.chainId === hardhat.id)
|
|
1674
|
-
|
|
1652
|
+
result = await this.mocksExecute();
|
|
1675
1653
|
else
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
return this.structsToHashPlusProof(items);
|
|
1679
|
-
return items;
|
|
1654
|
+
result = await this.productionExecute();
|
|
1655
|
+
return this.buildBatchResult(result);
|
|
1680
1656
|
}
|
|
1681
1657
|
};
|
|
1682
|
-
var
|
|
1658
|
+
var ACP_VALIDATOR_ABI = parseAbi([
|
|
1659
|
+
"function revokeSingle(uint256 id)",
|
|
1660
|
+
"function revokeAllExisting()",
|
|
1661
|
+
"function disabled(address issuer, uint256 id) view returns (bool)"
|
|
1662
|
+
]);
|
|
1663
|
+
var storeACP = async (acp, publicClient, walletClient) => {
|
|
1664
|
+
const chainId = await publicClient.getChainId();
|
|
1665
|
+
const account = walletClient.account.address;
|
|
1666
|
+
acpStore.setACP(chainId, account, acp);
|
|
1667
|
+
};
|
|
1668
|
+
var storeActiveACP = async (acp, publicClient, walletClient) => {
|
|
1669
|
+
await storeACP(acp, publicClient, walletClient);
|
|
1683
1670
|
const chainId = await publicClient.getChainId();
|
|
1684
1671
|
const account = walletClient.account.address;
|
|
1685
|
-
|
|
1686
|
-
permitStore.setActivePermitHash(chainId, account, permit.hash);
|
|
1672
|
+
acpStore.setActiveACPHash(chainId, account, acp.hash);
|
|
1687
1673
|
};
|
|
1688
|
-
var
|
|
1689
|
-
const
|
|
1690
|
-
|
|
1691
|
-
|
|
1674
|
+
var createACPWithSign = async (options, publicClient, walletClient, acpMethod, activate = true) => {
|
|
1675
|
+
const acp = await acpMethod(options, publicClient, walletClient);
|
|
1676
|
+
if (activate) {
|
|
1677
|
+
await storeActiveACP(acp, publicClient, walletClient);
|
|
1678
|
+
} else {
|
|
1679
|
+
await storeACP(acp, publicClient, walletClient);
|
|
1680
|
+
}
|
|
1681
|
+
return acp;
|
|
1692
1682
|
};
|
|
1693
1683
|
var createSelf = async (options, publicClient, walletClient) => {
|
|
1694
|
-
return
|
|
1684
|
+
return createACPWithSign(options, publicClient, walletClient, ACPUtils.createSelfAndSign);
|
|
1695
1685
|
};
|
|
1696
1686
|
var createSharing = async (options, publicClient, walletClient) => {
|
|
1697
|
-
return
|
|
1687
|
+
return createACPWithSign(options, publicClient, walletClient, ACPUtils.createSharingAndSign, false);
|
|
1698
1688
|
};
|
|
1699
1689
|
var importShared = async (options, publicClient, walletClient) => {
|
|
1700
|
-
return
|
|
1690
|
+
return createACPWithSign(options, publicClient, walletClient, ACPUtils.importSharedAndSign);
|
|
1701
1691
|
};
|
|
1702
|
-
var getHash = (
|
|
1703
|
-
return
|
|
1692
|
+
var getHash = (acp) => {
|
|
1693
|
+
return ACPUtils.getHash(acp);
|
|
1704
1694
|
};
|
|
1705
|
-
var exportShared = (
|
|
1706
|
-
return
|
|
1695
|
+
var exportShared = (acp) => {
|
|
1696
|
+
return ACPUtils.export(acp);
|
|
1707
1697
|
};
|
|
1708
|
-
var serialize = (
|
|
1709
|
-
return
|
|
1698
|
+
var serialize = (acp) => {
|
|
1699
|
+
return ACPUtils.serialize(acp);
|
|
1710
1700
|
};
|
|
1711
1701
|
var deserialize = (serialized) => {
|
|
1712
|
-
return
|
|
1702
|
+
return ACPUtils.deserialize(serialized);
|
|
1713
1703
|
};
|
|
1714
|
-
var
|
|
1715
|
-
return
|
|
1704
|
+
var getACP = (chainId, account, hash) => {
|
|
1705
|
+
return acpStore.getACP(chainId, account, hash);
|
|
1716
1706
|
};
|
|
1717
|
-
var
|
|
1718
|
-
return
|
|
1707
|
+
var getACPs = (chainId, account) => {
|
|
1708
|
+
return acpStore.getACPs(chainId, account);
|
|
1719
1709
|
};
|
|
1720
|
-
var
|
|
1721
|
-
return
|
|
1710
|
+
var getActiveACP = (chainId, account) => {
|
|
1711
|
+
return acpStore.getActiveACP(chainId, account);
|
|
1722
1712
|
};
|
|
1723
|
-
var
|
|
1724
|
-
return
|
|
1713
|
+
var getActiveACPHash = (chainId, account) => {
|
|
1714
|
+
return acpStore.getActiveACPHash(chainId, account);
|
|
1725
1715
|
};
|
|
1726
|
-
var
|
|
1727
|
-
|
|
1716
|
+
var selectActiveACP = (chainId, account, hash) => {
|
|
1717
|
+
acpStore.setActiveACPHash(chainId, account, hash);
|
|
1728
1718
|
};
|
|
1729
|
-
var
|
|
1719
|
+
var getOrCreateSelfACP = async (publicClient, walletClient, chainId, account, options) => {
|
|
1730
1720
|
const _chainId = chainId ?? await publicClient.getChainId();
|
|
1731
1721
|
const _account = account ?? walletClient.account.address;
|
|
1732
|
-
const
|
|
1733
|
-
if (
|
|
1734
|
-
return
|
|
1722
|
+
const activeACP = await getActiveACP(_chainId, _account);
|
|
1723
|
+
if (activeACP && activeACP.type === "self" && ACPUtils.isValid(activeACP).valid) {
|
|
1724
|
+
return activeACP;
|
|
1735
1725
|
}
|
|
1736
|
-
return createSelf(options ?? { issuer: _account, name: "Autogenerated Self
|
|
1726
|
+
return createSelf(options ?? { issuer: _account, name: "Autogenerated Self ACP" }, publicClient, walletClient);
|
|
1737
1727
|
};
|
|
1738
|
-
var
|
|
1728
|
+
var getOrCreateSharingACP = async (publicClient, walletClient, options, chainId, account) => {
|
|
1739
1729
|
const _chainId = chainId ?? await publicClient.getChainId();
|
|
1740
1730
|
const _account = account ?? walletClient.account.address;
|
|
1741
|
-
const
|
|
1742
|
-
if (
|
|
1743
|
-
return
|
|
1731
|
+
const activeACP = await getActiveACP(_chainId, _account);
|
|
1732
|
+
if (activeACP && activeACP.type === "sharing" && ACPUtils.isValid(activeACP).valid) {
|
|
1733
|
+
return activeACP;
|
|
1744
1734
|
}
|
|
1745
1735
|
return createSharing(options, publicClient, walletClient);
|
|
1746
1736
|
};
|
|
1747
|
-
var
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1737
|
+
var applyACPDefaults = (options, acpConfig, chainId) => {
|
|
1738
|
+
const result = { ...options };
|
|
1739
|
+
const defaultRevoker = acpConfig?.defaultRevoker?.[chainId];
|
|
1740
|
+
const hasValidatorOptions = options.revokerData != null || options.revokerContract != null;
|
|
1741
|
+
if (defaultRevoker != null && !hasValidatorOptions) {
|
|
1742
|
+
result.revokerContract = defaultRevoker;
|
|
1743
|
+
result.revokerData = Math.round(Date.now() / 1e3) - 60;
|
|
1744
|
+
}
|
|
1745
|
+
const defaultContracts = acpConfig?.defaultContractScopes?.[chainId];
|
|
1746
|
+
const hasScopeOptions = options.scope != null || options.contracts != null || options.handles != null;
|
|
1747
|
+
if (defaultContracts != null && defaultContracts.length > 0 && !hasScopeOptions) {
|
|
1748
|
+
result.contracts = defaultContracts;
|
|
1749
|
+
}
|
|
1750
|
+
return result;
|
|
1751
|
+
};
|
|
1752
|
+
var ACL_SERVED_ADDRESSES_ABI = parseAbi([
|
|
1753
|
+
"function acl() view returns (address)",
|
|
1754
|
+
"function defaultRevokerContract() view returns (address)",
|
|
1755
|
+
"function shareRegistry() view returns (address)"
|
|
1756
|
+
]);
|
|
1757
|
+
var aclServedAddressesCache = /* @__PURE__ */ new Map();
|
|
1758
|
+
var clearAclServedAddresses = () => aclServedAddressesCache.clear();
|
|
1759
|
+
var getAclServedAddresses = async (publicClient, chainId) => {
|
|
1760
|
+
const cached = aclServedAddressesCache.get(chainId);
|
|
1761
|
+
if (cached != null)
|
|
1762
|
+
return cached;
|
|
1763
|
+
let aclAddress;
|
|
1764
|
+
try {
|
|
1765
|
+
aclAddress = await publicClient.readContract({
|
|
1766
|
+
address: TASK_MANAGER_ADDRESS,
|
|
1767
|
+
abi: ACL_SERVED_ADDRESSES_ABI,
|
|
1768
|
+
functionName: "acl"
|
|
1769
|
+
});
|
|
1770
|
+
} catch {
|
|
1771
|
+
return {};
|
|
1772
|
+
}
|
|
1773
|
+
const [defaultRevoker, shareRegistry] = await Promise.all([
|
|
1774
|
+
publicClient.readContract({ address: aclAddress, abi: ACL_SERVED_ADDRESSES_ABI, functionName: "defaultRevokerContract" }).catch(() => void 0),
|
|
1775
|
+
publicClient.readContract({ address: aclAddress, abi: ACL_SERVED_ADDRESSES_ABI, functionName: "shareRegistry" }).catch(() => void 0)
|
|
1776
|
+
]);
|
|
1777
|
+
const resolved = {
|
|
1778
|
+
defaultRevoker: defaultRevoker != null && defaultRevoker !== zeroAddress ? defaultRevoker : void 0,
|
|
1779
|
+
shareRegistry: shareRegistry != null && shareRegistry !== zeroAddress ? shareRegistry : void 0
|
|
1780
|
+
};
|
|
1781
|
+
aclServedAddressesCache.set(chainId, resolved);
|
|
1782
|
+
return resolved;
|
|
1783
|
+
};
|
|
1784
|
+
var applyACPDefaultsFromChain = async (options, acpConfig, publicClient, chainId) => {
|
|
1785
|
+
const hasExplicitRevoker = acpConfig?.defaultRevoker?.[chainId] != null || options.revokerData != null || options.revokerContract != null;
|
|
1786
|
+
if (hasExplicitRevoker)
|
|
1787
|
+
return applyACPDefaults(options, acpConfig, chainId);
|
|
1788
|
+
const served = await getAclServedAddresses(publicClient, chainId);
|
|
1789
|
+
const effectiveConfig = served.defaultRevoker != null ? { ...acpConfig, defaultRevoker: { ...acpConfig?.defaultRevoker, [chainId]: served.defaultRevoker } } : acpConfig;
|
|
1790
|
+
return applyACPDefaults(options, effectiveConfig, chainId);
|
|
1791
|
+
};
|
|
1792
|
+
var revokeACP = async (acp, walletClient) => {
|
|
1793
|
+
if (acp.revokerContract === zeroAddress || acp.revokerData === 0) {
|
|
1794
|
+
throw new Error("ACP is not revocable: it has no revoker (revokerContract/revokerData unset)");
|
|
1795
|
+
}
|
|
1796
|
+
if (walletClient.account == null)
|
|
1797
|
+
throw new Error("Missing walletClient account");
|
|
1798
|
+
if (walletClient.account.address.toLowerCase() !== acp.issuer.toLowerCase()) {
|
|
1799
|
+
throw new Error("Only the acp issuer can revoke it");
|
|
1800
|
+
}
|
|
1801
|
+
return walletClient.writeContract({
|
|
1802
|
+
address: acp.revokerContract,
|
|
1803
|
+
abi: ACP_VALIDATOR_ABI,
|
|
1804
|
+
functionName: "revokeSingle",
|
|
1805
|
+
args: [BigInt(acp.revokerData)],
|
|
1806
|
+
account: walletClient.account,
|
|
1807
|
+
chain: walletClient.chain
|
|
1808
|
+
});
|
|
1809
|
+
};
|
|
1810
|
+
var revokeAllACPs = async (walletClient, publicClient, revokerContract) => {
|
|
1811
|
+
if (walletClient.account == null)
|
|
1812
|
+
throw new Error("Missing walletClient account");
|
|
1813
|
+
let revoker = revokerContract;
|
|
1814
|
+
if (revoker == null) {
|
|
1815
|
+
const chainId = await publicClient.getChainId();
|
|
1816
|
+
const active = getActiveACP(chainId, walletClient.account.address);
|
|
1817
|
+
revoker = active?.revokerContract;
|
|
1818
|
+
}
|
|
1819
|
+
if (revoker == null || revoker === zeroAddress) {
|
|
1820
|
+
throw new Error("No revoker contract: pass `revokerContract` or activate a revocable acp first");
|
|
1821
|
+
}
|
|
1822
|
+
return walletClient.writeContract({
|
|
1823
|
+
address: revoker,
|
|
1824
|
+
abi: ACP_VALIDATOR_ABI,
|
|
1825
|
+
functionName: "revokeAllExisting",
|
|
1826
|
+
args: [],
|
|
1827
|
+
account: walletClient.account,
|
|
1828
|
+
chain: walletClient.chain
|
|
1829
|
+
});
|
|
1830
|
+
};
|
|
1831
|
+
var isACPRevoked = async (acp, publicClient) => {
|
|
1832
|
+
if (acp.revokerContract === zeroAddress || acp.revokerData === 0)
|
|
1833
|
+
return false;
|
|
1834
|
+
return publicClient.readContract({
|
|
1835
|
+
address: acp.revokerContract,
|
|
1836
|
+
abi: ACP_VALIDATOR_ABI,
|
|
1837
|
+
functionName: "disabled",
|
|
1838
|
+
args: [acp.issuer, BigInt(acp.revokerData)]
|
|
1839
|
+
});
|
|
1840
|
+
};
|
|
1841
|
+
var ACP_SHARE_REGISTRY_ABI = parseAbi([
|
|
1842
|
+
"struct ACP { address issuer; uint64 expiration; address recipient; uint256 revokerData; address revokerContract; uint8 scope; address[] contracts; bytes32[] handles; bytes32 sealingKey; bytes issuerSignature; bytes recipientSignature; }",
|
|
1843
|
+
"function share(ACP calldata acp) external returns (bytes32)",
|
|
1844
|
+
"function removeShare(bytes32 shareId) external",
|
|
1845
|
+
"function sharesFor(address recipient) external view returns (ACP[] memory)",
|
|
1846
|
+
"function getShare(bytes32 shareId) external view returns (ACP memory)",
|
|
1847
|
+
"function isShareValid(bytes32 shareId) external view returns (bool)"
|
|
1848
|
+
]);
|
|
1849
|
+
var ACP_TUPLE = [
|
|
1850
|
+
{
|
|
1851
|
+
type: "tuple",
|
|
1852
|
+
components: [
|
|
1853
|
+
{ name: "issuer", type: "address" },
|
|
1854
|
+
{ name: "expiration", type: "uint64" },
|
|
1855
|
+
{ name: "recipient", type: "address" },
|
|
1856
|
+
{ name: "revokerData", type: "uint256" },
|
|
1857
|
+
{ name: "revokerContract", type: "address" },
|
|
1858
|
+
{ name: "scope", type: "uint8" },
|
|
1859
|
+
{ name: "contracts", type: "address[]" },
|
|
1860
|
+
{ name: "handles", type: "bytes32[]" },
|
|
1861
|
+
{ name: "sealingKey", type: "bytes32" },
|
|
1862
|
+
{ name: "issuerSignature", type: "bytes" },
|
|
1863
|
+
{ name: "recipientSignature", type: "bytes" }
|
|
1864
|
+
]
|
|
1865
|
+
}
|
|
1866
|
+
];
|
|
1867
|
+
var ZERO_BYTES32 = `0x${"0".repeat(64)}`;
|
|
1868
|
+
var toChainShare = (acp) => {
|
|
1869
|
+
const pub = ACPUtils.getPublic(acp, true);
|
|
1870
|
+
return {
|
|
1871
|
+
...pub,
|
|
1872
|
+
expiration: BigInt(pub.expiration),
|
|
1873
|
+
revokerData: BigInt(pub.revokerData),
|
|
1874
|
+
sealingKey: ZERO_BYTES32,
|
|
1875
|
+
recipientSignature: "0x"
|
|
1876
|
+
};
|
|
1877
|
+
};
|
|
1878
|
+
var computeShareId = (acp) => {
|
|
1879
|
+
const p = toChainShare(acp);
|
|
1880
|
+
return keccak256(encodeAbiParameters(ACP_TUPLE, [p]));
|
|
1881
|
+
};
|
|
1882
|
+
var shareOnChain = async (acp, walletClient, registry) => {
|
|
1883
|
+
if (acp.type !== "sharing") {
|
|
1884
|
+
throw new Error(`Cannot share a '${acp.type}' ACP on-chain \u2014 only 'sharing' ACPs are shareable.`);
|
|
1885
|
+
}
|
|
1886
|
+
if (acp.issuerSignature === "0x") {
|
|
1887
|
+
throw new Error("Cannot share an unsigned sharing ACP \u2014 sign it first.");
|
|
1888
|
+
}
|
|
1889
|
+
if (walletClient.account == null)
|
|
1890
|
+
throw new Error("Missing walletClient account");
|
|
1891
|
+
if (walletClient.account.address.toLowerCase() !== acp.issuer.toLowerCase()) {
|
|
1892
|
+
throw new Error("Only the ACP issuer can share it on-chain");
|
|
1893
|
+
}
|
|
1894
|
+
const txHash = await walletClient.writeContract({
|
|
1895
|
+
address: registry,
|
|
1896
|
+
abi: ACP_SHARE_REGISTRY_ABI,
|
|
1897
|
+
functionName: "share",
|
|
1898
|
+
args: [toChainShare(acp)],
|
|
1899
|
+
account: walletClient.account,
|
|
1900
|
+
chain: walletClient.chain ?? null
|
|
1901
|
+
});
|
|
1902
|
+
return { txHash, shareId: computeShareId(acp) };
|
|
1903
|
+
};
|
|
1904
|
+
var getIncomingShares = async (publicClient, registry, recipient) => {
|
|
1905
|
+
const raw = await publicClient.readContract({
|
|
1906
|
+
address: registry,
|
|
1907
|
+
abi: ACP_SHARE_REGISTRY_ABI,
|
|
1908
|
+
functionName: "sharesFor",
|
|
1909
|
+
args: [recipient]
|
|
1910
|
+
});
|
|
1911
|
+
return raw.map((s) => ({
|
|
1912
|
+
shareId: keccak256(encodeAbiParameters(ACP_TUPLE, [s])),
|
|
1913
|
+
issuer: s.issuer,
|
|
1914
|
+
expiration: Number(s.expiration),
|
|
1915
|
+
recipient: s.recipient,
|
|
1916
|
+
revokerData: Number(s.revokerData),
|
|
1917
|
+
revokerContract: s.revokerContract,
|
|
1918
|
+
scope: Number(s.scope),
|
|
1919
|
+
contracts: [...s.contracts],
|
|
1920
|
+
handles: [...s.handles],
|
|
1921
|
+
issuerSignature: s.issuerSignature
|
|
1922
|
+
}));
|
|
1923
|
+
};
|
|
1924
|
+
var importFromChain = async (share, publicClient, walletClient) => {
|
|
1925
|
+
const { shareId: _shareId, ...options } = share;
|
|
1926
|
+
return importShared({ ...options, type: "sharing" }, publicClient, walletClient);
|
|
1927
|
+
};
|
|
1928
|
+
var removeShareOnChain = async (shareId, walletClient, registry) => {
|
|
1929
|
+
if (walletClient.account == null)
|
|
1930
|
+
throw new Error("Missing walletClient account");
|
|
1931
|
+
return walletClient.writeContract({
|
|
1932
|
+
address: registry,
|
|
1933
|
+
abi: ACP_SHARE_REGISTRY_ABI,
|
|
1934
|
+
functionName: "removeShare",
|
|
1935
|
+
args: [shareId],
|
|
1936
|
+
account: walletClient.account,
|
|
1937
|
+
chain: walletClient.chain ?? null
|
|
1938
|
+
});
|
|
1939
|
+
};
|
|
1940
|
+
var removeACP = async (chainId, account, hash) => acpStore.removeACP(chainId, account, hash);
|
|
1941
|
+
var removeActiveACP = async (chainId, account) => acpStore.removeActiveACPHash(chainId, account);
|
|
1942
|
+
var acps = {
|
|
1943
|
+
getSnapshot: acpStore.store.getState,
|
|
1944
|
+
subscribe: acpStore.store.subscribe,
|
|
1752
1945
|
createSelf,
|
|
1753
1946
|
createSharing,
|
|
1754
1947
|
importShared,
|
|
1755
|
-
|
|
1756
|
-
|
|
1948
|
+
getOrCreateSelfACP,
|
|
1949
|
+
getOrCreateSharingACP,
|
|
1757
1950
|
getHash,
|
|
1758
1951
|
export: exportShared,
|
|
1759
1952
|
serialize,
|
|
1760
1953
|
deserialize,
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1954
|
+
getACP,
|
|
1955
|
+
getACPs,
|
|
1956
|
+
getActiveACP,
|
|
1957
|
+
getActiveACPHash,
|
|
1958
|
+
removeACP,
|
|
1959
|
+
selectActiveACP,
|
|
1960
|
+
removeActiveACP,
|
|
1961
|
+
revokeACP,
|
|
1962
|
+
revokeAllACPs,
|
|
1963
|
+
isACPRevoked,
|
|
1964
|
+
shareOnChain,
|
|
1965
|
+
getIncomingShares,
|
|
1966
|
+
importFromChain,
|
|
1967
|
+
removeShareOnChain,
|
|
1968
|
+
computeShareId,
|
|
1969
|
+
applyACPDefaults,
|
|
1970
|
+
applyACPDefaultsFromChain,
|
|
1971
|
+
getAclServedAddresses,
|
|
1972
|
+
clearAclServedAddresses
|
|
1768
1973
|
};
|
|
1769
1974
|
function uint160ToAddress(uint160) {
|
|
1770
1975
|
const hexStr = uint160.toString(16).padStart(40, "0");
|
|
@@ -1827,13 +2032,16 @@ var MockThresholdNetworkAbi = [
|
|
|
1827
2032
|
{
|
|
1828
2033
|
name: "permission",
|
|
1829
2034
|
type: "tuple",
|
|
1830
|
-
internalType: "struct
|
|
2035
|
+
internalType: "struct ACPermission",
|
|
1831
2036
|
components: [
|
|
1832
2037
|
{ name: "issuer", type: "address", internalType: "address" },
|
|
1833
2038
|
{ name: "expiration", type: "uint64", internalType: "uint64" },
|
|
1834
2039
|
{ name: "recipient", type: "address", internalType: "address" },
|
|
1835
|
-
{ name: "
|
|
1836
|
-
{ name: "
|
|
2040
|
+
{ name: "revokerData", type: "uint256", internalType: "uint256" },
|
|
2041
|
+
{ name: "revokerContract", type: "address", internalType: "address" },
|
|
2042
|
+
{ name: "scope", type: "uint8", internalType: "uint8" },
|
|
2043
|
+
{ name: "contracts", type: "address[]", internalType: "address[]" },
|
|
2044
|
+
{ name: "handles", type: "bytes32[]", internalType: "bytes32[]" },
|
|
1837
2045
|
{ name: "sealingKey", type: "bytes32", internalType: "bytes32" },
|
|
1838
2046
|
{ name: "issuerSignature", type: "bytes", internalType: "bytes" },
|
|
1839
2047
|
{ name: "recipientSignature", type: "bytes", internalType: "bytes" }
|
|
@@ -1856,13 +2064,16 @@ var MockThresholdNetworkAbi = [
|
|
|
1856
2064
|
{
|
|
1857
2065
|
name: "permission",
|
|
1858
2066
|
type: "tuple",
|
|
1859
|
-
internalType: "struct
|
|
2067
|
+
internalType: "struct ACPermission",
|
|
1860
2068
|
components: [
|
|
1861
2069
|
{ name: "issuer", type: "address", internalType: "address" },
|
|
1862
2070
|
{ name: "expiration", type: "uint64", internalType: "uint64" },
|
|
1863
2071
|
{ name: "recipient", type: "address", internalType: "address" },
|
|
1864
|
-
{ name: "
|
|
1865
|
-
{ name: "
|
|
2072
|
+
{ name: "revokerData", type: "uint256", internalType: "uint256" },
|
|
2073
|
+
{ name: "revokerContract", type: "address", internalType: "address" },
|
|
2074
|
+
{ name: "scope", type: "uint8", internalType: "uint8" },
|
|
2075
|
+
{ name: "contracts", type: "address[]", internalType: "address[]" },
|
|
2076
|
+
{ name: "handles", type: "bytes32[]", internalType: "bytes32[]" },
|
|
1866
2077
|
{ name: "sealingKey", type: "bytes32", internalType: "bytes32" },
|
|
1867
2078
|
{ name: "issuerSignature", type: "bytes", internalType: "bytes" },
|
|
1868
2079
|
{ name: "recipientSignature", type: "bytes", internalType: "bytes" }
|
|
@@ -1927,19 +2138,22 @@ var MockThresholdNetworkAbi = [
|
|
|
1927
2138
|
},
|
|
1928
2139
|
{
|
|
1929
2140
|
type: "function",
|
|
1930
|
-
name: "
|
|
2141
|
+
name: "decryptForTxWithACP",
|
|
1931
2142
|
inputs: [
|
|
1932
2143
|
{ name: "ctHash", type: "uint256", internalType: "uint256" },
|
|
1933
2144
|
{
|
|
1934
2145
|
name: "permission",
|
|
1935
2146
|
type: "tuple",
|
|
1936
|
-
internalType: "struct
|
|
2147
|
+
internalType: "struct ACPermission",
|
|
1937
2148
|
components: [
|
|
1938
2149
|
{ name: "issuer", type: "address", internalType: "address" },
|
|
1939
2150
|
{ name: "expiration", type: "uint64", internalType: "uint64" },
|
|
1940
2151
|
{ name: "recipient", type: "address", internalType: "address" },
|
|
1941
|
-
{ name: "
|
|
1942
|
-
{ name: "
|
|
2152
|
+
{ name: "revokerData", type: "uint256", internalType: "uint256" },
|
|
2153
|
+
{ name: "revokerContract", type: "address", internalType: "address" },
|
|
2154
|
+
{ name: "scope", type: "uint8", internalType: "uint8" },
|
|
2155
|
+
{ name: "contracts", type: "address[]", internalType: "address[]" },
|
|
2156
|
+
{ name: "handles", type: "bytes32[]", internalType: "bytes32[]" },
|
|
1943
2157
|
{ name: "sealingKey", type: "bytes32", internalType: "bytes32" },
|
|
1944
2158
|
{ name: "issuerSignature", type: "bytes", internalType: "bytes" },
|
|
1945
2159
|
{ name: "recipientSignature", type: "bytes", internalType: "bytes" }
|
|
@@ -1955,7 +2169,7 @@ var MockThresholdNetworkAbi = [
|
|
|
1955
2169
|
},
|
|
1956
2170
|
{
|
|
1957
2171
|
type: "function",
|
|
1958
|
-
name: "
|
|
2172
|
+
name: "decryptForTxWithoutACP",
|
|
1959
2173
|
inputs: [{ name: "ctHash", type: "uint256", internalType: "uint256" }],
|
|
1960
2174
|
outputs: [
|
|
1961
2175
|
{ name: "allowed", type: "bool", internalType: "bool" },
|
|
@@ -1967,12 +2181,12 @@ var MockThresholdNetworkAbi = [
|
|
|
1967
2181
|
];
|
|
1968
2182
|
|
|
1969
2183
|
// core/decrypt/cofheMocksDecryptForView.ts
|
|
1970
|
-
async function cofheMocksDecryptForView(ctHash, utype,
|
|
1971
|
-
const
|
|
2184
|
+
async function cofheMocksDecryptForView(ctHash, utype, acp, publicClient) {
|
|
2185
|
+
const wireAcp = ACPUtils.getPublic(acp, true);
|
|
1972
2186
|
const permissionWithBigInts = {
|
|
1973
|
-
...
|
|
1974
|
-
expiration: BigInt(
|
|
1975
|
-
|
|
2187
|
+
...wireAcp,
|
|
2188
|
+
expiration: BigInt(wireAcp.expiration),
|
|
2189
|
+
revokerData: BigInt(wireAcp.revokerData)
|
|
1976
2190
|
};
|
|
1977
2191
|
const [allowed, error, result] = await publicClient.readContract({
|
|
1978
2192
|
address: MOCKS_THRESHOLD_NETWORK_ADDRESS,
|
|
@@ -1993,7 +2207,7 @@ async function cofheMocksDecryptForView(ctHash, utype, permit, publicClient) {
|
|
|
1993
2207
|
});
|
|
1994
2208
|
}
|
|
1995
2209
|
const sealedBigInt = BigInt(result);
|
|
1996
|
-
const sealingKeyBigInt = BigInt(
|
|
2210
|
+
const sealingKeyBigInt = BigInt(acp.sealingKey);
|
|
1997
2211
|
const unsealed = sealedBigInt ^ sealingKeyBigInt;
|
|
1998
2212
|
return unsealed;
|
|
1999
2213
|
}
|
|
@@ -2036,11 +2250,61 @@ function computeMinuteRampPollIntervalMs(elapsedMs, params) {
|
|
|
2036
2250
|
return Math.min(params.maxIntervalMs, Math.max(params.minIntervalMs, intervalMs));
|
|
2037
2251
|
}
|
|
2038
2252
|
|
|
2253
|
+
// core/decrypt/apiError.ts
|
|
2254
|
+
var BACKEND_ERROR_CODE_TO_COFHE_ERROR_CODE = {
|
|
2255
|
+
bad_request: "BAD_REQUEST" /* BadRequest */,
|
|
2256
|
+
unknown_chain: "UNKNOWN_CHAIN" /* UnknownChain */,
|
|
2257
|
+
acp_malformed: "ACP_MALFORMED" /* ACPMalformed */,
|
|
2258
|
+
acp_denied: "ACP_DENIED" /* ACPDenied */,
|
|
2259
|
+
// ACP-era backends fold revoked into denied
|
|
2260
|
+
acp_expired: "ACP_EXPIRED" /* ACPExpired */,
|
|
2261
|
+
acp_invalid: "ACP_INVALID" /* ACPInvalid */,
|
|
2262
|
+
acp_required: "ACP_REQUIRED" /* ACPRequired */,
|
|
2263
|
+
acp_verifier_error: "ACP_VERIFIER_ERROR" /* ACPVerifierError */,
|
|
2264
|
+
acp_verifier_timeout: "ACP_VERIFIER_TIMEOUT" /* ACPVerifierTimeout */,
|
|
2265
|
+
not_publicly_allowed: "NOT_PUBLICLY_ALLOWED" /* NotPubliclyAllowed */,
|
|
2266
|
+
ct_not_found: "CT_NOT_FOUND" /* CtNotFound */,
|
|
2267
|
+
unsupported_security_zone: "UNSUPPORTED_SECURITY_ZONE" /* UnsupportedSecurityZone */,
|
|
2268
|
+
unsupported_type: "UNSUPPORTED_TYPE" /* UnsupportedType */,
|
|
2269
|
+
internal_error: "INTERNAL_ERROR" /* InternalError */,
|
|
2270
|
+
signing_failed: "SIGNING_FAILED" /* SigningFailed */,
|
|
2271
|
+
ct_source_error: "CT_SOURCE_ERROR" /* CtSourceError */,
|
|
2272
|
+
ct_source_timeout: "CT_SOURCE_TIMEOUT" /* CtSourceTimeout */,
|
|
2273
|
+
seal_failed: "SEAL_FAILED" /* SealFailed */
|
|
2274
|
+
};
|
|
2275
|
+
function isBackendApiErrorCode(value) {
|
|
2276
|
+
return value in BACKEND_ERROR_CODE_TO_COFHE_ERROR_CODE;
|
|
2277
|
+
}
|
|
2278
|
+
async function parseApiErrorResponseBody(response) {
|
|
2279
|
+
let errorMessage = `HTTP ${response.status}`;
|
|
2280
|
+
let apiErrorCode;
|
|
2281
|
+
try {
|
|
2282
|
+
const body = await response.json();
|
|
2283
|
+
if (body && typeof body === "object") {
|
|
2284
|
+
const record = body;
|
|
2285
|
+
if (typeof record.error === "string" && record.error.length > 0) {
|
|
2286
|
+
apiErrorCode = record.error;
|
|
2287
|
+
}
|
|
2288
|
+
if (typeof record.error_message === "string" && record.error_message.length > 0) {
|
|
2289
|
+
errorMessage = record.error_message;
|
|
2290
|
+
} else if (typeof record.message === "string" && record.message.length > 0) {
|
|
2291
|
+
errorMessage = record.message;
|
|
2292
|
+
}
|
|
2293
|
+
}
|
|
2294
|
+
} catch {
|
|
2295
|
+
errorMessage = response.statusText || errorMessage;
|
|
2296
|
+
}
|
|
2297
|
+
return { apiErrorCode, errorMessage };
|
|
2298
|
+
}
|
|
2299
|
+
function mapApiErrorCodeToCofheErrorCode(apiErrorCode, fallback) {
|
|
2300
|
+
if (apiErrorCode && isBackendApiErrorCode(apiErrorCode)) {
|
|
2301
|
+
return BACKEND_ERROR_CODE_TO_COFHE_ERROR_CODE[apiErrorCode];
|
|
2302
|
+
}
|
|
2303
|
+
return fallback;
|
|
2304
|
+
}
|
|
2305
|
+
|
|
2039
2306
|
// core/decrypt/submitRetry.ts
|
|
2040
2307
|
var DEFAULT_404_RETRY_TIMEOUT_MS = 1e4;
|
|
2041
|
-
function isRetryableSubmitStatus(status) {
|
|
2042
|
-
return status === 204 || status === 404;
|
|
2043
|
-
}
|
|
2044
2308
|
function normalize404RetryTimeoutMs(params) {
|
|
2045
2309
|
const { timeoutMs, operationLabel, errorCode } = params;
|
|
2046
2310
|
if (timeoutMs === void 0)
|
|
@@ -2057,32 +2321,24 @@ function normalize404RetryTimeoutMs(params) {
|
|
|
2057
2321
|
return timeoutMs;
|
|
2058
2322
|
}
|
|
2059
2323
|
async function classifySubmitResponse(params) {
|
|
2060
|
-
const { response,
|
|
2061
|
-
if (
|
|
2062
|
-
return { kind: "retryable", status:
|
|
2324
|
+
const { response, fallbackErrorCode } = params;
|
|
2325
|
+
if (response.status === 204) {
|
|
2326
|
+
return { kind: "retryable", status: 204 };
|
|
2063
2327
|
}
|
|
2064
2328
|
if (response.ok) {
|
|
2065
2329
|
return { kind: "parse-json" };
|
|
2066
2330
|
}
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
const maybeErrorMessage = extractErrorMessage?.(errorBody);
|
|
2071
|
-
if (typeof maybeErrorMessage === "string" && maybeErrorMessage.length > 0) {
|
|
2072
|
-
errorMessage = maybeErrorMessage;
|
|
2073
|
-
} else if (errorBody && typeof errorBody === "object") {
|
|
2074
|
-
const defaultMessage = errorBody.error_message;
|
|
2075
|
-
const fallbackMessage = errorBody.message;
|
|
2076
|
-
if (typeof defaultMessage === "string" && defaultMessage.length > 0) {
|
|
2077
|
-
errorMessage = defaultMessage;
|
|
2078
|
-
} else if (typeof fallbackMessage === "string" && fallbackMessage.length > 0) {
|
|
2079
|
-
errorMessage = fallbackMessage;
|
|
2080
|
-
}
|
|
2081
|
-
}
|
|
2082
|
-
} catch {
|
|
2083
|
-
errorMessage = response.statusText || errorMessage;
|
|
2331
|
+
const { apiErrorCode, errorMessage } = await parseApiErrorResponseBody(response);
|
|
2332
|
+
if (response.status === 404) {
|
|
2333
|
+
return { kind: "retryable", status: 404, apiErrorMessage: errorMessage };
|
|
2084
2334
|
}
|
|
2085
|
-
return {
|
|
2335
|
+
return {
|
|
2336
|
+
kind: "fatal-http",
|
|
2337
|
+
status: response.status,
|
|
2338
|
+
cofheErrorCode: mapApiErrorCodeToCofheErrorCode(apiErrorCode, fallbackErrorCode),
|
|
2339
|
+
apiErrorCode,
|
|
2340
|
+
errorMessage
|
|
2341
|
+
};
|
|
2086
2342
|
}
|
|
2087
2343
|
function throwIfSubmitRetryTimedOut(params) {
|
|
2088
2344
|
const {
|
|
@@ -2094,12 +2350,14 @@ function throwIfSubmitRetryTimedOut(params) {
|
|
|
2094
2350
|
overallTimeoutMs,
|
|
2095
2351
|
thresholdNetworkUrl,
|
|
2096
2352
|
body,
|
|
2097
|
-
attemptIndex
|
|
2353
|
+
attemptIndex,
|
|
2354
|
+
lastKnownErrorMessage
|
|
2098
2355
|
} = params;
|
|
2099
2356
|
if (status === 404 && elapsedMs > retry404TimeoutMs) {
|
|
2100
2357
|
throw new CofheError({
|
|
2101
|
-
code:
|
|
2102
|
-
|
|
2358
|
+
code: "CT_NOT_FOUND" /* CtNotFound */,
|
|
2359
|
+
apiErrorCode: "ct_not_found",
|
|
2360
|
+
message: `${operationLabel} ciphertext not found after retrying for ${retry404TimeoutMs}ms` + (lastKnownErrorMessage ? `: ${lastKnownErrorMessage}` : ""),
|
|
2103
2361
|
hint: "The ciphertext may not be indexed yet. Increase set404RetryTimeout(...) if the backend is slow to index ciphertexts.",
|
|
2104
2362
|
context: {
|
|
2105
2363
|
thresholdNetworkUrl,
|
|
@@ -2125,6 +2383,62 @@ function throwIfSubmitRetryTimedOut(params) {
|
|
|
2125
2383
|
});
|
|
2126
2384
|
}
|
|
2127
2385
|
}
|
|
2386
|
+
function normalizeTnSignature(signature) {
|
|
2387
|
+
if (typeof signature !== "string") {
|
|
2388
|
+
throw new CofheError({
|
|
2389
|
+
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
2390
|
+
message: "decrypt response missing signature",
|
|
2391
|
+
context: {
|
|
2392
|
+
signature
|
|
2393
|
+
}
|
|
2394
|
+
});
|
|
2395
|
+
}
|
|
2396
|
+
const trimmed = signature.trim();
|
|
2397
|
+
if (trimmed.length === 0) {
|
|
2398
|
+
throw new CofheError({
|
|
2399
|
+
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
2400
|
+
message: "decrypt response returned empty signature"
|
|
2401
|
+
});
|
|
2402
|
+
}
|
|
2403
|
+
const prefixed = trimmed.startsWith("0x") ? trimmed : `0x${trimmed}`;
|
|
2404
|
+
const parsed = parseSignature(prefixed);
|
|
2405
|
+
return serializeSignature(parsed);
|
|
2406
|
+
}
|
|
2407
|
+
function parseDecryptedBytesToBigInt(decrypted) {
|
|
2408
|
+
if (!Array.isArray(decrypted)) {
|
|
2409
|
+
throw new CofheError({
|
|
2410
|
+
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
2411
|
+
message: "decrypt response field <decrypted> must be a byte array",
|
|
2412
|
+
context: {
|
|
2413
|
+
decrypted
|
|
2414
|
+
}
|
|
2415
|
+
});
|
|
2416
|
+
}
|
|
2417
|
+
if (decrypted.length === 0) {
|
|
2418
|
+
throw new CofheError({
|
|
2419
|
+
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
2420
|
+
message: "decrypt response field <decrypted> was an empty byte array",
|
|
2421
|
+
context: {
|
|
2422
|
+
decrypted
|
|
2423
|
+
}
|
|
2424
|
+
});
|
|
2425
|
+
}
|
|
2426
|
+
let hex = "";
|
|
2427
|
+
for (const b of decrypted) {
|
|
2428
|
+
if (typeof b !== "number" || !Number.isInteger(b) || b < 0 || b > 255) {
|
|
2429
|
+
throw new CofheError({
|
|
2430
|
+
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
2431
|
+
message: "decrypt response field <decrypted> contained a non-byte value",
|
|
2432
|
+
context: {
|
|
2433
|
+
badElement: b,
|
|
2434
|
+
decrypted
|
|
2435
|
+
}
|
|
2436
|
+
});
|
|
2437
|
+
}
|
|
2438
|
+
hex += b.toString(16).padStart(2, "0");
|
|
2439
|
+
}
|
|
2440
|
+
return BigInt(`0x${hex}`);
|
|
2441
|
+
}
|
|
2128
2442
|
|
|
2129
2443
|
// core/decrypt/tnSealOutputV2.ts
|
|
2130
2444
|
var POLL_INTERVAL_MS = 1e3;
|
|
@@ -2187,13 +2501,14 @@ function parseCompletedSealOutputResponse(params) {
|
|
|
2187
2501
|
}
|
|
2188
2502
|
return convertSealedData(sealed);
|
|
2189
2503
|
}
|
|
2190
|
-
async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId,
|
|
2504
|
+
async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, acp, overallStartTime, retry404TimeoutMs, onPoll) {
|
|
2191
2505
|
const body = {
|
|
2192
2506
|
ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
|
|
2193
2507
|
host_chain_id: chainId,
|
|
2194
|
-
|
|
2508
|
+
acp
|
|
2195
2509
|
};
|
|
2196
2510
|
let attemptIndex = 0;
|
|
2511
|
+
let last404ApiErrorMessage;
|
|
2197
2512
|
for (; ; ) {
|
|
2198
2513
|
let response;
|
|
2199
2514
|
try {
|
|
@@ -2221,16 +2536,19 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, per
|
|
|
2221
2536
|
}
|
|
2222
2537
|
});
|
|
2223
2538
|
}
|
|
2224
|
-
const responseClassification = await classifySubmitResponse({
|
|
2539
|
+
const responseClassification = await classifySubmitResponse({
|
|
2540
|
+
response,
|
|
2541
|
+
fallbackErrorCode: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */
|
|
2542
|
+
});
|
|
2225
2543
|
if (responseClassification.kind === "fatal-http") {
|
|
2226
2544
|
throw new CofheError({
|
|
2227
|
-
code:
|
|
2545
|
+
code: responseClassification.cofheErrorCode,
|
|
2546
|
+
apiErrorCode: responseClassification.apiErrorCode,
|
|
2228
2547
|
message: `sealOutput request failed: ${responseClassification.errorMessage}`,
|
|
2229
2548
|
hint: "Check the threshold network URL and request parameters.",
|
|
2230
2549
|
context: {
|
|
2231
2550
|
thresholdNetworkUrl,
|
|
2232
|
-
status:
|
|
2233
|
-
statusText: response.statusText,
|
|
2551
|
+
status: responseClassification.status,
|
|
2234
2552
|
body,
|
|
2235
2553
|
attemptIndex
|
|
2236
2554
|
}
|
|
@@ -2276,6 +2594,9 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, per
|
|
|
2276
2594
|
}
|
|
2277
2595
|
});
|
|
2278
2596
|
}
|
|
2597
|
+
if (responseClassification.status === 404) {
|
|
2598
|
+
last404ApiErrorMessage = responseClassification.apiErrorMessage;
|
|
2599
|
+
}
|
|
2279
2600
|
const elapsedMs = Date.now() - overallStartTime;
|
|
2280
2601
|
throwIfSubmitRetryTimedOut({
|
|
2281
2602
|
operationLabel: "sealOutput",
|
|
@@ -2286,7 +2607,8 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, per
|
|
|
2286
2607
|
overallTimeoutMs: SEAL_OUTPUT_TIMEOUT_MS,
|
|
2287
2608
|
thresholdNetworkUrl,
|
|
2288
2609
|
body,
|
|
2289
|
-
attemptIndex
|
|
2610
|
+
attemptIndex,
|
|
2611
|
+
lastKnownErrorMessage: last404ApiErrorMessage
|
|
2290
2612
|
});
|
|
2291
2613
|
onPoll?.({
|
|
2292
2614
|
operation: "sealoutput",
|
|
@@ -2364,15 +2686,10 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStart
|
|
|
2364
2686
|
});
|
|
2365
2687
|
}
|
|
2366
2688
|
if (!response.ok) {
|
|
2367
|
-
|
|
2368
|
-
try {
|
|
2369
|
-
const errorBody = await response.json();
|
|
2370
|
-
errorMessage = errorBody.error_message || errorBody.message || errorMessage;
|
|
2371
|
-
} catch {
|
|
2372
|
-
errorMessage = response.statusText || errorMessage;
|
|
2373
|
-
}
|
|
2689
|
+
const { apiErrorCode, errorMessage } = await parseApiErrorResponseBody(response);
|
|
2374
2690
|
throw new CofheError({
|
|
2375
|
-
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed
|
|
2691
|
+
code: mapApiErrorCodeToCofheErrorCode(apiErrorCode, "SEAL_OUTPUT_FAILED" /* SealOutputFailed */),
|
|
2692
|
+
apiErrorCode,
|
|
2376
2693
|
message: `sealOutput status poll failed: ${errorMessage}`,
|
|
2377
2694
|
context: {
|
|
2378
2695
|
thresholdNetworkUrl,
|
|
@@ -2416,7 +2733,7 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStart
|
|
|
2416
2733
|
});
|
|
2417
2734
|
}
|
|
2418
2735
|
async function tnSealOutputV2(params) {
|
|
2419
|
-
const { thresholdNetworkUrl, ctHash, chainId,
|
|
2736
|
+
const { thresholdNetworkUrl, ctHash, chainId, acp, retry404TimeoutMs, onPoll } = params;
|
|
2420
2737
|
const normalized404RetryTimeoutMs = normalize404RetryTimeoutMs({
|
|
2421
2738
|
timeoutMs: retry404TimeoutMs,
|
|
2422
2739
|
operationLabel: "sealOutput",
|
|
@@ -2427,7 +2744,7 @@ async function tnSealOutputV2(params) {
|
|
|
2427
2744
|
thresholdNetworkUrl,
|
|
2428
2745
|
ctHash,
|
|
2429
2746
|
chainId,
|
|
2430
|
-
|
|
2747
|
+
acp,
|
|
2431
2748
|
overallStartTime,
|
|
2432
2749
|
normalized404RetryTimeoutMs,
|
|
2433
2750
|
onPoll
|
|
@@ -2443,8 +2760,8 @@ var DEFAULT_404_RETRY_TIMEOUT_MS2 = 1e4;
|
|
|
2443
2760
|
var DecryptForViewBuilder = class extends BaseBuilder {
|
|
2444
2761
|
ctHash;
|
|
2445
2762
|
utype;
|
|
2446
|
-
|
|
2447
|
-
|
|
2763
|
+
acpHash;
|
|
2764
|
+
acp;
|
|
2448
2765
|
pollCallback;
|
|
2449
2766
|
retry404TimeoutMs = DEFAULT_404_RETRY_TIMEOUT_MS2;
|
|
2450
2767
|
constructor(params) {
|
|
@@ -2458,11 +2775,11 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
2458
2775
|
});
|
|
2459
2776
|
this.ctHash = params.ctHash;
|
|
2460
2777
|
this.utype = params.utype;
|
|
2461
|
-
this.
|
|
2462
|
-
this.
|
|
2778
|
+
this.acpHash = params.acpHash;
|
|
2779
|
+
this.acp = params.acp;
|
|
2463
2780
|
}
|
|
2464
2781
|
/**
|
|
2465
|
-
* @param chainId - Chain to decrypt values from. Used to fetch the threshold network URL and use the correct
|
|
2782
|
+
* @param chainId - Chain to decrypt values from. Used to fetch the threshold network URL and use the correct acp.
|
|
2466
2783
|
*
|
|
2467
2784
|
* If not provided, the chainId will be fetched from the connected publicClient.
|
|
2468
2785
|
*
|
|
@@ -2483,7 +2800,7 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
2483
2800
|
return this.chainId;
|
|
2484
2801
|
}
|
|
2485
2802
|
/**
|
|
2486
|
-
* @param account - Account to decrypt values from. Used to fetch the correct
|
|
2803
|
+
* @param account - Account to decrypt values from. Used to fetch the correct acp.
|
|
2487
2804
|
*
|
|
2488
2805
|
* If not provided, the account will be fetched from the connected walletClient.
|
|
2489
2806
|
*
|
|
@@ -2520,61 +2837,61 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
2520
2837
|
this.retry404TimeoutMs = timeoutMs;
|
|
2521
2838
|
return this;
|
|
2522
2839
|
}
|
|
2523
|
-
|
|
2524
|
-
if (typeof
|
|
2525
|
-
this.
|
|
2526
|
-
this.
|
|
2527
|
-
} else if (
|
|
2528
|
-
this.
|
|
2529
|
-
this.
|
|
2840
|
+
withACP(acpOrACPHash) {
|
|
2841
|
+
if (typeof acpOrACPHash === "string") {
|
|
2842
|
+
this.acpHash = acpOrACPHash;
|
|
2843
|
+
this.acp = void 0;
|
|
2844
|
+
} else if (acpOrACPHash === void 0) {
|
|
2845
|
+
this.acpHash = void 0;
|
|
2846
|
+
this.acp = void 0;
|
|
2530
2847
|
} else {
|
|
2531
|
-
this.
|
|
2532
|
-
this.
|
|
2848
|
+
this.acp = acpOrACPHash;
|
|
2849
|
+
this.acpHash = void 0;
|
|
2533
2850
|
}
|
|
2534
2851
|
return this;
|
|
2535
2852
|
}
|
|
2536
2853
|
/**
|
|
2537
|
-
* @param
|
|
2854
|
+
* @param acpHash - ACP hash to decrypt values from. Used to fetch the correct acp.
|
|
2538
2855
|
*
|
|
2539
|
-
* If not provided, the active
|
|
2540
|
-
* If `
|
|
2856
|
+
* If not provided, the active acp for the chainId and account will be used.
|
|
2857
|
+
* If `setACP()` is called, it will be used regardless of chainId, account, or acpHash.
|
|
2541
2858
|
*
|
|
2542
2859
|
* Example:
|
|
2543
2860
|
* ```typescript
|
|
2544
2861
|
* const unsealed = await client.decryptForView(ctHash, utype)
|
|
2545
|
-
* .
|
|
2862
|
+
* .setACPHash('0x1234567890123456789012345678901234567890')
|
|
2546
2863
|
* .execute();
|
|
2547
2864
|
* ```
|
|
2548
2865
|
*
|
|
2549
2866
|
* @returns The chainable DecryptForViewBuilder instance.
|
|
2550
2867
|
*/
|
|
2551
|
-
/** @deprecated Use `
|
|
2552
|
-
|
|
2553
|
-
return this.
|
|
2868
|
+
/** @deprecated Use `withACP(acpHash)` instead. */
|
|
2869
|
+
setACPHash(acpHash) {
|
|
2870
|
+
return this.withACP(acpHash);
|
|
2554
2871
|
}
|
|
2555
|
-
|
|
2556
|
-
return this.
|
|
2872
|
+
getACPHash() {
|
|
2873
|
+
return this.acpHash;
|
|
2557
2874
|
}
|
|
2558
2875
|
/**
|
|
2559
|
-
* @param
|
|
2876
|
+
* @param acp - ACP to decrypt values with. If provided, it will be used regardless of chainId, account, or acpHash.
|
|
2560
2877
|
*
|
|
2561
|
-
* If not provided, the
|
|
2878
|
+
* If not provided, the acp will be determined by chainId, account, and acpHash.
|
|
2562
2879
|
*
|
|
2563
2880
|
* Example:
|
|
2564
2881
|
* ```typescript
|
|
2565
2882
|
* const unsealed = await client.decryptForView(ctHash, utype)
|
|
2566
|
-
* .
|
|
2883
|
+
* .setACP(acp)
|
|
2567
2884
|
* .execute();
|
|
2568
2885
|
* ```
|
|
2569
2886
|
*
|
|
2570
2887
|
* @returns The chainable DecryptForViewBuilder instance.
|
|
2571
2888
|
*/
|
|
2572
|
-
/** @deprecated Use `
|
|
2573
|
-
|
|
2574
|
-
return this.
|
|
2889
|
+
/** @deprecated Use `withACP(acp)` instead. */
|
|
2890
|
+
setACP(acp) {
|
|
2891
|
+
return this.withACP(acp);
|
|
2575
2892
|
}
|
|
2576
|
-
|
|
2577
|
-
return this.
|
|
2893
|
+
getACP() {
|
|
2894
|
+
return this.acp;
|
|
2578
2895
|
}
|
|
2579
2896
|
async getThresholdNetworkUrl() {
|
|
2580
2897
|
this.assertChainId();
|
|
@@ -2590,77 +2907,77 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
2590
2907
|
}
|
|
2591
2908
|
});
|
|
2592
2909
|
}
|
|
2593
|
-
async
|
|
2594
|
-
if (this.
|
|
2595
|
-
return this.
|
|
2910
|
+
async getResolvedACP() {
|
|
2911
|
+
if (this.acp)
|
|
2912
|
+
return this.acp;
|
|
2596
2913
|
this.assertChainId();
|
|
2597
2914
|
this.assertAccount();
|
|
2598
|
-
if (this.
|
|
2599
|
-
const
|
|
2600
|
-
if (!
|
|
2915
|
+
if (this.acpHash) {
|
|
2916
|
+
const acp2 = await acps.getACP(this.chainId, this.account, this.acpHash);
|
|
2917
|
+
if (!acp2) {
|
|
2601
2918
|
throw new CofheError({
|
|
2602
|
-
code: "
|
|
2603
|
-
message: `
|
|
2604
|
-
hint: "Ensure the
|
|
2919
|
+
code: "ACP_NOT_FOUND" /* ACPNotFound */,
|
|
2920
|
+
message: `ACP with hash <${this.acpHash}> not found for account <${this.account}> and chainId <${this.chainId}>`,
|
|
2921
|
+
hint: "Ensure the acp exists and is valid.",
|
|
2605
2922
|
context: {
|
|
2606
2923
|
chainId: this.chainId,
|
|
2607
2924
|
account: this.account,
|
|
2608
|
-
|
|
2925
|
+
acpHash: this.acpHash
|
|
2609
2926
|
}
|
|
2610
2927
|
});
|
|
2611
2928
|
}
|
|
2612
|
-
return
|
|
2929
|
+
return acp2;
|
|
2613
2930
|
}
|
|
2614
|
-
const
|
|
2615
|
-
if (!
|
|
2931
|
+
const acp = await acps.getActiveACP(this.chainId, this.account);
|
|
2932
|
+
if (!acp) {
|
|
2616
2933
|
throw new CofheError({
|
|
2617
|
-
code: "
|
|
2618
|
-
message: `Active
|
|
2619
|
-
hint: "Ensure
|
|
2934
|
+
code: "ACP_NOT_FOUND" /* ACPNotFound */,
|
|
2935
|
+
message: `Active acp not found for chainId <${this.chainId}> and account <${this.account}>`,
|
|
2936
|
+
hint: "Ensure an ACP exists for this account on this chain.",
|
|
2620
2937
|
context: {
|
|
2621
2938
|
chainId: this.chainId,
|
|
2622
2939
|
account: this.account
|
|
2623
2940
|
}
|
|
2624
2941
|
});
|
|
2625
2942
|
}
|
|
2626
|
-
return
|
|
2943
|
+
return acp;
|
|
2627
2944
|
}
|
|
2628
2945
|
/**
|
|
2629
2946
|
* On hardhat, interact with MockZkVerifier contract instead of CoFHE
|
|
2630
2947
|
*/
|
|
2631
|
-
async mocksSealOutput(
|
|
2948
|
+
async mocksSealOutput(acp) {
|
|
2632
2949
|
this.assertPublicClient();
|
|
2633
2950
|
const mocksDecryptDelay = this.config.mocks.decryptDelay;
|
|
2634
2951
|
if (mocksDecryptDelay > 0)
|
|
2635
2952
|
await sleep(mocksDecryptDelay);
|
|
2636
|
-
return cofheMocksDecryptForView(this.ctHash, this.utype,
|
|
2953
|
+
return cofheMocksDecryptForView(this.ctHash, this.utype, acp, this.publicClient);
|
|
2637
2954
|
}
|
|
2638
2955
|
/**
|
|
2639
2956
|
* In the production context, perform a true decryption with the CoFHE coprocessor.
|
|
2640
2957
|
*/
|
|
2641
|
-
async productionSealOutput(
|
|
2958
|
+
async productionSealOutput(acp) {
|
|
2642
2959
|
this.assertChainId();
|
|
2643
2960
|
this.assertPublicClient();
|
|
2644
2961
|
const thresholdNetworkUrl = await this.getThresholdNetworkUrl();
|
|
2645
|
-
const
|
|
2962
|
+
const wireAcp = ACPUtils.getPublic(acp, true);
|
|
2646
2963
|
const sealed = await tnSealOutputV2({
|
|
2647
2964
|
ctHash: this.ctHash,
|
|
2648
2965
|
chainId: this.chainId,
|
|
2649
|
-
|
|
2966
|
+
acp: wireAcp,
|
|
2650
2967
|
thresholdNetworkUrl,
|
|
2651
2968
|
retry404TimeoutMs: this.retry404TimeoutMs,
|
|
2652
2969
|
onPoll: this.pollCallback
|
|
2653
2970
|
});
|
|
2654
|
-
return
|
|
2971
|
+
return ACPUtils.unseal(acp, sealed);
|
|
2655
2972
|
}
|
|
2656
2973
|
/**
|
|
2657
2974
|
* Final step of the decryption process. MUST BE CALLED LAST IN THE CHAIN.
|
|
2658
2975
|
*
|
|
2659
2976
|
* This will:
|
|
2660
|
-
* - Use
|
|
2661
|
-
* - Check
|
|
2662
|
-
* - Call CoFHE `/sealoutput` with the
|
|
2663
|
-
* - Unseal the sealed item with the
|
|
2977
|
+
* - Use an ACP based on provided acp OR chainId + account + acpHash
|
|
2978
|
+
* - Check acp validity
|
|
2979
|
+
* - Call CoFHE `/sealoutput` with the acp, which returns a sealed (encrypted) item
|
|
2980
|
+
* - Unseal the sealed item with the acp
|
|
2664
2981
|
* - Return the unsealed item
|
|
2665
2982
|
*
|
|
2666
2983
|
* Example:
|
|
@@ -2668,7 +2985,7 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
2668
2985
|
* const unsealed = await client.decryptForView(ctHash, utype)
|
|
2669
2986
|
* .setChainId(11155111) // optional
|
|
2670
2987
|
* .setAccount('0x123...890') // optional
|
|
2671
|
-
* .
|
|
2988
|
+
* .withACP() // optional
|
|
2672
2989
|
* .execute(); // execute
|
|
2673
2990
|
* ```
|
|
2674
2991
|
*
|
|
@@ -2676,14 +2993,14 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
2676
2993
|
*/
|
|
2677
2994
|
async execute() {
|
|
2678
2995
|
this.validateUtypeOrThrow();
|
|
2679
|
-
const
|
|
2680
|
-
|
|
2681
|
-
const chainId =
|
|
2996
|
+
const acp = await this.getResolvedACP();
|
|
2997
|
+
ACPUtils.validate(acp);
|
|
2998
|
+
const chainId = acp._signedDomain.chainId;
|
|
2682
2999
|
let unsealed;
|
|
2683
3000
|
if (chainId === hardhat$1.id) {
|
|
2684
|
-
unsealed = await this.mocksSealOutput(
|
|
3001
|
+
unsealed = await this.mocksSealOutput(acp);
|
|
2685
3002
|
} else {
|
|
2686
|
-
unsealed = await this.productionSealOutput(
|
|
3003
|
+
unsealed = await this.productionSealOutput(acp);
|
|
2687
3004
|
}
|
|
2688
3005
|
return convertViaUtype(this.utype, unsealed);
|
|
2689
3006
|
}
|
|
@@ -2691,28 +3008,28 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
2691
3008
|
var UINT_TYPE_MASK = 0x7fn;
|
|
2692
3009
|
var TYPE_BYTE_OFFSET = 8n;
|
|
2693
3010
|
var getEncryptionTypeFromCtHash = (ctHash) => Number(ctHash >> TYPE_BYTE_OFFSET & UINT_TYPE_MASK);
|
|
2694
|
-
async function cofheMocksDecryptForTx(ctHash, utype,
|
|
3011
|
+
async function cofheMocksDecryptForTx(ctHash, utype, acp, publicClient) {
|
|
2695
3012
|
let allowed;
|
|
2696
3013
|
let error;
|
|
2697
3014
|
let decryptedValue;
|
|
2698
|
-
if (
|
|
2699
|
-
|
|
3015
|
+
if (acp !== null) {
|
|
3016
|
+
const wireAcp = ACPUtils.getPublic(acp, true);
|
|
2700
3017
|
const permissionWithBigInts = {
|
|
2701
|
-
...
|
|
2702
|
-
expiration: BigInt(
|
|
2703
|
-
|
|
3018
|
+
...wireAcp,
|
|
3019
|
+
expiration: BigInt(wireAcp.expiration),
|
|
3020
|
+
revokerData: BigInt(wireAcp.revokerData)
|
|
2704
3021
|
};
|
|
2705
3022
|
[allowed, error, decryptedValue] = await publicClient.readContract({
|
|
2706
3023
|
address: MOCKS_THRESHOLD_NETWORK_ADDRESS,
|
|
2707
3024
|
abi: MockThresholdNetworkAbi,
|
|
2708
|
-
functionName: "
|
|
3025
|
+
functionName: "decryptForTxWithACP",
|
|
2709
3026
|
args: [BigInt(ctHash), permissionWithBigInts]
|
|
2710
3027
|
});
|
|
2711
3028
|
} else {
|
|
2712
3029
|
[allowed, error, decryptedValue] = await publicClient.readContract({
|
|
2713
3030
|
address: MOCKS_THRESHOLD_NETWORK_ADDRESS,
|
|
2714
3031
|
abi: MockThresholdNetworkAbi,
|
|
2715
|
-
functionName: "
|
|
3032
|
+
functionName: "decryptForTxWithoutACP",
|
|
2716
3033
|
args: [BigInt(ctHash)]
|
|
2717
3034
|
});
|
|
2718
3035
|
}
|
|
@@ -2747,62 +3064,6 @@ async function cofheMocksDecryptForTx(ctHash, utype, permit, publicClient) {
|
|
|
2747
3064
|
signature
|
|
2748
3065
|
};
|
|
2749
3066
|
}
|
|
2750
|
-
function normalizeTnSignature(signature) {
|
|
2751
|
-
if (typeof signature !== "string") {
|
|
2752
|
-
throw new CofheError({
|
|
2753
|
-
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
2754
|
-
message: "decrypt response missing signature",
|
|
2755
|
-
context: {
|
|
2756
|
-
signature
|
|
2757
|
-
}
|
|
2758
|
-
});
|
|
2759
|
-
}
|
|
2760
|
-
const trimmed = signature.trim();
|
|
2761
|
-
if (trimmed.length === 0) {
|
|
2762
|
-
throw new CofheError({
|
|
2763
|
-
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
2764
|
-
message: "decrypt response returned empty signature"
|
|
2765
|
-
});
|
|
2766
|
-
}
|
|
2767
|
-
const prefixed = trimmed.startsWith("0x") ? trimmed : `0x${trimmed}`;
|
|
2768
|
-
const parsed = parseSignature(prefixed);
|
|
2769
|
-
return serializeSignature(parsed);
|
|
2770
|
-
}
|
|
2771
|
-
function parseDecryptedBytesToBigInt(decrypted) {
|
|
2772
|
-
if (!Array.isArray(decrypted)) {
|
|
2773
|
-
throw new CofheError({
|
|
2774
|
-
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
2775
|
-
message: "decrypt response field <decrypted> must be a byte array",
|
|
2776
|
-
context: {
|
|
2777
|
-
decrypted
|
|
2778
|
-
}
|
|
2779
|
-
});
|
|
2780
|
-
}
|
|
2781
|
-
if (decrypted.length === 0) {
|
|
2782
|
-
throw new CofheError({
|
|
2783
|
-
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
2784
|
-
message: "decrypt response field <decrypted> was an empty byte array",
|
|
2785
|
-
context: {
|
|
2786
|
-
decrypted
|
|
2787
|
-
}
|
|
2788
|
-
});
|
|
2789
|
-
}
|
|
2790
|
-
let hex = "";
|
|
2791
|
-
for (const b of decrypted) {
|
|
2792
|
-
if (typeof b !== "number" || !Number.isInteger(b) || b < 0 || b > 255) {
|
|
2793
|
-
throw new CofheError({
|
|
2794
|
-
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
2795
|
-
message: "decrypt response field <decrypted> contained a non-byte value",
|
|
2796
|
-
context: {
|
|
2797
|
-
badElement: b,
|
|
2798
|
-
decrypted
|
|
2799
|
-
}
|
|
2800
|
-
});
|
|
2801
|
-
}
|
|
2802
|
-
hex += b.toString(16).padStart(2, "0");
|
|
2803
|
-
}
|
|
2804
|
-
return BigInt(`0x${hex}`);
|
|
2805
|
-
}
|
|
2806
3067
|
|
|
2807
3068
|
// core/decrypt/tnDecryptV2.ts
|
|
2808
3069
|
var POLL_INTERVAL_MS2 = 1e3;
|
|
@@ -2924,15 +3185,16 @@ function assertDecryptStatusResponseV2(value) {
|
|
|
2924
3185
|
}
|
|
2925
3186
|
return value;
|
|
2926
3187
|
}
|
|
2927
|
-
async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId,
|
|
3188
|
+
async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, acp, overallStartTime, retry404TimeoutMs, onPoll) {
|
|
2928
3189
|
const body = {
|
|
2929
3190
|
ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
|
|
2930
3191
|
host_chain_id: chainId
|
|
2931
3192
|
};
|
|
2932
|
-
if (
|
|
2933
|
-
body.
|
|
3193
|
+
if (acp) {
|
|
3194
|
+
body.acp = acp;
|
|
2934
3195
|
}
|
|
2935
3196
|
let attemptIndex = 0;
|
|
3197
|
+
let last404ApiErrorMessage;
|
|
2936
3198
|
for (; ; ) {
|
|
2937
3199
|
let response;
|
|
2938
3200
|
try {
|
|
@@ -2960,16 +3222,19 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, perm
|
|
|
2960
3222
|
}
|
|
2961
3223
|
});
|
|
2962
3224
|
}
|
|
2963
|
-
const responseClassification = await classifySubmitResponse({
|
|
3225
|
+
const responseClassification = await classifySubmitResponse({
|
|
3226
|
+
response,
|
|
3227
|
+
fallbackErrorCode: "DECRYPT_FAILED" /* DecryptFailed */
|
|
3228
|
+
});
|
|
2964
3229
|
if (responseClassification.kind === "fatal-http") {
|
|
2965
3230
|
throw new CofheError({
|
|
2966
|
-
code:
|
|
3231
|
+
code: responseClassification.cofheErrorCode,
|
|
3232
|
+
apiErrorCode: responseClassification.apiErrorCode,
|
|
2967
3233
|
message: `decrypt request failed: ${responseClassification.errorMessage}`,
|
|
2968
3234
|
hint: "Check the threshold network URL and request parameters.",
|
|
2969
3235
|
context: {
|
|
2970
3236
|
thresholdNetworkUrl,
|
|
2971
|
-
status:
|
|
2972
|
-
statusText: response.statusText,
|
|
3237
|
+
status: responseClassification.status,
|
|
2973
3238
|
body,
|
|
2974
3239
|
attemptIndex
|
|
2975
3240
|
}
|
|
@@ -3017,6 +3282,9 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, perm
|
|
|
3017
3282
|
}
|
|
3018
3283
|
});
|
|
3019
3284
|
}
|
|
3285
|
+
if (responseClassification.status === 404) {
|
|
3286
|
+
last404ApiErrorMessage = responseClassification.apiErrorMessage;
|
|
3287
|
+
}
|
|
3020
3288
|
const elapsedMs = Date.now() - overallStartTime;
|
|
3021
3289
|
throwIfSubmitRetryTimedOut({
|
|
3022
3290
|
operationLabel: "decrypt",
|
|
@@ -3027,7 +3295,8 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, perm
|
|
|
3027
3295
|
overallTimeoutMs: DECRYPT_TIMEOUT_MS,
|
|
3028
3296
|
thresholdNetworkUrl,
|
|
3029
3297
|
body,
|
|
3030
|
-
attemptIndex
|
|
3298
|
+
attemptIndex,
|
|
3299
|
+
lastKnownErrorMessage: last404ApiErrorMessage
|
|
3031
3300
|
});
|
|
3032
3301
|
onPoll?.({
|
|
3033
3302
|
operation: "decrypt",
|
|
@@ -3105,17 +3374,10 @@ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartT
|
|
|
3105
3374
|
});
|
|
3106
3375
|
}
|
|
3107
3376
|
if (!response.ok) {
|
|
3108
|
-
|
|
3109
|
-
try {
|
|
3110
|
-
const errorBody = await response.json();
|
|
3111
|
-
const maybeMessage = errorBody.error_message || errorBody.message;
|
|
3112
|
-
if (typeof maybeMessage === "string" && maybeMessage.length > 0)
|
|
3113
|
-
errorMessage = maybeMessage;
|
|
3114
|
-
} catch {
|
|
3115
|
-
errorMessage = response.statusText || errorMessage;
|
|
3116
|
-
}
|
|
3377
|
+
const { apiErrorCode, errorMessage } = await parseApiErrorResponseBody(response);
|
|
3117
3378
|
throw new CofheError({
|
|
3118
|
-
code: "DECRYPT_FAILED" /* DecryptFailed
|
|
3379
|
+
code: mapApiErrorCodeToCofheErrorCode(apiErrorCode, "DECRYPT_FAILED" /* DecryptFailed */),
|
|
3380
|
+
apiErrorCode,
|
|
3119
3381
|
message: `decrypt status poll failed: ${errorMessage}`,
|
|
3120
3382
|
context: {
|
|
3121
3383
|
thresholdNetworkUrl,
|
|
@@ -3160,7 +3422,7 @@ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartT
|
|
|
3160
3422
|
});
|
|
3161
3423
|
}
|
|
3162
3424
|
async function tnDecryptV2(params) {
|
|
3163
|
-
const { thresholdNetworkUrl, ctHash, chainId,
|
|
3425
|
+
const { thresholdNetworkUrl, ctHash, chainId, acp, retry404TimeoutMs, onPoll } = params;
|
|
3164
3426
|
const normalized404RetryTimeoutMs = normalize404RetryTimeoutMs({
|
|
3165
3427
|
timeoutMs: retry404TimeoutMs,
|
|
3166
3428
|
operationLabel: "decrypt",
|
|
@@ -3171,7 +3433,7 @@ async function tnDecryptV2(params) {
|
|
|
3171
3433
|
thresholdNetworkUrl,
|
|
3172
3434
|
ctHash,
|
|
3173
3435
|
chainId,
|
|
3174
|
-
|
|
3436
|
+
acp,
|
|
3175
3437
|
overallStartTime,
|
|
3176
3438
|
normalized404RetryTimeoutMs,
|
|
3177
3439
|
onPoll
|
|
@@ -3186,9 +3448,9 @@ async function tnDecryptV2(params) {
|
|
|
3186
3448
|
var DEFAULT_404_RETRY_TIMEOUT_MS3 = 1e4;
|
|
3187
3449
|
var DecryptForTxBuilder = class extends BaseBuilder {
|
|
3188
3450
|
ctHash;
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3451
|
+
acpHash;
|
|
3452
|
+
acp;
|
|
3453
|
+
acpSelection = "unset";
|
|
3192
3454
|
pollCallback;
|
|
3193
3455
|
retry404TimeoutMs = DEFAULT_404_RETRY_TIMEOUT_MS3;
|
|
3194
3456
|
constructor(params) {
|
|
@@ -3233,137 +3495,137 @@ var DecryptForTxBuilder = class extends BaseBuilder {
|
|
|
3233
3495
|
this.retry404TimeoutMs = timeoutMs;
|
|
3234
3496
|
return this;
|
|
3235
3497
|
}
|
|
3236
|
-
|
|
3237
|
-
if (this.
|
|
3498
|
+
withACP(acpOrACPHash) {
|
|
3499
|
+
if (this.acpSelection === "with-acp") {
|
|
3238
3500
|
throw new CofheError({
|
|
3239
3501
|
code: "INTERNAL_ERROR" /* InternalError */,
|
|
3240
|
-
message: "decryptForTx:
|
|
3241
|
-
hint: "Choose the
|
|
3502
|
+
message: "decryptForTx: withACP() can only be selected once.",
|
|
3503
|
+
hint: "Choose the acp mode once. If you need a different acp, start a new decryptForTx() builder chain."
|
|
3242
3504
|
});
|
|
3243
3505
|
}
|
|
3244
|
-
if (this.
|
|
3506
|
+
if (this.acpSelection === "without-acp") {
|
|
3245
3507
|
throw new CofheError({
|
|
3246
3508
|
code: "INTERNAL_ERROR" /* InternalError */,
|
|
3247
|
-
message: "decryptForTx: cannot call
|
|
3248
|
-
hint: "Choose exactly one
|
|
3509
|
+
message: "decryptForTx: cannot call withACP() after withoutACP() has been selected.",
|
|
3510
|
+
hint: "Choose exactly one acp mode: either call .withACP(...) or .withoutACP(), but not both."
|
|
3249
3511
|
});
|
|
3250
3512
|
}
|
|
3251
|
-
this.
|
|
3252
|
-
if (typeof
|
|
3253
|
-
this.
|
|
3254
|
-
this.
|
|
3255
|
-
} else if (
|
|
3256
|
-
this.
|
|
3257
|
-
this.
|
|
3513
|
+
this.acpSelection = "with-acp";
|
|
3514
|
+
if (typeof acpOrACPHash === "string") {
|
|
3515
|
+
this.acpHash = acpOrACPHash;
|
|
3516
|
+
this.acp = void 0;
|
|
3517
|
+
} else if (acpOrACPHash === void 0) {
|
|
3518
|
+
this.acpHash = void 0;
|
|
3519
|
+
this.acp = void 0;
|
|
3258
3520
|
} else {
|
|
3259
|
-
this.
|
|
3260
|
-
this.
|
|
3521
|
+
this.acp = acpOrACPHash;
|
|
3522
|
+
this.acpHash = void 0;
|
|
3261
3523
|
}
|
|
3262
3524
|
return this;
|
|
3263
3525
|
}
|
|
3264
3526
|
/**
|
|
3265
|
-
* Select "no
|
|
3527
|
+
* Select "no acp" mode.
|
|
3266
3528
|
*
|
|
3267
|
-
* This uses global allowance (no
|
|
3529
|
+
* This uses global allowance (no acp required) and sends an empty permission payload to `/decrypt`.
|
|
3268
3530
|
*/
|
|
3269
|
-
|
|
3270
|
-
if (this.
|
|
3531
|
+
withoutACP() {
|
|
3532
|
+
if (this.acpSelection === "without-acp") {
|
|
3271
3533
|
throw new CofheError({
|
|
3272
3534
|
code: "INTERNAL_ERROR" /* InternalError */,
|
|
3273
|
-
message: "decryptForTx:
|
|
3274
|
-
hint: "Choose the
|
|
3535
|
+
message: "decryptForTx: withoutACP() can only be selected once.",
|
|
3536
|
+
hint: "Choose the acp mode once. If you need a different mode, start a new decryptForTx() builder chain."
|
|
3275
3537
|
});
|
|
3276
3538
|
}
|
|
3277
|
-
if (this.
|
|
3539
|
+
if (this.acpSelection === "with-acp") {
|
|
3278
3540
|
throw new CofheError({
|
|
3279
3541
|
code: "INTERNAL_ERROR" /* InternalError */,
|
|
3280
|
-
message: "decryptForTx: cannot call
|
|
3281
|
-
hint: "Choose exactly one
|
|
3542
|
+
message: "decryptForTx: cannot call withoutACP() after withACP() has been selected.",
|
|
3543
|
+
hint: "Choose exactly one acp mode: either call .withACP(...) or .withoutACP(), but not both."
|
|
3282
3544
|
});
|
|
3283
3545
|
}
|
|
3284
|
-
this.
|
|
3285
|
-
this.
|
|
3286
|
-
this.
|
|
3546
|
+
this.acpSelection = "without-acp";
|
|
3547
|
+
this.acpHash = void 0;
|
|
3548
|
+
this.acp = void 0;
|
|
3287
3549
|
return this;
|
|
3288
3550
|
}
|
|
3289
|
-
|
|
3290
|
-
return this.
|
|
3551
|
+
getACP() {
|
|
3552
|
+
return this.acp;
|
|
3291
3553
|
}
|
|
3292
|
-
|
|
3293
|
-
return this.
|
|
3554
|
+
getACPHash() {
|
|
3555
|
+
return this.acpHash;
|
|
3294
3556
|
}
|
|
3295
3557
|
async getThresholdNetworkUrl() {
|
|
3296
3558
|
this.assertChainId();
|
|
3297
3559
|
return getThresholdNetworkUrlOrThrow(this.config, this.chainId);
|
|
3298
3560
|
}
|
|
3299
|
-
async
|
|
3300
|
-
if (this.
|
|
3561
|
+
async getResolvedACP() {
|
|
3562
|
+
if (this.acpSelection === "unset") {
|
|
3301
3563
|
throw new CofheError({
|
|
3302
3564
|
code: "INTERNAL_ERROR" /* InternalError */,
|
|
3303
|
-
message: "decryptForTx: missing
|
|
3304
|
-
hint: "Call .
|
|
3565
|
+
message: "decryptForTx: missing acp selection; call withACP(...) or withoutACP() before execute().",
|
|
3566
|
+
hint: "Call .withACP() to use the active acp, or .withoutACP() for global allowance."
|
|
3305
3567
|
});
|
|
3306
3568
|
}
|
|
3307
|
-
if (this.
|
|
3569
|
+
if (this.acpSelection === "without-acp") {
|
|
3308
3570
|
return null;
|
|
3309
3571
|
}
|
|
3310
|
-
if (this.
|
|
3311
|
-
return this.
|
|
3572
|
+
if (this.acp)
|
|
3573
|
+
return this.acp;
|
|
3312
3574
|
this.assertChainId();
|
|
3313
3575
|
this.assertAccount();
|
|
3314
|
-
if (this.
|
|
3315
|
-
const
|
|
3316
|
-
if (!
|
|
3576
|
+
if (this.acpHash) {
|
|
3577
|
+
const acp2 = await acps.getACP(this.chainId, this.account, this.acpHash);
|
|
3578
|
+
if (!acp2) {
|
|
3317
3579
|
throw new CofheError({
|
|
3318
|
-
code: "
|
|
3319
|
-
message: `
|
|
3320
|
-
hint: "Ensure the
|
|
3580
|
+
code: "ACP_NOT_FOUND" /* ACPNotFound */,
|
|
3581
|
+
message: `ACP with hash <${this.acpHash}> not found for account <${this.account}> and chainId <${this.chainId}>`,
|
|
3582
|
+
hint: "Ensure the acp exists and is valid.",
|
|
3321
3583
|
context: {
|
|
3322
3584
|
chainId: this.chainId,
|
|
3323
3585
|
account: this.account,
|
|
3324
|
-
|
|
3586
|
+
acpHash: this.acpHash
|
|
3325
3587
|
}
|
|
3326
3588
|
});
|
|
3327
3589
|
}
|
|
3328
|
-
return
|
|
3590
|
+
return acp2;
|
|
3329
3591
|
}
|
|
3330
|
-
const
|
|
3331
|
-
if (!
|
|
3592
|
+
const acp = await acps.getActiveACP(this.chainId, this.account);
|
|
3593
|
+
if (!acp) {
|
|
3332
3594
|
throw new CofheError({
|
|
3333
|
-
code: "
|
|
3334
|
-
message: `Active
|
|
3335
|
-
hint: "Create
|
|
3595
|
+
code: "ACP_NOT_FOUND" /* ACPNotFound */,
|
|
3596
|
+
message: `Active acp not found for chainId <${this.chainId}> and account <${this.account}>`,
|
|
3597
|
+
hint: "Create an ACP (e.g. client.acp.createSelf(...)) and/or set it active (client.acp.selectActiveACP(hash)).",
|
|
3336
3598
|
context: {
|
|
3337
3599
|
chainId: this.chainId,
|
|
3338
3600
|
account: this.account
|
|
3339
3601
|
}
|
|
3340
3602
|
});
|
|
3341
3603
|
}
|
|
3342
|
-
return
|
|
3604
|
+
return acp;
|
|
3343
3605
|
}
|
|
3344
3606
|
/**
|
|
3345
3607
|
* On hardhat, interact with MockThresholdNetwork contract
|
|
3346
3608
|
*/
|
|
3347
|
-
async mocksDecryptForTx(
|
|
3609
|
+
async mocksDecryptForTx(acp) {
|
|
3348
3610
|
this.assertPublicClient();
|
|
3349
3611
|
const delay = this.config.mocks.decryptDelay;
|
|
3350
3612
|
if (delay > 0)
|
|
3351
3613
|
await sleep(delay);
|
|
3352
|
-
const result = await cofheMocksDecryptForTx(this.ctHash, 0,
|
|
3614
|
+
const result = await cofheMocksDecryptForTx(this.ctHash, 0, acp, this.publicClient);
|
|
3353
3615
|
return result;
|
|
3354
3616
|
}
|
|
3355
3617
|
/**
|
|
3356
3618
|
* In the production context, perform a true decryption with the CoFHE coprocessor.
|
|
3357
3619
|
*/
|
|
3358
|
-
async productionDecryptForTx(
|
|
3620
|
+
async productionDecryptForTx(acp) {
|
|
3359
3621
|
this.assertChainId();
|
|
3360
3622
|
this.assertPublicClient();
|
|
3361
3623
|
const thresholdNetworkUrl = await this.getThresholdNetworkUrl();
|
|
3362
|
-
const
|
|
3624
|
+
const wireAcp = acp ? ACPUtils.getPublic(acp, true) : null;
|
|
3363
3625
|
const { decryptedValue, signature } = await tnDecryptV2({
|
|
3364
3626
|
ctHash: this.ctHash,
|
|
3365
3627
|
chainId: this.chainId,
|
|
3366
|
-
|
|
3628
|
+
acp: wireAcp,
|
|
3367
3629
|
thresholdNetworkUrl,
|
|
3368
3630
|
retry404TimeoutMs: this.retry404TimeoutMs,
|
|
3369
3631
|
onPoll: this.pollCallback
|
|
@@ -3377,19 +3639,19 @@ var DecryptForTxBuilder = class extends BaseBuilder {
|
|
|
3377
3639
|
/**
|
|
3378
3640
|
* Final step of the decryptForTx process. MUST BE CALLED LAST IN THE CHAIN.
|
|
3379
3641
|
*
|
|
3380
|
-
* You must explicitly choose one
|
|
3381
|
-
* - `
|
|
3382
|
-
* - `
|
|
3642
|
+
* You must explicitly choose one acp mode before calling `execute()`:
|
|
3643
|
+
* - `withACP(acp)` / `withACP(acpHash)` / `withACP()` (active acp)
|
|
3644
|
+
* - `withoutACP()` (global allowance)
|
|
3383
3645
|
*/
|
|
3384
3646
|
async execute() {
|
|
3385
|
-
const
|
|
3386
|
-
if (
|
|
3387
|
-
|
|
3388
|
-
const chainId =
|
|
3647
|
+
const acp = await this.getResolvedACP();
|
|
3648
|
+
if (acp !== null) {
|
|
3649
|
+
ACPUtils.validate(acp);
|
|
3650
|
+
const chainId = acp._signedDomain.chainId;
|
|
3389
3651
|
if (chainId === hardhat$1.id) {
|
|
3390
|
-
return await this.mocksDecryptForTx(
|
|
3652
|
+
return await this.mocksDecryptForTx(acp);
|
|
3391
3653
|
} else {
|
|
3392
|
-
return await this.productionDecryptForTx(
|
|
3654
|
+
return await this.productionDecryptForTx(acp);
|
|
3393
3655
|
}
|
|
3394
3656
|
} else {
|
|
3395
3657
|
if (!this.chainId) {
|
|
@@ -3452,6 +3714,21 @@ function createCofheClientBase(opts) {
|
|
|
3452
3714
|
const updateConnectState = (partial) => {
|
|
3453
3715
|
connectStore.setState((state) => ({ ...state, ...partial }));
|
|
3454
3716
|
};
|
|
3717
|
+
const _resolveSharingRegistry = async (publicClient, chainId) => {
|
|
3718
|
+
const configured = opts.config.acp?.sharingRegistry?.[chainId];
|
|
3719
|
+
if (configured != null)
|
|
3720
|
+
return configured;
|
|
3721
|
+
const registry = (await acps.getAclServedAddresses(publicClient, chainId)).shareRegistry;
|
|
3722
|
+
if (registry == null) {
|
|
3723
|
+
throw new CofheError({
|
|
3724
|
+
code: "MISSING_CONFIG" /* MissingConfig */,
|
|
3725
|
+
message: `No ACP share registry available for chainId <${chainId}>`,
|
|
3726
|
+
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.",
|
|
3727
|
+
context: { chainId }
|
|
3728
|
+
});
|
|
3729
|
+
}
|
|
3730
|
+
return registry;
|
|
3731
|
+
};
|
|
3455
3732
|
const _requireConnected = () => {
|
|
3456
3733
|
const state = connectStore.getState();
|
|
3457
3734
|
const notConnected = !state.connected || !state.account || !state.chainId || !state.publicClient || !state.walletClient;
|
|
@@ -3574,74 +3851,147 @@ function createCofheClientBase(opts) {
|
|
|
3574
3851
|
}
|
|
3575
3852
|
return { chainId: _chainId, account: _account };
|
|
3576
3853
|
};
|
|
3577
|
-
const
|
|
3854
|
+
const clientACPs = {
|
|
3578
3855
|
// Pass through store access
|
|
3579
|
-
getSnapshot:
|
|
3580
|
-
subscribe:
|
|
3856
|
+
getSnapshot: acps.getSnapshot,
|
|
3857
|
+
subscribe: acps.subscribe,
|
|
3581
3858
|
// Creation methods (require connection)
|
|
3582
3859
|
createSelf: async (options, clients) => {
|
|
3583
3860
|
_requireConnected();
|
|
3584
3861
|
const { publicClient, walletClient } = clients ?? connectStore.getState();
|
|
3585
|
-
|
|
3862
|
+
const chainId = await publicClient.getChainId();
|
|
3863
|
+
return acps.createSelf(
|
|
3864
|
+
await acps.applyACPDefaultsFromChain(options, opts.config.acp, publicClient, chainId),
|
|
3865
|
+
publicClient,
|
|
3866
|
+
walletClient
|
|
3867
|
+
);
|
|
3586
3868
|
},
|
|
3587
3869
|
createSharing: async (options, clients) => {
|
|
3588
3870
|
_requireConnected();
|
|
3589
3871
|
const { publicClient, walletClient } = clients ?? connectStore.getState();
|
|
3590
|
-
|
|
3872
|
+
const chainId = await publicClient.getChainId();
|
|
3873
|
+
return acps.createSharing(
|
|
3874
|
+
await acps.applyACPDefaultsFromChain(options, opts.config.acp, publicClient, chainId),
|
|
3875
|
+
publicClient,
|
|
3876
|
+
walletClient
|
|
3877
|
+
);
|
|
3591
3878
|
},
|
|
3592
3879
|
importShared: async (options, clients) => {
|
|
3593
3880
|
_requireConnected();
|
|
3594
3881
|
const { publicClient, walletClient } = clients ?? connectStore.getState();
|
|
3595
|
-
return
|
|
3882
|
+
return acps.importShared(options, publicClient, walletClient);
|
|
3596
3883
|
},
|
|
3597
3884
|
// Get or create methods (require connection)
|
|
3598
|
-
|
|
3885
|
+
getOrCreateSelfACP: async (chainId, account, options) => {
|
|
3599
3886
|
_requireConnected();
|
|
3600
3887
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
3601
3888
|
const { publicClient, walletClient } = connectStore.getState();
|
|
3602
|
-
|
|
3889
|
+
const optionsWithDefaults = await acps.applyACPDefaultsFromChain(
|
|
3890
|
+
options ?? { issuer: _account, name: "Autogenerated Self ACP" },
|
|
3891
|
+
opts.config.acp,
|
|
3892
|
+
publicClient,
|
|
3893
|
+
_chainId
|
|
3894
|
+
);
|
|
3895
|
+
return acps.getOrCreateSelfACP(publicClient, walletClient, _chainId, _account, optionsWithDefaults);
|
|
3603
3896
|
},
|
|
3604
|
-
|
|
3897
|
+
getOrCreateSharingACP: async (options, chainId, account) => {
|
|
3605
3898
|
_requireConnected();
|
|
3606
3899
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
3607
3900
|
const { publicClient, walletClient } = connectStore.getState();
|
|
3608
|
-
return
|
|
3901
|
+
return acps.getOrCreateSharingACP(
|
|
3902
|
+
publicClient,
|
|
3903
|
+
walletClient,
|
|
3904
|
+
await acps.applyACPDefaultsFromChain(options, opts.config.acp, publicClient, _chainId),
|
|
3905
|
+
_chainId,
|
|
3906
|
+
_account
|
|
3907
|
+
);
|
|
3908
|
+
},
|
|
3909
|
+
// Revocation (require connection)
|
|
3910
|
+
revokeACP: async (acp) => {
|
|
3911
|
+
_requireConnected();
|
|
3912
|
+
const { walletClient } = connectStore.getState();
|
|
3913
|
+
return acps.revokeACP(acp, walletClient);
|
|
3914
|
+
},
|
|
3915
|
+
revokeAllACPs: async (revokerContract) => {
|
|
3916
|
+
_requireConnected();
|
|
3917
|
+
const { publicClient, walletClient } = connectStore.getState();
|
|
3918
|
+
return acps.revokeAllACPs(walletClient, publicClient, revokerContract);
|
|
3919
|
+
},
|
|
3920
|
+
isACPRevoked: async (acp) => {
|
|
3921
|
+
_requireConnected();
|
|
3922
|
+
const { publicClient } = connectStore.getState();
|
|
3923
|
+
return acps.isACPRevoked(acp, publicClient);
|
|
3924
|
+
},
|
|
3925
|
+
// On-chain sharing (require connection + config.acp.sharingRegistry)
|
|
3926
|
+
shareOnChain: async (acp) => {
|
|
3927
|
+
_requireConnected();
|
|
3928
|
+
const { publicClient, walletClient } = connectStore.getState();
|
|
3929
|
+
const chainId = await publicClient.getChainId();
|
|
3930
|
+
const sharingRegistry = await _resolveSharingRegistry(publicClient, chainId);
|
|
3931
|
+
return acps.shareOnChain(acp, walletClient, sharingRegistry);
|
|
3932
|
+
},
|
|
3933
|
+
getIncomingShares: async () => {
|
|
3934
|
+
_requireConnected();
|
|
3935
|
+
const { publicClient, walletClient } = connectStore.getState();
|
|
3936
|
+
const chainId = await publicClient.getChainId();
|
|
3937
|
+
const account = walletClient.account.address;
|
|
3938
|
+
const sharingRegistry = await _resolveSharingRegistry(publicClient, chainId);
|
|
3939
|
+
return acps.getIncomingShares(publicClient, sharingRegistry, account);
|
|
3940
|
+
},
|
|
3941
|
+
importFromChain: async (share) => {
|
|
3942
|
+
_requireConnected();
|
|
3943
|
+
const { publicClient, walletClient } = connectStore.getState();
|
|
3944
|
+
return acps.importFromChain(share, publicClient, walletClient);
|
|
3945
|
+
},
|
|
3946
|
+
dismissShare: async (shareId) => {
|
|
3947
|
+
_requireConnected();
|
|
3948
|
+
const { publicClient, walletClient } = connectStore.getState();
|
|
3949
|
+
const chainId = await publicClient.getChainId();
|
|
3950
|
+
const sharingRegistry = await _resolveSharingRegistry(publicClient, chainId);
|
|
3951
|
+
return acps.removeShareOnChain(shareId, walletClient, sharingRegistry);
|
|
3952
|
+
},
|
|
3953
|
+
cancelShare: async (shareId) => {
|
|
3954
|
+
_requireConnected();
|
|
3955
|
+
const { publicClient, walletClient } = connectStore.getState();
|
|
3956
|
+
const chainId = await publicClient.getChainId();
|
|
3957
|
+
const sharingRegistry = await _resolveSharingRegistry(publicClient, chainId);
|
|
3958
|
+
return acps.removeShareOnChain(shareId, walletClient, sharingRegistry);
|
|
3609
3959
|
},
|
|
3610
3960
|
// Retrieval methods (auto-fill chainId/account)
|
|
3611
|
-
|
|
3961
|
+
getACP: (hash, chainId, account) => {
|
|
3612
3962
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
3613
|
-
return
|
|
3963
|
+
return acps.getACP(_chainId, _account, hash);
|
|
3614
3964
|
},
|
|
3615
|
-
|
|
3965
|
+
getACPs: (chainId, account) => {
|
|
3616
3966
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
3617
|
-
return
|
|
3967
|
+
return acps.getACPs(_chainId, _account);
|
|
3618
3968
|
},
|
|
3619
|
-
|
|
3969
|
+
getActiveACP: (chainId, account) => {
|
|
3620
3970
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
3621
|
-
return
|
|
3971
|
+
return acps.getActiveACP(_chainId, _account);
|
|
3622
3972
|
},
|
|
3623
|
-
|
|
3973
|
+
getActiveACPHash: (chainId, account) => {
|
|
3624
3974
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
3625
|
-
return
|
|
3975
|
+
return acps.getActiveACPHash(_chainId, _account);
|
|
3626
3976
|
},
|
|
3627
3977
|
// Mutation methods (auto-fill chainId/account)
|
|
3628
|
-
|
|
3978
|
+
selectActiveACP: (hash, chainId, account) => {
|
|
3629
3979
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
3630
|
-
return
|
|
3980
|
+
return acps.selectActiveACP(_chainId, _account, hash);
|
|
3631
3981
|
},
|
|
3632
|
-
|
|
3982
|
+
removeACP: async (hash, chainId, account) => {
|
|
3633
3983
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
3634
|
-
return
|
|
3984
|
+
return acps.removeACP(_chainId, _account, hash);
|
|
3635
3985
|
},
|
|
3636
|
-
|
|
3986
|
+
removeActiveACP: async (chainId, account) => {
|
|
3637
3987
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
3638
|
-
return
|
|
3988
|
+
return acps.removeActiveACP(_chainId, _account);
|
|
3639
3989
|
},
|
|
3640
3990
|
// Utils (no context needed)
|
|
3641
|
-
getHash:
|
|
3642
|
-
export:
|
|
3643
|
-
serialize:
|
|
3644
|
-
deserialize:
|
|
3991
|
+
getHash: acps.getHash,
|
|
3992
|
+
export: acps.export,
|
|
3993
|
+
serialize: acps.serialize,
|
|
3994
|
+
deserialize: acps.deserialize
|
|
3645
3995
|
};
|
|
3646
3996
|
return {
|
|
3647
3997
|
// Zustand reactive accessors (don't export store directly to prevent mutation)
|
|
@@ -3669,7 +4019,7 @@ function createCofheClientBase(opts) {
|
|
|
3669
4019
|
decryptHandle: decryptForView,
|
|
3670
4020
|
decryptForTx,
|
|
3671
4021
|
verifyDecryptResult: verifyDecryptResult2,
|
|
3672
|
-
|
|
4022
|
+
acp: clientACPs
|
|
3673
4023
|
// Add SDK-specific methods below that require connection
|
|
3674
4024
|
// Example:
|
|
3675
4025
|
// async encryptData(data: unknown) {
|
|
@@ -3679,4 +4029,4 @@ function createCofheClientBase(opts) {
|
|
|
3679
4029
|
};
|
|
3680
4030
|
}
|
|
3681
4031
|
|
|
3682
|
-
export { CofheError, CofheErrorCode, DecryptForTxBuilder, DecryptForViewBuilder, EncryptInputsBuilder, EncryptStep, Encryptable, FheAllUTypes, FheTypes, FheUintUTypes, InitialConnectStore,
|
|
4032
|
+
export { CofheError, CofheErrorCode, DecryptForTxBuilder, DecryptForViewBuilder, EncryptInputsBuilder, EncryptStep, Encryptable, FheAllUTypes, FheTypes, FheUintUTypes, InitialConnectStore, assertNoRenamedConfigKeys, cofheFetch, createCofheClientBase, createCofheConfigBase, createKeysStore, fetchKeys, fheTypeToString, getCofheConfigItem, getCofheDebugInterceptors, isCofheError, isEncryptableItem, isLastEncryptionStep, setCofheDebugInterceptors, verifyDecryptResult, zkProveWithWorker };
|