@cofhe/sdk 0.6.1 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +45 -0
- package/acps/acp.ts +411 -0
- package/acps/index.ts +70 -0
- package/{permits → acps}/onchain-utils.ts +49 -24
- package/acps/sealing.ts +90 -0
- package/acps/signature.ts +89 -0
- package/acps/store.ts +172 -0
- package/acps/test/acp.test.ts +615 -0
- package/acps/test/localstorage.test.ts +105 -0
- package/acps/test/sealing.test.ts +77 -0
- package/acps/test/store.test.ts +88 -0
- package/acps/test/validation.test.ts +361 -0
- package/acps/test-utils.ts +32 -0
- package/acps/types.ts +252 -0
- package/acps/validation.ts +392 -0
- package/adapters/test/ethers5.test.ts +4 -1
- package/adapters/test/ethers6.test.ts +4 -1
- package/adapters/test/wagmi.test.ts +5 -2
- package/chains/chains/stagingCofhe.ts +21 -0
- package/chains/index.ts +3 -1
- package/chains/test/chains.test.ts +2 -1
- package/core/acps.ts +625 -0
- package/core/client.ts +136 -39
- package/core/clientTypes.ts +52 -41
- package/core/config.ts +66 -5
- package/core/decrypt/MockThresholdNetworkAbi.ts +20 -11
- package/core/decrypt/apiError.ts +104 -0
- package/core/decrypt/cofheMocksDecryptForTx.ts +11 -11
- package/core/decrypt/cofheMocksDecryptForView.ts +7 -7
- package/core/decrypt/decryptForTxBuilder.ts +102 -102
- package/core/decrypt/decryptForViewBuilder.ts +90 -90
- package/core/decrypt/submitRetry.ts +38 -30
- package/core/decrypt/tnDecryptV1.ts +5 -5
- package/core/decrypt/tnDecryptV2.ts +25 -21
- package/core/decrypt/tnSealOutputV1.ts +4 -3
- package/core/decrypt/tnSealOutputV2.ts +24 -18
- package/core/encrypt/cofheMocksZkVerifySign.ts +59 -74
- package/core/encrypt/encryptInputsBuilder.ts +86 -52
- package/core/encrypt/zkPackProveVerify.ts +25 -18
- package/core/error.ts +34 -6
- package/core/index.ts +4 -14
- package/core/test/acpDefaults.test.ts +52 -0
- package/core/test/acps.test.ts +596 -0
- package/core/test/apiError.test.ts +130 -0
- package/core/test/client.test.ts +22 -19
- package/core/test/config.test.ts +25 -5
- package/core/test/decrypt.test.ts +40 -35
- package/core/test/decryptBuilders.test.ts +68 -68
- package/core/test/decryptErrorCodes.test.ts +217 -0
- package/core/test/encryptInputsBuilder.test.ts +72 -41
- package/core/test/pollCallbacks.test.ts +89 -18
- package/core/test/stagingRedirect.ts +18 -0
- package/core/test/submitRetry.test.ts +182 -0
- package/core/types.ts +9 -69
- package/dist/acp-Wi6isVQI.d.cts +407 -0
- package/dist/acp-Wi6isVQI.d.ts +407 -0
- package/dist/acps.cjs +1081 -0
- package/dist/acps.d.cts +480 -0
- package/dist/acps.d.ts +480 -0
- package/dist/acps.js +2 -0
- package/dist/chains.cjs +14 -1
- package/dist/chains.d.cts +30 -1
- package/dist/chains.d.ts +30 -1
- package/dist/chains.js +1 -1
- package/dist/{chunk-NOC3PYB7.js → chunk-43USWPEH.js} +930 -580
- package/dist/{chunk-MTRAXQXC.js → chunk-N6IDQRRU.js} +14 -2
- package/dist/chunk-Q7CBWGQX.js +1029 -0
- package/dist/{clientTypes-CyUvRRzA.d.ts → clientTypes-BN3nbzYM.d.ts} +342 -165
- package/dist/{clientTypes-BDy1qIBu.d.cts → clientTypes-CYZjFznO.d.cts} +342 -165
- package/dist/core.cjs +1358 -1002
- package/dist/core.d.cts +31 -9
- package/dist/core.d.ts +31 -9
- package/dist/core.js +3 -3
- package/dist/node.cjs +1293 -952
- package/dist/node.d.cts +2 -2
- package/dist/node.d.ts +2 -2
- package/dist/node.js +3 -3
- package/dist/web.cjs +1293 -952
- package/dist/web.d.cts +2 -2
- package/dist/web.d.ts +2 -2
- package/dist/web.js +3 -3
- package/node/test/inherited.test.ts +75 -65
- package/node/test/tfheinit.test.ts +23 -8
- package/package.json +6 -6
- package/web/test/client.web.test.ts +5 -1
- package/web/test/inherited.web.test.ts +75 -65
- package/web/test/tfheinit.web.test.ts +14 -5
- package/web/test/worker.config.web.test.ts +38 -23
- package/web/test/worker.output.web.test.ts +25 -24
- package/core/encrypt/encryptUtils.ts +0 -67
- package/core/permits.ts +0 -216
- package/core/test/permits.test.ts +0 -596
- package/dist/chunk-VB62WYPL.js +0 -978
- package/dist/permit-DnVMDT5h.d.cts +0 -376
- package/dist/permit-DnVMDT5h.d.ts +0 -376
- package/dist/permits.cjs +0 -1026
- package/dist/permits.d.cts +0 -353
- package/dist/permits.d.ts +0 -353
- package/dist/permits.js +0 -2
- package/permits/index.ts +0 -68
- package/permits/permit.ts +0 -385
- package/permits/sealing.ts +0 -131
- package/permits/signature.ts +0 -79
- package/permits/store.ts +0 -157
- package/permits/test/localstorage.test.ts +0 -113
- package/permits/test/permit.test.ts +0 -557
- package/permits/test/sealing.test.ts +0 -84
- package/permits/test/store.test.ts +0 -88
- package/permits/test/validation.test.ts +0 -361
- package/permits/test-utils.ts +0 -28
- package/permits/types.ts +0 -204
- package/permits/validation.ts +0 -327
- /package/{permits → acps}/utils.ts +0 -0
package/dist/web.cjs
CHANGED
|
@@ -23,7 +23,8 @@ var CofheError = class _CofheError extends Error {
|
|
|
23
23
|
cause;
|
|
24
24
|
hint;
|
|
25
25
|
context;
|
|
26
|
-
|
|
26
|
+
apiErrorCode;
|
|
27
|
+
constructor({ code, message, cause, hint, context, apiErrorCode }) {
|
|
27
28
|
const fullMessage = cause ? `${message} | Caused by: ${cause.message}` : message;
|
|
28
29
|
super(fullMessage);
|
|
29
30
|
this.name = "CofheError";
|
|
@@ -31,6 +32,7 @@ var CofheError = class _CofheError extends Error {
|
|
|
31
32
|
this.cause = cause;
|
|
32
33
|
this.hint = hint;
|
|
33
34
|
this.context = context;
|
|
35
|
+
this.apiErrorCode = apiErrorCode;
|
|
34
36
|
if (Error.captureStackTrace) {
|
|
35
37
|
Error.captureStackTrace(this, _CofheError);
|
|
36
38
|
}
|
|
@@ -49,6 +51,7 @@ var CofheError = class _CofheError extends Error {
|
|
|
49
51
|
message: wrapperError?.message ?? "An internal error occurred",
|
|
50
52
|
hint: wrapperError?.hint,
|
|
51
53
|
context: wrapperError?.context,
|
|
54
|
+
apiErrorCode: wrapperError?.apiErrorCode,
|
|
52
55
|
cause
|
|
53
56
|
});
|
|
54
57
|
}
|
|
@@ -62,6 +65,7 @@ var CofheError = class _CofheError extends Error {
|
|
|
62
65
|
message: this.message,
|
|
63
66
|
hint: this.hint,
|
|
64
67
|
context: this.context,
|
|
68
|
+
apiErrorCode: this.apiErrorCode,
|
|
65
69
|
cause: this.cause ? {
|
|
66
70
|
name: this.cause.name,
|
|
67
71
|
message: this.cause.message,
|
|
@@ -74,7 +78,8 @@ var CofheError = class _CofheError extends Error {
|
|
|
74
78
|
* Returns a human-readable string representation of the error
|
|
75
79
|
*/
|
|
76
80
|
toString() {
|
|
77
|
-
const
|
|
81
|
+
const codeSuffix = this.apiErrorCode ? ` (api: ${this.apiErrorCode})` : "";
|
|
82
|
+
const parts = [`${this.name} [${this.code}]${codeSuffix}: ${this.message}`];
|
|
78
83
|
if (this.hint) {
|
|
79
84
|
parts.push(`Hint: ${this.hint}`);
|
|
80
85
|
}
|
|
@@ -346,18 +351,19 @@ var constructZkPoKMetadata = (accountAddr, securityZone, chainId) => {
|
|
|
346
351
|
metadata.set(chainIdBytes, 1 + accountBytes.length);
|
|
347
352
|
return metadata;
|
|
348
353
|
};
|
|
349
|
-
var
|
|
354
|
+
var zkVerifyBatch = async (verifierUrl, serializedBytes, address, securityZone, chainId, consumingContract) => {
|
|
350
355
|
const packed_list = toHexString(serializedBytes);
|
|
351
356
|
const sz_byte = new Uint8Array([securityZone]);
|
|
352
357
|
const payload = {
|
|
353
358
|
packed_list,
|
|
354
359
|
account_addr: address,
|
|
355
360
|
security_zone: sz_byte[0],
|
|
356
|
-
chain_id: chainId
|
|
361
|
+
chain_id: chainId,
|
|
362
|
+
contract_address: consumingContract
|
|
357
363
|
};
|
|
358
364
|
const body = JSON.stringify(payload);
|
|
359
365
|
try {
|
|
360
|
-
const response = await fetch(`${verifierUrl}/
|
|
366
|
+
const response = await fetch(`${verifierUrl}/verifyBatch`, {
|
|
361
367
|
method: "POST",
|
|
362
368
|
headers: {
|
|
363
369
|
"Content-Type": "application/json"
|
|
@@ -368,26 +374,25 @@ var zkVerify = async (verifierUrl, serializedBytes, address, securityZone, chain
|
|
|
368
374
|
const errorBody = await response.text();
|
|
369
375
|
throw new CofheError({
|
|
370
376
|
code: "ZK_VERIFY_FAILED" /* ZkVerifyFailed */,
|
|
371
|
-
message: `HTTP error! ZK proof verification failed - ${errorBody}`
|
|
377
|
+
message: `HTTP error! ZK batch proof verification failed - ${errorBody}`
|
|
372
378
|
});
|
|
373
379
|
}
|
|
374
380
|
const json = await response.json();
|
|
375
381
|
if (json.status !== "success") {
|
|
376
382
|
throw new CofheError({
|
|
377
383
|
code: "ZK_VERIFY_FAILED" /* ZkVerifyFailed */,
|
|
378
|
-
message: `ZK proof verification response malformed - ${json.error}`
|
|
384
|
+
message: `ZK batch proof verification response malformed - ${json.error}`
|
|
379
385
|
});
|
|
380
386
|
}
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
});
|
|
387
|
+
const { ciphertexts, signature, recid } = json.data;
|
|
388
|
+
return {
|
|
389
|
+
outputs: ciphertexts,
|
|
390
|
+
signature: concatSigRecid(signature, recid)
|
|
391
|
+
};
|
|
387
392
|
} catch (e) {
|
|
388
393
|
throw new CofheError({
|
|
389
394
|
code: "ZK_VERIFY_FAILED" /* ZkVerifyFailed */,
|
|
390
|
-
message: `ZK proof verification failed`,
|
|
395
|
+
message: `ZK batch proof verification failed`,
|
|
391
396
|
cause: e instanceof Error ? e : void 0
|
|
392
397
|
});
|
|
393
398
|
}
|
|
@@ -632,67 +637,59 @@ async function insertCtHashes(items, walletClient) {
|
|
|
632
637
|
});
|
|
633
638
|
}
|
|
634
639
|
}
|
|
635
|
-
async function
|
|
636
|
-
let signatures = [];
|
|
637
|
-
let encInputSignerClient;
|
|
640
|
+
async function createBatchProofSignature(items, securityZone, account, consumingContract) {
|
|
638
641
|
try {
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
642
|
+
const itemHashes = items.map(
|
|
643
|
+
(item) => viem.keccak256(
|
|
644
|
+
viem.encodePacked(
|
|
645
|
+
["uint256", "uint8", "uint8", "address", "uint256", "address"],
|
|
646
|
+
[
|
|
647
|
+
BigInt(item.ctHash),
|
|
648
|
+
item.utype,
|
|
649
|
+
securityZone,
|
|
650
|
+
account,
|
|
651
|
+
BigInt(chains.hardhat.id),
|
|
652
|
+
consumingContract
|
|
653
|
+
]
|
|
654
|
+
)
|
|
655
|
+
)
|
|
656
|
+
);
|
|
657
|
+
const batchDigest = viem.keccak256(
|
|
658
|
+
viem.encodePacked(
|
|
659
|
+
itemHashes.map(() => "bytes32"),
|
|
660
|
+
itemHashes
|
|
661
|
+
)
|
|
662
|
+
);
|
|
663
|
+
return await accounts.sign({
|
|
664
|
+
hash: batchDigest,
|
|
665
|
+
privateKey: MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY,
|
|
666
|
+
to: "hex"
|
|
648
667
|
});
|
|
649
|
-
}
|
|
650
|
-
try {
|
|
651
|
-
for (const item of items) {
|
|
652
|
-
const packedData = viem.encodePacked(
|
|
653
|
-
["uint256", "uint8", "uint8", "address", "uint256"],
|
|
654
|
-
[BigInt(item.ctHash), item.utype, securityZone, account, BigInt(chains.hardhat.id)]
|
|
655
|
-
);
|
|
656
|
-
const messageHash = viem.keccak256(packedData);
|
|
657
|
-
const signature = await accounts.sign({
|
|
658
|
-
hash: messageHash,
|
|
659
|
-
privateKey: MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY,
|
|
660
|
-
to: "hex"
|
|
661
|
-
});
|
|
662
|
-
signatures.push(signature);
|
|
663
|
-
}
|
|
664
668
|
} catch (err) {
|
|
665
669
|
throw new CofheError({
|
|
666
670
|
code: "ZK_MOCKS_CREATE_PROOF_SIGNATURE_FAILED" /* ZkMocksCreateProofSignatureFailed */,
|
|
667
|
-
message: `mockZkVerifySign
|
|
671
|
+
message: `mockZkVerifySign createBatchProofSignature failed while signing the batch digest`,
|
|
668
672
|
cause: err instanceof Error ? err : void 0,
|
|
669
673
|
context: {
|
|
670
674
|
items,
|
|
671
|
-
securityZone
|
|
672
|
-
|
|
673
|
-
});
|
|
674
|
-
}
|
|
675
|
-
if (signatures.length !== items.length) {
|
|
676
|
-
throw new CofheError({
|
|
677
|
-
code: "ZK_MOCKS_CREATE_PROOF_SIGNATURE_FAILED" /* ZkMocksCreateProofSignatureFailed */,
|
|
678
|
-
message: `mockZkVerifySign createProofSignatures returned incorrect number of signatures`,
|
|
679
|
-
context: {
|
|
680
|
-
items,
|
|
681
|
-
securityZone
|
|
675
|
+
securityZone,
|
|
676
|
+
consumingContract
|
|
682
677
|
}
|
|
683
678
|
});
|
|
684
679
|
}
|
|
685
|
-
return signatures;
|
|
686
680
|
}
|
|
687
|
-
async function cofheMocksZkVerifySign(items, account, securityZone, publicClient, walletClient, zkvWalletClient) {
|
|
681
|
+
async function cofheMocksZkVerifySign(items, account, securityZone, consumingContract, publicClient, walletClient, zkvWalletClient) {
|
|
688
682
|
const _walletClient = zkvWalletClient ?? createMockZkVerifierSigner();
|
|
689
683
|
const encryptableItems = await calcCtHashes(items, account, securityZone, publicClient);
|
|
690
684
|
await insertCtHashes(encryptableItems, _walletClient);
|
|
691
|
-
const
|
|
692
|
-
return
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
685
|
+
const signature = await createBatchProofSignature(encryptableItems, securityZone, account, consumingContract);
|
|
686
|
+
return {
|
|
687
|
+
outputs: encryptableItems.map((item) => ({
|
|
688
|
+
ct_hash: item.ctHash.toString(),
|
|
689
|
+
ct_type: item.utype
|
|
690
|
+
})),
|
|
691
|
+
signature
|
|
692
|
+
};
|
|
696
693
|
}
|
|
697
694
|
var EnvironmentSchema = zod.z.enum(["MOCK", "TESTNET", "MAINNET"]);
|
|
698
695
|
var CofheChainSchema = zod.z.object({
|
|
@@ -735,8 +732,8 @@ var CofheConfigSchema = zod.z.object({
|
|
|
735
732
|
environment: zod.z.enum(["node", "hardhat", "web", "react"]).optional().default("node"),
|
|
736
733
|
/** List of supported chain configurations */
|
|
737
734
|
supportedChains: zod.z.array(zod.z.custom()),
|
|
738
|
-
/** Default
|
|
739
|
-
|
|
735
|
+
/** Default acp expiration in seconds, default is 30 days */
|
|
736
|
+
defaultACPExpiration: zod.z.number().optional().default(60 * 60 * 24 * 30),
|
|
740
737
|
/** Storage method for fhe keys (defaults to indexedDB on web, filesystem on node) */
|
|
741
738
|
fheKeyStorage: zod.z.object({
|
|
742
739
|
getItem: zod.z.custom((val) => typeof val === "function", {
|
|
@@ -751,6 +748,12 @@ var CofheConfigSchema = zod.z.object({
|
|
|
751
748
|
}).or(zod.z.null()).default(null),
|
|
752
749
|
/** Whether to use Web Workers for ZK proof generation (web platform only) */
|
|
753
750
|
useWorkers: zod.z.boolean().optional().default(true),
|
|
751
|
+
/** ACP acp defaults */
|
|
752
|
+
acp: zod.z.object({
|
|
753
|
+
defaultRevoker: zod.z.custom().optional(),
|
|
754
|
+
defaultContractScopes: zod.z.custom().optional(),
|
|
755
|
+
sharingRegistry: zod.z.custom().optional()
|
|
756
|
+
}).optional().default({}),
|
|
754
757
|
/** Mocks configs */
|
|
755
758
|
mocks: zod.z.object({
|
|
756
759
|
decryptDelay: zod.z.number().optional().default(0),
|
|
@@ -761,8 +764,19 @@ var CofheConfigSchema = zod.z.object({
|
|
|
761
764
|
zkvWalletClient: zod.z.any().optional()
|
|
762
765
|
}).optional()
|
|
763
766
|
});
|
|
767
|
+
var RENAMED_COFHE_CONFIG_KEYS = {
|
|
768
|
+
defaultPermitExpiration: "defaultACPExpiration"
|
|
769
|
+
};
|
|
770
|
+
function assertNoRenamedConfigKeys(config, renamedKeys, label) {
|
|
771
|
+
const stale = Object.keys(config).filter((key) => key in renamedKeys);
|
|
772
|
+
if (stale.length === 0)
|
|
773
|
+
return;
|
|
774
|
+
const renames = stale.map((key) => `\`${key}\` is now \`${renamedKeys[key]}\``).join("; ");
|
|
775
|
+
throw new Error(`Invalid ${label}: ${renames}. See the v0.7.0 migration guide.`);
|
|
776
|
+
}
|
|
764
777
|
function createCofheConfigBase(config) {
|
|
765
|
-
|
|
778
|
+
assertNoRenamedConfigKeys(config, RENAMED_COFHE_CONFIG_KEYS, "cofhe configuration");
|
|
779
|
+
const result = CofheConfigSchema.strict().safeParse(config);
|
|
766
780
|
if (!result.success) {
|
|
767
781
|
throw new Error(`Invalid cofhe configuration: ${zod.z.prettifyError(result.error)}`, { cause: result.error });
|
|
768
782
|
}
|
|
@@ -1111,9 +1125,9 @@ var BaseBuilder = class {
|
|
|
1111
1125
|
// core/encrypt/encryptInputsBuilder.ts
|
|
1112
1126
|
var EncryptInputsBuilder = class extends BaseBuilder {
|
|
1113
1127
|
securityZone;
|
|
1128
|
+
consumingContract;
|
|
1114
1129
|
stepCallback;
|
|
1115
1130
|
inputItems;
|
|
1116
|
-
hpp = false;
|
|
1117
1131
|
zkvWalletClient;
|
|
1118
1132
|
tfhePublicKeyDeserializer;
|
|
1119
1133
|
compactPkeCrsDeserializer;
|
|
@@ -1180,20 +1194,6 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1180
1194
|
this.keysStorage = params.keysStorage;
|
|
1181
1195
|
this.useWorker = params.config?.useWorkers ?? true;
|
|
1182
1196
|
}
|
|
1183
|
-
/**
|
|
1184
|
-
* @param account - Account that will create the tx using the encrypted inputs.
|
|
1185
|
-
*
|
|
1186
|
-
* If not provided, the account will be fetched from the connected walletClient.
|
|
1187
|
-
*
|
|
1188
|
-
* Example:
|
|
1189
|
-
* ```typescript
|
|
1190
|
-
* const encrypted = await encryptInputs([Encryptable.uint128(10n)])
|
|
1191
|
-
* .setAccount("0x123")
|
|
1192
|
-
* .execute();
|
|
1193
|
-
* ```
|
|
1194
|
-
*
|
|
1195
|
-
* @returns The chainable EncryptInputsBuilder instance.
|
|
1196
|
-
*/
|
|
1197
1197
|
setAccount(account) {
|
|
1198
1198
|
this.account = account;
|
|
1199
1199
|
return this;
|
|
@@ -1201,20 +1201,6 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1201
1201
|
getAccount() {
|
|
1202
1202
|
return this.account;
|
|
1203
1203
|
}
|
|
1204
|
-
/**
|
|
1205
|
-
* @param chainId - Chain that will consume the encrypted inputs.
|
|
1206
|
-
*
|
|
1207
|
-
* If not provided, the chainId will be fetched from the connected publicClient.
|
|
1208
|
-
*
|
|
1209
|
-
* Example:
|
|
1210
|
-
* ```typescript
|
|
1211
|
-
* const encrypted = await encryptInputs([Encryptable.uint128(10n)])
|
|
1212
|
-
* .setChainId(11155111)
|
|
1213
|
-
* .execute();
|
|
1214
|
-
* ```
|
|
1215
|
-
*
|
|
1216
|
-
* @returns The chainable EncryptInputsBuilder instance.
|
|
1217
|
-
*/
|
|
1218
1204
|
setChainId(chainId) {
|
|
1219
1205
|
this.chainId = chainId;
|
|
1220
1206
|
return this;
|
|
@@ -1222,20 +1208,6 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1222
1208
|
getChainId() {
|
|
1223
1209
|
return this.chainId;
|
|
1224
1210
|
}
|
|
1225
|
-
/**
|
|
1226
|
-
* @param securityZone - Security zone to encrypt the inputs for.
|
|
1227
|
-
*
|
|
1228
|
-
* If not provided, the default securityZone 0 will be used.
|
|
1229
|
-
*
|
|
1230
|
-
* Example:
|
|
1231
|
-
* ```typescript
|
|
1232
|
-
* const encrypted = await encryptInputs([Encryptable.uint128(10n)])
|
|
1233
|
-
* .setSecurityZone(1)
|
|
1234
|
-
* .execute();
|
|
1235
|
-
* ```
|
|
1236
|
-
*
|
|
1237
|
-
* @returns The chainable EncryptInputsBuilder instance.
|
|
1238
|
-
*/
|
|
1239
1211
|
setSecurityZone(securityZone) {
|
|
1240
1212
|
this.securityZone = securityZone;
|
|
1241
1213
|
return this;
|
|
@@ -1244,33 +1216,44 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1244
1216
|
return this.securityZone;
|
|
1245
1217
|
}
|
|
1246
1218
|
/**
|
|
1219
|
+
* @param address - The contract that will consume the resulting hashes+signature (i.e. the
|
|
1220
|
+
* contract that will call `FHE.asEuint*`/`FHE.asEuint*s` with them).
|
|
1221
|
+
*
|
|
1222
|
+
* Required before `execute()` - the verifier binds this address into the signed digest, so a
|
|
1223
|
+
* batch signed for one contract cannot be replayed into another.
|
|
1224
|
+
*
|
|
1247
1225
|
* Example:
|
|
1248
1226
|
* ```typescript
|
|
1249
1227
|
* const encrypted = await encryptInputs([Encryptable.uint128(10n)])
|
|
1250
|
-
* .
|
|
1228
|
+
* .setConsumingContract("0x123...890")
|
|
1251
1229
|
* .execute();
|
|
1252
1230
|
* ```
|
|
1253
1231
|
*
|
|
1254
|
-
* @returns
|
|
1232
|
+
* @returns The chainable EncryptInputsBuilder instance.
|
|
1255
1233
|
*/
|
|
1256
|
-
|
|
1257
|
-
this.
|
|
1234
|
+
setConsumingContract(address) {
|
|
1235
|
+
this.consumingContract = address;
|
|
1258
1236
|
return this;
|
|
1259
1237
|
}
|
|
1238
|
+
getConsumingContract() {
|
|
1239
|
+
return this.consumingContract;
|
|
1240
|
+
}
|
|
1260
1241
|
/**
|
|
1261
|
-
*
|
|
1262
|
-
*
|
|
1263
|
-
* Overrides the config-level useWorkers setting for this specific encryption.
|
|
1264
|
-
*
|
|
1265
|
-
* Example:
|
|
1266
|
-
* ```typescript
|
|
1267
|
-
* const encrypted = await encryptInputs([Encryptable.uint128(10n)])
|
|
1268
|
-
* .setUseWorker(false)
|
|
1269
|
-
* .execute();
|
|
1270
|
-
* ```
|
|
1271
|
-
*
|
|
1272
|
-
* @returns The chainable EncryptInputsBuilder instance.
|
|
1242
|
+
* Asserts that this.consumingContract is populated
|
|
1243
|
+
* @throws {CofheError} If consumingContract is not set
|
|
1273
1244
|
*/
|
|
1245
|
+
assertConsumingContract() {
|
|
1246
|
+
if (this.consumingContract)
|
|
1247
|
+
return;
|
|
1248
|
+
throw new CofheError({
|
|
1249
|
+
code: "CONSUMING_CONTRACT_UNINITIALIZED" /* ConsumingContractUninitialized */,
|
|
1250
|
+
message: "Consuming contract is not set",
|
|
1251
|
+
hint: "Use setConsumingContract(...) to set the contract that will consume the encrypted inputs.",
|
|
1252
|
+
context: {
|
|
1253
|
+
consumingContract: this.consumingContract
|
|
1254
|
+
}
|
|
1255
|
+
});
|
|
1256
|
+
}
|
|
1274
1257
|
setUseWorker(useWorker) {
|
|
1275
1258
|
this.useWorker = useWorker;
|
|
1276
1259
|
return this;
|
|
@@ -1291,21 +1274,6 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1291
1274
|
getUseWorker() {
|
|
1292
1275
|
return this.useWorker;
|
|
1293
1276
|
}
|
|
1294
|
-
/**
|
|
1295
|
-
* @param callback - Function to be called with the encryption step.
|
|
1296
|
-
*
|
|
1297
|
-
* Useful for debugging and tracking the progress of the encryption process.
|
|
1298
|
-
* Useful for a UI element that shows the progress of the encryption process.
|
|
1299
|
-
*
|
|
1300
|
-
* Example:
|
|
1301
|
-
* ```typescript
|
|
1302
|
-
* const encrypted = await encryptInputs([Encryptable.uint128(10n)])
|
|
1303
|
-
* .onStep((step: EncryptStep) => console.log(step))
|
|
1304
|
-
* .execute();
|
|
1305
|
-
* ```
|
|
1306
|
-
*
|
|
1307
|
-
* @returns The EncryptInputsBuilder instance.
|
|
1308
|
-
*/
|
|
1309
1277
|
onStep(callback) {
|
|
1310
1278
|
this.stepCallback = callback;
|
|
1311
1279
|
return this;
|
|
@@ -1444,6 +1412,7 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1444
1412
|
this.assertAccount();
|
|
1445
1413
|
this.assertPublicClient();
|
|
1446
1414
|
this.assertWalletClient();
|
|
1415
|
+
this.assertConsumingContract();
|
|
1447
1416
|
const [initTfheDelay, fetchKeysDelay, packDelay, proveDelay, verifyDelay] = this.resolveEncryptDelays();
|
|
1448
1417
|
this.fireStepStart("initTfhe" /* InitTfhe */);
|
|
1449
1418
|
await sleep(initTfheDelay);
|
|
@@ -1469,22 +1438,17 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1469
1438
|
this.fireStepEnd("prove" /* Prove */, { isMocks: true, mockSleep: proveDelay });
|
|
1470
1439
|
this.fireStepStart("verify" /* Verify */);
|
|
1471
1440
|
await sleep(verifyDelay);
|
|
1472
|
-
const
|
|
1441
|
+
const result = await cofheMocksZkVerifySign(
|
|
1473
1442
|
this.inputItems,
|
|
1474
1443
|
this.account,
|
|
1475
1444
|
this.securityZone,
|
|
1445
|
+
this.consumingContract,
|
|
1476
1446
|
this.publicClient,
|
|
1477
1447
|
this.walletClient,
|
|
1478
1448
|
this.zkvWalletClient
|
|
1479
1449
|
);
|
|
1480
|
-
const encryptedInputs = signedResults.map(({ ct_hash, signature }, index) => ({
|
|
1481
|
-
ctHash: BigInt(ct_hash),
|
|
1482
|
-
securityZone: this.securityZone,
|
|
1483
|
-
utype: this.inputItems[index].utype,
|
|
1484
|
-
signature
|
|
1485
|
-
}));
|
|
1486
1450
|
this.fireStepEnd("verify" /* Verify */, { isMocks: true, mockSleep: verifyDelay });
|
|
1487
|
-
return
|
|
1451
|
+
return result;
|
|
1488
1452
|
}
|
|
1489
1453
|
/**
|
|
1490
1454
|
* In the production context, perform a true encryption with the CoFHE coprocessor.
|
|
@@ -1492,6 +1456,7 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1492
1456
|
async productionExecute() {
|
|
1493
1457
|
this.assertAccount();
|
|
1494
1458
|
this.assertChainId();
|
|
1459
|
+
this.assertConsumingContract();
|
|
1495
1460
|
this.fireStepStart("initTfhe" /* InitTfhe */);
|
|
1496
1461
|
const tfheInitializationExecuted = await this.initTfheOrThrow();
|
|
1497
1462
|
this.fireStepEnd("initTfhe" /* InitTfhe */, { tfheInitializationExecuted });
|
|
@@ -1526,26 +1491,24 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1526
1491
|
});
|
|
1527
1492
|
this.fireStepStart("verify" /* Verify */);
|
|
1528
1493
|
const zkVerifierUrl = await this.getZkVerifierUrl();
|
|
1529
|
-
const
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
})
|
|
1494
|
+
const result = await zkVerifyBatch(
|
|
1495
|
+
zkVerifierUrl,
|
|
1496
|
+
proof,
|
|
1497
|
+
this.account,
|
|
1498
|
+
this.securityZone,
|
|
1499
|
+
this.chainId,
|
|
1500
|
+
this.consumingContract
|
|
1537
1501
|
);
|
|
1538
1502
|
this.fireStepEnd("verify" /* Verify */);
|
|
1539
|
-
return
|
|
1540
|
-
}
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
return [...hashes, proof];
|
|
1503
|
+
return result;
|
|
1504
|
+
}
|
|
1505
|
+
/**
|
|
1506
|
+
* Converts a batch-verified result (per-item ctHash/ctType + one shared signature) into the
|
|
1507
|
+
* tuple returned by `execute()`: per-item hashes in input order, followed by the single signature.
|
|
1508
|
+
*/
|
|
1509
|
+
buildBatchResult(result) {
|
|
1510
|
+
const hashes = result.outputs.map((output) => "0x" + BigInt(output.ct_hash).toString(16).padStart(64, "0"));
|
|
1511
|
+
return [...hashes, result.signature];
|
|
1549
1512
|
}
|
|
1550
1513
|
/**
|
|
1551
1514
|
* Final step of the encryption process. MUST BE CALLED LAST IN THE CHAIN.
|
|
@@ -1567,18 +1530,16 @@ var EncryptInputsBuilder = class extends BaseBuilder {
|
|
|
1567
1530
|
* @returns The encrypted inputs.
|
|
1568
1531
|
*/
|
|
1569
1532
|
async execute() {
|
|
1570
|
-
let
|
|
1533
|
+
let result;
|
|
1571
1534
|
if (this.chainId === chains.hardhat.id)
|
|
1572
|
-
|
|
1535
|
+
result = await this.mocksExecute();
|
|
1573
1536
|
else
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
return this.structsToHashPlusProof(items);
|
|
1577
|
-
return items;
|
|
1537
|
+
result = await this.productionExecute();
|
|
1538
|
+
return this.buildBatchResult(result);
|
|
1578
1539
|
}
|
|
1579
1540
|
};
|
|
1580
1541
|
|
|
1581
|
-
//
|
|
1542
|
+
// acps/utils.ts
|
|
1582
1543
|
var fromHexString = (hexString) => {
|
|
1583
1544
|
const cleanString = hexString.length % 2 === 1 ? `0${hexString}` : hexString;
|
|
1584
1545
|
const arr = cleanString.replace(/^0x/, "").match(/.{1,2}/g);
|
|
@@ -1598,120 +1559,33 @@ function toBigInt(value) {
|
|
|
1598
1559
|
return value;
|
|
1599
1560
|
}
|
|
1600
1561
|
}
|
|
1601
|
-
function toBeArray(value) {
|
|
1602
|
-
const bigIntValue = typeof value === "number" ? BigInt(value) : value;
|
|
1603
|
-
const hex = bigIntValue.toString(16);
|
|
1604
|
-
const paddedHex = hex.length % 2 === 0 ? hex : "0" + hex;
|
|
1605
|
-
return fromHexString(paddedHex);
|
|
1606
|
-
}
|
|
1607
|
-
function isString(value) {
|
|
1608
|
-
if (typeof value !== "string") {
|
|
1609
|
-
throw new Error(`Expected value which is \`string\`, received value of type \`${typeof value}\`.`);
|
|
1610
|
-
}
|
|
1611
|
-
}
|
|
1612
|
-
function isNumber(value) {
|
|
1613
|
-
const is = typeof value === "number" && !Number.isNaN(value);
|
|
1614
|
-
if (!is) {
|
|
1615
|
-
throw new Error(`Expected value which is \`number\`, received value of type \`${typeof value}\`.`);
|
|
1616
|
-
}
|
|
1617
|
-
}
|
|
1618
|
-
function isBigIntOrNumber(value) {
|
|
1619
|
-
const is = typeof value === "bigint";
|
|
1620
|
-
if (!is) {
|
|
1621
|
-
try {
|
|
1622
|
-
isNumber(value);
|
|
1623
|
-
} catch (e) {
|
|
1624
|
-
throw new Error(`Value ${value} is not a number or bigint: ${typeof value}`);
|
|
1625
|
-
}
|
|
1626
|
-
}
|
|
1627
|
-
}
|
|
1628
1562
|
|
|
1629
|
-
//
|
|
1630
|
-
var
|
|
1631
|
-
var PUBLIC_KEY_LENGTH = 64;
|
|
1632
|
-
var SealingKey = class _SealingKey {
|
|
1633
|
-
/**
|
|
1634
|
-
* The private key used for decryption.
|
|
1635
|
-
*/
|
|
1636
|
-
privateKey;
|
|
1637
|
-
/**
|
|
1638
|
-
* The public key used for encryption.
|
|
1639
|
-
*/
|
|
1640
|
-
publicKey;
|
|
1641
|
-
/**
|
|
1642
|
-
* Constructs a SealingKey instance with the given private and public keys.
|
|
1643
|
-
*
|
|
1644
|
-
* @param {string} privateKey - The private key used for decryption.
|
|
1645
|
-
* @param {string} publicKey - The public key used for encryption.
|
|
1646
|
-
* @throws Will throw an error if the provided keys lengths do not match
|
|
1647
|
-
* the required lengths for private and public keys.
|
|
1648
|
-
*/
|
|
1649
|
-
constructor(privateKey, publicKey) {
|
|
1650
|
-
if (privateKey.length !== PRIVATE_KEY_LENGTH) {
|
|
1651
|
-
throw new Error(`Private key must be of length ${PRIVATE_KEY_LENGTH}`);
|
|
1652
|
-
}
|
|
1653
|
-
if (publicKey.length !== PUBLIC_KEY_LENGTH) {
|
|
1654
|
-
throw new Error(`Public key must be of length ${PUBLIC_KEY_LENGTH}`);
|
|
1655
|
-
}
|
|
1656
|
-
this.privateKey = privateKey;
|
|
1657
|
-
this.publicKey = publicKey;
|
|
1658
|
-
}
|
|
1659
|
-
unseal = (parsedData) => {
|
|
1660
|
-
const nonce = parsedData.nonce instanceof Uint8Array ? parsedData.nonce : new Uint8Array(parsedData.nonce);
|
|
1661
|
-
const ephemPublicKey = parsedData.public_key instanceof Uint8Array ? parsedData.public_key : new Uint8Array(parsedData.public_key);
|
|
1662
|
-
const dataToDecrypt = parsedData.data instanceof Uint8Array ? parsedData.data : new Uint8Array(parsedData.data);
|
|
1663
|
-
const privateKeyBytes = fromHexString(this.privateKey);
|
|
1664
|
-
const decryptedMessage = nacl__default.default.box.open(dataToDecrypt, nonce, ephemPublicKey, privateKeyBytes);
|
|
1665
|
-
if (!decryptedMessage) {
|
|
1666
|
-
throw new Error("Failed to decrypt message");
|
|
1667
|
-
}
|
|
1668
|
-
return toBigInt(decryptedMessage);
|
|
1669
|
-
};
|
|
1670
|
-
/**
|
|
1671
|
-
* Serializes the SealingKey to a JSON object.
|
|
1672
|
-
*/
|
|
1673
|
-
serialize = () => {
|
|
1674
|
-
return {
|
|
1675
|
-
privateKey: this.privateKey,
|
|
1676
|
-
publicKey: this.publicKey
|
|
1677
|
-
};
|
|
1678
|
-
};
|
|
1679
|
-
/**
|
|
1680
|
-
* Deserializes the SealingKey from a JSON object.
|
|
1681
|
-
*/
|
|
1682
|
-
static deserialize = (privateKey, publicKey) => {
|
|
1683
|
-
return new _SealingKey(privateKey, publicKey);
|
|
1684
|
-
};
|
|
1685
|
-
/**
|
|
1686
|
-
* Seals (encrypts) the provided message for a receiver with the specified public key.
|
|
1687
|
-
*
|
|
1688
|
-
* @param {bigint | number} value - The message to be encrypted.
|
|
1689
|
-
* @param {string} publicKey - The public key of the intended recipient.
|
|
1690
|
-
* @returns string - The encrypted message in hexadecimal format.
|
|
1691
|
-
* @static
|
|
1692
|
-
* @throws Will throw if the provided publicKey or value do not meet defined preconditions.
|
|
1693
|
-
*/
|
|
1694
|
-
static seal = (value, publicKey) => {
|
|
1695
|
-
isString(publicKey);
|
|
1696
|
-
isBigIntOrNumber(value);
|
|
1697
|
-
const ephemeralKeyPair = nacl__default.default.box.keyPair();
|
|
1698
|
-
const nonce = nacl__default.default.randomBytes(nacl__default.default.box.nonceLength);
|
|
1699
|
-
const encryptedMessage = nacl__default.default.box(toBeArray(value), nonce, fromHexString(publicKey), ephemeralKeyPair.secretKey);
|
|
1700
|
-
return {
|
|
1701
|
-
data: encryptedMessage,
|
|
1702
|
-
public_key: ephemeralKeyPair.publicKey,
|
|
1703
|
-
nonce
|
|
1704
|
-
};
|
|
1705
|
-
};
|
|
1706
|
-
};
|
|
1563
|
+
// acps/sealing.ts
|
|
1564
|
+
var KEY_HEX_LENGTH = 64;
|
|
1707
1565
|
var GenerateSealingKey = () => {
|
|
1708
1566
|
const sodiumKeypair = nacl__default.default.box.keyPair();
|
|
1709
|
-
return
|
|
1567
|
+
return {
|
|
1568
|
+
privateKey: `0x${toHexString2(sodiumKeypair.secretKey)}`,
|
|
1569
|
+
publicKey: `0x${toHexString2(sodiumKeypair.publicKey)}`
|
|
1570
|
+
};
|
|
1571
|
+
};
|
|
1572
|
+
var unsealWithPrivateKey = (privateKey, parsedData) => {
|
|
1573
|
+
assertKeyLength(privateKey, "Private");
|
|
1574
|
+
const nonce = parsedData.nonce instanceof Uint8Array ? parsedData.nonce : new Uint8Array(parsedData.nonce);
|
|
1575
|
+
const ephemPublicKey = parsedData.public_key instanceof Uint8Array ? parsedData.public_key : new Uint8Array(parsedData.public_key);
|
|
1576
|
+
const dataToDecrypt = parsedData.data instanceof Uint8Array ? parsedData.data : new Uint8Array(parsedData.data);
|
|
1577
|
+
const decryptedMessage = nacl__default.default.box.open(dataToDecrypt, nonce, ephemPublicKey, fromHexString(privateKey));
|
|
1578
|
+
if (!decryptedMessage) {
|
|
1579
|
+
throw new Error("Failed to decrypt message");
|
|
1580
|
+
}
|
|
1581
|
+
return toBigInt(decryptedMessage);
|
|
1582
|
+
};
|
|
1583
|
+
var assertKeyLength = (key, kind) => {
|
|
1584
|
+
const bare = key.startsWith("0x") ? key.slice(2) : key;
|
|
1585
|
+
if (bare.length !== KEY_HEX_LENGTH) {
|
|
1586
|
+
throw new Error(`${kind} key must be of length ${KEY_HEX_LENGTH}`);
|
|
1587
|
+
}
|
|
1710
1588
|
};
|
|
1711
|
-
var SerializedSealingPair = zod.z.object({
|
|
1712
|
-
privateKey: zod.z.string(),
|
|
1713
|
-
publicKey: zod.z.string()
|
|
1714
|
-
});
|
|
1715
1589
|
var addressSchema = zod.z.string().refine((val) => viem.isAddress(val), {
|
|
1716
1590
|
error: "Invalid address"
|
|
1717
1591
|
}).transform((val) => viem.getAddress(val));
|
|
@@ -1730,46 +1604,70 @@ var bytesNotEmptySchema = bytesSchema.refine((val) => val !== "0x", {
|
|
|
1730
1604
|
error: "Must not be empty"
|
|
1731
1605
|
});
|
|
1732
1606
|
var DEFAULT_EXPIRATION_FN = () => Math.round(Date.now() / 1e3) + 7 * 24 * 60 * 60;
|
|
1733
|
-
var
|
|
1734
|
-
|
|
1607
|
+
var handlesSchema = zod.z.array(zod.z.string().regex(/^0x[0-9a-fA-F]{64}$/, "Invalid handle: expected 32-byte hex")).optional().default([]);
|
|
1608
|
+
var contractsSchema = zod.z.array(addressSchema).optional().default([]);
|
|
1609
|
+
var SCOPE_GLOBAL = 0;
|
|
1610
|
+
var SCOPE_CONTRACT = 1;
|
|
1611
|
+
var SCOPE_HANDLES = 2;
|
|
1612
|
+
var ScopeConsistencyRefinement = [
|
|
1613
|
+
(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,
|
|
1614
|
+
{
|
|
1615
|
+
error: "ACP scope :: arrays must match the scope mode (Global: both empty; Contract: contracts only; Handles: handles only)",
|
|
1616
|
+
path: ["scope"]
|
|
1617
|
+
}
|
|
1618
|
+
];
|
|
1619
|
+
var withDerivedScope = (data) => ({
|
|
1620
|
+
...data,
|
|
1621
|
+
scope: data.scope ?? (data.contracts.length > 0 ? SCOPE_CONTRACT : data.handles.length > 0 ? SCOPE_HANDLES : SCOPE_GLOBAL)
|
|
1622
|
+
});
|
|
1623
|
+
var zACPWithDefaults = zod.z.object({
|
|
1624
|
+
name: zod.z.string().optional().default("Unnamed ACP"),
|
|
1735
1625
|
type: zod.z.enum(["self", "sharing", "recipient"]),
|
|
1736
1626
|
issuer: addressNotZeroSchema,
|
|
1737
1627
|
expiration: zod.z.int().optional().default(DEFAULT_EXPIRATION_FN),
|
|
1738
1628
|
recipient: addressSchema.optional().default(viem.zeroAddress),
|
|
1739
|
-
|
|
1740
|
-
|
|
1629
|
+
revokerData: zod.z.int().optional().default(0),
|
|
1630
|
+
revokerContract: addressSchema.optional().default(viem.zeroAddress),
|
|
1631
|
+
scope: zod.z.int().min(0).max(2).optional().default(0),
|
|
1632
|
+
contracts: contractsSchema,
|
|
1633
|
+
handles: handlesSchema,
|
|
1741
1634
|
issuerSignature: bytesSchema.optional().default("0x"),
|
|
1742
1635
|
recipientSignature: bytesSchema.optional().default("0x")
|
|
1743
1636
|
});
|
|
1744
|
-
var
|
|
1745
|
-
|
|
1637
|
+
var zACPWithSealingKeys = zACPWithDefaults.extend({
|
|
1638
|
+
/** X25519 private key, 0x-prefixed 32-byte hex; never leaves the client */
|
|
1639
|
+
sealingPrivateKey: zod.z.string().regex(/^0x[0-9a-fA-F]{64}$/, "Invalid sealing private key").optional(),
|
|
1640
|
+
sealingKey: zod.z.string().regex(/^0x[0-9a-fA-F]{64}$/, "Invalid sealing key").optional()
|
|
1746
1641
|
});
|
|
1747
1642
|
var ExternalValidatorRefinement = [
|
|
1748
|
-
(data) => data.
|
|
1643
|
+
(data) => data.revokerData !== 0 && data.revokerContract !== viem.zeroAddress || data.revokerData === 0 && data.revokerContract === viem.zeroAddress,
|
|
1749
1644
|
{
|
|
1750
|
-
error: "
|
|
1751
|
-
path: ["
|
|
1645
|
+
error: "ACP external revoker :: revokerData and revokerContract must either both be set or both be unset.",
|
|
1646
|
+
path: ["revokerData", "revokerContract"]
|
|
1752
1647
|
}
|
|
1753
1648
|
];
|
|
1754
1649
|
var RecipientRefinement = [
|
|
1755
1650
|
(data) => data.issuer !== data.recipient,
|
|
1756
1651
|
{
|
|
1757
|
-
error: "Sharing
|
|
1652
|
+
error: "Sharing acp :: issuer and recipient must not be the same",
|
|
1758
1653
|
path: ["issuer", "recipient"]
|
|
1759
1654
|
}
|
|
1760
1655
|
];
|
|
1761
|
-
var
|
|
1656
|
+
var SelfACPOptionsValidator = zod.z.object({
|
|
1762
1657
|
type: zod.z.literal("self").optional().default("self"),
|
|
1763
1658
|
issuer: addressNotZeroSchema,
|
|
1764
|
-
name: zod.z.string().optional().default("Unnamed
|
|
1659
|
+
name: zod.z.string().optional().default("Unnamed ACP"),
|
|
1765
1660
|
expiration: zod.z.int().optional().default(DEFAULT_EXPIRATION_FN),
|
|
1766
1661
|
recipient: addressSchema.optional().default(viem.zeroAddress),
|
|
1767
|
-
|
|
1768
|
-
|
|
1662
|
+
revokerData: zod.z.int().optional().default(0),
|
|
1663
|
+
revokerContract: addressSchema.optional().default(viem.zeroAddress),
|
|
1664
|
+
scope: zod.z.int().min(0).max(2).optional(),
|
|
1665
|
+
contracts: contractsSchema,
|
|
1666
|
+
handles: handlesSchema,
|
|
1769
1667
|
issuerSignature: bytesSchema.optional().default("0x"),
|
|
1770
1668
|
recipientSignature: bytesSchema.optional().default("0x")
|
|
1771
|
-
}).refine(...ExternalValidatorRefinement);
|
|
1772
|
-
var
|
|
1669
|
+
}).refine(...ExternalValidatorRefinement).transform(withDerivedScope).refine(...ScopeConsistencyRefinement);
|
|
1670
|
+
var SelfACPValidator = zACPWithSealingKeys.refine((data) => data.type === "self", {
|
|
1773
1671
|
error: "Type must be 'self'"
|
|
1774
1672
|
}).refine((data) => data.recipient === viem.zeroAddress, {
|
|
1775
1673
|
error: "Recipient must be zeroAddress"
|
|
@@ -1778,18 +1676,21 @@ var SelfPermitValidator = zPermitWithSealingPair.refine((data) => data.type ===
|
|
|
1778
1676
|
}).refine((data) => data.recipientSignature === "0x", {
|
|
1779
1677
|
error: "RecipientSignature must be empty"
|
|
1780
1678
|
}).refine(...ExternalValidatorRefinement);
|
|
1781
|
-
var
|
|
1679
|
+
var SharingACPOptionsValidator = zod.z.object({
|
|
1782
1680
|
type: zod.z.literal("sharing").optional().default("sharing"),
|
|
1783
1681
|
issuer: addressNotZeroSchema,
|
|
1784
1682
|
recipient: addressNotZeroSchema,
|
|
1785
|
-
name: zod.z.string().optional().default("Unnamed
|
|
1683
|
+
name: zod.z.string().optional().default("Unnamed ACP"),
|
|
1786
1684
|
expiration: zod.z.int().optional().default(DEFAULT_EXPIRATION_FN),
|
|
1787
|
-
|
|
1788
|
-
|
|
1685
|
+
revokerData: zod.z.int().optional().default(0),
|
|
1686
|
+
revokerContract: addressSchema.optional().default(viem.zeroAddress),
|
|
1687
|
+
scope: zod.z.int().min(0).max(2).optional(),
|
|
1688
|
+
contracts: contractsSchema,
|
|
1689
|
+
handles: handlesSchema,
|
|
1789
1690
|
issuerSignature: bytesSchema.optional().default("0x"),
|
|
1790
1691
|
recipientSignature: bytesSchema.optional().default("0x")
|
|
1791
|
-
}).refine(...RecipientRefinement).refine(...ExternalValidatorRefinement);
|
|
1792
|
-
var
|
|
1692
|
+
}).refine(...RecipientRefinement).refine(...ExternalValidatorRefinement).transform(withDerivedScope).refine(...ScopeConsistencyRefinement);
|
|
1693
|
+
var SharingACPValidator = zACPWithSealingKeys.refine((data) => data.type === "sharing", {
|
|
1793
1694
|
error: "Type must be 'sharing'"
|
|
1794
1695
|
}).refine((data) => data.recipient !== viem.zeroAddress, {
|
|
1795
1696
|
error: "Recipient must not be zeroAddress"
|
|
@@ -1798,18 +1699,21 @@ var SharingPermitValidator = zPermitWithSealingPair.refine((data) => data.type =
|
|
|
1798
1699
|
}).refine((data) => data.recipientSignature === "0x", {
|
|
1799
1700
|
error: "RecipientSignature must be empty"
|
|
1800
1701
|
}).refine(...ExternalValidatorRefinement);
|
|
1801
|
-
var
|
|
1702
|
+
var ImportACPOptionsValidator = zod.z.object({
|
|
1802
1703
|
type: zod.z.literal("recipient").optional().default("recipient"),
|
|
1803
1704
|
issuer: addressNotZeroSchema,
|
|
1804
1705
|
recipient: addressNotZeroSchema,
|
|
1805
|
-
name: zod.z.string().optional().default("Unnamed
|
|
1706
|
+
name: zod.z.string().optional().default("Unnamed ACP"),
|
|
1806
1707
|
expiration: zod.z.int(),
|
|
1807
|
-
|
|
1808
|
-
|
|
1708
|
+
revokerData: zod.z.int().optional().default(0),
|
|
1709
|
+
revokerContract: addressSchema.optional().default(viem.zeroAddress),
|
|
1710
|
+
scope: zod.z.int().min(0).max(2).optional(),
|
|
1711
|
+
contracts: contractsSchema,
|
|
1712
|
+
handles: handlesSchema,
|
|
1809
1713
|
issuerSignature: bytesNotEmptySchema,
|
|
1810
1714
|
recipientSignature: bytesSchema.optional().default("0x")
|
|
1811
|
-
}).refine(...ExternalValidatorRefinement);
|
|
1812
|
-
var
|
|
1715
|
+
}).refine(...ExternalValidatorRefinement).transform(withDerivedScope).refine(...ScopeConsistencyRefinement);
|
|
1716
|
+
var ImportACPValidator = zACPWithSealingKeys.refine((data) => data.type === "recipient", {
|
|
1813
1717
|
error: "Type must be 'recipient'"
|
|
1814
1718
|
}).refine((data) => data.recipient !== viem.zeroAddress, {
|
|
1815
1719
|
error: "Recipient must not be zeroAddress"
|
|
@@ -1825,116 +1729,125 @@ var safeParseAndThrowFormatted = (schema, data, message) => {
|
|
|
1825
1729
|
}
|
|
1826
1730
|
return result.data;
|
|
1827
1731
|
};
|
|
1828
|
-
var
|
|
1829
|
-
return safeParseAndThrowFormatted(
|
|
1732
|
+
var validateSelfACPOptions = (options) => {
|
|
1733
|
+
return safeParseAndThrowFormatted(SelfACPOptionsValidator, options, "Invalid self acp options");
|
|
1830
1734
|
};
|
|
1831
|
-
var
|
|
1832
|
-
return safeParseAndThrowFormatted(
|
|
1735
|
+
var validateSharingACPOptions = (options) => {
|
|
1736
|
+
return safeParseAndThrowFormatted(SharingACPOptionsValidator, options, "Invalid sharing acp options");
|
|
1833
1737
|
};
|
|
1834
|
-
var
|
|
1835
|
-
return safeParseAndThrowFormatted(
|
|
1738
|
+
var validateImportACPOptions = (options) => {
|
|
1739
|
+
return safeParseAndThrowFormatted(ImportACPOptionsValidator, options, "Invalid import acp options");
|
|
1836
1740
|
};
|
|
1837
|
-
var
|
|
1838
|
-
return safeParseAndThrowFormatted(
|
|
1741
|
+
var validateSelfACP = (acp) => {
|
|
1742
|
+
return safeParseAndThrowFormatted(SelfACPValidator, acp, "Invalid self acp");
|
|
1839
1743
|
};
|
|
1840
|
-
var
|
|
1841
|
-
return safeParseAndThrowFormatted(
|
|
1744
|
+
var validateSharingACP = (acp) => {
|
|
1745
|
+
return safeParseAndThrowFormatted(SharingACPValidator, acp, "Invalid sharing acp");
|
|
1842
1746
|
};
|
|
1843
|
-
var
|
|
1844
|
-
return safeParseAndThrowFormatted(
|
|
1747
|
+
var validateImportACP = (acp) => {
|
|
1748
|
+
return safeParseAndThrowFormatted(ImportACPValidator, acp, "Invalid import acp");
|
|
1845
1749
|
};
|
|
1846
1750
|
var ValidationUtils = {
|
|
1847
1751
|
/**
|
|
1848
|
-
* Check if
|
|
1752
|
+
* Check if acp is expired
|
|
1849
1753
|
*/
|
|
1850
|
-
isExpired: (
|
|
1851
|
-
return
|
|
1754
|
+
isExpired: (acp) => {
|
|
1755
|
+
return acp.expiration < Math.floor(Date.now() / 1e3);
|
|
1852
1756
|
},
|
|
1853
1757
|
/**
|
|
1854
|
-
* Check if
|
|
1758
|
+
* Check if acp is signed by the active party
|
|
1855
1759
|
*/
|
|
1856
|
-
isSigned: (
|
|
1857
|
-
if (
|
|
1858
|
-
return
|
|
1760
|
+
isSigned: (acp) => {
|
|
1761
|
+
if (acp.type === "self" || acp.type === "sharing") {
|
|
1762
|
+
return acp.issuerSignature !== "0x";
|
|
1859
1763
|
}
|
|
1860
|
-
if (
|
|
1861
|
-
return
|
|
1764
|
+
if (acp.type === "recipient") {
|
|
1765
|
+
return acp.recipientSignature !== "0x";
|
|
1862
1766
|
}
|
|
1863
1767
|
return false;
|
|
1864
1768
|
},
|
|
1865
1769
|
/**
|
|
1866
|
-
* Checks that
|
|
1770
|
+
* Checks that an ACP is signed and not expired.
|
|
1867
1771
|
*/
|
|
1868
|
-
isSignedAndNotExpired: (
|
|
1869
|
-
if (ValidationUtils.isExpired(
|
|
1772
|
+
isSignedAndNotExpired: (acp) => {
|
|
1773
|
+
if (ValidationUtils.isExpired(acp)) {
|
|
1870
1774
|
return { valid: false, error: "expired" };
|
|
1871
1775
|
}
|
|
1872
|
-
if (!ValidationUtils.isSigned(
|
|
1776
|
+
if (!ValidationUtils.isSigned(acp)) {
|
|
1873
1777
|
return { valid: false, error: "not-signed" };
|
|
1874
1778
|
}
|
|
1875
1779
|
return { valid: true, error: null };
|
|
1876
1780
|
},
|
|
1877
1781
|
/**
|
|
1878
|
-
* Asserts that
|
|
1782
|
+
* Asserts that an ACP is signed and not expired.
|
|
1879
1783
|
*
|
|
1880
1784
|
* Throws `Error` with message:
|
|
1881
|
-
* - `
|
|
1882
|
-
* - `
|
|
1785
|
+
* - `ACP is expired`
|
|
1786
|
+
* - `ACP is not signed`
|
|
1883
1787
|
*/
|
|
1884
|
-
assertSignedAndNotExpired: (
|
|
1885
|
-
const result = ValidationUtils.isSignedAndNotExpired(
|
|
1788
|
+
assertSignedAndNotExpired: (acp) => {
|
|
1789
|
+
const result = ValidationUtils.isSignedAndNotExpired(acp);
|
|
1886
1790
|
if (result.valid)
|
|
1887
1791
|
return;
|
|
1888
1792
|
if (result.error === "expired") {
|
|
1889
|
-
throw new Error("
|
|
1793
|
+
throw new Error("ACP is expired");
|
|
1890
1794
|
}
|
|
1891
1795
|
if (result.error === "not-signed") {
|
|
1892
|
-
throw new Error("
|
|
1796
|
+
throw new Error("ACP is not signed");
|
|
1893
1797
|
}
|
|
1894
|
-
throw new Error("
|
|
1798
|
+
throw new Error("ACP is invalid");
|
|
1895
1799
|
},
|
|
1896
|
-
isValid: (
|
|
1897
|
-
const schema =
|
|
1800
|
+
isValid: (acp) => {
|
|
1801
|
+
const schema = acp.type === "self" ? SelfACPValidator : acp.type === "sharing" ? SharingACPValidator : acp.type === "recipient" ? ImportACPValidator : null;
|
|
1898
1802
|
if (schema == null)
|
|
1899
1803
|
return { valid: false, error: "invalid-schema" };
|
|
1900
|
-
const schemaResult = schema.safeParse(
|
|
1804
|
+
const schemaResult = schema.safeParse(acp);
|
|
1901
1805
|
if (!schemaResult.success)
|
|
1902
1806
|
return { valid: false, error: "invalid-schema" };
|
|
1903
|
-
return ValidationUtils.isSignedAndNotExpired(
|
|
1807
|
+
return ValidationUtils.isSignedAndNotExpired(acp);
|
|
1904
1808
|
}
|
|
1905
1809
|
};
|
|
1906
1810
|
|
|
1907
|
-
//
|
|
1908
|
-
var
|
|
1811
|
+
// acps/signature.ts
|
|
1812
|
+
var ACPSignatureAllFields = [
|
|
1909
1813
|
{ name: "issuer", type: "address" },
|
|
1910
1814
|
{ name: "expiration", type: "uint64" },
|
|
1911
1815
|
{ name: "recipient", type: "address" },
|
|
1912
|
-
{ name: "
|
|
1913
|
-
{ name: "
|
|
1816
|
+
{ name: "revokerData", type: "uint256" },
|
|
1817
|
+
{ name: "revokerContract", type: "address" },
|
|
1818
|
+
{ name: "scope", type: "uint8" },
|
|
1819
|
+
{ name: "contracts", type: "address[]" },
|
|
1820
|
+
{ name: "handles", type: "bytes32[]" },
|
|
1914
1821
|
{ name: "sealingKey", type: "bytes32" },
|
|
1915
1822
|
{ name: "issuerSignature", type: "bytes" }
|
|
1916
1823
|
];
|
|
1917
1824
|
var SignatureTypes = {
|
|
1918
|
-
|
|
1825
|
+
ACPIssuerSelf: [
|
|
1919
1826
|
"issuer",
|
|
1920
1827
|
"expiration",
|
|
1921
1828
|
"recipient",
|
|
1922
|
-
"
|
|
1923
|
-
"
|
|
1829
|
+
"revokerData",
|
|
1830
|
+
"revokerContract",
|
|
1831
|
+
"scope",
|
|
1832
|
+
"contracts",
|
|
1833
|
+
"handles",
|
|
1924
1834
|
"sealingKey"
|
|
1925
1835
|
],
|
|
1926
|
-
|
|
1836
|
+
ACPIssuerShared: [
|
|
1927
1837
|
"issuer",
|
|
1928
1838
|
"expiration",
|
|
1929
1839
|
"recipient",
|
|
1930
|
-
"
|
|
1931
|
-
"
|
|
1840
|
+
"revokerData",
|
|
1841
|
+
"revokerContract",
|
|
1842
|
+
"scope",
|
|
1843
|
+
"contracts",
|
|
1844
|
+
"handles"
|
|
1932
1845
|
],
|
|
1933
|
-
|
|
1846
|
+
ACPRecipient: ["sealingKey", "issuerSignature"]
|
|
1934
1847
|
};
|
|
1935
1848
|
var getSignatureTypesAndMessage = (primaryType, fields, values) => {
|
|
1936
1849
|
const types = {
|
|
1937
|
-
[primaryType]:
|
|
1850
|
+
[primaryType]: ACPSignatureAllFields.filter((fieldType) => fields.includes(fieldType.name))
|
|
1938
1851
|
};
|
|
1939
1852
|
const message = {};
|
|
1940
1853
|
fields.forEach((field) => {
|
|
@@ -1946,22 +1859,22 @@ var getSignatureTypesAndMessage = (primaryType, fields, values) => {
|
|
|
1946
1859
|
};
|
|
1947
1860
|
var SignatureUtils = {
|
|
1948
1861
|
/**
|
|
1949
|
-
* Get signature parameters for
|
|
1862
|
+
* Get signature parameters for an ACP
|
|
1950
1863
|
*/
|
|
1951
|
-
getSignatureParams: (
|
|
1952
|
-
return getSignatureTypesAndMessage(primaryType, SignatureTypes[primaryType],
|
|
1864
|
+
getSignatureParams: (acp, primaryType) => {
|
|
1865
|
+
return getSignatureTypesAndMessage(primaryType, SignatureTypes[primaryType], acp);
|
|
1953
1866
|
},
|
|
1954
1867
|
/**
|
|
1955
|
-
* Determine the required signature type based on
|
|
1868
|
+
* Determine the required signature type based on acp type
|
|
1956
1869
|
*/
|
|
1957
|
-
getPrimaryType: (
|
|
1958
|
-
if (
|
|
1959
|
-
return "
|
|
1960
|
-
if (
|
|
1961
|
-
return "
|
|
1962
|
-
if (
|
|
1963
|
-
return "
|
|
1964
|
-
throw new Error(`Unknown
|
|
1870
|
+
getPrimaryType: (acpType) => {
|
|
1871
|
+
if (acpType === "self")
|
|
1872
|
+
return "ACPIssuerSelf";
|
|
1873
|
+
if (acpType === "sharing")
|
|
1874
|
+
return "ACPIssuerShared";
|
|
1875
|
+
if (acpType === "recipient")
|
|
1876
|
+
return "ACPRecipient";
|
|
1877
|
+
throw new Error(`Unknown acp type: ${acpType}`);
|
|
1965
1878
|
}
|
|
1966
1879
|
};
|
|
1967
1880
|
var getAclAddress = async (publicClient) => {
|
|
@@ -1983,6 +1896,11 @@ var getAclEIP712Domain = async (publicClient) => {
|
|
|
1983
1896
|
functionName: "eip712Domain"
|
|
1984
1897
|
});
|
|
1985
1898
|
const [_fields, name, version, chainId, verifyingContract, _salt, _extensions] = domain;
|
|
1899
|
+
if (version !== "2") {
|
|
1900
|
+
throw new Error(
|
|
1901
|
+
`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.`
|
|
1902
|
+
);
|
|
1903
|
+
}
|
|
1986
1904
|
return {
|
|
1987
1905
|
name,
|
|
1988
1906
|
version,
|
|
@@ -1990,23 +1908,26 @@ var getAclEIP712Domain = async (publicClient) => {
|
|
|
1990
1908
|
verifyingContract
|
|
1991
1909
|
};
|
|
1992
1910
|
};
|
|
1993
|
-
var
|
|
1911
|
+
var checkACPValidityOnChain = async (acp, publicClient) => {
|
|
1994
1912
|
const aclAddress = await getAclAddress(publicClient);
|
|
1995
1913
|
try {
|
|
1996
1914
|
await publicClient.simulateContract({
|
|
1997
1915
|
address: aclAddress,
|
|
1998
|
-
abi:
|
|
1999
|
-
functionName: "
|
|
1916
|
+
abi: checkACPValidityAbi,
|
|
1917
|
+
functionName: "checkPermissionValidity",
|
|
2000
1918
|
args: [
|
|
2001
1919
|
{
|
|
2002
|
-
issuer:
|
|
2003
|
-
expiration: BigInt(
|
|
2004
|
-
recipient:
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
1920
|
+
issuer: acp.issuer,
|
|
1921
|
+
expiration: BigInt(acp.expiration),
|
|
1922
|
+
recipient: acp.recipient,
|
|
1923
|
+
revokerData: BigInt(acp.revokerData),
|
|
1924
|
+
revokerContract: acp.revokerContract,
|
|
1925
|
+
scope: acp.scope,
|
|
1926
|
+
contracts: acp.contracts,
|
|
1927
|
+
handles: acp.handles,
|
|
1928
|
+
sealingKey: acp.sealingKey,
|
|
1929
|
+
issuerSignature: acp.issuerSignature,
|
|
1930
|
+
recipientSignature: acp.recipientSignature
|
|
2010
1931
|
}
|
|
2011
1932
|
]
|
|
2012
1933
|
});
|
|
@@ -2019,14 +1940,14 @@ var checkPermitValidityOnChain = async (permission, publicClient) => {
|
|
|
2019
1940
|
throw new Error(errorName);
|
|
2020
1941
|
}
|
|
2021
1942
|
}
|
|
2022
|
-
const customErrorName = extractCustomErrorFromDetails(err,
|
|
1943
|
+
const customErrorName = extractCustomErrorFromDetails(err, checkACPValidityAbi);
|
|
2023
1944
|
if (customErrorName) {
|
|
2024
1945
|
throw new Error(customErrorName);
|
|
2025
1946
|
}
|
|
2026
1947
|
const hhDetailsData = extractReturnData(err);
|
|
2027
1948
|
if (hhDetailsData != null) {
|
|
2028
1949
|
const decoded = viem.decodeErrorResult({
|
|
2029
|
-
abi:
|
|
1950
|
+
abi: checkACPValidityAbi,
|
|
2030
1951
|
data: hhDetailsData
|
|
2031
1952
|
});
|
|
2032
1953
|
throw new Error(decoded.errorName);
|
|
@@ -2054,15 +1975,15 @@ function extractReturnData(err) {
|
|
|
2054
1975
|
const s = anyErr?.details ?? anyErr?.cause?.details ?? anyErr?.shortMessage ?? anyErr?.message ?? String(err);
|
|
2055
1976
|
return s.match(/return data:\s*(0x[a-fA-F0-9]+)/)?.[1];
|
|
2056
1977
|
}
|
|
2057
|
-
var
|
|
1978
|
+
var checkACPValidityAbi = [
|
|
2058
1979
|
{
|
|
2059
1980
|
type: "function",
|
|
2060
|
-
name: "
|
|
1981
|
+
name: "checkPermissionValidity",
|
|
2061
1982
|
inputs: [
|
|
2062
1983
|
{
|
|
2063
|
-
name: "
|
|
1984
|
+
name: "acp",
|
|
2064
1985
|
type: "tuple",
|
|
2065
|
-
internalType: "struct
|
|
1986
|
+
internalType: "struct ACP",
|
|
2066
1987
|
components: [
|
|
2067
1988
|
{
|
|
2068
1989
|
name: "issuer",
|
|
@@ -2080,15 +2001,30 @@ var checkPermitValidityAbi = [
|
|
|
2080
2001
|
internalType: "address"
|
|
2081
2002
|
},
|
|
2082
2003
|
{
|
|
2083
|
-
name: "
|
|
2004
|
+
name: "revokerData",
|
|
2084
2005
|
type: "uint256",
|
|
2085
2006
|
internalType: "uint256"
|
|
2086
2007
|
},
|
|
2087
2008
|
{
|
|
2088
|
-
name: "
|
|
2009
|
+
name: "revokerContract",
|
|
2089
2010
|
type: "address",
|
|
2090
2011
|
internalType: "address"
|
|
2091
2012
|
},
|
|
2013
|
+
{
|
|
2014
|
+
name: "scope",
|
|
2015
|
+
type: "uint8",
|
|
2016
|
+
internalType: "uint8"
|
|
2017
|
+
},
|
|
2018
|
+
{
|
|
2019
|
+
name: "contracts",
|
|
2020
|
+
type: "address[]",
|
|
2021
|
+
internalType: "address[]"
|
|
2022
|
+
},
|
|
2023
|
+
{
|
|
2024
|
+
name: "handles",
|
|
2025
|
+
type: "bytes32[]",
|
|
2026
|
+
internalType: "bytes32[]"
|
|
2027
|
+
},
|
|
2092
2028
|
{
|
|
2093
2029
|
name: "sealingKey",
|
|
2094
2030
|
type: "bytes32",
|
|
@@ -2138,38 +2074,40 @@ var checkPermitValidityAbi = [
|
|
|
2138
2074
|
}
|
|
2139
2075
|
];
|
|
2140
2076
|
|
|
2141
|
-
//
|
|
2142
|
-
var
|
|
2077
|
+
// acps/acp.ts
|
|
2078
|
+
var ACPUtils = {
|
|
2143
2079
|
/**
|
|
2144
|
-
* Create a self
|
|
2080
|
+
* Create a self acp for personal use
|
|
2145
2081
|
*/
|
|
2146
2082
|
createSelf: (options) => {
|
|
2147
|
-
const validation =
|
|
2083
|
+
const validation = validateSelfACPOptions(options);
|
|
2148
2084
|
const sealingPair = GenerateSealingKey();
|
|
2149
|
-
const
|
|
2150
|
-
hash:
|
|
2085
|
+
const acp = {
|
|
2086
|
+
hash: ACPUtils.getHash(validation),
|
|
2151
2087
|
...validation,
|
|
2152
|
-
sealingPair,
|
|
2088
|
+
sealingPrivateKey: sealingPair.privateKey,
|
|
2089
|
+
sealingKey: sealingPair.publicKey,
|
|
2153
2090
|
_signedDomain: void 0
|
|
2154
2091
|
};
|
|
2155
|
-
return
|
|
2092
|
+
return acp;
|
|
2156
2093
|
},
|
|
2157
2094
|
/**
|
|
2158
|
-
* Create a sharing
|
|
2095
|
+
* Create a sharing acp to be shared with another user
|
|
2159
2096
|
*/
|
|
2160
2097
|
createSharing: (options) => {
|
|
2161
|
-
const validation =
|
|
2098
|
+
const validation = validateSharingACPOptions(options);
|
|
2162
2099
|
const sealingPair = GenerateSealingKey();
|
|
2163
|
-
const
|
|
2164
|
-
hash:
|
|
2100
|
+
const acp = {
|
|
2101
|
+
hash: ACPUtils.getHash(validation),
|
|
2165
2102
|
...validation,
|
|
2166
|
-
sealingPair,
|
|
2103
|
+
sealingPrivateKey: sealingPair.privateKey,
|
|
2104
|
+
sealingKey: sealingPair.publicKey,
|
|
2167
2105
|
_signedDomain: void 0
|
|
2168
2106
|
};
|
|
2169
|
-
return
|
|
2107
|
+
return acp;
|
|
2170
2108
|
},
|
|
2171
2109
|
/**
|
|
2172
|
-
* Import a shared
|
|
2110
|
+
* Import a shared acp from various input formats
|
|
2173
2111
|
*/
|
|
2174
2112
|
importShared: (options) => {
|
|
2175
2113
|
let parsedOptions;
|
|
@@ -2182,33 +2120,34 @@ var PermitUtils = {
|
|
|
2182
2120
|
} else if (typeof options === "object" && options !== null) {
|
|
2183
2121
|
parsedOptions = options;
|
|
2184
2122
|
} else {
|
|
2185
|
-
throw new Error("Invalid input type, expected
|
|
2123
|
+
throw new Error("Invalid input type, expected ImportSharedACPOptions, object, or string");
|
|
2186
2124
|
}
|
|
2187
2125
|
if (parsedOptions.type != null && parsedOptions.type !== "sharing") {
|
|
2188
|
-
throw new Error(`Invalid
|
|
2126
|
+
throw new Error(`Invalid acp type <${parsedOptions.type}>, must be "sharing"`);
|
|
2189
2127
|
}
|
|
2190
|
-
const validation =
|
|
2128
|
+
const validation = validateImportACPOptions({ ...parsedOptions, type: "recipient" });
|
|
2191
2129
|
const sealingPair = GenerateSealingKey();
|
|
2192
|
-
const
|
|
2193
|
-
hash:
|
|
2130
|
+
const acp = {
|
|
2131
|
+
hash: ACPUtils.getHash(validation),
|
|
2194
2132
|
...validation,
|
|
2195
|
-
sealingPair,
|
|
2133
|
+
sealingPrivateKey: sealingPair.privateKey,
|
|
2134
|
+
sealingKey: sealingPair.publicKey,
|
|
2196
2135
|
_signedDomain: void 0
|
|
2197
2136
|
};
|
|
2198
|
-
return
|
|
2137
|
+
return acp;
|
|
2199
2138
|
},
|
|
2200
2139
|
/**
|
|
2201
|
-
* Sign
|
|
2140
|
+
* Sign an ACP with the provided wallet client
|
|
2202
2141
|
*/
|
|
2203
|
-
sign: async (
|
|
2142
|
+
sign: async (acp, publicClient, walletClient) => {
|
|
2204
2143
|
if (walletClient == null || walletClient.account == null) {
|
|
2205
2144
|
throw new Error(
|
|
2206
|
-
"Missing walletClient, you must pass in a `walletClient` for the connected user to create
|
|
2145
|
+
"Missing walletClient, you must pass in a `walletClient` for the connected user to create an ACP signature"
|
|
2207
2146
|
);
|
|
2208
2147
|
}
|
|
2209
|
-
const primaryType = SignatureUtils.getPrimaryType(
|
|
2148
|
+
const primaryType = SignatureUtils.getPrimaryType(acp.type);
|
|
2210
2149
|
const domain = await getAclEIP712Domain(publicClient);
|
|
2211
|
-
const { types, message } = SignatureUtils.getSignatureParams(
|
|
2150
|
+
const { types, message } = SignatureUtils.getSignatureParams(ACPUtils.getPublic(acp, true), primaryType);
|
|
2212
2151
|
const signature = await walletClient.signTypedData({
|
|
2213
2152
|
domain,
|
|
2214
2153
|
types,
|
|
@@ -2216,190 +2155,209 @@ var PermitUtils = {
|
|
|
2216
2155
|
message,
|
|
2217
2156
|
account: walletClient.account
|
|
2218
2157
|
});
|
|
2219
|
-
let
|
|
2220
|
-
if (
|
|
2221
|
-
|
|
2222
|
-
...
|
|
2158
|
+
let updatedACP;
|
|
2159
|
+
if (acp.type === "self" || acp.type === "sharing") {
|
|
2160
|
+
updatedACP = {
|
|
2161
|
+
...acp,
|
|
2223
2162
|
issuerSignature: signature,
|
|
2224
2163
|
_signedDomain: domain
|
|
2225
2164
|
};
|
|
2226
2165
|
} else {
|
|
2227
|
-
|
|
2228
|
-
...
|
|
2166
|
+
updatedACP = {
|
|
2167
|
+
...acp,
|
|
2229
2168
|
recipientSignature: signature,
|
|
2230
2169
|
_signedDomain: domain
|
|
2231
2170
|
};
|
|
2232
2171
|
}
|
|
2233
|
-
return
|
|
2172
|
+
return updatedACP;
|
|
2234
2173
|
},
|
|
2235
2174
|
/**
|
|
2236
|
-
* Create and sign a self
|
|
2175
|
+
* Create and sign a self acp in one operation
|
|
2237
2176
|
*/
|
|
2238
2177
|
createSelfAndSign: async (options, publicClient, walletClient) => {
|
|
2239
|
-
const
|
|
2240
|
-
return
|
|
2178
|
+
const acp = ACPUtils.createSelf(options);
|
|
2179
|
+
return ACPUtils.sign(acp, publicClient, walletClient);
|
|
2241
2180
|
},
|
|
2242
2181
|
/**
|
|
2243
|
-
* Create and sign a sharing
|
|
2182
|
+
* Create and sign a sharing acp in one operation
|
|
2244
2183
|
*/
|
|
2245
2184
|
createSharingAndSign: async (options, publicClient, walletClient) => {
|
|
2246
|
-
const
|
|
2247
|
-
return
|
|
2185
|
+
const acp = ACPUtils.createSharing(options);
|
|
2186
|
+
return ACPUtils.sign(acp, publicClient, walletClient);
|
|
2248
2187
|
},
|
|
2249
2188
|
/**
|
|
2250
|
-
* Import and sign a shared
|
|
2189
|
+
* Import and sign a shared acp in one operation from various input formats
|
|
2251
2190
|
*/
|
|
2252
2191
|
importSharedAndSign: async (options, publicClient, walletClient) => {
|
|
2253
|
-
const
|
|
2254
|
-
return
|
|
2192
|
+
const acp = ACPUtils.importShared(options);
|
|
2193
|
+
return ACPUtils.sign(acp, publicClient, walletClient);
|
|
2255
2194
|
},
|
|
2256
2195
|
/**
|
|
2257
|
-
* Deserialize
|
|
2196
|
+
* Deserialize an ACP from serialized data
|
|
2258
2197
|
*/
|
|
2259
2198
|
deserialize: (data) => {
|
|
2260
|
-
return {
|
|
2261
|
-
...data,
|
|
2262
|
-
sealingPair: SealingKey.deserialize(data.sealingPair.privateKey, data.sealingPair.publicKey)
|
|
2263
|
-
};
|
|
2199
|
+
return { ...data };
|
|
2264
2200
|
},
|
|
2265
2201
|
/**
|
|
2266
|
-
* Serialize
|
|
2202
|
+
* Serialize an ACP for storage
|
|
2267
2203
|
*/
|
|
2268
|
-
serialize: (
|
|
2204
|
+
serialize: (acp) => {
|
|
2269
2205
|
return {
|
|
2270
|
-
hash:
|
|
2271
|
-
name:
|
|
2272
|
-
type:
|
|
2273
|
-
issuer:
|
|
2274
|
-
expiration:
|
|
2275
|
-
recipient:
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2206
|
+
hash: acp.hash,
|
|
2207
|
+
name: acp.name,
|
|
2208
|
+
type: acp.type,
|
|
2209
|
+
issuer: acp.issuer,
|
|
2210
|
+
expiration: acp.expiration,
|
|
2211
|
+
recipient: acp.recipient,
|
|
2212
|
+
revokerData: acp.revokerData,
|
|
2213
|
+
revokerContract: acp.revokerContract,
|
|
2214
|
+
scope: acp.scope,
|
|
2215
|
+
contracts: acp.contracts,
|
|
2216
|
+
handles: acp.handles,
|
|
2217
|
+
sealingKey: acp.sealingKey,
|
|
2218
|
+
issuerSignature: acp.issuerSignature,
|
|
2219
|
+
recipientSignature: acp.recipientSignature,
|
|
2220
|
+
_signedDomain: acp._signedDomain,
|
|
2221
|
+
sealingPrivateKey: acp.sealingPrivateKey
|
|
2282
2222
|
};
|
|
2283
2223
|
},
|
|
2284
2224
|
/**
|
|
2285
|
-
* Validate
|
|
2225
|
+
* Validate an ACP (schema-level validation)
|
|
2286
2226
|
*/
|
|
2287
|
-
validateSchema: (
|
|
2288
|
-
if (
|
|
2289
|
-
return
|
|
2290
|
-
} else if (
|
|
2291
|
-
return
|
|
2292
|
-
} else if (
|
|
2293
|
-
return
|
|
2227
|
+
validateSchema: (acp) => {
|
|
2228
|
+
if (acp.type === "self") {
|
|
2229
|
+
return validateSelfACP(acp);
|
|
2230
|
+
} else if (acp.type === "sharing") {
|
|
2231
|
+
return validateSharingACP(acp);
|
|
2232
|
+
} else if (acp.type === "recipient") {
|
|
2233
|
+
return validateImportACP(acp);
|
|
2294
2234
|
} else {
|
|
2295
|
-
throw new Error("Invalid
|
|
2235
|
+
throw new Error("Invalid ACP type");
|
|
2296
2236
|
}
|
|
2297
2237
|
},
|
|
2298
2238
|
/**
|
|
2299
|
-
* Validate
|
|
2239
|
+
* Validate an ACP (holistic validation).
|
|
2300
2240
|
*
|
|
2301
2241
|
* This validates:
|
|
2302
|
-
* -
|
|
2303
|
-
* -
|
|
2304
|
-
* -
|
|
2242
|
+
* - ACP schema (shape + invariants)
|
|
2243
|
+
* - ACP is signed
|
|
2244
|
+
* - ACP is not expired
|
|
2305
2245
|
*
|
|
2306
|
-
* For schema-only validation, use `validateSchema(
|
|
2246
|
+
* For schema-only validation, use `validateSchema(acp)`.
|
|
2307
2247
|
*/
|
|
2308
|
-
validate: (
|
|
2309
|
-
const validated =
|
|
2248
|
+
validate: (acp) => {
|
|
2249
|
+
const validated = ACPUtils.validateSchema(acp);
|
|
2310
2250
|
ValidationUtils.assertSignedAndNotExpired(validated);
|
|
2311
2251
|
return validated;
|
|
2312
2252
|
},
|
|
2313
2253
|
/**
|
|
2314
|
-
* Get the
|
|
2254
|
+
* Get the public component of an ACP — the signed struct sent on-chain / to the decryption backend.
|
|
2255
|
+
* Strips the private component (hash, name, type, sealing pair).
|
|
2315
2256
|
*/
|
|
2316
|
-
|
|
2257
|
+
getPublic: (acp, skipValidation = false) => {
|
|
2317
2258
|
if (!skipValidation) {
|
|
2318
|
-
|
|
2259
|
+
ACPUtils.validateSchema(acp);
|
|
2319
2260
|
}
|
|
2320
2261
|
return {
|
|
2321
|
-
issuer:
|
|
2322
|
-
expiration:
|
|
2323
|
-
recipient:
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2262
|
+
issuer: acp.issuer,
|
|
2263
|
+
expiration: acp.expiration,
|
|
2264
|
+
recipient: acp.recipient,
|
|
2265
|
+
revokerData: acp.revokerData,
|
|
2266
|
+
revokerContract: acp.revokerContract,
|
|
2267
|
+
scope: acp.scope,
|
|
2268
|
+
contracts: acp.contracts,
|
|
2269
|
+
handles: acp.handles,
|
|
2270
|
+
sealingKey: acp.sealingKey,
|
|
2271
|
+
issuerSignature: acp.issuerSignature,
|
|
2272
|
+
recipientSignature: acp.recipientSignature
|
|
2329
2273
|
};
|
|
2330
2274
|
},
|
|
2331
2275
|
/**
|
|
2332
|
-
* Get a stable hash for the
|
|
2276
|
+
* Get a stable hash for the acp (used as key in storage)
|
|
2333
2277
|
*/
|
|
2334
|
-
getHash: (
|
|
2278
|
+
getHash: (acp) => {
|
|
2335
2279
|
const data = JSON.stringify({
|
|
2336
|
-
type:
|
|
2337
|
-
issuer:
|
|
2338
|
-
expiration:
|
|
2339
|
-
recipient:
|
|
2340
|
-
|
|
2341
|
-
|
|
2280
|
+
type: acp.type,
|
|
2281
|
+
issuer: acp.issuer,
|
|
2282
|
+
expiration: acp.expiration,
|
|
2283
|
+
recipient: acp.recipient,
|
|
2284
|
+
revokerData: acp.revokerData,
|
|
2285
|
+
revokerContract: acp.revokerContract,
|
|
2286
|
+
scope: acp.scope,
|
|
2287
|
+
contracts: acp.contracts,
|
|
2288
|
+
handles: acp.handles
|
|
2342
2289
|
});
|
|
2343
2290
|
return viem.keccak256(viem.toHex(data));
|
|
2344
2291
|
},
|
|
2345
2292
|
/**
|
|
2346
|
-
* Export
|
|
2293
|
+
* Export acp data for sharing (strips the private component).
|
|
2294
|
+
* Fixed `SharedACP` shape — every field always present, aligned with
|
|
2295
|
+
* `ACPPublic` and the on-chain sharing payload.
|
|
2347
2296
|
*/
|
|
2348
|
-
export: (
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2297
|
+
export: (acp) => {
|
|
2298
|
+
if (acp.type !== "sharing") {
|
|
2299
|
+
throw new Error(
|
|
2300
|
+
`Cannot export a '${acp.type}' ACP \u2014 only 'sharing' ACPs are exportable. The export includes the issuer signature.`
|
|
2301
|
+
);
|
|
2302
|
+
}
|
|
2303
|
+
if (acp.issuerSignature === "0x") {
|
|
2304
|
+
throw new Error(
|
|
2305
|
+
"Cannot export an unsigned sharing ACP \u2014 sign it first (the recipient needs the issuer signature)."
|
|
2306
|
+
);
|
|
2307
|
+
}
|
|
2308
|
+
const shared = {
|
|
2309
|
+
name: acp.name,
|
|
2310
|
+
type: acp.type,
|
|
2311
|
+
issuer: acp.issuer,
|
|
2312
|
+
expiration: acp.expiration,
|
|
2313
|
+
recipient: acp.recipient,
|
|
2314
|
+
revokerData: acp.revokerData,
|
|
2315
|
+
revokerContract: acp.revokerContract,
|
|
2316
|
+
scope: acp.scope,
|
|
2317
|
+
contracts: acp.contracts,
|
|
2318
|
+
handles: acp.handles,
|
|
2319
|
+
issuerSignature: acp.issuerSignature
|
|
2354
2320
|
};
|
|
2355
|
-
|
|
2356
|
-
cleanedPermit.recipient = permit.recipient;
|
|
2357
|
-
if (permit.validatorId !== 0)
|
|
2358
|
-
cleanedPermit.validatorId = permit.validatorId;
|
|
2359
|
-
if (permit.validatorContract !== viem.zeroAddress)
|
|
2360
|
-
cleanedPermit.validatorContract = permit.validatorContract;
|
|
2361
|
-
if (permit.type === "sharing" && permit.issuerSignature !== "0x")
|
|
2362
|
-
cleanedPermit.issuerSignature = permit.issuerSignature;
|
|
2363
|
-
return JSON.stringify(cleanedPermit, void 0, 2);
|
|
2321
|
+
return JSON.stringify(shared, void 0, 2);
|
|
2364
2322
|
},
|
|
2365
2323
|
/**
|
|
2366
|
-
* Unseal encrypted data using the
|
|
2324
|
+
* Unseal encrypted data using the acp's sealing key
|
|
2367
2325
|
*/
|
|
2368
|
-
unseal: (
|
|
2369
|
-
return
|
|
2326
|
+
unseal: (acp, ciphertext) => {
|
|
2327
|
+
return unsealWithPrivateKey(acp.sealingPrivateKey, ciphertext);
|
|
2370
2328
|
},
|
|
2371
2329
|
/**
|
|
2372
|
-
* Check if
|
|
2330
|
+
* Check if acp is expired
|
|
2373
2331
|
*/
|
|
2374
|
-
isExpired: (
|
|
2375
|
-
return ValidationUtils.isExpired(
|
|
2332
|
+
isExpired: (acp) => {
|
|
2333
|
+
return ValidationUtils.isExpired(acp);
|
|
2376
2334
|
},
|
|
2377
2335
|
/**
|
|
2378
|
-
* Check if
|
|
2336
|
+
* Check if acp is signed
|
|
2379
2337
|
*/
|
|
2380
|
-
isSigned: (
|
|
2381
|
-
return ValidationUtils.isSigned(
|
|
2338
|
+
isSigned: (acp) => {
|
|
2339
|
+
return ValidationUtils.isSigned(acp);
|
|
2382
2340
|
},
|
|
2383
2341
|
/**
|
|
2384
|
-
* Check if
|
|
2342
|
+
* Check if acp is signed and not expired
|
|
2385
2343
|
*/
|
|
2386
|
-
isSignedAndNotExpired: (
|
|
2387
|
-
return ValidationUtils.isSignedAndNotExpired(
|
|
2344
|
+
isSignedAndNotExpired: (acp) => {
|
|
2345
|
+
return ValidationUtils.isSignedAndNotExpired(acp);
|
|
2388
2346
|
},
|
|
2389
2347
|
/**
|
|
2390
|
-
* Assert that
|
|
2348
|
+
* Assert that acp is signed and not expired
|
|
2391
2349
|
*/
|
|
2392
|
-
assertSignedAndNotExpired: (
|
|
2393
|
-
return ValidationUtils.assertSignedAndNotExpired(
|
|
2350
|
+
assertSignedAndNotExpired: (acp) => {
|
|
2351
|
+
return ValidationUtils.assertSignedAndNotExpired(acp);
|
|
2394
2352
|
},
|
|
2395
|
-
isValid: (
|
|
2396
|
-
return ValidationUtils.isValid(
|
|
2353
|
+
isValid: (acp) => {
|
|
2354
|
+
return ValidationUtils.isValid(acp);
|
|
2397
2355
|
},
|
|
2398
2356
|
/**
|
|
2399
|
-
* Update
|
|
2357
|
+
* Update acp name (returns new acp instance)
|
|
2400
2358
|
*/
|
|
2401
|
-
updateName: (
|
|
2402
|
-
return { ...
|
|
2359
|
+
updateName: (acp, name) => {
|
|
2360
|
+
return { ...acp, name };
|
|
2403
2361
|
},
|
|
2404
2362
|
/**
|
|
2405
2363
|
* Fetch EIP712 domain from the blockchain
|
|
@@ -2408,230 +2366,468 @@ var PermitUtils = {
|
|
|
2408
2366
|
return getAclEIP712Domain(publicClient);
|
|
2409
2367
|
},
|
|
2410
2368
|
/**
|
|
2411
|
-
* Check if
|
|
2369
|
+
* Check if acp's signed domain matches the provided domain
|
|
2412
2370
|
*/
|
|
2413
|
-
matchesDomain: (
|
|
2414
|
-
return
|
|
2371
|
+
matchesDomain: (acp, domain) => {
|
|
2372
|
+
return acp._signedDomain?.name === domain.name && acp._signedDomain?.version === domain.version && acp._signedDomain?.verifyingContract === domain.verifyingContract && acp._signedDomain?.chainId === domain.chainId;
|
|
2415
2373
|
},
|
|
2416
2374
|
/**
|
|
2417
|
-
* Check if
|
|
2375
|
+
* Check if acp's signed domain is valid for the current chain
|
|
2418
2376
|
*/
|
|
2419
|
-
checkSignedDomainValid: async (
|
|
2420
|
-
if (
|
|
2377
|
+
checkSignedDomainValid: async (acp, publicClient) => {
|
|
2378
|
+
if (acp._signedDomain == null)
|
|
2421
2379
|
return false;
|
|
2422
2380
|
const domain = await getAclEIP712Domain(publicClient);
|
|
2423
|
-
return
|
|
2381
|
+
return ACPUtils.matchesDomain(acp, domain);
|
|
2424
2382
|
},
|
|
2425
2383
|
/**
|
|
2426
|
-
* Check if
|
|
2384
|
+
* Check if acp passes the on-chain validation
|
|
2427
2385
|
*/
|
|
2428
|
-
checkValidityOnChain: async (
|
|
2429
|
-
const
|
|
2430
|
-
return
|
|
2386
|
+
checkValidityOnChain: async (acp, publicClient) => {
|
|
2387
|
+
const publicAcp = ACPUtils.getPublic(acp);
|
|
2388
|
+
return checkACPValidityOnChain(publicAcp, publicClient);
|
|
2431
2389
|
}
|
|
2432
2390
|
};
|
|
2433
|
-
var
|
|
2434
|
-
|
|
2435
|
-
|
|
2391
|
+
var ACP_STORE_DEFAULTS = {
|
|
2392
|
+
acps: {},
|
|
2393
|
+
activeACPHash: {}
|
|
2436
2394
|
};
|
|
2437
|
-
var
|
|
2438
|
-
|
|
2395
|
+
var ACP_STORE_VERSION = 3;
|
|
2396
|
+
var _acpStore = vanilla.createStore()(
|
|
2397
|
+
middleware.persist(() => ACP_STORE_DEFAULTS, {
|
|
2398
|
+
name: "cofhesdk-acps",
|
|
2399
|
+
version: ACP_STORE_VERSION,
|
|
2400
|
+
migrate: (persistedState, version) => {
|
|
2401
|
+
if (version < ACP_STORE_VERSION)
|
|
2402
|
+
return ACP_STORE_DEFAULTS;
|
|
2403
|
+
return persistedState;
|
|
2404
|
+
}
|
|
2405
|
+
})
|
|
2439
2406
|
);
|
|
2440
2407
|
var clearStaleStore = () => {
|
|
2441
|
-
const state =
|
|
2442
|
-
const hasExpectedStructure = state && typeof state === "object" && "
|
|
2408
|
+
const state = _acpStore.getState();
|
|
2409
|
+
const hasExpectedStructure = state && typeof state === "object" && "acps" in state && "activeACPHash" in state && typeof state.acps === "object" && typeof state.activeACPHash === "object";
|
|
2443
2410
|
if (hasExpectedStructure)
|
|
2444
2411
|
return;
|
|
2445
|
-
|
|
2412
|
+
_acpStore.setState({ acps: {}, activeACPHash: {} });
|
|
2446
2413
|
};
|
|
2447
|
-
var
|
|
2414
|
+
var getACP = (chainId, account, hash) => {
|
|
2448
2415
|
clearStaleStore();
|
|
2449
2416
|
if (chainId == null || account == null || hash == null)
|
|
2450
2417
|
return;
|
|
2451
|
-
const
|
|
2452
|
-
if (
|
|
2418
|
+
const savedACP = _acpStore.getState().acps[chainId]?.[account]?.[hash];
|
|
2419
|
+
if (savedACP == null)
|
|
2453
2420
|
return;
|
|
2454
|
-
return
|
|
2421
|
+
return ACPUtils.deserialize(savedACP);
|
|
2455
2422
|
};
|
|
2456
|
-
var
|
|
2423
|
+
var getActiveACP = (chainId, account) => {
|
|
2457
2424
|
clearStaleStore();
|
|
2458
2425
|
if (chainId == null || account == null)
|
|
2459
2426
|
return;
|
|
2460
|
-
const
|
|
2461
|
-
return
|
|
2427
|
+
const activeACPHash = _acpStore.getState().activeACPHash[chainId]?.[account];
|
|
2428
|
+
return getACP(chainId, account, activeACPHash);
|
|
2462
2429
|
};
|
|
2463
|
-
var
|
|
2430
|
+
var getACPs = (chainId, account) => {
|
|
2464
2431
|
clearStaleStore();
|
|
2465
2432
|
if (chainId == null || account == null)
|
|
2466
2433
|
return {};
|
|
2467
|
-
return Object.entries(
|
|
2468
|
-
(acc, [hash,
|
|
2469
|
-
if (
|
|
2434
|
+
return Object.entries(_acpStore.getState().acps[chainId]?.[account] ?? {}).reduce(
|
|
2435
|
+
(acc, [hash, acp]) => {
|
|
2436
|
+
if (acp == void 0)
|
|
2470
2437
|
return acc;
|
|
2471
|
-
return { ...acc, [hash]:
|
|
2438
|
+
return { ...acc, [hash]: ACPUtils.deserialize(acp) };
|
|
2472
2439
|
},
|
|
2473
2440
|
{}
|
|
2474
2441
|
);
|
|
2475
2442
|
};
|
|
2476
|
-
var
|
|
2443
|
+
var setACP = (chainId, account, acp) => {
|
|
2477
2444
|
clearStaleStore();
|
|
2478
|
-
|
|
2445
|
+
_acpStore.setState(
|
|
2479
2446
|
immer.produce((state) => {
|
|
2480
|
-
if (state.
|
|
2481
|
-
state.
|
|
2482
|
-
if (state.
|
|
2483
|
-
state.
|
|
2484
|
-
state.
|
|
2447
|
+
if (state.acps[chainId] == null)
|
|
2448
|
+
state.acps[chainId] = {};
|
|
2449
|
+
if (state.acps[chainId][account] == null)
|
|
2450
|
+
state.acps[chainId][account] = {};
|
|
2451
|
+
state.acps[chainId][account][acp.hash] = ACPUtils.serialize(acp);
|
|
2485
2452
|
})
|
|
2486
2453
|
);
|
|
2487
2454
|
};
|
|
2488
|
-
var
|
|
2455
|
+
var removeACP = (chainId, account, hash) => {
|
|
2489
2456
|
clearStaleStore();
|
|
2490
|
-
|
|
2457
|
+
_acpStore.setState(
|
|
2491
2458
|
immer.produce((state) => {
|
|
2492
|
-
if (state.
|
|
2493
|
-
state.
|
|
2494
|
-
if (state.
|
|
2495
|
-
state.
|
|
2496
|
-
const
|
|
2497
|
-
if (
|
|
2459
|
+
if (state.acps[chainId] == null)
|
|
2460
|
+
state.acps[chainId] = {};
|
|
2461
|
+
if (state.activeACPHash[chainId] == null)
|
|
2462
|
+
state.activeACPHash[chainId] = {};
|
|
2463
|
+
const accountACPs = state.acps[chainId][account];
|
|
2464
|
+
if (accountACPs == null)
|
|
2498
2465
|
return;
|
|
2499
|
-
if (
|
|
2466
|
+
if (accountACPs[hash] == null)
|
|
2500
2467
|
return;
|
|
2501
|
-
if (state.
|
|
2502
|
-
state.
|
|
2468
|
+
if (state.activeACPHash[chainId][account] === hash) {
|
|
2469
|
+
state.activeACPHash[chainId][account] = void 0;
|
|
2503
2470
|
}
|
|
2504
|
-
|
|
2471
|
+
accountACPs[hash] = void 0;
|
|
2505
2472
|
})
|
|
2506
2473
|
);
|
|
2507
2474
|
};
|
|
2508
|
-
var
|
|
2475
|
+
var getActiveACPHash = (chainId, account) => {
|
|
2509
2476
|
clearStaleStore();
|
|
2510
2477
|
if (chainId == null || account == null)
|
|
2511
2478
|
return void 0;
|
|
2512
|
-
return
|
|
2479
|
+
return _acpStore.getState().activeACPHash[chainId]?.[account];
|
|
2513
2480
|
};
|
|
2514
|
-
var
|
|
2481
|
+
var setActiveACPHash = (chainId, account, hash) => {
|
|
2515
2482
|
clearStaleStore();
|
|
2516
|
-
|
|
2483
|
+
_acpStore.setState(
|
|
2517
2484
|
immer.produce((state) => {
|
|
2518
|
-
if (state.
|
|
2519
|
-
state.
|
|
2520
|
-
state.
|
|
2485
|
+
if (state.activeACPHash[chainId] == null)
|
|
2486
|
+
state.activeACPHash[chainId] = {};
|
|
2487
|
+
state.activeACPHash[chainId][account] = hash;
|
|
2521
2488
|
})
|
|
2522
2489
|
);
|
|
2523
2490
|
};
|
|
2524
|
-
var
|
|
2491
|
+
var removeActiveACPHash = (chainId, account) => {
|
|
2525
2492
|
clearStaleStore();
|
|
2526
|
-
|
|
2493
|
+
_acpStore.setState(
|
|
2527
2494
|
immer.produce((state) => {
|
|
2528
|
-
if (state.
|
|
2529
|
-
state.
|
|
2495
|
+
if (state.activeACPHash[chainId])
|
|
2496
|
+
state.activeACPHash[chainId][account] = void 0;
|
|
2530
2497
|
})
|
|
2531
2498
|
);
|
|
2532
2499
|
};
|
|
2533
2500
|
var resetStore = () => {
|
|
2534
2501
|
clearStaleStore();
|
|
2535
|
-
|
|
2502
|
+
_acpStore.setState({ acps: {}, activeACPHash: {} });
|
|
2536
2503
|
};
|
|
2537
|
-
var
|
|
2538
|
-
store:
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2504
|
+
var acpStore = {
|
|
2505
|
+
store: _acpStore,
|
|
2506
|
+
getACP,
|
|
2507
|
+
getActiveACP,
|
|
2508
|
+
getACPs,
|
|
2509
|
+
setACP,
|
|
2510
|
+
removeACP,
|
|
2511
|
+
getActiveACPHash,
|
|
2512
|
+
setActiveACPHash,
|
|
2513
|
+
removeActiveACPHash,
|
|
2547
2514
|
resetStore
|
|
2548
2515
|
};
|
|
2549
|
-
var
|
|
2516
|
+
var ACP_VALIDATOR_ABI = viem.parseAbi([
|
|
2517
|
+
"function revokeSingle(uint256 id)",
|
|
2518
|
+
"function revokeAllExisting()",
|
|
2519
|
+
"function disabled(address issuer, uint256 id) view returns (bool)"
|
|
2520
|
+
]);
|
|
2521
|
+
var storeACP = async (acp, publicClient, walletClient) => {
|
|
2522
|
+
const chainId = await publicClient.getChainId();
|
|
2523
|
+
const account = walletClient.account.address;
|
|
2524
|
+
acpStore.setACP(chainId, account, acp);
|
|
2525
|
+
};
|
|
2526
|
+
var storeActiveACP = async (acp, publicClient, walletClient) => {
|
|
2527
|
+
await storeACP(acp, publicClient, walletClient);
|
|
2550
2528
|
const chainId = await publicClient.getChainId();
|
|
2551
2529
|
const account = walletClient.account.address;
|
|
2552
|
-
|
|
2553
|
-
permitStore.setActivePermitHash(chainId, account, permit.hash);
|
|
2530
|
+
acpStore.setActiveACPHash(chainId, account, acp.hash);
|
|
2554
2531
|
};
|
|
2555
|
-
var
|
|
2556
|
-
const
|
|
2557
|
-
|
|
2558
|
-
|
|
2532
|
+
var createACPWithSign = async (options, publicClient, walletClient, acpMethod, activate = true) => {
|
|
2533
|
+
const acp = await acpMethod(options, publicClient, walletClient);
|
|
2534
|
+
if (activate) {
|
|
2535
|
+
await storeActiveACP(acp, publicClient, walletClient);
|
|
2536
|
+
} else {
|
|
2537
|
+
await storeACP(acp, publicClient, walletClient);
|
|
2538
|
+
}
|
|
2539
|
+
return acp;
|
|
2559
2540
|
};
|
|
2560
2541
|
var createSelf = async (options, publicClient, walletClient) => {
|
|
2561
|
-
return
|
|
2542
|
+
return createACPWithSign(options, publicClient, walletClient, ACPUtils.createSelfAndSign);
|
|
2562
2543
|
};
|
|
2563
2544
|
var createSharing = async (options, publicClient, walletClient) => {
|
|
2564
|
-
return
|
|
2545
|
+
return createACPWithSign(options, publicClient, walletClient, ACPUtils.createSharingAndSign, false);
|
|
2565
2546
|
};
|
|
2566
2547
|
var importShared = async (options, publicClient, walletClient) => {
|
|
2567
|
-
return
|
|
2548
|
+
return createACPWithSign(options, publicClient, walletClient, ACPUtils.importSharedAndSign);
|
|
2568
2549
|
};
|
|
2569
|
-
var getHash = (
|
|
2570
|
-
return
|
|
2550
|
+
var getHash = (acp) => {
|
|
2551
|
+
return ACPUtils.getHash(acp);
|
|
2571
2552
|
};
|
|
2572
|
-
var exportShared = (
|
|
2573
|
-
return
|
|
2553
|
+
var exportShared = (acp) => {
|
|
2554
|
+
return ACPUtils.export(acp);
|
|
2574
2555
|
};
|
|
2575
|
-
var serialize = (
|
|
2576
|
-
return
|
|
2556
|
+
var serialize = (acp) => {
|
|
2557
|
+
return ACPUtils.serialize(acp);
|
|
2577
2558
|
};
|
|
2578
2559
|
var deserialize = (serialized) => {
|
|
2579
|
-
return
|
|
2560
|
+
return ACPUtils.deserialize(serialized);
|
|
2580
2561
|
};
|
|
2581
|
-
var
|
|
2582
|
-
return
|
|
2562
|
+
var getACP2 = (chainId, account, hash) => {
|
|
2563
|
+
return acpStore.getACP(chainId, account, hash);
|
|
2583
2564
|
};
|
|
2584
|
-
var
|
|
2585
|
-
return
|
|
2565
|
+
var getACPs2 = (chainId, account) => {
|
|
2566
|
+
return acpStore.getACPs(chainId, account);
|
|
2586
2567
|
};
|
|
2587
|
-
var
|
|
2588
|
-
return
|
|
2568
|
+
var getActiveACP2 = (chainId, account) => {
|
|
2569
|
+
return acpStore.getActiveACP(chainId, account);
|
|
2589
2570
|
};
|
|
2590
|
-
var
|
|
2591
|
-
return
|
|
2571
|
+
var getActiveACPHash2 = (chainId, account) => {
|
|
2572
|
+
return acpStore.getActiveACPHash(chainId, account);
|
|
2592
2573
|
};
|
|
2593
|
-
var
|
|
2594
|
-
|
|
2574
|
+
var selectActiveACP = (chainId, account, hash) => {
|
|
2575
|
+
acpStore.setActiveACPHash(chainId, account, hash);
|
|
2595
2576
|
};
|
|
2596
|
-
var
|
|
2577
|
+
var getOrCreateSelfACP = async (publicClient, walletClient, chainId, account, options) => {
|
|
2597
2578
|
const _chainId = chainId ?? await publicClient.getChainId();
|
|
2598
2579
|
const _account = account ?? walletClient.account.address;
|
|
2599
|
-
const
|
|
2600
|
-
if (
|
|
2601
|
-
return
|
|
2580
|
+
const activeACP = await getActiveACP2(_chainId, _account);
|
|
2581
|
+
if (activeACP && activeACP.type === "self" && ACPUtils.isValid(activeACP).valid) {
|
|
2582
|
+
return activeACP;
|
|
2602
2583
|
}
|
|
2603
|
-
return createSelf(options ?? { issuer: _account, name: "Autogenerated Self
|
|
2584
|
+
return createSelf(options ?? { issuer: _account, name: "Autogenerated Self ACP" }, publicClient, walletClient);
|
|
2604
2585
|
};
|
|
2605
|
-
var
|
|
2586
|
+
var getOrCreateSharingACP = async (publicClient, walletClient, options, chainId, account) => {
|
|
2606
2587
|
const _chainId = chainId ?? await publicClient.getChainId();
|
|
2607
2588
|
const _account = account ?? walletClient.account.address;
|
|
2608
|
-
const
|
|
2609
|
-
if (
|
|
2610
|
-
return
|
|
2589
|
+
const activeACP = await getActiveACP2(_chainId, _account);
|
|
2590
|
+
if (activeACP && activeACP.type === "sharing" && ACPUtils.isValid(activeACP).valid) {
|
|
2591
|
+
return activeACP;
|
|
2611
2592
|
}
|
|
2612
2593
|
return createSharing(options, publicClient, walletClient);
|
|
2613
2594
|
};
|
|
2614
|
-
var
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2595
|
+
var applyACPDefaults = (options, acpConfig, chainId) => {
|
|
2596
|
+
const result = { ...options };
|
|
2597
|
+
const defaultRevoker = acpConfig?.defaultRevoker?.[chainId];
|
|
2598
|
+
const hasValidatorOptions = options.revokerData != null || options.revokerContract != null;
|
|
2599
|
+
if (defaultRevoker != null && !hasValidatorOptions) {
|
|
2600
|
+
result.revokerContract = defaultRevoker;
|
|
2601
|
+
result.revokerData = Math.round(Date.now() / 1e3) - 60;
|
|
2602
|
+
}
|
|
2603
|
+
const defaultContracts = acpConfig?.defaultContractScopes?.[chainId];
|
|
2604
|
+
const hasScopeOptions = options.scope != null || options.contracts != null || options.handles != null;
|
|
2605
|
+
if (defaultContracts != null && defaultContracts.length > 0 && !hasScopeOptions) {
|
|
2606
|
+
result.contracts = defaultContracts;
|
|
2607
|
+
}
|
|
2608
|
+
return result;
|
|
2609
|
+
};
|
|
2610
|
+
var ACL_SERVED_ADDRESSES_ABI = viem.parseAbi([
|
|
2611
|
+
"function acl() view returns (address)",
|
|
2612
|
+
"function defaultRevokerContract() view returns (address)",
|
|
2613
|
+
"function shareRegistry() view returns (address)"
|
|
2614
|
+
]);
|
|
2615
|
+
var aclServedAddressesCache = /* @__PURE__ */ new Map();
|
|
2616
|
+
var clearAclServedAddresses = () => aclServedAddressesCache.clear();
|
|
2617
|
+
var getAclServedAddresses = async (publicClient, chainId) => {
|
|
2618
|
+
const cached = aclServedAddressesCache.get(chainId);
|
|
2619
|
+
if (cached != null)
|
|
2620
|
+
return cached;
|
|
2621
|
+
let aclAddress;
|
|
2622
|
+
try {
|
|
2623
|
+
aclAddress = await publicClient.readContract({
|
|
2624
|
+
address: TASK_MANAGER_ADDRESS,
|
|
2625
|
+
abi: ACL_SERVED_ADDRESSES_ABI,
|
|
2626
|
+
functionName: "acl"
|
|
2627
|
+
});
|
|
2628
|
+
} catch {
|
|
2629
|
+
return {};
|
|
2630
|
+
}
|
|
2631
|
+
const [defaultRevoker, shareRegistry] = await Promise.all([
|
|
2632
|
+
publicClient.readContract({ address: aclAddress, abi: ACL_SERVED_ADDRESSES_ABI, functionName: "defaultRevokerContract" }).catch(() => void 0),
|
|
2633
|
+
publicClient.readContract({ address: aclAddress, abi: ACL_SERVED_ADDRESSES_ABI, functionName: "shareRegistry" }).catch(() => void 0)
|
|
2634
|
+
]);
|
|
2635
|
+
const resolved = {
|
|
2636
|
+
defaultRevoker: defaultRevoker != null && defaultRevoker !== viem.zeroAddress ? defaultRevoker : void 0,
|
|
2637
|
+
shareRegistry: shareRegistry != null && shareRegistry !== viem.zeroAddress ? shareRegistry : void 0
|
|
2638
|
+
};
|
|
2639
|
+
aclServedAddressesCache.set(chainId, resolved);
|
|
2640
|
+
return resolved;
|
|
2641
|
+
};
|
|
2642
|
+
var applyACPDefaultsFromChain = async (options, acpConfig, publicClient, chainId) => {
|
|
2643
|
+
const hasExplicitRevoker = acpConfig?.defaultRevoker?.[chainId] != null || options.revokerData != null || options.revokerContract != null;
|
|
2644
|
+
if (hasExplicitRevoker)
|
|
2645
|
+
return applyACPDefaults(options, acpConfig, chainId);
|
|
2646
|
+
const served = await getAclServedAddresses(publicClient, chainId);
|
|
2647
|
+
const effectiveConfig = served.defaultRevoker != null ? { ...acpConfig, defaultRevoker: { ...acpConfig?.defaultRevoker, [chainId]: served.defaultRevoker } } : acpConfig;
|
|
2648
|
+
return applyACPDefaults(options, effectiveConfig, chainId);
|
|
2649
|
+
};
|
|
2650
|
+
var revokeACP = async (acp, walletClient) => {
|
|
2651
|
+
if (acp.revokerContract === viem.zeroAddress || acp.revokerData === 0) {
|
|
2652
|
+
throw new Error("ACP is not revocable: it has no revoker (revokerContract/revokerData unset)");
|
|
2653
|
+
}
|
|
2654
|
+
if (walletClient.account == null)
|
|
2655
|
+
throw new Error("Missing walletClient account");
|
|
2656
|
+
if (walletClient.account.address.toLowerCase() !== acp.issuer.toLowerCase()) {
|
|
2657
|
+
throw new Error("Only the acp issuer can revoke it");
|
|
2658
|
+
}
|
|
2659
|
+
return walletClient.writeContract({
|
|
2660
|
+
address: acp.revokerContract,
|
|
2661
|
+
abi: ACP_VALIDATOR_ABI,
|
|
2662
|
+
functionName: "revokeSingle",
|
|
2663
|
+
args: [BigInt(acp.revokerData)],
|
|
2664
|
+
account: walletClient.account,
|
|
2665
|
+
chain: walletClient.chain
|
|
2666
|
+
});
|
|
2667
|
+
};
|
|
2668
|
+
var revokeAllACPs = async (walletClient, publicClient, revokerContract) => {
|
|
2669
|
+
if (walletClient.account == null)
|
|
2670
|
+
throw new Error("Missing walletClient account");
|
|
2671
|
+
let revoker = revokerContract;
|
|
2672
|
+
if (revoker == null) {
|
|
2673
|
+
const chainId = await publicClient.getChainId();
|
|
2674
|
+
const active = getActiveACP2(chainId, walletClient.account.address);
|
|
2675
|
+
revoker = active?.revokerContract;
|
|
2676
|
+
}
|
|
2677
|
+
if (revoker == null || revoker === viem.zeroAddress) {
|
|
2678
|
+
throw new Error("No revoker contract: pass `revokerContract` or activate a revocable acp first");
|
|
2679
|
+
}
|
|
2680
|
+
return walletClient.writeContract({
|
|
2681
|
+
address: revoker,
|
|
2682
|
+
abi: ACP_VALIDATOR_ABI,
|
|
2683
|
+
functionName: "revokeAllExisting",
|
|
2684
|
+
args: [],
|
|
2685
|
+
account: walletClient.account,
|
|
2686
|
+
chain: walletClient.chain
|
|
2687
|
+
});
|
|
2688
|
+
};
|
|
2689
|
+
var isACPRevoked = async (acp, publicClient) => {
|
|
2690
|
+
if (acp.revokerContract === viem.zeroAddress || acp.revokerData === 0)
|
|
2691
|
+
return false;
|
|
2692
|
+
return publicClient.readContract({
|
|
2693
|
+
address: acp.revokerContract,
|
|
2694
|
+
abi: ACP_VALIDATOR_ABI,
|
|
2695
|
+
functionName: "disabled",
|
|
2696
|
+
args: [acp.issuer, BigInt(acp.revokerData)]
|
|
2697
|
+
});
|
|
2698
|
+
};
|
|
2699
|
+
var ACP_SHARE_REGISTRY_ABI = viem.parseAbi([
|
|
2700
|
+
"struct ACP { address issuer; uint64 expiration; address recipient; uint256 revokerData; address revokerContract; uint8 scope; address[] contracts; bytes32[] handles; bytes32 sealingKey; bytes issuerSignature; bytes recipientSignature; }",
|
|
2701
|
+
"function share(ACP calldata acp) external returns (bytes32)",
|
|
2702
|
+
"function removeShare(bytes32 shareId) external",
|
|
2703
|
+
"function sharesFor(address recipient) external view returns (ACP[] memory)",
|
|
2704
|
+
"function getShare(bytes32 shareId) external view returns (ACP memory)",
|
|
2705
|
+
"function isShareValid(bytes32 shareId) external view returns (bool)"
|
|
2706
|
+
]);
|
|
2707
|
+
var ACP_TUPLE = [
|
|
2708
|
+
{
|
|
2709
|
+
type: "tuple",
|
|
2710
|
+
components: [
|
|
2711
|
+
{ name: "issuer", type: "address" },
|
|
2712
|
+
{ name: "expiration", type: "uint64" },
|
|
2713
|
+
{ name: "recipient", type: "address" },
|
|
2714
|
+
{ name: "revokerData", type: "uint256" },
|
|
2715
|
+
{ name: "revokerContract", type: "address" },
|
|
2716
|
+
{ name: "scope", type: "uint8" },
|
|
2717
|
+
{ name: "contracts", type: "address[]" },
|
|
2718
|
+
{ name: "handles", type: "bytes32[]" },
|
|
2719
|
+
{ name: "sealingKey", type: "bytes32" },
|
|
2720
|
+
{ name: "issuerSignature", type: "bytes" },
|
|
2721
|
+
{ name: "recipientSignature", type: "bytes" }
|
|
2722
|
+
]
|
|
2723
|
+
}
|
|
2724
|
+
];
|
|
2725
|
+
var ZERO_BYTES32 = `0x${"0".repeat(64)}`;
|
|
2726
|
+
var toChainShare = (acp) => {
|
|
2727
|
+
const pub = ACPUtils.getPublic(acp, true);
|
|
2728
|
+
return {
|
|
2729
|
+
...pub,
|
|
2730
|
+
expiration: BigInt(pub.expiration),
|
|
2731
|
+
revokerData: BigInt(pub.revokerData),
|
|
2732
|
+
sealingKey: ZERO_BYTES32,
|
|
2733
|
+
recipientSignature: "0x"
|
|
2734
|
+
};
|
|
2735
|
+
};
|
|
2736
|
+
var computeShareId = (acp) => {
|
|
2737
|
+
const p = toChainShare(acp);
|
|
2738
|
+
return viem.keccak256(viem.encodeAbiParameters(ACP_TUPLE, [p]));
|
|
2739
|
+
};
|
|
2740
|
+
var shareOnChain = async (acp, walletClient, registry) => {
|
|
2741
|
+
if (acp.type !== "sharing") {
|
|
2742
|
+
throw new Error(`Cannot share a '${acp.type}' ACP on-chain \u2014 only 'sharing' ACPs are shareable.`);
|
|
2743
|
+
}
|
|
2744
|
+
if (acp.issuerSignature === "0x") {
|
|
2745
|
+
throw new Error("Cannot share an unsigned sharing ACP \u2014 sign it first.");
|
|
2746
|
+
}
|
|
2747
|
+
if (walletClient.account == null)
|
|
2748
|
+
throw new Error("Missing walletClient account");
|
|
2749
|
+
if (walletClient.account.address.toLowerCase() !== acp.issuer.toLowerCase()) {
|
|
2750
|
+
throw new Error("Only the ACP issuer can share it on-chain");
|
|
2751
|
+
}
|
|
2752
|
+
const txHash = await walletClient.writeContract({
|
|
2753
|
+
address: registry,
|
|
2754
|
+
abi: ACP_SHARE_REGISTRY_ABI,
|
|
2755
|
+
functionName: "share",
|
|
2756
|
+
args: [toChainShare(acp)],
|
|
2757
|
+
account: walletClient.account,
|
|
2758
|
+
chain: walletClient.chain ?? null
|
|
2759
|
+
});
|
|
2760
|
+
return { txHash, shareId: computeShareId(acp) };
|
|
2761
|
+
};
|
|
2762
|
+
var getIncomingShares = async (publicClient, registry, recipient) => {
|
|
2763
|
+
const raw = await publicClient.readContract({
|
|
2764
|
+
address: registry,
|
|
2765
|
+
abi: ACP_SHARE_REGISTRY_ABI,
|
|
2766
|
+
functionName: "sharesFor",
|
|
2767
|
+
args: [recipient]
|
|
2768
|
+
});
|
|
2769
|
+
return raw.map((s) => ({
|
|
2770
|
+
shareId: viem.keccak256(viem.encodeAbiParameters(ACP_TUPLE, [s])),
|
|
2771
|
+
issuer: s.issuer,
|
|
2772
|
+
expiration: Number(s.expiration),
|
|
2773
|
+
recipient: s.recipient,
|
|
2774
|
+
revokerData: Number(s.revokerData),
|
|
2775
|
+
revokerContract: s.revokerContract,
|
|
2776
|
+
scope: Number(s.scope),
|
|
2777
|
+
contracts: [...s.contracts],
|
|
2778
|
+
handles: [...s.handles],
|
|
2779
|
+
issuerSignature: s.issuerSignature
|
|
2780
|
+
}));
|
|
2781
|
+
};
|
|
2782
|
+
var importFromChain = async (share, publicClient, walletClient) => {
|
|
2783
|
+
const { shareId: _shareId, ...options } = share;
|
|
2784
|
+
return importShared({ ...options, type: "sharing" }, publicClient, walletClient);
|
|
2785
|
+
};
|
|
2786
|
+
var removeShareOnChain = async (shareId, walletClient, registry) => {
|
|
2787
|
+
if (walletClient.account == null)
|
|
2788
|
+
throw new Error("Missing walletClient account");
|
|
2789
|
+
return walletClient.writeContract({
|
|
2790
|
+
address: registry,
|
|
2791
|
+
abi: ACP_SHARE_REGISTRY_ABI,
|
|
2792
|
+
functionName: "removeShare",
|
|
2793
|
+
args: [shareId],
|
|
2794
|
+
account: walletClient.account,
|
|
2795
|
+
chain: walletClient.chain ?? null
|
|
2796
|
+
});
|
|
2797
|
+
};
|
|
2798
|
+
var removeACP2 = async (chainId, account, hash) => acpStore.removeACP(chainId, account, hash);
|
|
2799
|
+
var removeActiveACP = async (chainId, account) => acpStore.removeActiveACPHash(chainId, account);
|
|
2800
|
+
var acps = {
|
|
2801
|
+
getSnapshot: acpStore.store.getState,
|
|
2802
|
+
subscribe: acpStore.store.subscribe,
|
|
2619
2803
|
createSelf,
|
|
2620
2804
|
createSharing,
|
|
2621
2805
|
importShared,
|
|
2622
|
-
|
|
2623
|
-
|
|
2806
|
+
getOrCreateSelfACP,
|
|
2807
|
+
getOrCreateSharingACP,
|
|
2624
2808
|
getHash,
|
|
2625
2809
|
export: exportShared,
|
|
2626
2810
|
serialize,
|
|
2627
2811
|
deserialize,
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2812
|
+
getACP: getACP2,
|
|
2813
|
+
getACPs: getACPs2,
|
|
2814
|
+
getActiveACP: getActiveACP2,
|
|
2815
|
+
getActiveACPHash: getActiveACPHash2,
|
|
2816
|
+
removeACP: removeACP2,
|
|
2817
|
+
selectActiveACP,
|
|
2818
|
+
removeActiveACP,
|
|
2819
|
+
revokeACP,
|
|
2820
|
+
revokeAllACPs,
|
|
2821
|
+
isACPRevoked,
|
|
2822
|
+
shareOnChain,
|
|
2823
|
+
getIncomingShares,
|
|
2824
|
+
importFromChain,
|
|
2825
|
+
removeShareOnChain,
|
|
2826
|
+
computeShareId,
|
|
2827
|
+
applyACPDefaults,
|
|
2828
|
+
applyACPDefaultsFromChain,
|
|
2829
|
+
getAclServedAddresses,
|
|
2830
|
+
clearAclServedAddresses
|
|
2635
2831
|
};
|
|
2636
2832
|
function uint160ToAddress(uint160) {
|
|
2637
2833
|
const hexStr = uint160.toString(16).padStart(40, "0");
|
|
@@ -2694,13 +2890,16 @@ var MockThresholdNetworkAbi = [
|
|
|
2694
2890
|
{
|
|
2695
2891
|
name: "permission",
|
|
2696
2892
|
type: "tuple",
|
|
2697
|
-
internalType: "struct
|
|
2893
|
+
internalType: "struct ACPermission",
|
|
2698
2894
|
components: [
|
|
2699
2895
|
{ name: "issuer", type: "address", internalType: "address" },
|
|
2700
2896
|
{ name: "expiration", type: "uint64", internalType: "uint64" },
|
|
2701
2897
|
{ name: "recipient", type: "address", internalType: "address" },
|
|
2702
|
-
{ name: "
|
|
2703
|
-
{ name: "
|
|
2898
|
+
{ name: "revokerData", type: "uint256", internalType: "uint256" },
|
|
2899
|
+
{ name: "revokerContract", type: "address", internalType: "address" },
|
|
2900
|
+
{ name: "scope", type: "uint8", internalType: "uint8" },
|
|
2901
|
+
{ name: "contracts", type: "address[]", internalType: "address[]" },
|
|
2902
|
+
{ name: "handles", type: "bytes32[]", internalType: "bytes32[]" },
|
|
2704
2903
|
{ name: "sealingKey", type: "bytes32", internalType: "bytes32" },
|
|
2705
2904
|
{ name: "issuerSignature", type: "bytes", internalType: "bytes" },
|
|
2706
2905
|
{ name: "recipientSignature", type: "bytes", internalType: "bytes" }
|
|
@@ -2723,13 +2922,16 @@ var MockThresholdNetworkAbi = [
|
|
|
2723
2922
|
{
|
|
2724
2923
|
name: "permission",
|
|
2725
2924
|
type: "tuple",
|
|
2726
|
-
internalType: "struct
|
|
2925
|
+
internalType: "struct ACPermission",
|
|
2727
2926
|
components: [
|
|
2728
2927
|
{ name: "issuer", type: "address", internalType: "address" },
|
|
2729
2928
|
{ name: "expiration", type: "uint64", internalType: "uint64" },
|
|
2730
2929
|
{ name: "recipient", type: "address", internalType: "address" },
|
|
2731
|
-
{ name: "
|
|
2732
|
-
{ name: "
|
|
2930
|
+
{ name: "revokerData", type: "uint256", internalType: "uint256" },
|
|
2931
|
+
{ name: "revokerContract", type: "address", internalType: "address" },
|
|
2932
|
+
{ name: "scope", type: "uint8", internalType: "uint8" },
|
|
2933
|
+
{ name: "contracts", type: "address[]", internalType: "address[]" },
|
|
2934
|
+
{ name: "handles", type: "bytes32[]", internalType: "bytes32[]" },
|
|
2733
2935
|
{ name: "sealingKey", type: "bytes32", internalType: "bytes32" },
|
|
2734
2936
|
{ name: "issuerSignature", type: "bytes", internalType: "bytes" },
|
|
2735
2937
|
{ name: "recipientSignature", type: "bytes", internalType: "bytes" }
|
|
@@ -2794,19 +2996,22 @@ var MockThresholdNetworkAbi = [
|
|
|
2794
2996
|
},
|
|
2795
2997
|
{
|
|
2796
2998
|
type: "function",
|
|
2797
|
-
name: "
|
|
2999
|
+
name: "decryptForTxWithACP",
|
|
2798
3000
|
inputs: [
|
|
2799
3001
|
{ name: "ctHash", type: "uint256", internalType: "uint256" },
|
|
2800
3002
|
{
|
|
2801
3003
|
name: "permission",
|
|
2802
3004
|
type: "tuple",
|
|
2803
|
-
internalType: "struct
|
|
3005
|
+
internalType: "struct ACPermission",
|
|
2804
3006
|
components: [
|
|
2805
3007
|
{ name: "issuer", type: "address", internalType: "address" },
|
|
2806
3008
|
{ name: "expiration", type: "uint64", internalType: "uint64" },
|
|
2807
3009
|
{ name: "recipient", type: "address", internalType: "address" },
|
|
2808
|
-
{ name: "
|
|
2809
|
-
{ name: "
|
|
3010
|
+
{ name: "revokerData", type: "uint256", internalType: "uint256" },
|
|
3011
|
+
{ name: "revokerContract", type: "address", internalType: "address" },
|
|
3012
|
+
{ name: "scope", type: "uint8", internalType: "uint8" },
|
|
3013
|
+
{ name: "contracts", type: "address[]", internalType: "address[]" },
|
|
3014
|
+
{ name: "handles", type: "bytes32[]", internalType: "bytes32[]" },
|
|
2810
3015
|
{ name: "sealingKey", type: "bytes32", internalType: "bytes32" },
|
|
2811
3016
|
{ name: "issuerSignature", type: "bytes", internalType: "bytes" },
|
|
2812
3017
|
{ name: "recipientSignature", type: "bytes", internalType: "bytes" }
|
|
@@ -2822,7 +3027,7 @@ var MockThresholdNetworkAbi = [
|
|
|
2822
3027
|
},
|
|
2823
3028
|
{
|
|
2824
3029
|
type: "function",
|
|
2825
|
-
name: "
|
|
3030
|
+
name: "decryptForTxWithoutACP",
|
|
2826
3031
|
inputs: [{ name: "ctHash", type: "uint256", internalType: "uint256" }],
|
|
2827
3032
|
outputs: [
|
|
2828
3033
|
{ name: "allowed", type: "bool", internalType: "bool" },
|
|
@@ -2834,12 +3039,12 @@ var MockThresholdNetworkAbi = [
|
|
|
2834
3039
|
];
|
|
2835
3040
|
|
|
2836
3041
|
// core/decrypt/cofheMocksDecryptForView.ts
|
|
2837
|
-
async function cofheMocksDecryptForView(ctHash, utype,
|
|
2838
|
-
const
|
|
3042
|
+
async function cofheMocksDecryptForView(ctHash, utype, acp, publicClient) {
|
|
3043
|
+
const wireAcp = ACPUtils.getPublic(acp, true);
|
|
2839
3044
|
const permissionWithBigInts = {
|
|
2840
|
-
...
|
|
2841
|
-
expiration: BigInt(
|
|
2842
|
-
|
|
3045
|
+
...wireAcp,
|
|
3046
|
+
expiration: BigInt(wireAcp.expiration),
|
|
3047
|
+
revokerData: BigInt(wireAcp.revokerData)
|
|
2843
3048
|
};
|
|
2844
3049
|
const [allowed, error, result] = await publicClient.readContract({
|
|
2845
3050
|
address: MOCKS_THRESHOLD_NETWORK_ADDRESS,
|
|
@@ -2860,7 +3065,7 @@ async function cofheMocksDecryptForView(ctHash, utype, permit, publicClient) {
|
|
|
2860
3065
|
});
|
|
2861
3066
|
}
|
|
2862
3067
|
const sealedBigInt = BigInt(result);
|
|
2863
|
-
const sealingKeyBigInt = BigInt(
|
|
3068
|
+
const sealingKeyBigInt = BigInt(acp.sealingKey);
|
|
2864
3069
|
const unsealed = sealedBigInt ^ sealingKeyBigInt;
|
|
2865
3070
|
return unsealed;
|
|
2866
3071
|
}
|
|
@@ -2896,11 +3101,61 @@ function computeMinuteRampPollIntervalMs(elapsedMs, params) {
|
|
|
2896
3101
|
return Math.min(params.maxIntervalMs, Math.max(params.minIntervalMs, intervalMs));
|
|
2897
3102
|
}
|
|
2898
3103
|
|
|
3104
|
+
// core/decrypt/apiError.ts
|
|
3105
|
+
var BACKEND_ERROR_CODE_TO_COFHE_ERROR_CODE = {
|
|
3106
|
+
bad_request: "BAD_REQUEST" /* BadRequest */,
|
|
3107
|
+
unknown_chain: "UNKNOWN_CHAIN" /* UnknownChain */,
|
|
3108
|
+
acp_malformed: "ACP_MALFORMED" /* ACPMalformed */,
|
|
3109
|
+
acp_denied: "ACP_DENIED" /* ACPDenied */,
|
|
3110
|
+
// ACP-era backends fold revoked into denied
|
|
3111
|
+
acp_expired: "ACP_EXPIRED" /* ACPExpired */,
|
|
3112
|
+
acp_invalid: "ACP_INVALID" /* ACPInvalid */,
|
|
3113
|
+
acp_required: "ACP_REQUIRED" /* ACPRequired */,
|
|
3114
|
+
acp_verifier_error: "ACP_VERIFIER_ERROR" /* ACPVerifierError */,
|
|
3115
|
+
acp_verifier_timeout: "ACP_VERIFIER_TIMEOUT" /* ACPVerifierTimeout */,
|
|
3116
|
+
not_publicly_allowed: "NOT_PUBLICLY_ALLOWED" /* NotPubliclyAllowed */,
|
|
3117
|
+
ct_not_found: "CT_NOT_FOUND" /* CtNotFound */,
|
|
3118
|
+
unsupported_security_zone: "UNSUPPORTED_SECURITY_ZONE" /* UnsupportedSecurityZone */,
|
|
3119
|
+
unsupported_type: "UNSUPPORTED_TYPE" /* UnsupportedType */,
|
|
3120
|
+
internal_error: "INTERNAL_ERROR" /* InternalError */,
|
|
3121
|
+
signing_failed: "SIGNING_FAILED" /* SigningFailed */,
|
|
3122
|
+
ct_source_error: "CT_SOURCE_ERROR" /* CtSourceError */,
|
|
3123
|
+
ct_source_timeout: "CT_SOURCE_TIMEOUT" /* CtSourceTimeout */,
|
|
3124
|
+
seal_failed: "SEAL_FAILED" /* SealFailed */
|
|
3125
|
+
};
|
|
3126
|
+
function isBackendApiErrorCode(value) {
|
|
3127
|
+
return value in BACKEND_ERROR_CODE_TO_COFHE_ERROR_CODE;
|
|
3128
|
+
}
|
|
3129
|
+
async function parseApiErrorResponseBody(response) {
|
|
3130
|
+
let errorMessage = `HTTP ${response.status}`;
|
|
3131
|
+
let apiErrorCode;
|
|
3132
|
+
try {
|
|
3133
|
+
const body = await response.json();
|
|
3134
|
+
if (body && typeof body === "object") {
|
|
3135
|
+
const record = body;
|
|
3136
|
+
if (typeof record.error === "string" && record.error.length > 0) {
|
|
3137
|
+
apiErrorCode = record.error;
|
|
3138
|
+
}
|
|
3139
|
+
if (typeof record.error_message === "string" && record.error_message.length > 0) {
|
|
3140
|
+
errorMessage = record.error_message;
|
|
3141
|
+
} else if (typeof record.message === "string" && record.message.length > 0) {
|
|
3142
|
+
errorMessage = record.message;
|
|
3143
|
+
}
|
|
3144
|
+
}
|
|
3145
|
+
} catch {
|
|
3146
|
+
errorMessage = response.statusText || errorMessage;
|
|
3147
|
+
}
|
|
3148
|
+
return { apiErrorCode, errorMessage };
|
|
3149
|
+
}
|
|
3150
|
+
function mapApiErrorCodeToCofheErrorCode(apiErrorCode, fallback) {
|
|
3151
|
+
if (apiErrorCode && isBackendApiErrorCode(apiErrorCode)) {
|
|
3152
|
+
return BACKEND_ERROR_CODE_TO_COFHE_ERROR_CODE[apiErrorCode];
|
|
3153
|
+
}
|
|
3154
|
+
return fallback;
|
|
3155
|
+
}
|
|
3156
|
+
|
|
2899
3157
|
// core/decrypt/submitRetry.ts
|
|
2900
3158
|
var DEFAULT_404_RETRY_TIMEOUT_MS = 1e4;
|
|
2901
|
-
function isRetryableSubmitStatus(status) {
|
|
2902
|
-
return status === 204 || status === 404;
|
|
2903
|
-
}
|
|
2904
3159
|
function normalize404RetryTimeoutMs(params) {
|
|
2905
3160
|
const { timeoutMs, operationLabel, errorCode } = params;
|
|
2906
3161
|
if (timeoutMs === void 0)
|
|
@@ -2917,32 +3172,24 @@ function normalize404RetryTimeoutMs(params) {
|
|
|
2917
3172
|
return timeoutMs;
|
|
2918
3173
|
}
|
|
2919
3174
|
async function classifySubmitResponse(params) {
|
|
2920
|
-
const { response,
|
|
2921
|
-
if (
|
|
2922
|
-
return { kind: "retryable", status:
|
|
3175
|
+
const { response, fallbackErrorCode } = params;
|
|
3176
|
+
if (response.status === 204) {
|
|
3177
|
+
return { kind: "retryable", status: 204 };
|
|
2923
3178
|
}
|
|
2924
3179
|
if (response.ok) {
|
|
2925
3180
|
return { kind: "parse-json" };
|
|
2926
3181
|
}
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
const maybeErrorMessage = extractErrorMessage?.(errorBody);
|
|
2931
|
-
if (typeof maybeErrorMessage === "string" && maybeErrorMessage.length > 0) {
|
|
2932
|
-
errorMessage = maybeErrorMessage;
|
|
2933
|
-
} else if (errorBody && typeof errorBody === "object") {
|
|
2934
|
-
const defaultMessage = errorBody.error_message;
|
|
2935
|
-
const fallbackMessage = errorBody.message;
|
|
2936
|
-
if (typeof defaultMessage === "string" && defaultMessage.length > 0) {
|
|
2937
|
-
errorMessage = defaultMessage;
|
|
2938
|
-
} else if (typeof fallbackMessage === "string" && fallbackMessage.length > 0) {
|
|
2939
|
-
errorMessage = fallbackMessage;
|
|
2940
|
-
}
|
|
2941
|
-
}
|
|
2942
|
-
} catch {
|
|
2943
|
-
errorMessage = response.statusText || errorMessage;
|
|
3182
|
+
const { apiErrorCode, errorMessage } = await parseApiErrorResponseBody(response);
|
|
3183
|
+
if (response.status === 404) {
|
|
3184
|
+
return { kind: "retryable", status: 404, apiErrorMessage: errorMessage };
|
|
2944
3185
|
}
|
|
2945
|
-
return {
|
|
3186
|
+
return {
|
|
3187
|
+
kind: "fatal-http",
|
|
3188
|
+
status: response.status,
|
|
3189
|
+
cofheErrorCode: mapApiErrorCodeToCofheErrorCode(apiErrorCode, fallbackErrorCode),
|
|
3190
|
+
apiErrorCode,
|
|
3191
|
+
errorMessage
|
|
3192
|
+
};
|
|
2946
3193
|
}
|
|
2947
3194
|
function throwIfSubmitRetryTimedOut(params) {
|
|
2948
3195
|
const {
|
|
@@ -2954,12 +3201,14 @@ function throwIfSubmitRetryTimedOut(params) {
|
|
|
2954
3201
|
overallTimeoutMs,
|
|
2955
3202
|
thresholdNetworkUrl,
|
|
2956
3203
|
body,
|
|
2957
|
-
attemptIndex
|
|
3204
|
+
attemptIndex,
|
|
3205
|
+
lastKnownErrorMessage
|
|
2958
3206
|
} = params;
|
|
2959
3207
|
if (status === 404 && elapsedMs > retry404TimeoutMs) {
|
|
2960
3208
|
throw new CofheError({
|
|
2961
|
-
code:
|
|
2962
|
-
|
|
3209
|
+
code: "CT_NOT_FOUND" /* CtNotFound */,
|
|
3210
|
+
apiErrorCode: "ct_not_found",
|
|
3211
|
+
message: `${operationLabel} ciphertext not found after retrying for ${retry404TimeoutMs}ms` + (lastKnownErrorMessage ? `: ${lastKnownErrorMessage}` : ""),
|
|
2963
3212
|
hint: "The ciphertext may not be indexed yet. Increase set404RetryTimeout(...) if the backend is slow to index ciphertexts.",
|
|
2964
3213
|
context: {
|
|
2965
3214
|
thresholdNetworkUrl,
|
|
@@ -2985,6 +3234,62 @@ function throwIfSubmitRetryTimedOut(params) {
|
|
|
2985
3234
|
});
|
|
2986
3235
|
}
|
|
2987
3236
|
}
|
|
3237
|
+
function normalizeTnSignature(signature) {
|
|
3238
|
+
if (typeof signature !== "string") {
|
|
3239
|
+
throw new CofheError({
|
|
3240
|
+
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3241
|
+
message: "decrypt response missing signature",
|
|
3242
|
+
context: {
|
|
3243
|
+
signature
|
|
3244
|
+
}
|
|
3245
|
+
});
|
|
3246
|
+
}
|
|
3247
|
+
const trimmed = signature.trim();
|
|
3248
|
+
if (trimmed.length === 0) {
|
|
3249
|
+
throw new CofheError({
|
|
3250
|
+
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3251
|
+
message: "decrypt response returned empty signature"
|
|
3252
|
+
});
|
|
3253
|
+
}
|
|
3254
|
+
const prefixed = trimmed.startsWith("0x") ? trimmed : `0x${trimmed}`;
|
|
3255
|
+
const parsed = viem.parseSignature(prefixed);
|
|
3256
|
+
return viem.serializeSignature(parsed);
|
|
3257
|
+
}
|
|
3258
|
+
function parseDecryptedBytesToBigInt(decrypted) {
|
|
3259
|
+
if (!Array.isArray(decrypted)) {
|
|
3260
|
+
throw new CofheError({
|
|
3261
|
+
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3262
|
+
message: "decrypt response field <decrypted> must be a byte array",
|
|
3263
|
+
context: {
|
|
3264
|
+
decrypted
|
|
3265
|
+
}
|
|
3266
|
+
});
|
|
3267
|
+
}
|
|
3268
|
+
if (decrypted.length === 0) {
|
|
3269
|
+
throw new CofheError({
|
|
3270
|
+
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3271
|
+
message: "decrypt response field <decrypted> was an empty byte array",
|
|
3272
|
+
context: {
|
|
3273
|
+
decrypted
|
|
3274
|
+
}
|
|
3275
|
+
});
|
|
3276
|
+
}
|
|
3277
|
+
let hex = "";
|
|
3278
|
+
for (const b of decrypted) {
|
|
3279
|
+
if (typeof b !== "number" || !Number.isInteger(b) || b < 0 || b > 255) {
|
|
3280
|
+
throw new CofheError({
|
|
3281
|
+
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3282
|
+
message: "decrypt response field <decrypted> contained a non-byte value",
|
|
3283
|
+
context: {
|
|
3284
|
+
badElement: b,
|
|
3285
|
+
decrypted
|
|
3286
|
+
}
|
|
3287
|
+
});
|
|
3288
|
+
}
|
|
3289
|
+
hex += b.toString(16).padStart(2, "0");
|
|
3290
|
+
}
|
|
3291
|
+
return BigInt(`0x${hex}`);
|
|
3292
|
+
}
|
|
2988
3293
|
|
|
2989
3294
|
// core/decrypt/tnSealOutputV2.ts
|
|
2990
3295
|
var POLL_INTERVAL_MS = 1e3;
|
|
@@ -3047,13 +3352,14 @@ function parseCompletedSealOutputResponse(params) {
|
|
|
3047
3352
|
}
|
|
3048
3353
|
return convertSealedData(sealed);
|
|
3049
3354
|
}
|
|
3050
|
-
async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId,
|
|
3355
|
+
async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, acp, overallStartTime, retry404TimeoutMs, onPoll) {
|
|
3051
3356
|
const body = {
|
|
3052
3357
|
ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
|
|
3053
3358
|
host_chain_id: chainId,
|
|
3054
|
-
|
|
3359
|
+
acp
|
|
3055
3360
|
};
|
|
3056
3361
|
let attemptIndex = 0;
|
|
3362
|
+
let last404ApiErrorMessage;
|
|
3057
3363
|
for (; ; ) {
|
|
3058
3364
|
let response;
|
|
3059
3365
|
try {
|
|
@@ -3081,16 +3387,19 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, per
|
|
|
3081
3387
|
}
|
|
3082
3388
|
});
|
|
3083
3389
|
}
|
|
3084
|
-
const responseClassification = await classifySubmitResponse({
|
|
3390
|
+
const responseClassification = await classifySubmitResponse({
|
|
3391
|
+
response,
|
|
3392
|
+
fallbackErrorCode: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */
|
|
3393
|
+
});
|
|
3085
3394
|
if (responseClassification.kind === "fatal-http") {
|
|
3086
3395
|
throw new CofheError({
|
|
3087
|
-
code:
|
|
3396
|
+
code: responseClassification.cofheErrorCode,
|
|
3397
|
+
apiErrorCode: responseClassification.apiErrorCode,
|
|
3088
3398
|
message: `sealOutput request failed: ${responseClassification.errorMessage}`,
|
|
3089
3399
|
hint: "Check the threshold network URL and request parameters.",
|
|
3090
3400
|
context: {
|
|
3091
3401
|
thresholdNetworkUrl,
|
|
3092
|
-
status:
|
|
3093
|
-
statusText: response.statusText,
|
|
3402
|
+
status: responseClassification.status,
|
|
3094
3403
|
body,
|
|
3095
3404
|
attemptIndex
|
|
3096
3405
|
}
|
|
@@ -3136,6 +3445,9 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, per
|
|
|
3136
3445
|
}
|
|
3137
3446
|
});
|
|
3138
3447
|
}
|
|
3448
|
+
if (responseClassification.status === 404) {
|
|
3449
|
+
last404ApiErrorMessage = responseClassification.apiErrorMessage;
|
|
3450
|
+
}
|
|
3139
3451
|
const elapsedMs = Date.now() - overallStartTime;
|
|
3140
3452
|
throwIfSubmitRetryTimedOut({
|
|
3141
3453
|
operationLabel: "sealOutput",
|
|
@@ -3146,7 +3458,8 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, per
|
|
|
3146
3458
|
overallTimeoutMs: SEAL_OUTPUT_TIMEOUT_MS,
|
|
3147
3459
|
thresholdNetworkUrl,
|
|
3148
3460
|
body,
|
|
3149
|
-
attemptIndex
|
|
3461
|
+
attemptIndex,
|
|
3462
|
+
lastKnownErrorMessage: last404ApiErrorMessage
|
|
3150
3463
|
});
|
|
3151
3464
|
onPoll?.({
|
|
3152
3465
|
operation: "sealoutput",
|
|
@@ -3224,15 +3537,10 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStart
|
|
|
3224
3537
|
});
|
|
3225
3538
|
}
|
|
3226
3539
|
if (!response.ok) {
|
|
3227
|
-
|
|
3228
|
-
try {
|
|
3229
|
-
const errorBody = await response.json();
|
|
3230
|
-
errorMessage = errorBody.error_message || errorBody.message || errorMessage;
|
|
3231
|
-
} catch {
|
|
3232
|
-
errorMessage = response.statusText || errorMessage;
|
|
3233
|
-
}
|
|
3540
|
+
const { apiErrorCode, errorMessage } = await parseApiErrorResponseBody(response);
|
|
3234
3541
|
throw new CofheError({
|
|
3235
|
-
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed
|
|
3542
|
+
code: mapApiErrorCodeToCofheErrorCode(apiErrorCode, "SEAL_OUTPUT_FAILED" /* SealOutputFailed */),
|
|
3543
|
+
apiErrorCode,
|
|
3236
3544
|
message: `sealOutput status poll failed: ${errorMessage}`,
|
|
3237
3545
|
context: {
|
|
3238
3546
|
thresholdNetworkUrl,
|
|
@@ -3276,7 +3584,7 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStart
|
|
|
3276
3584
|
});
|
|
3277
3585
|
}
|
|
3278
3586
|
async function tnSealOutputV2(params) {
|
|
3279
|
-
const { thresholdNetworkUrl, ctHash, chainId,
|
|
3587
|
+
const { thresholdNetworkUrl, ctHash, chainId, acp, retry404TimeoutMs, onPoll } = params;
|
|
3280
3588
|
const normalized404RetryTimeoutMs = normalize404RetryTimeoutMs({
|
|
3281
3589
|
timeoutMs: retry404TimeoutMs,
|
|
3282
3590
|
operationLabel: "sealOutput",
|
|
@@ -3287,7 +3595,7 @@ async function tnSealOutputV2(params) {
|
|
|
3287
3595
|
thresholdNetworkUrl,
|
|
3288
3596
|
ctHash,
|
|
3289
3597
|
chainId,
|
|
3290
|
-
|
|
3598
|
+
acp,
|
|
3291
3599
|
overallStartTime,
|
|
3292
3600
|
normalized404RetryTimeoutMs,
|
|
3293
3601
|
onPoll
|
|
@@ -3303,8 +3611,8 @@ var DEFAULT_404_RETRY_TIMEOUT_MS2 = 1e4;
|
|
|
3303
3611
|
var DecryptForViewBuilder = class extends BaseBuilder {
|
|
3304
3612
|
ctHash;
|
|
3305
3613
|
utype;
|
|
3306
|
-
|
|
3307
|
-
|
|
3614
|
+
acpHash;
|
|
3615
|
+
acp;
|
|
3308
3616
|
pollCallback;
|
|
3309
3617
|
retry404TimeoutMs = DEFAULT_404_RETRY_TIMEOUT_MS2;
|
|
3310
3618
|
constructor(params) {
|
|
@@ -3318,11 +3626,11 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3318
3626
|
});
|
|
3319
3627
|
this.ctHash = params.ctHash;
|
|
3320
3628
|
this.utype = params.utype;
|
|
3321
|
-
this.
|
|
3322
|
-
this.
|
|
3629
|
+
this.acpHash = params.acpHash;
|
|
3630
|
+
this.acp = params.acp;
|
|
3323
3631
|
}
|
|
3324
3632
|
/**
|
|
3325
|
-
* @param chainId - Chain to decrypt values from. Used to fetch the threshold network URL and use the correct
|
|
3633
|
+
* @param chainId - Chain to decrypt values from. Used to fetch the threshold network URL and use the correct acp.
|
|
3326
3634
|
*
|
|
3327
3635
|
* If not provided, the chainId will be fetched from the connected publicClient.
|
|
3328
3636
|
*
|
|
@@ -3343,7 +3651,7 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3343
3651
|
return this.chainId;
|
|
3344
3652
|
}
|
|
3345
3653
|
/**
|
|
3346
|
-
* @param account - Account to decrypt values from. Used to fetch the correct
|
|
3654
|
+
* @param account - Account to decrypt values from. Used to fetch the correct acp.
|
|
3347
3655
|
*
|
|
3348
3656
|
* If not provided, the account will be fetched from the connected walletClient.
|
|
3349
3657
|
*
|
|
@@ -3380,61 +3688,61 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3380
3688
|
this.retry404TimeoutMs = timeoutMs;
|
|
3381
3689
|
return this;
|
|
3382
3690
|
}
|
|
3383
|
-
|
|
3384
|
-
if (typeof
|
|
3385
|
-
this.
|
|
3386
|
-
this.
|
|
3387
|
-
} else if (
|
|
3388
|
-
this.
|
|
3389
|
-
this.
|
|
3691
|
+
withACP(acpOrACPHash) {
|
|
3692
|
+
if (typeof acpOrACPHash === "string") {
|
|
3693
|
+
this.acpHash = acpOrACPHash;
|
|
3694
|
+
this.acp = void 0;
|
|
3695
|
+
} else if (acpOrACPHash === void 0) {
|
|
3696
|
+
this.acpHash = void 0;
|
|
3697
|
+
this.acp = void 0;
|
|
3390
3698
|
} else {
|
|
3391
|
-
this.
|
|
3392
|
-
this.
|
|
3699
|
+
this.acp = acpOrACPHash;
|
|
3700
|
+
this.acpHash = void 0;
|
|
3393
3701
|
}
|
|
3394
3702
|
return this;
|
|
3395
3703
|
}
|
|
3396
3704
|
/**
|
|
3397
|
-
* @param
|
|
3705
|
+
* @param acpHash - ACP hash to decrypt values from. Used to fetch the correct acp.
|
|
3398
3706
|
*
|
|
3399
|
-
* If not provided, the active
|
|
3400
|
-
* If `
|
|
3707
|
+
* If not provided, the active acp for the chainId and account will be used.
|
|
3708
|
+
* If `setACP()` is called, it will be used regardless of chainId, account, or acpHash.
|
|
3401
3709
|
*
|
|
3402
3710
|
* Example:
|
|
3403
3711
|
* ```typescript
|
|
3404
3712
|
* const unsealed = await client.decryptForView(ctHash, utype)
|
|
3405
|
-
* .
|
|
3713
|
+
* .setACPHash('0x1234567890123456789012345678901234567890')
|
|
3406
3714
|
* .execute();
|
|
3407
3715
|
* ```
|
|
3408
3716
|
*
|
|
3409
3717
|
* @returns The chainable DecryptForViewBuilder instance.
|
|
3410
3718
|
*/
|
|
3411
|
-
/** @deprecated Use `
|
|
3412
|
-
|
|
3413
|
-
return this.
|
|
3719
|
+
/** @deprecated Use `withACP(acpHash)` instead. */
|
|
3720
|
+
setACPHash(acpHash) {
|
|
3721
|
+
return this.withACP(acpHash);
|
|
3414
3722
|
}
|
|
3415
|
-
|
|
3416
|
-
return this.
|
|
3723
|
+
getACPHash() {
|
|
3724
|
+
return this.acpHash;
|
|
3417
3725
|
}
|
|
3418
3726
|
/**
|
|
3419
|
-
* @param
|
|
3727
|
+
* @param acp - ACP to decrypt values with. If provided, it will be used regardless of chainId, account, or acpHash.
|
|
3420
3728
|
*
|
|
3421
|
-
* If not provided, the
|
|
3729
|
+
* If not provided, the acp will be determined by chainId, account, and acpHash.
|
|
3422
3730
|
*
|
|
3423
3731
|
* Example:
|
|
3424
3732
|
* ```typescript
|
|
3425
3733
|
* const unsealed = await client.decryptForView(ctHash, utype)
|
|
3426
|
-
* .
|
|
3734
|
+
* .setACP(acp)
|
|
3427
3735
|
* .execute();
|
|
3428
3736
|
* ```
|
|
3429
3737
|
*
|
|
3430
3738
|
* @returns The chainable DecryptForViewBuilder instance.
|
|
3431
3739
|
*/
|
|
3432
|
-
/** @deprecated Use `
|
|
3433
|
-
|
|
3434
|
-
return this.
|
|
3740
|
+
/** @deprecated Use `withACP(acp)` instead. */
|
|
3741
|
+
setACP(acp) {
|
|
3742
|
+
return this.withACP(acp);
|
|
3435
3743
|
}
|
|
3436
|
-
|
|
3437
|
-
return this.
|
|
3744
|
+
getACP() {
|
|
3745
|
+
return this.acp;
|
|
3438
3746
|
}
|
|
3439
3747
|
async getThresholdNetworkUrl() {
|
|
3440
3748
|
this.assertChainId();
|
|
@@ -3450,77 +3758,77 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3450
3758
|
}
|
|
3451
3759
|
});
|
|
3452
3760
|
}
|
|
3453
|
-
async
|
|
3454
|
-
if (this.
|
|
3455
|
-
return this.
|
|
3761
|
+
async getResolvedACP() {
|
|
3762
|
+
if (this.acp)
|
|
3763
|
+
return this.acp;
|
|
3456
3764
|
this.assertChainId();
|
|
3457
3765
|
this.assertAccount();
|
|
3458
|
-
if (this.
|
|
3459
|
-
const
|
|
3460
|
-
if (!
|
|
3766
|
+
if (this.acpHash) {
|
|
3767
|
+
const acp2 = await acps.getACP(this.chainId, this.account, this.acpHash);
|
|
3768
|
+
if (!acp2) {
|
|
3461
3769
|
throw new CofheError({
|
|
3462
|
-
code: "
|
|
3463
|
-
message: `
|
|
3464
|
-
hint: "Ensure the
|
|
3770
|
+
code: "ACP_NOT_FOUND" /* ACPNotFound */,
|
|
3771
|
+
message: `ACP with hash <${this.acpHash}> not found for account <${this.account}> and chainId <${this.chainId}>`,
|
|
3772
|
+
hint: "Ensure the acp exists and is valid.",
|
|
3465
3773
|
context: {
|
|
3466
3774
|
chainId: this.chainId,
|
|
3467
3775
|
account: this.account,
|
|
3468
|
-
|
|
3776
|
+
acpHash: this.acpHash
|
|
3469
3777
|
}
|
|
3470
3778
|
});
|
|
3471
3779
|
}
|
|
3472
|
-
return
|
|
3780
|
+
return acp2;
|
|
3473
3781
|
}
|
|
3474
|
-
const
|
|
3475
|
-
if (!
|
|
3782
|
+
const acp = await acps.getActiveACP(this.chainId, this.account);
|
|
3783
|
+
if (!acp) {
|
|
3476
3784
|
throw new CofheError({
|
|
3477
|
-
code: "
|
|
3478
|
-
message: `Active
|
|
3479
|
-
hint: "Ensure
|
|
3785
|
+
code: "ACP_NOT_FOUND" /* ACPNotFound */,
|
|
3786
|
+
message: `Active acp not found for chainId <${this.chainId}> and account <${this.account}>`,
|
|
3787
|
+
hint: "Ensure an ACP exists for this account on this chain.",
|
|
3480
3788
|
context: {
|
|
3481
3789
|
chainId: this.chainId,
|
|
3482
3790
|
account: this.account
|
|
3483
3791
|
}
|
|
3484
3792
|
});
|
|
3485
3793
|
}
|
|
3486
|
-
return
|
|
3794
|
+
return acp;
|
|
3487
3795
|
}
|
|
3488
3796
|
/**
|
|
3489
3797
|
* On hardhat, interact with MockZkVerifier contract instead of CoFHE
|
|
3490
3798
|
*/
|
|
3491
|
-
async mocksSealOutput(
|
|
3799
|
+
async mocksSealOutput(acp) {
|
|
3492
3800
|
this.assertPublicClient();
|
|
3493
3801
|
const mocksDecryptDelay = this.config.mocks.decryptDelay;
|
|
3494
3802
|
if (mocksDecryptDelay > 0)
|
|
3495
3803
|
await sleep(mocksDecryptDelay);
|
|
3496
|
-
return cofheMocksDecryptForView(this.ctHash, this.utype,
|
|
3804
|
+
return cofheMocksDecryptForView(this.ctHash, this.utype, acp, this.publicClient);
|
|
3497
3805
|
}
|
|
3498
3806
|
/**
|
|
3499
3807
|
* In the production context, perform a true decryption with the CoFHE coprocessor.
|
|
3500
3808
|
*/
|
|
3501
|
-
async productionSealOutput(
|
|
3809
|
+
async productionSealOutput(acp) {
|
|
3502
3810
|
this.assertChainId();
|
|
3503
3811
|
this.assertPublicClient();
|
|
3504
3812
|
const thresholdNetworkUrl = await this.getThresholdNetworkUrl();
|
|
3505
|
-
const
|
|
3813
|
+
const wireAcp = ACPUtils.getPublic(acp, true);
|
|
3506
3814
|
const sealed = await tnSealOutputV2({
|
|
3507
3815
|
ctHash: this.ctHash,
|
|
3508
3816
|
chainId: this.chainId,
|
|
3509
|
-
|
|
3817
|
+
acp: wireAcp,
|
|
3510
3818
|
thresholdNetworkUrl,
|
|
3511
3819
|
retry404TimeoutMs: this.retry404TimeoutMs,
|
|
3512
3820
|
onPoll: this.pollCallback
|
|
3513
3821
|
});
|
|
3514
|
-
return
|
|
3822
|
+
return ACPUtils.unseal(acp, sealed);
|
|
3515
3823
|
}
|
|
3516
3824
|
/**
|
|
3517
3825
|
* Final step of the decryption process. MUST BE CALLED LAST IN THE CHAIN.
|
|
3518
3826
|
*
|
|
3519
3827
|
* This will:
|
|
3520
|
-
* - Use
|
|
3521
|
-
* - Check
|
|
3522
|
-
* - Call CoFHE `/sealoutput` with the
|
|
3523
|
-
* - Unseal the sealed item with the
|
|
3828
|
+
* - Use an ACP based on provided acp OR chainId + account + acpHash
|
|
3829
|
+
* - Check acp validity
|
|
3830
|
+
* - Call CoFHE `/sealoutput` with the acp, which returns a sealed (encrypted) item
|
|
3831
|
+
* - Unseal the sealed item with the acp
|
|
3524
3832
|
* - Return the unsealed item
|
|
3525
3833
|
*
|
|
3526
3834
|
* Example:
|
|
@@ -3528,7 +3836,7 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3528
3836
|
* const unsealed = await client.decryptForView(ctHash, utype)
|
|
3529
3837
|
* .setChainId(11155111) // optional
|
|
3530
3838
|
* .setAccount('0x123...890') // optional
|
|
3531
|
-
* .
|
|
3839
|
+
* .withACP() // optional
|
|
3532
3840
|
* .execute(); // execute
|
|
3533
3841
|
* ```
|
|
3534
3842
|
*
|
|
@@ -3536,14 +3844,14 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3536
3844
|
*/
|
|
3537
3845
|
async execute() {
|
|
3538
3846
|
this.validateUtypeOrThrow();
|
|
3539
|
-
const
|
|
3540
|
-
|
|
3541
|
-
const chainId =
|
|
3847
|
+
const acp = await this.getResolvedACP();
|
|
3848
|
+
ACPUtils.validate(acp);
|
|
3849
|
+
const chainId = acp._signedDomain.chainId;
|
|
3542
3850
|
let unsealed;
|
|
3543
3851
|
if (chainId === hardhat2.id) {
|
|
3544
|
-
unsealed = await this.mocksSealOutput(
|
|
3852
|
+
unsealed = await this.mocksSealOutput(acp);
|
|
3545
3853
|
} else {
|
|
3546
|
-
unsealed = await this.productionSealOutput(
|
|
3854
|
+
unsealed = await this.productionSealOutput(acp);
|
|
3547
3855
|
}
|
|
3548
3856
|
return convertViaUtype(this.utype, unsealed);
|
|
3549
3857
|
}
|
|
@@ -3551,28 +3859,28 @@ var DecryptForViewBuilder = class extends BaseBuilder {
|
|
|
3551
3859
|
var UINT_TYPE_MASK = 0x7fn;
|
|
3552
3860
|
var TYPE_BYTE_OFFSET = 8n;
|
|
3553
3861
|
var getEncryptionTypeFromCtHash = (ctHash) => Number(ctHash >> TYPE_BYTE_OFFSET & UINT_TYPE_MASK);
|
|
3554
|
-
async function cofheMocksDecryptForTx(ctHash, utype,
|
|
3862
|
+
async function cofheMocksDecryptForTx(ctHash, utype, acp, publicClient) {
|
|
3555
3863
|
let allowed;
|
|
3556
3864
|
let error;
|
|
3557
3865
|
let decryptedValue;
|
|
3558
|
-
if (
|
|
3559
|
-
|
|
3866
|
+
if (acp !== null) {
|
|
3867
|
+
const wireAcp = ACPUtils.getPublic(acp, true);
|
|
3560
3868
|
const permissionWithBigInts = {
|
|
3561
|
-
...
|
|
3562
|
-
expiration: BigInt(
|
|
3563
|
-
|
|
3869
|
+
...wireAcp,
|
|
3870
|
+
expiration: BigInt(wireAcp.expiration),
|
|
3871
|
+
revokerData: BigInt(wireAcp.revokerData)
|
|
3564
3872
|
};
|
|
3565
3873
|
[allowed, error, decryptedValue] = await publicClient.readContract({
|
|
3566
3874
|
address: MOCKS_THRESHOLD_NETWORK_ADDRESS,
|
|
3567
3875
|
abi: MockThresholdNetworkAbi,
|
|
3568
|
-
functionName: "
|
|
3876
|
+
functionName: "decryptForTxWithACP",
|
|
3569
3877
|
args: [BigInt(ctHash), permissionWithBigInts]
|
|
3570
3878
|
});
|
|
3571
3879
|
} else {
|
|
3572
3880
|
[allowed, error, decryptedValue] = await publicClient.readContract({
|
|
3573
3881
|
address: MOCKS_THRESHOLD_NETWORK_ADDRESS,
|
|
3574
3882
|
abi: MockThresholdNetworkAbi,
|
|
3575
|
-
functionName: "
|
|
3883
|
+
functionName: "decryptForTxWithoutACP",
|
|
3576
3884
|
args: [BigInt(ctHash)]
|
|
3577
3885
|
});
|
|
3578
3886
|
}
|
|
@@ -3607,62 +3915,6 @@ async function cofheMocksDecryptForTx(ctHash, utype, permit, publicClient) {
|
|
|
3607
3915
|
signature
|
|
3608
3916
|
};
|
|
3609
3917
|
}
|
|
3610
|
-
function normalizeTnSignature(signature) {
|
|
3611
|
-
if (typeof signature !== "string") {
|
|
3612
|
-
throw new CofheError({
|
|
3613
|
-
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3614
|
-
message: "decrypt response missing signature",
|
|
3615
|
-
context: {
|
|
3616
|
-
signature
|
|
3617
|
-
}
|
|
3618
|
-
});
|
|
3619
|
-
}
|
|
3620
|
-
const trimmed = signature.trim();
|
|
3621
|
-
if (trimmed.length === 0) {
|
|
3622
|
-
throw new CofheError({
|
|
3623
|
-
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3624
|
-
message: "decrypt response returned empty signature"
|
|
3625
|
-
});
|
|
3626
|
-
}
|
|
3627
|
-
const prefixed = trimmed.startsWith("0x") ? trimmed : `0x${trimmed}`;
|
|
3628
|
-
const parsed = viem.parseSignature(prefixed);
|
|
3629
|
-
return viem.serializeSignature(parsed);
|
|
3630
|
-
}
|
|
3631
|
-
function parseDecryptedBytesToBigInt(decrypted) {
|
|
3632
|
-
if (!Array.isArray(decrypted)) {
|
|
3633
|
-
throw new CofheError({
|
|
3634
|
-
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3635
|
-
message: "decrypt response field <decrypted> must be a byte array",
|
|
3636
|
-
context: {
|
|
3637
|
-
decrypted
|
|
3638
|
-
}
|
|
3639
|
-
});
|
|
3640
|
-
}
|
|
3641
|
-
if (decrypted.length === 0) {
|
|
3642
|
-
throw new CofheError({
|
|
3643
|
-
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3644
|
-
message: "decrypt response field <decrypted> was an empty byte array",
|
|
3645
|
-
context: {
|
|
3646
|
-
decrypted
|
|
3647
|
-
}
|
|
3648
|
-
});
|
|
3649
|
-
}
|
|
3650
|
-
let hex = "";
|
|
3651
|
-
for (const b of decrypted) {
|
|
3652
|
-
if (typeof b !== "number" || !Number.isInteger(b) || b < 0 || b > 255) {
|
|
3653
|
-
throw new CofheError({
|
|
3654
|
-
code: "DECRYPT_RETURNED_NULL" /* DecryptReturnedNull */,
|
|
3655
|
-
message: "decrypt response field <decrypted> contained a non-byte value",
|
|
3656
|
-
context: {
|
|
3657
|
-
badElement: b,
|
|
3658
|
-
decrypted
|
|
3659
|
-
}
|
|
3660
|
-
});
|
|
3661
|
-
}
|
|
3662
|
-
hex += b.toString(16).padStart(2, "0");
|
|
3663
|
-
}
|
|
3664
|
-
return BigInt(`0x${hex}`);
|
|
3665
|
-
}
|
|
3666
3918
|
|
|
3667
3919
|
// core/decrypt/tnDecryptV2.ts
|
|
3668
3920
|
var POLL_INTERVAL_MS2 = 1e3;
|
|
@@ -3784,15 +4036,16 @@ function assertDecryptStatusResponseV2(value) {
|
|
|
3784
4036
|
}
|
|
3785
4037
|
return value;
|
|
3786
4038
|
}
|
|
3787
|
-
async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId,
|
|
4039
|
+
async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, acp, overallStartTime, retry404TimeoutMs, onPoll) {
|
|
3788
4040
|
const body = {
|
|
3789
4041
|
ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
|
|
3790
4042
|
host_chain_id: chainId
|
|
3791
4043
|
};
|
|
3792
|
-
if (
|
|
3793
|
-
body.
|
|
4044
|
+
if (acp) {
|
|
4045
|
+
body.acp = acp;
|
|
3794
4046
|
}
|
|
3795
4047
|
let attemptIndex = 0;
|
|
4048
|
+
let last404ApiErrorMessage;
|
|
3796
4049
|
for (; ; ) {
|
|
3797
4050
|
let response;
|
|
3798
4051
|
try {
|
|
@@ -3820,16 +4073,19 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, perm
|
|
|
3820
4073
|
}
|
|
3821
4074
|
});
|
|
3822
4075
|
}
|
|
3823
|
-
const responseClassification = await classifySubmitResponse({
|
|
4076
|
+
const responseClassification = await classifySubmitResponse({
|
|
4077
|
+
response,
|
|
4078
|
+
fallbackErrorCode: "DECRYPT_FAILED" /* DecryptFailed */
|
|
4079
|
+
});
|
|
3824
4080
|
if (responseClassification.kind === "fatal-http") {
|
|
3825
4081
|
throw new CofheError({
|
|
3826
|
-
code:
|
|
4082
|
+
code: responseClassification.cofheErrorCode,
|
|
4083
|
+
apiErrorCode: responseClassification.apiErrorCode,
|
|
3827
4084
|
message: `decrypt request failed: ${responseClassification.errorMessage}`,
|
|
3828
4085
|
hint: "Check the threshold network URL and request parameters.",
|
|
3829
4086
|
context: {
|
|
3830
4087
|
thresholdNetworkUrl,
|
|
3831
|
-
status:
|
|
3832
|
-
statusText: response.statusText,
|
|
4088
|
+
status: responseClassification.status,
|
|
3833
4089
|
body,
|
|
3834
4090
|
attemptIndex
|
|
3835
4091
|
}
|
|
@@ -3877,6 +4133,9 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, perm
|
|
|
3877
4133
|
}
|
|
3878
4134
|
});
|
|
3879
4135
|
}
|
|
4136
|
+
if (responseClassification.status === 404) {
|
|
4137
|
+
last404ApiErrorMessage = responseClassification.apiErrorMessage;
|
|
4138
|
+
}
|
|
3880
4139
|
const elapsedMs = Date.now() - overallStartTime;
|
|
3881
4140
|
throwIfSubmitRetryTimedOut({
|
|
3882
4141
|
operationLabel: "decrypt",
|
|
@@ -3887,7 +4146,8 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, perm
|
|
|
3887
4146
|
overallTimeoutMs: DECRYPT_TIMEOUT_MS,
|
|
3888
4147
|
thresholdNetworkUrl,
|
|
3889
4148
|
body,
|
|
3890
|
-
attemptIndex
|
|
4149
|
+
attemptIndex,
|
|
4150
|
+
lastKnownErrorMessage: last404ApiErrorMessage
|
|
3891
4151
|
});
|
|
3892
4152
|
onPoll?.({
|
|
3893
4153
|
operation: "decrypt",
|
|
@@ -3965,17 +4225,10 @@ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartT
|
|
|
3965
4225
|
});
|
|
3966
4226
|
}
|
|
3967
4227
|
if (!response.ok) {
|
|
3968
|
-
|
|
3969
|
-
try {
|
|
3970
|
-
const errorBody = await response.json();
|
|
3971
|
-
const maybeMessage = errorBody.error_message || errorBody.message;
|
|
3972
|
-
if (typeof maybeMessage === "string" && maybeMessage.length > 0)
|
|
3973
|
-
errorMessage = maybeMessage;
|
|
3974
|
-
} catch {
|
|
3975
|
-
errorMessage = response.statusText || errorMessage;
|
|
3976
|
-
}
|
|
4228
|
+
const { apiErrorCode, errorMessage } = await parseApiErrorResponseBody(response);
|
|
3977
4229
|
throw new CofheError({
|
|
3978
|
-
code: "DECRYPT_FAILED" /* DecryptFailed
|
|
4230
|
+
code: mapApiErrorCodeToCofheErrorCode(apiErrorCode, "DECRYPT_FAILED" /* DecryptFailed */),
|
|
4231
|
+
apiErrorCode,
|
|
3979
4232
|
message: `decrypt status poll failed: ${errorMessage}`,
|
|
3980
4233
|
context: {
|
|
3981
4234
|
thresholdNetworkUrl,
|
|
@@ -4020,7 +4273,7 @@ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartT
|
|
|
4020
4273
|
});
|
|
4021
4274
|
}
|
|
4022
4275
|
async function tnDecryptV2(params) {
|
|
4023
|
-
const { thresholdNetworkUrl, ctHash, chainId,
|
|
4276
|
+
const { thresholdNetworkUrl, ctHash, chainId, acp, retry404TimeoutMs, onPoll } = params;
|
|
4024
4277
|
const normalized404RetryTimeoutMs = normalize404RetryTimeoutMs({
|
|
4025
4278
|
timeoutMs: retry404TimeoutMs,
|
|
4026
4279
|
operationLabel: "decrypt",
|
|
@@ -4031,7 +4284,7 @@ async function tnDecryptV2(params) {
|
|
|
4031
4284
|
thresholdNetworkUrl,
|
|
4032
4285
|
ctHash,
|
|
4033
4286
|
chainId,
|
|
4034
|
-
|
|
4287
|
+
acp,
|
|
4035
4288
|
overallStartTime,
|
|
4036
4289
|
normalized404RetryTimeoutMs,
|
|
4037
4290
|
onPoll
|
|
@@ -4046,9 +4299,9 @@ async function tnDecryptV2(params) {
|
|
|
4046
4299
|
var DEFAULT_404_RETRY_TIMEOUT_MS3 = 1e4;
|
|
4047
4300
|
var DecryptForTxBuilder = class extends BaseBuilder {
|
|
4048
4301
|
ctHash;
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4302
|
+
acpHash;
|
|
4303
|
+
acp;
|
|
4304
|
+
acpSelection = "unset";
|
|
4052
4305
|
pollCallback;
|
|
4053
4306
|
retry404TimeoutMs = DEFAULT_404_RETRY_TIMEOUT_MS3;
|
|
4054
4307
|
constructor(params) {
|
|
@@ -4093,137 +4346,137 @@ var DecryptForTxBuilder = class extends BaseBuilder {
|
|
|
4093
4346
|
this.retry404TimeoutMs = timeoutMs;
|
|
4094
4347
|
return this;
|
|
4095
4348
|
}
|
|
4096
|
-
|
|
4097
|
-
if (this.
|
|
4349
|
+
withACP(acpOrACPHash) {
|
|
4350
|
+
if (this.acpSelection === "with-acp") {
|
|
4098
4351
|
throw new CofheError({
|
|
4099
4352
|
code: "INTERNAL_ERROR" /* InternalError */,
|
|
4100
|
-
message: "decryptForTx:
|
|
4101
|
-
hint: "Choose the
|
|
4353
|
+
message: "decryptForTx: withACP() can only be selected once.",
|
|
4354
|
+
hint: "Choose the acp mode once. If you need a different acp, start a new decryptForTx() builder chain."
|
|
4102
4355
|
});
|
|
4103
4356
|
}
|
|
4104
|
-
if (this.
|
|
4357
|
+
if (this.acpSelection === "without-acp") {
|
|
4105
4358
|
throw new CofheError({
|
|
4106
4359
|
code: "INTERNAL_ERROR" /* InternalError */,
|
|
4107
|
-
message: "decryptForTx: cannot call
|
|
4108
|
-
hint: "Choose exactly one
|
|
4360
|
+
message: "decryptForTx: cannot call withACP() after withoutACP() has been selected.",
|
|
4361
|
+
hint: "Choose exactly one acp mode: either call .withACP(...) or .withoutACP(), but not both."
|
|
4109
4362
|
});
|
|
4110
4363
|
}
|
|
4111
|
-
this.
|
|
4112
|
-
if (typeof
|
|
4113
|
-
this.
|
|
4114
|
-
this.
|
|
4115
|
-
} else if (
|
|
4116
|
-
this.
|
|
4117
|
-
this.
|
|
4364
|
+
this.acpSelection = "with-acp";
|
|
4365
|
+
if (typeof acpOrACPHash === "string") {
|
|
4366
|
+
this.acpHash = acpOrACPHash;
|
|
4367
|
+
this.acp = void 0;
|
|
4368
|
+
} else if (acpOrACPHash === void 0) {
|
|
4369
|
+
this.acpHash = void 0;
|
|
4370
|
+
this.acp = void 0;
|
|
4118
4371
|
} else {
|
|
4119
|
-
this.
|
|
4120
|
-
this.
|
|
4372
|
+
this.acp = acpOrACPHash;
|
|
4373
|
+
this.acpHash = void 0;
|
|
4121
4374
|
}
|
|
4122
4375
|
return this;
|
|
4123
4376
|
}
|
|
4124
4377
|
/**
|
|
4125
|
-
* Select "no
|
|
4378
|
+
* Select "no acp" mode.
|
|
4126
4379
|
*
|
|
4127
|
-
* This uses global allowance (no
|
|
4380
|
+
* This uses global allowance (no acp required) and sends an empty permission payload to `/decrypt`.
|
|
4128
4381
|
*/
|
|
4129
|
-
|
|
4130
|
-
if (this.
|
|
4382
|
+
withoutACP() {
|
|
4383
|
+
if (this.acpSelection === "without-acp") {
|
|
4131
4384
|
throw new CofheError({
|
|
4132
4385
|
code: "INTERNAL_ERROR" /* InternalError */,
|
|
4133
|
-
message: "decryptForTx:
|
|
4134
|
-
hint: "Choose the
|
|
4386
|
+
message: "decryptForTx: withoutACP() can only be selected once.",
|
|
4387
|
+
hint: "Choose the acp mode once. If you need a different mode, start a new decryptForTx() builder chain."
|
|
4135
4388
|
});
|
|
4136
4389
|
}
|
|
4137
|
-
if (this.
|
|
4390
|
+
if (this.acpSelection === "with-acp") {
|
|
4138
4391
|
throw new CofheError({
|
|
4139
4392
|
code: "INTERNAL_ERROR" /* InternalError */,
|
|
4140
|
-
message: "decryptForTx: cannot call
|
|
4141
|
-
hint: "Choose exactly one
|
|
4393
|
+
message: "decryptForTx: cannot call withoutACP() after withACP() has been selected.",
|
|
4394
|
+
hint: "Choose exactly one acp mode: either call .withACP(...) or .withoutACP(), but not both."
|
|
4142
4395
|
});
|
|
4143
4396
|
}
|
|
4144
|
-
this.
|
|
4145
|
-
this.
|
|
4146
|
-
this.
|
|
4397
|
+
this.acpSelection = "without-acp";
|
|
4398
|
+
this.acpHash = void 0;
|
|
4399
|
+
this.acp = void 0;
|
|
4147
4400
|
return this;
|
|
4148
4401
|
}
|
|
4149
|
-
|
|
4150
|
-
return this.
|
|
4402
|
+
getACP() {
|
|
4403
|
+
return this.acp;
|
|
4151
4404
|
}
|
|
4152
|
-
|
|
4153
|
-
return this.
|
|
4405
|
+
getACPHash() {
|
|
4406
|
+
return this.acpHash;
|
|
4154
4407
|
}
|
|
4155
4408
|
async getThresholdNetworkUrl() {
|
|
4156
4409
|
this.assertChainId();
|
|
4157
4410
|
return getThresholdNetworkUrlOrThrow(this.config, this.chainId);
|
|
4158
4411
|
}
|
|
4159
|
-
async
|
|
4160
|
-
if (this.
|
|
4412
|
+
async getResolvedACP() {
|
|
4413
|
+
if (this.acpSelection === "unset") {
|
|
4161
4414
|
throw new CofheError({
|
|
4162
4415
|
code: "INTERNAL_ERROR" /* InternalError */,
|
|
4163
|
-
message: "decryptForTx: missing
|
|
4164
|
-
hint: "Call .
|
|
4416
|
+
message: "decryptForTx: missing acp selection; call withACP(...) or withoutACP() before execute().",
|
|
4417
|
+
hint: "Call .withACP() to use the active acp, or .withoutACP() for global allowance."
|
|
4165
4418
|
});
|
|
4166
4419
|
}
|
|
4167
|
-
if (this.
|
|
4420
|
+
if (this.acpSelection === "without-acp") {
|
|
4168
4421
|
return null;
|
|
4169
4422
|
}
|
|
4170
|
-
if (this.
|
|
4171
|
-
return this.
|
|
4423
|
+
if (this.acp)
|
|
4424
|
+
return this.acp;
|
|
4172
4425
|
this.assertChainId();
|
|
4173
4426
|
this.assertAccount();
|
|
4174
|
-
if (this.
|
|
4175
|
-
const
|
|
4176
|
-
if (!
|
|
4427
|
+
if (this.acpHash) {
|
|
4428
|
+
const acp2 = await acps.getACP(this.chainId, this.account, this.acpHash);
|
|
4429
|
+
if (!acp2) {
|
|
4177
4430
|
throw new CofheError({
|
|
4178
|
-
code: "
|
|
4179
|
-
message: `
|
|
4180
|
-
hint: "Ensure the
|
|
4431
|
+
code: "ACP_NOT_FOUND" /* ACPNotFound */,
|
|
4432
|
+
message: `ACP with hash <${this.acpHash}> not found for account <${this.account}> and chainId <${this.chainId}>`,
|
|
4433
|
+
hint: "Ensure the acp exists and is valid.",
|
|
4181
4434
|
context: {
|
|
4182
4435
|
chainId: this.chainId,
|
|
4183
4436
|
account: this.account,
|
|
4184
|
-
|
|
4437
|
+
acpHash: this.acpHash
|
|
4185
4438
|
}
|
|
4186
4439
|
});
|
|
4187
4440
|
}
|
|
4188
|
-
return
|
|
4441
|
+
return acp2;
|
|
4189
4442
|
}
|
|
4190
|
-
const
|
|
4191
|
-
if (!
|
|
4443
|
+
const acp = await acps.getActiveACP(this.chainId, this.account);
|
|
4444
|
+
if (!acp) {
|
|
4192
4445
|
throw new CofheError({
|
|
4193
|
-
code: "
|
|
4194
|
-
message: `Active
|
|
4195
|
-
hint: "Create
|
|
4446
|
+
code: "ACP_NOT_FOUND" /* ACPNotFound */,
|
|
4447
|
+
message: `Active acp not found for chainId <${this.chainId}> and account <${this.account}>`,
|
|
4448
|
+
hint: "Create an ACP (e.g. client.acp.createSelf(...)) and/or set it active (client.acp.selectActiveACP(hash)).",
|
|
4196
4449
|
context: {
|
|
4197
4450
|
chainId: this.chainId,
|
|
4198
4451
|
account: this.account
|
|
4199
4452
|
}
|
|
4200
4453
|
});
|
|
4201
4454
|
}
|
|
4202
|
-
return
|
|
4455
|
+
return acp;
|
|
4203
4456
|
}
|
|
4204
4457
|
/**
|
|
4205
4458
|
* On hardhat, interact with MockThresholdNetwork contract
|
|
4206
4459
|
*/
|
|
4207
|
-
async mocksDecryptForTx(
|
|
4460
|
+
async mocksDecryptForTx(acp) {
|
|
4208
4461
|
this.assertPublicClient();
|
|
4209
4462
|
const delay = this.config.mocks.decryptDelay;
|
|
4210
4463
|
if (delay > 0)
|
|
4211
4464
|
await sleep(delay);
|
|
4212
|
-
const result = await cofheMocksDecryptForTx(this.ctHash, 0,
|
|
4465
|
+
const result = await cofheMocksDecryptForTx(this.ctHash, 0, acp, this.publicClient);
|
|
4213
4466
|
return result;
|
|
4214
4467
|
}
|
|
4215
4468
|
/**
|
|
4216
4469
|
* In the production context, perform a true decryption with the CoFHE coprocessor.
|
|
4217
4470
|
*/
|
|
4218
|
-
async productionDecryptForTx(
|
|
4471
|
+
async productionDecryptForTx(acp) {
|
|
4219
4472
|
this.assertChainId();
|
|
4220
4473
|
this.assertPublicClient();
|
|
4221
4474
|
const thresholdNetworkUrl = await this.getThresholdNetworkUrl();
|
|
4222
|
-
const
|
|
4475
|
+
const wireAcp = acp ? ACPUtils.getPublic(acp, true) : null;
|
|
4223
4476
|
const { decryptedValue, signature } = await tnDecryptV2({
|
|
4224
4477
|
ctHash: this.ctHash,
|
|
4225
4478
|
chainId: this.chainId,
|
|
4226
|
-
|
|
4479
|
+
acp: wireAcp,
|
|
4227
4480
|
thresholdNetworkUrl,
|
|
4228
4481
|
retry404TimeoutMs: this.retry404TimeoutMs,
|
|
4229
4482
|
onPoll: this.pollCallback
|
|
@@ -4237,19 +4490,19 @@ var DecryptForTxBuilder = class extends BaseBuilder {
|
|
|
4237
4490
|
/**
|
|
4238
4491
|
* Final step of the decryptForTx process. MUST BE CALLED LAST IN THE CHAIN.
|
|
4239
4492
|
*
|
|
4240
|
-
* You must explicitly choose one
|
|
4241
|
-
* - `
|
|
4242
|
-
* - `
|
|
4493
|
+
* You must explicitly choose one acp mode before calling `execute()`:
|
|
4494
|
+
* - `withACP(acp)` / `withACP(acpHash)` / `withACP()` (active acp)
|
|
4495
|
+
* - `withoutACP()` (global allowance)
|
|
4243
4496
|
*/
|
|
4244
4497
|
async execute() {
|
|
4245
|
-
const
|
|
4246
|
-
if (
|
|
4247
|
-
|
|
4248
|
-
const chainId =
|
|
4498
|
+
const acp = await this.getResolvedACP();
|
|
4499
|
+
if (acp !== null) {
|
|
4500
|
+
ACPUtils.validate(acp);
|
|
4501
|
+
const chainId = acp._signedDomain.chainId;
|
|
4249
4502
|
if (chainId === hardhat2.id) {
|
|
4250
|
-
return await this.mocksDecryptForTx(
|
|
4503
|
+
return await this.mocksDecryptForTx(acp);
|
|
4251
4504
|
} else {
|
|
4252
|
-
return await this.productionDecryptForTx(
|
|
4505
|
+
return await this.productionDecryptForTx(acp);
|
|
4253
4506
|
}
|
|
4254
4507
|
} else {
|
|
4255
4508
|
if (!this.chainId) {
|
|
@@ -4312,6 +4565,21 @@ function createCofheClientBase(opts) {
|
|
|
4312
4565
|
const updateConnectState = (partial) => {
|
|
4313
4566
|
connectStore.setState((state) => ({ ...state, ...partial }));
|
|
4314
4567
|
};
|
|
4568
|
+
const _resolveSharingRegistry = async (publicClient, chainId) => {
|
|
4569
|
+
const configured = opts.config.acp?.sharingRegistry?.[chainId];
|
|
4570
|
+
if (configured != null)
|
|
4571
|
+
return configured;
|
|
4572
|
+
const registry = (await acps.getAclServedAddresses(publicClient, chainId)).shareRegistry;
|
|
4573
|
+
if (registry == null) {
|
|
4574
|
+
throw new CofheError({
|
|
4575
|
+
code: "MISSING_CONFIG" /* MissingConfig */,
|
|
4576
|
+
message: `No ACP share registry available for chainId <${chainId}>`,
|
|
4577
|
+
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.",
|
|
4578
|
+
context: { chainId }
|
|
4579
|
+
});
|
|
4580
|
+
}
|
|
4581
|
+
return registry;
|
|
4582
|
+
};
|
|
4315
4583
|
const _requireConnected = () => {
|
|
4316
4584
|
const state = connectStore.getState();
|
|
4317
4585
|
const notConnected = !state.connected || !state.account || !state.chainId || !state.publicClient || !state.walletClient;
|
|
@@ -4434,74 +4702,147 @@ function createCofheClientBase(opts) {
|
|
|
4434
4702
|
}
|
|
4435
4703
|
return { chainId: _chainId, account: _account };
|
|
4436
4704
|
};
|
|
4437
|
-
const
|
|
4705
|
+
const clientACPs = {
|
|
4438
4706
|
// Pass through store access
|
|
4439
|
-
getSnapshot:
|
|
4440
|
-
subscribe:
|
|
4707
|
+
getSnapshot: acps.getSnapshot,
|
|
4708
|
+
subscribe: acps.subscribe,
|
|
4441
4709
|
// Creation methods (require connection)
|
|
4442
4710
|
createSelf: async (options, clients) => {
|
|
4443
4711
|
_requireConnected();
|
|
4444
4712
|
const { publicClient, walletClient } = clients ?? connectStore.getState();
|
|
4445
|
-
|
|
4713
|
+
const chainId = await publicClient.getChainId();
|
|
4714
|
+
return acps.createSelf(
|
|
4715
|
+
await acps.applyACPDefaultsFromChain(options, opts.config.acp, publicClient, chainId),
|
|
4716
|
+
publicClient,
|
|
4717
|
+
walletClient
|
|
4718
|
+
);
|
|
4446
4719
|
},
|
|
4447
4720
|
createSharing: async (options, clients) => {
|
|
4448
4721
|
_requireConnected();
|
|
4449
4722
|
const { publicClient, walletClient } = clients ?? connectStore.getState();
|
|
4450
|
-
|
|
4723
|
+
const chainId = await publicClient.getChainId();
|
|
4724
|
+
return acps.createSharing(
|
|
4725
|
+
await acps.applyACPDefaultsFromChain(options, opts.config.acp, publicClient, chainId),
|
|
4726
|
+
publicClient,
|
|
4727
|
+
walletClient
|
|
4728
|
+
);
|
|
4451
4729
|
},
|
|
4452
4730
|
importShared: async (options, clients) => {
|
|
4453
4731
|
_requireConnected();
|
|
4454
4732
|
const { publicClient, walletClient } = clients ?? connectStore.getState();
|
|
4455
|
-
return
|
|
4733
|
+
return acps.importShared(options, publicClient, walletClient);
|
|
4456
4734
|
},
|
|
4457
4735
|
// Get or create methods (require connection)
|
|
4458
|
-
|
|
4736
|
+
getOrCreateSelfACP: async (chainId, account, options) => {
|
|
4459
4737
|
_requireConnected();
|
|
4460
4738
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
4461
4739
|
const { publicClient, walletClient } = connectStore.getState();
|
|
4462
|
-
|
|
4740
|
+
const optionsWithDefaults = await acps.applyACPDefaultsFromChain(
|
|
4741
|
+
options ?? { issuer: _account, name: "Autogenerated Self ACP" },
|
|
4742
|
+
opts.config.acp,
|
|
4743
|
+
publicClient,
|
|
4744
|
+
_chainId
|
|
4745
|
+
);
|
|
4746
|
+
return acps.getOrCreateSelfACP(publicClient, walletClient, _chainId, _account, optionsWithDefaults);
|
|
4463
4747
|
},
|
|
4464
|
-
|
|
4748
|
+
getOrCreateSharingACP: async (options, chainId, account) => {
|
|
4465
4749
|
_requireConnected();
|
|
4466
4750
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
4467
4751
|
const { publicClient, walletClient } = connectStore.getState();
|
|
4468
|
-
return
|
|
4752
|
+
return acps.getOrCreateSharingACP(
|
|
4753
|
+
publicClient,
|
|
4754
|
+
walletClient,
|
|
4755
|
+
await acps.applyACPDefaultsFromChain(options, opts.config.acp, publicClient, _chainId),
|
|
4756
|
+
_chainId,
|
|
4757
|
+
_account
|
|
4758
|
+
);
|
|
4759
|
+
},
|
|
4760
|
+
// Revocation (require connection)
|
|
4761
|
+
revokeACP: async (acp) => {
|
|
4762
|
+
_requireConnected();
|
|
4763
|
+
const { walletClient } = connectStore.getState();
|
|
4764
|
+
return acps.revokeACP(acp, walletClient);
|
|
4765
|
+
},
|
|
4766
|
+
revokeAllACPs: async (revokerContract) => {
|
|
4767
|
+
_requireConnected();
|
|
4768
|
+
const { publicClient, walletClient } = connectStore.getState();
|
|
4769
|
+
return acps.revokeAllACPs(walletClient, publicClient, revokerContract);
|
|
4770
|
+
},
|
|
4771
|
+
isACPRevoked: async (acp) => {
|
|
4772
|
+
_requireConnected();
|
|
4773
|
+
const { publicClient } = connectStore.getState();
|
|
4774
|
+
return acps.isACPRevoked(acp, publicClient);
|
|
4775
|
+
},
|
|
4776
|
+
// On-chain sharing (require connection + config.acp.sharingRegistry)
|
|
4777
|
+
shareOnChain: async (acp) => {
|
|
4778
|
+
_requireConnected();
|
|
4779
|
+
const { publicClient, walletClient } = connectStore.getState();
|
|
4780
|
+
const chainId = await publicClient.getChainId();
|
|
4781
|
+
const sharingRegistry = await _resolveSharingRegistry(publicClient, chainId);
|
|
4782
|
+
return acps.shareOnChain(acp, walletClient, sharingRegistry);
|
|
4783
|
+
},
|
|
4784
|
+
getIncomingShares: async () => {
|
|
4785
|
+
_requireConnected();
|
|
4786
|
+
const { publicClient, walletClient } = connectStore.getState();
|
|
4787
|
+
const chainId = await publicClient.getChainId();
|
|
4788
|
+
const account = walletClient.account.address;
|
|
4789
|
+
const sharingRegistry = await _resolveSharingRegistry(publicClient, chainId);
|
|
4790
|
+
return acps.getIncomingShares(publicClient, sharingRegistry, account);
|
|
4791
|
+
},
|
|
4792
|
+
importFromChain: async (share) => {
|
|
4793
|
+
_requireConnected();
|
|
4794
|
+
const { publicClient, walletClient } = connectStore.getState();
|
|
4795
|
+
return acps.importFromChain(share, publicClient, walletClient);
|
|
4796
|
+
},
|
|
4797
|
+
dismissShare: async (shareId) => {
|
|
4798
|
+
_requireConnected();
|
|
4799
|
+
const { publicClient, walletClient } = connectStore.getState();
|
|
4800
|
+
const chainId = await publicClient.getChainId();
|
|
4801
|
+
const sharingRegistry = await _resolveSharingRegistry(publicClient, chainId);
|
|
4802
|
+
return acps.removeShareOnChain(shareId, walletClient, sharingRegistry);
|
|
4803
|
+
},
|
|
4804
|
+
cancelShare: async (shareId) => {
|
|
4805
|
+
_requireConnected();
|
|
4806
|
+
const { publicClient, walletClient } = connectStore.getState();
|
|
4807
|
+
const chainId = await publicClient.getChainId();
|
|
4808
|
+
const sharingRegistry = await _resolveSharingRegistry(publicClient, chainId);
|
|
4809
|
+
return acps.removeShareOnChain(shareId, walletClient, sharingRegistry);
|
|
4469
4810
|
},
|
|
4470
4811
|
// Retrieval methods (auto-fill chainId/account)
|
|
4471
|
-
|
|
4812
|
+
getACP: (hash, chainId, account) => {
|
|
4472
4813
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
4473
|
-
return
|
|
4814
|
+
return acps.getACP(_chainId, _account, hash);
|
|
4474
4815
|
},
|
|
4475
|
-
|
|
4816
|
+
getACPs: (chainId, account) => {
|
|
4476
4817
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
4477
|
-
return
|
|
4818
|
+
return acps.getACPs(_chainId, _account);
|
|
4478
4819
|
},
|
|
4479
|
-
|
|
4820
|
+
getActiveACP: (chainId, account) => {
|
|
4480
4821
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
4481
|
-
return
|
|
4822
|
+
return acps.getActiveACP(_chainId, _account);
|
|
4482
4823
|
},
|
|
4483
|
-
|
|
4824
|
+
getActiveACPHash: (chainId, account) => {
|
|
4484
4825
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
4485
|
-
return
|
|
4826
|
+
return acps.getActiveACPHash(_chainId, _account);
|
|
4486
4827
|
},
|
|
4487
4828
|
// Mutation methods (auto-fill chainId/account)
|
|
4488
|
-
|
|
4829
|
+
selectActiveACP: (hash, chainId, account) => {
|
|
4489
4830
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
4490
|
-
return
|
|
4831
|
+
return acps.selectActiveACP(_chainId, _account, hash);
|
|
4491
4832
|
},
|
|
4492
|
-
|
|
4833
|
+
removeACP: async (hash, chainId, account) => {
|
|
4493
4834
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
4494
|
-
return
|
|
4835
|
+
return acps.removeACP(_chainId, _account, hash);
|
|
4495
4836
|
},
|
|
4496
|
-
|
|
4837
|
+
removeActiveACP: async (chainId, account) => {
|
|
4497
4838
|
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
4498
|
-
return
|
|
4839
|
+
return acps.removeActiveACP(_chainId, _account);
|
|
4499
4840
|
},
|
|
4500
4841
|
// Utils (no context needed)
|
|
4501
|
-
getHash:
|
|
4502
|
-
export:
|
|
4503
|
-
serialize:
|
|
4504
|
-
deserialize:
|
|
4842
|
+
getHash: acps.getHash,
|
|
4843
|
+
export: acps.export,
|
|
4844
|
+
serialize: acps.serialize,
|
|
4845
|
+
deserialize: acps.deserialize
|
|
4505
4846
|
};
|
|
4506
4847
|
return {
|
|
4507
4848
|
// Zustand reactive accessors (don't export store directly to prevent mutation)
|
|
@@ -4529,7 +4870,7 @@ function createCofheClientBase(opts) {
|
|
|
4529
4870
|
decryptHandle: decryptForView,
|
|
4530
4871
|
decryptForTx,
|
|
4531
4872
|
verifyDecryptResult: verifyDecryptResult2,
|
|
4532
|
-
|
|
4873
|
+
acp: clientACPs
|
|
4533
4874
|
// Add SDK-specific methods below that require connection
|
|
4534
4875
|
// Example:
|
|
4535
4876
|
// async encryptData(data: unknown) {
|