@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
package/dist/core.cjs
CHANGED
|
@@ -16,58 +16,78 @@ var nacl__default = /*#__PURE__*/_interopDefault(nacl);
|
|
|
16
16
|
// core/client.ts
|
|
17
17
|
|
|
18
18
|
// core/error.ts
|
|
19
|
-
var CofheErrorCode = /* @__PURE__ */ ((
|
|
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
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
19
|
+
var CofheErrorCode = /* @__PURE__ */ ((CofheErrorCode2) => {
|
|
20
|
+
CofheErrorCode2["InternalError"] = "INTERNAL_ERROR";
|
|
21
|
+
CofheErrorCode2["UnknownEnvironment"] = "UNKNOWN_ENVIRONMENT";
|
|
22
|
+
CofheErrorCode2["InitTfheFailed"] = "INIT_TFHE_FAILED";
|
|
23
|
+
CofheErrorCode2["InitViemFailed"] = "INIT_VIEM_FAILED";
|
|
24
|
+
CofheErrorCode2["InitEthersFailed"] = "INIT_ETHERS_FAILED";
|
|
25
|
+
CofheErrorCode2["NotConnected"] = "NOT_CONNECTED";
|
|
26
|
+
CofheErrorCode2["MissingPublicClient"] = "MISSING_PUBLIC_CLIENT";
|
|
27
|
+
CofheErrorCode2["MissingWalletClient"] = "MISSING_WALLET_CLIENT";
|
|
28
|
+
CofheErrorCode2["MissingProviderParam"] = "MISSING_PROVIDER_PARAM";
|
|
29
|
+
CofheErrorCode2["EmptySecurityZonesParam"] = "EMPTY_SECURITY_ZONES_PARAM";
|
|
30
|
+
CofheErrorCode2["InvalidACPData"] = "INVALID_ACP_DATA";
|
|
31
|
+
CofheErrorCode2["InvalidACPDomain"] = "INVALID_ACP_DOMAIN";
|
|
32
|
+
CofheErrorCode2["ACPNotFound"] = "ACP_NOT_FOUND";
|
|
33
|
+
CofheErrorCode2["CannotRemoveLastACP"] = "CANNOT_REMOVE_LAST_ACP";
|
|
34
|
+
CofheErrorCode2["AccountUninitialized"] = "ACCOUNT_UNINITIALIZED";
|
|
35
|
+
CofheErrorCode2["ChainIdUninitialized"] = "CHAIN_ID_UNINITIALIZED";
|
|
36
|
+
CofheErrorCode2["ConsumingContractUninitialized"] = "CONSUMING_CONTRACT_UNINITIALIZED";
|
|
37
|
+
CofheErrorCode2["SealOutputFailed"] = "SEAL_OUTPUT_FAILED";
|
|
38
|
+
CofheErrorCode2["SealOutputReturnedNull"] = "SEAL_OUTPUT_RETURNED_NULL";
|
|
39
|
+
CofheErrorCode2["InvalidUtype"] = "INVALID_UTYPE";
|
|
40
|
+
CofheErrorCode2["DecryptFailed"] = "DECRYPT_FAILED";
|
|
41
|
+
CofheErrorCode2["DecryptReturnedNull"] = "DECRYPT_RETURNED_NULL";
|
|
42
|
+
CofheErrorCode2["ZkMocksInsertCtHashesFailed"] = "ZK_MOCKS_INSERT_CT_HASHES_FAILED";
|
|
43
|
+
CofheErrorCode2["ZkMocksCalcCtHashesFailed"] = "ZK_MOCKS_CALC_CT_HASHES_FAILED";
|
|
44
|
+
CofheErrorCode2["ZkMocksVerifySignFailed"] = "ZK_MOCKS_VERIFY_SIGN_FAILED";
|
|
45
|
+
CofheErrorCode2["ZkMocksCreateProofSignatureFailed"] = "ZK_MOCKS_CREATE_PROOF_SIGNATURE_FAILED";
|
|
46
|
+
CofheErrorCode2["ZkVerifyFailed"] = "ZK_VERIFY_FAILED";
|
|
47
|
+
CofheErrorCode2["ZkPackFailed"] = "ZK_PACK_FAILED";
|
|
48
|
+
CofheErrorCode2["ZkProveFailed"] = "ZK_PROVE_FAILED";
|
|
49
|
+
CofheErrorCode2["EncryptRemainingInItems"] = "ENCRYPT_REMAINING_IN_ITEMS";
|
|
50
|
+
CofheErrorCode2["ZkUninitialized"] = "ZK_UNINITIALIZED";
|
|
51
|
+
CofheErrorCode2["ZkVerifierUrlUninitialized"] = "ZK_VERIFIER_URL_UNINITIALIZED";
|
|
52
|
+
CofheErrorCode2["ThresholdNetworkUrlUninitialized"] = "THRESHOLD_NETWORK_URL_UNINITIALIZED";
|
|
53
|
+
CofheErrorCode2["MissingConfig"] = "MISSING_CONFIG";
|
|
54
|
+
CofheErrorCode2["UnsupportedChain"] = "UNSUPPORTED_CHAIN";
|
|
55
|
+
CofheErrorCode2["MissingZkBuilderAndCrsGenerator"] = "MISSING_ZK_BUILDER_AND_CRS_GENERATOR";
|
|
56
|
+
CofheErrorCode2["MissingTfhePublicKeyDeserializer"] = "MISSING_TFHE_PUBLIC_KEY_DESERIALIZER";
|
|
57
|
+
CofheErrorCode2["MissingCompactPkeCrsDeserializer"] = "MISSING_COMPACT_PKE_CRS_DESERIALIZER";
|
|
58
|
+
CofheErrorCode2["MissingFheKey"] = "MISSING_FHE_KEY";
|
|
59
|
+
CofheErrorCode2["MissingCrs"] = "MISSING_CRS";
|
|
60
|
+
CofheErrorCode2["FetchKeysFailed"] = "FETCH_KEYS_FAILED";
|
|
61
|
+
CofheErrorCode2["PublicWalletGetChainIdFailed"] = "PUBLIC_WALLET_GET_CHAIN_ID_FAILED";
|
|
62
|
+
CofheErrorCode2["PublicWalletGetAddressesFailed"] = "PUBLIC_WALLET_GET_ADDRESSES_FAILED";
|
|
63
|
+
CofheErrorCode2["RehydrateKeysStoreFailed"] = "REHYDRATE_KEYS_STORE_FAILED";
|
|
64
|
+
CofheErrorCode2["BadRequest"] = "BAD_REQUEST";
|
|
65
|
+
CofheErrorCode2["UnknownChain"] = "UNKNOWN_CHAIN";
|
|
66
|
+
CofheErrorCode2["ACPMalformed"] = "ACP_MALFORMED";
|
|
67
|
+
CofheErrorCode2["ACPDenied"] = "ACP_DENIED";
|
|
68
|
+
CofheErrorCode2["ACPExpired"] = "ACP_EXPIRED";
|
|
69
|
+
CofheErrorCode2["ACPInvalid"] = "ACP_INVALID";
|
|
70
|
+
CofheErrorCode2["ACPRevoked"] = "ACP_REVOKED";
|
|
71
|
+
CofheErrorCode2["NotPubliclyAllowed"] = "NOT_PUBLICLY_ALLOWED";
|
|
72
|
+
CofheErrorCode2["CtNotFound"] = "CT_NOT_FOUND";
|
|
73
|
+
CofheErrorCode2["UnsupportedSecurityZone"] = "UNSUPPORTED_SECURITY_ZONE";
|
|
74
|
+
CofheErrorCode2["UnsupportedType"] = "UNSUPPORTED_TYPE";
|
|
75
|
+
CofheErrorCode2["SigningFailed"] = "SIGNING_FAILED";
|
|
76
|
+
CofheErrorCode2["CtSourceError"] = "CT_SOURCE_ERROR";
|
|
77
|
+
CofheErrorCode2["ACPVerifierError"] = "ACP_VERIFIER_ERROR";
|
|
78
|
+
CofheErrorCode2["CtSourceTimeout"] = "CT_SOURCE_TIMEOUT";
|
|
79
|
+
CofheErrorCode2["ACPVerifierTimeout"] = "ACP_VERIFIER_TIMEOUT";
|
|
80
|
+
CofheErrorCode2["ACPRequired"] = "ACP_REQUIRED";
|
|
81
|
+
CofheErrorCode2["SealFailed"] = "SEAL_FAILED";
|
|
82
|
+
return CofheErrorCode2;
|
|
64
83
|
})(CofheErrorCode || {});
|
|
65
84
|
var CofheError = class _CofheError extends Error {
|
|
66
85
|
code;
|
|
67
86
|
cause;
|
|
68
87
|
hint;
|
|
69
88
|
context;
|
|
70
|
-
|
|
89
|
+
apiErrorCode;
|
|
90
|
+
constructor({ code, message, cause, hint, context, apiErrorCode }) {
|
|
71
91
|
const fullMessage = cause ? `${message} | Caused by: ${cause.message}` : message;
|
|
72
92
|
super(fullMessage);
|
|
73
93
|
this.name = "CofheError";
|
|
@@ -75,6 +95,7 @@ var CofheError = class _CofheError extends Error {
|
|
|
75
95
|
this.cause = cause;
|
|
76
96
|
this.hint = hint;
|
|
77
97
|
this.context = context;
|
|
98
|
+
this.apiErrorCode = apiErrorCode;
|
|
78
99
|
if (Error.captureStackTrace) {
|
|
79
100
|
Error.captureStackTrace(this, _CofheError);
|
|
80
101
|
}
|
|
@@ -93,6 +114,7 @@ var CofheError = class _CofheError extends Error {
|
|
|
93
114
|
message: wrapperError?.message ?? "An internal error occurred",
|
|
94
115
|
hint: wrapperError?.hint,
|
|
95
116
|
context: wrapperError?.context,
|
|
117
|
+
apiErrorCode: wrapperError?.apiErrorCode,
|
|
96
118
|
cause
|
|
97
119
|
});
|
|
98
120
|
}
|
|
@@ -106,6 +128,7 @@ var CofheError = class _CofheError extends Error {
|
|
|
106
128
|
message: this.message,
|
|
107
129
|
hint: this.hint,
|
|
108
130
|
context: this.context,
|
|
131
|
+
apiErrorCode: this.apiErrorCode,
|
|
109
132
|
cause: this.cause ? {
|
|
110
133
|
name: this.cause.name,
|
|
111
134
|
message: this.cause.message,
|
|
@@ -118,7 +141,8 @@ var CofheError = class _CofheError extends Error {
|
|
|
118
141
|
* Returns a human-readable string representation of the error
|
|
119
142
|
*/
|
|
120
143
|
toString() {
|
|
121
|
-
const
|
|
144
|
+
const codeSuffix = this.apiErrorCode ? ` (api: ${this.apiErrorCode})` : "";
|
|
145
|
+
const parts = [`${this.name} [${this.code}]${codeSuffix}: ${this.message}`];
|
|
122
146
|
if (this.hint) {
|
|
123
147
|
parts.push(`Hint: ${this.hint}`);
|
|
124
148
|
}
|
|
@@ -215,10 +239,6 @@ var FheAllUTypes = [
|
|
|
215
239
|
// FheTypes.Uint256,
|
|
216
240
|
7 /* Uint160 */
|
|
217
241
|
];
|
|
218
|
-
function assertCorrectEncryptedItemInput(input) {
|
|
219
|
-
if (!input.signature.startsWith("0x"))
|
|
220
|
-
throw new Error("Signature must be a hex string starting with 0x");
|
|
221
|
-
}
|
|
222
242
|
var EncryptableFactoriesImpl = {
|
|
223
243
|
bool: (data, securityZone = 0) => ({ data, securityZone, utype: 0 /* Bool */ }),
|
|
224
244
|
address: (data, securityZone = 0) => ({ data, securityZone, utype: 7 /* Uint160 */ }),
|
|
@@ -498,18 +518,19 @@ var constructZkPoKMetadata = (accountAddr, securityZone, chainId) => {
|
|
|
498
518
|
metadata.set(chainIdBytes, 1 + accountBytes.length);
|
|
499
519
|
return metadata;
|
|
500
520
|
};
|
|
501
|
-
var
|
|
521
|
+
var zkVerifyBatch = async (verifierUrl, serializedBytes, address, securityZone, chainId, consumingContract) => {
|
|
502
522
|
const packed_list = toHexString(serializedBytes);
|
|
503
523
|
const sz_byte = new Uint8Array([securityZone]);
|
|
504
524
|
const payload = {
|
|
505
525
|
packed_list,
|
|
506
526
|
account_addr: address,
|
|
507
527
|
security_zone: sz_byte[0],
|
|
508
|
-
chain_id: chainId
|
|
528
|
+
chain_id: chainId,
|
|
529
|
+
contract_address: consumingContract
|
|
509
530
|
};
|
|
510
531
|
const body = JSON.stringify(payload);
|
|
511
532
|
try {
|
|
512
|
-
const response = await fetch(`${verifierUrl}/
|
|
533
|
+
const response = await fetch(`${verifierUrl}/verifyBatch`, {
|
|
513
534
|
method: "POST",
|
|
514
535
|
headers: {
|
|
515
536
|
"Content-Type": "application/json"
|
|
@@ -520,26 +541,25 @@ var zkVerify = async (verifierUrl, serializedBytes, address, securityZone, chain
|
|
|
520
541
|
const errorBody = await response.text();
|
|
521
542
|
throw new CofheError({
|
|
522
543
|
code: "ZK_VERIFY_FAILED" /* ZkVerifyFailed */,
|
|
523
|
-
message: `HTTP error! ZK proof verification failed - ${errorBody}`
|
|
544
|
+
message: `HTTP error! ZK batch proof verification failed - ${errorBody}`
|
|
524
545
|
});
|
|
525
546
|
}
|
|
526
547
|
const json = await response.json();
|
|
527
548
|
if (json.status !== "success") {
|
|
528
549
|
throw new CofheError({
|
|
529
550
|
code: "ZK_VERIFY_FAILED" /* ZkVerifyFailed */,
|
|
530
|
-
message: `ZK proof verification response malformed - ${json.error}`
|
|
551
|
+
message: `ZK batch proof verification response malformed - ${json.error}`
|
|
531
552
|
});
|
|
532
553
|
}
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
});
|
|
554
|
+
const { ciphertexts, signature, recid } = json.data;
|
|
555
|
+
return {
|
|
556
|
+
outputs: ciphertexts,
|
|
557
|
+
signature: concatSigRecid(signature, recid)
|
|
558
|
+
};
|
|
539
559
|
} catch (e) {
|
|
540
560
|
throw new CofheError({
|
|
541
561
|
code: "ZK_VERIFY_FAILED" /* ZkVerifyFailed */,
|
|
542
|
-
message: `ZK proof verification failed`,
|
|
562
|
+
message: `ZK batch proof verification failed`,
|
|
543
563
|
cause: e instanceof Error ? e : void 0
|
|
544
564
|
});
|
|
545
565
|
}
|
|
@@ -784,67 +804,59 @@ async function insertCtHashes(items, walletClient) {
|
|
|
784
804
|
});
|
|
785
805
|
}
|
|
786
806
|
}
|
|
787
|
-
async function
|
|
788
|
-
let signatures = [];
|
|
789
|
-
let encInputSignerClient;
|
|
807
|
+
async function createBatchProofSignature(items, securityZone, account, consumingContract) {
|
|
790
808
|
try {
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
809
|
+
const itemHashes = items.map(
|
|
810
|
+
(item) => viem.keccak256(
|
|
811
|
+
viem.encodePacked(
|
|
812
|
+
["uint256", "uint8", "uint8", "address", "uint256", "address"],
|
|
813
|
+
[
|
|
814
|
+
BigInt(item.ctHash),
|
|
815
|
+
item.utype,
|
|
816
|
+
securityZone,
|
|
817
|
+
account,
|
|
818
|
+
BigInt(chains.hardhat.id),
|
|
819
|
+
consumingContract
|
|
820
|
+
]
|
|
821
|
+
)
|
|
822
|
+
)
|
|
823
|
+
);
|
|
824
|
+
const batchDigest = viem.keccak256(
|
|
825
|
+
viem.encodePacked(
|
|
826
|
+
itemHashes.map(() => "bytes32"),
|
|
827
|
+
itemHashes
|
|
828
|
+
)
|
|
829
|
+
);
|
|
830
|
+
return await accounts.sign({
|
|
831
|
+
hash: batchDigest,
|
|
832
|
+
privateKey: MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY,
|
|
833
|
+
to: "hex"
|
|
800
834
|
});
|
|
801
|
-
}
|
|
802
|
-
try {
|
|
803
|
-
for (const item of items) {
|
|
804
|
-
const packedData = viem.encodePacked(
|
|
805
|
-
["uint256", "uint8", "uint8", "address", "uint256"],
|
|
806
|
-
[BigInt(item.ctHash), item.utype, securityZone, account, BigInt(chains.hardhat.id)]
|
|
807
|
-
);
|
|
808
|
-
const messageHash = viem.keccak256(packedData);
|
|
809
|
-
const signature = await accounts.sign({
|
|
810
|
-
hash: messageHash,
|
|
811
|
-
privateKey: MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY,
|
|
812
|
-
to: "hex"
|
|
813
|
-
});
|
|
814
|
-
signatures.push(signature);
|
|
815
|
-
}
|
|
816
835
|
} catch (err) {
|
|
817
836
|
throw new CofheError({
|
|
818
837
|
code: "ZK_MOCKS_CREATE_PROOF_SIGNATURE_FAILED" /* ZkMocksCreateProofSignatureFailed */,
|
|
819
|
-
message: `mockZkVerifySign
|
|
838
|
+
message: `mockZkVerifySign createBatchProofSignature failed while signing the batch digest`,
|
|
820
839
|
cause: err instanceof Error ? err : void 0,
|
|
821
840
|
context: {
|
|
822
841
|
items,
|
|
823
|
-
securityZone
|
|
824
|
-
|
|
825
|
-
});
|
|
826
|
-
}
|
|
827
|
-
if (signatures.length !== items.length) {
|
|
828
|
-
throw new CofheError({
|
|
829
|
-
code: "ZK_MOCKS_CREATE_PROOF_SIGNATURE_FAILED" /* ZkMocksCreateProofSignatureFailed */,
|
|
830
|
-
message: `mockZkVerifySign createProofSignatures returned incorrect number of signatures`,
|
|
831
|
-
context: {
|
|
832
|
-
items,
|
|
833
|
-
securityZone
|
|
842
|
+
securityZone,
|
|
843
|
+
consumingContract
|
|
834
844
|
}
|
|
835
845
|
});
|
|
836
846
|
}
|
|
837
|
-
return signatures;
|
|
838
847
|
}
|
|
839
|
-
async function cofheMocksZkVerifySign(items, account, securityZone, publicClient, walletClient, zkvWalletClient) {
|
|
848
|
+
async function cofheMocksZkVerifySign(items, account, securityZone, consumingContract, publicClient, walletClient, zkvWalletClient) {
|
|
840
849
|
const _walletClient = zkvWalletClient ?? createMockZkVerifierSigner();
|
|
841
850
|
const encryptableItems = await calcCtHashes(items, account, securityZone, publicClient);
|
|
842
851
|
await insertCtHashes(encryptableItems, _walletClient);
|
|
843
|
-
const
|
|
844
|
-
return
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
852
|
+
const signature = await createBatchProofSignature(encryptableItems, securityZone, account, consumingContract);
|
|
853
|
+
return {
|
|
854
|
+
outputs: encryptableItems.map((item) => ({
|
|
855
|
+
ct_hash: item.ctHash.toString(),
|
|
856
|
+
ct_type: item.utype
|
|
857
|
+
})),
|
|
858
|
+
signature
|
|
859
|
+
};
|
|
848
860
|
}
|
|
849
861
|
var EnvironmentSchema = zod.z.enum(["MOCK", "TESTNET", "MAINNET"]);
|
|
850
862
|
var CofheChainSchema = zod.z.object({
|
|
@@ -887,8 +899,8 @@ var CofheConfigSchema = zod.z.object({
|
|
|
887
899
|
environment: zod.z.enum(["node", "hardhat", "web", "react"]).optional().default("node"),
|
|
888
900
|
/** List of supported chain configurations */
|
|
889
901
|
supportedChains: zod.z.array(zod.z.custom()),
|
|
890
|
-
/** Default
|
|
891
|
-
|
|
902
|
+
/** Default acp expiration in seconds, default is 30 days */
|
|
903
|
+
defaultACPExpiration: zod.z.number().optional().default(60 * 60 * 24 * 30),
|
|
892
904
|
/** Storage method for fhe keys (defaults to indexedDB on web, filesystem on node) */
|
|
893
905
|
fheKeyStorage: zod.z.object({
|
|
894
906
|
getItem: zod.z.custom((val) => typeof val === "function", {
|
|
@@ -903,6 +915,12 @@ var CofheConfigSchema = zod.z.object({
|
|
|
903
915
|
}).or(zod.z.null()).default(null),
|
|
904
916
|
/** Whether to use Web Workers for ZK proof generation (web platform only) */
|
|
905
917
|
useWorkers: zod.z.boolean().optional().default(true),
|
|
918
|
+
/** ACP acp defaults */
|
|
919
|
+
acp: zod.z.object({
|
|
920
|
+
defaultRevoker: zod.z.custom().optional(),
|
|
921
|
+
defaultContractScopes: zod.z.custom().optional(),
|
|
922
|
+
sharingRegistry: zod.z.custom().optional()
|
|
923
|
+
}).optional().default({}),
|
|
906
924
|
/** Mocks configs */
|
|
907
925
|
mocks: zod.z.object({
|
|
908
926
|
decryptDelay: zod.z.number().optional().default(0),
|
|
@@ -913,8 +931,19 @@ var CofheConfigSchema = zod.z.object({
|
|
|
913
931
|
zkvWalletClient: zod.z.any().optional()
|
|
914
932
|
}).optional()
|
|
915
933
|
});
|
|
934
|
+
var RENAMED_COFHE_CONFIG_KEYS = {
|
|
935
|
+
defaultPermitExpiration: "defaultACPExpiration"
|
|
936
|
+
};
|
|
937
|
+
function assertNoRenamedConfigKeys(config, renamedKeys, label) {
|
|
938
|
+
const stale = Object.keys(config).filter((key) => key in renamedKeys);
|
|
939
|
+
if (stale.length === 0)
|
|
940
|
+
return;
|
|
941
|
+
const renames = stale.map((key) => `\`${key}\` is now \`${renamedKeys[key]}\``).join("; ");
|
|
942
|
+
throw new Error(`Invalid ${label}: ${renames}. See the v0.7.0 migration guide.`);
|
|
943
|
+
}
|
|
916
944
|
function createCofheConfigBase(config) {
|
|
917
|
-
|
|
945
|
+
assertNoRenamedConfigKeys(config, RENAMED_COFHE_CONFIG_KEYS, "cofhe configuration");
|
|
946
|
+
const result = CofheConfigSchema.strict().safeParse(config);
|
|
918
947
|
if (!result.success) {
|
|
919
948
|
throw new Error(`Invalid cofhe configuration: ${zod.z.prettifyError(result.error)}`, { cause: result.error });
|
|
920
949
|
}
|
|
@@ -1266,9 +1295,9 @@ var BaseBuilder = class {
|
|
|
1266
1295
|
// core/encrypt/encryptInputsBuilder.ts
|
|
1267
1296
|
var EncryptInputsBuilder = class extends BaseBuilder {
|
|
1268
1297
|
securityZone;
|
|
1298
|
+
consumingContract;
|
|
1269
1299
|
stepCallback;
|
|
1270
1300
|
inputItems;
|
|
1271
|
-
hpp = false;
|
|
1272
1301
|
zkvWalletClient;
|
|
1273
1302
|
tfhePublicKeyDeserializer;
|
|
1274
1303
|
compactPkeCrsDeserializer;
|
|
@@ -1335,20 +1364,6 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1335
1364
|
this.keysStorage = params.keysStorage;
|
|
1336
1365
|
this.useWorker = params.config?.useWorkers ?? true;
|
|
1337
1366
|
}
|
|
1338
|
-
/**
|
|
1339
|
-
* @param account - Account that will create the tx using the encrypted inputs.
|
|
1340
|
-
*
|
|
1341
|
-
* If not provided, the account will be fetched from the connected walletClient.
|
|
1342
|
-
*
|
|
1343
|
-
* Example:
|
|
1344
|
-
* ```typescript
|
|
1345
|
-
* const encrypted = await encryptInputs([Encryptable.uint128(10n)])
|
|
1346
|
-
* .setAccount("0x123")
|
|
1347
|
-
* .execute();
|
|
1348
|
-
* ```
|
|
1349
|
-
*
|
|
1350
|
-
* @returns The chainable EncryptInputsBuilder instance.
|
|
1351
|
-
*/
|
|
1352
1367
|
setAccount(account) {
|
|
1353
1368
|
this.account = account;
|
|
1354
1369
|
return this;
|
|
@@ -1356,20 +1371,6 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1356
1371
|
getAccount() {
|
|
1357
1372
|
return this.account;
|
|
1358
1373
|
}
|
|
1359
|
-
/**
|
|
1360
|
-
* @param chainId - Chain that will consume the encrypted inputs.
|
|
1361
|
-
*
|
|
1362
|
-
* If not provided, the chainId will be fetched from the connected publicClient.
|
|
1363
|
-
*
|
|
1364
|
-
* Example:
|
|
1365
|
-
* ```typescript
|
|
1366
|
-
* const encrypted = await encryptInputs([Encryptable.uint128(10n)])
|
|
1367
|
-
* .setChainId(11155111)
|
|
1368
|
-
* .execute();
|
|
1369
|
-
* ```
|
|
1370
|
-
*
|
|
1371
|
-
* @returns The chainable EncryptInputsBuilder instance.
|
|
1372
|
-
*/
|
|
1373
1374
|
setChainId(chainId) {
|
|
1374
1375
|
this.chainId = chainId;
|
|
1375
1376
|
return this;
|
|
@@ -1377,20 +1378,6 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1377
1378
|
getChainId() {
|
|
1378
1379
|
return this.chainId;
|
|
1379
1380
|
}
|
|
1380
|
-
/**
|
|
1381
|
-
* @param securityZone - Security zone to encrypt the inputs for.
|
|
1382
|
-
*
|
|
1383
|
-
* If not provided, the default securityZone 0 will be used.
|
|
1384
|
-
*
|
|
1385
|
-
* Example:
|
|
1386
|
-
* ```typescript
|
|
1387
|
-
* const encrypted = await encryptInputs([Encryptable.uint128(10n)])
|
|
1388
|
-
* .setSecurityZone(1)
|
|
1389
|
-
* .execute();
|
|
1390
|
-
* ```
|
|
1391
|
-
*
|
|
1392
|
-
* @returns The chainable EncryptInputsBuilder instance.
|
|
1393
|
-
*/
|
|
1394
1381
|
setSecurityZone(securityZone) {
|
|
1395
1382
|
this.securityZone = securityZone;
|
|
1396
1383
|
return this;
|
|
@@ -1399,33 +1386,44 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1399
1386
|
return this.securityZone;
|
|
1400
1387
|
}
|
|
1401
1388
|
/**
|
|
1389
|
+
* @param address - The contract that will consume the resulting hashes+signature (i.e. the
|
|
1390
|
+
* contract that will call `FHE.asEuint*`/`FHE.asEuint*s` with them).
|
|
1391
|
+
*
|
|
1392
|
+
* Required before `execute()` - the verifier binds this address into the signed digest, so a
|
|
1393
|
+
* batch signed for one contract cannot be replayed into another.
|
|
1394
|
+
*
|
|
1402
1395
|
* Example:
|
|
1403
1396
|
* ```typescript
|
|
1404
1397
|
* const encrypted = await encryptInputs([Encryptable.uint128(10n)])
|
|
1405
|
-
* .
|
|
1398
|
+
* .setConsumingContract("0x123...890")
|
|
1406
1399
|
* .execute();
|
|
1407
1400
|
* ```
|
|
1408
1401
|
*
|
|
1409
|
-
* @returns
|
|
1402
|
+
* @returns The chainable EncryptInputsBuilder instance.
|
|
1410
1403
|
*/
|
|
1411
|
-
|
|
1412
|
-
this.
|
|
1404
|
+
setConsumingContract(address) {
|
|
1405
|
+
this.consumingContract = address;
|
|
1413
1406
|
return this;
|
|
1414
1407
|
}
|
|
1408
|
+
getConsumingContract() {
|
|
1409
|
+
return this.consumingContract;
|
|
1410
|
+
}
|
|
1415
1411
|
/**
|
|
1416
|
-
*
|
|
1417
|
-
*
|
|
1418
|
-
* Overrides the config-level useWorkers setting for this specific encryption.
|
|
1419
|
-
*
|
|
1420
|
-
* Example:
|
|
1421
|
-
* ```typescript
|
|
1422
|
-
* const encrypted = await encryptInputs([Encryptable.uint128(10n)])
|
|
1423
|
-
* .setUseWorker(false)
|
|
1424
|
-
* .execute();
|
|
1425
|
-
* ```
|
|
1426
|
-
*
|
|
1427
|
-
* @returns The chainable EncryptInputsBuilder instance.
|
|
1412
|
+
* Asserts that this.consumingContract is populated
|
|
1413
|
+
* @throws {CofheError} If consumingContract is not set
|
|
1428
1414
|
*/
|
|
1415
|
+
assertConsumingContract() {
|
|
1416
|
+
if (this.consumingContract)
|
|
1417
|
+
return;
|
|
1418
|
+
throw new CofheError({
|
|
1419
|
+
code: "CONSUMING_CONTRACT_UNINITIALIZED" /* ConsumingContractUninitialized */,
|
|
1420
|
+
message: "Consuming contract is not set",
|
|
1421
|
+
hint: "Use setConsumingContract(...) to set the contract that will consume the encrypted inputs.",
|
|
1422
|
+
context: {
|
|
1423
|
+
consumingContract: this.consumingContract
|
|
1424
|
+
}
|
|
1425
|
+
});
|
|
1426
|
+
}
|
|
1429
1427
|
setUseWorker(useWorker) {
|
|
1430
1428
|
this.useWorker = useWorker;
|
|
1431
1429
|
return this;
|
|
@@ -1446,21 +1444,6 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1446
1444
|
getUseWorker() {
|
|
1447
1445
|
return this.useWorker;
|
|
1448
1446
|
}
|
|
1449
|
-
/**
|
|
1450
|
-
* @param callback - Function to be called with the encryption step.
|
|
1451
|
-
*
|
|
1452
|
-
* Useful for debugging and tracking the progress of the encryption process.
|
|
1453
|
-
* Useful for a UI element that shows the progress of the encryption process.
|
|
1454
|
-
*
|
|
1455
|
-
* Example:
|
|
1456
|
-
* ```typescript
|
|
1457
|
-
* const encrypted = await encryptInputs([Encryptable.uint128(10n)])
|
|
1458
|
-
* .onStep((step: EncryptStep) => console.log(step))
|
|
1459
|
-
* .execute();
|
|
1460
|
-
* ```
|
|
1461
|
-
*
|
|
1462
|
-
* @returns The EncryptInputsBuilder instance.
|
|
1463
|
-
*/
|
|
1464
1447
|
onStep(callback) {
|
|
1465
1448
|
this.stepCallback = callback;
|
|
1466
1449
|
return this;
|
|
@@ -1599,6 +1582,7 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1599
1582
|
this.assertAccount();
|
|
1600
1583
|
this.assertPublicClient();
|
|
1601
1584
|
this.assertWalletClient();
|
|
1585
|
+
this.assertConsumingContract();
|
|
1602
1586
|
const [initTfheDelay, fetchKeysDelay, packDelay, proveDelay, verifyDelay] = this.resolveEncryptDelays();
|
|
1603
1587
|
this.fireStepStart("initTfhe" /* InitTfhe */);
|
|
1604
1588
|
await sleep(initTfheDelay);
|
|
@@ -1624,22 +1608,17 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1624
1608
|
this.fireStepEnd("prove" /* Prove */, { isMocks: true, mockSleep: proveDelay });
|
|
1625
1609
|
this.fireStepStart("verify" /* Verify */);
|
|
1626
1610
|
await sleep(verifyDelay);
|
|
1627
|
-
const
|
|
1611
|
+
const result = await cofheMocksZkVerifySign(
|
|
1628
1612
|
this.inputItems,
|
|
1629
1613
|
this.account,
|
|
1630
1614
|
this.securityZone,
|
|
1615
|
+
this.consumingContract,
|
|
1631
1616
|
this.publicClient,
|
|
1632
1617
|
this.walletClient,
|
|
1633
1618
|
this.zkvWalletClient
|
|
1634
1619
|
);
|
|
1635
|
-
const encryptedInputs = signedResults.map(({ ct_hash, signature }, index) => ({
|
|
1636
|
-
ctHash: BigInt(ct_hash),
|
|
1637
|
-
securityZone: this.securityZone,
|
|
1638
|
-
utype: this.inputItems[index].utype,
|
|
1639
|
-
signature
|
|
1640
|
-
}));
|
|
1641
1620
|
this.fireStepEnd("verify" /* Verify */, { isMocks: true, mockSleep: verifyDelay });
|
|
1642
|
-
return
|
|
1621
|
+
return result;
|
|
1643
1622
|
}
|
|
1644
1623
|
/**
|
|
1645
1624
|
* In the production context, perform a true encryption with the CoFHE coprocessor.
|
|
@@ -1647,6 +1626,7 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1647
1626
|
async productionExecute() {
|
|
1648
1627
|
this.assertAccount();
|
|
1649
1628
|
this.assertChainId();
|
|
1629
|
+
this.assertConsumingContract();
|
|
1650
1630
|
this.fireStepStart("initTfhe" /* InitTfhe */);
|
|
1651
1631
|
const tfheInitializationExecuted = await this.initTfheOrThrow();
|
|
1652
1632
|
this.fireStepEnd("initTfhe" /* InitTfhe */, { tfheInitializationExecuted });
|
|
@@ -1681,26 +1661,24 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1681
1661
|
});
|
|
1682
1662
|
this.fireStepStart("verify" /* Verify */);
|
|
1683
1663
|
const zkVerifierUrl = await this.getZkVerifierUrl();
|
|
1684
|
-
const
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
})
|
|
1664
|
+
const result = await zkVerifyBatch(
|
|
1665
|
+
zkVerifierUrl,
|
|
1666
|
+
proof,
|
|
1667
|
+
this.account,
|
|
1668
|
+
this.securityZone,
|
|
1669
|
+
this.chainId,
|
|
1670
|
+
this.consumingContract
|
|
1692
1671
|
);
|
|
1693
1672
|
this.fireStepEnd("verify" /* Verify */);
|
|
1694
|
-
return
|
|
1695
|
-
}
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
return [...hashes, proof];
|
|
1673
|
+
return result;
|
|
1674
|
+
}
|
|
1675
|
+
/**
|
|
1676
|
+
* Converts a batch-verified result (per-item ctHash/ctType + one shared signature) into the
|
|
1677
|
+
* tuple returned by `execute()`: per-item hashes in input order, followed by the single signature.
|
|
1678
|
+
*/
|
|
1679
|
+
buildBatchResult(result) {
|
|
1680
|
+
const hashes = result.outputs.map((output) => "0x" + BigInt(output.ct_hash).toString(16).padStart(64, "0"));
|
|
1681
|
+
return [...hashes, result.signature];
|
|
1704
1682
|
}
|
|
1705
1683
|
/**
|
|
1706
1684
|
* Final step of the encryption process. MUST BE CALLED LAST IN THE CHAIN.
|
|
@@ -1722,18 +1700,16 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1722
1700
|
* @returns The encrypted inputs.
|
|
1723
1701
|
*/
|
|
1724
1702
|
async execute() {
|
|
1725
|
-
let
|
|
1703
|
+
let result;
|
|
1726
1704
|
if (this.chainId === chains.hardhat.id)
|
|
1727
|
-
|
|
1705
|
+
result = await this.mocksExecute();
|
|
1728
1706
|
else
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
return this.structsToHashPlusProof(items);
|
|
1732
|
-
return items;
|
|
1707
|
+
result = await this.productionExecute();
|
|
1708
|
+
return this.buildBatchResult(result);
|
|
1733
1709
|
}
|
|
1734
1710
|
};
|
|
1735
1711
|
|
|
1736
|
-
//
|
|
1712
|
+
// acps/utils.ts
|
|
1737
1713
|
var fromHexString = (hexString) => {
|
|
1738
1714
|
const cleanString = hexString.length % 2 === 1 ? `0${hexString}` : hexString;
|
|
1739
1715
|
const arr = cleanString.replace(/^0x/, "").match(/.{1,2}/g);
|
|
@@ -1753,120 +1729,33 @@ function toBigInt(value) {
|
|
|
1753
1729
|
return value;
|
|
1754
1730
|
}
|
|
1755
1731
|
}
|
|
1756
|
-
function toBeArray(value) {
|
|
1757
|
-
const bigIntValue = typeof value === "number" ? BigInt(value) : value;
|
|
1758
|
-
const hex = bigIntValue.toString(16);
|
|
1759
|
-
const paddedHex = hex.length % 2 === 0 ? hex : "0" + hex;
|
|
1760
|
-
return fromHexString(paddedHex);
|
|
1761
|
-
}
|
|
1762
|
-
function isString(value) {
|
|
1763
|
-
if (typeof value !== "string") {
|
|
1764
|
-
throw new Error(`Expected value which is \`string\`, received value of type \`${typeof value}\`.`);
|
|
1765
|
-
}
|
|
1766
|
-
}
|
|
1767
|
-
function isNumber(value) {
|
|
1768
|
-
const is = typeof value === "number" && !Number.isNaN(value);
|
|
1769
|
-
if (!is) {
|
|
1770
|
-
throw new Error(`Expected value which is \`number\`, received value of type \`${typeof value}\`.`);
|
|
1771
|
-
}
|
|
1772
|
-
}
|
|
1773
|
-
function isBigIntOrNumber(value) {
|
|
1774
|
-
const is = typeof value === "bigint";
|
|
1775
|
-
if (!is) {
|
|
1776
|
-
try {
|
|
1777
|
-
isNumber(value);
|
|
1778
|
-
} catch (e) {
|
|
1779
|
-
throw new Error(`Value ${value} is not a number or bigint: ${typeof value}`);
|
|
1780
|
-
}
|
|
1781
|
-
}
|
|
1782
|
-
}
|
|
1783
1732
|
|
|
1784
|
-
//
|
|
1785
|
-
var
|
|
1786
|
-
var PUBLIC_KEY_LENGTH = 64;
|
|
1787
|
-
var SealingKey = class _SealingKey {
|
|
1788
|
-
/**
|
|
1789
|
-
* The private key used for decryption.
|
|
1790
|
-
*/
|
|
1791
|
-
privateKey;
|
|
1792
|
-
/**
|
|
1793
|
-
* The public key used for encryption.
|
|
1794
|
-
*/
|
|
1795
|
-
publicKey;
|
|
1796
|
-
/**
|
|
1797
|
-
* Constructs a SealingKey instance with the given private and public keys.
|
|
1798
|
-
*
|
|
1799
|
-
* @param {string} privateKey - The private key used for decryption.
|
|
1800
|
-
* @param {string} publicKey - The public key used for encryption.
|
|
1801
|
-
* @throws Will throw an error if the provided keys lengths do not match
|
|
1802
|
-
* the required lengths for private and public keys.
|
|
1803
|
-
*/
|
|
1804
|
-
constructor(privateKey, publicKey) {
|
|
1805
|
-
if (privateKey.length !== PRIVATE_KEY_LENGTH) {
|
|
1806
|
-
throw new Error(`Private key must be of length ${PRIVATE_KEY_LENGTH}`);
|
|
1807
|
-
}
|
|
1808
|
-
if (publicKey.length !== PUBLIC_KEY_LENGTH) {
|
|
1809
|
-
throw new Error(`Public key must be of length ${PUBLIC_KEY_LENGTH}`);
|
|
1810
|
-
}
|
|
1811
|
-
this.privateKey = privateKey;
|
|
1812
|
-
this.publicKey = publicKey;
|
|
1813
|
-
}
|
|
1814
|
-
unseal = (parsedData) => {
|
|
1815
|
-
const nonce = parsedData.nonce instanceof Uint8Array ? parsedData.nonce : new Uint8Array(parsedData.nonce);
|
|
1816
|
-
const ephemPublicKey = parsedData.public_key instanceof Uint8Array ? parsedData.public_key : new Uint8Array(parsedData.public_key);
|
|
1817
|
-
const dataToDecrypt = parsedData.data instanceof Uint8Array ? parsedData.data : new Uint8Array(parsedData.data);
|
|
1818
|
-
const privateKeyBytes = fromHexString(this.privateKey);
|
|
1819
|
-
const decryptedMessage = nacl__default.default.box.open(dataToDecrypt, nonce, ephemPublicKey, privateKeyBytes);
|
|
1820
|
-
if (!decryptedMessage) {
|
|
1821
|
-
throw new Error("Failed to decrypt message");
|
|
1822
|
-
}
|
|
1823
|
-
return toBigInt(decryptedMessage);
|
|
1824
|
-
};
|
|
1825
|
-
/**
|
|
1826
|
-
* Serializes the SealingKey to a JSON object.
|
|
1827
|
-
*/
|
|
1828
|
-
serialize = () => {
|
|
1829
|
-
return {
|
|
1830
|
-
privateKey: this.privateKey,
|
|
1831
|
-
publicKey: this.publicKey
|
|
1832
|
-
};
|
|
1833
|
-
};
|
|
1834
|
-
/**
|
|
1835
|
-
* Deserializes the SealingKey from a JSON object.
|
|
1836
|
-
*/
|
|
1837
|
-
static deserialize = (privateKey, publicKey) => {
|
|
1838
|
-
return new _SealingKey(privateKey, publicKey);
|
|
1839
|
-
};
|
|
1840
|
-
/**
|
|
1841
|
-
* Seals (encrypts) the provided message for a receiver with the specified public key.
|
|
1842
|
-
*
|
|
1843
|
-
* @param {bigint | number} value - The message to be encrypted.
|
|
1844
|
-
* @param {string} publicKey - The public key of the intended recipient.
|
|
1845
|
-
* @returns string - The encrypted message in hexadecimal format.
|
|
1846
|
-
* @static
|
|
1847
|
-
* @throws Will throw if the provided publicKey or value do not meet defined preconditions.
|
|
1848
|
-
*/
|
|
1849
|
-
static seal = (value, publicKey) => {
|
|
1850
|
-
isString(publicKey);
|
|
1851
|
-
isBigIntOrNumber(value);
|
|
1852
|
-
const ephemeralKeyPair = nacl__default.default.box.keyPair();
|
|
1853
|
-
const nonce = nacl__default.default.randomBytes(nacl__default.default.box.nonceLength);
|
|
1854
|
-
const encryptedMessage = nacl__default.default.box(toBeArray(value), nonce, fromHexString(publicKey), ephemeralKeyPair.secretKey);
|
|
1855
|
-
return {
|
|
1856
|
-
data: encryptedMessage,
|
|
1857
|
-
public_key: ephemeralKeyPair.publicKey,
|
|
1858
|
-
nonce
|
|
1859
|
-
};
|
|
1860
|
-
};
|
|
1861
|
-
};
|
|
1733
|
+
// acps/sealing.ts
|
|
1734
|
+
var KEY_HEX_LENGTH = 64;
|
|
1862
1735
|
var GenerateSealingKey = () => {
|
|
1863
1736
|
const sodiumKeypair = nacl__default.default.box.keyPair();
|
|
1864
|
-
return
|
|
1737
|
+
return {
|
|
1738
|
+
privateKey: `0x${toHexString2(sodiumKeypair.secretKey)}`,
|
|
1739
|
+
publicKey: `0x${toHexString2(sodiumKeypair.publicKey)}`
|
|
1740
|
+
};
|
|
1741
|
+
};
|
|
1742
|
+
var unsealWithPrivateKey = (privateKey, parsedData) => {
|
|
1743
|
+
assertKeyLength(privateKey, "Private");
|
|
1744
|
+
const nonce = parsedData.nonce instanceof Uint8Array ? parsedData.nonce : new Uint8Array(parsedData.nonce);
|
|
1745
|
+
const ephemPublicKey = parsedData.public_key instanceof Uint8Array ? parsedData.public_key : new Uint8Array(parsedData.public_key);
|
|
1746
|
+
const dataToDecrypt = parsedData.data instanceof Uint8Array ? parsedData.data : new Uint8Array(parsedData.data);
|
|
1747
|
+
const decryptedMessage = nacl__default.default.box.open(dataToDecrypt, nonce, ephemPublicKey, fromHexString(privateKey));
|
|
1748
|
+
if (!decryptedMessage) {
|
|
1749
|
+
throw new Error("Failed to decrypt message");
|
|
1750
|
+
}
|
|
1751
|
+
return toBigInt(decryptedMessage);
|
|
1752
|
+
};
|
|
1753
|
+
var assertKeyLength = (key, kind) => {
|
|
1754
|
+
const bare = key.startsWith("0x") ? key.slice(2) : key;
|
|
1755
|
+
if (bare.length !== KEY_HEX_LENGTH) {
|
|
1756
|
+
throw new Error(`${kind} key must be of length ${KEY_HEX_LENGTH}`);
|
|
1757
|
+
}
|
|
1865
1758
|
};
|
|
1866
|
-
var SerializedSealingPair = zod.z.object({
|
|
1867
|
-
privateKey: zod.z.string(),
|
|
1868
|
-
publicKey: zod.z.string()
|
|
1869
|
-
});
|
|
1870
1759
|
var addressSchema = zod.z.string().refine((val) => viem.isAddress(val), {
|
|
1871
1760
|
error: "Invalid address"
|
|
1872
1761
|
}).transform((val) => viem.getAddress(val));
|
|
@@ -1885,46 +1774,70 @@ var bytesNotEmptySchema = bytesSchema.refine((val) => val !== "0x", {
|
|
|
1885
1774
|
error: "Must not be empty"
|
|
1886
1775
|
});
|
|
1887
1776
|
var DEFAULT_EXPIRATION_FN = () => Math.round(Date.now() / 1e3) + 7 * 24 * 60 * 60;
|
|
1888
|
-
var
|
|
1889
|
-
|
|
1777
|
+
var handlesSchema = zod.z.array(zod.z.string().regex(/^0x[0-9a-fA-F]{64}$/, "Invalid handle: expected 32-byte hex")).optional().default([]);
|
|
1778
|
+
var contractsSchema = zod.z.array(addressSchema).optional().default([]);
|
|
1779
|
+
var SCOPE_GLOBAL = 0;
|
|
1780
|
+
var SCOPE_CONTRACT = 1;
|
|
1781
|
+
var SCOPE_HANDLES = 2;
|
|
1782
|
+
var ScopeConsistencyRefinement = [
|
|
1783
|
+
(data) => data.scope === SCOPE_GLOBAL && data.contracts.length === 0 && data.handles.length === 0 || data.scope === SCOPE_CONTRACT && data.contracts.length > 0 && data.handles.length === 0 || data.scope === SCOPE_HANDLES && data.handles.length > 0 && data.contracts.length === 0,
|
|
1784
|
+
{
|
|
1785
|
+
error: "ACP scope :: arrays must match the scope mode (Global: both empty; Contract: contracts only; Handles: handles only)",
|
|
1786
|
+
path: ["scope"]
|
|
1787
|
+
}
|
|
1788
|
+
];
|
|
1789
|
+
var withDerivedScope = (data) => ({
|
|
1790
|
+
...data,
|
|
1791
|
+
scope: data.scope ?? (data.contracts.length > 0 ? SCOPE_CONTRACT : data.handles.length > 0 ? SCOPE_HANDLES : SCOPE_GLOBAL)
|
|
1792
|
+
});
|
|
1793
|
+
var zACPWithDefaults = zod.z.object({
|
|
1794
|
+
name: zod.z.string().optional().default("Unnamed ACP"),
|
|
1890
1795
|
type: zod.z.enum(["self", "sharing", "recipient"]),
|
|
1891
1796
|
issuer: addressNotZeroSchema,
|
|
1892
1797
|
expiration: zod.z.int().optional().default(DEFAULT_EXPIRATION_FN),
|
|
1893
1798
|
recipient: addressSchema.optional().default(viem.zeroAddress),
|
|
1894
|
-
|
|
1895
|
-
|
|
1799
|
+
revokerData: zod.z.int().optional().default(0),
|
|
1800
|
+
revokerContract: addressSchema.optional().default(viem.zeroAddress),
|
|
1801
|
+
scope: zod.z.int().min(0).max(2).optional().default(0),
|
|
1802
|
+
contracts: contractsSchema,
|
|
1803
|
+
handles: handlesSchema,
|
|
1896
1804
|
issuerSignature: bytesSchema.optional().default("0x"),
|
|
1897
1805
|
recipientSignature: bytesSchema.optional().default("0x")
|
|
1898
1806
|
});
|
|
1899
|
-
var
|
|
1900
|
-
|
|
1807
|
+
var zACPWithSealingKeys = zACPWithDefaults.extend({
|
|
1808
|
+
/** X25519 private key, 0x-prefixed 32-byte hex; never leaves the client */
|
|
1809
|
+
sealingPrivateKey: zod.z.string().regex(/^0x[0-9a-fA-F]{64}$/, "Invalid sealing private key").optional(),
|
|
1810
|
+
sealingKey: zod.z.string().regex(/^0x[0-9a-fA-F]{64}$/, "Invalid sealing key").optional()
|
|
1901
1811
|
});
|
|
1902
1812
|
var ExternalValidatorRefinement = [
|
|
1903
|
-
(data) => data.
|
|
1813
|
+
(data) => data.revokerData !== 0 && data.revokerContract !== viem.zeroAddress || data.revokerData === 0 && data.revokerContract === viem.zeroAddress,
|
|
1904
1814
|
{
|
|
1905
|
-
error: "
|
|
1906
|
-
path: ["
|
|
1815
|
+
error: "ACP external revoker :: revokerData and revokerContract must either both be set or both be unset.",
|
|
1816
|
+
path: ["revokerData", "revokerContract"]
|
|
1907
1817
|
}
|
|
1908
1818
|
];
|
|
1909
1819
|
var RecipientRefinement = [
|
|
1910
1820
|
(data) => data.issuer !== data.recipient,
|
|
1911
1821
|
{
|
|
1912
|
-
error: "Sharing
|
|
1822
|
+
error: "Sharing acp :: issuer and recipient must not be the same",
|
|
1913
1823
|
path: ["issuer", "recipient"]
|
|
1914
1824
|
}
|
|
1915
1825
|
];
|
|
1916
|
-
var
|
|
1826
|
+
var SelfACPOptionsValidator = zod.z.object({
|
|
1917
1827
|
type: zod.z.literal("self").optional().default("self"),
|
|
1918
1828
|
issuer: addressNotZeroSchema,
|
|
1919
|
-
name: zod.z.string().optional().default("Unnamed
|
|
1829
|
+
name: zod.z.string().optional().default("Unnamed ACP"),
|
|
1920
1830
|
expiration: zod.z.int().optional().default(DEFAULT_EXPIRATION_FN),
|
|
1921
1831
|
recipient: addressSchema.optional().default(viem.zeroAddress),
|
|
1922
|
-
|
|
1923
|
-
|
|
1832
|
+
revokerData: zod.z.int().optional().default(0),
|
|
1833
|
+
revokerContract: addressSchema.optional().default(viem.zeroAddress),
|
|
1834
|
+
scope: zod.z.int().min(0).max(2).optional(),
|
|
1835
|
+
contracts: contractsSchema,
|
|
1836
|
+
handles: handlesSchema,
|
|
1924
1837
|
issuerSignature: bytesSchema.optional().default("0x"),
|
|
1925
1838
|
recipientSignature: bytesSchema.optional().default("0x")
|
|
1926
|
-
}).refine(...ExternalValidatorRefinement);
|
|
1927
|
-
var
|
|
1839
|
+
}).refine(...ExternalValidatorRefinement).transform(withDerivedScope).refine(...ScopeConsistencyRefinement);
|
|
1840
|
+
var SelfACPValidator = zACPWithSealingKeys.refine((data) => data.type === "self", {
|
|
1928
1841
|
error: "Type must be 'self'"
|
|
1929
1842
|
}).refine((data) => data.recipient === viem.zeroAddress, {
|
|
1930
1843
|
error: "Recipient must be zeroAddress"
|
|
@@ -1933,18 +1846,21 @@ var SelfPermitValidator = zPermitWithSealingPair.refine((data) => data.type ===
|
|
|
1933
1846
|
}).refine((data) => data.recipientSignature === "0x", {
|
|
1934
1847
|
error: "RecipientSignature must be empty"
|
|
1935
1848
|
}).refine(...ExternalValidatorRefinement);
|
|
1936
|
-
var
|
|
1849
|
+
var SharingACPOptionsValidator = zod.z.object({
|
|
1937
1850
|
type: zod.z.literal("sharing").optional().default("sharing"),
|
|
1938
1851
|
issuer: addressNotZeroSchema,
|
|
1939
1852
|
recipient: addressNotZeroSchema,
|
|
1940
|
-
name: zod.z.string().optional().default("Unnamed
|
|
1853
|
+
name: zod.z.string().optional().default("Unnamed ACP"),
|
|
1941
1854
|
expiration: zod.z.int().optional().default(DEFAULT_EXPIRATION_FN),
|
|
1942
|
-
|
|
1943
|
-
|
|
1855
|
+
revokerData: zod.z.int().optional().default(0),
|
|
1856
|
+
revokerContract: addressSchema.optional().default(viem.zeroAddress),
|
|
1857
|
+
scope: zod.z.int().min(0).max(2).optional(),
|
|
1858
|
+
contracts: contractsSchema,
|
|
1859
|
+
handles: handlesSchema,
|
|
1944
1860
|
issuerSignature: bytesSchema.optional().default("0x"),
|
|
1945
1861
|
recipientSignature: bytesSchema.optional().default("0x")
|
|
1946
|
-
}).refine(...RecipientRefinement).refine(...ExternalValidatorRefinement);
|
|
1947
|
-
var
|
|
1862
|
+
}).refine(...RecipientRefinement).refine(...ExternalValidatorRefinement).transform(withDerivedScope).refine(...ScopeConsistencyRefinement);
|
|
1863
|
+
var SharingACPValidator = zACPWithSealingKeys.refine((data) => data.type === "sharing", {
|
|
1948
1864
|
error: "Type must be 'sharing'"
|
|
1949
1865
|
}).refine((data) => data.recipient !== viem.zeroAddress, {
|
|
1950
1866
|
error: "Recipient must not be zeroAddress"
|
|
@@ -1953,18 +1869,21 @@ var SharingPermitValidator = zPermitWithSealingPair.refine((data) => data.type =
|
|
|
1953
1869
|
}).refine((data) => data.recipientSignature === "0x", {
|
|
1954
1870
|
error: "RecipientSignature must be empty"
|
|
1955
1871
|
}).refine(...ExternalValidatorRefinement);
|
|
1956
|
-
var
|
|
1872
|
+
var ImportACPOptionsValidator = zod.z.object({
|
|
1957
1873
|
type: zod.z.literal("recipient").optional().default("recipient"),
|
|
1958
1874
|
issuer: addressNotZeroSchema,
|
|
1959
1875
|
recipient: addressNotZeroSchema,
|
|
1960
|
-
name: zod.z.string().optional().default("Unnamed
|
|
1876
|
+
name: zod.z.string().optional().default("Unnamed ACP"),
|
|
1961
1877
|
expiration: zod.z.int(),
|
|
1962
|
-
|
|
1963
|
-
|
|
1878
|
+
revokerData: zod.z.int().optional().default(0),
|
|
1879
|
+
revokerContract: addressSchema.optional().default(viem.zeroAddress),
|
|
1880
|
+
scope: zod.z.int().min(0).max(2).optional(),
|
|
1881
|
+
contracts: contractsSchema,
|
|
1882
|
+
handles: handlesSchema,
|
|
1964
1883
|
issuerSignature: bytesNotEmptySchema,
|
|
1965
1884
|
recipientSignature: bytesSchema.optional().default("0x")
|
|
1966
|
-
}).refine(...ExternalValidatorRefinement);
|
|
1967
|
-
var
|
|
1885
|
+
}).refine(...ExternalValidatorRefinement).transform(withDerivedScope).refine(...ScopeConsistencyRefinement);
|
|
1886
|
+
var ImportACPValidator = zACPWithSealingKeys.refine((data) => data.type === "recipient", {
|
|
1968
1887
|
error: "Type must be 'recipient'"
|
|
1969
1888
|
}).refine((data) => data.recipient !== viem.zeroAddress, {
|
|
1970
1889
|
error: "Recipient must not be zeroAddress"
|
|
@@ -1980,116 +1899,125 @@ var safeParseAndThrowFormatted = (schema, data, message) => {
|
|
|
1980
1899
|
}
|
|
1981
1900
|
return result.data;
|
|
1982
1901
|
};
|
|
1983
|
-
var
|
|
1984
|
-
return safeParseAndThrowFormatted(
|
|
1902
|
+
var validateSelfACPOptions = (options) => {
|
|
1903
|
+
return safeParseAndThrowFormatted(SelfACPOptionsValidator, options, "Invalid self acp options");
|
|
1985
1904
|
};
|
|
1986
|
-
var
|
|
1987
|
-
return safeParseAndThrowFormatted(
|
|
1905
|
+
var validateSharingACPOptions = (options) => {
|
|
1906
|
+
return safeParseAndThrowFormatted(SharingACPOptionsValidator, options, "Invalid sharing acp options");
|
|
1988
1907
|
};
|
|
1989
|
-
var
|
|
1990
|
-
return safeParseAndThrowFormatted(
|
|
1908
|
+
var validateImportACPOptions = (options) => {
|
|
1909
|
+
return safeParseAndThrowFormatted(ImportACPOptionsValidator, options, "Invalid import acp options");
|
|
1991
1910
|
};
|
|
1992
|
-
var
|
|
1993
|
-
return safeParseAndThrowFormatted(
|
|
1911
|
+
var validateSelfACP = (acp) => {
|
|
1912
|
+
return safeParseAndThrowFormatted(SelfACPValidator, acp, "Invalid self acp");
|
|
1994
1913
|
};
|
|
1995
|
-
var
|
|
1996
|
-
return safeParseAndThrowFormatted(
|
|
1914
|
+
var validateSharingACP = (acp) => {
|
|
1915
|
+
return safeParseAndThrowFormatted(SharingACPValidator, acp, "Invalid sharing acp");
|
|
1997
1916
|
};
|
|
1998
|
-
var
|
|
1999
|
-
return safeParseAndThrowFormatted(
|
|
1917
|
+
var validateImportACP = (acp) => {
|
|
1918
|
+
return safeParseAndThrowFormatted(ImportACPValidator, acp, "Invalid import acp");
|
|
2000
1919
|
};
|
|
2001
1920
|
var ValidationUtils = {
|
|
2002
1921
|
/**
|
|
2003
|
-
* Check if
|
|
1922
|
+
* Check if acp is expired
|
|
2004
1923
|
*/
|
|
2005
|
-
isExpired: (
|
|
2006
|
-
return
|
|
1924
|
+
isExpired: (acp) => {
|
|
1925
|
+
return acp.expiration < Math.floor(Date.now() / 1e3);
|
|
2007
1926
|
},
|
|
2008
1927
|
/**
|
|
2009
|
-
* Check if
|
|
1928
|
+
* Check if acp is signed by the active party
|
|
2010
1929
|
*/
|
|
2011
|
-
isSigned: (
|
|
2012
|
-
if (
|
|
2013
|
-
return
|
|
1930
|
+
isSigned: (acp) => {
|
|
1931
|
+
if (acp.type === "self" || acp.type === "sharing") {
|
|
1932
|
+
return acp.issuerSignature !== "0x";
|
|
2014
1933
|
}
|
|
2015
|
-
if (
|
|
2016
|
-
return
|
|
1934
|
+
if (acp.type === "recipient") {
|
|
1935
|
+
return acp.recipientSignature !== "0x";
|
|
2017
1936
|
}
|
|
2018
1937
|
return false;
|
|
2019
1938
|
},
|
|
2020
1939
|
/**
|
|
2021
|
-
* Checks that
|
|
1940
|
+
* Checks that an ACP is signed and not expired.
|
|
2022
1941
|
*/
|
|
2023
|
-
isSignedAndNotExpired: (
|
|
2024
|
-
if (ValidationUtils.isExpired(
|
|
1942
|
+
isSignedAndNotExpired: (acp) => {
|
|
1943
|
+
if (ValidationUtils.isExpired(acp)) {
|
|
2025
1944
|
return { valid: false, error: "expired" };
|
|
2026
1945
|
}
|
|
2027
|
-
if (!ValidationUtils.isSigned(
|
|
1946
|
+
if (!ValidationUtils.isSigned(acp)) {
|
|
2028
1947
|
return { valid: false, error: "not-signed" };
|
|
2029
1948
|
}
|
|
2030
1949
|
return { valid: true, error: null };
|
|
2031
1950
|
},
|
|
2032
1951
|
/**
|
|
2033
|
-
* Asserts that
|
|
1952
|
+
* Asserts that an ACP is signed and not expired.
|
|
2034
1953
|
*
|
|
2035
1954
|
* Throws `Error` with message:
|
|
2036
|
-
* - `
|
|
2037
|
-
* - `
|
|
1955
|
+
* - `ACP is expired`
|
|
1956
|
+
* - `ACP is not signed`
|
|
2038
1957
|
*/
|
|
2039
|
-
assertSignedAndNotExpired: (
|
|
2040
|
-
const result = ValidationUtils.isSignedAndNotExpired(
|
|
1958
|
+
assertSignedAndNotExpired: (acp) => {
|
|
1959
|
+
const result = ValidationUtils.isSignedAndNotExpired(acp);
|
|
2041
1960
|
if (result.valid)
|
|
2042
1961
|
return;
|
|
2043
1962
|
if (result.error === "expired") {
|
|
2044
|
-
throw new Error("
|
|
1963
|
+
throw new Error("ACP is expired");
|
|
2045
1964
|
}
|
|
2046
1965
|
if (result.error === "not-signed") {
|
|
2047
|
-
throw new Error("
|
|
1966
|
+
throw new Error("ACP is not signed");
|
|
2048
1967
|
}
|
|
2049
|
-
throw new Error("
|
|
1968
|
+
throw new Error("ACP is invalid");
|
|
2050
1969
|
},
|
|
2051
|
-
isValid: (
|
|
2052
|
-
const schema =
|
|
1970
|
+
isValid: (acp) => {
|
|
1971
|
+
const schema = acp.type === "self" ? SelfACPValidator : acp.type === "sharing" ? SharingACPValidator : acp.type === "recipient" ? ImportACPValidator : null;
|
|
2053
1972
|
if (schema == null)
|
|
2054
1973
|
return { valid: false, error: "invalid-schema" };
|
|
2055
|
-
const schemaResult = schema.safeParse(
|
|
1974
|
+
const schemaResult = schema.safeParse(acp);
|
|
2056
1975
|
if (!schemaResult.success)
|
|
2057
1976
|
return { valid: false, error: "invalid-schema" };
|
|
2058
|
-
return ValidationUtils.isSignedAndNotExpired(
|
|
1977
|
+
return ValidationUtils.isSignedAndNotExpired(acp);
|
|
2059
1978
|
}
|
|
2060
1979
|
};
|
|
2061
1980
|
|
|
2062
|
-
//
|
|
2063
|
-
var
|
|
1981
|
+
// acps/signature.ts
|
|
1982
|
+
var ACPSignatureAllFields = [
|
|
2064
1983
|
{ name: "issuer", type: "address" },
|
|
2065
1984
|
{ name: "expiration", type: "uint64" },
|
|
2066
1985
|
{ name: "recipient", type: "address" },
|
|
2067
|
-
{ name: "
|
|
2068
|
-
{ name: "
|
|
1986
|
+
{ name: "revokerData", type: "uint256" },
|
|
1987
|
+
{ name: "revokerContract", type: "address" },
|
|
1988
|
+
{ name: "scope", type: "uint8" },
|
|
1989
|
+
{ name: "contracts", type: "address[]" },
|
|
1990
|
+
{ name: "handles", type: "bytes32[]" },
|
|
2069
1991
|
{ name: "sealingKey", type: "bytes32" },
|
|
2070
1992
|
{ name: "issuerSignature", type: "bytes" }
|
|
2071
1993
|
];
|
|
2072
1994
|
var SignatureTypes = {
|
|
2073
|
-
|
|
1995
|
+
ACPIssuerSelf: [
|
|
2074
1996
|
"issuer",
|
|
2075
1997
|
"expiration",
|
|
2076
1998
|
"recipient",
|
|
2077
|
-
"
|
|
2078
|
-
"
|
|
1999
|
+
"revokerData",
|
|
2000
|
+
"revokerContract",
|
|
2001
|
+
"scope",
|
|
2002
|
+
"contracts",
|
|
2003
|
+
"handles",
|
|
2079
2004
|
"sealingKey"
|
|
2080
2005
|
],
|
|
2081
|
-
|
|
2006
|
+
ACPIssuerShared: [
|
|
2082
2007
|
"issuer",
|
|
2083
2008
|
"expiration",
|
|
2084
2009
|
"recipient",
|
|
2085
|
-
"
|
|
2086
|
-
"
|
|
2010
|
+
"revokerData",
|
|
2011
|
+
"revokerContract",
|
|
2012
|
+
"scope",
|
|
2013
|
+
"contracts",
|
|
2014
|
+
"handles"
|
|
2087
2015
|
],
|
|
2088
|
-
|
|
2016
|
+
ACPRecipient: ["sealingKey", "issuerSignature"]
|
|
2089
2017
|
};
|
|
2090
2018
|
var getSignatureTypesAndMessage = (primaryType, fields, values) => {
|
|
2091
2019
|
const types = {
|
|
2092
|
-
[primaryType]:
|
|
2020
|
+
[primaryType]: ACPSignatureAllFields.filter((fieldType) => fields.includes(fieldType.name))
|
|
2093
2021
|
};
|
|
2094
2022
|
const message = {};
|
|
2095
2023
|
fields.forEach((field) => {
|
|
@@ -2101,22 +2029,22 @@ var getSignatureTypesAndMessage = (primaryType, fields, values) => {
|
|
|
2101
2029
|
};
|
|
2102
2030
|
var SignatureUtils = {
|
|
2103
2031
|
/**
|
|
2104
|
-
* Get signature parameters for
|
|
2032
|
+
* Get signature parameters for an ACP
|
|
2105
2033
|
*/
|
|
2106
|
-
getSignatureParams: (
|
|
2107
|
-
return getSignatureTypesAndMessage(primaryType, SignatureTypes[primaryType],
|
|
2034
|
+
getSignatureParams: (acp, primaryType) => {
|
|
2035
|
+
return getSignatureTypesAndMessage(primaryType, SignatureTypes[primaryType], acp);
|
|
2108
2036
|
},
|
|
2109
2037
|
/**
|
|
2110
|
-
* Determine the required signature type based on
|
|
2038
|
+
* Determine the required signature type based on acp type
|
|
2111
2039
|
*/
|
|
2112
|
-
getPrimaryType: (
|
|
2113
|
-
if (
|
|
2114
|
-
return "
|
|
2115
|
-
if (
|
|
2116
|
-
return "
|
|
2117
|
-
if (
|
|
2118
|
-
return "
|
|
2119
|
-
throw new Error(`Unknown
|
|
2040
|
+
getPrimaryType: (acpType) => {
|
|
2041
|
+
if (acpType === "self")
|
|
2042
|
+
return "ACPIssuerSelf";
|
|
2043
|
+
if (acpType === "sharing")
|
|
2044
|
+
return "ACPIssuerShared";
|
|
2045
|
+
if (acpType === "recipient")
|
|
2046
|
+
return "ACPRecipient";
|
|
2047
|
+
throw new Error(`Unknown acp type: ${acpType}`);
|
|
2120
2048
|
}
|
|
2121
2049
|
};
|
|
2122
2050
|
var getAclAddress = async (publicClient) => {
|
|
@@ -2138,6 +2066,11 @@ var getAclEIP712Domain = async (publicClient) => {
|
|
|
2138
2066
|
functionName: "eip712Domain"
|
|
2139
2067
|
});
|
|
2140
2068
|
const [_fields, name, version, chainId, verifyingContract, _salt, _extensions] = domain;
|
|
2069
|
+
if (version !== "2") {
|
|
2070
|
+
throw new Error(
|
|
2071
|
+
`Chain ${chainId}'s ACL serves EIP-712 domain version "${version}" \u2014 this SDK requires the upgraded (ACP-era) ACL, which signs as version "2". Pre-upgrade (V2 Permission) chains are not supported.`
|
|
2072
|
+
);
|
|
2073
|
+
}
|
|
2141
2074
|
return {
|
|
2142
2075
|
name,
|
|
2143
2076
|
version,
|
|
@@ -2145,23 +2078,26 @@ var getAclEIP712Domain = async (publicClient) => {
|
|
|
2145
2078
|
verifyingContract
|
|
2146
2079
|
};
|
|
2147
2080
|
};
|
|
2148
|
-
var
|
|
2081
|
+
var checkACPValidityOnChain = async (acp, publicClient) => {
|
|
2149
2082
|
const aclAddress = await getAclAddress(publicClient);
|
|
2150
2083
|
try {
|
|
2151
2084
|
await publicClient.simulateContract({
|
|
2152
2085
|
address: aclAddress,
|
|
2153
|
-
abi:
|
|
2154
|
-
functionName: "
|
|
2086
|
+
abi: checkACPValidityAbi,
|
|
2087
|
+
functionName: "checkPermissionValidity",
|
|
2155
2088
|
args: [
|
|
2156
2089
|
{
|
|
2157
|
-
issuer:
|
|
2158
|
-
expiration: BigInt(
|
|
2159
|
-
recipient:
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2090
|
+
issuer: acp.issuer,
|
|
2091
|
+
expiration: BigInt(acp.expiration),
|
|
2092
|
+
recipient: acp.recipient,
|
|
2093
|
+
revokerData: BigInt(acp.revokerData),
|
|
2094
|
+
revokerContract: acp.revokerContract,
|
|
2095
|
+
scope: acp.scope,
|
|
2096
|
+
contracts: acp.contracts,
|
|
2097
|
+
handles: acp.handles,
|
|
2098
|
+
sealingKey: acp.sealingKey,
|
|
2099
|
+
issuerSignature: acp.issuerSignature,
|
|
2100
|
+
recipientSignature: acp.recipientSignature
|
|
2165
2101
|
}
|
|
2166
2102
|
]
|
|
2167
2103
|
});
|
|
@@ -2174,14 +2110,14 @@ var checkPermitValidityOnChain = async (permission, publicClient) => {
|
|
|
2174
2110
|
throw new Error(errorName);
|
|
2175
2111
|
}
|
|
2176
2112
|
}
|
|
2177
|
-
const customErrorName = extractCustomErrorFromDetails(err,
|
|
2113
|
+
const customErrorName = extractCustomErrorFromDetails(err, checkACPValidityAbi);
|
|
2178
2114
|
if (customErrorName) {
|
|
2179
2115
|
throw new Error(customErrorName);
|
|
2180
2116
|
}
|
|
2181
2117
|
const hhDetailsData = extractReturnData(err);
|
|
2182
2118
|
if (hhDetailsData != null) {
|
|
2183
2119
|
const decoded = viem.decodeErrorResult({
|
|
2184
|
-
abi:
|
|
2120
|
+
abi: checkACPValidityAbi,
|
|
2185
2121
|
data: hhDetailsData
|
|
2186
2122
|
});
|
|
2187
2123
|
throw new Error(decoded.errorName);
|
|
@@ -2209,15 +2145,15 @@ function extractReturnData(err) {
|
|
|
2209
2145
|
const s = anyErr?.details ?? anyErr?.cause?.details ?? anyErr?.shortMessage ?? anyErr?.message ?? String(err);
|
|
2210
2146
|
return s.match(/return data:\s*(0x[a-fA-F0-9]+)/)?.[1];
|
|
2211
2147
|
}
|
|
2212
|
-
var
|
|
2148
|
+
var checkACPValidityAbi = [
|
|
2213
2149
|
{
|
|
2214
2150
|
type: "function",
|
|
2215
|
-
name: "
|
|
2151
|
+
name: "checkPermissionValidity",
|
|
2216
2152
|
inputs: [
|
|
2217
2153
|
{
|
|
2218
|
-
name: "
|
|
2154
|
+
name: "acp",
|
|
2219
2155
|
type: "tuple",
|
|
2220
|
-
internalType: "struct
|
|
2156
|
+
internalType: "struct ACP",
|
|
2221
2157
|
components: [
|
|
2222
2158
|
{
|
|
2223
2159
|
name: "issuer",
|
|
@@ -2235,15 +2171,30 @@ var checkPermitValidityAbi = [
|
|
|
2235
2171
|
internalType: "address"
|
|
2236
2172
|
},
|
|
2237
2173
|
{
|
|
2238
|
-
name: "
|
|
2174
|
+
name: "revokerData",
|
|
2239
2175
|
type: "uint256",
|
|
2240
2176
|
internalType: "uint256"
|
|
2241
2177
|
},
|
|
2242
2178
|
{
|
|
2243
|
-
name: "
|
|
2179
|
+
name: "revokerContract",
|
|
2244
2180
|
type: "address",
|
|
2245
2181
|
internalType: "address"
|
|
2246
2182
|
},
|
|
2183
|
+
{
|
|
2184
|
+
name: "scope",
|
|
2185
|
+
type: "uint8",
|
|
2186
|
+
internalType: "uint8"
|
|
2187
|
+
},
|
|
2188
|
+
{
|
|
2189
|
+
name: "contracts",
|
|
2190
|
+
type: "address[]",
|
|
2191
|
+
internalType: "address[]"
|
|
2192
|
+
},
|
|
2193
|
+
{
|
|
2194
|
+
name: "handles",
|
|
2195
|
+
type: "bytes32[]",
|
|
2196
|
+
internalType: "bytes32[]"
|
|
2197
|
+
},
|
|
2247
2198
|
{
|
|
2248
2199
|
name: "sealingKey",
|
|
2249
2200
|
type: "bytes32",
|
|
@@ -2293,38 +2244,40 @@ var checkPermitValidityAbi = [
|
|
|
2293
2244
|
}
|
|
2294
2245
|
];
|
|
2295
2246
|
|
|
2296
|
-
//
|
|
2297
|
-
var
|
|
2247
|
+
// acps/acp.ts
|
|
2248
|
+
var ACPUtils = {
|
|
2298
2249
|
/**
|
|
2299
|
-
* Create a self
|
|
2250
|
+
* Create a self acp for personal use
|
|
2300
2251
|
*/
|
|
2301
2252
|
createSelf: (options) => {
|
|
2302
|
-
const validation =
|
|
2253
|
+
const validation = validateSelfACPOptions(options);
|
|
2303
2254
|
const sealingPair = GenerateSealingKey();
|
|
2304
|
-
const
|
|
2305
|
-
hash:
|
|
2255
|
+
const acp = {
|
|
2256
|
+
hash: ACPUtils.getHash(validation),
|
|
2306
2257
|
...validation,
|
|
2307
|
-
sealingPair,
|
|
2258
|
+
sealingPrivateKey: sealingPair.privateKey,
|
|
2259
|
+
sealingKey: sealingPair.publicKey,
|
|
2308
2260
|
_signedDomain: void 0
|
|
2309
2261
|
};
|
|
2310
|
-
return
|
|
2262
|
+
return acp;
|
|
2311
2263
|
},
|
|
2312
2264
|
/**
|
|
2313
|
-
* Create a sharing
|
|
2265
|
+
* Create a sharing acp to be shared with another user
|
|
2314
2266
|
*/
|
|
2315
2267
|
createSharing: (options) => {
|
|
2316
|
-
const validation =
|
|
2268
|
+
const validation = validateSharingACPOptions(options);
|
|
2317
2269
|
const sealingPair = GenerateSealingKey();
|
|
2318
|
-
const
|
|
2319
|
-
hash:
|
|
2270
|
+
const acp = {
|
|
2271
|
+
hash: ACPUtils.getHash(validation),
|
|
2320
2272
|
...validation,
|
|
2321
|
-
sealingPair,
|
|
2273
|
+
sealingPrivateKey: sealingPair.privateKey,
|
|
2274
|
+
sealingKey: sealingPair.publicKey,
|
|
2322
2275
|
_signedDomain: void 0
|
|
2323
2276
|
};
|
|
2324
|
-
return
|
|
2277
|
+
return acp;
|
|
2325
2278
|
},
|
|
2326
2279
|
/**
|
|
2327
|
-
* Import a shared
|
|
2280
|
+
* Import a shared acp from various input formats
|
|
2328
2281
|
*/
|
|
2329
2282
|
importShared: (options) => {
|
|
2330
2283
|
let parsedOptions;
|
|
@@ -2337,33 +2290,34 @@ var PermitUtils = {
|
|
|
2337
2290
|
} else if (typeof options === "object" && options !== null) {
|
|
2338
2291
|
parsedOptions = options;
|
|
2339
2292
|
} else {
|
|
2340
|
-
throw new Error("Invalid input type, expected
|
|
2293
|
+
throw new Error("Invalid input type, expected ImportSharedACPOptions, object, or string");
|
|
2341
2294
|
}
|
|
2342
2295
|
if (parsedOptions.type != null && parsedOptions.type !== "sharing") {
|
|
2343
|
-
throw new Error(`Invalid
|
|
2296
|
+
throw new Error(`Invalid acp type <${parsedOptions.type}>, must be "sharing"`);
|
|
2344
2297
|
}
|
|
2345
|
-
const validation =
|
|
2298
|
+
const validation = validateImportACPOptions({ ...parsedOptions, type: "recipient" });
|
|
2346
2299
|
const sealingPair = GenerateSealingKey();
|
|
2347
|
-
const
|
|
2348
|
-
hash:
|
|
2300
|
+
const acp = {
|
|
2301
|
+
hash: ACPUtils.getHash(validation),
|
|
2349
2302
|
...validation,
|
|
2350
|
-
sealingPair,
|
|
2303
|
+
sealingPrivateKey: sealingPair.privateKey,
|
|
2304
|
+
sealingKey: sealingPair.publicKey,
|
|
2351
2305
|
_signedDomain: void 0
|
|
2352
2306
|
};
|
|
2353
|
-
return
|
|
2307
|
+
return acp;
|
|
2354
2308
|
},
|
|
2355
2309
|
/**
|
|
2356
|
-
* Sign
|
|
2310
|
+
* Sign an ACP with the provided wallet client
|
|
2357
2311
|
*/
|
|
2358
|
-
sign: async (
|
|
2312
|
+
sign: async (acp, publicClient, walletClient) => {
|
|
2359
2313
|
if (walletClient == null || walletClient.account == null) {
|
|
2360
2314
|
throw new Error(
|
|
2361
|
-
"Missing walletClient, you must pass in a `walletClient` for the connected user to create
|
|
2315
|
+
"Missing walletClient, you must pass in a `walletClient` for the connected user to create an ACP signature"
|
|
2362
2316
|
);
|
|
2363
2317
|
}
|
|
2364
|
-
const primaryType = SignatureUtils.getPrimaryType(
|
|
2318
|
+
const primaryType = SignatureUtils.getPrimaryType(acp.type);
|
|
2365
2319
|
const domain = await getAclEIP712Domain(publicClient);
|
|
2366
|
-
const { types, message } = SignatureUtils.getSignatureParams(
|
|
2320
|
+
const { types, message } = SignatureUtils.getSignatureParams(ACPUtils.getPublic(acp, true), primaryType);
|
|
2367
2321
|
const signature = await walletClient.signTypedData({
|
|
2368
2322
|
domain,
|
|
2369
2323
|
types,
|
|
@@ -2371,190 +2325,209 @@ var PermitUtils = {
|
|
|
2371
2325
|
message,
|
|
2372
2326
|
account: walletClient.account
|
|
2373
2327
|
});
|
|
2374
|
-
let
|
|
2375
|
-
if (
|
|
2376
|
-
|
|
2377
|
-
...
|
|
2328
|
+
let updatedACP;
|
|
2329
|
+
if (acp.type === "self" || acp.type === "sharing") {
|
|
2330
|
+
updatedACP = {
|
|
2331
|
+
...acp,
|
|
2378
2332
|
issuerSignature: signature,
|
|
2379
2333
|
_signedDomain: domain
|
|
2380
2334
|
};
|
|
2381
2335
|
} else {
|
|
2382
|
-
|
|
2383
|
-
...
|
|
2336
|
+
updatedACP = {
|
|
2337
|
+
...acp,
|
|
2384
2338
|
recipientSignature: signature,
|
|
2385
2339
|
_signedDomain: domain
|
|
2386
2340
|
};
|
|
2387
2341
|
}
|
|
2388
|
-
return
|
|
2342
|
+
return updatedACP;
|
|
2389
2343
|
},
|
|
2390
2344
|
/**
|
|
2391
|
-
* Create and sign a self
|
|
2345
|
+
* Create and sign a self acp in one operation
|
|
2392
2346
|
*/
|
|
2393
2347
|
createSelfAndSign: async (options, publicClient, walletClient) => {
|
|
2394
|
-
const
|
|
2395
|
-
return
|
|
2348
|
+
const acp = ACPUtils.createSelf(options);
|
|
2349
|
+
return ACPUtils.sign(acp, publicClient, walletClient);
|
|
2396
2350
|
},
|
|
2397
2351
|
/**
|
|
2398
|
-
* Create and sign a sharing
|
|
2352
|
+
* Create and sign a sharing acp in one operation
|
|
2399
2353
|
*/
|
|
2400
2354
|
createSharingAndSign: async (options, publicClient, walletClient) => {
|
|
2401
|
-
const
|
|
2402
|
-
return
|
|
2355
|
+
const acp = ACPUtils.createSharing(options);
|
|
2356
|
+
return ACPUtils.sign(acp, publicClient, walletClient);
|
|
2403
2357
|
},
|
|
2404
2358
|
/**
|
|
2405
|
-
* Import and sign a shared
|
|
2359
|
+
* Import and sign a shared acp in one operation from various input formats
|
|
2406
2360
|
*/
|
|
2407
2361
|
importSharedAndSign: async (options, publicClient, walletClient) => {
|
|
2408
|
-
const
|
|
2409
|
-
return
|
|
2362
|
+
const acp = ACPUtils.importShared(options);
|
|
2363
|
+
return ACPUtils.sign(acp, publicClient, walletClient);
|
|
2410
2364
|
},
|
|
2411
2365
|
/**
|
|
2412
|
-
* Deserialize
|
|
2366
|
+
* Deserialize an ACP from serialized data
|
|
2413
2367
|
*/
|
|
2414
2368
|
deserialize: (data) => {
|
|
2415
|
-
return {
|
|
2416
|
-
...data,
|
|
2417
|
-
sealingPair: SealingKey.deserialize(data.sealingPair.privateKey, data.sealingPair.publicKey)
|
|
2418
|
-
};
|
|
2369
|
+
return { ...data };
|
|
2419
2370
|
},
|
|
2420
2371
|
/**
|
|
2421
|
-
* Serialize
|
|
2372
|
+
* Serialize an ACP for storage
|
|
2422
2373
|
*/
|
|
2423
|
-
serialize: (
|
|
2374
|
+
serialize: (acp) => {
|
|
2424
2375
|
return {
|
|
2425
|
-
hash:
|
|
2426
|
-
name:
|
|
2427
|
-
type:
|
|
2428
|
-
issuer:
|
|
2429
|
-
expiration:
|
|
2430
|
-
recipient:
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2376
|
+
hash: acp.hash,
|
|
2377
|
+
name: acp.name,
|
|
2378
|
+
type: acp.type,
|
|
2379
|
+
issuer: acp.issuer,
|
|
2380
|
+
expiration: acp.expiration,
|
|
2381
|
+
recipient: acp.recipient,
|
|
2382
|
+
revokerData: acp.revokerData,
|
|
2383
|
+
revokerContract: acp.revokerContract,
|
|
2384
|
+
scope: acp.scope,
|
|
2385
|
+
contracts: acp.contracts,
|
|
2386
|
+
handles: acp.handles,
|
|
2387
|
+
sealingKey: acp.sealingKey,
|
|
2388
|
+
issuerSignature: acp.issuerSignature,
|
|
2389
|
+
recipientSignature: acp.recipientSignature,
|
|
2390
|
+
_signedDomain: acp._signedDomain,
|
|
2391
|
+
sealingPrivateKey: acp.sealingPrivateKey
|
|
2437
2392
|
};
|
|
2438
2393
|
},
|
|
2439
2394
|
/**
|
|
2440
|
-
* Validate
|
|
2395
|
+
* Validate an ACP (schema-level validation)
|
|
2441
2396
|
*/
|
|
2442
|
-
validateSchema: (
|
|
2443
|
-
if (
|
|
2444
|
-
return
|
|
2445
|
-
} else if (
|
|
2446
|
-
return
|
|
2447
|
-
} else if (
|
|
2448
|
-
return
|
|
2397
|
+
validateSchema: (acp) => {
|
|
2398
|
+
if (acp.type === "self") {
|
|
2399
|
+
return validateSelfACP(acp);
|
|
2400
|
+
} else if (acp.type === "sharing") {
|
|
2401
|
+
return validateSharingACP(acp);
|
|
2402
|
+
} else if (acp.type === "recipient") {
|
|
2403
|
+
return validateImportACP(acp);
|
|
2449
2404
|
} else {
|
|
2450
|
-
throw new Error("Invalid
|
|
2405
|
+
throw new Error("Invalid ACP type");
|
|
2451
2406
|
}
|
|
2452
2407
|
},
|
|
2453
2408
|
/**
|
|
2454
|
-
* Validate
|
|
2409
|
+
* Validate an ACP (holistic validation).
|
|
2455
2410
|
*
|
|
2456
2411
|
* This validates:
|
|
2457
|
-
* -
|
|
2458
|
-
* -
|
|
2459
|
-
* -
|
|
2412
|
+
* - ACP schema (shape + invariants)
|
|
2413
|
+
* - ACP is signed
|
|
2414
|
+
* - ACP is not expired
|
|
2460
2415
|
*
|
|
2461
|
-
* For schema-only validation, use `validateSchema(
|
|
2416
|
+
* For schema-only validation, use `validateSchema(acp)`.
|
|
2462
2417
|
*/
|
|
2463
|
-
validate: (
|
|
2464
|
-
const validated =
|
|
2418
|
+
validate: (acp) => {
|
|
2419
|
+
const validated = ACPUtils.validateSchema(acp);
|
|
2465
2420
|
ValidationUtils.assertSignedAndNotExpired(validated);
|
|
2466
2421
|
return validated;
|
|
2467
2422
|
},
|
|
2468
2423
|
/**
|
|
2469
|
-
* Get the
|
|
2424
|
+
* Get the public component of an ACP — the signed struct sent on-chain / to the decryption backend.
|
|
2425
|
+
* Strips the private component (hash, name, type, sealing pair).
|
|
2470
2426
|
*/
|
|
2471
|
-
|
|
2427
|
+
getPublic: (acp, skipValidation = false) => {
|
|
2472
2428
|
if (!skipValidation) {
|
|
2473
|
-
|
|
2429
|
+
ACPUtils.validateSchema(acp);
|
|
2474
2430
|
}
|
|
2475
2431
|
return {
|
|
2476
|
-
issuer:
|
|
2477
|
-
expiration:
|
|
2478
|
-
recipient:
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2432
|
+
issuer: acp.issuer,
|
|
2433
|
+
expiration: acp.expiration,
|
|
2434
|
+
recipient: acp.recipient,
|
|
2435
|
+
revokerData: acp.revokerData,
|
|
2436
|
+
revokerContract: acp.revokerContract,
|
|
2437
|
+
scope: acp.scope,
|
|
2438
|
+
contracts: acp.contracts,
|
|
2439
|
+
handles: acp.handles,
|
|
2440
|
+
sealingKey: acp.sealingKey,
|
|
2441
|
+
issuerSignature: acp.issuerSignature,
|
|
2442
|
+
recipientSignature: acp.recipientSignature
|
|
2484
2443
|
};
|
|
2485
2444
|
},
|
|
2486
2445
|
/**
|
|
2487
|
-
* Get a stable hash for the
|
|
2446
|
+
* Get a stable hash for the acp (used as key in storage)
|
|
2488
2447
|
*/
|
|
2489
|
-
getHash: (
|
|
2448
|
+
getHash: (acp) => {
|
|
2490
2449
|
const data = JSON.stringify({
|
|
2491
|
-
type:
|
|
2492
|
-
issuer:
|
|
2493
|
-
expiration:
|
|
2494
|
-
recipient:
|
|
2495
|
-
|
|
2496
|
-
|
|
2450
|
+
type: acp.type,
|
|
2451
|
+
issuer: acp.issuer,
|
|
2452
|
+
expiration: acp.expiration,
|
|
2453
|
+
recipient: acp.recipient,
|
|
2454
|
+
revokerData: acp.revokerData,
|
|
2455
|
+
revokerContract: acp.revokerContract,
|
|
2456
|
+
scope: acp.scope,
|
|
2457
|
+
contracts: acp.contracts,
|
|
2458
|
+
handles: acp.handles
|
|
2497
2459
|
});
|
|
2498
2460
|
return viem.keccak256(viem.toHex(data));
|
|
2499
2461
|
},
|
|
2500
2462
|
/**
|
|
2501
|
-
* Export
|
|
2463
|
+
* Export acp data for sharing (strips the private component).
|
|
2464
|
+
* Fixed `SharedACP` shape — every field always present, aligned with
|
|
2465
|
+
* `ACPPublic` and the on-chain sharing payload.
|
|
2502
2466
|
*/
|
|
2503
|
-
export: (
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2467
|
+
export: (acp) => {
|
|
2468
|
+
if (acp.type !== "sharing") {
|
|
2469
|
+
throw new Error(
|
|
2470
|
+
`Cannot export a '${acp.type}' ACP \u2014 only 'sharing' ACPs are exportable. The export includes the issuer signature.`
|
|
2471
|
+
);
|
|
2472
|
+
}
|
|
2473
|
+
if (acp.issuerSignature === "0x") {
|
|
2474
|
+
throw new Error(
|
|
2475
|
+
"Cannot export an unsigned sharing ACP \u2014 sign it first (the recipient needs the issuer signature)."
|
|
2476
|
+
);
|
|
2477
|
+
}
|
|
2478
|
+
const shared = {
|
|
2479
|
+
name: acp.name,
|
|
2480
|
+
type: acp.type,
|
|
2481
|
+
issuer: acp.issuer,
|
|
2482
|
+
expiration: acp.expiration,
|
|
2483
|
+
recipient: acp.recipient,
|
|
2484
|
+
revokerData: acp.revokerData,
|
|
2485
|
+
revokerContract: acp.revokerContract,
|
|
2486
|
+
scope: acp.scope,
|
|
2487
|
+
contracts: acp.contracts,
|
|
2488
|
+
handles: acp.handles,
|
|
2489
|
+
issuerSignature: acp.issuerSignature
|
|
2509
2490
|
};
|
|
2510
|
-
|
|
2511
|
-
cleanedPermit.recipient = permit.recipient;
|
|
2512
|
-
if (permit.validatorId !== 0)
|
|
2513
|
-
cleanedPermit.validatorId = permit.validatorId;
|
|
2514
|
-
if (permit.validatorContract !== viem.zeroAddress)
|
|
2515
|
-
cleanedPermit.validatorContract = permit.validatorContract;
|
|
2516
|
-
if (permit.type === "sharing" && permit.issuerSignature !== "0x")
|
|
2517
|
-
cleanedPermit.issuerSignature = permit.issuerSignature;
|
|
2518
|
-
return JSON.stringify(cleanedPermit, void 0, 2);
|
|
2491
|
+
return JSON.stringify(shared, void 0, 2);
|
|
2519
2492
|
},
|
|
2520
2493
|
/**
|
|
2521
|
-
* Unseal encrypted data using the
|
|
2494
|
+
* Unseal encrypted data using the acp's sealing key
|
|
2522
2495
|
*/
|
|
2523
|
-
unseal: (
|
|
2524
|
-
return
|
|
2496
|
+
unseal: (acp, ciphertext) => {
|
|
2497
|
+
return unsealWithPrivateKey(acp.sealingPrivateKey, ciphertext);
|
|
2525
2498
|
},
|
|
2526
2499
|
/**
|
|
2527
|
-
* Check if
|
|
2500
|
+
* Check if acp is expired
|
|
2528
2501
|
*/
|
|
2529
|
-
isExpired: (
|
|
2530
|
-
return ValidationUtils.isExpired(
|
|
2502
|
+
isExpired: (acp) => {
|
|
2503
|
+
return ValidationUtils.isExpired(acp);
|
|
2531
2504
|
},
|
|
2532
2505
|
/**
|
|
2533
|
-
* Check if
|
|
2506
|
+
* Check if acp is signed
|
|
2534
2507
|
*/
|
|
2535
|
-
isSigned: (
|
|
2536
|
-
return ValidationUtils.isSigned(
|
|
2508
|
+
isSigned: (acp) => {
|
|
2509
|
+
return ValidationUtils.isSigned(acp);
|
|
2537
2510
|
},
|
|
2538
2511
|
/**
|
|
2539
|
-
* Check if
|
|
2512
|
+
* Check if acp is signed and not expired
|
|
2540
2513
|
*/
|
|
2541
|
-
isSignedAndNotExpired: (
|
|
2542
|
-
return ValidationUtils.isSignedAndNotExpired(
|
|
2514
|
+
isSignedAndNotExpired: (acp) => {
|
|
2515
|
+
return ValidationUtils.isSignedAndNotExpired(acp);
|
|
2543
2516
|
},
|
|
2544
2517
|
/**
|
|
2545
|
-
* Assert that
|
|
2518
|
+
* Assert that acp is signed and not expired
|
|
2546
2519
|
*/
|
|
2547
|
-
assertSignedAndNotExpired: (
|
|
2548
|
-
return ValidationUtils.assertSignedAndNotExpired(
|
|
2520
|
+
assertSignedAndNotExpired: (acp) => {
|
|
2521
|
+
return ValidationUtils.assertSignedAndNotExpired(acp);
|
|
2549
2522
|
},
|
|
2550
|
-
isValid: (
|
|
2551
|
-
return ValidationUtils.isValid(
|
|
2523
|
+
isValid: (acp) => {
|
|
2524
|
+
return ValidationUtils.isValid(acp);
|
|
2552
2525
|
},
|
|
2553
2526
|
/**
|
|
2554
|
-
* Update
|
|
2527
|
+
* Update acp name (returns new acp instance)
|
|
2555
2528
|
*/
|
|
2556
|
-
updateName: (
|
|
2557
|
-
return { ...
|
|
2529
|
+
updateName: (acp, name) => {
|
|
2530
|
+
return { ...acp, name };
|
|
2558
2531
|
},
|
|
2559
2532
|
/**
|
|
2560
2533
|
* Fetch EIP712 domain from the blockchain
|
|
@@ -2563,230 +2536,468 @@ var PermitUtils = {
|
|
|
2563
2536
|
return getAclEIP712Domain(publicClient);
|
|
2564
2537
|
},
|
|
2565
2538
|
/**
|
|
2566
|
-
* Check if
|
|
2539
|
+
* Check if acp's signed domain matches the provided domain
|
|
2567
2540
|
*/
|
|
2568
|
-
matchesDomain: (
|
|
2569
|
-
return
|
|
2541
|
+
matchesDomain: (acp, domain) => {
|
|
2542
|
+
return acp._signedDomain?.name === domain.name && acp._signedDomain?.version === domain.version && acp._signedDomain?.verifyingContract === domain.verifyingContract && acp._signedDomain?.chainId === domain.chainId;
|
|
2570
2543
|
},
|
|
2571
2544
|
/**
|
|
2572
|
-
* Check if
|
|
2545
|
+
* Check if acp's signed domain is valid for the current chain
|
|
2573
2546
|
*/
|
|
2574
|
-
checkSignedDomainValid: async (
|
|
2575
|
-
if (
|
|
2547
|
+
checkSignedDomainValid: async (acp, publicClient) => {
|
|
2548
|
+
if (acp._signedDomain == null)
|
|
2576
2549
|
return false;
|
|
2577
2550
|
const domain = await getAclEIP712Domain(publicClient);
|
|
2578
|
-
return
|
|
2551
|
+
return ACPUtils.matchesDomain(acp, domain);
|
|
2579
2552
|
},
|
|
2580
2553
|
/**
|
|
2581
|
-
* Check if
|
|
2554
|
+
* Check if acp passes the on-chain validation
|
|
2582
2555
|
*/
|
|
2583
|
-
checkValidityOnChain: async (
|
|
2584
|
-
const
|
|
2585
|
-
return
|
|
2556
|
+
checkValidityOnChain: async (acp, publicClient) => {
|
|
2557
|
+
const publicAcp = ACPUtils.getPublic(acp);
|
|
2558
|
+
return checkACPValidityOnChain(publicAcp, publicClient);
|
|
2586
2559
|
}
|
|
2587
2560
|
};
|
|
2588
|
-
var
|
|
2589
|
-
|
|
2590
|
-
|
|
2561
|
+
var ACP_STORE_DEFAULTS = {
|
|
2562
|
+
acps: {},
|
|
2563
|
+
activeACPHash: {}
|
|
2591
2564
|
};
|
|
2592
|
-
var
|
|
2593
|
-
|
|
2565
|
+
var ACP_STORE_VERSION = 3;
|
|
2566
|
+
var _acpStore = vanilla.createStore()(
|
|
2567
|
+
middleware.persist(() => ACP_STORE_DEFAULTS, {
|
|
2568
|
+
name: "cofhesdk-acps",
|
|
2569
|
+
version: ACP_STORE_VERSION,
|
|
2570
|
+
migrate: (persistedState, version) => {
|
|
2571
|
+
if (version < ACP_STORE_VERSION)
|
|
2572
|
+
return ACP_STORE_DEFAULTS;
|
|
2573
|
+
return persistedState;
|
|
2574
|
+
}
|
|
2575
|
+
})
|
|
2594
2576
|
);
|
|
2595
2577
|
var clearStaleStore = () => {
|
|
2596
|
-
const state =
|
|
2597
|
-
const hasExpectedStructure = state && typeof state === "object" && "
|
|
2578
|
+
const state = _acpStore.getState();
|
|
2579
|
+
const hasExpectedStructure = state && typeof state === "object" && "acps" in state && "activeACPHash" in state && typeof state.acps === "object" && typeof state.activeACPHash === "object";
|
|
2598
2580
|
if (hasExpectedStructure)
|
|
2599
2581
|
return;
|
|
2600
|
-
|
|
2582
|
+
_acpStore.setState({ acps: {}, activeACPHash: {} });
|
|
2601
2583
|
};
|
|
2602
|
-
var
|
|
2584
|
+
var getACP = (chainId, account, hash) => {
|
|
2603
2585
|
clearStaleStore();
|
|
2604
2586
|
if (chainId == null || account == null || hash == null)
|
|
2605
2587
|
return;
|
|
2606
|
-
const
|
|
2607
|
-
if (
|
|
2588
|
+
const savedACP = _acpStore.getState().acps[chainId]?.[account]?.[hash];
|
|
2589
|
+
if (savedACP == null)
|
|
2608
2590
|
return;
|
|
2609
|
-
return
|
|
2591
|
+
return ACPUtils.deserialize(savedACP);
|
|
2610
2592
|
};
|
|
2611
|
-
var
|
|
2593
|
+
var getActiveACP = (chainId, account) => {
|
|
2612
2594
|
clearStaleStore();
|
|
2613
2595
|
if (chainId == null || account == null)
|
|
2614
2596
|
return;
|
|
2615
|
-
const
|
|
2616
|
-
return
|
|
2597
|
+
const activeACPHash = _acpStore.getState().activeACPHash[chainId]?.[account];
|
|
2598
|
+
return getACP(chainId, account, activeACPHash);
|
|
2617
2599
|
};
|
|
2618
|
-
var
|
|
2600
|
+
var getACPs = (chainId, account) => {
|
|
2619
2601
|
clearStaleStore();
|
|
2620
2602
|
if (chainId == null || account == null)
|
|
2621
2603
|
return {};
|
|
2622
|
-
return Object.entries(
|
|
2623
|
-
(acc, [hash,
|
|
2624
|
-
if (
|
|
2604
|
+
return Object.entries(_acpStore.getState().acps[chainId]?.[account] ?? {}).reduce(
|
|
2605
|
+
(acc, [hash, acp]) => {
|
|
2606
|
+
if (acp == void 0)
|
|
2625
2607
|
return acc;
|
|
2626
|
-
return { ...acc, [hash]:
|
|
2608
|
+
return { ...acc, [hash]: ACPUtils.deserialize(acp) };
|
|
2627
2609
|
},
|
|
2628
2610
|
{}
|
|
2629
2611
|
);
|
|
2630
2612
|
};
|
|
2631
|
-
var
|
|
2613
|
+
var setACP = (chainId, account, acp) => {
|
|
2632
2614
|
clearStaleStore();
|
|
2633
|
-
|
|
2615
|
+
_acpStore.setState(
|
|
2634
2616
|
immer.produce((state) => {
|
|
2635
|
-
if (state.
|
|
2636
|
-
state.
|
|
2637
|
-
if (state.
|
|
2638
|
-
state.
|
|
2639
|
-
state.
|
|
2617
|
+
if (state.acps[chainId] == null)
|
|
2618
|
+
state.acps[chainId] = {};
|
|
2619
|
+
if (state.acps[chainId][account] == null)
|
|
2620
|
+
state.acps[chainId][account] = {};
|
|
2621
|
+
state.acps[chainId][account][acp.hash] = ACPUtils.serialize(acp);
|
|
2640
2622
|
})
|
|
2641
2623
|
);
|
|
2642
2624
|
};
|
|
2643
|
-
var
|
|
2625
|
+
var removeACP = (chainId, account, hash) => {
|
|
2644
2626
|
clearStaleStore();
|
|
2645
|
-
|
|
2627
|
+
_acpStore.setState(
|
|
2646
2628
|
immer.produce((state) => {
|
|
2647
|
-
if (state.
|
|
2648
|
-
state.
|
|
2649
|
-
if (state.
|
|
2650
|
-
state.
|
|
2651
|
-
const
|
|
2652
|
-
if (
|
|
2629
|
+
if (state.acps[chainId] == null)
|
|
2630
|
+
state.acps[chainId] = {};
|
|
2631
|
+
if (state.activeACPHash[chainId] == null)
|
|
2632
|
+
state.activeACPHash[chainId] = {};
|
|
2633
|
+
const accountACPs = state.acps[chainId][account];
|
|
2634
|
+
if (accountACPs == null)
|
|
2653
2635
|
return;
|
|
2654
|
-
if (
|
|
2636
|
+
if (accountACPs[hash] == null)
|
|
2655
2637
|
return;
|
|
2656
|
-
if (state.
|
|
2657
|
-
state.
|
|
2638
|
+
if (state.activeACPHash[chainId][account] === hash) {
|
|
2639
|
+
state.activeACPHash[chainId][account] = void 0;
|
|
2658
2640
|
}
|
|
2659
|
-
|
|
2641
|
+
accountACPs[hash] = void 0;
|
|
2660
2642
|
})
|
|
2661
2643
|
);
|
|
2662
2644
|
};
|
|
2663
|
-
var
|
|
2645
|
+
var getActiveACPHash = (chainId, account) => {
|
|
2664
2646
|
clearStaleStore();
|
|
2665
2647
|
if (chainId == null || account == null)
|
|
2666
2648
|
return void 0;
|
|
2667
|
-
return
|
|
2649
|
+
return _acpStore.getState().activeACPHash[chainId]?.[account];
|
|
2668
2650
|
};
|
|
2669
|
-
var
|
|
2651
|
+
var setActiveACPHash = (chainId, account, hash) => {
|
|
2670
2652
|
clearStaleStore();
|
|
2671
|
-
|
|
2653
|
+
_acpStore.setState(
|
|
2672
2654
|
immer.produce((state) => {
|
|
2673
|
-
if (state.
|
|
2674
|
-
state.
|
|
2675
|
-
state.
|
|
2655
|
+
if (state.activeACPHash[chainId] == null)
|
|
2656
|
+
state.activeACPHash[chainId] = {};
|
|
2657
|
+
state.activeACPHash[chainId][account] = hash;
|
|
2676
2658
|
})
|
|
2677
2659
|
);
|
|
2678
2660
|
};
|
|
2679
|
-
var
|
|
2661
|
+
var removeActiveACPHash = (chainId, account) => {
|
|
2680
2662
|
clearStaleStore();
|
|
2681
|
-
|
|
2663
|
+
_acpStore.setState(
|
|
2682
2664
|
immer.produce((state) => {
|
|
2683
|
-
if (state.
|
|
2684
|
-
state.
|
|
2665
|
+
if (state.activeACPHash[chainId])
|
|
2666
|
+
state.activeACPHash[chainId][account] = void 0;
|
|
2685
2667
|
})
|
|
2686
2668
|
);
|
|
2687
2669
|
};
|
|
2688
2670
|
var resetStore = () => {
|
|
2689
2671
|
clearStaleStore();
|
|
2690
|
-
|
|
2672
|
+
_acpStore.setState({ acps: {}, activeACPHash: {} });
|
|
2691
2673
|
};
|
|
2692
|
-
var
|
|
2693
|
-
store:
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2674
|
+
var acpStore = {
|
|
2675
|
+
store: _acpStore,
|
|
2676
|
+
getACP,
|
|
2677
|
+
getActiveACP,
|
|
2678
|
+
getACPs,
|
|
2679
|
+
setACP,
|
|
2680
|
+
removeACP,
|
|
2681
|
+
getActiveACPHash,
|
|
2682
|
+
setActiveACPHash,
|
|
2683
|
+
removeActiveACPHash,
|
|
2702
2684
|
resetStore
|
|
2703
2685
|
};
|
|
2704
|
-
var
|
|
2686
|
+
var ACP_VALIDATOR_ABI = viem.parseAbi([
|
|
2687
|
+
"function revokeSingle(uint256 id)",
|
|
2688
|
+
"function revokeAllExisting()",
|
|
2689
|
+
"function disabled(address issuer, uint256 id) view returns (bool)"
|
|
2690
|
+
]);
|
|
2691
|
+
var storeACP = async (acp, publicClient, walletClient) => {
|
|
2692
|
+
const chainId = await publicClient.getChainId();
|
|
2693
|
+
const account = walletClient.account.address;
|
|
2694
|
+
acpStore.setACP(chainId, account, acp);
|
|
2695
|
+
};
|
|
2696
|
+
var storeActiveACP = async (acp, publicClient, walletClient) => {
|
|
2697
|
+
await storeACP(acp, publicClient, walletClient);
|
|
2705
2698
|
const chainId = await publicClient.getChainId();
|
|
2706
2699
|
const account = walletClient.account.address;
|
|
2707
|
-
|
|
2708
|
-
permitStore.setActivePermitHash(chainId, account, permit.hash);
|
|
2700
|
+
acpStore.setActiveACPHash(chainId, account, acp.hash);
|
|
2709
2701
|
};
|
|
2710
|
-
var
|
|
2711
|
-
const
|
|
2712
|
-
|
|
2713
|
-
|
|
2702
|
+
var createACPWithSign = async (options, publicClient, walletClient, acpMethod, activate = true) => {
|
|
2703
|
+
const acp = await acpMethod(options, publicClient, walletClient);
|
|
2704
|
+
if (activate) {
|
|
2705
|
+
await storeActiveACP(acp, publicClient, walletClient);
|
|
2706
|
+
} else {
|
|
2707
|
+
await storeACP(acp, publicClient, walletClient);
|
|
2708
|
+
}
|
|
2709
|
+
return acp;
|
|
2714
2710
|
};
|
|
2715
2711
|
var createSelf = async (options, publicClient, walletClient) => {
|
|
2716
|
-
return
|
|
2712
|
+
return createACPWithSign(options, publicClient, walletClient, ACPUtils.createSelfAndSign);
|
|
2717
2713
|
};
|
|
2718
2714
|
var createSharing = async (options, publicClient, walletClient) => {
|
|
2719
|
-
return
|
|
2715
|
+
return createACPWithSign(options, publicClient, walletClient, ACPUtils.createSharingAndSign, false);
|
|
2720
2716
|
};
|
|
2721
2717
|
var importShared = async (options, publicClient, walletClient) => {
|
|
2722
|
-
return
|
|
2718
|
+
return createACPWithSign(options, publicClient, walletClient, ACPUtils.importSharedAndSign);
|
|
2723
2719
|
};
|
|
2724
|
-
var getHash = (
|
|
2725
|
-
return
|
|
2720
|
+
var getHash = (acp) => {
|
|
2721
|
+
return ACPUtils.getHash(acp);
|
|
2726
2722
|
};
|
|
2727
|
-
var exportShared = (
|
|
2728
|
-
return
|
|
2723
|
+
var exportShared = (acp) => {
|
|
2724
|
+
return ACPUtils.export(acp);
|
|
2729
2725
|
};
|
|
2730
|
-
var serialize = (
|
|
2731
|
-
return
|
|
2726
|
+
var serialize = (acp) => {
|
|
2727
|
+
return ACPUtils.serialize(acp);
|
|
2732
2728
|
};
|
|
2733
2729
|
var deserialize = (serialized) => {
|
|
2734
|
-
return
|
|
2730
|
+
return ACPUtils.deserialize(serialized);
|
|
2735
2731
|
};
|
|
2736
|
-
var
|
|
2737
|
-
return
|
|
2732
|
+
var getACP2 = (chainId, account, hash) => {
|
|
2733
|
+
return acpStore.getACP(chainId, account, hash);
|
|
2738
2734
|
};
|
|
2739
|
-
var
|
|
2740
|
-
return
|
|
2735
|
+
var getACPs2 = (chainId, account) => {
|
|
2736
|
+
return acpStore.getACPs(chainId, account);
|
|
2741
2737
|
};
|
|
2742
|
-
var
|
|
2743
|
-
return
|
|
2738
|
+
var getActiveACP2 = (chainId, account) => {
|
|
2739
|
+
return acpStore.getActiveACP(chainId, account);
|
|
2744
2740
|
};
|
|
2745
|
-
var
|
|
2746
|
-
return
|
|
2741
|
+
var getActiveACPHash2 = (chainId, account) => {
|
|
2742
|
+
return acpStore.getActiveACPHash(chainId, account);
|
|
2747
2743
|
};
|
|
2748
|
-
var
|
|
2749
|
-
|
|
2744
|
+
var selectActiveACP = (chainId, account, hash) => {
|
|
2745
|
+
acpStore.setActiveACPHash(chainId, account, hash);
|
|
2750
2746
|
};
|
|
2751
|
-
var
|
|
2747
|
+
var getOrCreateSelfACP = async (publicClient, walletClient, chainId, account, options) => {
|
|
2752
2748
|
const _chainId = chainId ?? await publicClient.getChainId();
|
|
2753
2749
|
const _account = account ?? walletClient.account.address;
|
|
2754
|
-
const
|
|
2755
|
-
if (
|
|
2756
|
-
return
|
|
2750
|
+
const activeACP = await getActiveACP2(_chainId, _account);
|
|
2751
|
+
if (activeACP && activeACP.type === "self" && ACPUtils.isValid(activeACP).valid) {
|
|
2752
|
+
return activeACP;
|
|
2757
2753
|
}
|
|
2758
|
-
return createSelf(options ?? { issuer: _account, name: "Autogenerated Self
|
|
2754
|
+
return createSelf(options ?? { issuer: _account, name: "Autogenerated Self ACP" }, publicClient, walletClient);
|
|
2759
2755
|
};
|
|
2760
|
-
var
|
|
2756
|
+
var getOrCreateSharingACP = async (publicClient, walletClient, options, chainId, account) => {
|
|
2761
2757
|
const _chainId = chainId ?? await publicClient.getChainId();
|
|
2762
2758
|
const _account = account ?? walletClient.account.address;
|
|
2763
|
-
const
|
|
2764
|
-
if (
|
|
2765
|
-
return
|
|
2759
|
+
const activeACP = await getActiveACP2(_chainId, _account);
|
|
2760
|
+
if (activeACP && activeACP.type === "sharing" && ACPUtils.isValid(activeACP).valid) {
|
|
2761
|
+
return activeACP;
|
|
2766
2762
|
}
|
|
2767
2763
|
return createSharing(options, publicClient, walletClient);
|
|
2768
2764
|
};
|
|
2769
|
-
var
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2765
|
+
var applyACPDefaults = (options, acpConfig, chainId) => {
|
|
2766
|
+
const result = { ...options };
|
|
2767
|
+
const defaultRevoker = acpConfig?.defaultRevoker?.[chainId];
|
|
2768
|
+
const hasValidatorOptions = options.revokerData != null || options.revokerContract != null;
|
|
2769
|
+
if (defaultRevoker != null && !hasValidatorOptions) {
|
|
2770
|
+
result.revokerContract = defaultRevoker;
|
|
2771
|
+
result.revokerData = Math.round(Date.now() / 1e3) - 60;
|
|
2772
|
+
}
|
|
2773
|
+
const defaultContracts = acpConfig?.defaultContractScopes?.[chainId];
|
|
2774
|
+
const hasScopeOptions = options.scope != null || options.contracts != null || options.handles != null;
|
|
2775
|
+
if (defaultContracts != null && defaultContracts.length > 0 && !hasScopeOptions) {
|
|
2776
|
+
result.contracts = defaultContracts;
|
|
2777
|
+
}
|
|
2778
|
+
return result;
|
|
2779
|
+
};
|
|
2780
|
+
var ACL_SERVED_ADDRESSES_ABI = viem.parseAbi([
|
|
2781
|
+
"function acl() view returns (address)",
|
|
2782
|
+
"function defaultRevokerContract() view returns (address)",
|
|
2783
|
+
"function shareRegistry() view returns (address)"
|
|
2784
|
+
]);
|
|
2785
|
+
var aclServedAddressesCache = /* @__PURE__ */ new Map();
|
|
2786
|
+
var clearAclServedAddresses = () => aclServedAddressesCache.clear();
|
|
2787
|
+
var getAclServedAddresses = async (publicClient, chainId) => {
|
|
2788
|
+
const cached = aclServedAddressesCache.get(chainId);
|
|
2789
|
+
if (cached != null)
|
|
2790
|
+
return cached;
|
|
2791
|
+
let aclAddress;
|
|
2792
|
+
try {
|
|
2793
|
+
aclAddress = await publicClient.readContract({
|
|
2794
|
+
address: TASK_MANAGER_ADDRESS,
|
|
2795
|
+
abi: ACL_SERVED_ADDRESSES_ABI,
|
|
2796
|
+
functionName: "acl"
|
|
2797
|
+
});
|
|
2798
|
+
} catch {
|
|
2799
|
+
return {};
|
|
2800
|
+
}
|
|
2801
|
+
const [defaultRevoker, shareRegistry] = await Promise.all([
|
|
2802
|
+
publicClient.readContract({ address: aclAddress, abi: ACL_SERVED_ADDRESSES_ABI, functionName: "defaultRevokerContract" }).catch(() => void 0),
|
|
2803
|
+
publicClient.readContract({ address: aclAddress, abi: ACL_SERVED_ADDRESSES_ABI, functionName: "shareRegistry" }).catch(() => void 0)
|
|
2804
|
+
]);
|
|
2805
|
+
const resolved = {
|
|
2806
|
+
defaultRevoker: defaultRevoker != null && defaultRevoker !== viem.zeroAddress ? defaultRevoker : void 0,
|
|
2807
|
+
shareRegistry: shareRegistry != null && shareRegistry !== viem.zeroAddress ? shareRegistry : void 0
|
|
2808
|
+
};
|
|
2809
|
+
aclServedAddressesCache.set(chainId, resolved);
|
|
2810
|
+
return resolved;
|
|
2811
|
+
};
|
|
2812
|
+
var applyACPDefaultsFromChain = async (options, acpConfig, publicClient, chainId) => {
|
|
2813
|
+
const hasExplicitRevoker = acpConfig?.defaultRevoker?.[chainId] != null || options.revokerData != null || options.revokerContract != null;
|
|
2814
|
+
if (hasExplicitRevoker)
|
|
2815
|
+
return applyACPDefaults(options, acpConfig, chainId);
|
|
2816
|
+
const served = await getAclServedAddresses(publicClient, chainId);
|
|
2817
|
+
const effectiveConfig = served.defaultRevoker != null ? { ...acpConfig, defaultRevoker: { ...acpConfig?.defaultRevoker, [chainId]: served.defaultRevoker } } : acpConfig;
|
|
2818
|
+
return applyACPDefaults(options, effectiveConfig, chainId);
|
|
2819
|
+
};
|
|
2820
|
+
var revokeACP = async (acp, walletClient) => {
|
|
2821
|
+
if (acp.revokerContract === viem.zeroAddress || acp.revokerData === 0) {
|
|
2822
|
+
throw new Error("ACP is not revocable: it has no revoker (revokerContract/revokerData unset)");
|
|
2823
|
+
}
|
|
2824
|
+
if (walletClient.account == null)
|
|
2825
|
+
throw new Error("Missing walletClient account");
|
|
2826
|
+
if (walletClient.account.address.toLowerCase() !== acp.issuer.toLowerCase()) {
|
|
2827
|
+
throw new Error("Only the acp issuer can revoke it");
|
|
2828
|
+
}
|
|
2829
|
+
return walletClient.writeContract({
|
|
2830
|
+
address: acp.revokerContract,
|
|
2831
|
+
abi: ACP_VALIDATOR_ABI,
|
|
2832
|
+
functionName: "revokeSingle",
|
|
2833
|
+
args: [BigInt(acp.revokerData)],
|
|
2834
|
+
account: walletClient.account,
|
|
2835
|
+
chain: walletClient.chain
|
|
2836
|
+
});
|
|
2837
|
+
};
|
|
2838
|
+
var revokeAllACPs = async (walletClient, publicClient, revokerContract) => {
|
|
2839
|
+
if (walletClient.account == null)
|
|
2840
|
+
throw new Error("Missing walletClient account");
|
|
2841
|
+
let revoker = revokerContract;
|
|
2842
|
+
if (revoker == null) {
|
|
2843
|
+
const chainId = await publicClient.getChainId();
|
|
2844
|
+
const active = getActiveACP2(chainId, walletClient.account.address);
|
|
2845
|
+
revoker = active?.revokerContract;
|
|
2846
|
+
}
|
|
2847
|
+
if (revoker == null || revoker === viem.zeroAddress) {
|
|
2848
|
+
throw new Error("No revoker contract: pass `revokerContract` or activate a revocable acp first");
|
|
2849
|
+
}
|
|
2850
|
+
return walletClient.writeContract({
|
|
2851
|
+
address: revoker,
|
|
2852
|
+
abi: ACP_VALIDATOR_ABI,
|
|
2853
|
+
functionName: "revokeAllExisting",
|
|
2854
|
+
args: [],
|
|
2855
|
+
account: walletClient.account,
|
|
2856
|
+
chain: walletClient.chain
|
|
2857
|
+
});
|
|
2858
|
+
};
|
|
2859
|
+
var isACPRevoked = async (acp, publicClient) => {
|
|
2860
|
+
if (acp.revokerContract === viem.zeroAddress || acp.revokerData === 0)
|
|
2861
|
+
return false;
|
|
2862
|
+
return publicClient.readContract({
|
|
2863
|
+
address: acp.revokerContract,
|
|
2864
|
+
abi: ACP_VALIDATOR_ABI,
|
|
2865
|
+
functionName: "disabled",
|
|
2866
|
+
args: [acp.issuer, BigInt(acp.revokerData)]
|
|
2867
|
+
});
|
|
2868
|
+
};
|
|
2869
|
+
var ACP_SHARE_REGISTRY_ABI = viem.parseAbi([
|
|
2870
|
+
"struct ACP { address issuer; uint64 expiration; address recipient; uint256 revokerData; address revokerContract; uint8 scope; address[] contracts; bytes32[] handles; bytes32 sealingKey; bytes issuerSignature; bytes recipientSignature; }",
|
|
2871
|
+
"function share(ACP calldata acp) external returns (bytes32)",
|
|
2872
|
+
"function removeShare(bytes32 shareId) external",
|
|
2873
|
+
"function sharesFor(address recipient) external view returns (ACP[] memory)",
|
|
2874
|
+
"function getShare(bytes32 shareId) external view returns (ACP memory)",
|
|
2875
|
+
"function isShareValid(bytes32 shareId) external view returns (bool)"
|
|
2876
|
+
]);
|
|
2877
|
+
var ACP_TUPLE = [
|
|
2878
|
+
{
|
|
2879
|
+
type: "tuple",
|
|
2880
|
+
components: [
|
|
2881
|
+
{ name: "issuer", type: "address" },
|
|
2882
|
+
{ name: "expiration", type: "uint64" },
|
|
2883
|
+
{ name: "recipient", type: "address" },
|
|
2884
|
+
{ name: "revokerData", type: "uint256" },
|
|
2885
|
+
{ name: "revokerContract", type: "address" },
|
|
2886
|
+
{ name: "scope", type: "uint8" },
|
|
2887
|
+
{ name: "contracts", type: "address[]" },
|
|
2888
|
+
{ name: "handles", type: "bytes32[]" },
|
|
2889
|
+
{ name: "sealingKey", type: "bytes32" },
|
|
2890
|
+
{ name: "issuerSignature", type: "bytes" },
|
|
2891
|
+
{ name: "recipientSignature", type: "bytes" }
|
|
2892
|
+
]
|
|
2893
|
+
}
|
|
2894
|
+
];
|
|
2895
|
+
var ZERO_BYTES32 = `0x${"0".repeat(64)}`;
|
|
2896
|
+
var toChainShare = (acp) => {
|
|
2897
|
+
const pub = ACPUtils.getPublic(acp, true);
|
|
2898
|
+
return {
|
|
2899
|
+
...pub,
|
|
2900
|
+
expiration: BigInt(pub.expiration),
|
|
2901
|
+
revokerData: BigInt(pub.revokerData),
|
|
2902
|
+
sealingKey: ZERO_BYTES32,
|
|
2903
|
+
recipientSignature: "0x"
|
|
2904
|
+
};
|
|
2905
|
+
};
|
|
2906
|
+
var computeShareId = (acp) => {
|
|
2907
|
+
const p = toChainShare(acp);
|
|
2908
|
+
return viem.keccak256(viem.encodeAbiParameters(ACP_TUPLE, [p]));
|
|
2909
|
+
};
|
|
2910
|
+
var shareOnChain = async (acp, walletClient, registry) => {
|
|
2911
|
+
if (acp.type !== "sharing") {
|
|
2912
|
+
throw new Error(`Cannot share a '${acp.type}' ACP on-chain \u2014 only 'sharing' ACPs are shareable.`);
|
|
2913
|
+
}
|
|
2914
|
+
if (acp.issuerSignature === "0x") {
|
|
2915
|
+
throw new Error("Cannot share an unsigned sharing ACP \u2014 sign it first.");
|
|
2916
|
+
}
|
|
2917
|
+
if (walletClient.account == null)
|
|
2918
|
+
throw new Error("Missing walletClient account");
|
|
2919
|
+
if (walletClient.account.address.toLowerCase() !== acp.issuer.toLowerCase()) {
|
|
2920
|
+
throw new Error("Only the ACP issuer can share it on-chain");
|
|
2921
|
+
}
|
|
2922
|
+
const txHash = await walletClient.writeContract({
|
|
2923
|
+
address: registry,
|
|
2924
|
+
abi: ACP_SHARE_REGISTRY_ABI,
|
|
2925
|
+
functionName: "share",
|
|
2926
|
+
args: [toChainShare(acp)],
|
|
2927
|
+
account: walletClient.account,
|
|
2928
|
+
chain: walletClient.chain ?? null
|
|
2929
|
+
});
|
|
2930
|
+
return { txHash, shareId: computeShareId(acp) };
|
|
2931
|
+
};
|
|
2932
|
+
var getIncomingShares = async (publicClient, registry, recipient) => {
|
|
2933
|
+
const raw = await publicClient.readContract({
|
|
2934
|
+
address: registry,
|
|
2935
|
+
abi: ACP_SHARE_REGISTRY_ABI,
|
|
2936
|
+
functionName: "sharesFor",
|
|
2937
|
+
args: [recipient]
|
|
2938
|
+
});
|
|
2939
|
+
return raw.map((s) => ({
|
|
2940
|
+
shareId: viem.keccak256(viem.encodeAbiParameters(ACP_TUPLE, [s])),
|
|
2941
|
+
issuer: s.issuer,
|
|
2942
|
+
expiration: Number(s.expiration),
|
|
2943
|
+
recipient: s.recipient,
|
|
2944
|
+
revokerData: Number(s.revokerData),
|
|
2945
|
+
revokerContract: s.revokerContract,
|
|
2946
|
+
scope: Number(s.scope),
|
|
2947
|
+
contracts: [...s.contracts],
|
|
2948
|
+
handles: [...s.handles],
|
|
2949
|
+
issuerSignature: s.issuerSignature
|
|
2950
|
+
}));
|
|
2951
|
+
};
|
|
2952
|
+
var importFromChain = async (share, publicClient, walletClient) => {
|
|
2953
|
+
const { shareId: _shareId, ...options } = share;
|
|
2954
|
+
return importShared({ ...options, type: "sharing" }, publicClient, walletClient);
|
|
2955
|
+
};
|
|
2956
|
+
var removeShareOnChain = async (shareId, walletClient, registry) => {
|
|
2957
|
+
if (walletClient.account == null)
|
|
2958
|
+
throw new Error("Missing walletClient account");
|
|
2959
|
+
return walletClient.writeContract({
|
|
2960
|
+
address: registry,
|
|
2961
|
+
abi: ACP_SHARE_REGISTRY_ABI,
|
|
2962
|
+
functionName: "removeShare",
|
|
2963
|
+
args: [shareId],
|
|
2964
|
+
account: walletClient.account,
|
|
2965
|
+
chain: walletClient.chain ?? null
|
|
2966
|
+
});
|
|
2967
|
+
};
|
|
2968
|
+
var removeACP2 = async (chainId, account, hash) => acpStore.removeACP(chainId, account, hash);
|
|
2969
|
+
var removeActiveACP = async (chainId, account) => acpStore.removeActiveACPHash(chainId, account);
|
|
2970
|
+
var acps = {
|
|
2971
|
+
getSnapshot: acpStore.store.getState,
|
|
2972
|
+
subscribe: acpStore.store.subscribe,
|
|
2774
2973
|
createSelf,
|
|
2775
2974
|
createSharing,
|
|
2776
2975
|
importShared,
|
|
2777
|
-
|
|
2778
|
-
|
|
2976
|
+
getOrCreateSelfACP,
|
|
2977
|
+
getOrCreateSharingACP,
|
|
2779
2978
|
getHash,
|
|
2780
2979
|
export: exportShared,
|
|
2781
2980
|
serialize,
|
|
2782
2981
|
deserialize,
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2982
|
+
getACP: getACP2,
|
|
2983
|
+
getACPs: getACPs2,
|
|
2984
|
+
getActiveACP: getActiveACP2,
|
|
2985
|
+
getActiveACPHash: getActiveACPHash2,
|
|
2986
|
+
removeACP: removeACP2,
|
|
2987
|
+
selectActiveACP,
|
|
2988
|
+
removeActiveACP,
|
|
2989
|
+
revokeACP,
|
|
2990
|
+
revokeAllACPs,
|
|
2991
|
+
isACPRevoked,
|
|
2992
|
+
shareOnChain,
|
|
2993
|
+
getIncomingShares,
|
|
2994
|
+
importFromChain,
|
|
2995
|
+
removeShareOnChain,
|
|
2996
|
+
computeShareId,
|
|
2997
|
+
applyACPDefaults,
|
|
2998
|
+
applyACPDefaultsFromChain,
|
|
2999
|
+
getAclServedAddresses,
|
|
3000
|
+
clearAclServedAddresses
|
|
2790
3001
|
};
|
|
2791
3002
|
function uint160ToAddress(uint160) {
|
|
2792
3003
|
const hexStr = uint160.toString(16).padStart(40, "0");
|
|
@@ -2849,13 +3060,16 @@ var MockThresholdNetworkAbi = [
|
|
|
2849
3060
|
{
|
|
2850
3061
|
name: "permission",
|
|
2851
3062
|
type: "tuple",
|
|
2852
|
-
internalType: "struct
|
|
3063
|
+
internalType: "struct ACPermission",
|
|
2853
3064
|
components: [
|
|
2854
3065
|
{ name: "issuer", type: "address", internalType: "address" },
|
|
2855
3066
|
{ name: "expiration", type: "uint64", internalType: "uint64" },
|
|
2856
3067
|
{ name: "recipient", type: "address", internalType: "address" },
|
|
2857
|
-
{ name: "
|
|
2858
|
-
{ name: "
|
|
3068
|
+
{ name: "revokerData", type: "uint256", internalType: "uint256" },
|
|
3069
|
+
{ name: "revokerContract", type: "address", internalType: "address" },
|
|
3070
|
+
{ name: "scope", type: "uint8", internalType: "uint8" },
|
|
3071
|
+
{ name: "contracts", type: "address[]", internalType: "address[]" },
|
|
3072
|
+
{ name: "handles", type: "bytes32[]", internalType: "bytes32[]" },
|
|
2859
3073
|
{ name: "sealingKey", type: "bytes32", internalType: "bytes32" },
|
|
2860
3074
|
{ name: "issuerSignature", type: "bytes", internalType: "bytes" },
|
|
2861
3075
|
{ name: "recipientSignature", type: "bytes", internalType: "bytes" }
|
|
@@ -2878,13 +3092,16 @@ var MockThresholdNetworkAbi = [
|
|
|
2878
3092
|
{
|
|
2879
3093
|
name: "permission",
|
|
2880
3094
|
type: "tuple",
|
|
2881
|
-
internalType: "struct
|
|
3095
|
+
internalType: "struct ACPermission",
|
|
2882
3096
|
components: [
|
|
2883
3097
|
{ name: "issuer", type: "address", internalType: "address" },
|
|
2884
3098
|
{ name: "expiration", type: "uint64", internalType: "uint64" },
|
|
2885
3099
|
{ name: "recipient", type: "address", internalType: "address" },
|
|
2886
|
-
{ name: "
|
|
2887
|
-
{ name: "
|
|
3100
|
+
{ name: "revokerData", type: "uint256", internalType: "uint256" },
|
|
3101
|
+
{ name: "revokerContract", type: "address", internalType: "address" },
|
|
3102
|
+
{ name: "scope", type: "uint8", internalType: "uint8" },
|
|
3103
|
+
{ name: "contracts", type: "address[]", internalType: "address[]" },
|
|
3104
|
+
{ name: "handles", type: "bytes32[]", internalType: "bytes32[]" },
|
|
2888
3105
|
{ name: "sealingKey", type: "bytes32", internalType: "bytes32" },
|
|
2889
3106
|
{ name: "issuerSignature", type: "bytes", internalType: "bytes" },
|
|
2890
3107
|
{ name: "recipientSignature", type: "bytes", internalType: "bytes" }
|
|
@@ -2949,19 +3166,22 @@ var MockThresholdNetworkAbi = [
|
|
|
2949
3166
|
},
|
|
2950
3167
|
{
|
|
2951
3168
|
type: "function",
|
|
2952
|
-
name: "
|
|
3169
|
+
name: "decryptForTxWithACP",
|
|
2953
3170
|
inputs: [
|
|
2954
3171
|
{ name: "ctHash", type: "uint256", internalType: "uint256" },
|
|
2955
3172
|
{
|
|
2956
3173
|
name: "permission",
|
|
2957
3174
|
type: "tuple",
|
|
2958
|
-
internalType: "struct
|
|
3175
|
+
internalType: "struct ACPermission",
|
|
2959
3176
|
components: [
|
|
2960
3177
|
{ name: "issuer", type: "address", internalType: "address" },
|
|
2961
3178
|
{ name: "expiration", type: "uint64", internalType: "uint64" },
|
|
2962
3179
|
{ name: "recipient", type: "address", internalType: "address" },
|
|
2963
|
-
{ name: "
|
|
2964
|
-
{ name: "
|
|
3180
|
+
{ name: "revokerData", type: "uint256", internalType: "uint256" },
|
|
3181
|
+
{ name: "revokerContract", type: "address", internalType: "address" },
|
|
3182
|
+
{ name: "scope", type: "uint8", internalType: "uint8" },
|
|
3183
|
+
{ name: "contracts", type: "address[]", internalType: "address[]" },
|
|
3184
|
+
{ name: "handles", type: "bytes32[]", internalType: "bytes32[]" },
|
|
2965
3185
|
{ name: "sealingKey", type: "bytes32", internalType: "bytes32" },
|
|
2966
3186
|
{ name: "issuerSignature", type: "bytes", internalType: "bytes" },
|
|
2967
3187
|
{ name: "recipientSignature", type: "bytes", internalType: "bytes" }
|
|
@@ -2977,7 +3197,7 @@ var MockThresholdNetworkAbi = [
|
|
|
2977
3197
|
},
|
|
2978
3198
|
{
|
|
2979
3199
|
type: "function",
|
|
2980
|
-
name: "
|
|
3200
|
+
name: "decryptForTxWithoutACP",
|
|
2981
3201
|
inputs: [{ name: "ctHash", type: "uint256", internalType: "uint256" }],
|
|
2982
3202
|
outputs: [
|
|
2983
3203
|
{ name: "allowed", type: "bool", internalType: "bool" },
|
|
@@ -2989,12 +3209,12 @@ var MockThresholdNetworkAbi = [
|
|
|
2989
3209
|
];
|
|
2990
3210
|
|
|
2991
3211
|
// core/decrypt/cofheMocksDecryptForView.ts
|
|
2992
|
-
async function cofheMocksDecryptForView(ctHash, utype,
|
|
2993
|
-
const
|
|
3212
|
+
async function cofheMocksDecryptForView(ctHash, utype, acp, publicClient) {
|
|
3213
|
+
const wireAcp = ACPUtils.getPublic(acp, true);
|
|
2994
3214
|
const permissionWithBigInts = {
|
|
2995
|
-
...
|
|
2996
|
-
expiration: BigInt(
|
|
2997
|
-
|
|
3215
|
+
...wireAcp,
|
|
3216
|
+
expiration: BigInt(wireAcp.expiration),
|
|
3217
|
+
revokerData: BigInt(wireAcp.revokerData)
|
|
2998
3218
|
};
|
|
2999
3219
|
const [allowed, error, result] = await publicClient.readContract({
|
|
3000
3220
|
address: MOCKS_THRESHOLD_NETWORK_ADDRESS,
|
|
@@ -3015,7 +3235,7 @@ async function cofheMocksDecryptForView(ctHash, utype, permit, publicClient) {
|
|
|
3015
3235
|
});
|
|
3016
3236
|
}
|
|
3017
3237
|
const sealedBigInt = BigInt(result);
|
|
3018
|
-
const sealingKeyBigInt = BigInt(
|
|
3238
|
+
const sealingKeyBigInt = BigInt(acp.sealingKey);
|
|
3019
3239
|
const unsealed = sealedBigInt ^ sealingKeyBigInt;
|
|
3020
3240
|
return unsealed;
|
|
3021
3241
|
}
|
|
@@ -3058,11 +3278,61 @@ function computeMinuteRampPollIntervalMs(elapsedMs, params) {
|
|
|
3058
3278
|
return Math.min(params.maxIntervalMs, Math.max(params.minIntervalMs, intervalMs));
|
|
3059
3279
|
}
|
|
3060
3280
|
|
|
3281
|
+
// core/decrypt/apiError.ts
|
|
3282
|
+
var BACKEND_ERROR_CODE_TO_COFHE_ERROR_CODE = {
|
|
3283
|
+
bad_request: "BAD_REQUEST" /* BadRequest */,
|
|
3284
|
+
unknown_chain: "UNKNOWN_CHAIN" /* UnknownChain */,
|
|
3285
|
+
acp_malformed: "ACP_MALFORMED" /* ACPMalformed */,
|
|
3286
|
+
acp_denied: "ACP_DENIED" /* ACPDenied */,
|
|
3287
|
+
// ACP-era backends fold revoked into denied
|
|
3288
|
+
acp_expired: "ACP_EXPIRED" /* ACPExpired */,
|
|
3289
|
+
acp_invalid: "ACP_INVALID" /* ACPInvalid */,
|
|
3290
|
+
acp_required: "ACP_REQUIRED" /* ACPRequired */,
|
|
3291
|
+
acp_verifier_error: "ACP_VERIFIER_ERROR" /* ACPVerifierError */,
|
|
3292
|
+
acp_verifier_timeout: "ACP_VERIFIER_TIMEOUT" /* ACPVerifierTimeout */,
|
|
3293
|
+
not_publicly_allowed: "NOT_PUBLICLY_ALLOWED" /* NotPubliclyAllowed */,
|
|
3294
|
+
ct_not_found: "CT_NOT_FOUND" /* CtNotFound */,
|
|
3295
|
+
unsupported_security_zone: "UNSUPPORTED_SECURITY_ZONE" /* UnsupportedSecurityZone */,
|
|
3296
|
+
unsupported_type: "UNSUPPORTED_TYPE" /* UnsupportedType */,
|
|
3297
|
+
internal_error: "INTERNAL_ERROR" /* InternalError */,
|
|
3298
|
+
signing_failed: "SIGNING_FAILED" /* SigningFailed */,
|
|
3299
|
+
ct_source_error: "CT_SOURCE_ERROR" /* CtSourceError */,
|
|
3300
|
+
ct_source_timeout: "CT_SOURCE_TIMEOUT" /* CtSourceTimeout */,
|
|
3301
|
+
seal_failed: "SEAL_FAILED" /* SealFailed */
|
|
3302
|
+
};
|
|
3303
|
+
function isBackendApiErrorCode(value) {
|
|
3304
|
+
return value in BACKEND_ERROR_CODE_TO_COFHE_ERROR_CODE;
|
|
3305
|
+
}
|
|
3306
|
+
async function parseApiErrorResponseBody(response) {
|
|
3307
|
+
let errorMessage = `HTTP ${response.status}`;
|
|
3308
|
+
let apiErrorCode;
|
|
3309
|
+
try {
|
|
3310
|
+
const body = await response.json();
|
|
3311
|
+
if (body && typeof body === "object") {
|
|
3312
|
+
const record = body;
|
|
3313
|
+
if (typeof record.error === "string" && record.error.length > 0) {
|
|
3314
|
+
apiErrorCode = record.error;
|
|
3315
|
+
}
|
|
3316
|
+
if (typeof record.error_message === "string" && record.error_message.length > 0) {
|
|
3317
|
+
errorMessage = record.error_message;
|
|
3318
|
+
} else if (typeof record.message === "string" && record.message.length > 0) {
|
|
3319
|
+
errorMessage = record.message;
|
|
3320
|
+
}
|
|
3321
|
+
}
|
|
3322
|
+
} catch {
|
|
3323
|
+
errorMessage = response.statusText || errorMessage;
|
|
3324
|
+
}
|
|
3325
|
+
return { apiErrorCode, errorMessage };
|
|
3326
|
+
}
|
|
3327
|
+
function mapApiErrorCodeToCofheErrorCode(apiErrorCode, fallback) {
|
|
3328
|
+
if (apiErrorCode && isBackendApiErrorCode(apiErrorCode)) {
|
|
3329
|
+
return BACKEND_ERROR_CODE_TO_COFHE_ERROR_CODE[apiErrorCode];
|
|
3330
|
+
}
|
|
3331
|
+
return fallback;
|
|
3332
|
+
}
|
|
3333
|
+
|
|
3061
3334
|
// core/decrypt/submitRetry.ts
|
|
3062
3335
|
var DEFAULT_404_RETRY_TIMEOUT_MS = 1e4;
|
|
3063
|
-
function isRetryableSubmitStatus(status) {
|
|
3064
|
-
return status === 204 || status === 404;
|
|
3065
|
-
}
|
|
3066
3336
|
function normalize404RetryTimeoutMs(params) {
|
|
3067
3337
|
const { timeoutMs, operationLabel, errorCode } = params;
|
|
3068
3338
|
if (timeoutMs === void 0)
|
|
@@ -3079,32 +3349,24 @@ function normalize404RetryTimeoutMs(params) {
|
|
|
3079
3349
|
return timeoutMs;
|
|
3080
3350
|
}
|
|
3081
3351
|
async function classifySubmitResponse(params) {
|
|
3082
|
-
const { response,
|
|
3083
|
-
if (
|
|
3084
|
-
return { kind: "retryable", status:
|
|
3352
|
+
const { response, fallbackErrorCode } = params;
|
|
3353
|
+
if (response.status === 204) {
|
|
3354
|
+
return { kind: "retryable", status: 204 };
|
|
3085
3355
|
}
|
|
3086
3356
|
if (response.ok) {
|
|
3087
3357
|
return { kind: "parse-json" };
|
|
3088
3358
|
}
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
const maybeErrorMessage = extractErrorMessage?.(errorBody);
|
|
3093
|
-
if (typeof maybeErrorMessage === "string" && maybeErrorMessage.length > 0) {
|
|
3094
|
-
errorMessage = maybeErrorMessage;
|
|
3095
|
-
} else if (errorBody && typeof errorBody === "object") {
|
|
3096
|
-
const defaultMessage = errorBody.error_message;
|
|
3097
|
-
const fallbackMessage = errorBody.message;
|
|
3098
|
-
if (typeof defaultMessage === "string" && defaultMessage.length > 0) {
|
|
3099
|
-
errorMessage = defaultMessage;
|
|
3100
|
-
} else if (typeof fallbackMessage === "string" && fallbackMessage.length > 0) {
|
|
3101
|
-
errorMessage = fallbackMessage;
|
|
3102
|
-
}
|
|
3103
|
-
}
|
|
3104
|
-
} catch {
|
|
3105
|
-
errorMessage = response.statusText || errorMessage;
|
|
3359
|
+
const { apiErrorCode, errorMessage } = await parseApiErrorResponseBody(response);
|
|
3360
|
+
if (response.status === 404) {
|
|
3361
|
+
return { kind: "retryable", status: 404, apiErrorMessage: errorMessage };
|
|
3106
3362
|
}
|
|
3107
|
-
return {
|
|
3363
|
+
return {
|
|
3364
|
+
kind: "fatal-http",
|
|
3365
|
+
status: response.status,
|
|
3366
|
+
cofheErrorCode: mapApiErrorCodeToCofheErrorCode(apiErrorCode, fallbackErrorCode),
|
|
3367
|
+
apiErrorCode,
|
|
3368
|
+
errorMessage
|
|
3369
|
+
};
|
|
3108
3370
|
}
|
|
3109
3371
|
function throwIfSubmitRetryTimedOut(params) {
|
|
3110
3372
|
const {
|
|
@@ -3116,12 +3378,14 @@ function throwIfSubmitRetryTimedOut(params) {
|
|
|
3116
3378
|
overallTimeoutMs,
|
|
3117
3379
|
thresholdNetworkUrl,
|
|
3118
3380
|
body,
|
|
3119
|
-
attemptIndex
|
|
3381
|
+
attemptIndex,
|
|
3382
|
+
lastKnownErrorMessage
|
|
3120
3383
|
} = params;
|
|
3121
3384
|
if (status === 404 && elapsedMs > retry404TimeoutMs) {
|
|
3122
3385
|
throw new CofheError({
|
|
3123
|
-
code:
|
|
3124
|
-
|
|
3386
|
+
code: "CT_NOT_FOUND" /* CtNotFound */,
|
|
3387
|
+
apiErrorCode: "ct_not_found",
|
|
3388
|
+
message: `${operationLabel} ciphertext not found after retrying for ${retry404TimeoutMs}ms` + (lastKnownErrorMessage ? `: ${lastKnownErrorMessage}` : ""),
|
|
3125
3389
|
hint: "The ciphertext may not be indexed yet. Increase set404RetryTimeout(...) if the backend is slow to index ciphertexts.",
|
|
3126
3390
|
context: {
|
|
3127
3391
|
thresholdNetworkUrl,
|
|
@@ -3147,6 +3411,62 @@ function throwIfSubmitRetryTimedOut(params) {
|
|
|
3147
3411
|
});
|
|
3148
3412
|
}
|
|
3149
3413
|
}
|
|
3414
|
+
function normalizeTnSignature(signature) {
|
|
3415
|
+
if (typeof signature !== "string") {
|
|
3416
|
+
throw new CofheError({
|
|
3417
|
+
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3418
|
+
message: "decrypt response missing signature",
|
|
3419
|
+
context: {
|
|
3420
|
+
signature
|
|
3421
|
+
}
|
|
3422
|
+
});
|
|
3423
|
+
}
|
|
3424
|
+
const trimmed = signature.trim();
|
|
3425
|
+
if (trimmed.length === 0) {
|
|
3426
|
+
throw new CofheError({
|
|
3427
|
+
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3428
|
+
message: "decrypt response returned empty signature"
|
|
3429
|
+
});
|
|
3430
|
+
}
|
|
3431
|
+
const prefixed = trimmed.startsWith("0x") ? trimmed : `0x${trimmed}`;
|
|
3432
|
+
const parsed = viem.parseSignature(prefixed);
|
|
3433
|
+
return viem.serializeSignature(parsed);
|
|
3434
|
+
}
|
|
3435
|
+
function parseDecryptedBytesToBigInt(decrypted) {
|
|
3436
|
+
if (!Array.isArray(decrypted)) {
|
|
3437
|
+
throw new CofheError({
|
|
3438
|
+
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3439
|
+
message: "decrypt response field <decrypted> must be a byte array",
|
|
3440
|
+
context: {
|
|
3441
|
+
decrypted
|
|
3442
|
+
}
|
|
3443
|
+
});
|
|
3444
|
+
}
|
|
3445
|
+
if (decrypted.length === 0) {
|
|
3446
|
+
throw new CofheError({
|
|
3447
|
+
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3448
|
+
message: "decrypt response field <decrypted> was an empty byte array",
|
|
3449
|
+
context: {
|
|
3450
|
+
decrypted
|
|
3451
|
+
}
|
|
3452
|
+
});
|
|
3453
|
+
}
|
|
3454
|
+
let hex = "";
|
|
3455
|
+
for (const b of decrypted) {
|
|
3456
|
+
if (typeof b !== "number" || !Number.isInteger(b) || b < 0 || b > 255) {
|
|
3457
|
+
throw new CofheError({
|
|
3458
|
+
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3459
|
+
message: "decrypt response field <decrypted> contained a non-byte value",
|
|
3460
|
+
context: {
|
|
3461
|
+
badElement: b,
|
|
3462
|
+
decrypted
|
|
3463
|
+
}
|
|
3464
|
+
});
|
|
3465
|
+
}
|
|
3466
|
+
hex += b.toString(16).padStart(2, "0");
|
|
3467
|
+
}
|
|
3468
|
+
return BigInt(`0x${hex}`);
|
|
3469
|
+
}
|
|
3150
3470
|
|
|
3151
3471
|
// core/decrypt/tnSealOutputV2.ts
|
|
3152
3472
|
var POLL_INTERVAL_MS = 1e3;
|
|
@@ -3209,13 +3529,14 @@ function parseCompletedSealOutputResponse(params) {
|
|
|
3209
3529
|
}
|
|
3210
3530
|
return convertSealedData(sealed);
|
|
3211
3531
|
}
|
|
3212
|
-
async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId,
|
|
3532
|
+
async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, acp, overallStartTime, retry404TimeoutMs, onPoll) {
|
|
3213
3533
|
const body = {
|
|
3214
3534
|
ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
|
|
3215
3535
|
host_chain_id: chainId,
|
|
3216
|
-
|
|
3536
|
+
acp
|
|
3217
3537
|
};
|
|
3218
3538
|
let attemptIndex = 0;
|
|
3539
|
+
let last404ApiErrorMessage;
|
|
3219
3540
|
for (; ; ) {
|
|
3220
3541
|
let response;
|
|
3221
3542
|
try {
|
|
@@ -3243,16 +3564,19 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, per
|
|
|
3243
3564
|
}
|
|
3244
3565
|
});
|
|
3245
3566
|
}
|
|
3246
|
-
const responseClassification = await classifySubmitResponse({
|
|
3567
|
+
const responseClassification = await classifySubmitResponse({
|
|
3568
|
+
response,
|
|
3569
|
+
fallbackErrorCode: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */
|
|
3570
|
+
});
|
|
3247
3571
|
if (responseClassification.kind === "fatal-http") {
|
|
3248
3572
|
throw new CofheError({
|
|
3249
|
-
code:
|
|
3573
|
+
code: responseClassification.cofheErrorCode,
|
|
3574
|
+
apiErrorCode: responseClassification.apiErrorCode,
|
|
3250
3575
|
message: `sealOutput request failed: ${responseClassification.errorMessage}`,
|
|
3251
3576
|
hint: "Check the threshold network URL and request parameters.",
|
|
3252
3577
|
context: {
|
|
3253
3578
|
thresholdNetworkUrl,
|
|
3254
|
-
status:
|
|
3255
|
-
statusText: response.statusText,
|
|
3579
|
+
status: responseClassification.status,
|
|
3256
3580
|
body,
|
|
3257
3581
|
attemptIndex
|
|
3258
3582
|
}
|
|
@@ -3298,6 +3622,9 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, per
|
|
|
3298
3622
|
}
|
|
3299
3623
|
});
|
|
3300
3624
|
}
|
|
3625
|
+
if (responseClassification.status === 404) {
|
|
3626
|
+
last404ApiErrorMessage = responseClassification.apiErrorMessage;
|
|
3627
|
+
}
|
|
3301
3628
|
const elapsedMs = Date.now() - overallStartTime;
|
|
3302
3629
|
throwIfSubmitRetryTimedOut({
|
|
3303
3630
|
operationLabel: "sealOutput",
|
|
@@ -3308,7 +3635,8 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, per
|
|
|
3308
3635
|
overallTimeoutMs: SEAL_OUTPUT_TIMEOUT_MS,
|
|
3309
3636
|
thresholdNetworkUrl,
|
|
3310
3637
|
body,
|
|
3311
|
-
attemptIndex
|
|
3638
|
+
attemptIndex,
|
|
3639
|
+
lastKnownErrorMessage: last404ApiErrorMessage
|
|
3312
3640
|
});
|
|
3313
3641
|
onPoll?.({
|
|
3314
3642
|
operation: "sealoutput",
|
|
@@ -3386,15 +3714,10 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStart
|
|
|
3386
3714
|
});
|
|
3387
3715
|
}
|
|
3388
3716
|
if (!response.ok) {
|
|
3389
|
-
|
|
3390
|
-
try {
|
|
3391
|
-
const errorBody = await response.json();
|
|
3392
|
-
errorMessage = errorBody.error_message || errorBody.message || errorMessage;
|
|
3393
|
-
} catch {
|
|
3394
|
-
errorMessage = response.statusText || errorMessage;
|
|
3395
|
-
}
|
|
3717
|
+
const { apiErrorCode, errorMessage } = await parseApiErrorResponseBody(response);
|
|
3396
3718
|
throw new CofheError({
|
|
3397
|
-
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed
|
|
3719
|
+
code: mapApiErrorCodeToCofheErrorCode(apiErrorCode, "SEAL_OUTPUT_FAILED" /* SealOutputFailed */),
|
|
3720
|
+
apiErrorCode,
|
|
3398
3721
|
message: `sealOutput status poll failed: ${errorMessage}`,
|
|
3399
3722
|
context: {
|
|
3400
3723
|
thresholdNetworkUrl,
|
|
@@ -3438,7 +3761,7 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStart
|
|
|
3438
3761
|
});
|
|
3439
3762
|
}
|
|
3440
3763
|
async function tnSealOutputV2(params) {
|
|
3441
|
-
const { thresholdNetworkUrl, ctHash, chainId,
|
|
3764
|
+
const { thresholdNetworkUrl, ctHash, chainId, acp, retry404TimeoutMs, onPoll } = params;
|
|
3442
3765
|
const normalized404RetryTimeoutMs = normalize404RetryTimeoutMs({
|
|
3443
3766
|
timeoutMs: retry404TimeoutMs,
|
|
3444
3767
|
operationLabel: "sealOutput",
|
|
@@ -3449,7 +3772,7 @@ async function tnSealOutputV2(params) {
|
|
|
3449
3772
|
thresholdNetworkUrl,
|
|
3450
3773
|
ctHash,
|
|
3451
3774
|
chainId,
|
|
3452
|
-
|
|
3775
|
+
acp,
|
|
3453
3776
|
overallStartTime,
|
|
3454
3777
|
normalized404RetryTimeoutMs,
|
|
3455
3778
|
onPoll
|
|
@@ -3465,8 +3788,8 @@ var DEFAULT_404_RETRY_TIMEOUT_MS2 = 1e4;
|
|
|
3465
3788
|
var DecryptForViewBuilder = class extends BaseBuilder {
|
|
3466
3789
|
ctHash;
|
|
3467
3790
|
utype;
|
|
3468
|
-
|
|
3469
|
-
|
|
3791
|
+
acpHash;
|
|
3792
|
+
acp;
|
|
3470
3793
|
pollCallback;
|
|
3471
3794
|
retry404TimeoutMs = DEFAULT_404_RETRY_TIMEOUT_MS2;
|
|
3472
3795
|
constructor(params) {
|
|
@@ -3480,11 +3803,11 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3480
3803
|
});
|
|
3481
3804
|
this.ctHash = params.ctHash;
|
|
3482
3805
|
this.utype = params.utype;
|
|
3483
|
-
this.
|
|
3484
|
-
this.
|
|
3806
|
+
this.acpHash = params.acpHash;
|
|
3807
|
+
this.acp = params.acp;
|
|
3485
3808
|
}
|
|
3486
3809
|
/**
|
|
3487
|
-
* @param chainId - Chain to decrypt values from. Used to fetch the threshold network URL and use the correct
|
|
3810
|
+
* @param chainId - Chain to decrypt values from. Used to fetch the threshold network URL and use the correct acp.
|
|
3488
3811
|
*
|
|
3489
3812
|
* If not provided, the chainId will be fetched from the connected publicClient.
|
|
3490
3813
|
*
|
|
@@ -3505,7 +3828,7 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3505
3828
|
return this.chainId;
|
|
3506
3829
|
}
|
|
3507
3830
|
/**
|
|
3508
|
-
* @param account - Account to decrypt values from. Used to fetch the correct
|
|
3831
|
+
* @param account - Account to decrypt values from. Used to fetch the correct acp.
|
|
3509
3832
|
*
|
|
3510
3833
|
* If not provided, the account will be fetched from the connected walletClient.
|
|
3511
3834
|
*
|
|
@@ -3542,61 +3865,61 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3542
3865
|
this.retry404TimeoutMs = timeoutMs;
|
|
3543
3866
|
return this;
|
|
3544
3867
|
}
|
|
3545
|
-
|
|
3546
|
-
if (typeof
|
|
3547
|
-
this.
|
|
3548
|
-
this.
|
|
3549
|
-
} else if (
|
|
3550
|
-
this.
|
|
3551
|
-
this.
|
|
3868
|
+
withACP(acpOrACPHash) {
|
|
3869
|
+
if (typeof acpOrACPHash === "string") {
|
|
3870
|
+
this.acpHash = acpOrACPHash;
|
|
3871
|
+
this.acp = void 0;
|
|
3872
|
+
} else if (acpOrACPHash === void 0) {
|
|
3873
|
+
this.acpHash = void 0;
|
|
3874
|
+
this.acp = void 0;
|
|
3552
3875
|
} else {
|
|
3553
|
-
this.
|
|
3554
|
-
this.
|
|
3876
|
+
this.acp = acpOrACPHash;
|
|
3877
|
+
this.acpHash = void 0;
|
|
3555
3878
|
}
|
|
3556
3879
|
return this;
|
|
3557
3880
|
}
|
|
3558
3881
|
/**
|
|
3559
|
-
* @param
|
|
3882
|
+
* @param acpHash - ACP hash to decrypt values from. Used to fetch the correct acp.
|
|
3560
3883
|
*
|
|
3561
|
-
* If not provided, the active
|
|
3562
|
-
* If `
|
|
3884
|
+
* If not provided, the active acp for the chainId and account will be used.
|
|
3885
|
+
* If `setACP()` is called, it will be used regardless of chainId, account, or acpHash.
|
|
3563
3886
|
*
|
|
3564
3887
|
* Example:
|
|
3565
3888
|
* ```typescript
|
|
3566
3889
|
* const unsealed = await client.decryptForView(ctHash, utype)
|
|
3567
|
-
* .
|
|
3890
|
+
* .setACPHash('0x1234567890123456789012345678901234567890')
|
|
3568
3891
|
* .execute();
|
|
3569
3892
|
* ```
|
|
3570
3893
|
*
|
|
3571
3894
|
* @returns The chainable DecryptForViewBuilder instance.
|
|
3572
3895
|
*/
|
|
3573
|
-
/** @deprecated Use `
|
|
3574
|
-
|
|
3575
|
-
return this.
|
|
3896
|
+
/** @deprecated Use `withACP(acpHash)` instead. */
|
|
3897
|
+
setACPHash(acpHash) {
|
|
3898
|
+
return this.withACP(acpHash);
|
|
3576
3899
|
}
|
|
3577
|
-
|
|
3578
|
-
return this.
|
|
3900
|
+
getACPHash() {
|
|
3901
|
+
return this.acpHash;
|
|
3579
3902
|
}
|
|
3580
3903
|
/**
|
|
3581
|
-
* @param
|
|
3904
|
+
* @param acp - ACP to decrypt values with. If provided, it will be used regardless of chainId, account, or acpHash.
|
|
3582
3905
|
*
|
|
3583
|
-
* If not provided, the
|
|
3906
|
+
* If not provided, the acp will be determined by chainId, account, and acpHash.
|
|
3584
3907
|
*
|
|
3585
3908
|
* Example:
|
|
3586
3909
|
* ```typescript
|
|
3587
3910
|
* const unsealed = await client.decryptForView(ctHash, utype)
|
|
3588
|
-
* .
|
|
3911
|
+
* .setACP(acp)
|
|
3589
3912
|
* .execute();
|
|
3590
3913
|
* ```
|
|
3591
3914
|
*
|
|
3592
3915
|
* @returns The chainable DecryptForViewBuilder instance.
|
|
3593
3916
|
*/
|
|
3594
|
-
/** @deprecated Use `
|
|
3595
|
-
|
|
3596
|
-
return this.
|
|
3917
|
+
/** @deprecated Use `withACP(acp)` instead. */
|
|
3918
|
+
setACP(acp) {
|
|
3919
|
+
return this.withACP(acp);
|
|
3597
3920
|
}
|
|
3598
|
-
|
|
3599
|
-
return this.
|
|
3921
|
+
getACP() {
|
|
3922
|
+
return this.acp;
|
|
3600
3923
|
}
|
|
3601
3924
|
async getThresholdNetworkUrl() {
|
|
3602
3925
|
this.assertChainId();
|
|
@@ -3612,77 +3935,77 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3612
3935
|
}
|
|
3613
3936
|
});
|
|
3614
3937
|
}
|
|
3615
|
-
async
|
|
3616
|
-
if (this.
|
|
3617
|
-
return this.
|
|
3938
|
+
async getResolvedACP() {
|
|
3939
|
+
if (this.acp)
|
|
3940
|
+
return this.acp;
|
|
3618
3941
|
this.assertChainId();
|
|
3619
3942
|
this.assertAccount();
|
|
3620
|
-
if (this.
|
|
3621
|
-
const
|
|
3622
|
-
if (!
|
|
3943
|
+
if (this.acpHash) {
|
|
3944
|
+
const acp2 = await acps.getACP(this.chainId, this.account, this.acpHash);
|
|
3945
|
+
if (!acp2) {
|
|
3623
3946
|
throw new CofheError({
|
|
3624
|
-
code: "
|
|
3625
|
-
message: `
|
|
3626
|
-
hint: "Ensure the
|
|
3947
|
+
code: "ACP_NOT_FOUND" /* ACPNotFound */,
|
|
3948
|
+
message: `ACP with hash <${this.acpHash}> not found for account <${this.account}> and chainId <${this.chainId}>`,
|
|
3949
|
+
hint: "Ensure the acp exists and is valid.",
|
|
3627
3950
|
context: {
|
|
3628
3951
|
chainId: this.chainId,
|
|
3629
3952
|
account: this.account,
|
|
3630
|
-
|
|
3953
|
+
acpHash: this.acpHash
|
|
3631
3954
|
}
|
|
3632
3955
|
});
|
|
3633
3956
|
}
|
|
3634
|
-
return
|
|
3957
|
+
return acp2;
|
|
3635
3958
|
}
|
|
3636
|
-
const
|
|
3637
|
-
if (!
|
|
3959
|
+
const acp = await acps.getActiveACP(this.chainId, this.account);
|
|
3960
|
+
if (!acp) {
|
|
3638
3961
|
throw new CofheError({
|
|
3639
|
-
code: "
|
|
3640
|
-
message: `Active
|
|
3641
|
-
hint: "Ensure
|
|
3962
|
+
code: "ACP_NOT_FOUND" /* ACPNotFound */,
|
|
3963
|
+
message: `Active acp not found for chainId <${this.chainId}> and account <${this.account}>`,
|
|
3964
|
+
hint: "Ensure an ACP exists for this account on this chain.",
|
|
3642
3965
|
context: {
|
|
3643
3966
|
chainId: this.chainId,
|
|
3644
3967
|
account: this.account
|
|
3645
3968
|
}
|
|
3646
3969
|
});
|
|
3647
3970
|
}
|
|
3648
|
-
return
|
|
3971
|
+
return acp;
|
|
3649
3972
|
}
|
|
3650
3973
|
/**
|
|
3651
3974
|
* On hardhat, interact with MockZkVerifier contract instead of CoFHE
|
|
3652
3975
|
*/
|
|
3653
|
-
async mocksSealOutput(
|
|
3976
|
+
async mocksSealOutput(acp) {
|
|
3654
3977
|
this.assertPublicClient();
|
|
3655
3978
|
const mocksDecryptDelay = this.config.mocks.decryptDelay;
|
|
3656
3979
|
if (mocksDecryptDelay > 0)
|
|
3657
3980
|
await sleep(mocksDecryptDelay);
|
|
3658
|
-
return cofheMocksDecryptForView(this.ctHash, this.utype,
|
|
3981
|
+
return cofheMocksDecryptForView(this.ctHash, this.utype, acp, this.publicClient);
|
|
3659
3982
|
}
|
|
3660
3983
|
/**
|
|
3661
3984
|
* In the production context, perform a true decryption with the CoFHE coprocessor.
|
|
3662
3985
|
*/
|
|
3663
|
-
async productionSealOutput(
|
|
3986
|
+
async productionSealOutput(acp) {
|
|
3664
3987
|
this.assertChainId();
|
|
3665
3988
|
this.assertPublicClient();
|
|
3666
3989
|
const thresholdNetworkUrl = await this.getThresholdNetworkUrl();
|
|
3667
|
-
const
|
|
3990
|
+
const wireAcp = ACPUtils.getPublic(acp, true);
|
|
3668
3991
|
const sealed = await tnSealOutputV2({
|
|
3669
3992
|
ctHash: this.ctHash,
|
|
3670
3993
|
chainId: this.chainId,
|
|
3671
|
-
|
|
3994
|
+
acp: wireAcp,
|
|
3672
3995
|
thresholdNetworkUrl,
|
|
3673
3996
|
retry404TimeoutMs: this.retry404TimeoutMs,
|
|
3674
3997
|
onPoll: this.pollCallback
|
|
3675
3998
|
});
|
|
3676
|
-
return
|
|
3999
|
+
return ACPUtils.unseal(acp, sealed);
|
|
3677
4000
|
}
|
|
3678
4001
|
/**
|
|
3679
4002
|
* Final step of the decryption process. MUST BE CALLED LAST IN THE CHAIN.
|
|
3680
4003
|
*
|
|
3681
4004
|
* This will:
|
|
3682
|
-
* - Use
|
|
3683
|
-
* - Check
|
|
3684
|
-
* - Call CoFHE `/sealoutput` with the
|
|
3685
|
-
* - Unseal the sealed item with the
|
|
4005
|
+
* - Use an ACP based on provided acp OR chainId + account + acpHash
|
|
4006
|
+
* - Check acp validity
|
|
4007
|
+
* - Call CoFHE `/sealoutput` with the acp, which returns a sealed (encrypted) item
|
|
4008
|
+
* - Unseal the sealed item with the acp
|
|
3686
4009
|
* - Return the unsealed item
|
|
3687
4010
|
*
|
|
3688
4011
|
* Example:
|
|
@@ -3690,7 +4013,7 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3690
4013
|
* const unsealed = await client.decryptForView(ctHash, utype)
|
|
3691
4014
|
* .setChainId(11155111) // optional
|
|
3692
4015
|
* .setAccount('0x123...890') // optional
|
|
3693
|
-
* .
|
|
4016
|
+
* .withACP() // optional
|
|
3694
4017
|
* .execute(); // execute
|
|
3695
4018
|
* ```
|
|
3696
4019
|
*
|
|
@@ -3698,14 +4021,14 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3698
4021
|
*/
|
|
3699
4022
|
async execute() {
|
|
3700
4023
|
this.validateUtypeOrThrow();
|
|
3701
|
-
const
|
|
3702
|
-
|
|
3703
|
-
const chainId =
|
|
4024
|
+
const acp = await this.getResolvedACP();
|
|
4025
|
+
ACPUtils.validate(acp);
|
|
4026
|
+
const chainId = acp._signedDomain.chainId;
|
|
3704
4027
|
let unsealed;
|
|
3705
4028
|
if (chainId === hardhat2.id) {
|
|
3706
|
-
unsealed = await this.mocksSealOutput(
|
|
4029
|
+
unsealed = await this.mocksSealOutput(acp);
|
|
3707
4030
|
} else {
|
|
3708
|
-
unsealed = await this.productionSealOutput(
|
|
4031
|
+
unsealed = await this.productionSealOutput(acp);
|
|
3709
4032
|
}
|
|
3710
4033
|
return convertViaUtype(this.utype, unsealed);
|
|
3711
4034
|
}
|
|
@@ -3713,28 +4036,28 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3713
4036
|
var UINT_TYPE_MASK = 0x7fn;
|
|
3714
4037
|
var TYPE_BYTE_OFFSET = 8n;
|
|
3715
4038
|
var getEncryptionTypeFromCtHash = (ctHash) => Number(ctHash >> TYPE_BYTE_OFFSET & UINT_TYPE_MASK);
|
|
3716
|
-
async function cofheMocksDecryptForTx(ctHash, utype,
|
|
4039
|
+
async function cofheMocksDecryptForTx(ctHash, utype, acp, publicClient) {
|
|
3717
4040
|
let allowed;
|
|
3718
4041
|
let error;
|
|
3719
4042
|
let decryptedValue;
|
|
3720
|
-
if (
|
|
3721
|
-
|
|
4043
|
+
if (acp !== null) {
|
|
4044
|
+
const wireAcp = ACPUtils.getPublic(acp, true);
|
|
3722
4045
|
const permissionWithBigInts = {
|
|
3723
|
-
...
|
|
3724
|
-
expiration: BigInt(
|
|
3725
|
-
|
|
4046
|
+
...wireAcp,
|
|
4047
|
+
expiration: BigInt(wireAcp.expiration),
|
|
4048
|
+
revokerData: BigInt(wireAcp.revokerData)
|
|
3726
4049
|
};
|
|
3727
4050
|
[allowed, error, decryptedValue] = await publicClient.readContract({
|
|
3728
4051
|
address: MOCKS_THRESHOLD_NETWORK_ADDRESS,
|
|
3729
4052
|
abi: MockThresholdNetworkAbi,
|
|
3730
|
-
functionName: "
|
|
4053
|
+
functionName: "decryptForTxWithACP",
|
|
3731
4054
|
args: [BigInt(ctHash), permissionWithBigInts]
|
|
3732
4055
|
});
|
|
3733
4056
|
} else {
|
|
3734
4057
|
[allowed, error, decryptedValue] = await publicClient.readContract({
|
|
3735
4058
|
address: MOCKS_THRESHOLD_NETWORK_ADDRESS,
|
|
3736
4059
|
abi: MockThresholdNetworkAbi,
|
|
3737
|
-
functionName: "
|
|
4060
|
+
functionName: "decryptForTxWithoutACP",
|
|
3738
4061
|
args: [BigInt(ctHash)]
|
|
3739
4062
|
});
|
|
3740
4063
|
}
|
|
@@ -3769,62 +4092,6 @@ async function cofheMocksDecryptForTx(ctHash, utype, permit, publicClient) {
|
|
|
3769
4092
|
signature
|
|
3770
4093
|
};
|
|
3771
4094
|
}
|
|
3772
|
-
function normalizeTnSignature(signature) {
|
|
3773
|
-
if (typeof signature !== "string") {
|
|
3774
|
-
throw new CofheError({
|
|
3775
|
-
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3776
|
-
message: "decrypt response missing signature",
|
|
3777
|
-
context: {
|
|
3778
|
-
signature
|
|
3779
|
-
}
|
|
3780
|
-
});
|
|
3781
|
-
}
|
|
3782
|
-
const trimmed = signature.trim();
|
|
3783
|
-
if (trimmed.length === 0) {
|
|
3784
|
-
throw new CofheError({
|
|
3785
|
-
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3786
|
-
message: "decrypt response returned empty signature"
|
|
3787
|
-
});
|
|
3788
|
-
}
|
|
3789
|
-
const prefixed = trimmed.startsWith("0x") ? trimmed : `0x${trimmed}`;
|
|
3790
|
-
const parsed = viem.parseSignature(prefixed);
|
|
3791
|
-
return viem.serializeSignature(parsed);
|
|
3792
|
-
}
|
|
3793
|
-
function parseDecryptedBytesToBigInt(decrypted) {
|
|
3794
|
-
if (!Array.isArray(decrypted)) {
|
|
3795
|
-
throw new CofheError({
|
|
3796
|
-
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3797
|
-
message: "decrypt response field <decrypted> must be a byte array",
|
|
3798
|
-
context: {
|
|
3799
|
-
decrypted
|
|
3800
|
-
}
|
|
3801
|
-
});
|
|
3802
|
-
}
|
|
3803
|
-
if (decrypted.length === 0) {
|
|
3804
|
-
throw new CofheError({
|
|
3805
|
-
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3806
|
-
message: "decrypt response field <decrypted> was an empty byte array",
|
|
3807
|
-
context: {
|
|
3808
|
-
decrypted
|
|
3809
|
-
}
|
|
3810
|
-
});
|
|
3811
|
-
}
|
|
3812
|
-
let hex = "";
|
|
3813
|
-
for (const b of decrypted) {
|
|
3814
|
-
if (typeof b !== "number" || !Number.isInteger(b) || b < 0 || b > 255) {
|
|
3815
|
-
throw new CofheError({
|
|
3816
|
-
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3817
|
-
message: "decrypt response field <decrypted> contained a non-byte value",
|
|
3818
|
-
context: {
|
|
3819
|
-
badElement: b,
|
|
3820
|
-
decrypted
|
|
3821
|
-
}
|
|
3822
|
-
});
|
|
3823
|
-
}
|
|
3824
|
-
hex += b.toString(16).padStart(2, "0");
|
|
3825
|
-
}
|
|
3826
|
-
return BigInt(`0x${hex}`);
|
|
3827
|
-
}
|
|
3828
4095
|
|
|
3829
4096
|
// core/decrypt/tnDecryptV2.ts
|
|
3830
4097
|
var POLL_INTERVAL_MS2 = 1e3;
|
|
@@ -3946,15 +4213,16 @@ function assertDecryptStatusResponseV2(value) {
|
|
|
3946
4213
|
}
|
|
3947
4214
|
return value;
|
|
3948
4215
|
}
|
|
3949
|
-
async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId,
|
|
4216
|
+
async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, acp, overallStartTime, retry404TimeoutMs, onPoll) {
|
|
3950
4217
|
const body = {
|
|
3951
4218
|
ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
|
|
3952
4219
|
host_chain_id: chainId
|
|
3953
4220
|
};
|
|
3954
|
-
if (
|
|
3955
|
-
body.
|
|
4221
|
+
if (acp) {
|
|
4222
|
+
body.acp = acp;
|
|
3956
4223
|
}
|
|
3957
4224
|
let attemptIndex = 0;
|
|
4225
|
+
let last404ApiErrorMessage;
|
|
3958
4226
|
for (; ; ) {
|
|
3959
4227
|
let response;
|
|
3960
4228
|
try {
|
|
@@ -3982,16 +4250,19 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, perm
|
|
|
3982
4250
|
}
|
|
3983
4251
|
});
|
|
3984
4252
|
}
|
|
3985
|
-
const responseClassification = await classifySubmitResponse({
|
|
4253
|
+
const responseClassification = await classifySubmitResponse({
|
|
4254
|
+
response,
|
|
4255
|
+
fallbackErrorCode: "DECRYPT_FAILED" /* DecryptFailed */
|
|
4256
|
+
});
|
|
3986
4257
|
if (responseClassification.kind === "fatal-http") {
|
|
3987
4258
|
throw new CofheError({
|
|
3988
|
-
code:
|
|
4259
|
+
code: responseClassification.cofheErrorCode,
|
|
4260
|
+
apiErrorCode: responseClassification.apiErrorCode,
|
|
3989
4261
|
message: `decrypt request failed: ${responseClassification.errorMessage}`,
|
|
3990
4262
|
hint: "Check the threshold network URL and request parameters.",
|
|
3991
4263
|
context: {
|
|
3992
4264
|
thresholdNetworkUrl,
|
|
3993
|
-
status:
|
|
3994
|
-
statusText: response.statusText,
|
|
4265
|
+
status: responseClassification.status,
|
|
3995
4266
|
body,
|
|
3996
4267
|
attemptIndex
|
|
3997
4268
|
}
|
|
@@ -4039,6 +4310,9 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, perm
|
|
|
4039
4310
|
}
|
|
4040
4311
|
});
|
|
4041
4312
|
}
|
|
4313
|
+
if (responseClassification.status === 404) {
|
|
4314
|
+
last404ApiErrorMessage = responseClassification.apiErrorMessage;
|
|
4315
|
+
}
|
|
4042
4316
|
const elapsedMs = Date.now() - overallStartTime;
|
|
4043
4317
|
throwIfSubmitRetryTimedOut({
|
|
4044
4318
|
operationLabel: "decrypt",
|
|
@@ -4049,7 +4323,8 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, perm
|
|
|
4049
4323
|
overallTimeoutMs: DECRYPT_TIMEOUT_MS,
|
|
4050
4324
|
thresholdNetworkUrl,
|
|
4051
4325
|
body,
|
|
4052
|
-
attemptIndex
|
|
4326
|
+
attemptIndex,
|
|
4327
|
+
lastKnownErrorMessage: last404ApiErrorMessage
|
|
4053
4328
|
});
|
|
4054
4329
|
onPoll?.({
|
|
4055
4330
|
operation: "decrypt",
|
|
@@ -4127,17 +4402,10 @@ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartT
|
|
|
4127
4402
|
});
|
|
4128
4403
|
}
|
|
4129
4404
|
if (!response.ok) {
|
|
4130
|
-
|
|
4131
|
-
try {
|
|
4132
|
-
const errorBody = await response.json();
|
|
4133
|
-
const maybeMessage = errorBody.error_message || errorBody.message;
|
|
4134
|
-
if (typeof maybeMessage === "string" && maybeMessage.length > 0)
|
|
4135
|
-
errorMessage = maybeMessage;
|
|
4136
|
-
} catch {
|
|
4137
|
-
errorMessage = response.statusText || errorMessage;
|
|
4138
|
-
}
|
|
4405
|
+
const { apiErrorCode, errorMessage } = await parseApiErrorResponseBody(response);
|
|
4139
4406
|
throw new CofheError({
|
|
4140
|
-
code: "DECRYPT_FAILED" /* DecryptFailed
|
|
4407
|
+
code: mapApiErrorCodeToCofheErrorCode(apiErrorCode, "DECRYPT_FAILED" /* DecryptFailed */),
|
|
4408
|
+
apiErrorCode,
|
|
4141
4409
|
message: `decrypt status poll failed: ${errorMessage}`,
|
|
4142
4410
|
context: {
|
|
4143
4411
|
thresholdNetworkUrl,
|
|
@@ -4182,7 +4450,7 @@ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartT
|
|
|
4182
4450
|
});
|
|
4183
4451
|
}
|
|
4184
4452
|
async function tnDecryptV2(params) {
|
|
4185
|
-
const { thresholdNetworkUrl, ctHash, chainId,
|
|
4453
|
+
const { thresholdNetworkUrl, ctHash, chainId, acp, retry404TimeoutMs, onPoll } = params;
|
|
4186
4454
|
const normalized404RetryTimeoutMs = normalize404RetryTimeoutMs({
|
|
4187
4455
|
timeoutMs: retry404TimeoutMs,
|
|
4188
4456
|
operationLabel: "decrypt",
|
|
@@ -4193,7 +4461,7 @@ async function tnDecryptV2(params) {
|
|
|
4193
4461
|
thresholdNetworkUrl,
|
|
4194
4462
|
ctHash,
|
|
4195
4463
|
chainId,
|
|
4196
|
-
|
|
4464
|
+
acp,
|
|
4197
4465
|
overallStartTime,
|
|
4198
4466
|
normalized404RetryTimeoutMs,
|
|
4199
4467
|
onPoll
|
|
@@ -4208,9 +4476,9 @@ async function tnDecryptV2(params) {
|
|
|
4208
4476
|
var DEFAULT_404_RETRY_TIMEOUT_MS3 = 1e4;
|
|
4209
4477
|
var DecryptForTxBuilder = class extends BaseBuilder {
|
|
4210
4478
|
ctHash;
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4479
|
+
acpHash;
|
|
4480
|
+
acp;
|
|
4481
|
+
acpSelection = "unset";
|
|
4214
4482
|
pollCallback;
|
|
4215
4483
|
retry404TimeoutMs = DEFAULT_404_RETRY_TIMEOUT_MS3;
|
|
4216
4484
|
constructor(params) {
|
|
@@ -4255,137 +4523,137 @@ var DecryptForTxBuilder = class extends BaseBuilder {
|
|
|
4255
4523
|
this.retry404TimeoutMs = timeoutMs;
|
|
4256
4524
|
return this;
|
|
4257
4525
|
}
|
|
4258
|
-
|
|
4259
|
-
if (this.
|
|
4526
|
+
withACP(acpOrACPHash) {
|
|
4527
|
+
if (this.acpSelection === "with-acp") {
|
|
4260
4528
|
throw new CofheError({
|
|
4261
4529
|
code: "INTERNAL_ERROR" /* InternalError */,
|
|
4262
|
-
message: "decryptForTx:
|
|
4263
|
-
hint: "Choose the
|
|
4530
|
+
message: "decryptForTx: withACP() can only be selected once.",
|
|
4531
|
+
hint: "Choose the acp mode once. If you need a different acp, start a new decryptForTx() builder chain."
|
|
4264
4532
|
});
|
|
4265
4533
|
}
|
|
4266
|
-
if (this.
|
|
4534
|
+
if (this.acpSelection === "without-acp") {
|
|
4267
4535
|
throw new CofheError({
|
|
4268
4536
|
code: "INTERNAL_ERROR" /* InternalError */,
|
|
4269
|
-
message: "decryptForTx: cannot call
|
|
4270
|
-
hint: "Choose exactly one
|
|
4537
|
+
message: "decryptForTx: cannot call withACP() after withoutACP() has been selected.",
|
|
4538
|
+
hint: "Choose exactly one acp mode: either call .withACP(...) or .withoutACP(), but not both."
|
|
4271
4539
|
});
|
|
4272
4540
|
}
|
|
4273
|
-
this.
|
|
4274
|
-
if (typeof
|
|
4275
|
-
this.
|
|
4276
|
-
this.
|
|
4277
|
-
} else if (
|
|
4278
|
-
this.
|
|
4279
|
-
this.
|
|
4541
|
+
this.acpSelection = "with-acp";
|
|
4542
|
+
if (typeof acpOrACPHash === "string") {
|
|
4543
|
+
this.acpHash = acpOrACPHash;
|
|
4544
|
+
this.acp = void 0;
|
|
4545
|
+
} else if (acpOrACPHash === void 0) {
|
|
4546
|
+
this.acpHash = void 0;
|
|
4547
|
+
this.acp = void 0;
|
|
4280
4548
|
} else {
|
|
4281
|
-
this.
|
|
4282
|
-
this.
|
|
4549
|
+
this.acp = acpOrACPHash;
|
|
4550
|
+
this.acpHash = void 0;
|
|
4283
4551
|
}
|
|
4284
4552
|
return this;
|
|
4285
4553
|
}
|
|
4286
4554
|
/**
|
|
4287
|
-
* Select "no
|
|
4555
|
+
* Select "no acp" mode.
|
|
4288
4556
|
*
|
|
4289
|
-
* This uses global allowance (no
|
|
4557
|
+
* This uses global allowance (no acp required) and sends an empty permission payload to `/decrypt`.
|
|
4290
4558
|
*/
|
|
4291
|
-
|
|
4292
|
-
if (this.
|
|
4559
|
+
withoutACP() {
|
|
4560
|
+
if (this.acpSelection === "without-acp") {
|
|
4293
4561
|
throw new CofheError({
|
|
4294
4562
|
code: "INTERNAL_ERROR" /* InternalError */,
|
|
4295
|
-
message: "decryptForTx:
|
|
4296
|
-
hint: "Choose the
|
|
4563
|
+
message: "decryptForTx: withoutACP() can only be selected once.",
|
|
4564
|
+
hint: "Choose the acp mode once. If you need a different mode, start a new decryptForTx() builder chain."
|
|
4297
4565
|
});
|
|
4298
4566
|
}
|
|
4299
|
-
if (this.
|
|
4567
|
+
if (this.acpSelection === "with-acp") {
|
|
4300
4568
|
throw new CofheError({
|
|
4301
4569
|
code: "INTERNAL_ERROR" /* InternalError */,
|
|
4302
|
-
message: "decryptForTx: cannot call
|
|
4303
|
-
hint: "Choose exactly one
|
|
4570
|
+
message: "decryptForTx: cannot call withoutACP() after withACP() has been selected.",
|
|
4571
|
+
hint: "Choose exactly one acp mode: either call .withACP(...) or .withoutACP(), but not both."
|
|
4304
4572
|
});
|
|
4305
4573
|
}
|
|
4306
|
-
this.
|
|
4307
|
-
this.
|
|
4308
|
-
this.
|
|
4574
|
+
this.acpSelection = "without-acp";
|
|
4575
|
+
this.acpHash = void 0;
|
|
4576
|
+
this.acp = void 0;
|
|
4309
4577
|
return this;
|
|
4310
4578
|
}
|
|
4311
|
-
|
|
4312
|
-
return this.
|
|
4579
|
+
getACP() {
|
|
4580
|
+
return this.acp;
|
|
4313
4581
|
}
|
|
4314
|
-
|
|
4315
|
-
return this.
|
|
4582
|
+
getACPHash() {
|
|
4583
|
+
return this.acpHash;
|
|
4316
4584
|
}
|
|
4317
4585
|
async getThresholdNetworkUrl() {
|
|
4318
4586
|
this.assertChainId();
|
|
4319
4587
|
return getThresholdNetworkUrlOrThrow(this.config, this.chainId);
|
|
4320
4588
|
}
|
|
4321
|
-
async
|
|
4322
|
-
if (this.
|
|
4589
|
+
async getResolvedACP() {
|
|
4590
|
+
if (this.acpSelection === "unset") {
|
|
4323
4591
|
throw new CofheError({
|
|
4324
4592
|
code: "INTERNAL_ERROR" /* InternalError */,
|
|
4325
|
-
message: "decryptForTx: missing
|
|
4326
|
-
hint: "Call .
|
|
4593
|
+
message: "decryptForTx: missing acp selection; call withACP(...) or withoutACP() before execute().",
|
|
4594
|
+
hint: "Call .withACP() to use the active acp, or .withoutACP() for global allowance."
|
|
4327
4595
|
});
|
|
4328
4596
|
}
|
|
4329
|
-
if (this.
|
|
4597
|
+
if (this.acpSelection === "without-acp") {
|
|
4330
4598
|
return null;
|
|
4331
4599
|
}
|
|
4332
|
-
if (this.
|
|
4333
|
-
return this.
|
|
4600
|
+
if (this.acp)
|
|
4601
|
+
return this.acp;
|
|
4334
4602
|
this.assertChainId();
|
|
4335
4603
|
this.assertAccount();
|
|
4336
|
-
if (this.
|
|
4337
|
-
const
|
|
4338
|
-
if (!
|
|
4604
|
+
if (this.acpHash) {
|
|
4605
|
+
const acp2 = await acps.getACP(this.chainId, this.account, this.acpHash);
|
|
4606
|
+
if (!acp2) {
|
|
4339
4607
|
throw new CofheError({
|
|
4340
|
-
code: "
|
|
4341
|
-
message: `
|
|
4342
|
-
hint: "Ensure the
|
|
4608
|
+
code: "ACP_NOT_FOUND" /* ACPNotFound */,
|
|
4609
|
+
message: `ACP with hash <${this.acpHash}> not found for account <${this.account}> and chainId <${this.chainId}>`,
|
|
4610
|
+
hint: "Ensure the acp exists and is valid.",
|
|
4343
4611
|
context: {
|
|
4344
4612
|
chainId: this.chainId,
|
|
4345
4613
|
account: this.account,
|
|
4346
|
-
|
|
4614
|
+
acpHash: this.acpHash
|
|
4347
4615
|
}
|
|
4348
4616
|
});
|
|
4349
4617
|
}
|
|
4350
|
-
return
|
|
4618
|
+
return acp2;
|
|
4351
4619
|
}
|
|
4352
|
-
const
|
|
4353
|
-
if (!
|
|
4620
|
+
const acp = await acps.getActiveACP(this.chainId, this.account);
|
|
4621
|
+
if (!acp) {
|
|
4354
4622
|
throw new CofheError({
|
|
4355
|
-
code: "
|
|
4356
|
-
message: `Active
|
|
4357
|
-
hint: "Create
|
|
4623
|
+
code: "ACP_NOT_FOUND" /* ACPNotFound */,
|
|
4624
|
+
message: `Active acp not found for chainId <${this.chainId}> and account <${this.account}>`,
|
|
4625
|
+
hint: "Create an ACP (e.g. client.acp.createSelf(...)) and/or set it active (client.acp.selectActiveACP(hash)).",
|
|
4358
4626
|
context: {
|
|
4359
4627
|
chainId: this.chainId,
|
|
4360
4628
|
account: this.account
|
|
4361
4629
|
}
|
|
4362
4630
|
});
|
|
4363
4631
|
}
|
|
4364
|
-
return
|
|
4632
|
+
return acp;
|
|
4365
4633
|
}
|
|
4366
4634
|
/**
|
|
4367
4635
|
* On hardhat, interact with MockThresholdNetwork contract
|
|
4368
4636
|
*/
|
|
4369
|
-
async mocksDecryptForTx(
|
|
4637
|
+
async mocksDecryptForTx(acp) {
|
|
4370
4638
|
this.assertPublicClient();
|
|
4371
4639
|
const delay = this.config.mocks.decryptDelay;
|
|
4372
4640
|
if (delay > 0)
|
|
4373
4641
|
await sleep(delay);
|
|
4374
|
-
const result = await cofheMocksDecryptForTx(this.ctHash, 0,
|
|
4642
|
+
const result = await cofheMocksDecryptForTx(this.ctHash, 0, acp, this.publicClient);
|
|
4375
4643
|
return result;
|
|
4376
4644
|
}
|
|
4377
4645
|
/**
|
|
4378
4646
|
* In the production context, perform a true decryption with the CoFHE coprocessor.
|
|
4379
4647
|
*/
|
|
4380
|
-
async productionDecryptForTx(
|
|
4648
|
+
async productionDecryptForTx(acp) {
|
|
4381
4649
|
this.assertChainId();
|
|
4382
4650
|
this.assertPublicClient();
|
|
4383
4651
|
const thresholdNetworkUrl = await this.getThresholdNetworkUrl();
|
|
4384
|
-
const
|
|
4652
|
+
const wireAcp = acp ? ACPUtils.getPublic(acp, true) : null;
|
|
4385
4653
|
const { decryptedValue, signature } = await tnDecryptV2({
|
|
4386
4654
|
ctHash: this.ctHash,
|
|
4387
4655
|
chainId: this.chainId,
|
|
4388
|
-
|
|
4656
|
+
acp: wireAcp,
|
|
4389
4657
|
thresholdNetworkUrl,
|
|
4390
4658
|
retry404TimeoutMs: this.retry404TimeoutMs,
|
|
4391
4659
|
onPoll: this.pollCallback
|
|
@@ -4399,19 +4667,19 @@ var DecryptForTxBuilder = class extends BaseBuilder {
|
|
|
4399
4667
|
/**
|
|
4400
4668
|
* Final step of the decryptForTx process. MUST BE CALLED LAST IN THE CHAIN.
|
|
4401
4669
|
*
|
|
4402
|
-
* You must explicitly choose one
|
|
4403
|
-
* - `
|
|
4404
|
-
* - `
|
|
4670
|
+
* You must explicitly choose one acp mode before calling `execute()`:
|
|
4671
|
+
* - `withACP(acp)` / `withACP(acpHash)` / `withACP()` (active acp)
|
|
4672
|
+
* - `withoutACP()` (global allowance)
|
|
4405
4673
|
*/
|
|
4406
4674
|
async execute() {
|
|
4407
|
-
const
|
|
4408
|
-
if (
|
|
4409
|
-
|
|
4410
|
-
const chainId =
|
|
4675
|
+
const acp = await this.getResolvedACP();
|
|
4676
|
+
if (acp !== null) {
|
|
4677
|
+
ACPUtils.validate(acp);
|
|
4678
|
+
const chainId = acp._signedDomain.chainId;
|
|
4411
4679
|
if (chainId === hardhat2.id) {
|
|
4412
|
-
return await this.mocksDecryptForTx(
|
|
4680
|
+
return await this.mocksDecryptForTx(acp);
|
|
4413
4681
|
} else {
|
|
4414
|
-
return await this.productionDecryptForTx(
|
|
4682
|
+
return await this.productionDecryptForTx(acp);
|
|
4415
4683
|
}
|
|
4416
4684
|
} else {
|
|
4417
4685
|
if (!this.chainId) {
|
|
@@ -4474,6 +4742,21 @@ function createCofheClientBase(opts) {
|
|
|
4474
4742
|
const updateConnectState = (partial) => {
|
|
4475
4743
|
connectStore.setState((state) => ({ ...state, ...partial }));
|
|
4476
4744
|
};
|
|
4745
|
+
const _resolveSharingRegistry = async (publicClient, chainId) => {
|
|
4746
|
+
const configured = opts.config.acp?.sharingRegistry?.[chainId];
|
|
4747
|
+
if (configured != null)
|
|
4748
|
+
return configured;
|
|
4749
|
+
const registry = (await acps.getAclServedAddresses(publicClient, chainId)).shareRegistry;
|
|
4750
|
+
if (registry == null) {
|
|
4751
|
+
throw new CofheError({
|
|
4752
|
+
code: "MISSING_CONFIG" /* MissingConfig */,
|
|
4753
|
+
message: `No ACP share registry available for chainId <${chainId}>`,
|
|
4754
|
+
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.",
|
|
4755
|
+
context: { chainId }
|
|
4756
|
+
});
|
|
4757
|
+
}
|
|
4758
|
+
return registry;
|
|
4759
|
+
};
|
|
4477
4760
|
const _requireConnected = () => {
|
|
4478
4761
|
const state = connectStore.getState();
|
|
4479
4762
|
const notConnected = !state.connected || !state.account || !state.chainId || !state.publicClient || !state.walletClient;
|
|
@@ -4596,74 +4879,147 @@ function createCofheClientBase(opts) {
|
|
|
4596
4879
|
}
|
|
4597
4880
|
return { chainId: _chainId, account: _account };
|
|
4598
4881
|
};
|
|
4599
|
-
const
|
|
4882
|
+
const clientACPs = {
|
|
4600
4883
|
// Pass through store access
|
|
4601
|
-
getSnapshot:
|
|
4602
|
-
subscribe:
|
|
4884
|
+
getSnapshot: acps.getSnapshot,
|
|
4885
|
+
subscribe: acps.subscribe,
|
|
4603
4886
|
// Creation methods (require connection)
|
|
4604
4887
|
createSelf: async (options, clients) => {
|
|
4605
4888
|
_requireConnected();
|
|
4606
4889
|
const { publicClient, walletClient } = clients ?? connectStore.getState();
|
|
4607
|
-
|
|
4890
|
+
const chainId = await publicClient.getChainId();
|
|
4891
|
+
return acps.createSelf(
|
|
4892
|
+
await acps.applyACPDefaultsFromChain(options, opts.config.acp, publicClient, chainId),
|
|
4893
|
+
publicClient,
|
|
4894
|
+
walletClient
|
|
4895
|
+
);
|
|
4608
4896
|
},
|
|
4609
4897
|
createSharing: async (options, clients) => {
|
|
4610
4898
|
_requireConnected();
|
|
4611
4899
|
const { publicClient, walletClient } = clients ?? connectStore.getState();
|
|
4612
|
-
|
|
4900
|
+
const chainId = await publicClient.getChainId();
|
|
4901
|
+
return acps.createSharing(
|
|
4902
|
+
await acps.applyACPDefaultsFromChain(options, opts.config.acp, publicClient, chainId),
|
|
4903
|
+
publicClient,
|
|
4904
|
+
walletClient
|
|
4905
|
+
);
|
|
4613
4906
|
},
|
|
4614
4907
|
importShared: async (options, clients) => {
|
|
4615
4908
|
_requireConnected();
|
|
4616
4909
|
const { publicClient, walletClient } = clients ?? connectStore.getState();
|
|
4617
|
-
return
|
|
4910
|
+
return acps.importShared(options, publicClient, walletClient);
|
|
4618
4911
|
},
|
|
4619
4912
|
// Get or create methods (require connection)
|
|
4620
|
-
|
|
4913
|
+
getOrCreateSelfACP: async (chainId, account, options) => {
|
|
4621
4914
|
_requireConnected();
|
|
4622
4915
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
4623
4916
|
const { publicClient, walletClient } = connectStore.getState();
|
|
4624
|
-
|
|
4917
|
+
const optionsWithDefaults = await acps.applyACPDefaultsFromChain(
|
|
4918
|
+
options ?? { issuer: _account, name: "Autogenerated Self ACP" },
|
|
4919
|
+
opts.config.acp,
|
|
4920
|
+
publicClient,
|
|
4921
|
+
_chainId
|
|
4922
|
+
);
|
|
4923
|
+
return acps.getOrCreateSelfACP(publicClient, walletClient, _chainId, _account, optionsWithDefaults);
|
|
4625
4924
|
},
|
|
4626
|
-
|
|
4925
|
+
getOrCreateSharingACP: async (options, chainId, account) => {
|
|
4627
4926
|
_requireConnected();
|
|
4628
4927
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
4629
4928
|
const { publicClient, walletClient } = connectStore.getState();
|
|
4630
|
-
return
|
|
4929
|
+
return acps.getOrCreateSharingACP(
|
|
4930
|
+
publicClient,
|
|
4931
|
+
walletClient,
|
|
4932
|
+
await acps.applyACPDefaultsFromChain(options, opts.config.acp, publicClient, _chainId),
|
|
4933
|
+
_chainId,
|
|
4934
|
+
_account
|
|
4935
|
+
);
|
|
4936
|
+
},
|
|
4937
|
+
// Revocation (require connection)
|
|
4938
|
+
revokeACP: async (acp) => {
|
|
4939
|
+
_requireConnected();
|
|
4940
|
+
const { walletClient } = connectStore.getState();
|
|
4941
|
+
return acps.revokeACP(acp, walletClient);
|
|
4942
|
+
},
|
|
4943
|
+
revokeAllACPs: async (revokerContract) => {
|
|
4944
|
+
_requireConnected();
|
|
4945
|
+
const { publicClient, walletClient } = connectStore.getState();
|
|
4946
|
+
return acps.revokeAllACPs(walletClient, publicClient, revokerContract);
|
|
4947
|
+
},
|
|
4948
|
+
isACPRevoked: async (acp) => {
|
|
4949
|
+
_requireConnected();
|
|
4950
|
+
const { publicClient } = connectStore.getState();
|
|
4951
|
+
return acps.isACPRevoked(acp, publicClient);
|
|
4952
|
+
},
|
|
4953
|
+
// On-chain sharing (require connection + config.acp.sharingRegistry)
|
|
4954
|
+
shareOnChain: async (acp) => {
|
|
4955
|
+
_requireConnected();
|
|
4956
|
+
const { publicClient, walletClient } = connectStore.getState();
|
|
4957
|
+
const chainId = await publicClient.getChainId();
|
|
4958
|
+
const sharingRegistry = await _resolveSharingRegistry(publicClient, chainId);
|
|
4959
|
+
return acps.shareOnChain(acp, walletClient, sharingRegistry);
|
|
4960
|
+
},
|
|
4961
|
+
getIncomingShares: async () => {
|
|
4962
|
+
_requireConnected();
|
|
4963
|
+
const { publicClient, walletClient } = connectStore.getState();
|
|
4964
|
+
const chainId = await publicClient.getChainId();
|
|
4965
|
+
const account = walletClient.account.address;
|
|
4966
|
+
const sharingRegistry = await _resolveSharingRegistry(publicClient, chainId);
|
|
4967
|
+
return acps.getIncomingShares(publicClient, sharingRegistry, account);
|
|
4968
|
+
},
|
|
4969
|
+
importFromChain: async (share) => {
|
|
4970
|
+
_requireConnected();
|
|
4971
|
+
const { publicClient, walletClient } = connectStore.getState();
|
|
4972
|
+
return acps.importFromChain(share, publicClient, walletClient);
|
|
4973
|
+
},
|
|
4974
|
+
dismissShare: async (shareId) => {
|
|
4975
|
+
_requireConnected();
|
|
4976
|
+
const { publicClient, walletClient } = connectStore.getState();
|
|
4977
|
+
const chainId = await publicClient.getChainId();
|
|
4978
|
+
const sharingRegistry = await _resolveSharingRegistry(publicClient, chainId);
|
|
4979
|
+
return acps.removeShareOnChain(shareId, walletClient, sharingRegistry);
|
|
4980
|
+
},
|
|
4981
|
+
cancelShare: async (shareId) => {
|
|
4982
|
+
_requireConnected();
|
|
4983
|
+
const { publicClient, walletClient } = connectStore.getState();
|
|
4984
|
+
const chainId = await publicClient.getChainId();
|
|
4985
|
+
const sharingRegistry = await _resolveSharingRegistry(publicClient, chainId);
|
|
4986
|
+
return acps.removeShareOnChain(shareId, walletClient, sharingRegistry);
|
|
4631
4987
|
},
|
|
4632
4988
|
// Retrieval methods (auto-fill chainId/account)
|
|
4633
|
-
|
|
4989
|
+
getACP: (hash, chainId, account) => {
|
|
4634
4990
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
4635
|
-
return
|
|
4991
|
+
return acps.getACP(_chainId, _account, hash);
|
|
4636
4992
|
},
|
|
4637
|
-
|
|
4993
|
+
getACPs: (chainId, account) => {
|
|
4638
4994
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
4639
|
-
return
|
|
4995
|
+
return acps.getACPs(_chainId, _account);
|
|
4640
4996
|
},
|
|
4641
|
-
|
|
4997
|
+
getActiveACP: (chainId, account) => {
|
|
4642
4998
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
4643
|
-
return
|
|
4999
|
+
return acps.getActiveACP(_chainId, _account);
|
|
4644
5000
|
},
|
|
4645
|
-
|
|
5001
|
+
getActiveACPHash: (chainId, account) => {
|
|
4646
5002
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
4647
|
-
return
|
|
5003
|
+
return acps.getActiveACPHash(_chainId, _account);
|
|
4648
5004
|
},
|
|
4649
5005
|
// Mutation methods (auto-fill chainId/account)
|
|
4650
|
-
|
|
5006
|
+
selectActiveACP: (hash, chainId, account) => {
|
|
4651
5007
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
4652
|
-
return
|
|
5008
|
+
return acps.selectActiveACP(_chainId, _account, hash);
|
|
4653
5009
|
},
|
|
4654
|
-
|
|
5010
|
+
removeACP: async (hash, chainId, account) => {
|
|
4655
5011
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
4656
|
-
return
|
|
5012
|
+
return acps.removeACP(_chainId, _account, hash);
|
|
4657
5013
|
},
|
|
4658
|
-
|
|
5014
|
+
removeActiveACP: async (chainId, account) => {
|
|
4659
5015
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
4660
|
-
return
|
|
5016
|
+
return acps.removeActiveACP(_chainId, _account);
|
|
4661
5017
|
},
|
|
4662
5018
|
// Utils (no context needed)
|
|
4663
|
-
getHash:
|
|
4664
|
-
export:
|
|
4665
|
-
serialize:
|
|
4666
|
-
deserialize:
|
|
5019
|
+
getHash: acps.getHash,
|
|
5020
|
+
export: acps.export,
|
|
5021
|
+
serialize: acps.serialize,
|
|
5022
|
+
deserialize: acps.deserialize
|
|
4667
5023
|
};
|
|
4668
5024
|
return {
|
|
4669
5025
|
// Zustand reactive accessors (don't export store directly to prevent mutation)
|
|
@@ -4691,7 +5047,7 @@ function createCofheClientBase(opts) {
|
|
|
4691
5047
|
decryptHandle: decryptForView,
|
|
4692
5048
|
decryptForTx,
|
|
4693
5049
|
verifyDecryptResult: verifyDecryptResult2,
|
|
4694
|
-
|
|
5050
|
+
acp: clientACPs
|
|
4695
5051
|
// Add SDK-specific methods below that require connection
|
|
4696
5052
|
// Example:
|
|
4697
5053
|
// async encryptData(data: unknown) {
|
|
@@ -4720,7 +5076,7 @@ exports.MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY = MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_
|
|
|
4720
5076
|
exports.TASK_MANAGER_ADDRESS = TASK_MANAGER_ADDRESS;
|
|
4721
5077
|
exports.TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT = TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT;
|
|
4722
5078
|
exports.TFHE_RS_ZK_MAX_BITS = TFHE_RS_ZK_MAX_BITS;
|
|
4723
|
-
exports.
|
|
5079
|
+
exports.assertNoRenamedConfigKeys = assertNoRenamedConfigKeys;
|
|
4724
5080
|
exports.cofheFetch = cofheFetch;
|
|
4725
5081
|
exports.createCofheClientBase = createCofheClientBase;
|
|
4726
5082
|
exports.createCofheConfigBase = createCofheConfigBase;
|